static PF_COMMAND_FUNC( centroid ) { Data_Obj *dst1_dp; Data_Obj *dst2_dp; Data_Obj *src_dp; Vec_Obj_Args oargs; dst1_dp = PICK_OBJ("x scratch image"); dst2_dp = PICK_OBJ("y scratch image"); src_dp = PICK_OBJ("source image"); if( OBJ_MACH_PREC(src_dp) != PREC_SP && OBJ_MACH_PREC(src_dp) != PREC_DP ){ sprintf(ERROR_STRING,"Object %s (%s) must have %s or %s precision for centroid helper", OBJ_NAME(src_dp),PREC_NAME(OBJ_PREC_PTR(src_dp)),PREC_NAME(PREC_FOR_CODE(PREC_SP)), PREC_NAME(PREC_FOR_CODE(PREC_DP))); WARN(ERROR_STRING); return; } // BUG - do more checking here sizes must match, precisions must match. setvarg3(&oargs,dst1_dp,dst2_dp,src_dp); /* abusing this a little */ if( OBJ_PREC(src_dp) == PREC_SP ) sp_cu2_centroid(&oargs); else if( OBJ_PREC(src_dp) == PREC_DP ) dp_cu2_centroid(&oargs); #ifdef CAUTIOUS else ERROR1("CAUTIOUS: centroid: unexpected source precision!?"); #endif /* CAUTIOUS */ }
void _make_dragg(QSP_ARG_DECL const char *name,Data_Obj *bm,Data_Obj *dp) { Draggable *dgp; if( !dp_same_size(bm,dp,"make_dragg") ){ warn("image/bitmap size mismatch"); return; } if( OBJ_PREC(bm) != PREC_BIT ){ sprintf(ERROR_STRING,"Object %s has precision %s, should be %s", OBJ_NAME(bm),PREC_NAME(OBJ_PREC_PTR(bm)), PREC_NAME(PREC_FOR_CODE(PREC_BIT))); warn(ERROR_STRING); return; } if( OBJ_PREC(dp) != PREC_BY && OBJ_PREC(dp) != PREC_UBY ){ sprintf(ERROR_STRING,"Image %s (for draggable object) has %s precision, should be %s or %s", OBJ_NAME(dp),PREC_NAME(OBJ_PREC_PTR(dp)), PREC_NAME(PREC_FOR_CODE(PREC_BY)), PREC_NAME(PREC_FOR_CODE(PREC_UBY)) ); warn(ERROR_STRING); return; } dgp = new_dragg(name); if( dgp == NULL ) return; dgp->dg_width = (int) OBJ_COLS(dp); dgp->dg_height = (int) OBJ_ROWS(dp); dgp->dg_bitmap = bm; dgp->dg_image = dp; dgp->dg_np = mk_node(dgp); }
static int prec_and_type_match(Data_Obj *dp1,Data_Obj *dp2,const char *func_name) { if( OBJ_PREC(dp1) != OBJ_PREC(dp2) ){ sprintf(DEFAULT_ERROR_STRING,"Function %s: precisions of objects %s (%s) and %s (%s) do not match!?", func_name,OBJ_NAME(dp1),OBJ_PREC_NAME(dp1),OBJ_NAME(dp2),OBJ_PREC_NAME(dp2)); NWARN(DEFAULT_ERROR_STRING); return(0); } return(1); }
void compute_histo(QSP_ARG_DECL Data_Obj *histo_dp,Data_Obj *data_dp,double bin_width,double min_limit) { dimension_t i,j,k; float num; float *histbuf; incr_t index; dimension_t n_bins; int n_under=0, n_over=0; INSIST_RAM_OBJ(histo_dp,compute_histo); INSIST_RAM_OBJ(data_dp,compute_histo); if( OBJ_PREC(histo_dp) != PREC_SP ){ WARN("histogram precision must be float"); return; } if( OBJ_COMPS(histo_dp) != 1 ){ WARN("histogram data must be real"); return; } if( OBJ_ROWS(histo_dp) > 1 || OBJ_FRAMES(histo_dp) > 1 ){ WARN("only using first row of histogram image"); } if( OBJ_COMPS(data_dp) != 1 ){ WARN("input data must be real"); return; } switch( OBJ_PREC(data_dp) ){ case PREC_SP: HISTOGRAM(float) break; case PREC_DP: HISTOGRAM(double) break; case PREC_UBY: HISTOGRAM(u_char) break; case PREC_BY: HISTOGRAM(char) break; case PREC_UIN: HISTOGRAM(u_short) break; case PREC_IN: HISTOGRAM(short) break; case PREC_UDI: HISTOGRAM(u_long) break; case PREC_DI: HISTOGRAM(long) break; default: NWARN("unhandled source precision in histogram"); return; } if( (n_under > 0) || (n_over > 0) ){ sprintf(ERROR_STRING, "Histogram for %s had %d underflows and %d overflows", OBJ_NAME(data_dp),n_under,n_over); advise(ERROR_STRING); } }
static int bad_plot_vec2(QSP_ARG_DECL Data_Obj *dp,dimension_t n_comps_expected,const char *funcname) { if( dp==NO_OBJ ) return 1; if( OBJ_PREC(dp) != PREC_SP && OBJ_PREC(dp) != PREC_DP ) { sprintf(ERROR_STRING, "%s: data vector %s (%s) should have float or double precision", funcname, OBJ_NAME(dp),OBJ_MACH_PREC_NAME(dp)); WARN(ERROR_STRING); return 1; } if( OBJ_COMPS(dp) != n_comps_expected ) { sprintf(ERROR_STRING,"%s: data vector %s (%d) should have %d components", funcname,OBJ_NAME(dp),OBJ_COMPS(dp),n_comps_expected); WARN(ERROR_STRING); return 1; } return 0; }
void set_texture_image(QSP_ARG_DECL Data_Obj *dp) { int code,prec; /*glDepthFunc(GL_LEQUAL); glPixelStorei(GL_UNPACK_ALIGNMENT,1);*/ if(OBJ_COMPS(dp)==1) code=GL_LUMINANCE; else if( OBJ_COMPS(dp) == 3 ) code=GL_RGB; else { sprintf(ERROR_STRING, "set_texture_image: Object %s has type dimension %d, expected 1 or 3", OBJ_NAME(dp),OBJ_COMPS(dp)); warn(ERROR_STRING); return; } if( OBJ_PREC(dp) == PREC_SP ) prec=GL_FLOAT; else if( OBJ_PREC(dp) == PREC_UBY ) prec=GL_UNSIGNED_BYTE; else { sprintf(ERROR_STRING,"set_texture_image: Object %s has precision %s, expected %s or %s", OBJ_NAME(dp),PREC_NAME(OBJ_PREC_PTR(dp)), NAME_FOR_PREC_CODE(PREC_SP),NAME_FOR_PREC_CODE(PREC_UBY)); warn(ERROR_STRING); return; } if( debug & gl_debug ) advise("glTexImage2D"); glTexImage2D(GL_TEXTURE_2D, 0, OBJ_COMPS(dp), OBJ_COLS(dp), OBJ_ROWS(dp), 0, code, prec, OBJ_DATA_PTR(dp)); if( debug & gl_debug ) advise("glTexParameterf (4)"); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); if( debug & gl_debug ) advise("glTexEnv"); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); /*glEnable(GL_TEXTURE_2D); glShadeModel(GL_FLAT);*/ }
void convert_polh_vector(Data_Obj *flt_dp,Data_Obj *polh_dp) { uint32_t i,j; short *rpdp; float *cvt_p; Fmt_Pt fp1; int station; if( OBJ_PREC(flt_dp) != PREC_SP ){ sprintf(ERROR_STRING,"convert_polh_data: object %s has precision %s, should be %s", OBJ_NAME(flt_dp),PREC_NAME(OBJ_PREC_PTR(flt_dp)),PREC_NAME(prec_for_code(PREC_SP))); warn(ERROR_STRING); return; } if( OBJ_COLS(flt_dp) != OBJ_COLS(polh_dp) ){ sprintf(ERROR_STRING,"convert_polh_data: vectors %s (%d) and %s (%d) do not have the same number of columns", OBJ_NAME(flt_dp),OBJ_COLS(flt_dp),OBJ_NAME(polh_dp),OBJ_COLS(polh_dp)); warn(ERROR_STRING); return; } /* BUG should make sure that tdim of flt_dp is correct! */ /* assume that the object has already been checked for proper dim, type... */ if( n_active_stations == 2 ) station=0; else if(n_active_stations < 1 ){ warn("format_polh_vector: no active stations!?"); return; } else station=curr_station_idx; rpdp = (short *) OBJ_DATA_PTR(polh_dp); for(i=0;i<OBJ_COLS(polh_dp);i++){ Polh_Record_Format *prfp; cvt_p = ((float *) OBJ_DATA_PTR(flt_dp)) + i * OBJ_PXL_INC(flt_dp); prfp = &station_info[station].sd_multi_prf; format_polh_data(&fp1,rpdp,prfp); for(j=0;j<prfp->rf_n_data;j++){ Polh_Output_Type type; type = prfp->rf_output[j]; convert_chunk(cvt_p,&fp1,type); cvt_p += od_tbl[type].od_strings; /* BUG not the right variable?... */ } rpdp += prfp->rf_n_words; if( n_active_stations == 2 ) station ^= 1; } }
static int parse_polh_reading( QSP_ARG_DECL Data_Obj *dp, char * s ) { char str[32]; float *f_p; #ifdef QUIP_DEBUG if( debug & debug_polhemus ){ sprintf(ERROR_STRING,"parse_polh_reading \"%s\"",show_printable(DEFAULT_QSP_ARG s)); advise(ERROR_STRING); } #endif /* QUIP_DEBUG */ if( OBJ_PREC(dp) != PREC_SP ){ sprintf(ERROR_STRING,"Object %s has %s precision, should be %s", OBJ_NAME(dp), PREC_NAME(OBJ_PREC_PTR(dp)), PREC_NAME(prec_for_code(PREC_SP)) ); warn(ERROR_STRING); return(-1); } if( ! IS_CONTIGUOUS(dp) ){ sprintf(ERROR_STRING,"Object %s should be contiguous",OBJ_NAME(dp)); warn(ERROR_STRING); return(-1); } if( OBJ_N_MACH_ELTS(dp) < 6 ){ sprintf(ERROR_STRING,"Object %s should have at least 6 elements",OBJ_NAME(dp)); warn(ERROR_STRING); return(-1); } f_p = OBJ_DATA_PTR(dp); if( sscanf(s,"%s %f %f %f %f %f %f",str, f_p+0, f_p+1, f_p+2, f_p+3, f_p+4, f_p+5 ) != 7 ){ sprintf(ERROR_STRING,"Error scanning polhemus data string"); warn(ERROR_STRING); sprintf(ERROR_STRING,"String: \"%s\"",show_printable(DEFAULT_QSP_ARG s)); advise(ERROR_STRING); return(-1); } return(0); }
int good_polh_vector(QSP_ARG_DECL Data_Obj *dp) { int n_expected_words; /* The polhemus can output floats, but we'll assume it's all short here... */ if( dp == NULL ) return(0); if( OBJ_PREC(dp) != PREC_IN && OBJ_PREC(dp) != PREC_UIN ) { sprintf(ERROR_STRING, "Object %s has %s precision, should be %s or %s for polhemus data", OBJ_NAME(dp), OBJ_PREC_NAME(dp), NAME_FOR_PREC_CODE(PREC_IN), NAME_FOR_PREC_CODE(PREC_UIN) ); warn(ERROR_STRING); return(0); } if( n_active_stations == 2 ) n_expected_words = station_info[0].sd_multi_prf.rf_n_words + station_info[1].sd_multi_prf.rf_n_words; else n_expected_words = station_info[curr_station_idx].sd_multi_prf.rf_n_words ; if( OBJ_COMPS(dp) != n_expected_words ) { sprintf(ERROR_STRING, "Object %s has bad type dimensions (%d), should be %d", OBJ_NAME(dp), OBJ_COMPS(dp), n_expected_words); warn(ERROR_STRING); return(0); } if( !IS_CONTIGUOUS(dp) ) { sprintf(ERROR_STRING, "good_polh_vector: Object %s must be contiguous", OBJ_NAME(dp)); warn(ERROR_STRING); return(0); } return(1); }
void corr_matrix(Data_Obj *dpto,Data_Obj *dpfr) { int had_err=0; float *op1, *op2; float *dest, *dest2; dimension_t i,j; Vec_Args args; if( ! is_real(dpto,"corr_matrix") ) return; if( ! is_real(dpfr,"corr_matrix") ) return; if( OBJ_COLS(dpto) != OBJ_ROWS(dpto) ){ sprintf(ERROR_STRING,"target matrix %s (%dx%d) must be square",OBJ_NAME(dpto), OBJ_ROWS(dpto),OBJ_COLS(dpto)); WARN(ERROR_STRING); had_err++; } if( OBJ_COLS(dpto) != OBJ_ROWS(dpfr) ){ sprintf(ERROR_STRING, "target matrix %s size %d not equal to source matrix %s rows (%d)", OBJ_NAME(dpto),OBJ_COLS(dpto),OBJ_NAME(dpfr),OBJ_ROWS(dpfr)); WARN(ERROR_STRING); had_err++; } if( had_err ) return; if( IS_COMPLEX(dpto) ) args.arg_argstype = COMPLEX_ARGS; else args.arg_argstype = REAL_ARGS; args.arg_inc1 = OBJ_PXL_INC(dpfr); args.arg_inc2 = OBJ_PXL_INC(dpfr); args.arg_n1 = OBJ_COLS(dpfr); args.arg_n2 = OBJ_COLS(dpfr); args.arg_prec1 = OBJ_PREC(dpfr); args.arg_prec2 = OBJ_PREC(dpfr); op1 = OBJ_DATA_PTR(dpfr); for(i=0;i<OBJ_ROWS(dpfr);i++){ dest = dest2 = OBJ_DATA_PTR(dpto); dest += i*OBJ_ROW_INC(dpto); dest += i*OBJ_PXL_INC(dpto); dest2 += i*OBJ_PXL_INC(dpto); dest2 += i*OBJ_ROW_INC(dpto); op2 = OBJ_DATA_PTR(dpfr); op2 += i*OBJ_ROW_INC(dpfr); for(j=i;j<OBJ_ROWS(dpfr);j++){ args.arg_v1 = op1; args.arg_v2 = op2; vdot(&args); *dest2 = *dest; /* symmetric matrix */ op2 += OBJ_ROW_INC(dpfr); dest += OBJ_PXL_INC(dpto); dest2 += OBJ_ROW_INC(dpto); } op1 += OBJ_ROW_INC(dpfr); } } /* end corr_matrix() */
// This function allows us to do a different mapping of the image... static void map_cuda_viewer(QSP_ARG_DECL Cuda_Viewer *cvp, Data_Obj *img_dp, Data_Obj *coord_dp) { if( OBJ_PREC(coord_dp) != PREC_SP ){ sprintf(ERROR_STRING, "map_cuda_viewer: coord object %s must have %s precision!?", OBJ_NAME(coord_dp),PREC_NAME(OBJ_PREC_PTR(coord_dp))); WARN(ERROR_STRING); return; } if( ! IS_CONTIGUOUS(coord_dp) ){ sprintf(ERROR_STRING, "map_cuda_viewer: coord object %s must be contiguous!?", OBJ_NAME(coord_dp)); WARN(ERROR_STRING); return; } if( OBJ_COMPS(coord_dp) != 2 ){ sprintf(ERROR_STRING, "map_cuda_viewer: coord object %s must have 2 components!?", OBJ_NAME(coord_dp)); WARN(ERROR_STRING); return; } if( OBJ_COLS(coord_dp) != 2 ){ sprintf(ERROR_STRING, "map_cuda_viewer: coord object %s must have 2 columns!?", OBJ_NAME(coord_dp)); WARN(ERROR_STRING); return; } if( OBJ_ROWS(coord_dp) != 2 ){ sprintf(ERROR_STRING, "map_cuda_viewer: coord object %s must have 2 rows!?", OBJ_NAME(coord_dp)); WARN(ERROR_STRING); return; } #ifdef HAVE_OPENGL float *f; prepare_image_for_mapping(img_dp); f=(float *)OBJ_DATA_PTR(coord_dp); glBegin(GL_QUADS); fprintf(stderr,"first vertex at %f, %f (normally -1, -1)\n",f[0],f[1]); glTexCoord2f(0, 1); glVertex2f( f[0], f[1] ); // -1, -1 fprintf(stderr,"second vertex at %f, %f (normally -1, 1)\n",f[4],f[5]); glTexCoord2f(0, 0); glVertex2f( f[4], f[5] ); // -1, 1 fprintf(stderr,"third vertex at %f, %f (normally 1, 1)\n",f[6],f[7]); glTexCoord2f(1, 0); glVertex2f( f[6], f[7] ); // 1, 1 fprintf(stderr,"fourth vertex at %f, %f (normally 1, -1)\n",f[2],f[3]); glTexCoord2f(1, 1); glVertex2f( f[2], f[3] ); // 1, -1 glEnd(); glBindTexture(GL_TEXTURE_2D, 0); cuda_display_finish(QSP_ARG img_dp); #else // ! HAVE_OPENGL NO_OGL_MSG #endif // ! HAVE_OPENGL }
void multivariate_histo(QSP_ARG_DECL Data_Obj *histo_dp,Data_Obj *data_dp,float *width_array,float *min_array) { dimension_t n_dimensions; dimension_t i,j,k; unsigned int l; float *fbase, *fptr, *f; float *histbuf; incr_t index[MAX_DIMENSIONS]; int n_bins[MAX_DIMENSIONS]; int n_under[MAX_DIMENSIONS], n_over[MAX_DIMENSIONS]; INSIST_RAM_OBJ(histo_dp,compute_histo); INSIST_RAM_OBJ(data_dp,compute_histo); if( OBJ_PREC(histo_dp) != PREC_SP ){ NWARN("2D histogram precision must be float"); return; } if( OBJ_COMPS(histo_dp) != 1 ){ NWARN("2D histogram data must be real"); return; } if( OBJ_PXL_INC(histo_dp) != 1 ){ NWARN("2D histogram data must be contiguous"); return; } n_dimensions = OBJ_COMPS(data_dp); if( n_dimensions > MAX_DIMENSIONS ){ NWARN("Too many 2D histogram dimensions"); return; } if( OBJ_PREC(data_dp) != PREC_SP ){ NWARN("2D data precision must be float"); return; } fbase = (float *) OBJ_DATA_PTR(data_dp); for(l=0;l<n_dimensions;l++){ n_over[l]=0; n_under[l]=0; n_bins[l] = OBJ_TYPE_DIM(histo_dp,l+1); } histbuf = (float *) OBJ_DATA_PTR(histo_dp); zero_dimension(histo_dp,(float *)OBJ_DATA_PTR(histo_dp),n_dimensions,0L); for(l=0;l<MAX_DIMENSIONS;l++) index[l]=0; for(i=0;i<OBJ_FRAMES(data_dp);i++){ fptr = fbase; for(j=0;j<OBJ_ROWS(data_dp);j++){ f=fptr; for(k=0;k<OBJ_COLS(data_dp);k++){ float num[MAX_DIMENSIONS]; for(l=0;l<n_dimensions;l++){ num[l] = f[l]; /* assume cinc=1 */ num[l] -= min_array[l]; num[l] /= width_array[l]; num[l] += 0.5; index[l] = (incr_t)num[l]; /* cast to int */ if( index[l] < 0 ){ index[l]=0; n_under[l]++; } else if( index[l] >= n_bins[l] ){ index[l] = n_bins[l]-1; n_over[l]++; } } histbuf[ index[0] + index[1] * OBJ_ROW_INC(histo_dp) + index[2] * OBJ_FRM_INC(histo_dp) ] += 1.0; f += OBJ_PXL_INC(data_dp); } fptr += OBJ_ROW_INC(data_dp); } fbase += OBJ_FRM_INC(data_dp); } for(l=0;l<n_dimensions;l++){ if( (n_under[l] > 0) || (n_over[l] > 0) ){ sprintf(ERROR_STRING, "Histogram for %s had %d underflows and %d overflows in dimension %d", OBJ_NAME(data_dp),n_under[l],n_over[l],l); advise(ERROR_STRING); } } }
static void test_parport(void) { int n,s; Data_Obj *dp; u_long *lp; FB_Info *fbip; pthread_attr_t attr1; VBoard_Info vbi1; PPort_Info ppti1; u_long l; pthread_attr_init(&attr1); /* initialize to default values */ pthread_attr_setinheritsched(&attr1,PTHREAD_INHERIT_SCHED); fbip = pick_fbi("frame buffer for VSYNC"); dp = pick_obj("data vector for latencies"); if( fbip == NULL || dp == NULL ) return; INSIST_RAM_OBJ(dp,"test_parport") if( OBJ_PREC(dp) != PREC_UDI ){ sprintf(ERROR_STRING,"latency vector %s (%s) should have precision %s", OBJ_NAME(dp),PREC_NAME(OBJ_PREC_PTR(dp)), NAME_FOR_PREC_CODE(PREC_UDI)); WARN(ERROR_STRING); return; } if( OBJ_COMPS(dp) != 2 ){ sprintf(ERROR_STRING,"latency vector %s (%d) should have 2 components", OBJ_NAME(dp),OBJ_COMPS(dp)); WARN(ERROR_STRING); return; } if( ! IS_CONTIGUOUS(dp) ){ sprintf(ERROR_STRING,"latency vector %s should be contiguous",OBJ_NAME(dp)); WARN(ERROR_STRING); return; } n = OBJ_N_MACH_ELTS(dp)/2; lp = (u_long *) OBJ_DATA_PTR(dp); vbi1.vbi_fbip = fbip; vbi1.vbi_buf = lp; vbi1.vbi_count = n; vbi1.vbi_inc = 2; #ifdef THREAD_SAFE_QUERY vbi1.vbi_qsp = THIS_QSP; #endif // THREAD_SAFE_QUERY lp ++; if( the_ppp == NULL ){ the_ppp=open_parport(NULL); /* use default */ if( the_ppp == NULL ) return; } ppti1.ppti_ppp = the_ppp; ppti1.ppti_buf = lp; ppti1.ppti_count = n; ppti1.ppti_inc = 2; tvp = NULL; /* force re-zero */ s=read_til_transition(the_ppp,8); if( s==0 ) s=read_til_transition(the_ppp,8); /* should now be in the one state */ /* this is the end of the (negative) pulse */ l = delta_usecs(); /* zero the clock */ pthread_create(&vboard_thr,&attr1,vboard_daemon,&vbi1); pthread_create(&pport_thr,&attr1,pport_logger,&ppti1); /* should wait for threads here... */ if( pthread_join(vboard_thr,NULL) != 0 ){ perror("pthread_join"); WARN("error joining video board thread"); } if( pthread_join(pport_thr,NULL) != 0 ){ perror("pthread_join"); WARN("error joining parallel port thread"); } }
static COMMAND_FUNC( do_cyplot ) { Data_Obj *dp; Data_Obj *cdp; u_long i, np; /* number of points */ long inc; long cinc; std_type x,y,dx,*yp; char *cp; dp=PICK_OBJ("data vector"); cdp=PICK_OBJ("color vector"); if( dp==NO_OBJ ) return; if( cdp==NO_OBJ ) return; INSIST_RAM_OBJ(dp,"cyplot") INSIST_RAM_OBJ(cdp,"cyplot") if( OBJ_PREC(dp) != PREC_SP ) { WARN("do_cyplot: data vector should be float"); return; } if( OBJ_PREC(cdp) != PREC_BY ) { WARN("color vector should be byte"); return; } if( !dp_same_size(QSP_ARG dp,cdp,"do_cyplot") ) { sprintf(ERROR_STRING,"data vector %s and color vector %s must have identical sizes", OBJ_NAME(dp),OBJ_NAME(cdp)); WARN(ERROR_STRING); return; } if( OBJ_COLS(dp)==1 ) { /* maybe this is a column vector? */ np=OBJ_ROWS(dp); inc = OBJ_ROW_INC(dp); cinc = OBJ_ROW_INC(cdp); } else { np=OBJ_COLS(dp); inc = OBJ_PXL_INC(dp); cinc = OBJ_PXL_INC(cdp); } x=0; dx=1; i=np-1; yp = (std_type *) OBJ_DATA_PTR(dp); cp = (char *) OBJ_DATA_PTR(cdp); xp_fmove(x,*yp); xp_select(*cp); xp_fcont(x,*yp); while(i--) { yp += inc; cp += cinc; x += dx; y = *yp; xp_select(*cp); xp_fcont(x,y); } }