diff --git a/TODO b/TODO
index 038debc..04ff7e9 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,5 @@
Technology Preview 2 :
+- Implement perspective correction for coordinate mapping of rasterized polygons.
- Finalize terrain editor.
=> Add a generation dialog for base noise (overwriting changes).
- Get rid of noise dialogs, for simpler settings.
@@ -15,6 +16,7 @@ Technology Preview 2 :
Technlogy Preview 3 :
- Start an undo/redo system ?
+- Alter aerial perspective using estimation of the amount of light left after cloud layers traversal.
- Add a map preview to terrain editor.
- Better time selection widget for atmosphere.
- Clouds should keep distance to ground.
diff --git a/data/ui_pictures.qrc b/data/ui_pictures.qrc
index b16e299..a3fa8d0 100644
--- a/data/ui_pictures.qrc
+++ b/data/ui_pictures.qrc
@@ -6,6 +6,9 @@
images/explore.png
images/render.png
images/about.png
+ images/load.png
+ images/new.png
+ images/save.png
images/tab_atmosphere.png
@@ -15,4 +18,10 @@
images/tab_textures.png
images/tab_water.png
+
+ images/logo_16.png
+ images/logo_32.png
+ images/logo_64.png
+ images/logo_256.png
+
diff --git a/src/editing/common/freeformhelper.cpp b/src/editing/common/freeformhelper.cpp
index 9ab7c67..36967fd 100644
--- a/src/editing/common/freeformhelper.cpp
+++ b/src/editing/common/freeformhelper.cpp
@@ -2,11 +2,16 @@
#include
#include
+#include
+#include
+#include
#include
+#include
#include "dialogrender.h"
#include "dialogexplorer.h"
#include "rendering/scenery.h"
#include "rendering/renderer.h"
+#include "tools.h"
Q_DECLARE_METATYPE(double*)
@@ -24,8 +29,43 @@ FreeFormHelper::~FreeFormHelper()
{
}
+bool FreeFormHelper::eventFilter(QObject* object, QEvent* event)
+{
+ if (event->type() == QEvent::Resize && object == _form_widget)
+ {
+ QSize form_size = ((QResizeEvent*) event)->size();
+ QSize preview_size;
+
+ if (form_size.width() > 1400 && form_size.height() > 900)
+ {
+ preview_size = QSize(300, 300);
+ }
+ else if (form_size.width() < 1000 || form_size.height() < 700)
+ {
+ preview_size = QSize(160, 160);
+ }
+ else
+ {
+ preview_size = QSize(220, 220);
+ }
+
+ for (int i = 0; i < _previews.size(); i++)
+ {
+ if (_previews[i]->size() != preview_size)
+ {
+ _previews[i]->setMinimumSize(preview_size);
+ _previews[i]->setMaximumSize(preview_size);
+ _previews[i]->resize(preview_size);
+ }
+ }
+ }
+ return false;
+}
+
void FreeFormHelper::startManaging()
{
+ _form_widget->installEventFilter(this);
+
connect(this, SIGNAL(needLocalRefreshing()), _form_widget, SLOT(refreshFromLocalData()));
connect(this, SIGNAL(needGlobalRefreshing()), _form_widget, SLOT(refreshFromFellowData()));
connect(this, SIGNAL(needReverting()), _form_widget, SLOT(updateLocalDataFromScenery()));
diff --git a/src/editing/common/freeformhelper.h b/src/editing/common/freeformhelper.h
index c245fcb..5592d3b 100644
--- a/src/editing/common/freeformhelper.h
+++ b/src/editing/common/freeformhelper.h
@@ -1,11 +1,12 @@
#ifndef FREEFORMHELPER_H
#define FREEFORMHELPER_H
-#include
-#include
#include "widgetsliderdecimal.h"
#include "../basepreview.h"
+class QSlider;
+class QPushButton;
+
class FreeFormHelper:public QObject
{
Q_OBJECT
@@ -57,6 +58,9 @@ public slots:
void processRenderClicked();
void processDecimalChange(double value);
+protected:
+ bool eventFilter(QObject* object, QEvent* event);
+
private:
QWidget* _form_widget;
diff --git a/src/editing/mainwindow.cpp b/src/editing/common/mainwindow.cpp
similarity index 76%
rename from src/editing/mainwindow.cpp
rename to src/editing/common/mainwindow.cpp
index b568c73..6597607 100644
--- a/src/editing/mainwindow.cpp
+++ b/src/editing/common/mainwindow.cpp
@@ -1,10 +1,10 @@
#include "mainwindow.h"
+#include "ui_mainwindow.h"
#include
#include
#include
#include
-#include
#include
#include
#include
@@ -64,6 +64,7 @@ int main(int argc, char** argv)
window = new MainWindow();
window->show();
+ //window->showMaximized();
splash->finish(window);
delete splash;
@@ -79,68 +80,60 @@ int main(int argc, char** argv)
}
MainWindow::MainWindow(QWidget *parent) :
-QMainWindow(parent)
+ QMainWindow(parent),
+ ui(new Ui::MainWindow)
{
+ ui->setupUi(this);
+
BaseForm* form;
- QTabWidget* tabs;
- QToolBar* toolbar;
- tabs = new QTabWidget(this);
- tabs->setIconSize(QSize(32, 32));
+ connect(ui->action_explore, SIGNAL(triggered()), this, SLOT(explore3D()));
+ connect(ui->action_quick_render, SIGNAL(triggered()), this, SLOT(quickPreview()));
+ connect(ui->action_final_render, SIGNAL(triggered()), this, SLOT(finalRender()));
+ connect(ui->action_file_new, SIGNAL(triggered()), this, SLOT(fileNew()));
+ connect(ui->action_file_save, SIGNAL(triggered()), this, SLOT(fileSave()));
+ connect(ui->action_file_load, SIGNAL(triggered()), this, SLOT(fileLoad()));
+ connect(ui->action_about, SIGNAL(triggered()), this, SLOT(showAboutDialog()));
- tabs->addTab(new MainTerrainForm(tabs), QIcon(getDataPath("images/tab_terrain.png")), tr("Landscape shape"));
-
- form = new FormTextures(tabs);
- tabs->addTab(form, QIcon(getDataPath("images/tab_textures.png")), tr("Textures"));
+ form = new FormTextures(ui->tabs);
+ ui->tabs->addTab(form, QIcon(getDataPath("images/tab_textures.png")), tr("Textures"));
QObject::connect(form, SIGNAL(configApplied()), this, SLOT(refreshAll()), Qt::QueuedConnection);
_forms.append(form);
- form = new FormWater(tabs);
- tabs->addTab(form, QIcon(getDataPath("images/tab_water.png")), tr("Water"));
+ form = new FormWater(ui->tabs);
+ ui->tabs->addTab(form, QIcon(getDataPath("images/tab_water.png")), tr("Water"));
QObject::connect(form, SIGNAL(configApplied()), this, SLOT(refreshAll()), Qt::QueuedConnection);
_forms.append(form);
- form = new FormAtmosphere(tabs);
- tabs->addTab(form, QIcon(getDataPath("images/tab_atmosphere.png")), tr("Atmosphere"));
+ form = new FormAtmosphere(ui->tabs);
+ ui->tabs->addTab(form, QIcon(getDataPath("images/tab_atmosphere.png")), tr("Atmosphere"));
QObject::connect(form, SIGNAL(configApplied()), this, SLOT(refreshAll()), Qt::QueuedConnection);
_forms.append(form);
- form = new FormClouds(tabs);
- tabs->addTab(form, QIcon(getDataPath("images/tab_clouds.png")), tr("Clouds"));
+ form = new FormClouds(ui->tabs);
+ ui->tabs->addTab(form, QIcon(getDataPath("images/tab_clouds.png")), tr("Clouds"));
QObject::connect(form, SIGNAL(configApplied()), this, SLOT(refreshAll()), Qt::QueuedConnection);
_forms.append(form);
- _form_render = new FormRender(tabs);
- tabs->addTab(_form_render, QIcon(getDataPath("images/tab_render.png")), tr("Render"));
+ _form_render = new FormRender(ui->tabs);
+ ui->tabs->addTab(_form_render, QIcon(getDataPath("images/tab_render.png")), tr("Render"));
_forms.append(_form_render);
- toolbar = new QToolBar(this);
- toolbar->setOrientation(Qt::Vertical);
- toolbar->setAllowedAreas(Qt::LeftToolBarArea);
- toolbar->setMovable(false);
- toolbar->setFloatable(false);
- toolbar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
- toolbar->toggleViewAction()->setEnabled(false);
- toolbar->setIconSize(QSize(32, 32));
- addToolBar(Qt::LeftToolBarArea, toolbar);
-
- toolbar->addAction(QIcon(getDataPath("images/new.png")), tr("&New"), this, SLOT(fileNew()))->setShortcut(QKeySequence(tr("Crtl+N")));
- toolbar->addAction(QIcon(getDataPath("images/save.png")), tr("&Save"), this, SLOT(fileSave()))->setShortcut(QKeySequence(tr("Crtl+S")));
- toolbar->addAction(QIcon(getDataPath("images/load.png")), tr("&Load"), this, SLOT(fileLoad()))->setShortcut(QKeySequence(tr("Crtl+L")));
- toolbar->addAction(QIcon(getDataPath("images/explore.png")), tr("&Explore (F2)"), this, SLOT(explore3D()))->setShortcut(QKeySequence(tr("F2")));
- toolbar->addAction(QIcon(getDataPath("images/render.png")), tr("&Quick\nrender (F5)"), this, SLOT(quickPreview()))->setShortcut(QKeySequence(tr("F5")));
- toolbar->addAction(QIcon(getDataPath("images/about.png")), tr("&About"), this, SLOT(showAboutDialog()));
-
- setCentralWidget(tabs);
-
- setWindowTitle("Paysages 3D");
- setWindowIcon(QIcon(getDataPath("images/logo_32.png")));
+ // TODO Decide this according to platform / screen size
+ //ui->toolBar->hide();
+ ui->tool_panel->hide();
+ ui->menuBar->hide();
scenerySetCustomDataCallback(MainWindow::guiSaveCallback, MainWindow::guiLoadCallback, this);
refreshAll();
}
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
bool MainWindow::event(QEvent* event)
{
if (event->type() == QEvent::WindowActivate)
@@ -160,6 +153,7 @@ void MainWindow::refreshAll()
{
_forms[i]->revertConfig();
}
+ // TODO Refresh free forms
// Refresh preview OSD
CameraDefinition* camera = cameraCreateDefinition();
@@ -244,6 +238,16 @@ void MainWindow::quickPreview()
_form_render->startQuickRender();
}
+void MainWindow::finalRender()
+{
+ _form_render->startRender();
+}
+
+void MainWindow::showLastRender()
+{
+ _form_render->showRender();
+}
+
void MainWindow::explore3D()
{
CameraDefinition* camera;
diff --git a/src/editing/mainwindow.h b/src/editing/common/mainwindow.h
similarity index 72%
rename from src/editing/mainwindow.h
rename to src/editing/common/mainwindow.h
index 0a00ae8..64b73de 100644
--- a/src/editing/mainwindow.h
+++ b/src/editing/common/mainwindow.h
@@ -1,16 +1,25 @@
-#ifndef _PAYSAGES_QT_MAINWINDOW_H_
-#define _PAYSAGES_QT_MAINWINDOW_H_
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
#include
-#include "formrender.h"
+#include
#include "rendering/tools/pack.h"
+class BaseForm;
+class FormRender;
+
+namespace Ui {
+class MainWindow;
+}
+
class MainWindow : public QMainWindow
{
Q_OBJECT
-
+
public:
explicit MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
virtual bool event(QEvent* event);
static void guiSaveCallback(PackStream* stream, void* data);
@@ -26,9 +35,14 @@ public slots:
void showAboutDialog();
void quickPreview();
+ void finalRender();
+ void showLastRender();
+
void explore3D();
private:
+ Ui::MainWindow *ui;
+
void guiSave(PackStream* stream);
void guiLoad(PackStream* stream);
@@ -36,4 +50,4 @@ private:
FormRender* _form_render;
};
-#endif
+#endif // MAINWINDOW_H
diff --git a/src/editing/common/mainwindow.ui b/src/editing/common/mainwindow.ui
new file mode 100644
index 0000000..b6744c8
--- /dev/null
+++ b/src/editing/common/mainwindow.ui
@@ -0,0 +1,572 @@
+
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 946
+ 651
+
+
+
+ Paysages 3D
+
+
+
+ :/logo/images/logo_32.png:/logo/images/logo_32.png
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
-
+
+
+ <html><head/><body><p><span style=" font-size:14pt; font-weight:600;">Paysages 3D</span></p><p><img src=":/logo/images/logo_32.png"/></p></body></html>
+
+
+ Qt::RichText
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
-
+
+
+ Preview
+
+
+ true
+
+
+
+ -
+
+
+ 3D
+
+
+
+ -
+
+
+ Top
+
+
+
+
+
+ -
+
+
+ QFrame::Panel
+
+
+ QFrame::Raised
+
+
+ 3
+
+
+
+ 0
+
+
+ QLayout::SetMinimumSize
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 200
+ 150
+
+
+
+
+ 400
+ 300
+
+
+
+
+
+ widget
+ widget
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Actions
+
+
+
-
+
+
+ Explore in 3D
+
+
+
+ :/buttons/logo/images/explore.png:/buttons/logo/images/explore.png
+
+
+ F2
+
+
+
+ -
+
+
+ Render
+
+
+
+ :/buttons/logo/images/render.png:/buttons/logo/images/render.png
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ File
+
+
+
-
+
+
+ New
+
+
+
+ :/buttons/logo/images/new.png:/buttons/logo/images/new.png
+
+
+
+ -
+
+
+ Save
+
+
+
+ :/buttons/logo/images/save.png:/buttons/logo/images/save.png
+
+
+
+ -
+
+
+ Load
+
+
+
+ :/buttons/logo/images/load.png:/buttons/logo/images/load.png
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+ -
+
+
+ 0
+
+
+
+ 32
+ 32
+
+
+
+
+
+ :/tabs/images/tab_terrain.png:/tabs/images/tab_terrain.png
+
+
+ Lanscape shape
+
+
+
+
+
+
+
+
+ toolBar
+
+
+ false
+
+
+ Qt::LeftToolBarArea
+
+
+
+ 32
+ 32
+
+
+
+ Qt::ToolButtonTextUnderIcon
+
+
+ false
+
+
+ LeftToolBarArea
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :/buttons/logo/images/explore.png:/buttons/logo/images/explore.png
+
+
+ Explore in 3D
+
+
+ Start exploring your scenery in real-time 3D
+
+
+ F2
+
+
+
+
+
+ :/buttons/logo/images/new.png:/buttons/logo/images/new.png
+
+
+ New scene
+
+
+ Create a virgin scene
+
+
+ Ctrl+N
+
+
+
+
+
+ :/buttons/logo/images/load.png:/buttons/logo/images/load.png
+
+
+ Load scene
+
+
+ Load a scenery from a file
+
+
+ Ctrl+O
+
+
+
+
+
+ :/buttons/logo/images/save.png:/buttons/logo/images/save.png
+
+
+ Save scene
+
+
+ Save a scenery to a file
+
+
+ Ctrl+S
+
+
+
+
+
+ :/buttons/logo/images/render.png:/buttons/logo/images/render.png
+
+
+ Quick render
+
+
+ Start a quick render
+
+
+ F5
+
+
+
+
+
+ :/buttons/logo/images/render.png:/buttons/logo/images/render.png
+
+
+ Final render
+
+
+ Start the final rendering processs
+
+
+ Ctrl+F5
+
+
+
+
+
+ :/buttons/logo/images/about.png:/buttons/logo/images/about.png
+
+
+ About
+
+
+ Display information on this software
+
+
+ F1
+
+
+
+
+
+ :/buttons/logo/images/render.png:/buttons/logo/images/render.png
+
+
+ Show last render
+
+
+ Display the last render done
+
+
+ F6
+
+
+
+
+
+ MainTerrainForm
+ QWidget
+ terrain/mainterrainform.h
+ 1
+
+
+
+
+
+
+
+ button_explore
+ clicked()
+ action_explore
+ trigger()
+
+
+ 127
+ 380
+
+
+ -1
+ -1
+
+
+
+
+ button_render
+ clicked()
+ action_final_render
+ trigger()
+
+
+ 213
+ 425
+
+
+ 213
+ 425
+
+
+
+
+ button_file_new
+ clicked()
+ action_file_new
+ trigger()
+
+
+ 213
+ 522
+
+
+ -1
+ -1
+
+
+
+
+ button_file_load
+ clicked()
+ action_file_load
+ trigger()
+
+
+ 213
+ 588
+
+
+ -1
+ -1
+
+
+
+
+ button_file_save
+ clicked()
+ action_file_save
+ trigger()
+
+
+ 213
+ 555
+
+
+ -1
+ -1
+
+
+
+
+
diff --git a/src/editing/dialogrender.cpp b/src/editing/dialogrender.cpp
index 09844b9..d8fe4fa 100644
--- a/src/editing/dialogrender.cpp
+++ b/src/editing/dialogrender.cpp
@@ -133,7 +133,7 @@ DialogRender::DialogRender(QWidget *parent, Renderer* renderer):
_actions->layout()->addWidget(_save_button);
// Connections
- connect(this, SIGNAL(renderSizeChanged(int, int)), this, SLOT(applyRenderSize(int, int)));
+ //connect(this, SIGNAL(renderSizeChanged(int, int)), this, SLOT(applyRenderSize(int, int)));
connect(this, SIGNAL(progressChanged(double)), this, SLOT(applyProgress(double)));
connect(this, SIGNAL(renderEnded()), this, SLOT(applyRenderEnded()));
connect(_save_button, SIGNAL(clicked()), this, SLOT(saveRender()));
@@ -173,7 +173,7 @@ void DialogRender::startRender(RenderParams params)
{
_started = time(NULL);
- //applyRenderSize(params.width, params.height);
+ applyRenderSize(params.width, params.height);
rendererSetPreviewCallbacks(_renderer, _renderStart, _renderDraw, _renderUpdate);
_render_thread = new RenderThread(this, _renderer, params);
@@ -217,9 +217,10 @@ void DialogRender::toneMappingChanged()
void DialogRender::loadLastRender()
{
- //applyRenderSize(_renderer->render_width, _renderer->render_height);
+ applyRenderSize(_renderer->render_width, _renderer->render_height);
rendererSetPreviewCallbacks(_renderer, _renderStart, _renderDraw, _renderUpdate);
renderEnded();
+ toneMappingChanged();
exec();
}
diff --git a/src/editing/formclouds.cpp b/src/editing/formclouds.cpp
index 885e73b..4a47163 100644
--- a/src/editing/formclouds.cpp
+++ b/src/editing/formclouds.cpp
@@ -1,5 +1,6 @@
#include "formclouds.h"
+#include "rendering/clouds/clo_preview.h"
#include "rendering/tools/color.h"
#include "rendering/tools/euclid.h"
#include "rendering/scenery.h"
@@ -12,24 +13,22 @@ class PreviewCloudsCoverage:public BasePreview
public:
PreviewCloudsCoverage(QWidget* parent, CloudsLayerDefinition* layer):BasePreview(parent)
{
- _renderer = cloudsCreatePreviewCoverageRenderer();
+ _renderer = cloudsPreviewCoverageCreateRenderer();
_3d = true;
_original_layer = layer;
- _preview_definition = (CloudsDefinition*)CloudsDefinitionClass.create();
addToggle("3d", tr("Perspective"), true);
configScaling(100.0, 1000.0, 20.0, 200.0);
}
~PreviewCloudsCoverage()
{
- CloudsDefinitionClass.destroy(_preview_definition);
rendererDelete(_renderer);
}
protected:
Color getColor(double x, double y)
{
- return cloudsGetPreviewCoverage(_renderer, x, y, scaling, _3d);
+ return cloudsPreviewCoverageGetPixel(_renderer, x, y, scaling, _3d);
}
virtual void toggleChangeEvent(QString key, bool value)
{
@@ -41,15 +40,12 @@ protected:
}
void updateData()
{
- layersDeleteLayer(_preview_definition->layers, 0);
- layersAddLayer(_preview_definition->layers, _original_layer);
- CloudsRendererClass.bind(_renderer, _preview_definition);
+ cloudsPreviewCoverageBindLayer(_renderer, _original_layer);
}
private:
Renderer* _renderer;
CloudsLayerDefinition* _original_layer;
- CloudsDefinition* _preview_definition;
bool _3d;
};
@@ -59,27 +55,28 @@ public:
PreviewCloudsColor(QWidget* parent, CloudsLayerDefinition* layer):BasePreview(parent)
{
_original_layer = layer;
- _preview_definition = (CloudsDefinition*)CloudsDefinitionClass.create();
- _renderer = cloudsCreatePreviewColorRenderer();
+ _renderer = cloudsPreviewMaterialCreateRenderer();
configScaling(0.5, 2.0, 0.1, 2.0);
}
+
+ ~PreviewCloudsColor()
+ {
+ rendererDelete(_renderer);
+ }
protected:
Color getColor(double x, double y)
{
- return cloudsGetPreviewColor(_renderer, x, y);
+ return cloudsPreviewMaterialGetPixel(_renderer, x, y);
}
void updateData()
{
- layersDeleteLayer(_preview_definition->layers, 0);
- layersAddLayer(_preview_definition->layers, _original_layer);
- CloudsRendererClass.bind(_renderer, _preview_definition);
+ cloudsPreviewMaterialBindLayer(_renderer, _original_layer);
}
private:
Renderer* _renderer;
CloudsLayerDefinition* _original_layer;
- CloudsDefinition* _preview_definition;
};
/**************** Form ****************/
diff --git a/src/editing/formrender.h b/src/editing/formrender.h
index c7629ea..d0b18e6 100644
--- a/src/editing/formrender.h
+++ b/src/editing/formrender.h
@@ -21,14 +21,12 @@ public slots:
virtual void revertConfig();
virtual void applyConfig();
void startQuickRender();
+ void startRender();
+ void showRender();
protected slots:
virtual void configChangeEvent();
-private slots:
- void startRender();
- void showRender();
-
private:
RenderParams _params;
CameraDefinition* _camera;
diff --git a/src/editing/paysages-qt.pro b/src/editing/paysages-qt.pro
index 290b851..1169b91 100644
--- a/src/editing/paysages-qt.pro
+++ b/src/editing/paysages-qt.pro
@@ -24,14 +24,13 @@ win32:LIBS += ../libpaysages.a ../libpaysages_exploring.a -lDevIL -lILU -lILUT -
TRANSLATIONS = $$PROJECT_PATH/data/i18n/paysages_fr.ts
HEADERS += \
- widgetheightmap.h \
+ terrain/widgetheightmap.h \
widgetexplorer.h \
widgetcurveeditor.h \
tools.h \
previewosd.h \
previewmaterial.h \
previewcolorgradation.h \
- mainwindow.h \
inputnoise.h \
inputmaterial.h \
inputlayers.h \
@@ -70,17 +69,19 @@ HEADERS += \
common/freeformhelper.h \
terrain/previewterrainshape.h \
common/widgetsliderdecimal.h \
- common/previewrenderer.h
+ common/previewrenderer.h \
+ terrain/widgetterrainbasenoisepreview.h \
+ common/mainwindow.h \
+ terrain/dialogbaseterrainnoise.h
SOURCES += \
- widgetheightmap.cpp \
+ terrain/widgetheightmap.cpp \
widgetexplorer.cpp \
widgetcurveeditor.cpp \
tools.cpp \
previewosd.cpp \
previewmaterial.cpp \
previewcolorgradation.cpp \
- mainwindow.cpp \
inputnoise.cpp \
inputmaterial.cpp \
inputlayers.cpp \
@@ -119,12 +120,17 @@ SOURCES += \
common/freeformhelper.cpp \
terrain/previewterrainshape.cpp \
common/widgetsliderdecimal.cpp \
- common/previewrenderer.cpp
+ common/previewrenderer.cpp \
+ terrain/widgetterrainbasenoisepreview.cpp \
+ common/mainwindow.cpp \
+ terrain/dialogbaseterrainnoise.cpp
FORMS += \
terrain/dialogterrainpainting.ui \
common/widgetglobalformbuttons.ui \
- terrain/mainterrainform.ui
+ terrain/mainterrainform.ui \
+ common/mainwindow.ui \
+ terrain/dialogbaseterrainnoise.ui
RESOURCES += \
../../data/ui_pictures.qrc
diff --git a/src/editing/terrain/dialogbaseterrainnoise.cpp b/src/editing/terrain/dialogbaseterrainnoise.cpp
new file mode 100644
index 0000000..5b139c8
--- /dev/null
+++ b/src/editing/terrain/dialogbaseterrainnoise.cpp
@@ -0,0 +1,31 @@
+#include "dialogbaseterrainnoise.h"
+#include "ui_dialogbaseterrainnoise.h"
+
+DialogBaseTerrainNoise::DialogBaseTerrainNoise(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::DialogBaseTerrainNoise)
+{
+ ui->setupUi(this);
+
+ _original = 0;
+ _modified = noiseCreateGenerator();
+}
+
+DialogBaseTerrainNoise::~DialogBaseTerrainNoise()
+{
+ delete ui;
+ noiseDeleteGenerator(_modified);
+}
+
+void DialogBaseTerrainNoise::setNoise(NoiseGenerator* noise)
+{
+ _original = noise;
+ noiseCopy(noise, _modified);
+}
+
+int DialogBaseTerrainNoise::editNoise(QWidget* parent, NoiseGenerator* noise)
+{
+ DialogBaseTerrainNoise dialog(parent);
+ dialog.setNoise(noise);
+ return dialog.exec();
+}
diff --git a/src/editing/terrain/dialogbaseterrainnoise.h b/src/editing/terrain/dialogbaseterrainnoise.h
new file mode 100644
index 0000000..a38292c
--- /dev/null
+++ b/src/editing/terrain/dialogbaseterrainnoise.h
@@ -0,0 +1,29 @@
+#ifndef DIALOGBASETERRAINNOISE_H
+#define DIALOGBASETERRAINNOISE_H
+
+#include
+#include "rendering/noise.h"
+
+namespace Ui {
+class DialogBaseTerrainNoise;
+}
+
+class DialogBaseTerrainNoise : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit DialogBaseTerrainNoise(QWidget *parent = 0);
+ ~DialogBaseTerrainNoise();
+
+ void setNoise(NoiseGenerator* noise);
+
+ static int editNoise(QWidget* parent, NoiseGenerator* noise);
+
+private:
+ Ui::DialogBaseTerrainNoise *ui;
+ NoiseGenerator* _original;
+ NoiseGenerator* _modified;
+};
+
+#endif // DIALOGBASETERRAINNOISE_H
diff --git a/src/editing/terrain/dialogbaseterrainnoise.ui b/src/editing/terrain/dialogbaseterrainnoise.ui
new file mode 100644
index 0000000..57b1add
--- /dev/null
+++ b/src/editing/terrain/dialogbaseterrainnoise.ui
@@ -0,0 +1,43 @@
+
+
+ DialogBaseTerrainNoise
+
+
+ Qt::ApplicationModal
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ Paysages 3D - Base terrain noise
+
+
+ true
+
+
+ -
+
+
+
+
+
+
+ WidgetGlobalFormButtons
+ QWidget
+ common/widgetglobalformbuttons.h
+ 1
+
+ okClicked()
+ revertClicked()
+ cancelClicked()
+
+
+
+
+
+
diff --git a/src/editing/terrain/dialogterrainpainting.ui b/src/editing/terrain/dialogterrainpainting.ui
index 72d405f..fb7a98c 100644
--- a/src/editing/terrain/dialogterrainpainting.ui
+++ b/src/editing/terrain/dialogterrainpainting.ui
@@ -789,7 +789,7 @@
WidgetHeightMap
QWidget
-
+ terrain/widgetheightmap.h
1
heightmapChanged()
diff --git a/src/editing/terrain/mainterrainform.cpp b/src/editing/terrain/mainterrainform.cpp
index 04ad6c7..0c659ed 100644
--- a/src/editing/terrain/mainterrainform.cpp
+++ b/src/editing/terrain/mainterrainform.cpp
@@ -1,6 +1,8 @@
#include "mainterrainform.h"
#include "ui_mainterrainform.h"
+#include
+#include "dialogbaseterrainnoise.h"
#include "dialogterrainpainting.h"
#include "previewterrainshape.h"
#include "tools.h"
@@ -20,15 +22,16 @@ MainTerrainForm::MainTerrainForm(QWidget *parent) :
_form_helper->addPreview(ui->preview_shape, _renderer_shape);
_form_helper->addDoubleInputSlider(ui->input_scaling, &_terrain->scaling, 0.1, 3.0, 0.03, 0.3);
- _form_helper->addDoubleInputSlider(ui->input_height, &_terrain->height, 1.0, 45.0, 0.3, 3.0);
+ _form_helper->addDoubleInputSlider(ui->input_height, &_terrain->height, 1.0, 90.0, 0.5, 5.0);
_form_helper->addDoubleInputSlider(ui->input_shadow_smoothing, &_terrain->shadow_smoothing, 0.0, 0.3, 0.003, 0.03);
- _form_helper->addDoubleInputSlider(ui->input_water_height, &_terrain->water_height, -2.0, 2.0, 0.01, 0.1);
+ _form_helper->addDoubleInputSlider(ui->input_water_height, &_terrain->water_height, -1.0, 1.0, 0.01, 0.1);
_form_helper->setApplyButton(ui->button_apply);
_form_helper->setRevertButton(ui->button_revert);
_form_helper->setExploreButton(ui->button_explore);
_form_helper->setRenderButton(ui->button_render);
+ connect(ui->button_dialog_basenoise, SIGNAL(clicked()), this, SLOT(buttonBaseNoisePressed()));
connect(ui->button_dialog_painting, SIGNAL(clicked()), this, SLOT(buttonPaintingPressed()));
connect(ui->button_goto_textures, SIGNAL(clicked()), this, SLOT(buttonTexturesPressed()));
@@ -55,6 +58,8 @@ void MainTerrainForm::refreshFromLocalData()
{
_form_helper->setLabelText("label_painting_info", tr("No manual scuplting done"));
}
+
+ ui->widget_base_noise_preview->setNoise(_terrain->_height_noise);
}
void MainTerrainForm::refreshFromFellowData()
@@ -77,6 +82,27 @@ void MainTerrainForm::alterRenderer(Renderer* renderer)
TerrainRendererClass.bind(renderer, _terrain);
}
+void MainTerrainForm::buttonBaseNoisePressed()
+{
+ int erase;
+ if (terrainGetMemoryStats(_terrain) > 0)
+ {
+ erase = QMessageBox::question(this, tr("Paysages 3D - Base noise edition"), tr("You have manual modifications on this terrain, regenerating base noise may produce weird results."), tr("Keep my changes anyway"), tr("Erase my changes"));
+ }
+ else
+ {
+ erase = 0;
+ }
+
+ if (DialogBaseTerrainNoise::editNoise(this, _terrain->_height_noise))
+ {
+ if (erase)
+ {
+ terrainClearPainting(_terrain->height_map);
+ }
+ }
+}
+
void MainTerrainForm::buttonPaintingPressed()
{
DialogTerrainPainting dialog(this, _terrain);
diff --git a/src/editing/terrain/mainterrainform.h b/src/editing/terrain/mainterrainform.h
index 712197a..5cf5bb9 100644
--- a/src/editing/terrain/mainterrainform.h
+++ b/src/editing/terrain/mainterrainform.h
@@ -26,6 +26,7 @@ public slots:
void commitLocalDataToScenery();
void alterRenderer(Renderer* renderer);
+ void buttonBaseNoisePressed();
void buttonPaintingPressed();
void buttonTexturesPressed();
diff --git a/src/editing/terrain/mainterrainform.ui b/src/editing/terrain/mainterrainform.ui
index 3e08c61..dac4f2f 100644
--- a/src/editing/terrain/mainterrainform.ui
+++ b/src/editing/terrain/mainterrainform.ui
@@ -44,7 +44,7 @@
-
-
-
+
Generate base noise
@@ -54,7 +54,7 @@
-
-
+
1
@@ -447,6 +447,12 @@
QSlider
common/widgetsliderdecimal.h
+
+ WidgetTerrainBaseNoisePreview
+ QWidget
+ terrain/widgetterrainbasenoisepreview.h
+ 1
+
diff --git a/src/editing/terrain/previewterrainshape.cpp b/src/editing/terrain/previewterrainshape.cpp
index 5582f9d..0919370 100644
--- a/src/editing/terrain/previewterrainshape.cpp
+++ b/src/editing/terrain/previewterrainshape.cpp
@@ -5,6 +5,7 @@
PreviewTerrainShape::PreviewTerrainShape(TerrainDefinition* terrain)
{
_terrain = terrain;
+ _highlight_enabled = true;
// TODO Don't delete the base renderer, just alter it
rendererDelete(renderer);
@@ -14,6 +15,7 @@ PreviewTerrainShape::PreviewTerrainShape(TerrainDefinition* terrain)
void PreviewTerrainShape::bindEvent(BasePreview* preview)
{
preview->addOsd(QString("geolocation"));
+ //preview->addToggle("highlight", tr("Coverage highlight"), true);
preview->configScaling(20.0, 1000.0, 20.0, 50.0);
preview->configScrolling(-1000.0, 1000.0, 0.0, -1000.0, 1000.0, 0.0);
@@ -26,5 +28,13 @@ void PreviewTerrainShape::updateEvent()
Color PreviewTerrainShape::getColor2D(double x, double y, double scaling)
{
- return terrainGetPreviewColor(renderer, x, y, scaling);
+ return waterGetPreviewCoverage(renderer, x, y, scaling, _highlight_enabled ? 1 : 0);
+}
+
+void PreviewTerrainShape::toggleChangeEvent(QString key, bool value)
+{
+ if (key == "highlight")
+ {
+ _highlight_enabled = value;
+ }
}
diff --git a/src/editing/terrain/previewterrainshape.h b/src/editing/terrain/previewterrainshape.h
index ae54091..c99141e 100644
--- a/src/editing/terrain/previewterrainshape.h
+++ b/src/editing/terrain/previewterrainshape.h
@@ -15,9 +15,12 @@ protected:
virtual void bindEvent(BasePreview* preview);
virtual void updateEvent();
virtual Color getColor2D(double x, double y, double scaling);
+ virtual void toggleChangeEvent(QString key, bool value);
private:
TerrainDefinition* _terrain;
+ bool _highlight_enabled;
+ double _water_height;
};
#endif // PREVIEWTERRAINSHAPE_H
diff --git a/src/editing/widgetheightmap.cpp b/src/editing/terrain/widgetheightmap.cpp
similarity index 99%
rename from src/editing/widgetheightmap.cpp
rename to src/editing/terrain/widgetheightmap.cpp
index cd13d71..f6cde1e 100644
--- a/src/editing/widgetheightmap.cpp
+++ b/src/editing/terrain/widgetheightmap.cpp
@@ -35,8 +35,8 @@ QGLWidget(parent)
_average_frame_time = 0.0;
_last_brush_action = 0;
- _last_mouse_x = 0;
- _last_mouse_y = 0;
+ _last_mouse_x = 250;
+ _last_mouse_y = 250;
_last_time = QDateTime::currentDateTime();
_mouse_moved = false;
diff --git a/src/editing/widgetheightmap.h b/src/editing/terrain/widgetheightmap.h
similarity index 100%
rename from src/editing/widgetheightmap.h
rename to src/editing/terrain/widgetheightmap.h
diff --git a/src/editing/terrain/widgetterrainbasenoisepreview.cpp b/src/editing/terrain/widgetterrainbasenoisepreview.cpp
new file mode 100644
index 0000000..aacdc99
--- /dev/null
+++ b/src/editing/terrain/widgetterrainbasenoisepreview.cpp
@@ -0,0 +1,45 @@
+#include "widgetterrainbasenoisepreview.h"
+
+#include
+#include
+#include "tools.h"
+
+WidgetTerrainBaseNoisePreview::WidgetTerrainBaseNoisePreview(QWidget* parent) :
+ QWidget(parent)
+{
+ _noise = NULL;
+}
+
+void WidgetTerrainBaseNoisePreview::setNoise(NoiseGenerator* noise)
+{
+ _noise = noise;
+ update();
+}
+
+void WidgetTerrainBaseNoisePreview::paintEvent(QPaintEvent* event)
+{
+ QPainter painter(this);
+
+ painter.setBrush(Qt::SolidPattern);
+ painter.drawRect(rect());
+
+ int height = this->height();
+
+ if (_noise)
+ {
+ QRect boundaries = event->region().boundingRect();
+ double value, factor;
+ double minvalue, maxvalue;
+
+ noiseGetRange(_noise, &minvalue, &maxvalue);
+ factor = ((double)height) / (maxvalue - minvalue);
+
+ for (int x = boundaries.left(); x <= boundaries.right(); x++)
+ {
+ value = noiseGet1DTotal(_noise, 100.0 * ((double)x) / factor);
+
+ painter.setPen(Qt::white);
+ painter.drawLine(x, height - 1 - (value - minvalue) * factor, x, height - 1);
+ }
+ }
+}
diff --git a/src/editing/terrain/widgetterrainbasenoisepreview.h b/src/editing/terrain/widgetterrainbasenoisepreview.h
new file mode 100644
index 0000000..f3e12a5
--- /dev/null
+++ b/src/editing/terrain/widgetterrainbasenoisepreview.h
@@ -0,0 +1,26 @@
+#ifndef _PAYSAGES_EDITING_TERRAIN_WIDGETTERRAINBASENOISEPREVIEW_H_
+#define _PAYSAGES_EDITING_TERRAIN_WIDGETTERRAINBASENOISEPREVIEW_H_
+
+#include
+#include "rendering/noise.h"
+
+class WidgetTerrainBaseNoisePreview : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit WidgetTerrainBaseNoisePreview(QWidget* parent = 0);
+
+ void setNoise(NoiseGenerator* noise);
+
+protected:
+ virtual void paintEvent(QPaintEvent* event);
+
+signals:
+
+public slots:
+
+private:
+ NoiseGenerator* _noise;
+};
+
+#endif
diff --git a/src/rendering/atmosphere/atm_bruneton.c b/src/rendering/atmosphere/atm_bruneton.c
index 64f93ab..1549948 100644
--- a/src/rendering/atmosphere/atm_bruneton.c
+++ b/src/rendering/atmosphere/atm_bruneton.c
@@ -922,6 +922,8 @@ static Color _getInscatterColor(Vector3* _x, double* _t, Vector3 v, Vector3 s, d
static Color _sunColor(Vector3 v, Vector3 s, double r, double mu, double radius)
{
Color transmittance = r <= Rt ? _transmittanceWithShadow(r, mu) : COLOR_WHITE; /* T(x,xo) */
+ double d = _limit(r, mu);
+ radius *= (1.0 + 10.0 * d / Rt); /* Inflating due to lens effect near horizon */
double isun = step(cos(radius * M_PI / 180.0), v3Dot(v, s)) * ISun; /* Lsun */
transmittance.r *= isun;
transmittance.g *= isun;
diff --git a/src/rendering/clouds/clo_definition.c b/src/rendering/clouds/clo_definition.c
index 1bdf822..845c3d9 100644
--- a/src/rendering/clouds/clo_definition.c
+++ b/src/rendering/clouds/clo_definition.c
@@ -112,7 +112,7 @@ void cloudsLayerValidateDefinition(CloudsLayerDefinition* definition)
break;
}
- noiseNormalizeAmplitude(definition->_coverage_noise, 0.0, 1.0, 0);
+ noiseNormalizeAmplitude(definition->_coverage_noise, -1.0, 3.0, 0);
noiseNormalizeAmplitude(definition->_shape_noise, -0.5, 0.5, 0);
}
diff --git a/src/rendering/clouds/clo_preview.c b/src/rendering/clouds/clo_preview.c
index df39f87..5a0afa6 100644
--- a/src/rendering/clouds/clo_preview.c
+++ b/src/rendering/clouds/clo_preview.c
@@ -18,7 +18,7 @@ Color _fakeApplyLightingToSurface(Renderer* renderer, Vector3 location, Vector3
return COLOR_WHITE;
}
-Renderer* cloudsCreatePreviewCoverageRenderer()
+Renderer* cloudsPreviewCoverageCreateRenderer()
{
Renderer* result = rendererCreate();
result->render_quality = 5;
@@ -26,7 +26,15 @@ Renderer* cloudsCreatePreviewCoverageRenderer()
return result;
}
-Color cloudsGetPreviewCoverage(Renderer* renderer, double x, double y, double scaling, int perspective)
+void cloudsPreviewCoverageBindLayer(Renderer* renderer, CloudsLayerDefinition* layer)
+{
+ CloudsDefinition* definition = (CloudsDefinition*)CloudsDefinitionClass.create();
+ layersAddLayer(definition->layers, layer);
+ CloudsRendererClass.bind(renderer, definition);
+ CloudsDefinitionClass.destroy(definition);
+}
+
+Color cloudsPreviewCoverageGetPixel(Renderer* renderer, double x, double y, double scaling, int perspective)
{
if (perspective)
{
@@ -55,25 +63,91 @@ Color cloudsGetPreviewCoverage(Renderer* renderer, double x, double y, double sc
}
}
-Renderer* cloudsCreatePreviewColorRenderer()
+static void _getLightingStatus(Renderer* renderer, LightStatus* status, Vector3 normal, int opaque)
+{
+ LightDefinition light;
+
+ UNUSED(renderer);
+ UNUSED(normal);
+ UNUSED(opaque);
+
+ light.color.r = 1.0;
+ light.color.g = 1.0;
+ light.color.b = 1.0;
+ light.direction.x = -1.0;
+ light.direction.y = -0.5;
+ light.direction.z = 1.0;
+ light.direction = v3Normalize(light.direction);
+ light.altered = 1;
+ light.reflection = 0.0;
+ lightingPushLight(status, &light);
+
+ light.color.r = 0.2;
+ light.color.g = 0.2;
+ light.color.b = 0.2;
+ light.direction.x = 1.0;
+ light.direction.y = -0.5;
+ light.direction.z = -1.0;
+ light.direction = v3Normalize(light.direction);
+ light.altered = 0;
+ light.reflection = 0.0;
+ lightingPushLight(status, &light);
+}
+
+Renderer* cloudsPreviewMaterialCreateRenderer()
{
Renderer* result = rendererCreate();
result->render_quality = 8;
+ result->atmosphere->getLightingStatus = _getLightingStatus;
return result;
}
-Color cloudsGetPreviewColor(Renderer* renderer, double x, double y)
+static double _getDensity(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 location)
+{
+ UNUSED(renderer);
+ UNUSED(layer);
+
+ double distance = v3Norm(location);
+ if (distance > 1.0)
+ {
+ return 0.0;
+ }
+ else if (distance < 0.8)
+ {
+ return 1.0;
+ }
+ else
+ {
+ return (1.0 - distance) / 0.2;
+ }
+}
+
+void cloudsPreviewMaterialBindLayer(Renderer* renderer, CloudsLayerDefinition* layer)
+{
+ CloudsDefinition* definition = (CloudsDefinition*)CloudsDefinitionClass.create();
+ layersAddLayer(definition->layers, layer);
+ CloudsRendererClass.bind(renderer, definition);
+ CloudsDefinitionClass.destroy(definition);
+
+ layer = layersGetLayer(renderer->clouds->definition->layers, 0);
+ layer->lower_altitude = -1.0;
+ layer->thickness = 2.0;
+
+ renderer->clouds->getLayerDensity = _getDensity;
+}
+
+Color cloudsPreviewMaterialGetPixel(Renderer* renderer, double x, double y)
{
Vector3 start, end;
- double thickness = 0.5;
+ double thickness = 2.0;
start.x = x * thickness * 0.5;
- start.y = -y * thickness * 0.5;
- start.z = thickness * 0.5;
+ start.z = y * thickness * 0.5;
+ start.y = thickness * 0.5;
end.x = start.x;
- end.y = start.y;
- end.z = -start.z;
+ end.z = start.z;
+ end.y = -start.y;
return renderer->clouds->getColor(renderer, COLOR_BLUE, start, end);
}
diff --git a/src/rendering/clouds/clo_preview.h b/src/rendering/clouds/clo_preview.h
new file mode 100644
index 0000000..c1bfe35
--- /dev/null
+++ b/src/rendering/clouds/clo_preview.h
@@ -0,0 +1,28 @@
+#ifndef _PAYSAGES_CLOUDS_PREVIEW_H_
+#define _PAYSAGES_CLOUDS_PREVIEW_H_
+
+#include "public.h"
+#include "../tools/euclid.h"
+
+/**
+ * Cloud preview helpers.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+Renderer* cloudsPreviewCoverageCreateRenderer();
+void cloudsPreviewCoverageBindLayer(Renderer* renderer, CloudsLayerDefinition* layer);
+Color cloudsPreviewCoverageGetPixel(Renderer* renderer, double x, double y, double scaling, int perspective);
+
+Renderer* cloudsPreviewMaterialCreateRenderer();
+void cloudsPreviewMaterialBindLayer(Renderer* renderer, CloudsLayerDefinition* layer);
+Color cloudsPreviewMaterialGetPixel(Renderer* renderer, double x, double y);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/rendering/clouds/clo_rendering.c b/src/rendering/clouds/clo_rendering.c
index e5e8ada..1d6abd4 100644
--- a/src/rendering/clouds/clo_rendering.c
+++ b/src/rendering/clouds/clo_rendering.c
@@ -1,9 +1,11 @@
#include "private.h"
+#include
#include
#include "../tools.h"
#include "../renderer.h"
#include "clo_density.h"
+#include "clo_walking.h"
/******************** Fake ********************/
static int _fakeAlterLight(Renderer* renderer, LightDefinition* light, Vector3 location)
@@ -25,24 +27,117 @@ static Color _fakeGetColor(Renderer* renderer, Color base, Vector3 start, Vector
}
/******************** Real ********************/
-/*static int _cmpLayer(const void* layer1, const void* layer2)
+typedef struct
{
- return (((CloudsLayerDefinition*)layer1)->lower_altitude > ((CloudsLayerDefinition*)layer2)->lower_altitude) ? -1 : 1;
-}*/
+ double light_power;
+ double out_scattering; /* Amount of light scattered away by heavy particles */
+} AccumulatedLightData;
+
+static void _walkerFilterCallback(CloudsWalker* walker)
+{
+ CloudWalkerStepInfo* segment = cloudsWalkerGetLastSegment(walker);
+ AccumulatedLightData* data = (AccumulatedLightData*)segment->data;
+
+ assert(data != NULL);
+
+ double density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
+
+ data->out_scattering += 0.3 * density_integral;
+
+ if (data->out_scattering > data->light_power)
+ {
+ cloudsWalkerOrderStop(walker);
+ }
+}
static int _alterLight(Renderer* renderer, LightDefinition* light, Vector3 location)
{
CloudsDefinition* definition = renderer->clouds->definition;
int i, n;
+ AccumulatedLightData data;
+ data.out_scattering = 0.0;
+ data.light_power = colorGetPower(&light->color);
+
/* TODO Iter layers in sorted order */
n = layersCount(definition->layers);
for (i = 0; i < n; i++)
{
- light->color = cloudsLayerFilterLight(layersGetLayer(definition->layers, i), renderer, light->color, location, v3Add(location, v3Scale(light->direction, -10000.0)), v3Scale(light->direction, -1.0));
- /* TODO Reduce light->reflection too */
+ CloudsLayerDefinition* layer = (CloudsLayerDefinition*)layersGetLayer(renderer->clouds->definition->layers, i);
+ Vector3 ostart, oend;
+
+ ostart = location;
+ oend = v3Add(location, v3Scale(light->direction, -10000.0));
+ if (!cloudsOptimizeWalkingBounds(layer, &ostart, &oend))
+ {
+ continue;
+ }
+ else
+ {
+ CloudsWalker* walker;
+
+ walker = cloudsCreateWalker(renderer, layer, ostart, oend);
+ cloudsWalkerSetStepSize(walker, -1.0);
+ cloudsStartWalking(walker, _walkerFilterCallback, &data);
+ cloudsDeleteWalker(walker);
+ }
}
- return n > 0;
+
+ double max_power = colorGetPower(&light->color) - data.out_scattering;
+ if (max_power < 0.0)
+ {
+ light->color = COLOR_BLACK;
+ }
+ else
+ {
+ colorLimitPower(&light->color, max_power);
+ }
+
+ return data.out_scattering > 0.0;
+}
+
+typedef struct
+{
+ double out_scattering; /* Amount of light scattered away by heavy particles */
+ Color in_scattering; /* Amount of light redirected toward the viewer */
+} AccumulatedMaterialData;
+
+static inline void _applyOutScattering(Color* col, double out_scattering)
+{
+ if (out_scattering >= 1.0)
+ {
+ col->r = col->g = col->b = 0.0;
+ }
+ else
+ {
+ col->r *= (1.0 - out_scattering);
+ col->g *= (1.0 - out_scattering);
+ col->b *= (1.0 - out_scattering);
+ }
+}
+
+static void _walkerMaterialCallback(CloudsWalker* walker)
+{
+ CloudWalkerStepInfo* segment = cloudsWalkerGetLastSegment(walker);
+ AccumulatedMaterialData* data = (AccumulatedMaterialData*)segment->data;
+ Renderer* renderer = segment->renderer;
+ CloudsLayerDefinition* layer = segment->layer;
+
+ assert(data != NULL);
+
+ double density_integral = segment->length * (segment->start.global_density + segment->end.global_density) / 2.0;
+
+ data->out_scattering += 0.5 * density_integral;
+
+ Color in_scattering = renderer->applyLightingToSurface(renderer, segment->start.location, VECTOR_UP, &layer->material);
+ in_scattering.r *= density_integral * 5.0;
+ in_scattering.g *= density_integral * 5.0;
+ in_scattering.b *= density_integral * 5.0;
+ _applyOutScattering(&in_scattering, data->out_scattering);
+
+ data->in_scattering.r += in_scattering.r;
+ data->in_scattering.g += in_scattering.g;
+ data->in_scattering.b += in_scattering.b;
}
static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 end)
@@ -59,7 +154,39 @@ static Color _getColor(Renderer* renderer, Color base, Vector3 start, Vector3 en
/* TODO Iter layers in sorted order */
for (i = 0; i < n; i++)
{
- base = cloudsApplyLayer(layersGetLayer(definition->layers, i), base, renderer, start, end);
+ CloudsLayerDefinition* layer = (CloudsLayerDefinition*)layersGetLayer(renderer->clouds->definition->layers, i);
+ Vector3 ostart, oend;
+
+ ostart = start;
+ oend = end;
+ if (!cloudsOptimizeWalkingBounds(layer, &ostart, &oend))
+ {
+ continue;
+ }
+ else
+ {
+ CloudsWalker* walker;
+ AccumulatedMaterialData data;
+ data.out_scattering = 0.0;
+ data.in_scattering = COLOR_BLACK;
+
+ walker = cloudsCreateWalker(renderer, layer, ostart, oend);
+ cloudsWalkerSetStepSize(walker, -1.0);
+ cloudsStartWalking(walker, _walkerMaterialCallback, &data);
+ cloudsDeleteWalker(walker);
+
+ /* Apply final out_scattering to base */
+ _applyOutScattering(&base, data.out_scattering);
+
+ /* Apply in_scattering */
+ base.r += data.in_scattering.r;
+ base.g += data.in_scattering.g;
+ base.b += data.in_scattering.b;
+
+ /* Apply aerial perspective approximation */
+ /* TODO This should be done at cloud entry */
+ base = renderer->atmosphere->applyAerialPerspective(renderer, ostart, base).final;
+ }
}
return base;
diff --git a/src/rendering/clouds/clo_tools.c b/src/rendering/clouds/clo_tools.c
deleted file mode 100644
index 5337e54..0000000
--- a/src/rendering/clouds/clo_tools.c
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "private.h"
-
-/*
- * Clouds tools.
- */
-
-#include "clo_walking.h"
-#include "../renderer.h"
-#include "../tools.h"
-
-static inline Vector3 _getNormal(CloudsLayerDefinition* layer, Vector3 position, double detail)
-{
- Vector3 result = {0.0, 0.0, 0.0};
- /*Vector3 dposition;
- double val, dval;
-
- val = _getDistanceToBorder(layer, position);
-
- dposition.x = position.x + detail;
- dposition.y = position.y;
- dposition.z = position.z;
- dval = val - _getDistanceToBorder(layer, dposition);
- result.x += dval;
-
- dposition.x = position.x - detail;
- dval = val - _getDistanceToBorder(layer, dposition);
- result.x -= dval;
-
- dposition.x = position.x;
- dposition.y = position.y + detail;
- dval = val - _getDistanceToBorder(layer, dposition);
- result.y += dval;
-
- dposition.y = position.y - detail;
- dval = val - _getDistanceToBorder(layer, dposition);
- result.y -= dval;
-
- dposition.y = position.y;
- dposition.z = position.z + detail;
- dval = val - _getDistanceToBorder(layer, dposition);
- result.z += dval;
-
- dposition.z = position.z - detail;
- dval = val - _getDistanceToBorder(layer, dposition);
- result.z -= dval;*/
-
- return v3Normalize(result);
-}
-
-static Color _applyLayerLighting(CloudsLayerDefinition* definition, Renderer* renderer, Vector3 location, double detail)
-{
- Vector3 normal;
- Color col1, col2;
- LightStatus* lighting;
-
- normal = _getNormal(definition, location, 3.0);
- if (renderer->render_quality > 3)
- {
- normal = v3Add(normal, _getNormal(definition, location, 2.0));
- normal = v3Add(normal, _getNormal(definition, location, 1.0));
- }
- if (renderer->render_quality > 5)
- {
- normal = v3Add(normal, _getNormal(definition, location, 0.5));
- }
- if (renderer->render_quality > 8)
- {
- normal = v3Add(normal, _getNormal(definition, location, 0.75));
- normal = v3Add(normal, _getNormal(definition, location, 1.25));
- normal = v3Add(normal, _getNormal(definition, location, 2.5));
- }
- normal = v3Scale(v3Normalize(normal), definition->hardness);
-
- return renderer->applyLightingToSurface(renderer, location, normal, &definition->material);
-
- lighting = lightingCreateStatus(renderer->lighting, location, renderer->getCameraLocation(renderer, location));
- renderer->atmosphere->getLightingStatus(renderer, lighting, normal, 0);
- col1 = lightingApplyStatus(lighting, normal, &definition->material);
- col2 = lightingApplyStatus(lighting, v3Scale(normal, -1.0), &definition->material);
- lightingDeleteStatus(lighting);
-
- col1.r = (col1.r + col2.r) / 2.0;
- col1.g = (col1.g + col2.g) / 2.0;
- col1.b = (col1.b + col2.b) / 2.0;
- col1.a = (col1.a + col2.a) / 2.0;
-
- return col1;
-}
-
-Color cloudsApplyLayer(CloudsLayerDefinition* definition, Color base, Renderer* renderer, Vector3 start, Vector3 end)
-{
- int segment_count;
- Color col;
- CloudPrimarySegment segments[MAX_SEGMENT_COUNT];
-
- segment_count = cloudsGetLayerPrimarySegments(renderer, definition, start, end, MAX_SEGMENT_COUNT, segments);
- /* TODO Crawl in segments for render */
-
- col = definition->material.base;
- /*if (definition->transparencydepth == 0 || inside_length >= definition->transparencydepth)
- {
- col.a = 1.0;
- }
- else
- {
- col.a = inside_length / definition->transparencydepth;
- }*/
-
- col = renderer->atmosphere->applyAerialPerspective(renderer, start, col).final;
- col.a = 0.0;
-
- colorMask(&base, &col);
-
- return base;
-}
-
-Color cloudsLayerFilterLight(CloudsLayerDefinition* definition, Renderer* renderer, Color light, Vector3 location, Vector3 light_location, Vector3 direction_to_light)
-{
- /*double inside_depth, total_depth, factor;
- CloudSegment segments[MAX_SEGMENT_COUNT];
-
- if (!cloudsOptimizeWalkingBounds(definition, &location, &light_location))
- {
- return light;
- }
-
- _getPrimarySegments(definition, renderer, location, direction_to_light, MAX_SEGMENT_COUNT, definition->lighttraversal, v3Norm(v3Sub(light_location, location)), &inside_depth, &total_depth, segments);
-
- if (definition->lighttraversal < 0.0001)
- {
- factor = 0.0;
- }
- else
- {
- factor = inside_depth / definition->lighttraversal;
- if (factor > 1.0)
- {
- factor = 1.0;
- }
- }
-
- factor = 1.0 - (1.0 - definition->minimumlight) * factor;
-
- light.r = light.r * factor;
- light.g = light.g * factor;
- light.b = light.b * factor;*/
-
- return light;
-}
diff --git a/src/rendering/clouds/clo_walking.c b/src/rendering/clouds/clo_walking.c
index 5efb929..5a84b4c 100644
--- a/src/rendering/clouds/clo_walking.c
+++ b/src/rendering/clouds/clo_walking.c
@@ -2,6 +2,47 @@
#include "../renderer.h"
+/**
+ * Control of the next walking order.
+ */
+typedef enum
+{
+ CLOUD_WALKING_CONTINUE,
+ CLOUD_WALKING_STOP,
+ CLOUD_WALKING_REFINE,
+ CLOUD_WALKING_SUBDIVIDE
+} CloudWalkingOrder;
+
+/**
+ * Additional info for walking orders.
+ */
+typedef struct
+{
+ CloudWalkingOrder order;
+ double precision;
+ int max_segments;
+} CloudWalkingNextAction;
+
+/*
+ * Private structure for the walker.
+ */
+struct CloudsWalker
+{
+ Vector3 start;
+ Vector3 end;
+ Vector3 diff;
+
+ double cursor;
+ double max_length;
+ double step_size;
+
+ int started;
+ CloudWalkerStepInfo last_segment;
+
+ CloudWalkingNextAction next_action;
+};
+
+
int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Vector3* end)
{
Vector3 diff;
@@ -51,107 +92,176 @@ int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Ve
}
}
- /* TODO Limit the search length */
return 1;
}
-int cloudsGetLayerPrimarySegments(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end, int max_segments, CloudPrimarySegment* out_segments)
+CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end)
{
- int inside, segment_count;
- double step_length, segment_length;
- Vector3 diff, walker, segment_start;
- double render_precision, density;
- double diff_length, progress;
+ CloudsWalker* result;
- if (max_segments <= 0)
- {
- return 0;
- }
+ result = (CloudsWalker*)malloc(sizeof (CloudsWalker));
- if (!cloudsOptimizeWalkingBounds(layer, &start, &end))
- {
- return 0;
- }
+ result->start = start;
+ result->end = end;
+ result->diff = v3Sub(end, start);
+ result->max_length = v3Norm(result->diff);
+ result->cursor = 0.0;
+ result->step_size = 1.0;
- diff = v3Sub(end, start);
- diff_length = v3Norm(diff);
+ result->started = 0;
+ result->last_segment.renderer = renderer;
+ result->last_segment.layer = layer;
- if (diff_length < 0.000001)
- {
- return 0;
- }
+ result->next_action.order = CLOUD_WALKING_CONTINUE;
- render_precision = 1.005 - 0.01 * (double)(renderer->render_quality * renderer->render_quality);
- /*if (render_precision > max_total_length / 10.0)
- {
- render_precision = max_total_length / 10.0;
- }
- else if (render_precision < max_total_length / 10000.0)
- {
- render_precision = max_total_length / 10000.0;
- }*/
-
- segment_count = 0;
- segment_length = 0.0;
- density = renderer->clouds->getLayerDensity(renderer, layer, start);
- progress = 0.0;
- step_length = render_precision;
- inside = (density > 0.0);
-
- do
- {
- progress += step_length;
- walker = v3Add(start, v3Scale(diff, progress / diff_length));
-
- if (progress >= diff_length)
- {
- density = 0.0;
- }
- else
- {
- density = renderer->clouds->getLayerDensity(renderer, layer, walker);
- }
-
- if (density > 0.0)
- {
- if (inside)
- {
- /* inside the cloud */
- segment_length += step_length;
- }
- else
- {
- /* entering the cloud */
- segment_length = step_length;
- segment_start = v3Add(start, v3Scale(diff, (progress - step_length) / diff_length));
- /* TODO Refine entry position */
-
- inside = 1;
- }
- }
- else
- {
- if (inside)
- {
- /* exiting the cloud */
- segment_length += step_length;
-
- out_segments->enter = segment_start;
- out_segments->exit = walker;
- out_segments->length = segment_length;
- out_segments++;
- if (++segment_count >= max_segments)
- {
- break;
- }
- /* TODO Refine exit position */
-
- inside = 0;
- }
- }
- /* step = v3Scale(direction, (info.distance_to_edge < render_precision) ? render_precision : info.distance_to_edge); */
- }
- while (inside || (walker.y <= layer->lower_altitude + layer->thickness + 0.001 && walker.y >= layer->lower_altitude - 0.001 && progress < diff_length));
-
- return segment_count;
+ return result;
+}
+
+void cloudsDeleteWalker(CloudsWalker* walker)
+{
+ free(walker);
+}
+
+void cloudsWalkerSetStepSize(CloudsWalker* walker, double step)
+{
+ if (step > 0.0)
+ {
+ walker->step_size = step;
+ }
+ else
+ {
+ /* TODO Automatic settings (using rendering quality and cloud feature size) */
+ walker->step_size = 1.0;
+ }
+}
+
+static void _getPoint(CloudsWalker* walker, double cursor, CloudWalkerPoint* out_point)
+{
+ out_point->distance_from_start = cursor;
+ out_point->location = v3Add(walker->start, v3Scale(walker->diff, out_point->distance_from_start / walker->max_length));
+
+ Renderer* renderer = walker->last_segment.renderer;
+ CloudsLayerDefinition* layer = walker->last_segment.layer;
+ out_point->global_density = renderer->clouds->getLayerDensity(renderer, layer, out_point->location);
+}
+
+static void _refineSegment(CloudsWalker* walker, double start_cursor, double start_density, double end_cursor, double end_density, double precision, CloudWalkerPoint* result)
+{
+ CloudWalkerPoint middle;
+
+ _getPoint(walker, (start_cursor + end_cursor) / 2.0, &middle);
+
+ if (start_density == 0.0)
+ {
+ /* Looking for entry */
+ if (middle.distance_from_start - start_cursor < precision)
+ {
+ *result = middle;
+ }
+ else if (middle.global_density == 0.0)
+ {
+ _refineSegment(walker, middle.distance_from_start, middle.global_density, end_cursor, end_density, precision, result);
+ }
+ else
+ {
+ _refineSegment(walker, start_cursor, start_density, middle.distance_from_start, middle.global_density, precision, result);
+ }
+ }
+ else
+ {
+ /* Looking for exit */
+ if (end_cursor - middle.distance_from_start < precision)
+ {
+ *result = middle;
+ }
+ else if (middle.global_density == 0.0)
+ {
+ _refineSegment(walker, start_cursor, start_density, middle.distance_from_start, middle.global_density, precision, result);
+ }
+ else
+ {
+ _refineSegment(walker, middle.distance_from_start, middle.global_density, end_cursor, end_density, precision, result);
+ }
+ }
+}
+
+int cloudsWalkerPerformStep(CloudsWalker* walker)
+{
+ if (!walker->started)
+ {
+ _getPoint(walker, 0.0, &walker->last_segment.end);
+ walker->started = 1;
+ }
+
+ if (walker->next_action.order == CLOUD_WALKING_STOP || walker->cursor >= walker->max_length)
+ {
+ walker->next_action.order = CLOUD_WALKING_STOP;
+ return 0;
+ }
+ else if (walker->next_action.order == CLOUD_WALKING_CONTINUE)
+ {
+ /* TODO Limit to end */
+ walker->last_segment.start = walker->last_segment.end;
+
+ walker->cursor += walker->step_size;
+
+ _getPoint(walker, walker->cursor, &walker->last_segment.end);
+ walker->last_segment.length = walker->step_size;
+ walker->last_segment.refined = 0;
+
+ return 1;
+ }
+ else if (walker->next_action.order == CLOUD_WALKING_REFINE)
+ {
+ /* Refine segment with dichotomy */
+ _refineSegment(walker,
+ walker->last_segment.start.distance_from_start,
+ walker->last_segment.start.global_density,
+ walker->last_segment.end.distance_from_start,
+ walker->last_segment.end.global_density,
+ walker->next_action.precision,
+ (walker->last_segment.start.global_density == 0.0) ? (&walker->last_segment.start) : (&walker->last_segment.end));
+ walker->last_segment.length = walker->last_segment.end.distance_from_start - walker->last_segment.start.distance_from_start;
+ walker->last_segment.refined = 1;
+
+ walker->next_action.order = CLOUD_WALKING_CONTINUE;
+
+ return 1;
+ }
+ else
+ {
+ /* TODO */
+ return 0;
+ }
+}
+
+void cloudsWalkerOrderStop(CloudsWalker* walker)
+{
+ walker->next_action.order = CLOUD_WALKING_STOP;
+}
+
+void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision)
+{
+ walker->next_action.order = CLOUD_WALKING_REFINE;
+ walker->next_action.precision = precision;
+}
+
+void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments)
+{
+ walker->next_action.order = CLOUD_WALKING_SUBDIVIDE;
+ walker->next_action.max_segments = max_segments;
+}
+
+CloudWalkerStepInfo* cloudsWalkerGetLastSegment(CloudsWalker* walker)
+{
+ return &walker->last_segment;
+}
+
+void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data)
+{
+ walker->last_segment.data = data;
+ while (cloudsWalkerPerformStep(walker))
+ {
+ callback(walker);
+ }
}
diff --git a/src/rendering/clouds/clo_walking.h b/src/rendering/clouds/clo_walking.h
index 2ad19b3..1bd31fc 100644
--- a/src/rendering/clouds/clo_walking.h
+++ b/src/rendering/clouds/clo_walking.h
@@ -15,10 +15,33 @@ extern "C"
typedef struct
{
- Vector3 enter;
- Vector3 exit;
+ double distance_from_start;
+ Vector3 location;
+ double global_density;
+} CloudWalkerPoint;
+
+/**
+ * Information on a segment yielded by walking.
+ */
+typedef struct
+{
+ Renderer* renderer;
+ CloudsLayerDefinition* layer;
+
+ CloudWalkerPoint start;
+ CloudWalkerPoint end;
double length;
-} CloudPrimarySegment;
+
+ int refined;
+ /*int subdivision_level;
+ double precision_asked;*/
+
+ void* data;
+} CloudWalkerStepInfo;
+
+typedef struct CloudsWalker CloudsWalker;
+
+typedef void (*FuncCloudsWalkingCallback)(CloudsWalker* walker);
/**
* Optimize the search limits in a layer.
@@ -31,17 +54,81 @@ typedef struct
int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Vector3* end);
/**
- * Go through the cloud layer to find segments (parts of the lookup that are likely to contain cloud).
+ * Create a cloud walker.
*
- * @param renderer The renderer environment
- * @param layer The cloud layer
- * @param start Start position of the lookup
- * @param end End position of the lookup
- * @param max_segments Maximum number of segments to collect
- * @param out_segments Allocated space to fill found segments
- * @return Number of segments found
+ * For better performance, the segment should by optimized using cloudsOptimizeWalkingBounds.
+ * @param renderer Renderer context
+ * @param layer The cloud layer to traverse
+ * @param start Start of the walk
+ * @param end End of the walk
*/
-int cloudsGetLayerPrimarySegments(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end, int max_segments, CloudPrimarySegment* out_segments);
+CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end);
+
+/**
+ * Delete a cloud walker.
+ *
+ * @param walker The walker to free
+ */
+void cloudsDeleteWalker(CloudsWalker* walker);
+
+/**
+ * Define the segment size for next steps.
+ *
+ * @param walker The walker to configure
+ * @param step The step length, negative for automatic
+ */
+void cloudsWalkerSetStepSize(CloudsWalker* walker, double step);
+
+/**
+ * Perform a single step.
+ *
+ * @param walker The walker to use
+ * @return 1 to continue the loop, 0 to stop
+ */
+int cloudsWalkerPerformStep(CloudsWalker* walker);
+
+/**
+ * Order the walker to stop.
+ *
+ * @param walker The walker to use
+ */
+void cloudsWalkerOrderStop(CloudsWalker* walker);
+
+/**
+ * Order the walker to refine the search for cloud entry or exit.
+ *
+ * The refinement will next yield a shorter version of the segment, containing only the cloud-inside portion, with a
+ * tolerance fixed by precision. For an entry point, this will discard the part before cloud entry. For en exit point,
+ * the portion after this point will be part of the next step, as normal walking resumes.
+ * @param walker The walker to use
+ * @param precision Precision wanted for the refinement
+ */
+void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision);
+
+/**
+ * Order the walker to subdivide the previous segment in smaller segments.
+ *
+ * @param walker The walker to use
+ * @param max_segments Maximal number of segments
+ */
+void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments);
+
+/**
+ * Get the last segment information.
+ *
+ * @param walker The walker to use
+ */
+CloudWalkerStepInfo* cloudsWalkerGetLastSegment(CloudsWalker* walker);
+
+/**
+ * Start walking automatically through a segment.
+ *
+ * The callback will be called with each segment found, giving info and asking for desired alteration on walking.
+ * @param walker The walker to use
+ * @param callback Callback to be called with each found segment
+ * @param data User data that will be passed back in the callback
+ */
+void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data);
#ifdef __cplusplus
}
diff --git a/src/rendering/clouds/public.h b/src/rendering/clouds/public.h
index beded50..283ac27 100644
--- a/src/rendering/clouds/public.h
+++ b/src/rendering/clouds/public.h
@@ -80,12 +80,6 @@ LayerType cloudsGetLayerType();
void cloudsAutoPreset(CloudsDefinition* definition, CloudsPreset preset);
void cloudsLayerAutoPreset(CloudsLayerDefinition* definition, CloudsLayerPreset preset);
-Renderer* cloudsCreatePreviewCoverageRenderer();
-Color cloudsGetPreviewCoverage(Renderer* renderer, double x, double y, double scaling, int perspective);
-
-Renderer* cloudsCreatePreviewColorRenderer();
-Color cloudsGetPreviewColor(Renderer* renderer, double x, double y);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/rendering/main.c b/src/rendering/main.c
index 970e351..3006430 100644
--- a/src/rendering/main.c
+++ b/src/rendering/main.c
@@ -2,6 +2,7 @@
#include
#include "auto.h"
+#include "tools/data.h"
#include "system.h"
#include "scenery.h"
#include "render.h"
@@ -13,6 +14,12 @@
void paysagesInit()
{
systemInit();
+ if (!dataInit())
+ {
+ /* TODO Add error callback (for interface) */
+ fprintf(stderr, "ERROR : Can't locate data files.\n");
+ exit(1);
+ }
openclInit();
sceneryInit();
diff --git a/src/rendering/noise.c b/src/rendering/noise.c
index 5525cc9..60b652f 100644
--- a/src/rendering/noise.c
+++ b/src/rendering/noise.c
@@ -202,17 +202,8 @@ void noiseValidate(NoiseGenerator* generator)
generator->_max_value = generator->height_offset;
for (x = 0; x < generator->level_count; x++)
{
- double min_value = generator->levels[x].minvalue;
- double max_value = min_value + generator->levels[x].amplitude;
-
- if (min_value < generator->_min_value)
- {
- generator->_min_value = min_value;
- }
- if (max_value > generator->_max_value)
- {
- generator->_max_value = max_value;
- }
+ generator->_min_value += generator->levels[x].minvalue;
+ generator->_max_value += generator->levels[x].minvalue + generator->levels[x].amplitude;
}
}
@@ -394,14 +385,14 @@ void noiseNormalizeAmplitude(NoiseGenerator* generator, double minvalue, double
for (level = 0; level < generator->level_count; level++)
{
- generator->levels[level].minvalue = minvalue + (generator->levels[level].minvalue - current_minvalue) * factor;
+ generator->levels[level].minvalue *= factor;
generator->levels[level].amplitude *= factor;
if (adjust_scaling)
{
generator->levels[level].wavelength *= factor;
}
}
- /*generator->height_offset = minvalue + (generator->height_offset - current_minvalue) * factor;*/
+ generator->height_offset = minvalue + (generator->height_offset - current_minvalue) * factor;
noiseValidate(generator);
}
diff --git a/src/rendering/terrain/public.h b/src/rendering/terrain/public.h
index ca83821..905e626 100644
--- a/src/rendering/terrain/public.h
+++ b/src/rendering/terrain/public.h
@@ -81,6 +81,7 @@ typedef struct
/* Heightmap manipulation */
int terrainIsPainted(TerrainHeightMap* heightmap, int x, int z);
+void terrainClearPainting(TerrainHeightMap* heightmap);
void terrainBrushElevation(TerrainHeightMap* heightmap, TerrainBrush* brush, double value);
void terrainBrushSmooth(TerrainHeightMap* heightmap, TerrainBrush* brush, double value);
void terrainBrushAddNoise(TerrainHeightMap* heightmap, TerrainBrush* brush, NoiseGenerator* generator, double value);
diff --git a/src/rendering/terrain/ter_definition.c b/src/rendering/terrain/ter_definition.c
index b61c74a..be387c2 100644
--- a/src/rendering/terrain/ter_definition.c
+++ b/src/rendering/terrain/ter_definition.c
@@ -27,13 +27,13 @@ static TerrainDefinition* _createDefinition()
{
TerrainDefinition* definition = malloc(sizeof(TerrainDefinition));
- definition->height = 0.0;
+ definition->height = 1.0;
definition->scaling = 1.0;
definition->shadow_smoothing = 0.0;
definition->height_map = terrainHeightMapCreate(definition);
- definition->water_height = -0.8;
+ definition->water_height = -0.3;
definition->_height_noise = noiseCreateGenerator();
diff --git a/src/rendering/terrain/ter_painting.c b/src/rendering/terrain/ter_painting.c
index 3d60890..b94ab59 100644
--- a/src/rendering/terrain/ter_painting.c
+++ b/src/rendering/terrain/ter_painting.c
@@ -454,6 +454,12 @@ int terrainIsPainted(TerrainHeightMap* heightmap, int x, int z)
return _getDataPointer(&heightmap->brush_data, x, z, NULL, NULL, 0) || _getDataPointer(&heightmap->merged_data, x, z, NULL, NULL, 0);
}
+void terrainClearPainting(TerrainHeightMap* heightmap)
+{
+ _clearData(&heightmap->merged_data);
+ _clearData(&heightmap->brush_data);
+}
+
typedef double (*BrushCallback)(TerrainHeightMap* heightmap, TerrainBrush* brush, double x, double z, double basevalue, double influence, double force, void* data);
static inline void _applyBrush(TerrainHeightMap* heightmap, TerrainBrush* brush, double force, void* data, BrushCallback callback)
diff --git a/src/rendering/terrain/ter_presets.c b/src/rendering/terrain/ter_presets.c
index e7236c0..4fd52e0 100644
--- a/src/rendering/terrain/ter_presets.c
+++ b/src/rendering/terrain/ter_presets.c
@@ -19,7 +19,7 @@ void terrainAutoPreset(TerrainDefinition* definition, TerrainPreset preset)
noiseNormalizeAmplitude(definition->_height_noise, -1.0, 1.0, 0);
noiseSetFunctionParams(definition->_height_noise, NOISE_FUNCTION_SIMPLEX, 0.0, 0.0);
definition->scaling = 1.0;
- definition->height = 15.0;
+ definition->height = 30.0;
definition->shadow_smoothing = 0.03;
break;
default:
diff --git a/src/rendering/tools/data.c b/src/rendering/tools/data.c
new file mode 100644
index 0000000..859abe7
--- /dev/null
+++ b/src/rendering/tools/data.c
@@ -0,0 +1,34 @@
+#include "data.h"
+
+#include
+#include
+#include
+
+static const char* _datapath = NULL;
+
+static int _tryDataPath(const char* path)
+{
+ char* buffer;
+
+ buffer = malloc(sizeof (char) * (strlen(path) + 30));
+ strcpy(buffer, path);
+ strcat(buffer, "/.paysages_data");
+
+ FILE* f = fopen(buffer, "r");
+ free(buffer);
+ if (f)
+ {
+ _datapath = path;
+ fclose(f);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int dataInit()
+{
+ return _tryDataPath("./data");
+}
diff --git a/src/rendering/tools/data.h b/src/rendering/tools/data.h
new file mode 100644
index 0000000..f5c77b1
--- /dev/null
+++ b/src/rendering/tools/data.h
@@ -0,0 +1,10 @@
+#ifndef _PAYSAGES_TOOLS_DATA_H_
+#define _PAYSAGES_TOOLS_DATA_H_
+
+/*
+ * Data directory management.
+ */
+
+int dataInit();
+
+#endif
diff --git a/src/testing/common.h b/src/testing/common.h
index e06d1ad..1992adb 100644
--- a/src/testing/common.h
+++ b/src/testing/common.h
@@ -29,6 +29,11 @@ static inline void _add_methods_to_case(TCase* tc, ...)
suite_add_tcase(s, tc); \
}
+/***** Boolean assertions *****/
+#define ck_assert_true(_X_) ck_assert_int_ne((_X_), 0)
+#define ck_assert_false(_X_) ck_assert_int_eq((_X_), 0)
+
+/***** Floating point assertions *****/
static inline int _double_equals(double x, double y)
{
return fabs(x - y) < 0.00000000001;
@@ -39,7 +44,7 @@ static inline int _double_not_equals(double x, double y)
}
static inline int _double_greater(double x, double y)
{
- return _double_not_equals(x, y) || (x > y);
+ return _double_not_equals(x, y) && (x > y);
}
static inline int _double_greater_or_equal(double x, double y)
{
@@ -47,7 +52,7 @@ static inline int _double_greater_or_equal(double x, double y)
}
static inline int _double_less(double x, double y)
{
- return _double_not_equals(x, y) || (x < y);
+ return _double_not_equals(x, y) && (x < y);
}
static inline int _double_less_or_equal(double x, double y)
{
@@ -58,8 +63,8 @@ static inline int _double_less_or_equal(double x, double 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)
#define ck_assert_double_gt(X, Y) _ck_assert_double(_double_greater, X, >, Y)
-#define ck_assert_double_lt(X, Y) _ck_assert_double(_double_greater_or_equal, X, >=, Y)
-#define ck_assert_double_gte(X, Y) _ck_assert_double(_double_less, X, <, Y)
+#define ck_assert_double_lt(X, Y) _ck_assert_double(_double_less, X, <, Y)
+#define ck_assert_double_gte(X, Y) _ck_assert_double(_double_greater_or_equal, X, >=, Y)
#define ck_assert_double_lte(X, Y) _ck_assert_double(_double_less_or_equal, X, <=, Y)
diff --git a/src/testing/main.c b/src/testing/main.c
index aebbe85..df8b459 100644
--- a/src/testing/main.c
+++ b/src/testing/main.c
@@ -9,6 +9,7 @@ extern void test_euclid_case(Suite* s);
extern void test_camera_case(Suite* s);
extern void test_clouds_case(Suite* s);
extern void test_render_case(Suite* s);
+extern void test_noise_case(Suite* s);
int main(int argc, char** argv)
{
@@ -24,6 +25,7 @@ int main(int argc, char** argv)
test_camera_case(s);
test_clouds_case(s);
test_render_case(s);
+ test_noise_case(s);
SRunner *sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
diff --git a/src/testing/test_clouds.c b/src/testing/test_clouds.c
index 7ab715e..4d255c3 100644
--- a/src/testing/test_clouds.c
+++ b/src/testing/test_clouds.c
@@ -200,11 +200,9 @@ static double _getLayerDensitySinX(Renderer* renderer, CloudsLayerDefinition* la
return (density > 0.0) ? density : 0.0;
}
-START_TEST(test_clouds_primary_segments)
+START_TEST(test_clouds_walking)
{
- int segment_count, i;
- CloudPrimarySegment segments[10];
-
+ /* Init */
CloudsLayerDefinition* layer;
layer = cloudsGetLayerType().callback_create();
layer->lower_altitude = -1.0;
@@ -217,36 +215,88 @@ START_TEST(test_clouds_primary_segments)
renderer->render_quality = 8;
renderer->clouds->getLayerDensity = _getLayerDensitySinX;
- segment_count = cloudsGetLayerPrimarySegments(renderer, layer, v3(-0.4, 0.0, 0.0), v3(1.9, 0.0, 0.0), 10, segments);
- ck_assert_int_eq(segment_count, 2);
- for (i = 0; i < segment_count; i++)
- {
- ck_assert_double_eq(segments[i].enter.y, 0.0);
- ck_assert_double_eq(segments[i].enter.z, 0.0);
- ck_assert_double_eq(segments[i].exit.y, 0.0);
- ck_assert_double_eq(segments[i].exit.z, 0.0);
- }
- ck_assert_double_in_range(segments[0].enter.x, -0.5, 0.0);
- ck_assert_double_in_range(segments[0].exit.x, 0.5, 1.0);
- ck_assert_double_in_range(segments[0].length, 0.5, 1.5);
- ck_assert_double_gte(segments[1].enter.x, segments[0].exit.x);
- ck_assert_double_in_range(segments[1].enter.x, 0.5, 1.0);
- ck_assert_double_in_range(segments[1].exit.x, 1.5, 2.0);
- ck_assert_double_in_range(segments[1].length, 0.5, 1.5);
+ CloudsWalker* walker = cloudsCreateWalker(renderer, layer, v3(-0.4, 0.0, 0.0), v3(10.0, 0.0, 0.0));
+ CloudWalkerStepInfo* segment;
+ int result;
+
+ /* First step */
+ cloudsWalkerSetStepSize(walker, 0.3);
+ result = cloudsWalkerPerformStep(walker);
+ segment = cloudsWalkerGetLastSegment(walker);
+ ck_assert_int_eq(result, 1);
+ ck_assert_false(segment->refined);
+ ck_assert_double_eq(segment->length, 0.3);
+ ck_assert_double_eq(segment->start.distance_from_start, 0.0);
+ ck_assert_vector_values(segment->start.location, -0.4, 0.0, 0.0);
+ ck_assert_double_eq(segment->start.global_density, 0.0);
+ ck_assert_double_eq(segment->end.distance_from_start, 0.3);
+ ck_assert_vector_values(segment->end.location, -0.1, 0.0, 0.0);
+ ck_assert_double_eq(segment->end.global_density, 0.0);
+
+ /* Second step */
+ result = cloudsWalkerPerformStep(walker);
+ segment = cloudsWalkerGetLastSegment(walker);
+ ck_assert_int_eq(result, 1);
+ ck_assert_false(segment->refined);
+ ck_assert_double_eq(segment->length, 0.3);
+ ck_assert_double_eq(segment->start.distance_from_start, 0.3);
+ ck_assert_vector_values(segment->start.location, -0.1, 0.0, 0.0);
+ ck_assert_double_eq(segment->start.global_density, 0.0);
+ ck_assert_double_eq(segment->end.distance_from_start, 0.6);
+ ck_assert_vector_values(segment->end.location, 0.2, 0.0, 0.0);
+ ck_assert_double_gt(segment->end.global_density, 0.9);
+
+ /* Order to refine second step around the entry point */
+ cloudsWalkerOrderRefine(walker, 0.01);
+ result = cloudsWalkerPerformStep(walker);
+ segment = cloudsWalkerGetLastSegment(walker);
+ ck_assert_int_eq(result, 1);
+ ck_assert_true(segment->refined);
+ ck_assert_double_in_range(segment->length, 0.19, 0.20);
+ ck_assert_double_in_range(segment->start.distance_from_start, 0.40, 0.41);
+ ck_assert_double_in_range(segment->start.location.x, 0.0, 0.01);
+ ck_assert_double_gt(segment->start.global_density, 0.0);
+ ck_assert_double_eq(segment->end.distance_from_start, 0.6);
+ ck_assert_vector_values(segment->end.location, 0.2, 0.0, 0.0);
+ ck_assert_double_gt(segment->end.global_density, 0.9);
+
+ /* Third step, change step size */
+ cloudsWalkerSetStepSize(walker, 0.4);
+ result = cloudsWalkerPerformStep(walker);
+ segment = cloudsWalkerGetLastSegment(walker);
+ ck_assert_int_eq(result, 1);
+ ck_assert_false(segment->refined);
+ ck_assert_double_eq(segment->length, 0.4);
+ ck_assert_double_eq(segment->start.distance_from_start, 0.6);
+ ck_assert_vector_values(segment->start.location, 0.2, 0.0, 0.0);
+ ck_assert_double_gt(segment->start.global_density, 0.9);
+ ck_assert_double_eq(segment->end.distance_from_start, 1.0);
+ ck_assert_vector_values(segment->end.location, 0.6, 0.0, 0.0);
+ ck_assert_double_eq(segment->end.global_density, 0.0);
+
+ /* Refine exit point */
+ cloudsWalkerOrderRefine(walker, 0.001);
+ result = cloudsWalkerPerformStep(walker);
+ segment = cloudsWalkerGetLastSegment(walker);
+ ck_assert_int_eq(result, 1);
+ ck_assert_true(segment->refined);
+ ck_assert_double_in_range(segment->length, 0.3, 0.301);
+ ck_assert_double_eq(segment->start.distance_from_start, 0.6);
+ ck_assert_vector_values(segment->start.location, 0.2, 0.0, 0.0);
+ ck_assert_double_gt(segment->start.global_density, 0.9);
+ ck_assert_double_in_range(segment->end.distance_from_start, 0.9, 0.901);
+ ck_assert_double_in_range(segment->end.location.x, 0.5, 0.501);
+ ck_assert_double_lt(segment->end.global_density, 0.1);
+
+ /* Clean up */
+ cloudsDeleteWalker(walker);
cloudsGetLayerType().callback_delete(layer);
rendererDelete(renderer);
}
END_TEST
-START_TEST(test_clouds_preview_color)
-{
- Renderer* renderer = cloudsCreatePreviewColorRenderer();
-
- /* TODO Test the density overriding */
-
- rendererDelete(renderer);
-}
-END_TEST
-
-TEST_CASE(clouds, test_clouds_density, test_clouds_walking_boundaries, test_clouds_primary_segments, test_clouds_preview_color)
+TEST_CASE(clouds,
+ test_clouds_density,
+ test_clouds_walking_boundaries,
+ test_clouds_walking)
diff --git a/src/testing/test_noise.c b/src/testing/test_noise.c
new file mode 100644
index 0000000..5ab413e
--- /dev/null
+++ b/src/testing/test_noise.c
@@ -0,0 +1,78 @@
+#include "testing/common.h"
+
+#include "rendering/noise.h"
+
+START_TEST(test_noise_range)
+{
+ NoiseGenerator* noise;
+ double minvalue, maxvalue;
+
+ noise = noiseCreateGenerator();
+
+ noiseAddLevelSimple(noise, 0.1, -1.0, 1.0);
+ noiseAddLevelSimple(noise, 0.2, -0.5, 0.2);
+ noiseAddLevelSimple(noise, 0.4, -0.3, 1.2);
+ noiseValidate(noise);
+ noiseGetRange(noise, &minvalue, &maxvalue);
+
+ ck_assert_double_eq(minvalue, -1.8);
+ ck_assert_double_eq(maxvalue, 2.4);
+}
+END_TEST
+
+START_TEST(test_noise_normalize)
+{
+ int x;
+ NoiseGenerator* noise;
+
+ noise = noiseCreateGenerator();
+
+ /* Symmetric case */
+ noiseAddLevelsSimple(noise, 10, 1.0, -4.0, 4.0, 0.5);
+ noiseValidate(noise);
+ noiseNormalizeAmplitude(noise, -1.0, 1.0, 0);
+ for (x = 0; x < 1000; x++)
+ {
+ double value = noiseGet1DTotal(noise, 0.01 * (double)x);
+ ck_assert_double_in_range(value, -1.0, 1.0);
+ }
+
+ /* Target center differs from current center */
+ noiseClearLevels(noise);
+ noiseAddLevelsSimple(noise, 10, 1.0, -5.0, 5.0, 0.5);
+ noiseValidate(noise);
+ noiseNormalizeAmplitude(noise, 0.0, 1.0, 0);
+ for (x = 0; x < 1000; x++)
+ {
+ double value = noiseGet1DTotal(noise, 0.01 * (double)x);
+ ck_assert_double_in_range(value, 0.0, 1.0);
+ }
+
+ /* Asymmetric range */
+ noiseClearLevels(noise);
+ noiseAddLevelsSimple(noise, 10, 1.0, 0.0, 10.0, 0.0);
+ noiseValidate(noise);
+ noiseNormalizeAmplitude(noise, 0.0, 1.0, 0);
+ for (x = 0; x < 1000; x++)
+ {
+ double value = noiseGet1DTotal(noise, 0.01 * (double)x);
+ ck_assert_double_in_range(value, 0.0, 1.0);
+ }
+
+ /* Complex asymmetric case */
+ noiseClearLevels(noise);
+ noiseAddLevelsSimple(noise, 3, 1.0, -2.0, 8.0, 0.3);
+ noiseValidate(noise);
+ noiseNormalizeAmplitude(noise, -2.0, 4.0, 0.0);
+ for (x = 0; x < 1000; x++)
+ {
+ double value = noiseGet1DTotal(noise, 0.01 * (double)x);
+ ck_assert_double_in_range(value, -2.0, 4.0);
+ }
+
+ noiseDeleteGenerator(noise);
+}
+END_TEST
+
+TEST_CASE(noise, test_noise_range, test_noise_normalize)
+