/* $Id: Exp $ *************************************************************************** X server for LibGLTEX - xlgtex datatypes and related functions Copyright (C) 2002 Christopher Alexander North-Keys http://www.talisman.org/~erlkonig/ *************************************************************************** */ /* The key function in the file is InitOutput, * called by main in dix/main.c during server startup */ #include #include #include #include #include #include #include "xgltex.h" xgltexVars_t xgltexVars = { 0, /* in GCC we'd use ".initted = 0;" */ }; const xgltexArgument_t xgltexArgInfo[] = { { /* long short arg? fmt scanf-target */ "--xsize", "-x", 1, "%lu", &xgltexVars.cmd.xsize, "X size (width) in pixels of the texture" },{ "--ysize", "-y", 1, "%lu", &xgltexVars.cmd.ysize, "Y size (height) in pixels of the texture" },{ "--zsize", "-z", 1, "%lu", &xgltexVars.cmd.zsize, "Z size (depth) in components of a pixel, from { 1 2 3 4 }" },{ "--compbits", "-c", 1, "%u", &xgltexVars.cmd.comp_bits, "number of bits in a component, from { 1 8 16 32 }" },{ "--pixbits", "-p", 1, "%u", &xgltexVars.cmd.pixel_bits, "bits to which a pixel is padded, from { 1 8 16 24 32 48 64 }" },{ "--lsb", "-l", 0, 0, &xgltexVars.cmd.comp_lsb, "indicates that components must be in little-endian mode" },{ "--shmid", "-s", 1, "%u", &xgltexVars.cmd.shmid, "pre-existing shared memory id to use (conflicts w/ -b)" },{ "--shmbytes", "-b", 1, "%lu", &xgltexVars.cmd.shmbytes, "minimum size of a shmem segment to create (conflicts w/ -s)" } }; enum { xgltexArgInfoCount = sizeof xgltexArgInfo / sizeof *xgltexArgInfo }; /* 'finalize tells whether resources are actual and should be shut down */ void xgltexVarsTexClear(xgltexTexture_t *tex, int finalize) { if(finalize) { if(tex->shmid) { if(XGLTEX_RESREQ_SHMAT == tex->resource) ; /* nothing special */ else if(XGLTEX_RESREQ_SHMGET == tex->resource) { /* use shmctl to mark for removal */ if(0 == shmctl(tex->shmid, IPC_RMID, (struct shmid_ds*)0)) printf("set shared memory id %d to self-destruct\n", tex->shmaddr); else fprintf(stderr, ("shmctl FAILED to set shared memory id %d" " to self-destruct\n"), tex->shmaddr); } } else if(tex->shmaddr) { shmdt(tex->shmaddr); } } /* STOMP */ memset(tex, 0, sizeof *tex); } void xgltexVarsClear() /* deallocates resources in use */ { xgltexVarsTexClear(&xgltexVars.tex, 1); /* finalize the tex in use */ xgltexVarsTexClear(&xgltexVars.cmd, 0); /* don't finalize - cmdline */ xgltexVars.initted = 0; } static int intInSet(int sought, int *set, int set_elem_count) { int succp = 0; int i; for(i = 0 ; i < set_elem_count ; ++i) if(sought == set[i]) { succp = 1; break; } return succp; } static unsigned int NearestPower2(unsigned int n) { unsigned int p2 = 0; for(p2 = 1 ; p2 ; p2 *= 2) if(p2 >= n) return p2; return 0; } int xgltexVarsActivate() /* setup .tex from .cmd */ { int succp = 1; /* until anything disagrees */ xgltexTexture_t *tex = &(xgltexVars.tex); xgltexTexture_t *cmd = &(xgltexVars.cmd); int zsize_valid[] = { 1, 2, 3, 4 }; int comp_bits_valid[] = { 1, 8, 16, 32 }; int pixel_bits_valid[] = { 1, 8, 16, 24, 32, 48, 64 }; int booleans_valid[] = { 0, 1 }; enum { zsize_vsz = sizeof zsize_valid /sizeof zsize_valid[0], comp_bits_vsz = sizeof comp_bits_valid /sizeof comp_bits_valid[0], pixel_bits_vsz= sizeof pixel_bits_valid /sizeof pixel_bits_valid[0], booleans_vsz = 2, /* computing this would be amusing, but... */ }; /* clear anything currently in .tex */ xgltexVarsTexClear(tex, 1); /* finalize the tex in use */ /* clone .cmd to .tex */ memcpy(tex, cmd, sizeof (xgltexTexture_t)); /* do any defaulting and complaining */ tex->alloc_fail = 0; /* start w/ the ones immune to cmdline */ tex->image = 0; tex->shmaddr = 0; tex->resource = XGLTEX_RESREQ_NONE; tex->image_bytes = 0; tex->xsize2 = 0; tex->ysize2 = 0; tex->image_bytes2 = 0; tex->xsize2pad = 0; tex->ysize2pad = 0; if(tex->xsize < 1) tex->xsize = 1; if(tex->ysize < 1) tex->ysize = 1; if(tex->zsize < 1) tex->zsize = 1; if(tex->comp_bits < 1) tex->comp_bits = 8; /* default to 1 byte comp's */ if(tex->pixel_bits < 1) tex->pixel_bits = 24; /* default to 3B RGB */ if((tex->pixel_bits) < (tex->zsize * tex->comp_bits)) tex->pixel_bits = (tex->zsize * tex->comp_bits); if( 1 == tex->pixel_bits) /* packed monochrome */ tex->comp_bits = 1; /* has to also be true */ if( intInSet(tex->zsize, &zsize_valid[0], zsize_vsz) && intInSet(tex->comp_bits, &comp_bits_valid[0], comp_bits_vsz) && intInSet(tex->pixel_bits, &pixel_bits_valid[0], pixel_bits_vsz) && intInSet(tex->comp_lsb, &booleans_valid[0], booleans_vsz)) { tex->xsize2 = NearestPower2(tex->xsize); tex->ysize2 = NearestPower2(tex->ysize); tex->xsize2pad = tex->xsize2 - tex->xsize; tex->ysize2pad = tex->ysize2 - tex->ysize; if(1 == tex->pixel_bits) /* 8 pixel/bytes, pad scanlines to byte */ { tex->image_bytes = tex->xsize * (tex->ysize + 7)/8; tex->image_bytes2 = tex->xsize2 * (tex->ysize2 + 7)/8; } else { tex->image_bytes = tex->xsize * tex->ysize * (tex->pixel_bits/8); tex->image_bytes2= tex->xsize2 * tex->ysize2 * (tex->pixel_bits/8); } if(tex->shmid) { tex->resource = XGLTEX_RESREQ_SHMAT; tex->shmaddr = shmat(tex->shmid, (const void*)0, 0); /* get size with shmctl() or something */ } else { key_t key = IPC_PRIVATE; /* key_t is int */ int shmflag = 0; tex->resource = XGLTEX_RESREQ_SHMGET; /* else defaults ..NONE */ if( ! tex->shmbytes) tex->shmbytes = ((tex->image_bytes2/PAGE_SIZE) +1) * PAGE_SIZE; tex->shmid = shmget(key, tex->shmbytes, IPC_CREAT | 0600); tex->shmaddr = shmat(tex->shmid, (const void*)0, shmflag); } if(tex->shmaddr) tex->image = tex->shmaddr; } else { ErrorF("illegal value in zsize, comp_bits, pixel_bits or comp_lsb\n"); succp = 0; } ErrorF("++++++++++ outputting results according to interpreted cmdline\n"); /* xgltexTestPattern(stderr); */ xgltexVarsPrint(stderr); /* xscreen still needs to be initialized */ return succp; } unsigned long int numberFromBytes(void *src, size_t count, int bigendian_p) { unsigned long int number = 0; if(bigendian_p) { unsigned char *current = (unsigned char *)src; unsigned char *toofar = current + count; while(current < toofar) { number <<= 8; number |= *current; ++current; } } else { unsigned char *srcbyte = (unsigned char *)src; unsigned char *toofar = srcbyte + 1; unsigned char *current = srcbyte - (count - 1); while(current > toofar) { number <<= 8; number |= *current; --current; } } return number; } /* large-order bytes are done first, if 'forward, write big-endian data * write count bytes into bytes starting at trg. * if count is >4, pad with zeros * if count is <4, skip high-order section of number */ void numberToBytes(void *trg, size_t count, unsigned long int number, int bigendian_p) { if(bigendian_p) { /* write modulo'd-off values starting at right */ unsigned char *trgbyte = (unsigned char *)trg; unsigned char *current = trgbyte + (count - 1); unsigned char *toofar = trgbyte - 1; while(current > toofar) { unsigned char fragment = number % 256; *current = fragment; number >>= 8; --current; } } else { /* write modulo'd-off values starting at left (little-endian) */ unsigned char *trgbyte = (unsigned char *)trg; unsigned char *current = trgbyte; unsigned char *toofar = trgbyte + count; while(current < toofar) { unsigned char fragment = number % 256; *current = fragment; number >>= 8; ++current; } } } int xgltexSetPixel(unsigned int x, unsigned int y, float r, float g, float b, float a) { int succp = 0; xgltexTexture_t *tex = &(xgltexVars.tex); #if 0 if((x < 7) && (y < 7)) fprintf(stderr, __FUNCTION__ ": %d,%d (%.3f %.3f %.3f %.3f)\n", x, y, r, g, b, a); #endif /* SGI RGB images, and textures are 0,0 in bottom left (sci style) and */ /* by scanline. so the first scanline pixels are lowest in the vector */ if((x <= tex->xsize) && (y <= tex->ysize)) { if( 1 == tex->pixel_bits) /* also implies ( 1 == tex->comp_bits) */ { /* int xsize_in_bytes = (tex->xsize + 7) / 8; */ int xsize_in_bytes = (tex->xsize + tex->xsize2pad + 7) / 8; unsigned char *target = tex->image + ( (y * xsize_in_bytes) + ((x + 7) / 8)); int target_bit = x % 8; /* [0] is left bit */ int bitmask = 1 << (7 - target_bit); /* left-to-right numbering */ if( !! r) /* get red component, permuted to a single bit */ *target |= bitmask; /* enable new bit pixel */ else *target &= ~bitmask; /* clear old bit pixel */ } else /* byte or larger components */ { /* we might use floorf, but the one on this host is broken */ float rf = 255.98 * r; float gf = 255.98 * g; float bf = 255.98 * b; float af = 255.98 * a; #if 0 int t3 = (x<7&&y<7) ? fprintf(stderr, " " "(%.1f %.1f %.1f %.1f) rf gf bf af\n", rf, gf, bf, af) : 0; #endif unsigned char rr = (unsigned char)rf; unsigned char gg = (unsigned char)gf; unsigned char bb = (unsigned char)bf; unsigned char aa = (unsigned char)af; #if 0 int t2 = (x<7&&y<7) ? fprintf(stderr, " " "(%5d %5d %5d %5d) rr gg bb aa\n", rr, gg, bb, aa) : 0; #endif int pixel_bytesize = tex->pixel_bits / 8; unsigned char *pixel /* = tex->image + ( (y * tex->xsize * (pixel_bytesize)) */ = tex->image + ( (y * tex->xsize2 * (pixel_bytesize)) + (x * 1 * (pixel_bytesize))); int comp_bytesize = tex->comp_bits / 8; unsigned char *rc = pixel + (0 * comp_bytesize); unsigned char *gc = pixel + (1 * comp_bytesize); unsigned char *bc = pixel + (2 * comp_bytesize); unsigned char *ac = pixel + (3 * comp_bytesize); #if 0 int t1 = (x<7&&y<7) ? fprintf(stderr, " " " pixel %#lx (pBsz %d, cBsz %d)\n" " " " %#lx %#lx %#lx %#lx \n", (unsigned long int)pixel, pixel_bytesize, comp_bytesize, (unsigned long int)rc, (unsigned long int)gc, (unsigned long int)bc, (unsigned long int)ac ) : 0; #endif /* tex->zsize limits the number of components we need to process */ switch(tex->comp_bits) { case 1: /* no 3bit pixels, so this must be monochrome * true bitmaps already done, so this is 1 bit set * at 1 byte alignment (eek). * fall into (case 8:) (case/zsize 1) below - luminance */ case 8: switch(tex->zsize) { case 4: *ac = aa; /* rgba */ case 3: *bc = bb; /* rgb */ case 2: *gc = gg; /* lum+alpha */ case 1: *rc = rr; /* lum */ succp = 1; break; default: ErrorF("%s: bad depth %d\n",__FUNCTION__, tex->zsize); break; } break; } #if 0 if((x < 7) && (y < 7)) fprintf(stderr, " result-> " "(%4d %4d %4d %4d)\n", *ac, *bc, *gc, *rc); #endif } } return succp; } int xgltexSetRectangle(unsigned int x0, unsigned int y0, unsigned int w, unsigned int h, float r, float g, float b, float a) { int succp = 0; xgltexTexture_t *tex = &(xgltexVars.tex); if( (0 <= x0) && (x0 <= tex->xsize) && (0 <= y0) && (y0 <= tex->ysize) && (0 <= w) && ((x0 + w) <= tex->xsize) && (0 <= h) && ((y0 + h) <= tex->ysize)) { int xmax = x0 + w, ymax = y0 + h; int x, y; for( y = y0 ; y < ymax ; ++y) for(x = x0 ; x < xmax ; ++x) xgltexSetPixel(x, y, r, g, b, a); succp = 1; } return succp; } void xgltexTestPattern() { xgltexTexture_t *tex = &(xgltexVars.tex); int period = 10; int thick = 3; int x, y; for( y = 0 ; y < tex->ysize ; ++y) for(x = 0 ; x < tex->xsize ; ++x) xgltexSetPixel(x, y, 1.00, 0.5, 1.0, 1.0); /* xgltexSetRectangle(0, 0, tex->xsize, tex->ysize, 0, 0, 0, 0); */ for( y = thick ; y < (tex->ysize - thick); y += period) for(x = thick ; x < (tex->xsize - thick); x += period) xgltexSetRectangle(x, y, thick, thick, 0.0, 1.0, 0.0, 1.0); } const char *xgltexResourceToString(xgltexResource_t r) { const char *s = ""; switch(r) { case XGLTEX_RESREQ_NONE: s = "none"; break; case XGLTEX_RESREQ_SHMAT: s = "shmat"; break; case XGLTEX_RESREQ_SHMGET: s = "shmget"; break; case XGLTEX_RESREQ_INVALID: s = "invalid"; break; } return s; } void xgltexVarsTexPrint(FILE *out, xgltexTexture_t *tex) { fprintf(out, "(width) X: %d pixels (%d used)\n" "(height) Y: %d pixels (%d used)\n" "(depth) Z: %d components { 1 2 3 4 }\n", tex->xsize, tex->xsize2, tex->ysize, tex->ysize2, tex->zsize); fprintf(out, " comp bits: %d bits/component { 1 8 16 32 }\n", tex->comp_bits); fprintf(out, " pixel bits: %d bits/pixel w/pad { 1 8 16 24 32 48 64 }\n", tex->pixel_bits); fprintf(out, " alloc fail: %s\n", (tex->alloc_fail ? "true" : "false")); fprintf(out, " little-end: %s\n", (tex->comp_lsb ? "true" : "false")); fprintf(out, " image bytes: %d\n", tex->image_bytes); fprintf(out, "texture bytes: %d\n", tex->image_bytes2); fprintf(out, " x pixels pad: %d\n", tex->xsize2pad); fprintf(out, " y pixels pad: %d\n", tex->ysize2pad); fprintf(out, " image addr: %#lx\n", (unsigned long int)(tex->image)); fprintf(out, " resource: %s\n", xgltexResourceToString(tex->resource)); fprintf(out, " shared mem: %d shmid, %ld bytes, address %#lx\n", tex->shmid, tex->shmbytes, (unsigned long int)(tex->shmaddr)); fprintf(out, " xscreen: %#lx\n", (unsigned long int)tex->xscreen); } void xgltexVarsPrint(FILE *out) { fprintf(out, "---------- defaults and command line overrides\n"); xgltexVarsTexPrint(out, &(xgltexVars.cmd)); fprintf(out, "---------- current texture settings\n"); xgltexVarsTexPrint(out, &(xgltexVars.tex)); fprintf(out, "---------- general variables\n"); fprintf(out, " initted: %s\n", (xgltexVars.initted ? "true" : "false")); fprintf(out, "---------- end\n"); } void xgltexUsage(void) { int i; ErrorF("\n"); ErrorF("XGLTEX adds numerous options (both short and long form), most\n" " to allow configuration of the image format in memory:\n"); ErrorF(" short/long arg description\n"); ErrorF("------------ --- -------------------------------------------\n"); for( i = 0 ; i < xgltexArgInfoCount ; ++i) { ErrorF("%s %-10s %3s %s\n", xgltexArgInfo[i].option_short, xgltexArgInfo[i].option_long, (xgltexArgInfo[i].optarg_required ? "" : " " ), xgltexArgInfo[i].help); } ErrorF("\n"); } int xgltexProcessArg(int argc, char *argv[], int argi) { int args_processed = 0; /* 1 for flag, 2 for opt + optarg */ int i; /* fprintf(stderr, __FUNCTION__ " entered\n"); /**/ for( i = 0 ; (i < xgltexArgInfoCount) && ! args_processed ; ++i) { /* fprintf(stderr, __FUNCTION__ " processing \"%s\"\n", argv[argi]);/**/ if( ( ! strcmp(argv[argi], xgltexArgInfo[i].option_short)) || ( ! strcmp(argv[argi], xgltexArgInfo[i].option_long))) { if(xgltexArgInfo[i].optarg_required) /* optarg needed */ { if((argi + 1) < argc) /* ... and present? */ { if(1 == sscanf(argv[argi + 1], /* successful parse? */ xgltexArgInfo[i].sscanf_format, xgltexArgInfo[i].sscanf_target)) { args_processed = 2; /* parse succeeded */ /* fprintf(stderr, "arg + optarg set\n"); /**/ } else ErrorF("Option \"%s\" / \"%s\"" /* parse failed */ " parse of optarg \"%s\" failed\n", xgltexArgInfo[i].option_short, xgltexArgInfo[i].option_long, argv[argi + 1]); } else { /* missing optarg */ ErrorF("Option \"%s\" / \"%s\"" " requires an option-argument\n", xgltexArgInfo[i].option_short, xgltexArgInfo[i].option_long); } } else { /* no optarg required */ *(unsigned int*)(xgltexArgInfo[i].sscanf_target) = 1; /* fprintf(stderr, "arg set\n"); /**/ args_processed = 1; /* assumed successful */ } } } return args_processed; } /*-------------------------------------------------------------- eof --- */