/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include #include "internals.h" #if DXD_HAS_LIBIOP #include struct arg { Object o; /* the object to copy */ struct fbpixel *fb; /* the fb */ int ox, oy; /* overall image origin */ int width, height; /* total size of fb */ int i, n; /* we are part i of n */ }; #define SGN(x) ((x)>0? 1 : (x)<0? -1 : 0) static Error traverse(Object o, struct arg *arg) { union { Pointer ptr; RGBColor *rgb; unsigned char *byte; } pixels, f, ff; RGBColor *fmap = NULL; struct { unsigned char r, g, b; } imap[256]; Object oo; Point box[8]; int tx, ty, p, px, py, ox, oy, width, height, x, y, i; struct fbpixel *t, *tt; struct { float x, y; } deltas[2]; int d0, d1, dims[2], offsets[2]; Array a; switch (DXGetObjectClass((Object)o)) { case CLASS_GROUP: if (DXGetGroupClass((Group)o)!=CLASS_COMPOSITEFIELD) DXErrorReturn(ERROR_BAD_PARAMETER, "generic groups and series cannot be displayed"); for (i=0; oo=DXGetEnumeratedMember((Group)o, i, NULL); i++) if (!traverse(oo, arg)) return ERROR; break; case CLASS_FIELD: /* check */ if (DXGetComponentValue((Field)o,IMAGE)) DXErrorReturn(ERROR_BAD_PARAMETER, "arranged special-format images not supported"); /* mapped? */ a = (Array) DXGetComponentValue((Field)o, "color map"); if (a) { char *conv = (char *)_dxd_convert + UNSIGN(0); fmap = (RGBColor *) DXGetArrayData(a); if (!fmap) goto error; for (i=0; i<256; i++) { int r = ((union hl *)&fmap[i].r)->hl.hi; int g = ((union hl *)&fmap[i].g)->hl.hi; int b = ((union hl *)&fmap[i].b)->hl.hi; imap[i].r = conv[r]; imap[i].g = conv[g]; imap[i].b = conv[b]; } a = (Array) DXGetComponentValue((Field)o, "colors"); pixels.ptr = DXGetArrayData(a); } else { pixels.rgb = DXGetPixels((Field)o); } if (!pixels.ptr) return ERROR; /* XXX - checking? */ a = (Array) DXGetComponentValue((Field)o, POSITIONS); DXQueryGridPositions(a, NULL, dims, NULL, (float *)deltas); deltas[0].x = SGN(deltas[0].x); deltas[0].y = SGN(deltas[0].y); deltas[1].x = SGN(deltas[1].x); deltas[1].y = SGN(deltas[1].y); height = dims[0]; width = dims[1]; /* mesh offsets for position */ a = (Array) DXGetComponentValue((Field)o, CONNECTIONS); DXGetMeshOffsets((MeshArray)a, offsets); /* deltas for writing */ d0 = deltas[0].x - arg->width*deltas[0].y; d1 = deltas[1].x - arg->width*deltas[1].y; /* origin */ ox = offsets[0]*deltas[0].x + offsets[1]*deltas[1].x; oy = offsets[0]*deltas[0].y + offsets[1]*deltas[1].y; /* offset for implicit partitioning */ p = arg->i*height/arg->n; height = (arg->i+1)*height/arg->n - p; /* effect of that offset on placement within image */ px = deltas[0].x * p; py = deltas[0].y * p; /* where to start writing */ tx = ox - arg->ox + px; /* origin of this part */ ty = oy - arg->oy + py; /* origin of this part */ ty = arg->height - ty - 1; /* flip upside down */ t = arg->fb + ty*arg->width + tx; /* to */ /* XXX - performance critical code follows. */ if (fmap) { int r, g, b, zero = FBPIXEL(0,0,0); f.byte = pixels.byte + p*width; for (y=0; yb = b; /* order is important here */ tt->g = g; /* to keep the writes in the buffer */ tt->r = r; /* for as long as possible */ tt->a = 0xff; } else *(int *)tt = zero; ff.byte++; tt += d1; } f.byte += width; t += d0; } } else { char *conv = (char *)_dxd_convert + UNSIGN(0); int r, g, b, zero = FBPIXEL(0,0,0); f.rgb = pixels.rgb + p*width; for (y=0; yr))->hl.hi; g = ((union hl *)&(ff.rgb->g))->hl.hi; b = ((union hl *)&(ff.rgb->b))->hl.hi; if (r || g || b) { b = conv[b]; g = conv[g]; r = conv[r]; tt->b = b; /* order is important here */ tt->g = g; /* to keep the writes in the buffer */ tt->r = r; /* for as long as possible */ tt->a = 0xff; } else *(int *)tt = zero; ff.rgb++; tt += d1; } f.rgb += width; t += d0; } } break; } return OK; error: return ERROR; } static Error task(struct arg *arg) { return traverse(arg->o, arg); } /* * */ struct arg2 { int i, n; struct fbpixel *fb; int width, height; }; static Error task2(struct arg2 *arg2) { int start = (arg2->i*arg2->height/arg2->n) * arg2->width; int end = (((arg2->i+1)*arg2->height/arg2->n)) * arg2->width; memset(arg2->fb+start, 0, (end-start)*sizeof(*(arg2->fb))); return OK; } /* * */ #define ONE_KB 1024 struct fb { int nb; /* whether use non-blocking send */ afb_id afb_id; /* id for non-blocking i/o */ char *buffer; /* buffer address if pending, NULL if free */ Object object; /* object that owns buffer for fbimage */ } *fb; /* frame buffer state */ Error _dxf_initfb() { fb = (struct fb *) DXAllocateZero(sizeof(struct fb)); if (!fb) return ERROR; fb->nb = getenv("NOFBNB")? 0 : 1; _dxfinit_convert(1.5); /* gamma=1.5 is suitable for frame buffer */ return OK; } static Error send(char *chan, struct fb *fb, void *image, int width, int height, int x, int y) { static int mask = 0xffffffff; int flags = AFB_SWITCH; if (!*chan) chan = NULL; if (x < 0) { x = -(1 + x); flags = 0; } x &= ~3; y &= ~3; DXMarkTime("start send"); if (fb->nb) { fb->afb_id = afb_send_nb(chan,mask,flags, image, width, height, x, y); if (!fb->afb_id) { DXSetError(ERROR_INTERNAL, "fb send: %s", afb_errmsg(afb_errno)); return ERROR; } } else { int rc = afb_send(chan, mask, flags, image, width, height, x, y); if (rc < 0) { DXSetError(ERROR_INTERNAL, "fb send: %s", afb_errmsg(rc)); return ERROR; } } DXMarkTime("end send"); return OK; } Object DXDisplayFB(Object o, char *name, int x, int y) { int i, j, n, rc, fbimage; Point box[8]; struct arg arg; struct fbpixel *pp, *p; char copy[100], *s; DXMarkTime("start output fb"); /* strip :0 off end of name */ strcpy(copy, name? name : ""); for (s=copy; *s; s++) if (*s==':') *s = '\0'; DXDebug("X", "sending to FB '%s'", copy); /* composite image size */ if (!DXGetImageBounds(o, &arg.ox, &arg.oy, &arg.width, &arg.height)) return NULL; /* is it a simple FB image? */ fbimage = (DXGetObjectClass(o)==CLASS_FIELD && DXGetComponentValue((Field)o,IMAGE)); /* wait for pending send */ if (fb->buffer || fb->object) { rc = afb_send_wait(fb->afb_id); if (rc<0) { DXSetError(ERROR_INTERNAL, "fb wait: %s", afb_errmsg(rc)); goto error; } DXFree(fb->buffer); DXDelete(fb->object); fb->buffer = NULL; fb->object = NULL; DXMarkTime("end wait"); } if (fbimage) { struct fbpixel *pixels = _dxf_GetFBPixels((Field)o); /* send it */ if (!pixels) goto error; if (!send(copy, fb, (void*)pixels, arg.width, arg.height, x, y)) goto error; if (fb->nb) fb->object = DXReference(o); } else { /* allocate a buffer large enough for the entire image */ int oldw, oldh, neww, newh; /* extra margins for 4-pixel alignment */ oldw = arg.width; oldh = arg.height; neww = arg.width = (oldw & 0x3) ? (oldw & (~3)) + 4 : oldw; newh = arg.height = (oldh & 0x3) ? (oldh & (~3)) + 4 : oldh; /* allocate buffer, zero extra "edges", or whole thing if composite */ n = neww * newh * sizeof(struct fbpixel); fb->buffer = DXAllocate(n + ONE_KB); if (!fb->buffer) return NULL; arg.fb = (struct fbpixel *)(((int)fb->buffer+ONE_KB-1) & ~(ONE_KB-1)); if (DXGetObjectClass(o)==CLASS_FIELD) { for (i=0, pp=arg.fb; inb) { DXFree(fb->buffer); fb->buffer = NULL; } } /* free buffer and return */ DXMarkTime("end output fb"); return o; error: DXFree(fb->buffer); DXDelete(fb->object); fb->buffer = NULL; fb->object = NULL; return NULL; } /* * FB images have type char, each item is four chars */ Field _dxf_MakeFBImage(int width, int height) { Field i; Array a; /* sanity check */ if ((double)width*height*3*sizeof(float) > (double)(unsigned int)(-1)) { DXSetError(ERROR_BAD_PARAMETER, "image size %dx%d exceeds address space", width, height); return NULL; } /* an image is a field */ i = DXNewField(); if (!i) return NULL; /* positions */ a = DXMakeGridPositions(2, height,width, /* origin: */ 0.0,0.0, /* deltas: */ 0.0,1.0, 1.0,0.0); if (!a) return NULL; DXSetComponentValue(i, POSITIONS, (Object)a); /* connections */ a = DXMakeGridConnections(2, height,width); if (!a) return NULL; DXSetConnections(i, "quads", a); /* colors */ a = DXNewArray(TYPE_UBYTE, CATEGORY_REAL, 1, 4); if (!a) return NULL; if (!DXAddArrayData(a, 0, width*height, NULL)) { DXAddMessage("can't make %dx%d image", width, height); return NULL; } DXSetComponentValue(i, IMAGE, (Object)a); DXSetAttribute((Object)a, IMAGE_TYPE, O_FB_IMAGE); /* set default ref and dep */ return DXEndField(i); } struct fbpixel * _dxf_GetFBPixels(Field i) { Array a; /* return the colors component */ a = (Array) DXGetComponentValue(i, IMAGE); if (!a || DXGetAttribute((Object)a,IMAGE_TYPE) != O_FB_IMAGE) DXErrorReturn(ERROR_BAD_PARAMETER, "not an FB image field"); if (!DXTypeCheck(a, TYPE_UBYTE, CATEGORY_REAL, 1, 4)) DXErrorReturn(ERROR_BAD_PARAMETER, "FB image has wrong type"); return (struct fbpixel *) DXGetArrayData(a); } Field _dxf_ZeroFBPixels(Field image, int left, int right, int top, int bot, RGBColor c) { int bwidth, n, bheight, iwidth, iheight, x, y; int *tt, *t, *pixels; int pix; int r, g, b; bwidth = right-left; n = bwidth * sizeof(int); bheight = top-bot; pixels = (int *) _dxf_GetFBPixels(image); DXGetImageSize(image, &iwidth, &iheight); tt = pixels + (iheight-bot-1)*iwidth + left; r = (int)255*c.r; g = (int)255*c.g; b = (int)255*c.b; pix = FBPIXEL(r,g,b); for (y=0; y