paysages : WIP on several parts.

git-svn-id: https://subversion.assembla.com/svn/thunderk/paysages@516 b1fd45b6-86a6-48da-8261-f70d1f35bdcc
This commit is contained in:
Michaël Lemaire 2013-02-05 21:25:30 +00:00 committed by ThunderK
parent 22ed375111
commit 47ebc90552
20 changed files with 273 additions and 94 deletions

View file

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

View file

@ -6,6 +6,10 @@
#include <QColor>
#include <QPainter>
#include <QMessageBox>
#include <QFileDialog>
#include <QMessageBox>
#include <QListWidget>
#include <QPushButton>
#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);

View file

@ -6,6 +6,8 @@
#include <QThread>
#include <QProgressBar>
#include <QScrollArea>
#include <QSlider>
#include <QComboBox>
#include <QLabel>
#include <QMutex>
#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;

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,5 @@
#include "formrender.h"
#include <QFileDialog>
#include <QMessageBox>
#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));
}
}
}
}

View file

@ -28,7 +28,6 @@ protected slots:
private slots:
void startRender();
void showRender();
void saveRender();
private:
RenderParams _params;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,6 +9,7 @@
#include <string.h>
#include <math.h>
#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;
}

View file

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

View file

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

View file

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

View file

@ -1,11 +1,54 @@
#include "memory.h"
#include <stdlib.h>
#include <string.h>
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)