/* Terraform - (C) 1997-2002 Robert Gasch (r.gasch@chello.nl) * - http://terraform.sourceforge.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "tterrain.h" #include "tterrainview.h" #include "tperlin.h" #include "selection.h" #include "support.h" #include "support2.h" #include "base64.h" #include "xmlsupport.h" #include "terrainwindow.h" #include "filterwindow.h" #include "contour.h" #include "filenameops.h" #define CLIP(x,m,M) MAX(MIN(x,M),m) #define SQR(x) ((x)*(x)) guint heightfield_modified_signal; guint title_modified_signal; guint selection_modified_signal; guint object_added_signal; guint object_modified_signal; guint object_deleted_signal; void t_terrain_object_clear (TTerrainObject *object) { g_free (object->name); memset (object, 0, sizeof (TTerrainObject)); } static gint g_list_string_index (GList *list, gchar *string) { gint i; g_return_val_if_fail (list != NULL, -1); g_return_val_if_fail (string != NULL, -1); for (i = 0, list = g_list_first (list); list != NULL; i++, list = list->next) if (!strcmp (list->data, string)) return i; return -1; } static void t_terrain_class_init (TTerrainClass *klass); static void t_terrain_init (TTerrain *terrain); static void t_terrain_destroy (GtkObject *object); static void t_terrain_finalize (GtkObject *object); GtkType t_terrain_get_type (void) { static GtkType terrain_type = 0; if (!terrain_type) { static const GtkTypeInfo terrain_info = { "TTerrain", sizeof (TTerrain), sizeof (TTerrainClass), (GtkClassInitFunc) t_terrain_class_init, (GtkObjectInitFunc) t_terrain_init, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL }; terrain_type = gtk_type_unique (GTK_TYPE_OBJECT, &terrain_info); } return terrain_type; } GtkObject * t_terrain_new (gint width, gint height) { TTerrain *terrain; terrain = gtk_type_new (T_TYPE_TERRAIN); terrain->width = width; terrain->height = height; terrain->heightfield = g_new0 (gfloat, width * height); return GTK_OBJECT (terrain); } void t_terrain_set_filename (TTerrain *terrain, gchar *filename) { if (terrain->filename != filename) { g_free (terrain->filename); terrain->filename = g_strdup (filename); gtk_signal_emit (GTK_OBJECT (terrain), title_modified_signal); } } gchar * t_terrain_get_title (TTerrain *terrain) { return g_strdup_printf ("%s%s", terrain->filename, terrain->modified ? _(" (not saved)") : ""); } void t_terrain_set_modified (TTerrain *terrain, gboolean modified) { if (terrain->modified != modified) { terrain->modified = modified; gtk_signal_emit (GTK_OBJECT (terrain), title_modified_signal); } } /* t_terrain_get_height: retrieve height of terrain at a point using * linear interpolation */ gdouble t_terrain_get_height (TTerrain *terrain, gdouble x, gdouble y) { gdouble point[4]; int index_x, index_y; int index; index_x = (int) (x * (terrain->width - 1)); index_x = CLIP (index_x, 0, terrain->width - 2); index_y = (int) (y * (terrain->height - 1)); index_y = CLIP (index_y, 0, terrain->height - 2); index = index_y * terrain->width + index_x; point[0] = terrain->heightfield[index]; point[1] = terrain->heightfield[index + 1]; point[2] = terrain->heightfield[index + terrain->width]; point[3] = terrain->heightfield[index + terrain->width + 1]; x = x * (terrain->width - 1) - index_x; y = y * (terrain->height - 1) - index_y; return (point[0] * (1.0 - x) + point[1] * x) * (1.0 - y) + (point[2] * (1.0 - x) + point[3] * x) * y; } void t_terrain_heightfield_modified (TTerrain *terrain) { t_terrain_set_modified (terrain, TRUE); gtk_signal_emit (GTK_OBJECT (terrain), heightfield_modified_signal); } void t_terrain_selection_modified (TTerrain *terrain) { gtk_signal_emit (GTK_OBJECT (terrain), selection_modified_signal); } static GtkObjectClass *parent_class; static void t_terrain_class_init (TTerrainClass *klass) { GtkObjectClass *object_class = GTK_OBJECT_CLASS (klass); GtkType type; type = T_TYPE_TERRAIN; parent_class = gtk_type_class (GTK_TYPE_OBJECT); klass->heightfield_modified = NULL; klass->title_modified = NULL; klass->selection_modified = NULL; klass->object_added = NULL; klass->object_modified = NULL; klass->object_deleted = NULL; object_class->destroy = &t_terrain_destroy; object_class->finalize = &t_terrain_finalize; heightfield_modified_signal = gtk_signal_new ("heightfield_modified", GTK_RUN_FIRST, type, GTK_SIGNAL_OFFSET (TTerrainClass, heightfield_modified), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); title_modified_signal = gtk_signal_new ("title_modified", GTK_RUN_FIRST, type, GTK_SIGNAL_OFFSET (TTerrainClass, title_modified), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); selection_modified_signal = gtk_signal_new ("selection_modified", GTK_RUN_FIRST, type, GTK_SIGNAL_OFFSET (TTerrainClass, selection_modified), gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); object_added_signal = gtk_signal_new ("object_added", GTK_RUN_FIRST, type, GTK_SIGNAL_OFFSET (TTerrainClass, object_added), gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1, GTK_TYPE_INT); object_modified_signal = gtk_signal_new ("object_modified", GTK_RUN_FIRST, type, GTK_SIGNAL_OFFSET (TTerrainClass, object_modified), gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1, GTK_TYPE_INT); object_deleted_signal = gtk_signal_new ("object_deleted", GTK_RUN_FIRST, type, GTK_SIGNAL_OFFSET (TTerrainClass, object_deleted), gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1, GTK_TYPE_INT); gtk_object_class_add_signals (object_class, &heightfield_modified_signal, 1); gtk_object_class_add_signals (object_class, &title_modified_signal, 1); gtk_object_class_add_signals (object_class, &selection_modified_signal, 1); gtk_object_class_add_signals (object_class, &object_added_signal, 1); gtk_object_class_add_signals (object_class, &object_modified_signal, 1); gtk_object_class_add_signals (object_class, &object_deleted_signal, 1); } static void t_terrain_init (TTerrain *terrain) { terrain->filename = g_strdup (""); terrain->heightfield = NULL; terrain->selection = NULL; terrain->width = 0; terrain->height = 0; terrain->modified = FALSE; terrain->autogenned = FALSE; terrain->objects = g_array_new (FALSE, FALSE, sizeof (TTerrainObject)); terrain->riversources = g_array_new (FALSE, FALSE, sizeof (TTerrainRiverCoords)); terrain->riverfield = NULL; terrain->camera_height_factor = 0.33; terrain->contour_levels = 10; terrain->do_filled_sea = TRUE; terrain->sealevel = 0.33; terrain->wireframe_resolution = 10; terrain->y_scale_factor = 0.33; terrain->render_options.do_clouds = TRUE; terrain->render_options.do_fog = FALSE; terrain->render_options.do_ground_fog = FALSE; terrain->render_options.do_observe_sealevel = TRUE; terrain->render_options.do_rainbow = FALSE; terrain->render_options.camera_x = 0.5; terrain->render_options.camera_y = 2.5; terrain->render_options.camera_z = -1.25; terrain->render_options.lookat_x = 0.5; terrain->render_options.lookat_y = 0.0; terrain->render_options.lookat_z = 0.5; terrain->render_options.elevation_offset = 0.1; terrain->render_options.fog_alt = 0.25; terrain->render_options.fog_density = 0.25; terrain->render_options.fog_offset = 0.33; terrain->render_options.fog_turbulence = 0.33; terrain->render_options.time_of_day = 12.0; terrain->render_options.north_direction = 0.0; terrain->render_options.water_clarity = 0.65; terrain->render_options.render_scale_x = 1000; terrain->render_options.render_scale_y = 1000*terrain->y_scale_factor; terrain->render_options.render_scale_z = 1000; terrain->render_options.atmosphere_file = g_strdup ("earth_fog.inc"); terrain->render_options.cloud_file = g_strdup ("clouds_01.inc"); terrain->render_options.image_size_string = g_strdup ("320x240"); terrain->render_options.povray_filename = g_strdup (""); terrain->render_options.sky_file = g_strdup ("earth_regular_sky.inc"); terrain->render_options.star_file = g_strdup ("stars_01.inc"); terrain->render_options.texture_file = g_strdup ("earth_green_landscape.inc"); terrain->render_options.water_file = g_strdup ("earth_water.inc"); terrain->render_options.do_aa = FALSE; terrain->render_options.do_custom_size = FALSE; terrain->render_options.do_jitter = FALSE; terrain->render_options.filetype = 0; /* 0 = png */ terrain->render_options.image_width = 320; terrain->render_options.image_height = 240; terrain->render_options.render_quality = 9; terrain->render_options.aa_depth = 1.0; terrain->render_options.aa_threshold = 0.3; terrain->render_options.aa_type = 0; terrain->render_options.jitter_amount = 0.5; } static void t_terrain_free_render_options (TTerrainOptRender *ropt) { g_free (ropt->povray_filename); g_free (ropt->texture_file); g_free (ropt->cloud_file); g_free (ropt->atmosphere_file); g_free (ropt->sky_file); g_free (ropt->star_file); g_free (ropt->water_file); g_free (ropt->image_size_string); } static void t_terrain_free (TTerrain *terrain) { t_terrain_remove_objects (terrain); g_array_free (terrain->objects, TRUE); g_array_free (terrain->riversources, TRUE); g_free (terrain->heightfield); g_free (terrain->riverfield); g_free (terrain->selection); g_free (terrain->filename); t_terrain_free_render_options (&(terrain->render_options)); } static void t_terrain_destroy (GtkObject *object) { TTerrain *terrain = T_TERRAIN (object); t_terrain_free (terrain); t_terrain_init (terrain); if (parent_class->destroy != NULL) parent_class->destroy (object); } static void t_terrain_finalize (GtkObject *object) { TTerrain *terrain = T_TERRAIN (object); t_terrain_free (terrain); if (parent_class->finalize != NULL) parent_class->finalize (object); } static void t_terrain_copy_settings_render_options (TTerrainOptRender *new, TTerrainOptRender *orig) { /* render related options, assumed non-required for previews */ g_free (new->texture_file); new->texture_file = g_strdup (orig->texture_file); g_free (new->cloud_file); new->cloud_file = g_strdup (orig->cloud_file); g_free (new->atmosphere_file); new->atmosphere_file = g_strdup (orig->atmosphere_file); g_free (new->sky_file); new->sky_file = g_strdup (orig->sky_file); g_free (new->star_file); new->star_file = g_strdup (orig->star_file); g_free (new->water_file); new->water_file = g_strdup (orig->water_file); new->camera_x = orig->camera_x; new->camera_y = orig->camera_y; new->camera_z = orig->camera_z; new->lookat_x = orig->lookat_x; new->lookat_y = orig->lookat_y; new->lookat_z = orig->lookat_z; new->elevation_offset = orig->elevation_offset; new->do_clouds = orig->do_clouds; new->do_fog = orig->do_fog; new->do_ground_fog = orig->do_ground_fog; new->do_rainbow = orig->do_rainbow; new->fog_offset = orig->fog_offset; new->fog_alt = orig->fog_alt; new->fog_density = orig->fog_density; new->fog_turbulence = orig->fog_turbulence; new->time_of_day = orig->time_of_day; new->north_direction = orig->north_direction; new->water_clarity = orig->water_clarity; new->render_scale_x = orig->render_scale_x; new->render_scale_y = orig->render_scale_y; new->render_scale_z = orig->render_scale_z; new->render_scale_z = orig->render_scale_z; new->do_observe_sealevel = orig->do_observe_sealevel; /* povray specific options */ g_free (new->povray_filename); new->povray_filename = g_strdup (orig->povray_filename); g_free (new->image_size_string); new->image_size_string = g_strdup (orig->image_size_string); new->render_quality = orig->render_quality; new->filetype = orig->filetype; new->do_custom_size = orig->do_custom_size; new->image_width = orig->image_width; new->image_height = orig->image_height; new->do_aa = orig->do_aa; new->aa_threshold = orig->aa_threshold; new->aa_type = orig->aa_type; new->aa_depth = orig->aa_depth; new->do_jitter = orig->do_jitter; new->jitter_amount = orig->jitter_amount; } static void t_terrain_copy_settings (TTerrain *new, TTerrain *orig) { g_free (new->filename); new->filename = g_strdup (orig->filename); new->camera_height_factor = orig->camera_height_factor; new->contour_levels = orig->contour_levels; new->do_filled_sea = orig->do_filled_sea; new->sealevel = orig->sealevel; new->wireframe_resolution = orig->wireframe_resolution; new->y_scale_factor = orig->y_scale_factor; t_terrain_copy_settings_render_options (&(new->render_options), &(orig->render_options)); } TTerrain * t_terrain_clone (TTerrain *terrain) { GtkObject *object; TTerrain *out; gint i; gint memsize; gint memsizeb; memsize = terrain->width * terrain->height * sizeof(gfloat); memsizeb = terrain->width * terrain->height * sizeof(gboolean); object = t_terrain_new (terrain->width, terrain->height); out = T_TERRAIN (object); t_terrain_copy_settings (out, terrain); memcpy (out->heightfield, terrain->heightfield, memsize); if (terrain->riverfield != NULL) out->riverfield = g_memdup (terrain->riverfield, sizeof(gfloat)*terrain->width*terrain->height); if (terrain->selection != NULL) out->selection = g_memdup (terrain->selection, sizeof(gfloat)*terrain->width*terrain->height); if (terrain->riversources != NULL) for (i=0; iriversources->len; i++) g_array_append_val (out->riversources, g_array_index (terrain->riversources, TTerrainRiverCoords, i)); if (terrain->objects != NULL) for (i=0; iobjects->len; i++) g_array_append_val (out->objects, g_array_index (terrain->objects, TTerrainObject, i)); return out; } TTerrain * t_terrain_clone_resize (TTerrain *terrain, gint width, gint height, gboolean terrain_only) { GtkObject *object; TTerrain *out; gfloat fx = width/terrain->width; gfloat fz = height/terrain->height; gfloat fy = (fx+fz)/2; gint y; gint pos; object = t_terrain_new (width, height); out = T_TERRAIN (object); t_terrain_copy_settings (out, terrain); if (terrain->riverfield != NULL) out->riverfield = g_new (gfloat, out->width * out->height); if (terrain->selection != NULL) out->selection = g_new (gfloat, out->width * out->height); pos = 0; for (y = 0; y < out->height; y++) { gint x; gint count; gint prev_pos; prev_pos = y * terrain->height / out->height * terrain->width; count = 0; for (x = 0; x < out->width; x++) { out->heightfield[pos] = terrain->heightfield[prev_pos]; if (out->riverfield != NULL) out->riverfield[pos] = terrain->riverfield[prev_pos]; if (out->selection != NULL) out->selection[pos] = terrain->selection[prev_pos]; pos++; count += terrain->width; while (count >= out->width) { count -= out->width; prev_pos++; } } } /* clone_resize doesn't always need rivers (when it's used for preview) */ if (!terrain_only) for (y=0; yriversources->len; y++) { TTerrainRiverCoords *obj; obj = &g_array_index (terrain->riversources, TTerrainRiverCoords, y); obj->x *= fx; obj->y *= fz; g_array_append_val (out->riversources, obj); } /* clone_resize doesn't always need objects (when it's used for preview) */ if (!terrain_only) for (y = 0; y < terrain->objects->len; y++) { TTerrainObject obj; obj = g_array_index (terrain->objects, TTerrainObject, y); obj.x *= fx; obj.y *= fz; obj.scale_x *= fx; obj.scale_z *= fz; obj.scale_y *= fy; g_array_append_val (out->objects, obj); } return out; } void t_terrain_set_size (TTerrain *terrain, gint width, gint height) { if (terrain->width != width || terrain->height != height) { terrain->width = width; terrain->height = height; g_free (terrain->heightfield); g_free (terrain->selection); g_free (terrain->riverfield); terrain->heightfield = g_new0 (gfloat, width * height); terrain->selection = NULL; terrain->riverfield = NULL; } } TTerrain * t_terrain_clone_preview (TTerrain *terrain) { gint maximum; TTerrain *clone; maximum = MAX (terrain->width, terrain->height); clone = t_terrain_clone_resize (terrain, MAX (1, MIN(terrain->width * 100 / maximum, terrain->width)), MAX (1, MIN(terrain->height * 100 / maximum, terrain->height)), TRUE); clone->wireframe_resolution = 5; return clone; } gint * t_terrain_histogram (TTerrain *terrain, gint n, gint scale) { gint tsize = terrain->width * terrain->height; gint *data; gint max = 0; gint i; data = g_new0 (gint, n); for (i = 0; i < tsize; i++) { gint off; off = (gint) (terrain->heightfield[i] * n); off = (off == n ? off - 1 : off); data[off]++; } /* find max and adjust all data points to 1 .. 100 */ for (i=0; i max) max = data[i]; for (i=0; i 0) data[i] = 1; } return data; } /* * create a preview HF filled with histogram values * since we already have code to paint HFs, this is * a lazy way of getting a histogram displayed */ TTerrain * t_terrain_clone_histogram (TTerrain *terrain, gfloat display_yscale) { GtkObject *object; TTerrain *thist; gint *dhist; gint size; /* number of intervals */ gint width; gint height; gint i,j; gint ypos; gfloat f; gfloat v; gfloat lim; size = width = height = 100; f = 1.0/size; dhist = t_terrain_histogram (terrain, size, height); object = t_terrain_new (width, height); thist = T_TERRAIN (object); /* populate histogram data */ for (i=0; iheightfield[ypos*width+i] = v; } } g_free (dhist); return thist; } void t_terrain_copy_heightfield (TTerrain *from, TTerrain *to) { gint memsize; g_return_if_fail (from->width == to->width && from->height == to->height); memsize = from->width*from->height*sizeof(gfloat); memcpy (to->heightfield, from->heightfield, memsize); to->sealevel = from->sealevel; } void t_terrain_copy_heightfield_and_extras (TTerrain *from, TTerrain *to) { gint memsize; gint i; g_return_if_fail (from->width == to->width && from->height == to->height); memsize = from->width*from->height*sizeof(gfloat); t_terrain_copy_heightfield (from, to); /* copy selection */ if (from->selection == NULL) { g_free (to->selection); to->selection = NULL; } else { if (to->selection == NULL) to->selection = g_memdup (from->selection, memsize); else memcpy (to->selection, from->selection, memsize); } /* copy riverfield */ if (from->riverfield == NULL) { g_free (to->riverfield); to->riverfield = NULL; } else { if (to->selection == NULL) to->selection = g_memdup (from->riverfield, memsize); else memcpy (to->riverfield, from->riverfield, memsize); } /* copy riversources */ if (from->riversources != NULL) for (i=0; iriversources->len; i++) g_array_append_val (to->riversources, g_array_index (from->riversources, TTerrainRiverCoords, i)); /* copy riversources */ if (from->objects != NULL) for (i=0; iobjects->len; i++) g_array_append_val (to->objects, g_array_index (from->objects, TTerrainObject, i)); } void t_terrain_normalize (TTerrain *terrain, gboolean never_grow) { gint i, last; gfloat min, max; gfloat *data; data = terrain->heightfield; last = terrain->width * terrain->height; /* * When never_grow is true, normalize assumes that if the minimum * and maximum value range of the terrain is smaller than [0.0, 1.0], * the user wants it that way. */ if (never_grow) min = 0.0, max = 1.0; else min = max = data[0]; for (i = 0; i < last; i++) { if (data[i] < min) min = data[i]; if (data[i] > max) max = data[i]; } if (fabs (max - min) > 0.0001) { gfloat k; k = 1.0 / (max - min); for (i = 0; i < last; i++) data[i] = (data[i] - min) * k; if (never_grow) terrain->sealevel = MIN (MAX ((terrain->sealevel - min) * k, 0.0), 1.0); } } void t_terrain_crop (TTerrain *terrain, gint x1, gint y1, gint x2, gint y2) { gint from_x, from_y; gint to_x, to_y; g_return_if_fail (x1 >= 0 && y1 >= 0 && x2 < terrain->width && y2 < terrain->height); g_return_if_fail (x1 <= x2 && y1 <= y2); for (from_y = y1, to_y = 0; from_y <= y2; from_y++, to_y++) { gint from_pos, to_pos; from_pos = from_y * terrain->width + x1; to_pos = to_y * (x2 - x1 + 1); for (from_x = x1, to_x = 0; from_x <= x2; from_x++, to_x++) { terrain->heightfield[to_pos] = terrain->heightfield[from_pos]; if (terrain->riverfield != NULL) terrain->riverfield[to_pos] = terrain->riverfield[from_pos]; if (terrain->selection != NULL) terrain->selection[to_pos] = terrain->selection[from_pos]; from_pos++; to_pos++; } } terrain->width = x2 - x1 + 1; terrain->height = y2 - y1 + 1; terrain->heightfield = g_renew (gfloat, terrain->heightfield, terrain->width * terrain->height); if (terrain->riverfield != NULL) terrain->riverfield = g_renew (gfloat, terrain->riverfield, terrain->width * terrain->height); if (terrain->selection != NULL) terrain->selection = g_renew (gfloat, terrain->selection, terrain->width * terrain->height); } TTerrain * t_terrain_crop_new (TTerrain *terrain, gint x1, gint y1, gint x2, gint y2) { gint x, y; gint width = x2 - x1 + 1; gint height = y2 - y1 + 1; GtkObject *tnew_object; TTerrain *tnew; g_return_val_if_fail (width > 10, NULL); g_return_val_if_fail (height > 10, NULL); /* fix larger-than-allowed size params */ if (width > terrain->width) width = terrain->width; if (height > terrain->height) height = terrain->height; tnew_object = t_terrain_new (width, height); tnew = T_TERRAIN (tnew_object); if (terrain->riverfield != NULL) tnew->riverfield = g_new0 (gfloat, width * height); if (terrain->selection != NULL) tnew->selection = g_new0 (gfloat, width * height); for (y = 0; y < height; y++) for (x = 0; x < width; x++) { gint offdst = y * width + x; gint offsrc = (y1 + y) * terrain->width + (x1 + x); tnew->heightfield[offdst] = terrain->heightfield[offsrc]; if (terrain->riverfield != NULL) tnew->riverfield[offdst] = terrain->riverfield[offsrc]; if (terrain->selection != NULL) tnew->selection[offdst] = terrain->selection[offsrc]; } t_terrain_normalize (terrain, TRUE); t_terrain_set_modified (tnew, TRUE); return tnew; } void t_terrain_invert (TTerrain *terrain) { gint i; gint size; size = terrain->width * terrain->height; for (i = 0; i < size; i++) terrain->heightfield[i] = 1.0 - terrain->heightfield[i]; } void t_terrain_pack_scene_options (TTerrain *terrain, GtkWidget *options) { TTerrainOptRender * const ropt = &(terrain->render_options); GList *themes; GList *clouds; GList *atms; GList *skies; GList *stars; GList *waters; themes = gtk_object_get_data (GTK_OBJECT (options), "data_themes"); clouds = gtk_object_get_data (GTK_OBJECT (options), "data_clouds"); atms = gtk_object_get_data (GTK_OBJECT (options), "data_atmospheres"); skies = gtk_object_get_data (GTK_OBJECT (options), "data_skies"); stars = gtk_object_get_data (GTK_OBJECT (options), "data_stars"); waters = gtk_object_get_data (GTK_OBJECT (options), "data_water"); terrain->do_filled_sea = get_boolean (options, "render_filled_sea"); terrain->sealevel = get_float (options, "render_sealevel"); terrain->y_scale_factor = get_float (options, "render_y_scale_factor"); ropt->camera_x = get_float (options, "render_camera_x"); ropt->camera_y = get_float (options, "render_camera_y"); ropt->camera_z = get_float (options, "render_camera_z"); ropt->lookat_x = get_float (options, "render_lookat_x"); ropt->lookat_y = get_float (options, "render_lookat_y"); ropt->lookat_z = get_float (options, "render_lookat_z"); ropt->do_observe_sealevel = get_boolean (options, "render_observe_sealevel"); ropt->elevation_offset = get_float (options, "render_elevation"); ropt->do_clouds = get_boolean (options, "render_clouds"); ropt->do_fog = get_boolean (options, "render_fog"); ropt->do_ground_fog = get_boolean (options, "render_ground_fog"); ropt->do_rainbow = get_boolean (options, "render_rainbow"); ropt->fog_offset = get_float (options, "render_fog_offset"); ropt->fog_alt = get_float (options, "render_fog_alt"); ropt->fog_density = get_float (options, "render_fog_density"); ropt->fog_turbulence = get_float (options, "render_fog_turbulence"); ropt->time_of_day = get_float (options, "render_time_of_day"); ropt->north_direction = get_float (options, "render_north_direction"); ropt->water_clarity = get_float (options, "render_clarity"); ropt->render_scale_x = get_int (options, "render_scale_x"); ropt->render_scale_y = ( (ropt->render_scale_x + ropt->render_scale_y)/2)*terrain->y_scale_factor; ropt->render_scale_z = get_int (options, "render_scale_z"); g_free (ropt->texture_file); ropt->texture_file = g_strdup ( g_list_nth_data (themes, get_option (options, "render_theme"))); g_free (ropt->cloud_file); ropt->cloud_file = g_strdup ( g_list_nth_data (clouds, get_option (options, "render_cloud_type"))); g_free (ropt->atmosphere_file); ropt->atmosphere_file = g_strdup ( g_list_nth_data (atms, get_option (options, "render_atmosphere_type"))); g_free (ropt->sky_file); ropt->sky_file = g_strdup ( g_list_nth_data (skies, get_option (options, "render_sky_type"))); g_free (ropt->star_file); ropt->star_file = g_strdup ( g_list_nth_data (stars, get_option (options, "render_star_type"))); g_free (ropt->water_file); ropt->water_file = g_strdup ( g_list_nth_data (waters, get_option (options, "render_water_type"))); t_terrain_set_modified (terrain, TRUE); } void t_terrain_pack_terrain_options (TTerrain *terrain, GtkWidget *options) { /* TTerrainOptRender * const ropt = &(terrain->render_options); */ terrain->contour_levels = get_int (options, "render_levels"); terrain->camera_height_factor = get_float (options, "render_camera_height_factor"); terrain->wireframe_resolution = get_int (options, "render_wireframe_resolution"); t_terrain_set_modified (terrain, TRUE); } void t_terrain_unpack_scene_options (TTerrain *terrain, GtkWidget *options) { const TTerrainOptRender *ropt = &(terrain->render_options); GList *themes; GList *clouds; GList *atms; GList *skies; GList *stars; GList *waters; gint value; /* options = lookup_toplevel (options); */ themes = gtk_object_get_data (GTK_OBJECT (options), "data_themes"); clouds = gtk_object_get_data (GTK_OBJECT (options), "data_clouds"); atms = gtk_object_get_data (GTK_OBJECT (options), "data_atmospheres"); skies = gtk_object_get_data (GTK_OBJECT (options), "data_skies"); stars = gtk_object_get_data (GTK_OBJECT (options), "data_stars"); waters = gtk_object_get_data (GTK_OBJECT (options), "data_water"); set_boolean (options, "render_filled_sea", terrain->do_filled_sea); set_float (options, "render_sealevel", terrain->sealevel); set_float (options, "render_y_scale_factor", terrain->y_scale_factor); set_float (options, "render_camera_x", ropt->camera_x); set_float (options, "render_camera_y", ropt->camera_y); set_float (options, "render_camera_z", ropt->camera_z); set_float (options, "render_lookat_x", ropt->lookat_x); set_float (options, "render_lookat_y", ropt->lookat_y); set_float (options, "render_lookat_z", ropt->lookat_z); /* set_boolean (options, "render_tile_terrain", terrain->do_tile); */ set_boolean (options, "render_observe_sealevel", ropt->do_observe_sealevel); set_float (options, "render_elevation", ropt->elevation_offset); set_boolean (options, "render_clouds", ropt->do_clouds); set_boolean (options, "render_fog", ropt->do_fog); set_boolean (options, "render_ground_fog", ropt->do_ground_fog); set_boolean (options, "render_rainbow", ropt->do_rainbow); set_float (options, "render_fog_offset", ropt->fog_offset); set_float (options, "render_fog_alt", ropt->fog_alt); set_float (options, "render_fog_density", ropt->fog_density); set_float (options, "render_fog_turbulence", ropt->fog_turbulence); set_float (options, "render_time_of_day", ropt->time_of_day); set_float (options, "render_north_direction", ropt->north_direction); set_float (options, "render_clarity", ropt->water_clarity); set_int (options, "render_scale_x", ropt->render_scale_x); set_int (options, "render_scale_z", ropt->render_scale_z); set_int (options, "spinbutton_render_scale_x", ropt->render_scale_x); set_int (options, "spinbutton_render_scale_z", ropt->render_scale_z); set_float (options, "spinbutton_render_y_scale_factor", terrain->y_scale_factor); value = g_list_string_index (themes, ropt->texture_file); set_option (options, "render_theme", value >= 0 ? value : 0); value = g_list_string_index (clouds, ropt->cloud_file); set_option (options, "render_cloud_type", value >= 0 ? value : 0); value = g_list_string_index (atms, ropt->atmosphere_file); set_option (options, "render_atmosphere_type", value >= 0 ? value : 0); value = g_list_string_index (stars, ropt->sky_file); set_option (options, "render_sky_type", value >= 0 ? value : 0); value = g_list_string_index (skies, ropt->star_file); set_option (options, "render_star_type", value >= 0 ? value : 0); value = g_list_string_index (waters, ropt->water_file); set_option (options, "render_water_type", value >= 0 ? value : 0); /* doesn't have a GUI counterpart -> derived */ /* set_int (options, "render_scale_y", ((ropt->render_scale_x + ropt->render_scale_y))/2*terrain->y_scale_factor); */ } void t_terrain_unpack_terrain_options (TTerrain *terrain, GtkWidget *options) { /* const TTerrainOptRender *ropt = &(terrain->render_options); */ set_float (options, "render_camera_height_factor", terrain->camera_height_factor); set_int (options, "render_levels", terrain->contour_levels); set_int (options, "render_wireframe_resolution", terrain->wireframe_resolution); } void t_terrain_pack_povray_options (TTerrain *terrain, GtkWidget *options) { GtkWidget *fileentry; GList *render_sizes; TTerrainOptRender * const ropt = &(terrain->render_options); t_terrain_set_modified (terrain, TRUE); /* get filename */ fileentry = lookup_widget (GTK_WIDGET (options), "fileentry_povray_filename"); ropt->povray_filename = gnome_file_entry_get_full_path (GNOME_FILE_ENTRY (fileentry), FALSE); /* get filetype */ ropt->filetype = get_option (options, "optionmenu_filetype"); /* get image size */ render_sizes = gtk_object_get_data (GTK_OBJECT (options), "data_render_size"); g_free (ropt->image_size_string); ropt->image_size_string = g_strdup ( g_list_nth_data (render_sizes, get_option (options, "optionmenu_render_size"))); ropt->do_custom_size = get_boolean (options, "custom_size"); if(ropt->do_custom_size) { ropt->image_width = get_int(options, "image_width"); ropt->image_height = get_int(options, "image_height"); } else { ropt->image_width = atoi(g_string_get_image_size(ropt->image_size_string, TRUE)); ropt->image_height = atoi(g_string_get_image_size(ropt->image_size_string, FALSE)); } /* get quality settings */ ropt->render_quality = get_option (options, "optionmenu_quality"); /* get antialiasing options */ ropt->do_aa = get_boolean (options, "use_antialiasing"); ropt->aa_threshold = get_float (options, "aa_threshold"); ropt->aa_type = get_option (options, "optionmenu_aa_type"); ropt->aa_depth = get_float (options, "aa_depth"); ropt->do_jitter = get_boolean (options, "use_jitter"); ropt->jitter_amount = get_float (options, "jitter_amount"); } void t_terrain_unpack_povray_options (TTerrain *terrain, GtkWidget *options) { GtkWidget *fileentry; GList *render_sizes; gint value; const gchar *filename; const TTerrainOptRender *ropt = &(terrain->render_options); /* set filename */ fileentry = lookup_widget (options, "fileentry_povray_filename"); if ( /* ropt->povray_filename == NULL || */ strlen(ropt->povray_filename) < 1 ) filename = filename_get_without_extension_and_dot (terrain->filename); else filename = ropt->povray_filename; gtk_entry_set_text (GTK_ENTRY (gnome_file_entry_gtk_entry (GNOME_FILE_ENTRY(fileentry))), filename); /* set filetype */ set_option (options, "optionmenu_filetype", ropt->filetype); /* set image size */ set_boolean (options, "custom_size", ropt->do_custom_size); render_sizes = gtk_object_get_data (GTK_OBJECT (options), "data_render_size"); value = g_list_string_index (render_sizes, ropt->image_size_string); set_option (options, "optionmenu_render_size", value >= 0 ? value : 0); set_int (options, "image_width", ropt->image_width); set_int (options, "image_height", ropt->image_height); /* set quality settings */ set_option (options, "optionmenu_quality", ropt->render_quality); /* set antialiasing options */ set_boolean (options, "use_antialiasing", ropt->do_aa); set_float (options, "aa_threshold", ropt->aa_threshold); set_option (options, "optionmenu_aa_type", ropt->aa_type); set_float (options, "aa_depth", ropt->aa_depth); set_boolean (options, "use_jitter", ropt->do_jitter); set_float (options, "jitter_amount", ropt->jitter_amount); } void t_terrain_print_contour_map (TTerrain *terrain, GnomePrintContext *context) { GList *list; gdouble scale; gdouble translate_x, translate_y; gdouble page_width, page_height; gdouble usable_width, usable_height; GList *contour_lines; page_width = 8.5 * 72.0; page_height = 11.0 * 72.0; usable_width = 7.0 * 72.0; usable_height = 9.0 * 72.0; scale = MIN (usable_width / terrain->width, usable_height / terrain->height); translate_x = (page_width - scale * terrain->width) * 0.5; translate_y = page_height - (page_height - scale * terrain->height) * 0.5; gnome_print_translate (context, translate_x, translate_y); gnome_print_scale (context, scale, -scale); gnome_print_newpath (context); gnome_print_moveto (context, 0.0, 0.0); gnome_print_lineto (context, terrain->width, 0.0); gnome_print_lineto (context, terrain->width, terrain->height); gnome_print_lineto (context, 0.0, terrain->height); gnome_print_closepath (context); gnome_print_stroke (context); contour_lines = t_terrain_contour_lines (terrain, terrain->contour_levels, 5); list = g_list_first (contour_lines); while (list != NULL) { GArray *array; gdouble x, y; gint i; array = list->data; x = g_array_index (array, gfloat, 1); y = g_array_index (array, gfloat, 2); gnome_print_newpath (context); gnome_print_moveto (context, x, y); for (i = 1; i < array->len; i += 2) { x = g_array_index (array, gfloat, i + 0); y = g_array_index (array, gfloat, i + 1); gnome_print_lineto (context, x, y); } gnome_print_stroke (context); list = list->next; } t_terrain_contour_list_free (contour_lines); } void t_terrain_ref (TTerrain *terrain) { gtk_object_ref (GTK_OBJECT (terrain)); gtk_object_sink (GTK_OBJECT (terrain)); } void t_terrain_unref (TTerrain *terrain) { gtk_object_unref (GTK_OBJECT (terrain)); } TTerrain * t_terrain_import_heightfield (gchar *filename) { return NULL; } void t_terrain_export_heightfield (TTerrain *terrain, gchar *filename) { } static void raster_set (TTerrain *terrain, gint x1, gint y, gint x2, TComposeOp op) { gint pos; if (y < 0 || y >= terrain->height || x2 < 0 || x1 >= terrain->width || x2 < x1) return; x1 = MAX (x1, 0); x2 = MIN (x2, terrain->width - 1); pos = y * terrain->width + x1; switch (op) { case T_COMPOSE_REPLACE: case T_COMPOSE_ADD: for (; x1 <= x2; x1++) terrain->selection[pos++] = 1.0; break; case T_COMPOSE_SUBTRACT: for (; x1 <= x2; x1++) terrain->selection[pos++] = 0.0; break; default: break; } } void t_terrain_select_by_height (TTerrain *terrain, gfloat floor, gfloat ceil, TComposeOp op) { gint i = 0; gint x, y; gint size = terrain->width * terrain->height; if (op == T_COMPOSE_NONE) return; if (terrain->selection == NULL) terrain->selection = g_new (gfloat, size); if (op == T_COMPOSE_REPLACE) memset (terrain->selection, 0, sizeof (gfloat)*size); for (y=0; yheight; y++) for (x=0; xwidth; x++, i++) { if (terrain->heightfield[i] >= floor && terrain->heightfield[i] <= ceil) raster_set (terrain, x, y, x, op); } } void t_terrain_select (TTerrain *terrain, gfloat x1, gfloat y1, gfloat x2, gfloat y2, TSelectionType type, TComposeOp op) { gint y, _x1, _y1, _x2, _y2; if (op == T_COMPOSE_NONE) return; _x1 = x1 * (terrain->width - 1); _y1 = y1 * (terrain->height - 1); _x2 = x2 * (terrain->width - 1); _y2 = y2 * (terrain->height - 1); if (type == T_SELECTION_NONE) { if (op == T_COMPOSE_REPLACE) { t_terrain_select_destroy (terrain); } return; } if (terrain->selection == NULL) terrain->selection = g_new0 (gfloat, terrain->width * terrain->height); else if (op == T_COMPOSE_REPLACE) memset (terrain->selection, 0, sizeof (gfloat) * terrain->width * terrain->height); switch (type) { case T_SELECTION_RECTANGLE: for (y = _y1; y <= _y2; y++) raster_set (terrain, _x1, y, _x2, op); break; case T_SELECTION_ELLIPSE: for (y = _y1; y <= _y2; y++) { gfloat value; gfloat x_radius; gint x_start, x_stop; gfloat y_value; if (y < ((_y1 + _y2) >> 1)) value = y - _y1; else value = _y2 - y; y_value = 1.0 - 2.0 * value / (_y2 - _y1 + 1); x_radius = sqrt (1.0 - y_value * y_value) * (_x2 - _x1 + 1) * 0.5; x_start = (_x1 + _x2) * 0.5 - x_radius; x_stop = (_x1 + _x2) * 0.5 + x_radius; raster_set (terrain, x_start, y, x_stop, op); } break; default: break; } t_terrain_selection_modified (terrain); } void t_terrain_select_destroy (TTerrain *terrain) { if (terrain->selection != NULL) { g_free (terrain->selection); t_terrain_selection_modified (terrain); } terrain->selection = NULL; } gint t_terrain_add_object (TTerrain *terrain, gint ox, gint oy, gfloat x, gfloat y, gfloat angle, gfloat scale_x, gfloat scale_y, gfloat scale_z, gchar *object_name) { TTerrainObject object; object.name = g_strdup (object_name); object.ox = ox; object.oy = oy; object.x = x; object.y = y; object.angle = angle; object.scale_x = scale_x; object.scale_y = scale_y; object.scale_z = scale_z; g_array_append_val (terrain->objects, object); gtk_signal_emit (GTK_OBJECT (terrain), object_added_signal, terrain->objects->len - 1); return terrain->objects->len - 1; } void t_terrain_move_object (TTerrain *terrain, gint item, gfloat x, gfloat y) { TTerrainObject *object; object = &g_array_index (terrain->objects, TTerrainObject, item); object->x = CLIP (x, 0.0, 1.0); object->y = CLIP (y, 0.0, 1.0); gtk_signal_emit (GTK_OBJECT (terrain), object_modified_signal, item); } void t_terrain_rotate_object (TTerrain *terrain, gint item, gfloat angle) { g_array_index (terrain->objects, TTerrainObject, item).angle = angle; gtk_signal_emit (GTK_OBJECT (terrain), object_modified_signal, item); } void t_terrain_remove_object (TTerrain *terrain, gint item) { t_terrain_object_clear (&g_array_index (terrain->objects, TTerrainObject, item)); g_array_remove_index_fast (terrain->objects, item); } void t_terrain_remove_objects (TTerrain *terrain) { gint i, size; GArray *objects = terrain->objects; size = objects->len; for (i = 0; i < size; i++) t_terrain_object_clear (&g_array_index (objects, TTerrainObject, i)); for (i = size - 1; i >= 0; i--) gtk_signal_emit (GTK_OBJECT (terrain), object_deleted_signal, i); g_array_free (objects, TRUE); terrain->objects = g_array_new (FALSE, FALSE, sizeof (TTerrainObject)); } /** * t_terrain_seed: seed the specified HF with the specified data. * Returns a partially filled HF! */ gint t_terrain_seed_data (TTerrain *terrain, gfloat *data, gint width, gint height) { gint x, y; gfloat incx, incy; gfloat offx=0, offy=0; gfloat *heightfield = terrain->heightfield; g_return_val_if_fail (data != NULL, -1); g_return_val_if_fail (width > 10, -1); g_return_val_if_fail (height > 10, -1); g_return_val_if_fail (terrain->width > width, -1); g_return_val_if_fail (terrain->height > height, -1); incx = terrain->width / width; incy = terrain->height / height; memset (heightfield, 0, (terrain->width * terrain->height) * sizeof (gfloat)); for (y = 0; y < height; y++, offy += incy, offx = 0) for (x = 0, offx = 0; x < width; x++, offx += incx) { /* printf ("%f, %f\n", offx, offy);fflush (stdout); */ heightfield[(gint)(((gint) offy) * terrain->width + offx)] = data[y * width + x]; } t_terrain_set_modified (terrain, TRUE); return 0; } /** * t_terrain_seed: re-seed the specified terrain with it's data from * the specified region. Optionally resizes the terrain to * new_width * new_height */ gint t_terrain_seed (TTerrain *terrain, gint new_width, gint new_height, gint sel_x, gint sel_y, gint sel_width, gint sel_height) { gint x, y; gint rc; gint sel_size = sel_width*sel_height; gfloat *heightfield = terrain->heightfield; gfloat *data_extract = g_new (gfloat, sel_size); if (sel_x+sel_width > terrain->width) sel_width = terrain->width - sel_x; if (sel_y+sel_height > terrain->height) sel_height = terrain->height - sel_y; for (y=0; ywidth + (sel_x + x); data_extract[offdst] = heightfield[offsrc]; } if (new_width != -1 && new_height != -1) if (new_width != terrain->width && new_height != terrain->height) { terrain->heightfield = g_renew (gfloat, terrain->heightfield, new_width * new_height); terrain->width = new_width; terrain->height = new_height; } rc = t_terrain_seed_data (terrain, data_extract, sel_width, sel_height); if (rc == 0) t_terrain_select_none (terrain); g_free (data_extract); return rc; } TTerrain * t_terrain_tile_new (TTerrain *terrain, gint num_x, gint num_y) { GtkObject *object; TTerrain *tnew; gint lim_x = terrain->width * num_x; gint lim_y = terrain->height * num_y; gint x; gint y; gchar *ext; gchar *base; gchar buf[256]; object = t_terrain_new (lim_x, lim_y); tnew = T_TERRAIN (object); if (terrain->riverfield != NULL) tnew->riverfield = g_new (gfloat, lim_x * lim_y); if (terrain->selection != NULL) tnew->selection = g_new (gfloat, lim_x * lim_y); for (y=0; yheight; for (x=0; xwidth + x % terrain->width; tnew->heightfield[pnew] = terrain->heightfield[porg]; if (terrain->riverfield != NULL) tnew->riverfield[pnew] = terrain->riverfield[porg]; if (terrain->selection != NULL) tnew->selection[pnew] = terrain->selection[porg]; } } base = filename_get_base_without_extension (terrain->filename); ext = filename_get_extension (terrain->filename); snprintf (buf, 256, "%s_tiled_%dx%d.%s", base, num_x, num_y, ext); g_free (base); g_free (ext); tnew->filename = g_strdup (buf); return tnew; }