diff --git a/TODO b/TODO index 1d60719..55a1aa5 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,9 @@ Technology Preview 2 : -- Replace zone ranges with curves. -- Interface for textures thickness, slope_range and thickness_transparency. +- Replace zone ranges with curves (with curve input and curve dialog). +- Interface for textures thickness, slope_range and thickness_transparency (and correct slider ranges). - Render tab previews should not rerender when changing render options. - Compute shadows only once for all textures at a same location. => Add an intermediary light status (two pass lighting). -- Don't change opacity when scrolling previews. - Add layer sorting/naming. - Save GUI config (views, render params). - Add an OSD ability on previews and use it for camera location and user landmarks. @@ -12,6 +11,7 @@ Technology Preview 2 : - Add a zone editor dialog for localized textures. - Add a terrain modifier dialog with zones. - Add a noise filler (and maybe noise intervals ?). +- Fix the sun appearance. - Improve curve editor. => Add curve modes => Improve curve rendering @@ -19,7 +19,6 @@ Technology Preview 2 : - Water and terrain LOD moves with the camera, fix it like in the wanderer. - Pause previews drawing of main window when a dialog is opened. - Interrupt preview chunk renderings that will be discarded at commit, or that are no more visible. -- Can't overwrite picture files (ILError). - Fix "RGB parameters out of range" (and segfault) on preview while moving render params fast in render tab. => May need to change the updateData system. => Previews need to be paused while updating data. diff --git a/gui_qt/basepreview.cpp b/gui_qt/basepreview.cpp index 605519a..bb7420a 100644 --- a/gui_qt/basepreview.cpp +++ b/gui_qt/basepreview.cpp @@ -519,8 +519,8 @@ void BasePreview::mouseMoveEvent(QMouseEvent* event) } QImage part = pixbuf->copy(xstart, ystart, xsize, ysize); - QPainter painter(pixbuf); pixbuf->fill(0x00000000); + QPainter painter(pixbuf); painter.drawImage(xstart + ndx, ystart + ndy, part); updateChunks(); @@ -597,8 +597,8 @@ void BasePreview::wheelEvent(QWheelEvent* event) new_width = (int) floor(((double) width) * scaling / old_scaling); new_height = (int) floor(((double) height) * scaling / old_scaling); QImage part = pixbuf->copy((width - new_width) / 2, (height - new_height) / 2, new_width, new_height).scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - QPainter painter(pixbuf); pixbuf->fill(0x00000000); + QPainter painter(pixbuf); painter.drawImage(0, 0, part); invalidatePixbuf(254); lock_drawing->unlock(); @@ -609,8 +609,8 @@ void BasePreview::wheelEvent(QWheelEvent* event) { lock_drawing->lock(); QImage part = pixbuf->scaled((int) floor(((double) width) * old_scaling / scaling), (int) floor(((double) height) * old_scaling / scaling), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - QPainter painter(pixbuf); pixbuf->fill(0x00000000); + QPainter painter(pixbuf); painter.drawImage((width - part.width()) / 2, (height - part.height()) / 2, part); invalidatePixbuf(254); lock_drawing->unlock(); diff --git a/gui_qt/formrender.cpp b/gui_qt/formrender.cpp index 48e3247..5b1cd88 100644 --- a/gui_qt/formrender.cpp +++ b/gui_qt/formrender.cpp @@ -201,8 +201,14 @@ void FormRender::saveRender() { filepath = filepath.append(".png"); } - renderSaveToFile(_renderer.render_area, (char*)filepath.toStdString().c_str()); - QMessageBox::information(this, "Message", QString(tr("The picture %1 has been saved.")).arg(filepath)); + if (renderSaveToFile(_renderer.render_area, (char*)filepath.toStdString().c_str())) + { + QMessageBox::information(this, "Message", QString(tr("The picture %1 has been saved.")).arg(filepath)); + } + else + { + QMessageBox::critical(this, "Message", QString(tr("Can't write to file : %1")).arg(filepath)); + } } } } diff --git a/gui_qt/formtextures.cpp b/gui_qt/formtextures.cpp index f700156..89cc5ad 100644 --- a/gui_qt/formtextures.cpp +++ b/gui_qt/formtextures.cpp @@ -97,7 +97,7 @@ public: _zone = zoneCreate(); - configScaling(0.1, 10.0, 0.1, 1.0); + configScaling(0.01, 1.0, 0.01, 0.1); configScrolling(-1000.0, 1000.0, 0.0, -1000.0, 1000.0, 0.0); } protected: diff --git a/i18n/paysages_fr.ts b/i18n/paysages_fr.ts index 6338424..d6bd209 100644 --- a/i18n/paysages_fr.ts +++ b/i18n/paysages_fr.ts @@ -407,6 +407,11 @@ Maintenir Ctrl : Plus rapide Images (*.png *.jpg) Images (*.png *.jpg) + + + Can't write to file : %1 + + Images (*.png, *.jpg) Images (*.png *.jpg) @@ -416,7 +421,7 @@ Maintenir Ctrl : Plus rapide Choisissez un nom de fichier pour le rendu - + The picture %1 has been saved. L'image %1 a été sauvegardée. diff --git a/lib_paysages/lighting.c b/lib_paysages/lighting.c index 80b5337..f185010 100644 --- a/lib_paysages/lighting.c +++ b/lib_paysages/lighting.c @@ -149,17 +149,46 @@ void lightingDeleteLight(LightingDefinition* definition, int light) } } -static Color _applyLightCustom(LightDefinition* definition, Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial material) +static int _getLightStatus(LightDefinition* definition, Renderer* renderer, Vector3 location, LightDefinition* result) +{ + Color light; + Vector3 direction_inv; + + light = definition->color; + direction_inv = v3Scale(definition->direction, -1.0); + if (definition->masked) + { + light = renderer->maskLight(renderer, light, location, v3Add(location, v3Scale(direction_inv, 1000.0)), direction_inv); + } + if (definition->filtered) + { + light = renderer->filterLight(renderer, light, location, v3Add(location, v3Scale(direction_inv, 1000.0)), direction_inv); + } + + if (light.r > 0.0 || light.g > 0.0 || light.b > 0.0) + { + *result = *definition; + result->color = light; + return 1; + } + else + { + return 0; + } +} + +static Color _applyDirectLight(LightDefinition* definition, Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial material) { Color result, light; double diffuse, specular, normal_norm; Vector3 view, reflect, direction_inv; light = definition->color; + direction_inv = v3Scale(definition->direction, -1.0); if (definition->amplitude > 0.0) { - // TODO Sampling around light direction + /* TODO Sampling around light direction */ int xsamples, ysamples, samples, x, y; double xstep, ystep, factor; LightDefinition sublight; @@ -178,7 +207,7 @@ static Color _applyLightCustom(LightDefinition* definition, Renderer* renderer, sublight.color.g *= factor; sublight.color.b *= factor; - result = _applyLightCustom(&sublight, renderer, location, normal, material); + result = _applyDirectLight(&sublight, renderer, location, normal, material); for (x = 0; x < xsamples; x++) { for (y = 0; y < ysamples; y++) @@ -186,7 +215,7 @@ static Color _applyLightCustom(LightDefinition* definition, Renderer* renderer, sublight.direction.x = cos(x * xstep) * cos(y * ystep); sublight.direction.y = -sin(y * ystep); sublight.direction.z = sin(x * xstep) * cos(y * ystep); - light = _applyLightCustom(&sublight, renderer, location, normal, material); + light = _applyDirectLight(&sublight, renderer, location, normal, material); result.r += light.r; result.g += light.g; result.b += light.b; @@ -195,16 +224,6 @@ static Color _applyLightCustom(LightDefinition* definition, Renderer* renderer, return result; } - direction_inv = v3Scale(definition->direction, -1.0); - if (definition->masked) - { - light = renderer->maskLight(renderer, light, location, v3Add(location, v3Scale(direction_inv, 1000.0)), direction_inv); - } - if (definition->filtered) - { - light = renderer->filterLight(renderer, light, location, v3Add(location, v3Scale(direction_inv, 1000.0)), direction_inv); - } - normal_norm = v3Norm(normal); if (normal_norm > 1.0) { @@ -213,7 +232,7 @@ static Color _applyLightCustom(LightDefinition* definition, Renderer* renderer, normal = v3Normalize(normal); diffuse = v3Dot(direction_inv, normal); - //diffuse = pow(diffuse * 0.5 + 0.5, 2.0); + /*diffuse = pow(diffuse * 0.5 + 0.5, 2.0);*/ diffuse = diffuse * 0.5 + 0.5; if (diffuse > 0.0) { @@ -255,28 +274,51 @@ static Color _applyLightCustom(LightDefinition* definition, Renderer* renderer, return result; } -Color lightingApplyToSurface(LightingDefinition* definition, Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial material) +void lightingGetStatus(LightingDefinition* definition, Renderer* renderer, Vector3 location, LightStatus* result) +{ + int i; + + result->nblights = 0; + + for (i = 0; i < definition->nblights; i++) + { + if (_getLightStatus(definition->lights + i, renderer, location, result->lights + result->nblights)) + { + result->nblights++; + } + } + for (i = 0; i < definition->_nbautolights; i++) + { + if (_getLightStatus(definition->_autolights + i, renderer, location, result->lights + result->nblights)) + { + result->nblights++; + } + } +} + +Color lightingApplyStatusToSurface(Renderer* renderer, LightStatus* status, Vector3 location, Vector3 normal, SurfaceMaterial material) { Color result, lighted; int i; result = COLOR_BLACK; result.a = material.base.a; - - for (i = 0; i < definition->nblights; i++) + + for (i = 0; i < status->nblights; i++) { - lighted = _applyLightCustom(definition->lights + i, renderer, location, normal, material); + lighted = _applyDirectLight(status->lights + i, renderer, location, normal, material); result.r += lighted.r; result.g += lighted.g; result.b += lighted.b; } - for (i = 0; i < definition->_nbautolights; i++) - { - lighted = _applyLightCustom(definition->_autolights + i, renderer, location, normal, material); - result.r += lighted.r; - result.g += lighted.g; - result.b += lighted.b; - } - + return result; } + +Color lightingApplyToSurface(LightingDefinition* definition, Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial material) +{ + LightStatus status; + + lightingGetStatus(definition, renderer, location, &status); + return lightingApplyStatusToSurface(renderer, &status, location, normal, material); +} diff --git a/lib_paysages/lighting.h b/lib_paysages/lighting.h index 310165c..a56e7b8 100644 --- a/lib_paysages/lighting.h +++ b/lib_paysages/lighting.h @@ -30,6 +30,12 @@ typedef struct LightDefinition _autolights[LIGHTING_MAX_LIGHTS]; } LightingDefinition; +typedef struct +{ + int nblights; + LightDefinition lights[LIGHTING_MAX_LIGHTS * 2]; +} LightStatus; + void lightingInit(); void lightingQuit(); void lightingSave(PackStream* stream, LightingDefinition* definition); @@ -45,6 +51,8 @@ LightDefinition lightingGetLight(LightingDefinition* definition, int light); int lightingAddLight(LightingDefinition* definition, LightDefinition light); void lightingDeleteLight(LightingDefinition* definition, int light); +void lightingGetStatus(LightingDefinition* definition, Renderer* renderer, Vector3 location, LightStatus* result); +Color lightingApplyStatusToSurface(Renderer* renderer, LightStatus* status, Vector3 location, Vector3 normal, SurfaceMaterial material); Color lightingApplyToSurface(LightingDefinition* definition, Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial material); #ifdef __cplusplus diff --git a/lib_paysages/render.c b/lib_paysages/render.c index 6cf535c..b9fbf3b 100644 --- a/lib_paysages/render.c +++ b/lib_paysages/render.c @@ -1,6 +1,7 @@ #include "render.h" #include +#include #include #include "IL/il.h" #include "IL/ilu.h" @@ -745,7 +746,7 @@ void renderPostProcess(RenderArea* area, Renderer* renderer, int nbchunks) _processDirtyPixels(area); } -void renderSaveToFile(RenderArea* area, const char* path) +int renderSaveToFile(RenderArea* area, const char* path) { ILuint image_id; ilGenImages(1, &image_id); @@ -756,6 +757,7 @@ void renderSaveToFile(RenderArea* area, const char* path) ILuint data[area->height * area->width]; ILenum error; Array* pixel_data; + int error_count; for (y = 0; y < area->height; y++) { @@ -769,14 +771,18 @@ void renderSaveToFile(RenderArea* area, const char* path) } ilTexImage((ILuint)area->width, (ILuint)area->height, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, data); + remove(path); ilSaveImage(path); ilDeleteImages(1, &image_id); + error_count = 0; while ((error=ilGetError()) != IL_NO_ERROR) { fprintf(stderr, "IL ERROR : %s\n", iluErrorString(error)); + error_count++; } + return !error_count; } void renderSetPreviewCallbacks(RenderArea* area, RenderCallbackStart start, RenderCallbackDraw draw, RenderCallbackUpdate update) diff --git a/lib_paysages/render.h b/lib_paysages/render.h index 9a566b5..ea27706 100644 --- a/lib_paysages/render.h +++ b/lib_paysages/render.h @@ -25,7 +25,7 @@ void renderPushFragment(RenderArea* area, int x, int y, double z, Vertex* vertex void renderPushTriangle(RenderArea* area, Vertex* v1, Vertex* v2, Vertex* v3, Vector3 p1, Vector3 p2, Vector3 p3); void renderPostProcess(RenderArea* area, Renderer* renderer, int nbchunks); -void renderSaveToFile(RenderArea* area, const char* path); +int renderSaveToFile(RenderArea* area, const char* path); void renderSetPreviewCallbacks(RenderArea* area, RenderCallbackStart start, RenderCallbackDraw draw, RenderCallbackUpdate update); diff --git a/lib_paysages/textures.c b/lib_paysages/textures.c index aabfdf4..effc7a6 100644 --- a/lib_paysages/textures.c +++ b/lib_paysages/textures.c @@ -216,35 +216,6 @@ void texturesDeleteLayer(TexturesDefinition* definition, int layer) } } -Color texturesGetLayerColor(TextureLayerDefinition* definition, Renderer* renderer, Vector3 location, double detail) -{ - Color result; - Vector3 normal; - double coverage, noise; - - result = COLOR_TRANSPARENT; - /*normal = _getPreNormal(definition, renderer, location, detail * 0.1); - - coverage = zoneGetValue(definition->zone, location, normal); - if (coverage > 0.0) - { - if (coverage < 1.0) - { - noise = noiseGet2DTotal(definition->border_noise, location.x * 1000.0, location.z * 1000.0); - coverage = -1.0 + 2.0 * coverage + noise * (1.0 - coverage); - } - if (coverage > 0.0) - { - normal = _getPostNormal(definition, renderer, location, normal, detail * 0.1); - result = renderer->applyLightingToSurface(renderer, location, normal, definition->material); - result.a = coverage < 0.1 ? coverage / 0.1 : 1.0; - } - }*/ - return result; -} - - - static inline Vector3 _getNormal4(Vector3 center, Vector3 north, Vector3 east, Vector3 south, Vector3 west) { Vector3 dnorth, deast, dsouth, dwest, normal; @@ -369,6 +340,11 @@ double texturesGetLayerCoverage(TextureLayerDefinition* definition, Renderer* re return zoneGetValue(definition->zone, base.location, base.normal); } +Color texturesGetLayerColor(TextureLayerDefinition* definition, Renderer* renderer, Vector3 location, double detail) +{ + return _getLayerResult(definition, renderer, location.x, location.z, detail).color; +} + Color texturesGetColor(TexturesDefinition* definition, Renderer* renderer, double x, double z, double detail) { TextureResult results[TEXTURES_MAX_LAYERS + 1];