gint create_hf_list (gl_preview_struct *hf) { // Creates the HF list for the current HF gint list, i, j; list = glGenLists(1); // printf("**************CREATE_HF_LIST\n"); glNewList(list, GL_COMPILE); glColor4fv(terrain_colour); for (i=0; i<hf->mesh_size-1; i++) for (j=0; j<hf->mesh_size-1; j++) { glBegin(GL_TRIANGLES); // Triangle 1 // glEdgeFlag(TRUE); draw_vertex(VECTORIZE(i,j,hf->mesh_size),hf->hf); draw_vertex(VECTORIZE(i+1,j,hf->mesh_size),hf->hf); // glEdgeFlag(FALSE); draw_vertex(VECTORIZE(i+1,j+1,hf->mesh_size),hf->hf); // Triangle 2 draw_vertex(VECTORIZE(i,j,hf->mesh_size),hf->hf); // glEdgeFlag(TRUE); draw_vertex(VECTORIZE(i+1,j+1,hf->mesh_size),hf->hf); draw_vertex(VECTORIZE(i,j+1,hf->mesh_size),hf->hf); glEnd(); } glEndList(); glClearColor(0.0, 0.0, 0.0, 1.0); return list; }
void create_vertices(gl_preview_struct *gl_hf) { // Create the Open GL vertices from the HF buffer gint i,j,indx; unsigned int lag; vertex *p1, *p2, *p3, *p4; vertex v1,v2,v3; gfloat step,incx, incy, incz, norm, value, height_scale; switch (gl_hf->data_type) { case GDOUBLE_ID: height_scale = 1.0 / HEIGHT_SCALE; break; case HF_TYPE_ID: height_scale = 65535.0 / HEIGHT_SCALE; break; case GINT_ID: height_scale = 65535.0 / HEIGHT_SCALE; break; default: // UNSIGNED_CHAR_ID height_scale = 256.0 / HEIGHT_SCALE; } step = 2.0 / (gl_hf->mesh_size-1); if (gl_hf->hf) x_free(gl_hf->hf); gl_hf->hf = (vertex *) x_malloc(sizeof(vertex) * (gl_hf->mesh_size+1) * (gl_hf->mesh_size+1), "vertex"); // printf("CREATE_VERTICES - MESH_SIZE: %d; step: %6.4f; Height scale: %5.3f\n", gl_hf->mesh_size, step, height_scale); // Initializing normals for (i=0; i<gl_hf->mesh_size; i++) for (j=0; j<gl_hf->mesh_size; j++) { gl_hf->hf[VECTORIZE(i,j,gl_hf->mesh_size)].nx = 0.0; gl_hf->hf[VECTORIZE(i,j,gl_hf->mesh_size)].ny = 0.0; gl_hf->hf[VECTORIZE(i,j,gl_hf->mesh_size)].nz = 0.0; } // printf("********* Normals initialized *************\n"); // Filling vertices array // **** MODIFY TO ALLOW NON SQUARE GRIDS **** lag = log2i(gl_hf->max_x)-log2i(gl_hf->mesh_size); // printf("***************MAX_X: %d; MESH_SIZE: %d; LAG: %d\n", gl_hf->max_x, gl_hf->mesh_size, lag); for (i=0; i<gl_hf->mesh_size; i++) for (j=0; j<gl_hf->mesh_size; j++) { gl_hf->hf[VECTORIZE(i,j,gl_hf->mesh_size)].x = -1+i*step; gl_hf->hf[VECTORIZE(i,j,gl_hf->mesh_size)].y = -1+j*step; indx = VECTORIZE(j<<lag,i<<lag,gl_hf->max_x); switch (gl_hf->data_type) { case GDOUBLE_ID: value = (gfloat) *(((gdouble*) gl_hf->grid)+indx); break; case HF_TYPE_ID: value = (gfloat) *(((hf_type*) gl_hf->grid)+indx); break; case GINT_ID: value = (gfloat) *(((gint*) gl_hf->grid)+indx); break; default: // UNSIGNED_CHAR_ID value = (gfloat) *(((unsigned char*) gl_hf->grid)+indx); } gl_hf->hf[VECTORIZE(i,j,gl_hf->mesh_size)].z = value / height_scale; } // printf("********* Vertices array filled *************\n"); for (i=0; i<gl_hf->mesh_size-1; i++) for (j=0; j<gl_hf->mesh_size-1; j++) { p1 = &gl_hf->hf[VECTORIZE(i,j,gl_hf->mesh_size)]; p2 = &gl_hf->hf[VECTORIZE(i+1,j,gl_hf->mesh_size)]; p3 = &gl_hf->hf[VECTORIZE(i+1,j+1,gl_hf->mesh_size)]; p4 = &gl_hf->hf[VECTORIZE(i,j+1,gl_hf->mesh_size)]; // v1, v2, v3: vectors used to calculate normals to triangles v1.x = p2->x - p1->x; v1.y = p2->y - p1->y; v1.z = p2->z - p1->z; v2.x = p3->x - p1->x; v2.y = p3->y - p1->y; v2.z = p3->z - p1->z; v3.x = p4->x - p1->x; v3.y = p4->y - p1->y; v3.z = p4->z - p1->z; // Vector product = unnormalized normal incx = v2.y*v1.z - v1.y*v2.z; incy = v2.z*v1.x - v1.z*v2.x; incz = v2.x*v1.y - v1.x*v2.y; norm = sqrt(incx*incx+incy*incy+incz*incz); incx = incx / norm; incy = incy / norm; incz = incz / norm; p1->nx -= incx; p1->ny -= incy; p1->nz -= incz; p2->nx -= incx; p2->ny -= incy; p2->nz -= incz; p3->nx -= incx; p3->ny -= incy; p3->nz -= incz; incx = v3.y*v2.z - v2.y*v3.z; incy = v3.z*v2.x - v2.z*v3.x; incz = v3.x*v2.y - v2.x*v3.y; p1->nx -= incx; p1->ny -= incy; p1->nz -= incz; p3->nx -= incx; p3->ny -= incy; p3->nz -= incz; p4->nx -= incx; p4->ny -= incy; p4->nz -= incz; } // Nomalizing normals for (i=0; i<gl_hf->mesh_size; i++) for (j=0; j<gl_hf->mesh_size; j++) { p1 = &gl_hf->hf[VECTORIZE(i,j,gl_hf->mesh_size)]; norm = sqrt(p1->nx*p1->nx + p1->ny*p1->ny + p1->nz*p1->nz); p1->nx = p1->nx / norm; p1->ny = p1->ny / norm; p1->nz = p1->nz / norm; // printf("(%d,%d): (x,y,z): (%f, %f, %f); (nx,ny,nz): (%f,%f,%f); \n",i,j,p1->x,p1->y,p1->z,p1->nx,p1->ny,p1->nz); } // printf("********* Normals normalized *************\n"); }
void fill_span_from_shadow (hf_type *buffer_in, hf_type *buffer_out, gint xmax, gint ymax, hf_type v1, hf_type v2, hf_type filling_value, gint y, gint x1, gint x2, gint direction, gint select_mode) { gint i, mark1, mark2; glong value_to_test; hf_type output_value; gboolean span_end, filled, to_fill; filled = FALSE; // printf("FILLING y = %d, from x = %d to %d, direction = %d; value: %d\n",y, x1, x2, direction, filling_value); if (write_span(y,encode_span(direction,x1,x2))) { // printf("FILLING in DOUBLE y = %d, from x = %d to %d, direction = %s; value: %d; mode: %s\n",y, x1, x2, // ((direction==0)?"FILL_UP":((direction==1)?"FILL_DOWN":"FILL_BOTH")), filling_value, // ((select_mode==0)?"SELECT_REPLACE":((select_mode==1)?"SELECT_ADD":"SELECT_SUBTRACT"))); return; } // Direction: FILL_UP (North), FILL_DOWN (South), FILL_BOTH if ( direction==FILL_BOTH ) { if ( (y-1) >= 0 ) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, x1, x2, FILL_UP, select_mode); if ( (y+1) <= ymax) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, x1, x2, FILL_DOWN, select_mode); return; } // 1. Calculate direction (FILL_UP or FILL_DOWN) if ( direction==FILL_UP ) y--; else y++; // Test the boundaries in case the function is called // at the first recursivity level with direction <> FILL_BOTH if ( (y<0) || (y>=ymax) ) return; // 2. Process span // 2.1 Backup original span mark1 = x1; mark2 = x2; // 2.2 For x1, if the filling test is true, extend the span as needed output_value = *(buffer_out + VECTORIZE(x1,y,xmax)); if ( (buffer_out==buffer_in) || (select_mode==SELECT_SUBTRACT)) value_to_test = *(buffer_in + VECTORIZE(x1,y,xmax)); else // select_mode==SELECT_ADD / REPLACE || buffer_in != buffer_out value_to_test = ((glong) *(buffer_in + VECTORIZE(x1,y,xmax))) + ((glong) output_value); if ( test_fill (value_to_test, v1, v2, select_mode, output_value) ) { // Filling test is true, we extend the span backwards, filling pixels for (mark1 = x1-1; mark1>=0; mark1--) { output_value = *(buffer_out + VECTORIZE(mark1,y,xmax)); if ( (buffer_out==buffer_in) || (select_mode==SELECT_SUBTRACT)) value_to_test = *(buffer_in + VECTORIZE(mark1,y,xmax)); else // select_mode==SELECT_ADD / REPLACE || buffer_in != buffer_out value_to_test = ((glong) *(buffer_in + VECTORIZE(mark1,y,xmax))) + ((glong) output_value); // Stop when the filling test is false if (! test_fill (value_to_test, v1, v2, select_mode, output_value)){ break; } else *(buffer_out + VECTORIZE(mark1,y,xmax)) = filling_value; } mark1++; } else { // If the filling test is false, narrow the span as needed while ( mark1<=mark2 ) { mark1++; output_value = *(buffer_out + VECTORIZE(mark1,y,xmax)); if ( (buffer_out==buffer_in) || (select_mode==SELECT_SUBTRACT)) value_to_test = *(buffer_in + VECTORIZE(mark1,y,xmax)); else // select_mode==SELECT_ADD / REPLACE || buffer_in != buffer_out value_to_test = ((glong) *(buffer_in + VECTORIZE(mark1,y,xmax))) + ((glong) output_value); if ( test_fill (value_to_test, v1, v2, select_mode, output_value) ) break; } } if (mark1>mark2) return; // Run from mark1 through mark2, filling pixels and calling recursively fill_from_shadow // for the current span, each time a discontinuity is encountered // At this point, the filling test is true for mark1 // If mark1 < x1, then the mark1-x1 range is already filled, including x1 span_end = FALSE; // We don't need to fill pixels before x1, // but we need mark1 to specify the shadow for the span on the next y i = MAX(x1,mark1); // We need to fill the shadow between x1 and mark1, if mark1<(x1-1) if (mark1<(x1-1)) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, mark1, x1, ((direction==FILL_UP) ? FILL_DOWN : FILL_UP ), select_mode ); to_fill = TRUE; while (i<=mark2) { // count++; // if (i==384) // printf("Count: %d; I: %d; Mark1: %d; Mark2: %d\n",count, i, mark1, mark2); if ( to_fill ) { *(buffer_out + VECTORIZE(i,y,xmax)) = filling_value; if (span_end) // begin a new span mark1 = i; span_end = FALSE; filled = TRUE; } else { // The first time the fill condition is false, a span has ended, // we must call "fill_from_shadow" for this span // After, we're looking for the beginning of a new span if ( (!span_end) && (i>x1)) { fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1, v2, filling_value, y, mark1, i-1, direction, select_mode); // If the new span boundary exceeds the old one by more than one pixel, // we start a filling movement on the other direction if ( (i-1) > x2 ) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, x2+1, i-1, ((direction==FILL_UP) ? FILL_DOWN : FILL_UP ), select_mode ); span_end = TRUE; filled = TRUE; } mark1 = i+1; if (mark1>=x2) break; } i++; if (i==xmax) break; output_value = *(buffer_out + VECTORIZE(i,y,xmax)); if ( (buffer_out==buffer_in) || (select_mode==SELECT_SUBTRACT)) value_to_test = *(buffer_in + VECTORIZE(i,y,xmax)); else // select_mode==SELECT_ADD / REPLACE || buffer_in != buffer_out value_to_test = ((glong) *(buffer_in + VECTORIZE(i,y,xmax))) + ((glong) output_value); if ( test_fill (value_to_test, v1, v2, select_mode, output_value) ) { to_fill = TRUE; if (i>x2) { mark2++; // We extend the span as necessary if (mark2==xmax) { mark2--; break; } } } else to_fill = FALSE; } // "Flush" the last span if required if (filled && ((i>mark2) || (i==xmax-1))) { fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, mark1, mark2, direction, select_mode); // If the new span boundary exceeds the old one by more than one pixel, // we start a filling movement on the other direction if ( mark2 > x2 ) fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, x2+1, mark2, ((direction==FILL_UP) ? FILL_DOWN : FILL_UP ), select_mode ); } }
void fill_area_with_mode (hf_type *buffer_in, hf_type *buffer_out, gint xmax, gint ymax, hf_type filling_value, hf_type range, gint x, gint y, gint fill_mode, gint select_mode) { // Fill area in buffer_out around filling seed (x,y) in buffer_in with filling_value // if surrounding pixels value are in a � range // 1. Determine first span // 2. Fill first span // 3. Fill top and bottom spans from shadow // buffer_in and buffer_out could be the same (ex. when drawing faults) // They would be different, for instance, when buffer_in is used as // a select tool // 2005-04-20 Modified to allow filling up to a maximum gint i, x1, x2; hf_type v1, v2, value_to_test; // v1, v2: value to replace (range) // Initialize our control structure if (xmax<=SPAN_MAX) { for (i=0; i<SPAN_LIST_LENGTH; i++) span_list[i]=0; span_count=0; } // Range & filling_value should be >= 1 range = MAX(range,1); filling_value = MAX(filling_value,MIN_FILLING_VALUE); if (fill_mode==FILL_MAX) { v1 = 0; v2 = range; } else { // fill_mode == FILL_RANGE v2 = v1 = *(buffer_in + VECTORIZE(x,y,xmax)); if (v1 >= range) v1 = v1 - range; else v1 = 0; if (range <= (MAX_HF_VALUE - v2)) v2 = v2 + range; else v2 = MAX_HF_VALUE; } *(buffer_out + VECTORIZE(x,y,xmax)) = filling_value; // Find the first span for (x1=x-1; x1>=0; x1--) { value_to_test = *(buffer_in + VECTORIZE(x1,y,xmax)); if (!test_fill(value_to_test,v1,v2,select_mode,*(buffer_out + VECTORIZE(x1,y,xmax)))) { break; } else *(buffer_out + VECTORIZE(x1,y,xmax)) = filling_value; } // end for x1 x1++; for (x2=x+1; x2<xmax; x2++) { value_to_test = *(buffer_in + VECTORIZE(x2,y,xmax)); if (!test_fill(value_to_test,v1,v2,select_mode,*(buffer_out + VECTORIZE(x2,y,xmax)))) { break; } else *(buffer_out + VECTORIZE(x2,y,xmax)) = filling_value; } // end for x2 x2--; fill_span_from_shadow (buffer_in, buffer_out, xmax,ymax, v1,v2, filling_value, y, x1, x2, FILL_BOTH, select_mode); // printf("LAST COUNT: %d\n",span_count); }
void map_init (map_struct *map, gint size, gint level, gint shape, gdouble spacing) { gint x,y, radius, ss; gdouble dlevel, offset, ddist, p, maxd = (gdouble) MAX_HF_VALUE; shape_type *shape_data=NULL; radius = size >> 1; // The map size should always be odd size = 2*radius+1; ss = size * size; map->data = (hf_type *) x_realloc (map->data, sizeof(hf_type) * ss, "hf_type (map->data in draw.c)"); map->tmp = (hf_type *) x_realloc (map->tmp, sizeof(hf_type) * ss, "hf_type (map->tmp in draw.c)"); map->map_to_use = map->data; map->units = (hf_type *) x_realloc (map->units, sizeof(hf_type) * ss, "hf_type (map->units in draw.c)"); FILL_MAP(map->units,ss,1); if (spacing == SPACING_HIGH_QUALITY) { dlevel = LEVEL_HQ_SPACING; } else { if (spacing == SPACING_STANDARD_QUALITY) dlevel = LEVEL_SQ_SPACING; else if (spacing == SPACING_VHIGH_QUALITY) dlevel = LEVEL_VHQ_SPACING; else dlevel = LEVEL_LQ_SPACING; } if (shape != NO_WAVE_SHAPE) { shape_data = shape_type_new(shape, size); map->square_symmetry = FALSE; } else map->square_symmetry = TRUE; // Position (0,0) in the map is the minimum value // We "clamp" all the edges to 0 // The maximum edge value is at (0,radius) or (radius,0) or (2*radius, radius) or (radius, 2*radius) offset = BELLD(CONST_E,2.0,1.5*DIST2(0,0,0,radius),radius); if (shape_data) { // square_symmetry == FALSE dlevel = ((gdouble) level)*dlevel/(100.0*(gdouble) MAX_HF_VALUE); // We intersect the gaussian bell (values from 0.0 to 1.0) with the pen tip shape for (x=0; x<size; x++) for (y=0; y<size; y++) { // Technique #1: gaussian bell on x axis, shape on y axis // A basic technique, giving, with sharps tips, straight lines when the stroke curves /* *(map->data+VECTORIZE(x,y,size)) = (hf_type) (dlevel * *(shape_data+y) * MAX(0.0, BELLD(e,2.0,1.5*ABS(radius-x),radius) - offset) ); */ // Technique #2: same as technique #1, but the shape // is emphasized only around the center // Towards the edges, we average it with a gaussian bell // in proportion with the square of the distance // Increasing the base to 10.0 shortens the shape // so that even with sharp tips, straight lines are invisible in stroke curves p = MAX(0.0, BELLD(10.0,2.0,1.5*ABS(radius-x),radius) - offset); *(map->data+VECTORIZE(x,y,size)) = (hf_type) (dlevel * (p * *(shape_data+y) + (1.0-p) * MAX(0.0, BELLD(CONST_E,2.0,1.5*ABS(radius-y),radius) - offset) * maxd ) * MAX(0.0, BELLD(CONST_E,2.0,1.5*ABS(radius-x),radius) - offset) ); } } else { // Level is relative (50 means 50%) dlevel = ((gdouble) level)*dlevel/100.0; for (x=0; x<(radius+1); x++) for (y=0; y<(radius+1); y++) { ddist = (gdouble) DIST2(0,0,x,y); if (ddist >= radius) *(map->data+VECTORIZE(radius-x,radius-y,radius+1)) = 0; else *(map->data+VECTORIZE(radius-x,radius-y,radius+1)) = (hf_type) (dlevel * MAX(0.0, BELLD(CONST_E,2.0,1.5*ddist,radius) - offset) ); // 0x04FF; // TEST } } map->radius = radius; if (map->dr_buf) draw_buf_free(map->dr_buf); map->dr_buf = draw_buf_new (MULT_SIZE*size/DIV_SIZE); draw_buf_init (map, spacing); if (shape_data) free(shape_data); }