Make mv's use signed chars explicitly.
[xiph/unicode.git] / sushivision / plane-bg.c
blob0d9c056e9a343e73cd92c48207168c5826624426
1 /*
3 * sushivision copyright (C) 2006-2007 Monty <monty@xiph.org>
5 * sushivision is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * sushivision is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with sushivision; see the file COPYING. If not, write to the
17 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 #define _GNU_SOURCE
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <math.h>
28 #include <signal.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <gtk/gtk.h>
32 #include <cairo-ft.h>
33 #include "internal.h"
35 // called from worker thread
36 static void recompute_setup(sv_plane2d_t *pl, sv_panel_t *p,
37 sv_dim_data_t *payload, int dims){
39 pl->image_serialno++;
40 pl->image_x = _sv_dim_panelscale(payload + x_dim, p->w, 0);
41 pl->image_y = _sv_dim_panelscale(payload + y_dim, p->h, 1);
46 // called from worker thread
47 static int image_work(sv_plane2d_t *pl, sv_panel_t *p){
52 // called from worker thread
53 static int data_work(sv_plane2d_t *pl, sv_panel_t *p){
58 // called from GTK/API
59 static void plane_remap(sv_plane2d_t *pl, sv_panel_t *p){
64 sv_plane_t *sv_plane2d_new(){
73 // enter unlocked
74 static void _sv_planez_compute_line(sv_panel_t *p,
75 _sv_plane2d_t *z,
77 int serialno,
79 int dw,
80 int y,
81 int x_d,
82 _sv_scalespace_t sxi,
83 double *dim_vals,
84 _sv_bythread_cache_2d_t *c){
86 _sv_panel2d_t *p2 = p->subtype->p2;
87 int i,j;
89 /* cache access is unlocked because the cache is private to this
90 worker thread */
92 for(j=0;j<dw;j++){
93 double *fout = c->fout;
94 sv_func_t **f = p2->used_function_list;
95 int *obj_y_off = p2->y_fout_offset;
96 int *onum = p2->y_obj_to_panel;
98 /* by function */
99 dim_vals[x_d] = _sv_scalespace_value(&sxi,j);
100 for(i=0;i<p2->used_functions;i++){
101 (*f)->callback(dim_vals,fout);
102 fout += (*f)->outputs;
103 f++;
106 /* process function output by plane type/objective */
107 /* 2d panels currently only care about the Y output value */
109 /* slider map */
110 for(i=0;i<p2->y_obj_num;i++){
111 float val = (float)_sv_slider_val_to_del(p2->range_scales[*onum++], c->fout[*obj_y_off++]);
112 if(isnan(val)){
113 c->y_map[i][j] = -1;
114 }else{
115 if(val<0)val=0;
116 if(val>1)val=1;
117 c->y_map[i][j] = rint(val * (256.f*256.f*256.f));
122 gdk_lock ();
123 if(p->private->plot_serialno == serialno){
124 for(j=0;j<p2->y_obj_num;j++){
125 int *d = p2->y_map[j] + y*dw;
126 int *td = c->y_map[j];
128 memcpy(d,td,dw*sizeof(*d));
132 gdk_unlock ();
135 // call with lock
136 static void _sv_panel2d_clear_pane(sv_panel_t *p){
138 _sv_panel2d_t *p2 = p->subtype->p2;
139 int pw = p2->x.pixels;
140 int ph = p2->y.pixels;
141 int i;
142 _sv_plot_t *plot = PLOT(p->private->graph);
144 for(i=0;i<p2->y_obj_num;i++){
145 // map is freed and nulled to avoid triggering a fast-scale on an empty data pane
146 if(p2->y_map[i])
147 free(p2->y_map[i]);
148 p2->y_map[i]=NULL;
150 // free y_planes so that initial remap doesn't waste time on mix
151 // op; they are recreated during remap at the point the y_todo
152 // vector indicates something to do
153 if(p2->y_planes[i])
154 free(p2->y_planes[i]);
155 p2->y_planes[i] = NULL;
157 // work vector is merely cleared
158 memset(p2->y_planetodo[i], 0, ph*sizeof(**p2->y_planetodo));
161 // clear the background surface
162 if(plot->datarect)
163 memset(plot->datarect, 0, ph*pw*sizeof(*plot->datarect));
165 // the bg is not marked to be refreshed; computation setup will do
166 // that as part of the fast_scale, even if the fast_scale is
167 // short-circuited to a noop.
170 typedef struct{
171 double x;
172 double y;
173 double z;
174 } compute_result;
176 // used by the legend code. this lets us get away with having only a mapped display pane
177 // call with lock
178 static void _sv_panel2d_compute_point(sv_panel_t *p,sv_obj_t *o, double x, double y, compute_result *out){
179 double dim_vals[_sv_dimensions];
180 int i,j;
181 int pflag=0;
182 int eflag=0;
184 // fill in dimensions
185 int x_d = p->private->x_d->number;
186 int y_d = p->private->y_d->number;
188 for(i=0;i<_sv_dimensions;i++){
189 sv_dim_t *dim = _sv_dimension_list[i];
190 dim_vals[i]=dim->val;
193 gdk_unlock ();
195 dim_vals[x_d] = x;
196 dim_vals[y_d] = y;
198 *out = (compute_result){NAN,NAN,NAN,NAN,NAN,NAN,NAN,NAN};
200 // compute
201 for(i=0;i<_sv_functions;i++){
202 sv_func_t *f = _sv_function_list[i];
203 int compflag = 0;
204 double fout[f->outputs];
205 double val;
207 // compute and demultiplex output
208 for(j=0;j<o->outputs;j++){
209 if(o->function_map[j] == i){
211 if(!compflag) f->callback(dim_vals,fout);
212 compflag = 1;
214 val = fout[o->output_map[j]];
215 switch(o->output_types[j]){
216 case 'X':
217 out->x = val;
218 break;
219 case 'Y':
220 out->y = val;
221 break;
222 case 'Z':
223 out->z = val;
224 break;
225 case 'E':
226 if(eflag)
227 out->e2 = val;
228 else
229 out->e1 = val;
230 eflag = 1;
231 break;
232 case 'P':
233 if(pflag)
234 out->p2 = val;
235 else
236 out->p1 = val;
237 pflag = 1;
238 break;
239 case 'M':
240 out->m = val;
241 break;
246 gdk_lock ();
250 /* functions that perform actual graphical rendering */
252 static float _sv_panel2d_resample_helpers_init(_sv_scalespace_t *to, _sv_scalespace_t *from,
253 unsigned char *delA, unsigned char *delB,
254 int *posA, int *posB,
255 int xymul){
256 int i;
257 int dw = from->pixels;
258 int pw = to->pixels;
260 long scalenum = _sv_scalespace_scalenum(to,from);
261 long scaleden = _sv_scalespace_scaleden(to,from);
262 long del = _sv_scalespace_scaleoff(to,from);
263 int bin = del / scaleden;
264 del -= bin * scaleden;
265 int discscale = (scaleden>scalenum?scalenum:scaleden);
266 int total = xymul*scalenum/discscale;
268 for(i=0;i<pw;i++){
269 long del2 = del + scalenum;
270 int sizeceil = (del2 + scaleden - 1)/ scaleden; // ceiling
271 int sizefloor = del2 / scaleden;
273 while(bin<0 && del2>scaleden){
274 bin++;
275 del = 0;
276 del2 -= scaleden;
277 sizeceil--;
280 if(del2 > scaleden && bin>=0 && bin<dw){
281 int rem = total;
283 delA[i] = ((xymul * (scaleden - del)) + (discscale>>1)) / discscale;
284 posA[i] = bin;
285 rem -= delA[i];
286 rem -= xymul*(sizeceil-2);
288 while(bin+sizeceil>dw){
289 sizeceil--;
290 del2=0;
293 del2 %= scaleden;
294 if(rem<0){
295 delA[i] += rem;
296 delB[i] = 0;
297 }else{
298 delB[i] = rem; // don't leak
300 posB[i] = bin+sizeceil;
302 }else{
303 if(bin<0 || bin>=dw){
304 delA[i] = 0;
305 posA[i] = 0;
306 delB[i] = 0;
307 posB[i] = 0;
308 }else{
309 delA[i] = xymul;
310 posA[i] = bin;
311 delB[i] = 0;
312 posB[i] = bin+1;
313 if(del2 == scaleden)del2=0;
317 bin += sizefloor;
318 del = del2;
320 return (float)xymul/total;
323 /* x resample helpers are put in the per-thread cache because locking it would
324 be relatively expensive. */
325 // call while locked
326 static void _sv_panel2d_resample_helpers_manage_x(sv_panel_t *p, _sv_bythread_cache_2d_t *c){
327 _sv_panel2d_t *p2 = p->subtype->p2;
328 if(p->private->plot_serialno != c->serialno){
329 int pw = p2->x.pixels;
330 c->serialno = p->private->plot_serialno;
332 if(c->xdelA)
333 free(c->xdelA);
334 if(c->xdelB)
335 free(c->xdelB);
336 if(c->xnumA)
337 free(c->xnumA);
338 if(c->xnumB)
339 free(c->xnumB);
341 c->xdelA = calloc(pw,sizeof(*c->xdelA));
342 c->xdelB = calloc(pw,sizeof(*c->xdelB));
343 c->xnumA = calloc(pw,sizeof(*c->xnumA));
344 c->xnumB = calloc(pw,sizeof(*c->xnumB));
345 c->xscalemul = _sv_panel2d_resample_helpers_init(&p2->x, &p2->x_v, c->xdelA, c->xdelB, c->xnumA, c->xnumB, 17);
349 /* y resample is in the panel struct as per-row access is already locked */
350 // call while locked
351 static void _sv_panel2d_resample_helpers_manage_y(sv_panel_t *p){
352 _sv_panel2d_t *p2 = p->subtype->p2;
353 if(p->private->plot_serialno != p2->resample_serialno){
354 int ph = p2->y.pixels;
355 p2->resample_serialno = p->private->plot_serialno;
357 if(p2->ydelA)
358 free(p2->ydelA);
359 if(p2->ydelB)
360 free(p2->ydelB);
361 if(p2->ynumA)
362 free(p2->ynumA);
363 if(p2->ynumB)
364 free(p2->ynumB);
366 p2->ydelA = calloc(ph,sizeof(*p2->ydelA));
367 p2->ydelB = calloc(ph,sizeof(*p2->ydelB));
368 p2->ynumA = calloc(ph,sizeof(*p2->ynumA));
369 p2->ynumB = calloc(ph,sizeof(*p2->ynumB));
370 p2->yscalemul = _sv_panel2d_resample_helpers_init(&p2->y, &p2->y_v, p2->ydelA, p2->ydelB, p2->ynumA, p2->ynumB, 15);
374 static inline void _sv_panel2d_mapping_calc( void (*m)(int,int, _sv_lcolor_t *),
375 int low,
376 float range,
377 int in,
378 int alpha,
379 int mul,
380 _sv_lcolor_t *outc){
381 if(mul && in>=alpha){
382 int val = rint((in - low) * range);
383 if(val<0)val=0;
384 if(val>65536)val=65536;
385 m(val,mul,outc);
389 /* the data rectangle is data width/height mapped deltas. we render
390 and subsample at the same time. */
391 /* return: -1 == abort
392 0 == more work to be done in this plane
393 1 == plane fully dispatched (possibly not complete) */
395 /* enter with lock */
396 static int _sv_panel2d_resample_render_y_plane_line(sv_panel_t *p, _sv_bythread_cache_2d_t *c,
397 int plot_serialno, int map_serialno, int y_no){
399 _sv_panel2d_t *p2 = p->subtype->p2;
400 int objnum = p2->y_obj_to_panel[y_no];
401 int *in_data = p2->y_map[y_no];
402 int ph = p2->y.pixels;
404 if(!in_data || !c){
405 p->private->map_complete_count -= ph;
406 return 1;
409 unsigned char *todo = p2->y_planetodo[y_no];
410 int i = p2->y_next_line;
411 int j;
413 /* find a row that needs to be updated */
414 while(i<ph && !todo[i]){
415 p->private->map_complete_count--;
416 p2->y_next_line++;
417 i++;
420 if(i == ph) return 1;
422 p2->y_next_line++;
424 /* row [i] needs to be updated; marshal */
425 _sv_mapping_t *map = p2->mappings+objnum;
426 void (*mapfunc)(int,int, _sv_lcolor_t *) = map->mapfunc;
427 int ol_alpha = rint(p2->alphadel[y_no] * 16777216.f);
428 _sv_ucolor_t *panel = p2->y_planes[y_no];
429 int ol_low = rint(map->low * 16777216.f);
430 float ol_range = map->i_range * (1.f/256.f);
432 int pw = p2->x.pixels;
433 int dw = p2->x_v.pixels;
434 int dh = p2->y_v.pixels;
435 _sv_ccolor_t work[pw];
437 if(!panel)
438 panel = p2->y_planes[y_no] = calloc(pw*ph, sizeof(**p2->y_planes));
440 if(ph!=dh || pw!=dw){
441 /* resampled row computation; may involve multiple data rows */
443 _sv_panel2d_resample_helpers_manage_y(p);
444 _sv_panel2d_resample_helpers_manage_x(p,c);
446 float idel = p2->yscalemul * c->xscalemul;
448 /* by column */
449 int ydelA=p2->ydelA[i];
450 int ydelB=p2->ydelB[i];
451 int ystart=p2->ynumA[i];
452 int yend=p2->ynumB[i];
453 int lh = yend - ystart;
454 int data[lh*dw];
456 memcpy(data,in_data+ystart*dw,sizeof(data));
458 gdk_unlock();
460 unsigned char *xdelA = c->xdelA;
461 unsigned char *xdelB = c->xdelB;
462 int *xnumA = c->xnumA;
463 int *xnumB = c->xnumB;
465 /* by panel col */
466 for(j=0;j<pw;j++){
468 _sv_lcolor_t out = (_sv_lcolor_t){0,0,0,0};
469 int xstart = xnumA[j];
470 int xend = xnumB[j];
471 int dx = xstart;
472 int xA = xdelA[j];
473 int xB = xdelB[j];
474 int y = ystart;
476 // first line
477 if(y<yend){
478 if(dx<xend)
479 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[dx++], ol_alpha, ydelA*xA, &out);
481 for(; dx < xend-1; dx++)
482 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydelA*17, &out);
484 if(dx<xend)
485 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydelA*xB, &out);
486 y++;
489 // mid lines
490 for(;y<yend-1;y++){
491 dx = xstart += dw;
492 xend += dw;
493 if(dx<xend)
494 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[dx++], ol_alpha, 15*xA, &out);
496 for(; dx < xend-1; dx++)
497 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, 255, &out);
499 if(dx<xend)
500 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, 15*xB, &out);
503 // last line
504 if(y<yend){
505 dx = xstart += dw;
506 xend += dw;
507 if(dx<xend)
508 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[dx++], ol_alpha, ydelB*xA, &out);
510 for(; dx < xend-1; dx++)
511 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydelB*17, &out);
513 if(dx<xend)
514 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[dx], ol_alpha, ydelB*xB, &out);
517 work[j].a = (u_int32_t)(out.a*idel);
518 work[j].r = (u_int32_t)(out.r*idel);
519 work[j].g = (u_int32_t)(out.g*idel);
520 work[j].b = (u_int32_t)(out.b*idel);
524 }else{
525 /* non-resampling render */
527 int data[dw];
528 memcpy(data,in_data+i*dw,sizeof(data));
529 gdk_unlock();
531 for(j=0;j<pw;j++){
533 _sv_lcolor_t out = (_sv_lcolor_t){0,0,0,0};
534 _sv_panel2d_mapping_calc(mapfunc, ol_low, ol_range, data[j], ol_alpha, 255, &out);
536 work[j].a = (u_int32_t)(out.a);
537 work[j].r = (u_int32_t)(out.r);
538 work[j].g = (u_int32_t)(out.g);
539 work[j].b = (u_int32_t)(out.b);
543 gdk_lock ();
544 if(plot_serialno != p->private->plot_serialno ||
545 map_serialno != p->private->map_serialno)
546 return -1;
547 memcpy(panel+i*pw,work,sizeof(work));
548 p2->bg_todo[i] = 1;
549 p2->y_planetodo[y_no][i] = 0;
551 // must be last; it indicates completion
552 p->private->map_complete_count--;
553 return 0;
556 static void render_checks(_sv_ucolor_t *c, int w, int y){
557 /* default checked background */
558 /* 16x16 'mid-checks' */
559 int x,j;
561 int phase = (y>>4)&1;
562 for(x=0;x<w;){
563 u_int32_t phaseval = 0xff505050UL;
564 if(phase) phaseval = 0xff808080UL;
565 for(j=0;j<16 && x<w;j++,x++)
566 c[x].u = phaseval;
567 phase=!phase;
571 // enter with lock
572 static int _sv_panel2d_render_bg_line(sv_panel_t *p, int plot_serialno, int map_serialno){
573 _sv_panel2d_t *p2 = p->subtype->p2;
574 _sv_plot_t *plot = PLOT(p->private->graph);
575 if(plot_serialno != p->private->plot_serialno ||
576 map_serialno != p->private->map_serialno) return -1;
578 int ph = p2->y.pixels;
579 int pw = p2->x.pixels;
580 unsigned char *todo = p2->bg_todo;
581 int i = p2->bg_next_line,j;
582 _sv_ucolor_t work_bg[pw];
583 _sv_ucolor_t work_pl[pw];
584 int bgmode = p->private->bg_type;
586 /* find a row that needs to be updated */
587 while(i<ph && !todo[i]){
588 p->private->map_complete_count--;
589 p2->bg_next_line++;
590 i++;
593 if(i == ph)
594 goto done;
596 if(i < p2->bg_first_line) p2->bg_first_line = i;
597 if(i+1 > p2->bg_last_line) p2->bg_last_line = i+1;
598 p2->bg_next_line++;
600 /* gray background checks */
601 gdk_unlock();
603 switch(bgmode){
604 case SV_BG_WHITE:
605 for(j=0;j<pw;j++)
606 work_bg[j].u = 0xffffffffU;
607 break;
608 case SV_BG_BLACK:
609 for(j=0;j<pw;j++)
610 work_bg[j].u = 0xff000000U;
611 break;
612 default:
613 render_checks(work_bg,pw,i);
614 break;
617 /* by objective */
618 for(j=0;j<p->objectives;j++){
619 int o_ynum = p2->y_obj_from_panel[j];
621 gdk_lock();
622 if(plot_serialno != p->private->plot_serialno ||
623 map_serialno != p->private->map_serialno) return -1;
625 /**** mix Y plane */
627 if(p2->y_planes[o_ynum]){
628 int x;
629 _sv_ucolor_t (*mixfunc)(_sv_ucolor_t,_sv_ucolor_t) = p2->mappings[j].mixfunc;
630 _sv_ucolor_t *rect = p2->y_planes[o_ynum] + i*pw;
631 memcpy(work_pl,rect,sizeof(work_pl));
633 gdk_unlock();
634 for(x=0;x<pw;x++)
635 work_bg[x] = mixfunc(work_pl[x],work_bg[x]);
636 }else
637 gdk_unlock();
639 /**** mix Z plane */
641 /**** mix vector plane */
645 gdk_lock();
646 if(plot_serialno != p->private->plot_serialno ||
647 map_serialno != p->private->map_serialno) return -1;
649 // rendered a line, get it on the screen */
651 memcpy(plot->datarect+pw*i, work_bg, sizeof(work_bg));
653 p->private->map_complete_count--;
655 done:
656 if(p->private->map_complete_count)
657 return 1; // not done yet
659 return 0;
662 static void _sv_panel2d_mark_map_full(sv_panel_t *p);
664 // enter with lock; returns zero if thread should sleep / get distracted
665 static int _sv_panel2d_remap(sv_panel_t *p, _sv_bythread_cache_2d_t *thread_cache){
666 _sv_panel2d_t *p2 = p->subtype->p2;
667 _sv_plot_t *plot = PLOT(p->private->graph);
669 if(!plot) goto abort;
670 int ph = plot->y.pixels;
671 int pw = plot->x.pixels;
673 int plot_serialno = p->private->plot_serialno;
674 int map_serialno = p->private->map_serialno;
676 /* brand new remap indicated by the generic progress indicator being set to 0 */
677 if(p->private->map_progress_count == 0){
679 p->private->map_progress_count = 1; // 'in progress'
680 p->private->map_complete_count = p2->y_obj_num * ph; // count down to 0; 0 indicates completion
682 // set up Y plane rendering
683 p2->y_next_plane = 0;
684 p2->y_next_line = 0;
686 // bg mix
687 p2->bg_next_line = 0;
688 p2->bg_first_line = ph;
689 p2->bg_last_line = 0;
691 if(!p2->partial_remap)
692 _sv_panel2d_mark_map_full(p);
695 /* by plane, by line; each plane renders independently */
696 /* Y planes */
697 if(p2->y_planetodo){
698 if(p2->y_next_plane < p2->y_obj_num){
699 int status = _sv_panel2d_resample_render_y_plane_line(p, thread_cache,
700 plot_serialno, map_serialno,
701 p2->y_next_plane);
702 if(status == -1) goto abort;
703 if(status == 1){
704 p2->y_next_plane++;
705 p2->y_next_line = 0;
707 return 1;
709 }else{
710 p->private->map_complete_count = 0;
713 /* renders have been completely dispatched, but are they complete? */
714 /* the below is effectively a a thread join */
715 if(p2->bg_next_line == 0){
717 // join still needs to complete....
718 if(p->private->map_complete_count){
719 // nonzero complete count, not finished. returning zero will cause
720 // this worker thread to sleep or go on to do other things.
721 return 0;
722 }else{
723 // zero complete count, the planes are done; we can begin
724 // background render. At least one thread is guaranteed to get
725 // here, which is enough; we can now wake the others [if they were
726 // asleep] and have them look for work here. */
727 p->private->map_complete_count = ph; // [ph] lines to render in bg plane
728 p2->bg_next_line = 0;
730 _sv_wake_workers();
734 /* mix new background, again line by line */
735 if(p2->bg_next_line < ph){
736 int status = _sv_panel2d_render_bg_line(p, plot_serialno, map_serialno);
737 if(status == -1) goto abort;
738 if(p->private->map_complete_count)return status;
739 }else
740 return 0; // nothing left to dispatch
742 // entirely finished.
744 // remap completed; flush background to screen
745 _sv_plot_expose_request_partial (plot,0,p2->bg_first_line,
746 pw,p2->bg_last_line - p2->bg_first_line);
747 gdk_flush();
749 // clean bg todo list
750 memset(p2->bg_todo,0,ph*sizeof(*p2->bg_todo));
752 // clear 'panel in progress' flag
753 p2->partial_remap = 0;
754 _sv_panel_clean_map(p);
755 return 0;
757 abort:
758 // reset progress to 'start over'
759 return 1;
762 // looks like a cop-out but is actually the correct thing to do; the
763 // data *must* be WYSIWYG from panel display.
764 static void _sv_panel2d_print_bg(sv_panel_t *p, cairo_t *c){
765 _sv_plot_t *plot = PLOT(p->private->graph);
767 if(!plot) return;
769 cairo_pattern_t *pattern = cairo_pattern_create_for_surface(plot->back);
770 cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
771 cairo_set_source(c,pattern);
772 cairo_paint(c);
774 cairo_pattern_destroy(pattern);
777 static void _sv_panel2d_print(sv_panel_t *p, cairo_t *c, int w, int h){
778 _sv_panel2d_t *p2 = p->subtype->p2;
779 _sv_plot_t *plot = PLOT(p->private->graph);
780 double pw = p->private->graph->allocation.width;
781 double ph = p->private->graph->allocation.height;
782 double scale;
783 int i;
784 double maxlabelw=0;
785 double y;
787 if(w/pw < h/ph)
788 scale = w/pw;
789 else
790 scale = h/ph;
792 cairo_matrix_t m;
793 cairo_save(c);
794 cairo_get_matrix(c,&m);
795 cairo_matrix_scale(&m,scale,scale);
796 cairo_set_matrix(c,&m);
798 _sv_plot_print(plot, c, ph*scale, (void(*)(void *, cairo_t *))_sv_panel2d_print_bg, p);
799 cairo_restore(c);
801 // find extents widths for objective scale labels
802 cairo_set_font_size(c,10);
803 for(i=0;i<p->objectives;i++){
804 cairo_text_extents_t ex;
805 sv_obj_t *o = p->objective_list[i].o;
806 cairo_text_extents(c, o->name, &ex);
807 if(ex.width > maxlabelw) maxlabelw=ex.width;
811 y = ph * scale + 10;
813 for(i=0;i<p->objectives;i++){
814 sv_obj_t *o = p->objective_list[i].o;
815 _sv_slider_t *s = p2->range_scales[i];
817 // get scale height
818 double labelh = _sv_slider_print_height(s);
819 cairo_text_extents_t ex;
820 cairo_text_extents (c, o->name, &ex);
822 int lx = maxlabelw - ex.width;
823 int ly = labelh/2 + ex.height/2;
825 // print objective labels
826 cairo_set_source_rgb(c,0.,0.,0.);
827 cairo_move_to (c, lx,ly+y);
828 cairo_show_text (c, o->name);
830 // draw slider
831 // set translation
832 cairo_save(c);
833 cairo_translate (c, maxlabelw + 10, y);
834 _sv_slider_print(s, c, pw*scale - maxlabelw - 10, labelh);
835 cairo_restore(c);
837 y += labelh;
842 // call while locked
843 static void _sv_panel2d_mark_map_plane(sv_panel_t *p, int onum, int y, int z, int v){
844 _sv_panel2d_t *p2 = p->subtype->p2;
845 int ph = p2->y.pixels;
847 if(y && p2->y_planetodo){
848 int y_no = p2->y_obj_from_panel[onum];
849 if(y_no>=0 && p2->y_planetodo[y_no])
850 memset(p2->y_planetodo[y_no],1,ph * sizeof(**p2->y_planetodo));
852 p2->partial_remap = 1;
855 // call while locked
856 static void _sv_panel2d_mark_map_line_y(sv_panel_t *p, int line){
857 // determine all panel lines this y data line affects
858 _sv_panel2d_t *p2 = p->subtype->p2;
859 int ph = p2->y.pixels;
860 int pw = p2->x.pixels;
861 int dw = p2->x_v.pixels;
862 int dh = p2->y_v.pixels;
863 int i,j;
865 p2->partial_remap = 1;
867 if(ph!=dh || pw!=dw){
868 /* resampled row computation; may involve multiple data rows */
869 if(p2->y_planetodo){
870 _sv_panel2d_resample_helpers_manage_y(p);
872 for(i=0;i<ph;i++)
873 if(p2->ynumA[i]<=line &&
874 p2->ynumB[i]>line){
876 for(j=0;j<p2->y_obj_num;j++)
877 if(p2->y_planetodo[j])
878 p2->y_planetodo[j][i]=1;
881 }else{
882 if(p2->y_planetodo)
883 if(line>=0 && line<ph)
884 for(j=0;j<p2->y_obj_num;j++)
885 if(p2->y_planetodo[j])
886 p2->y_planetodo[j][line]=1;
890 // call while locked
891 static void _sv_panel2d_mark_map_full(sv_panel_t *p){
892 _sv_panel2d_t *p2 = p->subtype->p2;
893 int ph = p2->y.pixels;
894 int i,j;
896 p2->partial_remap = 1;
898 if(p2->y_planetodo){
899 for(j=0;j<p2->y_obj_num;j++){
900 if(p2->y_planetodo[j]){
901 for(i=0;i<ph;i++){
902 p2->y_planetodo[j][i]=1;
909 // enter with lock
910 static void _sv_panel2d_update_legend(sv_panel_t *p){
911 _sv_panel2d_t *p2 = p->subtype->p2;
912 _sv_plot_t *plot = PLOT(p->private->graph);
914 if(plot){
915 int i;
916 char buffer[320];
917 int depth = 0;
918 _sv_plot_legend_clear(plot);
920 // potentially add each dimension to the legend; add axis
921 // dimensions only if crosshairs are active
923 // display decimal precision relative to display scales
924 if(3-_sv_scalespace_decimal_exponent(&p2->x) > depth)
925 depth = 3-_sv_scalespace_decimal_exponent(&p2->x);
926 if(3-_sv_scalespace_decimal_exponent(&p2->y) > depth)
927 depth = 3-_sv_scalespace_decimal_exponent(&p2->y);
928 for(i=0;i<p->dimensions;i++){
929 sv_dim_t *d = p->dimension_list[i].d;
930 if( (d!=p->private->x_d && d!=p->private->y_d) ||
931 plot->cross_active){
932 snprintf(buffer,320,"%s = %+.*f",
933 p->dimension_list[i].d->legend,
934 depth,
935 p->dimension_list[i].d->val);
936 _sv_plot_legend_add(plot,buffer);
940 // add each active objective plane to the legend
941 // choose the value under the crosshairs
942 if(plot->cross_active){
943 // one space
944 _sv_plot_legend_add(plot,NULL);
946 for(i=0;i<p->objectives;i++){
948 if(!_sv_mapping_inactive_p(p2->mappings+i)){
949 compute_result vals;
950 _sv_panel2d_compute_point(p,p->objective_list[i].o, plot->selx, plot->sely, &vals);
952 if(!isnan(vals.y)){
954 snprintf(buffer,320,"%s = %f",
955 p->objective_list[i].o->name,
956 vals.y);
957 _sv_plot_legend_add(plot,buffer);
965 static void _sv_panel2d_mapchange_callback(GtkWidget *w,gpointer in){
966 sv_obj_list_t *optr = (sv_obj_list_t *)in;
967 //sv_obj_t *o = optr->o;
968 sv_panel_t *p = optr->p;
969 _sv_panel2d_t *p2 = p->subtype->p2;
970 int onum = optr - p->objective_list;
972 _sv_undo_push();
973 _sv_undo_suspend();
975 _sv_mapping_set_func(&p2->mappings[onum],gtk_combo_box_get_active(GTK_COMBO_BOX(w)));
977 //redraw the map slider
978 _sv_slider_set_gradient(p2->range_scales[onum], &p2->mappings[onum]);
980 // in the event the mapping active state changed
981 _sv_panel_dirty_legend(p);
983 //redraw the plot
984 _sv_panel2d_mark_map_plane(p,onum,1,0,0);
985 _sv_panel_dirty_map(p);
986 _sv_undo_resume();
989 static void _sv_panel2d_map_callback(void *in,int buttonstate){
990 sv_obj_list_t *optr = (sv_obj_list_t *)in;
991 //sv_obj_t *o = optr->o;
992 sv_panel_t *p = optr->p;
993 _sv_panel2d_t *p2 = p->subtype->p2;
994 int onum = optr - p->objective_list;
996 if(buttonstate == 0){
997 _sv_undo_push();
998 _sv_undo_suspend();
1001 // recache alpha del */
1002 p2->alphadel[onum] =
1003 _sv_slider_val_to_del(p2->range_scales[onum],
1004 _sv_slider_get_value(p2->range_scales[onum],1));
1006 // redraw the plot on motion
1007 if(buttonstate == 1){
1008 _sv_panel2d_mark_map_plane(p,onum,1,0,0);
1009 _sv_panel_dirty_map(p);
1011 if(buttonstate == 2)
1012 _sv_undo_resume();
1015 static void _sv_panel2d_update_xysel(sv_panel_t *p){
1016 _sv_panel2d_t *p2 = p->subtype->p2;
1017 int i;
1018 // update which x/y buttons are pressable */
1019 // enable/disable dimension slider thumbs
1021 for(i=0;i<p->dimensions;i++){
1022 if(p2->dim_xb[i] &&
1023 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_xb[i]))){
1024 // make the y insensitive
1025 if(p2->dim_yb[i])
1026 _gtk_widget_set_sensitive_fixup(p2->dim_yb[i],FALSE);
1028 // set the x dim flag
1029 p->private->x_d = p->dimension_list[i].d;
1030 p2->x_scale = p->private->dim_scales[i];
1031 p2->x_dnum = i;
1032 }else{
1033 // if there is a y, make it sensitive
1034 if(p2->dim_yb[i])
1035 _gtk_widget_set_sensitive_fixup(p2->dim_yb[i],TRUE);
1037 if(p2->dim_yb[i] &&
1038 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_yb[i]))){
1039 // make the x insensitive
1040 if(p2->dim_xb[i])
1041 _gtk_widget_set_sensitive_fixup(p2->dim_xb[i],FALSE);
1043 // set the y dim
1044 p->private->y_d = p->dimension_list[i].d;
1045 p2->y_scale = p->private->dim_scales[i];
1046 p2->y_dnum = i;
1047 }else{
1048 // if there is a x, make it sensitive
1049 if(p2->dim_xb[i])
1050 _gtk_widget_set_sensitive_fixup(p2->dim_xb[i],TRUE);
1052 if((p2->dim_xb[i] &&
1053 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_xb[i]))) ||
1054 (p2->dim_yb[i] &&
1055 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(p2->dim_yb[i])))){
1056 // make all thumbs visible
1057 _sv_dim_widget_set_thumb_active(p->private->dim_scales[i],0,1);
1058 _sv_dim_widget_set_thumb_active(p->private->dim_scales[i],2,1);
1059 }else{
1060 // make bracket thumbs invisible */
1061 _sv_dim_widget_set_thumb_active(p->private->dim_scales[i],0,0);
1062 _sv_dim_widget_set_thumb_active(p->private->dim_scales[i],2,0);
1067 static int _v_swizzle(int y, int height){
1068 int yy = height >> 5;
1069 if(y < yy)
1070 return (y<<5)+31;
1072 y -= yy;
1073 yy = (height+16) >> 5;
1074 if(y < yy)
1075 return (y<<5)+15;
1077 y -= yy;
1078 yy = (height+8) >> 4;
1079 if(y < yy)
1080 return (y<<4)+7;
1082 y -= yy;
1083 yy = (height+4) >> 3;
1084 if(y < yy)
1085 return (y<<3)+3;
1087 y -= yy;
1088 yy = (height+2) >> 2;
1089 if(y < yy)
1090 return (y<<2)+1;
1092 y -= yy;
1093 return y<<1;
1096 // assumes data is locked
1097 static void _sv_panel2d_fast_scale_x(_sv_spinner_t *sp,
1098 int *data,
1099 int w,
1100 int h,
1101 _sv_scalespace_t new,
1102 _sv_scalespace_t old){
1103 int x,y;
1104 int work[w];
1105 int mapbase[w];
1106 int mapdel[w];
1107 double old_w = old.pixels;
1108 double new_w = new.pixels;
1110 double old_lo = _sv_scalespace_value(&old,0);
1111 double old_hi = _sv_scalespace_value(&old,old_w);
1112 double new_lo = _sv_scalespace_value(&new,0);
1113 double new_hi = _sv_scalespace_value(&new,new_w);
1114 double newscale = (new_hi-new_lo)/new_w;
1115 double oldscale = old_w/(old_hi-old_lo);
1116 for(x=0;x<w;x++){
1117 double xval = (x)*newscale+new_lo;
1118 double map = ((xval-old_lo)*oldscale);
1119 int base = (int)floor(map);
1120 int del = rint((map - floor(map))*64.f);
1121 /* hack to overwhelm roundoff error; this is inside a purely
1122 temporary cosmetic approximation anyway*/
1123 if(base>0 && del==0){
1124 mapbase[x]=base-1;
1125 mapdel[x]=64;
1126 }else{
1127 mapbase[x]=base;
1128 mapdel[x]=del;
1132 for(y=0;y<h;y++){
1133 int *data_line = data+y*w;
1134 _sv_spinner_set_busy(sp);
1135 for(x=0;x<w;x++){
1136 if(mapbase[x]<0 || mapbase[x]>=(w-1)){
1137 work[x]=-1;
1138 }else{
1139 int base = mapbase[x];
1140 int A = data_line[base];
1141 int B = data_line[base+1];
1142 if(A<0 || B<0)
1143 work[x]=-1;
1144 else
1145 work[x]= A + (((B - A)*mapdel[x])>>6);
1149 memcpy(data_line,work,w*(sizeof(*work)));
1153 static void _sv_panel2d_fast_scale_y(_sv_spinner_t *sp,
1154 int *olddata,
1155 int *newdata,
1156 int oldw,
1157 int neww,
1158 _sv_scalespace_t new,
1159 _sv_scalespace_t old){
1160 int x,y;
1161 int w = (oldw<neww?oldw:neww);
1163 int old_h = old.pixels;
1164 int new_h = new.pixels;
1166 int mapbase[new_h];
1167 int mapdel[new_h];
1169 double old_lo = _sv_scalespace_value(&old,0);
1170 double old_hi = _sv_scalespace_value(&old,(double)old_h);
1171 double new_lo = _sv_scalespace_value(&new,0);
1172 double new_hi = _sv_scalespace_value(&new,(double)new_h);
1173 double newscale = (new_hi-new_lo)/new_h;
1174 double oldscale = old_h/(old_hi-old_lo);
1176 for(y=0;y<new_h;y++){
1177 double yval = (y)*newscale+new_lo;
1178 double map = ((yval-old_lo)*oldscale);
1179 int base = (int)floor(map);
1180 int del = rint((map - floor(map))*64.);
1181 /* hack to overwhelm roundoff error; this is inside a purely
1182 temporary cosmetic approximation anyway */
1183 if(base>0 && del==0){
1184 mapbase[y]=base-1;
1185 mapdel[y]=64;
1186 }else{
1187 mapbase[y]=base;
1188 mapdel[y]=del;
1193 for(y=0;y<new_h;y++){
1194 int base = mapbase[y];
1195 int *new_column = &newdata[y*neww];
1196 _sv_spinner_set_busy(sp);
1198 if(base<0 || base>=(old_h-1)){
1199 for(x=0;x<w;x++)
1200 new_column[x] = -1;
1201 }else{
1202 int del = mapdel[y];
1203 int *old_column = &olddata[base*oldw];
1205 for(x=0;x<w;x++){
1206 int A = old_column[x];
1207 int B = old_column[x+oldw];
1208 if(A<0 || B<0)
1209 new_column[x]=-1;
1210 else
1211 new_column[x]= A + (((B-A)*del)>>6);
1217 static void _sv_panel2d_fast_scale(_sv_spinner_t *sp,
1218 int *newdata,
1219 _sv_scalespace_t xnew,
1220 _sv_scalespace_t ynew,
1221 int *olddata,
1222 _sv_scalespace_t xold,
1223 _sv_scalespace_t yold){
1225 int new_w = xnew.pixels;
1226 int new_h = ynew.pixels;
1227 int old_w = xold.pixels;
1228 int old_h = yold.pixels;
1230 if(new_w > old_w){
1231 _sv_panel2d_fast_scale_y(sp,olddata,newdata,old_w,new_w,ynew,yold);
1232 _sv_panel2d_fast_scale_x(sp,newdata,new_w,new_h,xnew,xold);
1233 }else{
1234 _sv_panel2d_fast_scale_x(sp,olddata,old_w,old_h,xnew,xold);
1235 _sv_panel2d_fast_scale_y(sp,olddata,newdata,old_w,new_w,ynew,yold);
1239 // call only from main gtk thread
1240 static void _sv_panel2d_mark_recompute(sv_panel_t *p){
1241 if(!p->private->realized) return;
1242 _sv_plot_t *plot = PLOT(p->private->graph);
1244 if(plot && GTK_WIDGET_REALIZED(GTK_WIDGET(plot))){
1245 _sv_panel_dirty_plot(p);
1249 static void _sv_panel2d_update_crosshairs(sv_panel_t *p){
1250 _sv_plot_t *plot = PLOT(p->private->graph);
1251 double x=0,y=0;
1252 int i;
1254 for(i=0;i<p->dimensions;i++){
1255 sv_dim_t *d = p->dimension_list[i].d;
1256 if(d == p->private->x_d)
1257 x = d->val;
1258 if(d == p->private->y_d)
1259 y = d->val;
1263 _sv_plot_set_crosshairs(plot,x,y);
1264 _sv_panel_dirty_legend(p);
1267 static void _sv_panel2d_center_callback(sv_dim_list_t *dptr){
1268 sv_dim_t *d = dptr->d;
1269 sv_panel_t *p = dptr->p;
1270 int axisp = (d == p->private->x_d || d == p->private->y_d);
1272 if(!axisp){
1273 // mid slider of a non-axis dimension changed, rerender
1274 _sv_panel2d_mark_recompute(p);
1275 }else{
1276 // mid slider of an axis dimension changed, move crosshairs
1277 _sv_panel2d_update_crosshairs(p);
1281 static void _sv_panel2d_bracket_callback(sv_dim_list_t *dptr){
1282 sv_dim_t *d = dptr->d;
1283 sv_panel_t *p = dptr->p;
1284 int axisp = (d == p->private->x_d || d == p->private->y_d);
1286 if(axisp)
1287 _sv_panel2d_mark_recompute(p);
1291 static void _sv_panel2d_dimchange_callback(GtkWidget *button,gpointer in){
1292 sv_panel_t *p = (sv_panel_t *)in;
1294 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))){
1296 _sv_undo_push();
1297 _sv_undo_suspend();
1299 _sv_plot_unset_box(PLOT(p->private->graph));
1300 _sv_panel2d_update_xysel(p);
1302 _sv_panel2d_clear_pane(p);
1303 _sv_panel2d_mark_recompute(p);
1304 _sv_panel2d_update_crosshairs(p);
1306 _sv_undo_resume();
1310 static void _sv_panel2d_crosshairs_callback(sv_panel_t *p){
1311 double x=PLOT(p->private->graph)->selx;
1312 double y=PLOT(p->private->graph)->sely;
1313 int i;
1315 _sv_undo_push();
1316 _sv_undo_suspend();
1318 //plot_snap_crosshairs(PLOT(p->private->graph));
1320 for(i=0;i<p->dimensions;i++){
1321 sv_dim_t *d = p->dimension_list[i].d;
1322 if(d == p->private->x_d){
1323 _sv_dim_widget_set_thumb(p->private->dim_scales[i],1,x);
1326 if(d == p->private->y_d){
1327 _sv_dim_widget_set_thumb(p->private->dim_scales[i],1,y);
1330 p->private->oldbox_active = 0;
1333 // dimension setting might have enforced granularity restrictions;
1334 // have the display reflect that
1335 x = p->private->x_d->val;
1336 y = p->private->y_d->val;
1338 _sv_plot_set_crosshairs(PLOT(p->private->graph),x,y);
1340 _sv_panel_dirty_legend(p);
1341 _sv_undo_resume();
1344 static void _sv_panel2d_box_callback(void *in, int state){
1345 sv_panel_t *p = (sv_panel_t *)in;
1346 _sv_panel2d_t *p2 = p->subtype->p2;
1347 _sv_plot_t *plot = PLOT(p->private->graph);
1349 switch(state){
1350 case 0: // box set
1351 _sv_undo_push();
1352 _sv_plot_box_vals(plot,p2->oldbox);
1353 p->private->oldbox_active = plot->box_active;
1354 break;
1355 case 1: // box activate
1356 _sv_undo_push();
1357 _sv_undo_suspend();
1359 _sv_panel2d_crosshairs_callback(p);
1361 _sv_dim_widget_set_thumb(p2->x_scale,0,p2->oldbox[0]);
1362 _sv_dim_widget_set_thumb(p2->x_scale,2,p2->oldbox[1]);
1363 _sv_dim_widget_set_thumb(p2->y_scale,0,p2->oldbox[2]);
1364 _sv_dim_widget_set_thumb(p2->y_scale,2,p2->oldbox[3]);
1365 p->private->oldbox_active = 0;
1366 _sv_undo_resume();
1367 break;
1369 _sv_panel_update_menus(p);
1372 void _sv_panel2d_maintain_cache(sv_panel_t *p, _sv_bythread_cache_2d_t *c, int w){
1373 _sv_panel2d_t *p2 = p->subtype->p2;
1375 /* toplevel initialization */
1376 if(c->fout == 0){
1377 int i,count=0;
1379 /* allocate output temporary buffer */
1380 for(i=0;i<p2->used_functions;i++){
1381 int fnum = p2->used_function_list[i]->number;
1382 sv_func_t *f = _sv_function_list[fnum];
1383 count += f->outputs;
1385 c->fout = calloc(count, sizeof(*c->fout));
1387 /* objective line buffer index */
1388 c->y_map = calloc(p2->y_obj_num,sizeof(*c->y_map));
1389 for(i=0;i<p2->y_obj_num;i++)
1390 c->y_map[i] = calloc(w,sizeof(**c->y_map));
1391 c->storage_width = w;
1394 /* anytime the data width changes */
1395 if(c->storage_width != w){
1396 int i;
1397 c->storage_width = w;
1399 for(i=0;i<p2->y_obj_num;i++)
1400 c->y_map[i] = realloc(c->y_map[i],w*sizeof(**c->y_map));
1406 // subtype entry point for plot remaps; lock held
1407 static int _sv_panel2d_map_redraw(sv_panel_t *p, _sv_bythread_cache_t *c){
1408 return _sv_panel2d_remap(p,&c->p2);
1411 // subtype entry point for legend redraws; lock held
1412 static int _sv_panel2d_legend_redraw(sv_panel_t *p){
1413 _sv_plot_t *plot = PLOT(p->private->graph);
1415 if(p->private->legend_progress_count)return 0;
1416 p->private->legend_progress_count++;
1417 _sv_panel2d_update_legend(p);
1418 _sv_panel_clean_legend(p);
1420 gdk_unlock();
1421 _sv_plot_draw_scales(plot);
1422 gdk_lock();
1424 _sv_plot_expose_request(plot);
1425 return 1;
1428 // subtype entry point for recomputation; lock held
1429 static int _sv_panel2d_compute(sv_panel_t *p,
1430 _sv_bythread_cache_t *c){
1432 _sv_panel2d_t *p2 = p->subtype->p2;
1433 _sv_plot_t *plot;
1435 int pw,ph,dw,dh,i,d;
1436 int serialno;
1437 double x_min, x_max;
1438 double y_min, y_max;
1439 int x_d=-1, y_d=-1;
1440 _sv_scalespace_t sx,sx_v,sx_i;
1441 _sv_scalespace_t sy,sy_v,sy_i;
1443 plot = PLOT(p->private->graph);
1444 pw = plot->x.pixels;
1445 ph = plot->y.pixels;
1447 x_d = p->private->x_d->number;
1448 y_d = p->private->y_d->number;
1450 // beginning of computation init
1451 if(p->private->plot_progress_count==0){
1452 int remapflag = 0;
1454 _sv_scalespace_t old_x = p2->x;
1455 _sv_scalespace_t old_y = p2->y;
1456 _sv_scalespace_t old_xv = p2->x_v;
1457 _sv_scalespace_t old_yv = p2->y_v;
1459 // generate new scales
1460 _sv_dim_scales(p->private->x_d,
1461 p->private->x_d->bracket[0],
1462 p->private->x_d->bracket[1],
1463 pw,pw * p->private->oversample_n / p->private->oversample_d,
1464 plot->scalespacing,
1465 p->private->x_d->legend,
1466 &sx,
1467 &sx_v,
1468 &sx_i);
1469 _sv_dim_scales(p->private->y_d,
1470 p->private->y_d->bracket[1],
1471 p->private->y_d->bracket[0],
1472 ph,ph * p->private->oversample_n / p->private->oversample_d,
1473 plot->scalespacing,
1474 p->private->y_d->legend,
1475 &sy,
1476 &sy_v,
1477 &sy_i);
1479 p2->x = sx;
1480 p2->x_v = sx_v;
1481 p2->x_i = sx_i;
1482 p2->y = sy;
1483 p2->y_v = sy_v;
1484 p2->y_i = sy_i;
1486 plot->x = sx;
1487 plot->y = sy;
1488 plot->x_v = sx_v;
1489 plot->y_v = sy_v;
1491 p->private->plot_progress_count++;
1492 p->private->plot_serialno++; // we're about to free the old data rectangles
1494 // realloc/fast scale the current data contents if appropriate
1495 if(memcmp(&sx_v,&old_xv,sizeof(sx_v)) || memcmp(&sy_v,&old_yv,sizeof(sy_v))){
1497 // maintain data planes
1498 for(i=0;i<p2->y_obj_num;i++){
1499 // allocate new storage
1500 int *newmap = calloc(sx_v.pixels*sy_v.pixels,sizeof(*newmap));
1501 int *oldmap = p2->y_map[i];
1502 int j;
1504 for(j=0;j<sx_v.pixels*sy_v.pixels;j++)
1505 newmap[j]=-1;
1507 // zoom scale data in map planes as placeholder for render
1508 if(oldmap){
1509 _sv_panel2d_fast_scale(p->private->spinner,newmap, sx_v, sy_v,
1510 oldmap,old_xv, old_yv);
1511 free(oldmap);
1513 p2->y_map[i] = newmap;
1515 remapflag = 1;
1518 // realloc render planes if appropriate
1519 if(memcmp(&sx,&old_x,sizeof(sx)) || memcmp(&sy,&old_y,sizeof(sy))){
1520 for(i=0;i<p2->y_obj_num;i++){
1522 // y planes
1523 if(p2->y_planes[i])
1524 free(p2->y_planes[i]);
1525 p2->y_planes[i] = calloc(sx.pixels*sy.pixels,sizeof(**p2->y_planes));
1527 // todo lists
1528 if(p2->y_planetodo[i])
1529 free(p2->y_planetodo[i]);
1530 p2->y_planetodo[i] = calloc(sy.pixels,sizeof(**p2->y_planetodo));
1534 if(p2->bg_todo)
1535 free(p2->bg_todo);
1536 p2->bg_todo=calloc(ph,sizeof(*p2->bg_todo));
1538 remapflag = 1;
1541 if(remapflag){
1542 _sv_panel2d_mark_map_full(p);
1543 _sv_panel_dirty_map(p);
1545 gdk_unlock ();
1546 _sv_plot_draw_scales(plot); // this should happen outside lock
1547 gdk_lock ();
1550 _sv_map_set_throttle_time(p); // swallow the first 'throttled' remap which would only be a single line;
1552 return 1;
1553 }else{
1554 sx = p2->x;
1555 sx_v = p2->x_v;
1556 sx_i = p2->x_i;
1557 sy = p2->y;
1558 sy_v = p2->y_v;
1559 sy_i = p2->y_i;
1560 serialno = p->private->plot_serialno;
1563 dw = sx_v.pixels;
1564 dh = sy_v.pixels;
1566 if(p->private->plot_progress_count>dh) return 0;
1568 _sv_panel2d_maintain_cache(p,&c->p2,dw);
1570 d = p->dimensions;
1572 /* render using local dimension array; several threads will be
1573 computing objectives */
1574 double dim_vals[_sv_dimensions];
1575 int y = _v_swizzle(p->private->plot_progress_count-1,dh);
1576 p->private->plot_progress_count++;
1578 x_min = _sv_scalespace_value(&p2->x_i,0);
1579 x_max = _sv_scalespace_value(&p2->x_i,dw);
1581 y_min = _sv_scalespace_value(&p2->y_i,0);
1582 y_max = _sv_scalespace_value(&p2->y_i,dh);
1584 // Initialize local dimension value array
1585 for(i=0;i<_sv_dimensions;i++){
1586 sv_dim_t *dim = _sv_dimension_list[i];
1587 dim_vals[i]=dim->val;
1590 /* unlock for computation */
1591 gdk_unlock ();
1593 dim_vals[y_d]=_sv_scalespace_value(&sy_i, y);
1594 _sv_panel2d_compute_line(p, serialno, dw, y, x_d, sx_i, dim_vals, &c->p2);
1596 gdk_lock ();
1598 if(p->private->plot_serialno == serialno){
1599 p->private->plot_complete_count++;
1600 _sv_panel2d_mark_map_line_y(p,y);
1601 if(p->private->plot_complete_count>=dh){
1602 _sv_panel_dirty_map(p);
1603 _sv_panel_dirty_legend(p);
1604 _sv_panel_clean_plot(p);
1605 }else
1606 _sv_panel_dirty_map_throttled(p);
1609 return 1;
1612 // only called for resize events
1613 static void _sv_panel2d_recompute_callback(void *ptr){
1614 sv_panel_t *p = (sv_panel_t *)ptr;
1615 int i;
1617 gdk_lock ();
1618 _sv_panel2d_mark_recompute(p);
1619 _sv_panel2d_compute(p,NULL); // initial scale setup
1621 // temporary: blank background to checks
1622 _sv_plot_t *plot = PLOT(p->private->graph);
1623 int pw = plot->x.pixels;
1624 int ph = plot->y.pixels;
1625 for(i=0;i<ph;i++)
1626 render_checks((_sv_ucolor_t *)plot->datarect+pw*i, pw, i);
1628 gdk_unlock();
1631 static void _sv_panel2d_undo_log(_sv_panel_undo_t *u, sv_panel_t *p){
1632 _sv_panel2d_t *p2 = p->subtype->p2;
1633 int i;
1635 // alloc fields as necessary
1637 if(!u->mappings)
1638 u->mappings = calloc(p->objectives,sizeof(*u->mappings));
1639 if(!u->scale_vals[0])
1640 u->scale_vals[0] = calloc(p->objectives,sizeof(**u->scale_vals));
1641 if(!u->scale_vals[1])
1642 u->scale_vals[1] = calloc(p->objectives,sizeof(**u->scale_vals));
1643 if(!u->scale_vals[2])
1644 u->scale_vals[2] = calloc(p->objectives,sizeof(**u->scale_vals));
1646 // populate undo
1647 for(i=0;i<p->objectives;i++){
1648 u->mappings[i] = p2->mappings[i].mapnum;
1649 u->scale_vals[0][i] = _sv_slider_get_value(p2->range_scales[i],0);
1650 u->scale_vals[1][i] = _sv_slider_get_value(p2->range_scales[i],1);
1651 u->scale_vals[2][i] = _sv_slider_get_value(p2->range_scales[i],2);
1654 u->x_d = p2->x_dnum;
1655 u->y_d = p2->y_dnum;
1656 u->box[0] = p2->oldbox[0];
1657 u->box[1] = p2->oldbox[1];
1658 u->box[2] = p2->oldbox[2];
1659 u->box[3] = p2->oldbox[3];
1660 u->box_active = p->private->oldbox_active;
1663 static void _sv_panel2d_undo_restore(_sv_panel_undo_t *u, sv_panel_t *p){
1664 _sv_panel2d_t *p2 = p->subtype->p2;
1665 _sv_plot_t *plot = PLOT(p->private->graph);
1666 int i;
1668 // go in through widgets
1669 for(i=0;i<p->objectives;i++){
1670 gtk_combo_box_set_active(GTK_COMBO_BOX(p2->range_pulldowns[i]),u->mappings[i]);
1671 _sv_slider_set_value(p2->range_scales[i],0,u->scale_vals[0][i]);
1672 _sv_slider_set_value(p2->range_scales[i],1,u->scale_vals[1][i]);
1673 _sv_slider_set_value(p2->range_scales[i],2,u->scale_vals[2][i]);
1676 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2->dim_xb[u->x_d]),TRUE);
1677 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2->dim_yb[u->y_d]),TRUE);
1679 _sv_panel2d_update_xysel(p);
1681 if(u->box_active){
1682 p2->oldbox[0] = u->box[0];
1683 p2->oldbox[1] = u->box[1];
1684 p2->oldbox[2] = u->box[2];
1685 p2->oldbox[3] = u->box[3];
1686 _sv_plot_box_set(plot,u->box);
1687 p->private->oldbox_active = 1;
1688 }else{
1689 _sv_plot_unset_box(plot);
1690 p->private->oldbox_active = 0;
1694 static void _sv_panel2d_realize(sv_panel_t *p){
1695 _sv_panel2d_t *p2 = p->subtype->p2;
1696 int i;
1698 _sv_undo_suspend();
1700 p->private->toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1701 g_signal_connect_swapped (G_OBJECT (p->private->toplevel), "delete-event",
1702 G_CALLBACK (_sv_clean_exit), (void *)SIGINT);
1704 // add border to sides with hbox/padding
1705 GtkWidget *borderbox = gtk_hbox_new(0,0);
1706 gtk_container_add (GTK_CONTAINER (p->private->toplevel), borderbox);
1708 // main layout vbox
1709 p->private->topbox = gtk_vbox_new(0,0);
1710 gtk_box_pack_start(GTK_BOX(borderbox), p->private->topbox, 1,1,4);
1711 gtk_container_set_border_width (GTK_CONTAINER (p->private->toplevel), 1);
1713 /* spinner, top bar */
1715 GtkWidget *hbox = gtk_hbox_new(0,0);
1716 gtk_box_pack_start(GTK_BOX(p->private->topbox), hbox, 0,0,0);
1717 gtk_box_pack_end(GTK_BOX(hbox),GTK_WIDGET(p->private->spinner),0,0,0);
1720 /* plotbox, graph */
1722 p->private->graph = GTK_WIDGET(_sv_plot_new(_sv_panel2d_recompute_callback,p,
1723 (void *)(void *)_sv_panel2d_crosshairs_callback,p,
1724 _sv_panel2d_box_callback,p,0));
1725 p->private->plotbox = p->private->graph;
1726 gtk_box_pack_start(GTK_BOX(p->private->topbox), p->private->plotbox, 1,1,2);
1729 /* obj box */
1731 p2->obj_table = gtk_table_new(p->objectives, 5, 0);
1732 gtk_box_pack_start(GTK_BOX(p->private->topbox), p2->obj_table, 0,0,1);
1734 /* objective sliders */
1735 p2->range_scales = calloc(p->objectives,sizeof(*p2->range_scales));
1736 p2->range_pulldowns = calloc(p->objectives,sizeof(*p2->range_pulldowns));
1737 p2->alphadel = calloc(p->objectives,sizeof(*p2->alphadel));
1738 p2->mappings = calloc(p->objectives,sizeof(*p2->mappings));
1739 for(i=0;i<p->objectives;i++){
1740 GtkWidget **sl = calloc(3,sizeof(*sl));
1741 sv_obj_t *o = p->objective_list[i].o;
1742 int lo = o->scale->val_list[0];
1743 int hi = o->scale->val_list[o->scale->vals-1];
1745 /* label */
1746 GtkWidget *label = gtk_label_new(o->name);
1747 gtk_misc_set_alignment(GTK_MISC(label),1.,.5);
1748 gtk_table_attach(GTK_TABLE(p2->obj_table),label,0,1,i,i+1,
1749 GTK_FILL,0,8,0);
1751 /* mapping pulldown */
1753 GtkWidget *menu=_gtk_combo_box_new_markup();
1754 int j;
1755 for(j=0;j<_sv_mapping_names();j++)
1756 gtk_combo_box_append_text (GTK_COMBO_BOX (menu), _sv_mapping_name(j));
1757 gtk_combo_box_set_active(GTK_COMBO_BOX(menu),0);
1758 g_signal_connect (G_OBJECT (menu), "changed",
1759 G_CALLBACK (_sv_panel2d_mapchange_callback), p->objective_list+i);
1760 gtk_table_attach(GTK_TABLE(p2->obj_table),menu,4,5,i,i+1,
1761 GTK_SHRINK,GTK_SHRINK,0,0);
1762 p2->range_pulldowns[i] = menu;
1765 /* the range mapping slices/slider */
1766 sl[0] = _sv_slice_new(_sv_panel2d_map_callback,p->objective_list+i);
1767 sl[1] = _sv_slice_new(_sv_panel2d_map_callback,p->objective_list+i);
1768 sl[2] = _sv_slice_new(_sv_panel2d_map_callback,p->objective_list+i);
1770 gtk_table_attach(GTK_TABLE(p2->obj_table),sl[0],1,2,i,i+1,
1771 GTK_EXPAND|GTK_FILL,0,0,0);
1772 gtk_table_attach(GTK_TABLE(p2->obj_table),sl[1],2,3,i,i+1,
1773 GTK_EXPAND|GTK_FILL,0,0,0);
1774 gtk_table_attach(GTK_TABLE(p2->obj_table),sl[2],3,4,i,i+1,
1775 GTK_EXPAND|GTK_FILL,0,0,0);
1776 p2->range_scales[i] = _sv_slider_new((_sv_slice_t **)sl,3,o->scale->label_list,o->scale->val_list,
1777 o->scale->vals,_SV_SLIDER_FLAG_INDEPENDENT_MIDDLE);
1778 gtk_table_set_col_spacing(GTK_TABLE(p2->obj_table),3,5);
1780 _sv_slice_thumb_set((_sv_slice_t *)sl[0],lo);
1781 _sv_slice_thumb_set((_sv_slice_t *)sl[1],lo);
1782 _sv_slice_thumb_set((_sv_slice_t *)sl[2],hi);
1783 _sv_mapping_setup(&p2->mappings[i],0.,1.,0);
1784 _sv_slider_set_gradient(p2->range_scales[i], &p2->mappings[i]);
1788 /* dims */
1790 p2->dim_table = gtk_table_new(p->dimensions,4,0);
1791 gtk_box_pack_start(GTK_BOX(p->private->topbox), p2->dim_table, 0,0,4);
1793 GtkWidget *first_x = NULL;
1794 GtkWidget *first_y = NULL;
1795 GtkWidget *pressed_y = NULL;
1796 p->private->dim_scales = calloc(p->dimensions,sizeof(*p->private->dim_scales));
1797 p2->dim_xb = calloc(p->dimensions,sizeof(*p2->dim_xb));
1798 p2->dim_yb = calloc(p->dimensions,sizeof(*p2->dim_yb));
1800 for(i=0;i<p->dimensions;i++){
1801 sv_dim_t *d = p->dimension_list[i].d;
1803 /* label */
1804 GtkWidget *label = gtk_label_new(d->legend);
1805 gtk_misc_set_alignment(GTK_MISC(label),1.,.5);
1806 gtk_table_attach(GTK_TABLE(p2->dim_table),label,0,1,i,i+1,
1807 GTK_FILL,0,5,0);
1809 /* x/y radio buttons */
1810 if(!(d->flags & SV_DIM_NO_X)){
1811 if(first_x)
1812 p2->dim_xb[i] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_x),"X");
1813 else{
1814 first_x = p2->dim_xb[i] = gtk_radio_button_new_with_label(NULL,"X");
1815 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2->dim_xb[i]),TRUE);
1817 gtk_table_attach(GTK_TABLE(p2->dim_table),p2->dim_xb[i],1,2,i,i+1,
1818 GTK_SHRINK,0,3,0);
1821 if(!(d->flags & SV_DIM_NO_Y)){
1822 if(first_y)
1823 p2->dim_yb[i] = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(first_y),"Y");
1824 else
1825 first_y = p2->dim_yb[i] = gtk_radio_button_new_with_label(NULL,"Y");
1826 if(!pressed_y && p2->dim_xb[i]!=first_x){
1827 pressed_y = p2->dim_yb[i];
1828 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(p2->dim_yb[i]),TRUE);
1830 gtk_table_attach(GTK_TABLE(p2->dim_table),p2->dim_yb[i],2,3,i,i+1,
1831 GTK_SHRINK,0,3,0);
1834 p->private->dim_scales[i] =
1835 _sv_dim_widget_new(p->dimension_list+i,_sv_panel2d_center_callback,_sv_panel2d_bracket_callback);
1837 gtk_table_attach(GTK_TABLE(p2->dim_table),
1838 p->private->dim_scales[i]->t,
1839 3,4,i,i+1,
1840 GTK_EXPAND|GTK_FILL,0,0,0);
1843 for(i=0;i<p->dimensions;i++){
1844 if(p2->dim_xb[i])
1845 g_signal_connect (G_OBJECT (p2->dim_xb[i]), "toggled",
1846 G_CALLBACK (_sv_panel2d_dimchange_callback), p);
1847 if(p2->dim_yb[i])
1848 g_signal_connect (G_OBJECT (p2->dim_yb[i]), "toggled",
1849 G_CALLBACK (_sv_panel2d_dimchange_callback), p);
1853 _sv_panel2d_update_xysel(p);
1855 gtk_widget_realize(p->private->toplevel);
1856 gtk_widget_realize(p->private->graph);
1857 gtk_widget_realize(GTK_WIDGET(p->private->spinner));
1858 gtk_widget_show_all(p->private->toplevel);
1859 _sv_panel2d_update_xysel(p); // yes, this was already done; however,
1860 // gtk clobbered the event setup on the
1861 // insensitive buttons when it realized
1862 // them. This call will restore them.
1864 _sv_undo_resume();
1867 static int _sv_panel2d_save(sv_panel_t *p, xmlNodePtr pn){
1868 _sv_panel2d_t *p2 = p->subtype->p2;
1869 int ret=0,i;
1871 xmlNodePtr n;
1873 xmlNewProp(pn, (xmlChar *)"type", (xmlChar *)"2d");
1875 // box
1876 if(p->private->oldbox_active){
1877 xmlNodePtr boxn = xmlNewChild(pn, NULL, (xmlChar *) "box", NULL);
1878 _xmlNewPropF(boxn, "x1", p2->oldbox[0]);
1879 _xmlNewPropF(boxn, "x2", p2->oldbox[1]);
1880 _xmlNewPropF(boxn, "y1", p2->oldbox[2]);
1881 _xmlNewPropF(boxn, "y2", p2->oldbox[3]);
1884 // objective map settings
1885 for(i=0;i<p->objectives;i++){
1886 sv_obj_t *o = p->objective_list[i].o;
1887 xmlNodePtr on = xmlNewChild(pn, NULL, (xmlChar *) "objective", NULL);
1888 _xmlNewPropI(on, "position", i);
1889 _xmlNewPropI(on, "number", o->number);
1890 _xmlNewPropS(on, "name", o->name);
1891 _xmlNewPropS(on, "type", o->output_types);
1893 // right now Y is the only type; the below is Y-specific
1894 n = xmlNewChild(on, NULL, (xmlChar *) "y-map", NULL);
1895 _xmlNewPropS(n, "color", _sv_mapping_name(p2->mappings[i].mapnum));
1896 _xmlNewPropF(n, "low-bracket", _sv_slider_get_value(p2->range_scales[i],0));
1897 _xmlNewPropF(n, "alpha", _sv_slider_get_value(p2->range_scales[i],1));
1898 _xmlNewPropF(n, "high-bracket", _sv_slider_get_value(p2->range_scales[i],2));
1901 // x/y dim selection
1902 n = xmlNewChild(pn, NULL, (xmlChar *) "axes", NULL);
1903 _xmlNewPropI(n, "xpos", p2->x_dnum);
1904 _xmlNewPropI(n, "ypos", p2->y_dnum);
1906 return ret;
1909 int _sv_panel2d_load(sv_panel_t *p,
1910 _sv_panel_undo_t *u,
1911 xmlNodePtr pn,
1912 int warn){
1913 int i;
1915 // check type
1916 _xmlCheckPropS(pn,"type","2d", "Panel %d type mismatch in save file.",p->number,&warn);
1918 // box
1919 u->box_active = 0;
1920 _xmlGetChildPropFPreserve(pn, "box", "x1", &u->box[0]);
1921 _xmlGetChildPropFPreserve(pn, "box", "x2", &u->box[1]);
1922 _xmlGetChildPropFPreserve(pn, "box", "y1", &u->box[2]);
1923 _xmlGetChildPropFPreserve(pn, "box", "y2", &u->box[3]);
1925 xmlNodePtr n = _xmlGetChildS(pn, "box", NULL, NULL);
1926 if(n){
1927 u->box_active = 1;
1928 xmlFree(n);
1931 // objective map settings
1932 for(i=0;i<p->objectives;i++){
1933 sv_obj_t *o = p->objective_list[i].o;
1934 xmlNodePtr on = _xmlGetChildI(pn, "objective", "position", i);
1935 if(!on){
1936 _sv_first_load_warning(&warn);
1937 fprintf(stderr,"No save data found for panel %d objective \"%s\".\n",p->number, o->name);
1938 }else{
1939 // check name, type
1940 _xmlCheckPropS(on,"name",o->name, "Objectve position %d name mismatch in save file.",i,&warn);
1941 _xmlCheckPropS(on,"type",o->output_types, "Objectve position %d type mismatch in save file.",i,&warn);
1943 // right now Y is the only type; the below is Y-specific
1944 // load maptype, values
1945 _xmlGetChildPropFPreserve(on, "y-map", "low-bracket", &u->scale_vals[0][i]);
1946 _xmlGetChildPropFPreserve(on, "y-map", "alpha", &u->scale_vals[1][i]);
1947 _xmlGetChildPropFPreserve(on, "y-map", "high-bracket", &u->scale_vals[2][i]);
1948 _xmlGetChildMap(on, "y-map", "color", _sv_mapping_map(), &u->mappings[i],
1949 "Panel %d objective unknown mapping setting", p->number, &warn);
1951 xmlFreeNode(on);
1955 // x/y dim selection
1956 _xmlGetChildPropIPreserve(pn, "axes", "xpos", &u->x_d);
1957 _xmlGetChildPropI(pn, "axes", "ypos", &u->y_d);
1959 return warn;
1962 sv_panel_t *sv_panel_new_2d(int number,
1963 char *name,
1964 char *objectivelist,
1965 char *dimensionlist,
1966 unsigned flags){
1968 int i,j;
1969 sv_panel_t *p = _sv_panel_new(number,name,objectivelist,dimensionlist,flags);
1970 if(!p)return NULL;
1972 _sv_panel2d_t *p2 = calloc(1, sizeof(*p2));
1973 int fout_offsets[_sv_functions];
1975 p->subtype =
1976 calloc(1, sizeof(*p->subtype)); /* the union is alloced not
1977 embedded as its internal
1978 structure must be hidden */
1979 p->subtype->p2 = p2;
1980 p->type = SV_PANEL_2D;
1981 p->private->bg_type = SV_BG_CHECKS;
1983 // verify all the objectives have scales
1984 for(i=0;i<p->objectives;i++){
1985 if(!p->objective_list[i].o->scale){
1986 fprintf(stderr,"All objectives in a 2d panel must have a scale\n");
1987 errno = -EINVAL;
1988 return NULL;
1992 p->private->realize = _sv_panel2d_realize;
1993 p->private->map_action = _sv_panel2d_map_redraw;
1994 p->private->legend_action = _sv_panel2d_legend_redraw;
1995 p->private->compute_action = _sv_panel2d_compute;
1996 p->private->request_compute = _sv_panel2d_mark_recompute;
1997 p->private->crosshair_action = _sv_panel2d_crosshairs_callback;
1998 p->private->print_action = _sv_panel2d_print;
1999 p->private->undo_log = _sv_panel2d_undo_log;
2000 p->private->undo_restore = _sv_panel2d_undo_restore;
2001 p->private->save_action = _sv_panel2d_save;
2002 p->private->load_action = _sv_panel2d_load;
2004 /* set up helper data structures for rendering */
2006 /* determine which functions are actually needed; if it's referenced
2007 by an objective, it's used. Precache them in dense form. */
2009 int fn = _sv_functions;
2010 int used[fn],count=0,offcount=0;
2011 memset(used,0,sizeof(used));
2012 memset(fout_offsets,-1,sizeof(fout_offsets));
2014 for(i=0;i<p->objectives;i++){
2015 sv_obj_t *o = p->objective_list[i].o;
2016 for(j=0;j<o->outputs;j++)
2017 used[o->function_map[j]]=1;
2020 for(i=0;i<fn;i++)
2021 if(used[i]){
2022 sv_func_t *f = _sv_function_list[i];
2023 fout_offsets[i] = offcount;
2024 offcount += f->outputs;
2025 count++;
2028 p2->used_functions = count;
2029 p2->used_function_list = calloc(count, sizeof(*p2->used_function_list));
2031 for(count=0,i=0;i<fn;i++)
2032 if(used[i]){
2033 p2->used_function_list[count]=_sv_function_list[i];
2034 count++;
2038 /* set up computation/render helpers for Y planes */
2040 /* set up Y object mapping index */
2042 int yobj_count = 0;
2044 for(i=0;i<p->objectives;i++){
2045 sv_obj_t *o = p->objective_list[i].o;
2046 if(o->private->y_func) yobj_count++;
2049 p2->y_obj_num = yobj_count;
2050 p2->y_obj_list = calloc(yobj_count, sizeof(*p2->y_obj_list));
2051 p2->y_obj_to_panel = calloc(yobj_count, sizeof(*p2->y_obj_to_panel));
2052 p2->y_obj_from_panel = calloc(p->objectives, sizeof(*p2->y_obj_from_panel));
2054 yobj_count=0;
2055 for(i=0;i<p->objectives;i++){
2056 sv_obj_t *o = p->objective_list[i].o;
2057 if(o->private->y_func){
2058 p2->y_obj_list[yobj_count] = o;
2059 p2->y_obj_to_panel[yobj_count] = i;
2060 p2->y_obj_from_panel[i] = yobj_count;
2061 yobj_count++;
2062 }else
2063 p2->y_obj_from_panel[i] = -1;
2068 /* set up function Y output value demultiplex helper */
2070 p2->y_fout_offset = calloc(p2->y_obj_num, sizeof(*p2->y_fout_offset));
2071 for(i=0;i<p2->y_obj_num;i++){
2072 sv_obj_t *o = p2->y_obj_list[i];
2073 int funcnum = o->private->y_func->number;
2074 p2->y_fout_offset[i] = fout_offsets[funcnum] + o->private->y_fout;
2078 p2->y_map = calloc(p2->y_obj_num,sizeof(*p2->y_map));
2079 p2->y_planetodo = calloc(p2->y_obj_num,sizeof(*p2->y_planetodo));
2080 p2->y_planes = calloc(p2->y_obj_num,sizeof(*p2->y_planes));
2082 return p;