diff --git a/data/gui.glade b/data/gui.glade index ef7b2ec..72dd9cc 100644 --- a/data/gui.glade +++ b/data/gui.glade @@ -975,7 +975,7 @@ A small entropy will make the noise repeat more often. 5 5 5 - 4 + 6 2 @@ -1050,7 +1050,7 @@ A small entropy will make the noise repeat more often. True False - Base color + Surface color 0 @@ -1092,6 +1092,65 @@ A small entropy will make the noise repeat more often. 1 + + + True + False + Depth color + + + 0 + 4 + 1 + 1 + + + + + True + False + Depth limit + + + 0 + 5 + 1 + 1 + + + + + 100 + True + True + True + start + False + Choose a main water color + rgb(0,0,0) + + + 1 + 4 + 1 + 1 + + + + + 250 + True + True + 2 + 2 + + + 1 + 5 + 1 + 1 + + False diff --git a/src/auto.c b/src/auto.c index e915f2e..0313b95 100644 --- a/src/auto.c +++ b/src/auto.c @@ -170,12 +170,17 @@ void autoGenRealisticLandscape(int seed) /* Water */ water.height = 0.0; - water.transparency = 0.4; - water.reflection = 0.5; + water.transparency = 0.5; + water.reflection = 0.3; + water.transparency_depth = 6.0; water.main_color.r = 0.1; water.main_color.g = 0.3; water.main_color.b = 0.4; water.main_color.a = 1.0; + water.depth_color.r = 0.0; + water.depth_color.g = 0.2; + water.depth_color.b = 0.3; + water.depth_color.a = 1.0; water.height_noise = noiseCreateGenerator(); noiseGenerateBaseNoise(water.height_noise, 262144); noiseAddLevelsSimple(water.height_noise, 2, 0.2, 0.015); diff --git a/src/color.c b/src/color.c index 76d0f66..fdcb216 100644 --- a/src/color.c +++ b/src/color.c @@ -206,4 +206,5 @@ ColorGradation colorGradationLoad(FILE* f) result.parts[i].col = colorLoad(f); } + return result; } diff --git a/src/gui/tab_water.c b/src/gui/tab_water.c index 5746aeb..55eef92 100644 --- a/src/gui/tab_water.c +++ b/src/gui/tab_water.c @@ -14,7 +14,7 @@ static RayCastingResult _rayCastFromWater(Vector3 start, Vector3 direction) { RayCastingResult result; double x, y; - + result.hit = 1; if (direction.z < 0.0001) { @@ -24,7 +24,7 @@ static RayCastingResult _rayCastFromWater(Vector3 start, Vector3 direction) { x = start.x + direction.x * (0.0 - start.z) / direction.z; y = start.y + direction.y * (0.0 - start.z) / direction.z; - + if (((int)ceil(x * 0.2) % 2 == 0) ^ ((int)ceil(y * 0.2 - 0.5) % 2 == 0)) { result.hit_color = COLOR_WHITE; @@ -35,7 +35,7 @@ static RayCastingResult _rayCastFromWater(Vector3 start, Vector3 direction) } } /* TODO hit_location */ - + return result; } @@ -43,7 +43,7 @@ static Color _cbPreviewCoverage(SmallPreview* preview, double x, double y, doubl { Color result; double height; - + height = terrainGetHeight(x, y); if (height <= _definition.height) { @@ -53,7 +53,7 @@ static Color _cbPreviewCoverage(SmallPreview* preview, double x, double y, doubl { result.r = result.g = result.b = terrainGetHeightNormalized(x, y); result.a = 1.0; - + return result; } } @@ -64,7 +64,7 @@ static Color _cbPreviewRender(SmallPreview* preview, double x, double y, double WaterDefinition definition; WaterEnvironment environment; WaterQuality quality; - + eye.x = 0.0; eye.y = scaling; eye.z = -10.0 * scaling; @@ -72,12 +72,12 @@ static Color _cbPreviewRender(SmallPreview* preview, double x, double y, double look.y = -y * 0.01 / scaling - 0.3; look.z = 1.0; look = v3Normalize(look); - + if (look.y > -0.0001) { return _rayCastFromWater(eye, look).hit_color; } - + location.x = eye.x - look.x * eye.y / look.y; location.y = 0.0; location.z = eye.z - look.z * eye.y / look.y; @@ -94,7 +94,7 @@ static Color _cbPreviewRender(SmallPreview* preview, double x, double y, double environment.toggle_fog = 0; environment.toggle_shadows = 0; quality.force_detail = 0.0001; - + return waterGetColorCustom(location, look, &definition, &quality, &environment).final; } @@ -111,7 +111,7 @@ static void _cbEditNoise(GtkWidget* widget, gpointer data) static void _cbHeightChanged(GtkRange* range, gpointer data) { - _definition.height = gtk_range_get_value(range); + _definition.height = gtk_range_get_value(range); guiPreviewRedraw(_preview_coverage); } @@ -127,16 +127,36 @@ static void _cbReflectionChanged(GtkRange* range, gpointer data) guiPreviewRedraw(_preview_render); } +static void _cbTransparencyDepthChanged(GtkRange* range, gpointer data) +{ + _definition.transparency_depth = gtk_range_get_value(range); + guiPreviewRedraw(_preview_render); +} + static void _cbColorChanged(GtkColorButton* colorbutton, gpointer data) { GdkRGBA col; - + gtk_color_button_get_rgba(colorbutton, &col); _definition.main_color.r = col.red; _definition.main_color.g = col.green; _definition.main_color.b = col.blue; _definition.main_color.a = 1.0; - + + guiPreviewRedraw(_preview_render); + guiPreviewRedraw(_preview_coverage); +} + +static void _cbColorDepthChanged(GtkColorButton* colorbutton, gpointer data) +{ + GdkRGBA col; + + gtk_color_button_get_rgba(colorbutton, &col); + _definition.depth_color.r = col.red; + _definition.depth_color.g = col.green; + _definition.depth_color.b = col.blue; + _definition.depth_color.a = 1.0; + guiPreviewRedraw(_preview_render); guiPreviewRedraw(_preview_coverage); } @@ -144,18 +164,24 @@ static void _cbColorChanged(GtkColorButton* colorbutton, gpointer data) static void _cbRevertConfig(GtkWidget* widget, gpointer data) { GdkRGBA col; - + waterCopyDefinition(waterGetDefinition(), &_definition); - + gtk_range_set_value(GTK_RANGE(GET_WIDGET("water_height")), _definition.height); gtk_range_set_value(GTK_RANGE(GET_WIDGET("water_transparency")), _definition.transparency); gtk_range_set_value(GTK_RANGE(GET_WIDGET("water_reflection")), _definition.reflection); + gtk_range_set_value(GTK_RANGE(GET_WIDGET("water_transparency_depth")), _definition.transparency_depth); col.red = _definition.main_color.r; col.green = _definition.main_color.g; col.blue = _definition.main_color.b; col.alpha = 1.0; gtk_color_button_set_rgba(GTK_COLOR_BUTTON(GET_WIDGET("water_color")), &col); - + col.red = _definition.depth_color.r; + col.green = _definition.depth_color.g; + col.blue = _definition.depth_color.b; + col.alpha = 1.0; + gtk_color_button_set_rgba(GTK_COLOR_BUTTON(GET_WIDGET("water_color_depth")), &col); + guiPreviewRedraw(_preview_render); guiPreviewRedraw(_preview_coverage); } @@ -169,23 +195,26 @@ static void _cbApplyConfig(GtkWidget* widget, gpointer data) void guiWaterInit() { _definition = waterCreateDefinition(); - + /* Buttons */ g_signal_connect(GET_WIDGET("water_noise_edit"), "clicked", G_CALLBACK(_cbEditNoise), NULL); g_signal_connect(GET_WIDGET("water_apply"), "clicked", G_CALLBACK(_cbApplyConfig), NULL); g_signal_connect(GET_WIDGET("water_revert"), "clicked", G_CALLBACK(_cbRevertConfig), NULL); - + /* Configs */ gtk_range_set_range(GTK_RANGE(GET_WIDGET("water_height")), -20.0, 20.0); gtk_range_set_range(GTK_RANGE(GET_WIDGET("water_transparency")), 0.0, 1.0); gtk_range_set_range(GTK_RANGE(GET_WIDGET("water_reflection")), 0.0, 1.0); - + gtk_range_set_range(GTK_RANGE(GET_WIDGET("water_transparency_depth")), 0.0, 100.0); + /* Config signals */ g_signal_connect(GET_WIDGET("water_height"), "value-changed", G_CALLBACK(_cbHeightChanged), NULL); g_signal_connect(GET_WIDGET("water_transparency"), "value-changed", G_CALLBACK(_cbTransparencyChanged), NULL); + g_signal_connect(GET_WIDGET("water_transparency_depth"), "value-changed", G_CALLBACK(_cbTransparencyDepthChanged), NULL); g_signal_connect(GET_WIDGET("water_reflection"), "value-changed", G_CALLBACK(_cbReflectionChanged), NULL); g_signal_connect(GET_WIDGET("water_color"), "color-set", G_CALLBACK(_cbColorChanged), NULL); - + g_signal_connect(GET_WIDGET("water_color_depth"), "color-set", G_CALLBACK(_cbColorDepthChanged), NULL); + /* Previews */ _preview_coverage = guiPreviewNew(GTK_IMAGE(GET_WIDGET("water_preview_coverage"))); guiPreviewConfigScaling(_preview_coverage, 0.01, 1.0, 0.05); diff --git a/src/sky.c b/src/sky.c index fbc6864..e8f95d8 100644 --- a/src/sky.c +++ b/src/sky.c @@ -192,8 +192,8 @@ void skyRender(RenderProgressCallback callback) Color col; Vector3 direction; - res_i = render_quality * 20; - res_j = render_quality * 10; + res_i = render_quality * 40; + res_j = render_quality * 20; step_i = M_PI * 2.0 / (double)res_i; step_j = M_PI / (double)res_j; diff --git a/src/water.c b/src/water.c index 3a152f8..81741e5 100644 --- a/src/water.c +++ b/src/water.c @@ -13,13 +13,13 @@ static WaterEnvironment _environment; static RayCastingResult _reflectionFunction(Vector3 start, Vector3 direction) { RayCastingResult result; - + if (!terrainProjectRay(start, direction, &result.hit_location, &result.hit_color)) { result.hit_color = skyProjectRay(start, direction); /* TODO hit_location */ } - + result.hit = 1; return result; } @@ -27,18 +27,18 @@ static RayCastingResult _reflectionFunction(Vector3 start, Vector3 direction) static RayCastingResult _refractionFunction(Vector3 start, Vector3 direction) { RayCastingResult result; - + result.hit = terrainProjectRay(start, direction, &result.hit_location, &result.hit_color); - + return result; } void waterInit() { _definition = waterCreateDefinition(); - + /* TODO quality */ - + _environment.reflection_function = _reflectionFunction; _environment.refraction_function = _refractionFunction; _environment.toggle_fog = 1; @@ -49,6 +49,8 @@ void waterSave(FILE* f) { toolsSaveDouble(f, _definition.height); colorSave(_definition.main_color, f); + colorSave(_definition.depth_color, f); + toolsSaveDouble(f, _definition.transparency_depth); toolsSaveDouble(f, _definition.transparency); toolsSaveDouble(f, _definition.reflection); noiseSave(_definition.height_noise, f); @@ -58,6 +60,8 @@ void waterLoad(FILE* f) { _definition.height = toolsLoadDouble(f); _definition.main_color = colorLoad(f); + _definition.depth_color = colorLoad(f); + _definition.transparency_depth = toolsLoadDouble(f); _definition.transparency = toolsLoadDouble(f); _definition.reflection = toolsLoadDouble(f); noiseLoad(_definition.height_noise, f); @@ -66,10 +70,10 @@ void waterLoad(FILE* f) WaterDefinition waterCreateDefinition() { WaterDefinition result; - + result.height = -1000.0; result.height_noise = noiseCreateGenerator(); - + return result; } @@ -81,7 +85,7 @@ void waterDeleteDefinition(WaterDefinition definition) void waterCopyDefinition(WaterDefinition source, WaterDefinition* destination) { NoiseGenerator* noise; - + noise = destination->height_noise; *destination = source; destination->height_noise = noise; @@ -101,7 +105,7 @@ WaterDefinition waterGetDefinition() void waterSetQuality(WaterQuality quality) { _quality = quality; - + _quality.detail_boost = (_quality.detail_boost < 0.1) ? 0.1 : _quality.detail_boost; } @@ -139,7 +143,7 @@ static inline Vector3 _getNormal(WaterDefinition* definition, Vector3 base, doub static inline Vector3 _reflectRay(Vector3 incoming, Vector3 normal) { double c; - + c = v3Dot(normal, v3Scale(incoming, -1.0)); return v3Add(incoming, v3Scale(normal, 2.0 * c)); } @@ -147,7 +151,7 @@ static inline Vector3 _reflectRay(Vector3 incoming, Vector3 normal) static inline Vector3 _refractRay(Vector3 incoming, Vector3 normal) { double c1, c2, f; - + f = 1.0 / 1.33; c1 = v3Dot(normal, v3Scale(incoming, -1.0)); c2 = sqrt(1.0 - pow(f, 2.0) * (1.0 - pow(c1, 2.0))); @@ -164,10 +168,11 @@ static inline Vector3 _refractRay(Vector3 incoming, Vector3 normal) WaterResult waterGetColorCustom(Vector3 location, Vector3 look, WaterDefinition* definition, WaterQuality* quality, WaterEnvironment* environment) { WaterResult result; + RayCastingResult refracted; Vector3 normal; Color color; - double shadowed, detail; - + double shadowed, detail, depth; + if (definition == NULL) { definition = &_definition; @@ -196,13 +201,26 @@ WaterResult waterGetColorCustom(Vector3 location, Vector3 look, WaterDefinition* normal = _getNormal(definition, location, detail); look = v3Normalize(look); result.reflected = environment->reflection_function(location, _reflectRay(look, normal)).hit_color; - result.refracted = environment->refraction_function(location, _refractRay(look, normal)).hit_color; + refracted = environment->refraction_function(location, _refractRay(look, normal)); + depth = v3Norm(v3Sub(location, refracted.hit_location)); + if (depth > definition->transparency_depth) + { + result.refracted = definition->depth_color; + } + else + { + depth /= definition->transparency_depth; + result.refracted.r = refracted.hit_color.r * (1.0 - depth) + definition->depth_color.r * depth; + result.refracted.g = refracted.hit_color.g * (1.0 - depth) + definition->depth_color.g * depth; + result.refracted.b = refracted.hit_color.b * (1.0 - depth) + definition->depth_color.b * depth; + result.refracted.a = 1.0; + } color.r = definition->main_color.r * (1.0 - definition->transparency) + result.reflected.r * definition->reflection + result.refracted.r * definition->transparency; color.g = definition->main_color.g * (1.0 - definition->transparency) + result.reflected.g * definition->reflection + result.refracted.g * definition->transparency; color.b = definition->main_color.b * (1.0 - definition->transparency) + result.reflected.b * definition->reflection + result.refracted.b * definition->transparency; color.a = 1.0; - + if (environment->toggle_shadows) { shadowed = terrainGetShadow(location, sun_direction_inv); @@ -311,7 +329,7 @@ void waterRender(RenderProgressCallback callback) { return; } - + for (i = 0; i < chunk_count - 1; i++) { _renderQuad(cx - radius_ext + chunk_size * i, cz - radius_ext, chunk_size); diff --git a/src/water.h b/src/water.h index fb10433..6554cd3 100644 --- a/src/water.h +++ b/src/water.h @@ -10,6 +10,8 @@ typedef struct double transparency; double reflection; Color main_color; + Color depth_color; + double transparency_depth; NoiseGenerator* height_noise; } WaterDefinition;