starfish-1.1/ 42775 764 764 0 7216004626 12473 5ustar msaxmanmsaxmanstarfish-1.1/portable/ 42700 764 764 0 7042177200 14263 5ustar msaxmanmsaxmanstarfish-1.1/portable/.AppleDouble/ 42700 764 764 0 7042177111 16536 5ustar msaxmanmsaxmanstarfish-1.1/portable/.AppleDouble/.Parent100700 764 764 1115 7042177111 20064 0ustar msaxmanmsaxmanMVU - portable]+QPRNstarfish-1.1/portable/.AppleDouble/generators.c100600 764 764 1771 7042177111 21156 0ustar msaxmanmsaxmanMV U - generators.cuTEXTCWIEZZR generators.ctTEXTCWIETEXTCWIEy> H Monaco`c,A ,X^,X^ZZR u5RMPSRMWBB* s8starfish-1.1/portable/.AppleDouble/generators.h100600 764 764 1771 7042177111 21163 0ustar msaxmanmsaxmanMV U - generators.huTEXTCWIEaZZR6 generators.htTEXTCWIEaTEXTCWIEay "su%6Apple Menu Options Prefs %6AppleCD Audio Player Prefs%6Apple Video Player PrefsH Monaco`c,A ( ( ZZR u5RMPSRMWBB* s4starfish-1.1/portable/.AppleDouble/genutils.c100600 764 764 1771 7042177111 20637 0ustar msaxmanmsaxmanMV U - genutils.cuTEXTCWIEaZZR~8 8 genutils.ctPartSIT!PartSIT!k(P QVR RSSLSB F/ F$* FH Monaco`c,A ( ( ZZR u5RMPSRMWBB* s@starfish-1.1/portable/.AppleDouble/genutils.h100600 764 764 1747 7042177111 20647 0ustar msaxmanmsaxmanMV U - genutils.hvTEXTCWIE TTFR*chPICTDN R*chPICT genutils.htPartSIT!PartSIT!k(R*chTEXTL R*chTEXTM R*chTEXTO R*chTEXTS@ R*chTEXTSNH Monaco`c,A --󴆆TTF u5FMWBBMPSR s8starfish-1.1/portable/.AppleDouble/Icon 100600 764 764 1553 7042177111 17467 0ustar msaxmanmsaxmanMVU - Icon ]]iconMACS@8BIcon @Icon PartSIT!PartSIT!k( 8BIcon @8C n>.>. fstarfish-1.1/portable/.AppleDouble/starfish-engine.c100600 764 764 1771 7042177111 22073 0ustar msaxmanmsaxmanMVU - starfish-engine.cyTEXTCWIE aZZRstarfish-engine.cTEXTCWIETEXTCWIE ayur9H Monaco`c,A > [c> [cZZR u5RMPSRMWBB* s4starfish-1.1/portable/.AppleDouble/starfish-engine.h100600 764 764 1771 7042177111 22100 0ustar msaxmanmsaxmanMVU - starfish-engine.hyTEXTCWIE ZZR[ Claris Emailer Filesestarfish-engine.hTEXTCWIETEXTCWIE yuv ds#nusZD/ @ [ EmailerAPPLMMan!F*pqH Monaco`c,A ( ( ZZR u5RMPSRMWBB* s@starfish-1.1/portable/generators/ 42700 764 764 0 7152641003 16433 5ustar msaxmanmsaxmanstarfish-1.1/portable/generators/.AppleDouble/ 42700 764 764 0 7042177111 20707 5ustar msaxmanmsaxmanstarfish-1.1/portable/generators/.AppleDouble/.Parent100700 764 764 1115 7042177111 22235 0ustar msaxmanmsaxmanMV U - generatorsڊ!]starfish-1.1/portable/generators/.AppleDouble/branchfrac-gen.c100600 764 764 1771 7042177111 24016 0ustar msaxmanmsaxmanMVU - branchfrac-gen.c)oTEXTCWIEZZR.678652e+00 fl=65536 cpu=194796.branchfrac-gen.c-PartSIT!PartSIT!k(_ind=2 bs_chirp_rate=-3.809798 bs_fft_len=131072 bg_score=0.118052 bg_power=1.739919 bg_chisq=14.738618 bg_bin=9951 bg_fft_ind=13 H Monaco`c,A ( *( *ZZR u5RMPSRMWBB* s8starfish-1.1/portable/generators/.AppleDouble/branchfrac-gen.h100600 764 764 1115 7042177111 24013 0ustar msaxmanmsaxmanMVU - branchfrac-gen.h oTEXTCWIE`starfish-1.1/portable/generators/.AppleDouble/bubble-gen.c100600 764 764 1771 7042177111 23160 0ustar msaxmanmsaxmanMV U - bubble-gen.cspTEXTCWIEaZZRlude #define MAX_BUBBL bubble-gen.c-TEXTCWIEaTEXTCWIEa + shrink the influence of this bubble? float h, v; //coordinates for the origin of the bubble float bias; //does this bubblH Monaco`c,A * * ZZR u5RMPSRMWBB* s4starfish-1.1/portable/generators/.AppleDouble/bubble-gen.h100600 764 764 1115 7042177111 23155 0ustar msaxmanmsaxmanMV U - bubble-gen.hpTEXTCWIEstarfish-1.1/portable/generators/.AppleDouble/coswave-gen.c100600 764 764 1771 7042177111 23374 0ustar msaxmanmsaxmanMV U - coswave-gen.c+pTEXTCWIEZZR coswave-gen.cPartSIT!PartSIT!k(H Monaco`c,A - - ZZR u5RMPSRMWBB* s@starfish-1.1/portable/generators/.AppleDouble/coswave-gen.h100600 764 764 1115 7042177111 23371 0ustar msaxmanmsaxmanMV U - coswave-gen.hqTEXTCWIEastarfish-1.1/portable/generators/.AppleDouble/flatwave-gen.c100600 764 764 1747 7042177111 23541 0ustar msaxmanmsaxmanMVU - flatwave-gen.c qTEXTCWIE0qTTF4tflatwave-gen.c-PartSIT!PartSIT!k(| ij)klEhnCH Monaco`c,A WuWuTTF u5FMWBBMPSR s8starfish-1.1/portable/generators/.AppleDouble/flatwave-gen.h100600 764 764 1771 7042177111 23543 0ustar msaxmanmsaxmanMVU - flatwave-gen.hqTEXTCWIE0ZZRflatwave-gen.h-PartSIT!PartSIT!k(H Monaco`c,A ( ( ZZR u5RMPSRMWBB* s4starfish-1.1/portable/generators/.AppleDouble/galaxy-gen.c100600 764 764 1771 7042177111 23212 0ustar msaxmanmsaxmanMV U - galaxy-gen.csrTEXTCWIEqZZRlude #define MAX_BUBBL galaxy-gen.c-PartSIT!PartSIT!k( shrink the influence of this bubble? float h, v; //coordinates for the origin of the bubble float bias; //does this bubblH Monaco`c,A ( ( ZZR u5RMPSRMWBB* s@starfish-1.1/portable/generators/.AppleDouble/galaxy-gen.h100600 764 764 1771 7042177111 23217 0ustar msaxmanmsaxmanMV U - galaxy-gen.hrTEXTCWIEZZR]>Discover Programming Web Gu galaxy-gen.h-PartSIT!PartSIT!k( %]J o%]JMetroNub Utilities p%]MMetroNubUserInterface.hH Monaco`c,A ( ( ZZR u5RMPSRMWBB* s8starfish-1.1/portable/generators/.AppleDouble/ramp-gen.c100600 764 764 1115 7042177111 22654 0ustar msaxmanmsaxmanMV U - ramp-gen.c rTEXTCWIE astarfish-1.1/portable/generators/.AppleDouble/ramp-gen.h100600 764 764 1115 7042177111 22661 0ustar msaxmanmsaxmanMV U - ramp-gen.hsTEXTCWIE starfish-1.1/portable/generators/.AppleDouble/rangefrac-gen.c100600 764 764 1771 7042177111 23655 0ustar msaxmanmsaxmanMVU - rangefrac-gen.cdsTEXTCWIEaZZRrangefrac-gen.cPartSIT!PartSIT!k(H Monaco`c,A . . ZZR u5RMPSRMWBB* s4starfish-1.1/portable/generators/.AppleDouble/rangefrac-gen.h100600 764 764 1115 7042177111 23652 0ustar msaxmanmsaxmanMVU - rangefrac-gen.hcatTEXTCWIEstarfish-1.1/portable/generators/.AppleDouble/spinflake-gen.c100600 764 764 1771 7042177111 23701 0ustar msaxmanmsaxmanMVU - spinflake-gen.ctTEXTCWIE`ZZRspinflake-gen.cPartSIT!PartSIT!k(H Monaco`c,A - - ZZR u5RMPSRMWBB* s@starfish-1.1/portable/generators/.AppleDouble/spinflake-gen.h100600 764 764 1115 7042177111 23676 0ustar msaxmanmsaxmanMVU - spinflake-gen.hHtTEXTCWIE`astarfish-1.1/portable/generators/branchfrac-gen.c100600 764 764 17164 7152641002 21564 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Branchfractal Generator Creates an iterative fern or tree like branching fractal. Pixel values are calculated based on distance from the nearest stem. This is one of the more complex algorithms. It would be nice to make it even more complicated by adding a third dimension... but that's off in the future somewhere. It would also be nice to add curves. */ #include "branchfrac-gen.h" #include "genutils.h" #include #include #define MAX_BRANCHES 8 #define CLOSE_ENOUGH 0.0001 #define MAX_RAYS 128 //must be less than max(short) #define ROOT_RAY 0 #define MAX_PARENTS 5 typedef struct Ray { float h,v; //where does the ray originate? float angle; //and which way does it point? float length; //how long, in that way, does it go? int ancestors; //how many ancestors does this ray have? int children; //and how many children? short leaf[MAX_BRANCHES]; //which children belong to this ray? } Ray; typedef struct Tree { int branchmin, branchmax; //how many branches do we add, minimum and maximum? float divgmin, divgmax; //how far apart can the branches be? float scalemin, scalemax; //by how much do we scale down each branch? float twistmin, twistmax; //how far do we rotate branches from the base? int raycount; //how many rays in the array are allocated? Ray branch[MAX_RAYS]; //all the rays in this tree } Tree; static float TangentRayDistance(float h, float v, Ray* ray); static float ValueFromRay(float h, float v, Ray* ray, Tree* tree); static float ValueFromBranches(float h, float v, Ray* ray, Tree* tree); static int AllocRay(Tree* tree); static void MakeLeaves(Ray* ray, Tree* tree); static void MakeBranch(const Ray* ray, int whichbranch, Ray* branch, Tree* tree); void* BranchfracInit(void) { /* Make a new tree. We will pick random branching and divergence values. These will be used to calculate the rest of the fractal. */ Tree* out = (Tree*)malloc(sizeof(Tree)); if(out) { Ray* root = &out->branch[0]; out->raycount = 1; //The root of the tree always starts in the centre of the image. root->h = root->v = 0.5; //Pick some random values for our root. root->angle = frand(pi * 2); root->length = 0.2; root->ancestors = 0; root->children = 0; out->scalemin = 0.7;//frand(0.5) + 0.5; out->scalemax = 0.7; //Pick how many branches this tree may have. Range is from 1 through 8 per node. //Min can never be greater than max, and max can never be less than 1. out->branchmax = 4;//round(frand(3.0) + 1.0); out->branchmin = 2;//(rand() * out->branchmax) / RAND_MAX; //Now pick some random divergence values - this determines how bushy the tree will be. //We go from eighth-pi through half-pi. out->divgmax = frand(pi / 2); out->divgmin = frand(out->divgmax - (pi / 8)) + (pi / 8); //That's all the parameters we need for the fractal. //Now go build the tree. MakeLeaves(root, out); } return out; } static int AllocRay(Tree* tree) { //Allocate the next ray in the tree. Kinda simple. if(tree->raycount >= MAX_RAYS) return 0; return tree->raycount++; } static void MakeLeaves(Ray* ray, Tree* tree) { /* Create a bunch of branches for this ray. We pick a random number of branches, then iterate through each one and create it separately. Each one in turn creates *its* own set of branches. */ int ctr; ray->children = irandge(tree->branchmin, tree->branchmax); for(ctr = 0; ctr < ray->children; ctr++) { int leafindex; Ray* leaf; leafindex = AllocRay(tree); ray->leaf[ctr] = leafindex; if(leafindex) { leaf = &tree->branch[leafindex]; MakeBranch(ray, ctr, leaf, tree); } } } void BranchfracExit(void* refcon) { /* Throw away our tree, if it was created successfully. */ if(refcon) free(refcon); } float Branchfrac(float h, float v, void* refcon) { /* We have a point and an angle. Find the distance from (h,v) to the tangent point on the ray. */ float out = 0; Tree* glb = (Tree*)refcon; //Get the distance to the nearest branch. out = ValueFromRay(h, v, &glb->branch[ROOT_RAY], glb); //Prettify that distance so it becomes an outputable value. //We will eventually have several ways to do this. return 1 / ((out * 10.0) + 1.0); } static float TangentRayDistance(float h, float v, Ray* ray) { /* Calculate the distance from this point to the tangent point on the specified ray. If we are past the end of the ray's length, the distance is the shorter of the distance to the tangent or the distance to the endpoint. */ float pointangle, distance; float leg; pointangle = atan((ray->v - v) / (ray->h - h)) + ray->angle; distance = fabs(cos(pointangle) * hypotf(ray->v - v, ray->h - h)); leg = sin(pointangle) * hypotf(ray->v - v, ray->h - h); if(ray->h < h) leg = -leg; //This algorithm results in a smooth, circular glow around the ends of the ray. if(leg < 0.0) { distance = hypotf(distance, leg); } if(leg > ray->length) { distance = hypotf(distance, leg - ray->length); } //This algorithm, not currently in use, creates funky-cool glowing rays. //The smooth glow is preferred because it is more organicky. //if(leg < 0.0) distance += fabs(leg); //if(leg > ray->length) distance += fabs(leg - ray->length); return distance; } static float ValueFromRay(float h, float v, Ray* ray, Tree* tree) { /* Calculate the value of the pixel, according to this ray. We first calculate the value according to the tangent from the ray itself. Then we check the ray's branches, in case they happen to be closer to the ray. */ float out, branchbest; out = TangentRayDistance(h, v, ray); //If we aren't within the "close enough" threshold, see what the branches have. if(out > CLOSE_ENOUGH && ray->ancestors < MAX_PARENTS && ray->children > 0) { branchbest = ValueFromBranches(h, v, ray, tree); if(branchbest < out) out = branchbest; } return out; } static float ValueFromBranches(float h, float v, Ray* ray, Tree* tree) { //For testing purposes, make a single branch and return its value. float out, test; int ctr; Ray branch; out = 1 / 0.000000001; //as close to 1/0 as the compiler will let me for(ctr = 0; ctr < ray->children; ctr++) { Ray* leaf; if(ray->leaf[ctr]) { leaf = &tree->branch[ray->leaf[ctr]]; test = ValueFromRay(h, v, leaf, tree); if(test < out) out = test; } } return out; } static void MakeBranch(const Ray* ray, int whichbranch, Ray* branch, Tree* tree) { /* For testing purposes, we follow a hard-wired formula: The angle is 90 degrees off. The length is half. */ //Position the origin of this branch at the end of the parent ray. branch->length = ray->length * tree->scalemax;// 2; branch->h = ray->h - sin(ray->angle) * ray->length; branch->v = ray->v - cos(ray->angle) * ray->length; //Now pick an angle for it, based on its position within the group. //branch->angle = ray->angle - pi / 2; //branch->angle += (pi / 6) * whichbranch; branch->angle = frand(pi); branch->ancestors = ray->ancestors + 1; if(branch->ancestors < MAX_PARENTS) MakeLeaves(branch, tree); } starfish-1.1/portable/generators/branchfrac-gen.h100600 764 764 2220 7042177111 21537 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Branchfractal Generator Creates an iterative fern or tree like branching fractal. Pixel values are calculated based on distance from the nearest stem. This is one of the more complex algorithms. It would be nice to make it even more complicated by adding a third dimension... but that's off in the future somewhere. */ void* BranchfracInit(void); void BranchfracExit(void* refcon); float Branchfrac(float h, float v, void* refcon); starfish-1.1/portable/generators/bubble-gen.c100600 764 764 25642 7152641002 20726 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Bubble Generator Makes a field of hemispheric bubbles. The bubbles have varying sizes, alignments, and aspect ratios. Pixels are calculated by finding the highest point on any intersecting bubble. The result looks something like adding glycerine to a tub of water and blowing in it with a straw. */ #include "bubble-gen.h" #include "genutils.h" #include #include #define MAX_BUBBLES 32 typedef struct BubbleData { float scale; //by what factor should we shrink the influence of this bubble? float squish; //we multiply the h by this and divide the v by it float angle; //how far should we rotate this bubble's coordinate system? float h, v; //coordinates for the origin of the bubble float boundL, boundT, boundR, boundB; //approximate bounding box for the circle } BubbleData; typedef struct BubbleGlobals { int count; float scalemin, scalemax; float squishmin, squishmax; float anglemin, anglemax; BubbleData tip[MAX_BUBBLES]; } BubbleGlobals; typedef BubbleGlobals* BubbleRef; static float GetAllWrappedBubblesValue(float h, float v, BubbleRef it); static float GetAllBubblesValue(float h, float v, BubbleRef it); static float GetOneBubbleValue(float h, float v, BubbleData* bub); static float GetSpunBubbleValue(float h, float v, BubbleData* bub); static float GetSquishedBubbleValue(float h, float v, BubbleData* bub); static float GetRawBubbleValue(float h, float v, BubbleData* bub); static void InitBubble(BubbleData* bub, BubbleRef globals); static void CalcBubbleBoundingBox(BubbleData* bub); void* BubbleInit(void) { BubbleRef out = (BubbleRef)malloc(sizeof(BubbleGlobals)); if(out) { int ctr; /* Pick a random number of bubbles. We have a compiled-in maximum number of bubbles - obviously we won't use more than that. I pseudo- arbitrarily chose max / 2 as the minimum, simply to see how it looked. Some other number less than MAX_BUBBLES could just as easily be chosen. The number should be small enough to be distinct from max, but large enough that many of the bubbles intersect each other - that's where the look comes from. */ out->count = irandge(MAX_BUBBLES / 4, MAX_BUBBLES); /* Pick a random minimum and maximum size. Based on empirical testing I've decided that 0.2 is the largest reasonable scale. Any bigger than that and single bubbles start to take over the entire scene. All bubble sizes will fall within the range we pick here. It doesn't matter if the "min" and "max" are actually reversed; frandge will take care of it. */ out->scalemin = frand(0.2); out->scalemax = frand(0.2); /* Pick random squish sizes. A squish of 1 means a perfect circle. Under 1 means it becomes taller and narrower. Over 1 means it becomes wider and shorter. By setting a squishmin and squishmax for the entire bubblespace, we can control the "look" of the bubbles. If we want an entire space of tall, skinny bubbles, we can get it - or if we want one with no squishiness at all, we can get that too. Or we can let it be all over the map. Variety is a good thing, but too much of it is chaos. This is a way of "directing randomness" to get interesting variety. */ if(maybe()) { out->squishmin = frandge(1.0, 4.0); if(maybe()) out->squishmin = 1.0 / out->squishmin; } else out->squishmin = 1.0; if(maybe()) { out->squishmax = frandge(1.0, 4.0); if(maybe()) out->squishmax = 1.0 / out->squishmax; } else out->squishmax = 1.0; /* Some random angles. By rotating the bubbles' coordinate systems, we can make the squish factor turn. This makes the non-circular bubbles point in many strange directions. We do the same limited-random thing here as we have done elsewhere: the bubble-angles may be all over the map, or they may be cinched down into a certain direction similar to each other. This makes the field retain some consistency. Circular bubbles don't exhibit much appearance change when rotated. */ out->anglemin = frand(pi / 2.0); out->anglemax = frand(pi / 2.0); /* Now go through and create all of the bubbles using these data. */ for(ctr = 0; ctr < out->count; ctr++) { InitBubble(&out->tip[ctr], out); } } return out; } void BubbleExit(void* refcon) { if(refcon) free(refcon); } float Bubble(float h, float v, void* refcon) { /* Get the biggest value we can find out of all these bubbles. We will eventually do more interesting things with bubble clumps, points, and antibubbles, but this is just a beginning. */ BubbleRef it = (BubbleRef)refcon; return GetAllWrappedBubblesValue(h, v, it); } static float GetAllWrappedBubblesValue(float h, float v, BubbleRef it) { /* Calculate nine values from the array of bubbles, corresponding to the main tile and each of its neighboring imaginary tiles. This lets the edges of the bubbles spill over and affect neighbouring tiles, creating the illusion of an infinitely tiled seamless space. We damp down the influence of neighbouring tiles proportionate to their distance from the edge of the main tile. This is to prevent really huge bubbles that cover multiple tiles from breaking the smooth edges. */ float current, best = 0; current = best = GetAllBubblesValue(h, v, it); current = GetAllBubblesValue(h + 1.0, v, it) * (1.0 - h); //right if(current > best) best = current; current = GetAllBubblesValue(h - 1.0, v, it) * (h); //left if(current > best) best = current; current = GetAllBubblesValue(h, v + 1.0, it) * (1.0 - v); //bottom if(current > best) best = current; current = GetAllBubblesValue(h, v - 1.0, it) * (v); //top if(current > best) best = current; current = GetAllBubblesValue(h + 1.0, v + 1.0, it) * (1.0 - h) * (1.0 - v); //bottom right if(current > best) best = current; current = GetAllBubblesValue(h + 1.0, v - 1.0, it) * (1.0 - h) * (v); //top right if(current > best) best = current; current = GetAllBubblesValue(h - 1.0, v + 1.0, it) * (h) * (1.0 - v); //bottom left if(current > best) best = current; current = GetAllBubblesValue(h - 1.0, v - 1.0, it) * (h) * (v); //bottom right if(current > best) best = current; return best; } static float GetAllBubblesValue(float h, float v, BubbleRef it) { /* Get the biggest lump we can from this array of bubbles. We just scan through the list, compare the point with each bubble, and return the best match we can find. */ int ctr; float current, best; best = 0; for(ctr = 0; ctr < it->count; ctr++) { current = GetOneBubbleValue(h, v, &it->tip[ctr]); if(current > best) best = current; } return best; } static float GetOneBubbleValue(float h, float v, BubbleData* bub) { return GetSpunBubbleValue(h, v, bub); } static float GetSpunBubbleValue(float h, float v, BubbleData* bub) { /* Rotate the h and v values around the origin of the bubble according to the bubble's angle. Then pass the new h and v on to the squisher. */ float hypangle, hypotenuse; float distance, transverse; //Move the coordinates into bubble-relative coordinates. h -= bub->h; v -= bub->v; //Calculate the distance from the new origin to this point. hypotenuse = hypotf(h, v); /* Draw a line from the origin to this point. Get the angle this line forms with the horizontal. Then add the amount this bubble is rotated. */ hypangle = atan(v / h) + bub->angle; //The next line is magic. I don't quite understand it. if(h < 0) hypangle += pi; //We have the angle and the hypotenuse. Take the sine and cosine to get //the new horizontal and vertical distances in the new coordinate system. transverse = (cos(hypangle) * hypotenuse) + bub->h; distance = (sin(hypangle) * hypotenuse) + bub->h; //That's it. Pass in the transverse and distance values as the new h and v. return GetSquishedBubbleValue(transverse, distance, bub); } static float GetSquishedBubbleValue(float h, float v, BubbleData* bub) { /* Perform the h, v compensation here. We multiply the h by the squish value and divide the v by it. So if squish is less than zero, the effect is reversed. Very simple little effect that gets non-spherical bubbles. */ h = bub->h + ((h - bub->h) * bub->squish); v = bub->v + ((v - bub->v) / bub->squish); return GetRawBubbleValue(h, v, bub); } static float GetRawBubbleValue(float h, float v, BubbleData* bub) { /* Calculate the value of this point inside this bubble. If the point is outside the bubble, this will return a negative number. If the point is on the bubble's radius, this will return zero. Otherwise, this will return a number between zero and 1. */ float hypotenuse; hypotenuse = hypotf(h - bub->h, v - bub->v); return 1.0 - hypotenuse * hypotenuse / bub->scale; } static void InitBubble(BubbleData* bub, BubbleRef globals) { /* Come up with some reasonable values for this bubble. The limits for these values are determined by certain fields in the globals. Limits on minimum and maximum size, squish, angle, and proximity are specified there. We just make sure the bubble fits within those values. */ /* There is no proximity limit yet. Bubbles can be positioned anywhere in the field. */ bub->h = frand(1.0); bub->v = frand(1.0); /* The bubble's scale must be in line with the scale limits for this field. This can force a bubble-scene to be uniform or allow it to be diverse. */ bub->scale = frandge(globals->scalemin, globals->scalemax); /* The bubble's squish factor has to fit the bubblefield, too. This is what determines its height-to-width aspect ratio. */ bub->squish = frandge(globals->squishmin, globals->squishmax); /* Each bubble needs an angle. This determines the rotation of its coordinate system around the bubble's origin, relative to the bubblefield. It's what makes squished bubbles point in different directions. */ bub->angle = frandge(globals->anglemin, globals->anglemax); /* We've set up all the bubble's information. Now give it a bounding box so we can do quicker hit tests. */ CalcBubbleBoundingBox(bub); } static void CalcBubbleBoundingBox(BubbleData* bub) { /* Calculate the greatest and least coordinate values this bubble is able to hit in both horizontal and vertical axes. This is useful for hit-testing; we can quickly exclude circles that a given point doesn't hit. */ bub->boundL = bub->h - (bub->scale); bub->boundR = bub->h + (bub->scale); bub->boundT = bub->v - (bub->scale); bub->boundB = bub->v + (bub->scale); } starfish-1.1/portable/generators/bubble-gen.h100600 764 764 1725 7042177111 20712 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Bubble Generator Dunno what this looks like just yet, or how exactly it is going to work. I'll add detail later when I see its output... :-) */ void* BubbleInit(void); void BubbleExit(void* refcon); float Bubble(float h, float v, void* refcon); starfish-1.1/portable/generators/coswave-gen.c100600 764 764 12130 7152641003 21127 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Starfish Coswave This is the original texture from Starfish's venerable ancestor. This was cool enough by itself, but when you combine it with the trippy-cool edge wrapping code in starfish, it creates *really* neat turbulent lumpy patterns. Very smooth. This is an astonishingly versatile generator, as the simplest formulae often are. OK, *I* think it's cool. Stop laughing already. */ #include "genutils.h" #include "coswave-gen.h" #include #include enum waveaccelmethods { accelNone, accelLinear, accelSine, ACCEL_METHOD_COUNT }; typedef struct CoswaveGlobals { float originH, originV; float wavescale; float squish, sqangle, distortion; int packmethod; int accelmethod; float accel; } CoswaveGlobals; void* CoswaveInit(void) { /* We don't actually care about the pixel size of this texture, though I suppose we *could* use it for some kind of scalefactor correction. All we do here is pick some random values, put them in a global record, and return it. */ CoswaveGlobals* out = NULL; out = (CoswaveGlobals*)malloc(sizeof(CoswaveGlobals)); if(out) { out->originH = frand(1); out->originV = frand(1); out->packmethod = RandomPackMethod(); /* I once attempted to make the coswave shift its scale over time, much like the spinflake generator does with its twist. I wasn't particularly succesful. But I did happen upon a *beautifully* bizarre twist to the generator which is really strange but not terribly useful. So I fire it once in every 64 generations or so, which is just infrequent enough that the viewer really goes "what the hell is THAT" when they see it. It's chaotic moirness, sorta - the wavescale increases by the exponent of the distance. At some point, the wavescale becomes less than one pixel, and then chaos begins to happen. Odd eddies show up, turbulences become visible, and a bit of static shines through here and there. It's quite beautiful in an abstract sort of way. */ if(maybe() && maybe() && maybe() && maybe() && maybe() && maybe()) { out->accelmethod = accelLinear; out->accel = frand(2.0) + 1.0; } else out->accelmethod = accelNone; /* Packmethods flipsign and truncate effectively double the wavescale, because they turn both peaks and valleys into peaks. So we use a lower wavescale, then double it with the scaleToFit method to put it in range with the other packmethods. */ out->wavescale = frand(25) + 1.0; if(out->packmethod == scaleToFit) out->wavescale *= 2; /* We don't like waves that are always perfect circles; they're too predictable. So we "squish" them a bit. We choose a squish factor, which serves as a multiplier. Currently wave scale modifications can range from half length to double length. It would be fun to widen this sometime and see what happened. The squish angle determines the "direction" of the squish effect. The strength of the squish is determined by the sine of the difference between the angle between the current point and the origin, and the sqangle. */ out->squish = frand(2.0) + 0.5; if(maybe()) out->squish = -out->squish; out->sqangle = frand(pi); out->distortion = frand(1.5) + 0.5; } return out; } void CoswaveExit(void* refcon) { //If we successfully created a globals record, throw it away now. if(refcon) free(refcon); } float Coswave(float h, float v, void* refcon) { float out = 0.0; CoswaveGlobals* glb = (CoswaveGlobals*)refcon; if(glb) { /* Calculate this point's distance from the origin. Perform a cosine on the point. Then move the results of the cosine into the appropriate range. */ float hypotenuse, hypangle; float rawcos, compwavescale; //Rotate the axes of this shape. h -= glb->originH; v -= glb->originV; hypangle = atan((v / h) * glb->distortion) + glb->sqangle; hypotenuse = hypot(h, v); h = (cos(hypangle) * hypotenuse); v = (sin(hypangle) * hypotenuse); //Calculate the squished distance from the origin to the desired point. hypotenuse = hypot(h * glb->squish, v / glb->squish); //Scale the wavescale according to our accelerator function. switch(glb->accelmethod) { case accelNone: compwavescale = glb->wavescale; break; case accelLinear: compwavescale = powf(glb->wavescale, hypotenuse * glb->accel); break; } //Now map our cosine function along that distance. out = PackedCos(hypotenuse, compwavescale, glb->packmethod); } return out; } starfish-1.1/portable/generators/coswave-gen.h100600 764 764 2112 7042177111 21115 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Starfish Coswave This is the original texture from Starfish's venerable ancestor. This was cool enough by itself, but when you combine it with the trippy-cool edge wrapping code in starfish, it creates *really* neat turbulent lumpy patterns. Very smooth. */ void* CoswaveInit(void); void CoswaveExit(void* refcon); float Coswave(float h, float v, void* refcon); starfish-1.1/portable/generators/flatwave-gen.c100600 764 764 16110 7152641003 21273 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Starfish Flatwave - produces linear waves at arbitrary angles. Like Coswave, but produces linear ("flat") waves instead of waves oriented around a point. The flatwave module will eventually generate several waves at a time, interfering with each other and making interesting effects. */ #include #include #include "genutils.h" #include "flatwave-gen.h" enum interference_methods { intfMostExtreme, intfLeastExtreme, intfMax, intfMin, intfAverage, MAX_INTERFERENCE_METHODS }; enum accel_methods { accelNone, accelWave, MAX_ACCEL_METHODS }; /* A wave is a curve on a line. Each wave may have different scaling and display packing options. */ typedef struct WaveRec { float scale; int packmethod; int accelmethod; float accelscale; float accelamp; int accelpack; } WaveRec; /* A wavepacket is a group of waves on the same line. A wavepacket has an origin and an angle. All waves in the packet are calculated relative to that line. */ typedef struct WavePacketRec { float originH, originV; float angle; WaveRec wave; } WavePacketRec; /* The FlatwaveRec contains all the information about a flatwave layer. This equals a list of wavepackets and a description of the way to interfere them with each other. */ #define MAX_WAVE_PACKETS 3 typedef struct FlatwaveRec { int packets; int interferencemethod; WavePacketRec packet[MAX_WAVE_PACKETS + 1]; } FlatwaveRec; void InitWavePacket(WavePacketRec* it); void InitWave(WaveRec* it); float CalcWavePacket(float h, float v, WavePacketRec* it); float CalcWave(float distance, float transverse, WaveRec* it); void* FlatwaveInit(void) { /* All of the information we use to create an image lives in a FlatwaveRec. Allocate one such record and fill in appropriate random values. */ FlatwaveRec* out = (FlatwaveRec*)malloc(sizeof(FlatwaveRec)); if(out) { int ctr; //Pick a random number of packets, from 1 through MAX_WAVE_PACKETS. out->packets = irand(MAX_WAVE_PACKETS) + 1; out->interferencemethod = (rand() * MAX_INTERFERENCE_METHODS) / RAND_MAX; for(ctr = 0; ctr <= out->packets; ctr++) { InitWavePacket(&out->packet[ctr]); } } return out; } void InitWavePacket(WavePacketRec* it) { /* Pick a location and angle for this wave packet. Then create a wave. */ it->originH = frand(1.0); it->originV = frand(1.0); it->angle = frand(pi); InitWave(&it->wave); } void InitWave(WaveRec* it) { /* Set up this wave. Pick a scaling factor and display packing method. */ it->scale = frandge(2.0, 30.0); it->packmethod = RandomPackMethod(); if(it->packmethod == scaleToFit) it->scale *= 2.0; it->accelmethod = irand(MAX_ACCEL_METHODS); switch(it->accelmethod) { case accelNone: //No setup to do. Exit. break; case accelWave: //Make a sine wave to squiggle this one sideways. it->accelscale = frandge(2.0, 30.0); it->accelamp = frand(0.1); it->accelpack = RandomPackMethod(); break; } } void FlatwaveExit(void* refcon) { if(refcon) free(refcon); } float Flatwave(float h, float v, void* refcon) { /* Turn the angle from the origin to this point into a right triangle. Compute the legs of this triangle. We will use these legs to determine where on the linear wave this point happens to fall. */ float hypangle, hypotenuse; float distance, transverse; float out = 0.5; FlatwaveRec* glb = (FlatwaveRec*)refcon; if(glb) { int ctr; float layer; switch(glb->interferencemethod) { case intfMostExtreme: out = 0.5; break; case intfLeastExtreme: out = 0; break; case intfMax: out = 0; break; case intfMin: out = 1; break; case intfAverage: out = 0; break; } for(ctr = 0; ctr <= glb->packets; ctr++) { layer = CalcWavePacket(h, v, &glb->packet[ctr]); if(glb->packets > 1) { switch(glb->interferencemethod) { case intfMostExtreme: /* Is this value's distance from 0.5 greater than the existing value's distance from 0.5? */ if(fabs(layer - 0.5) > fabs(out - 0.5)) out = layer; break; case intfLeastExtreme: /* Is this value closer to the median than the existing value? */ if(fabs(layer - 0.5) < fabs(out - 0.5)) out = layer; break; case intfMax: //Is this value closer to 1 than the existing value? if(layer > out) out = layer; break; case intfMin: //Is this value closer to zero than the existing one was? if(out > layer) out = layer; break; case intfAverage: //Sum all the values up and compute the average at the end. out += layer; break; default: //Beats me what to do with this case. It should never happen. out = layer; } } else out = layer; } //If we are in average mode, do the averaging now. if(glb->interferencemethod == intfAverage) out /= glb->packets; } return out; } float CalcWavePacket(float h, float v, WavePacketRec* it) { /* Calculate the value returned by this wave packet. We find the origin of the wave and determine how far away and at what angle this point lies from that origin. Then we feed the distance & traverse values we get into each wave. We combine the results with any of several interference schemes. */ float hypangle, hypotenuse; float distance, transverse; float out = 0.5; //Re-centre the point on our wave's origin. h -= it->originH; v -= it->originV; //Now figure the length from the origin to this point. hypotenuse = hypotf(h, v); //Find the angle of the line from this point to the origin. hypangle = atan(v / h) + it->angle; if(h < 0) hypangle += pi; //Using the angle and the hypotenuse, we can figure out the individual legs. transverse = (cos(hypangle) * hypotenuse); distance = (sin(hypangle) * hypotenuse); //Our return value, for now, is just the value of our wave. out = CalcWave(distance, transverse, &it->wave); return out; } float CalcWave(float distance, float transverse, WaveRec* it) { /* We have a distance and a transverse value for this wave. Use them to calculate the value of the wave at this point. Then pack the results to fit in the 0..1 allowed output scale. */ float out; switch(it->accelmethod) { case accelNone: //No acceleration. Do nothing. break; case accelWave: distance += (PackedCos(transverse, it->accelscale, it->accelpack) * it->accelamp); break; } out = PackedCos(distance, it->scale, it->packmethod); return out; } starfish-1.1/portable/generators/flatwave-gen.h100600 764 764 2152 7042177111 21263 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Starfish Flatwave - produces linear waves at arbitrary angles. Like Coswave, but produces linear ("flat") waves instead of waves oriented around a point. The flatwave module will eventually generate several waves at a time, interfering with each other and making interesting effects. */ void* FlatwaveInit(void); void FlatwaveExit(void* refcon); float Flatwave(float h, float v, void* refcon); starfish-1.1/portable/generators/galaxy-gen.c100600 764 764 3057 7152641003 20735 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Galaxy Generator This works, and makes convincing-looking, perfectly spherical galaxies. It isn't too interesting or flexible, though. More of a novelty than a useful Starfish engine. */ #include "galaxy-gen.h" #include "genutils.h" #include #include typedef struct GalaxyGlobals { float rangemin; float rangemax; } GalaxyGlobals; typedef GalaxyGlobals* GalaxyRef; void* GalaxyInit(void) { GalaxyRef out = (GalaxyRef)malloc(sizeof(GalaxyGlobals)); if(out) { out->rangemin = frandge(0.0, 4.0); out->rangemax = frandge(1.0, 48.0); } return out; } void GalaxyExit(void* refcon) { if(refcon) free(refcon); } float Galaxy(float h, float v, void* refcon) { float dist; GalaxyRef it = (GalaxyRef)refcon; dist = hypot(h - 0.5, v - 0.5); return 1.0 - dist * dist * frandge(it->rangemin, it->rangemax); } starfish-1.1/portable/generators/galaxy-gen.h100600 764 764 2504 7042177111 20740 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Galaxy Generator This is a sort of cheap shot generator with an interesting effect. It uses limiting randoms around a point to create a bursted, scattered, staticy galaxy effect. It looks like a field of stars clustering in a brilliant core, so bright you can't pick out the individual elements. The galaxy comes in random sizes, and that's about the extent of it. This is not an official part of the starfish canon because it is so predictable. I like generators to be a little more flexible than this is. */ void* GalaxyInit(void); void GalaxyExit(void* refcon); float Galaxy(float h, float v, void* refcon); starfish-1.1/portable/generators/ramp-gen.c100600 764 764 7410 7152641003 20404 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Rampgen - a simple module that just spits out a test pattern It exists because it is very predictable :-) It should not go in any working version of starfish */ #include "ramp-gen.h" #include void* RampgenInit(void) { return NULL; } void RampgenExit(void* refcon) { return; } float Rampgen(float h, float v, void* refcon) { /* Calculate a grey value according to the position. Actually, for now, we just spit out medium grey... */ float tempv; float hpower, vpower; #if 1 return exp(h * v); #endif #if 0 /* This algorithm assumes that you are dealing with a range from 0..1 in each direction, and that the origin is (0.5, 0.5). It returns 0 in the centre, 1 along all of the edges. Along the way, it curves gently. The slope of the curve is determined by the darkfactor. Darkfactors lower than 1 create a convex curve: most of the domain returns high values, sloping rapidly to low values. Darkfactors higher than 1 create a concave surface: the centre remains 1, but it tails off to low values rather quickly. The "natural domain" of this function is 0 through 1/4. The peak value will always equal SCALEFACTOR/4. Thus a scalefactor of 4 results in a range of 0..1. The useful range for DARKFACTOR in edge-smoothing applications seems to be 0.35 (very little overlap) through 0.8 (extremely high overlap). */ #define DARKFACTOR 0.4 //lower values lighter, higher values darker, 0..1 #define SCALEFACTOR 4 if(h >= 0.5) h = 1 - h; if(v >= 0.5) v = 1 - v; return powf(h * v * SCALEFACTOR, DARKFACTOR); #endif #if 0 float slope, nearleg; float fardist, neardist; //Calculate the angle from here to our known point. slope = v / h; if(slope < 1.0) slope = 1.0 / slope; nearleg = 1 / slope; //Now calculate the distance from centre to edgepoint. fardist = hypotf(nearleg, 1.0); neardist = hypotf(h, v); //The result is the ratio of neardist to fardist return fardist; #endif #if 0 return fabs(0.5 - v) / fabs(0.5 -h); #endif #if 0 return ((0.5 + fabs(0.5 - h)) * (0.5 + fabs(0.5 - v)))*1.0; #endif #if 0 return (cos(hypotf(h - 0.3, v - 0.6) * 20.0) + 1.0) / 2.0; //Function to sum 4-way weighting and see what happens. //This one makes a pretty picture, but I don't think it's what I want. #endif #if 0 if(h>0.5) h = 1.0 - h; if(v>0.5) v = 1.0 - v; return ( (powf(h * v, 0.5)) + (powf(fabs(1.0 - h) * v, 0.5)) + (powf(h * fabs(1.0 - v), 0.5)) + (powf(fabs(1.0 - h) * fabs(1.0 - v), 0.5)) ); #endif #if 0 if(h>0.5) h = 1.0 - h; if(v>0.5) v = 1.0 - v; //Function to calculate weight for local pixel: return 0.5 + powf(h * v, 0.5); #endif #if 0 if(h>0.5) h = 1.0 - h; if(v>0.5) v = 1.0 - v; //Function for SUM of remote pixels: return 0.5 - powf(h * v, 0.5); #endif #if 0 /* Whoa! The following function produces some incredible turbulence and a really neat cross in the centre... check it out sometime */ //this works with or without the if(h>0.5) h = 1.0 - h; stuff. hpower = powf(fabs(0.5 - h), 1.0+fabs(0.5-h)); vpower = powf(fabs(0.5 - v), 1.0+fabs(0.5-v)); return powf(hpower * vpower, -2); #endif /* */ } starfish-1.1/portable/generators/ramp-gen.h100600 764 764 1762 7042177111 20417 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Starfish Rampgen - a simple module that just spits out a test pattern It exists because it is very predictable :-) It should not go in any working version of starfish */ void* RampgenInit(void); void RampgenExit(void* refcon); float Rampgen(float h, float v, void* refcon); starfish-1.1/portable/generators/rangefrac-gen.c100600 764 764 20457 7152641003 21423 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Rangefractal Generator Creates a range fractal. It creates a starting matrix of random values, then interpolates using existing values as min/max points for intermediate random values. The results can look like mountains, clouds, clusters of vegetation, and other turbulent mixtures of two materials. */ #include "rangefrac-gen.h" #include "genutils.h" #include #include /* Our points are stored in a big matrix. When the caller asks for a data point, we calculate it based on the stuff in the matrix. */ /* The scale determines how many data points we calculate. The more data points, the tighter the resolution, and the larger the quantity of memory consumed. The size must be an even power of 2 in order to work properly, so we calculate it in terms of SCALE. SCALE should be a value 3..10. */ #define VALMATRIX_SCALE 8 #define VALMATRIX_SIZE (1<level[h][v] = 0; } } } void GenerateFractal(RangefracGlobals* out) { /* Walk through the matrix. For each point, search its neighbors. For each neighboring point of higher level than current, compare its value against the current min and max. If the neighboring point exceeds min or max, use its value as the new min or max. Repeat. */ int h, v; int step; for(step = VALMATRIX_SIZE / 2; step > 0; step /= 2) { for(v = 0; v < VALMATRIX_SIZE; v += step) { for(h = 0; h < VALMATRIX_SIZE; h += step) { float max, min, val; //See if we need to calculate this pixel at all. if(out->level[h][v] < step) { //Go hunting for the highest and lowest values among this pixel's neighbors. max = 0.0; min = 1.0; //Top left if(out->level[WrapH(h - step)][WrapV(v - step)] > step) { val = out->data[WrapH(h - step)][WrapV(v - step)]; if(val < min) min = val; if(val > max) max = val; } //Top if(out->level[h][WrapV(v - step)] > step) { val = out->data[h][WrapV(v - step)]; if(val < min) min = val; if(val > max) max = val; } //Top right if(out->level[WrapH(h + step)][WrapV(v - step)] > step) { val = out->data[WrapH(h + step)][WrapV(v - step)]; if(val < min) min = val; if(val > max) max = val; } //Left if(out->level[WrapH(h - step)][v] > step) { val = out->data[WrapH(h - step)][v]; if(val < min) min = val; if(val > max) max = val; } //Right if(out->level[WrapH(h + step)][v] > step) { val = out->data[WrapH(h + step)][v]; if(val < min) min = val; if(val > max) max = val; } //Bottom left if(out->level[WrapH(h - step)][WrapV(v + step)] > step) { val = out->data[WrapH(h - step)][WrapV(v + step)]; if(val < min) min = val; if(val > max) max = val; } //Bottom if(out->level[h][WrapV(v + step)] > step) { val = out->data[h][WrapV(v + step)]; if(val < min) min = val; if(val > max) max = val; } //Bottom right if(out->level[WrapH(h + step)][WrapV(v + step)] > step) { val = out->data[WrapH(h + step)][WrapV(v + step)]; if(val < min) min = val; if(val > max) max = val; } val = frand(max - min) + min; if(step >= VALMATRIX_SIZE / 2) { /* The first pieces of data are always picked completely at random, because they have no neighbors to influence their decisions. But these data are the extremes of the image - no values can be any larger or smaller than them. So we "push" them out a little bit by rounding them to integer values, then averaging them with their original values. This gives us whiter whites and blacker blacks, without forcing the first data to be pure white or black. */ int valint; valint = (val > 0.5) ? 1 : 0; val = (valint + val) / 2.0; } out->data[h][v] = val; out->level[h][v] = step; } } } } } float CalcDistance(int matrixh, int matrixv, float desth, float destv) { return hypotf(matrixh - (desth * VALMATRIX_SIZE), matrixv - (destv * VALMATRIX_SIZE)); } float CalcWeight(int matrixh, int matrixv, float desth, float destv) { float out; out = 1 - CalcDistance(matrixh, matrixv, desth, destv); if(out < 0.0) out = 0.0; return out; } float GetMatrixVal(int matrixh, int matrixv, RangefracGlobals* glb) { return glb->data[WrapH(matrixh)][WrapV(matrixv)]; } int WrapH(int coord) { while(coord > VALMATRIX_MAX) coord -= VALMATRIX_SIZE; while(coord < 0) coord += VALMATRIX_SIZE; return coord; } int WrapV(int coord) { while(coord > VALMATRIX_MAX) coord -= VALMATRIX_SIZE; while(coord < 0) coord += VALMATRIX_SIZE; return coord; } starfish-1.1/portable/generators/rangefrac-gen.h100600 764 764 2062 7042177111 21402 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Rangefractal Generator Creates a mountain-like (occasionally cloud-like) range fractal. It creates a starting matrix of random values, then interpolates using existing values as min/max points for intermediate random values. */ void* RangefracInit(void); void RangefracExit(void* refcon); float Rangefrac(float h, float v, void* refcon); starfish-1.1/portable/generators/spinflake-gen.c100600 764 764 23302 7152641003 21437 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Starfish Spinflake Generator. Embosses rotationally symmetrical shapes. Mad ppatter! 1.6 introduced an attempt at creating crystalline, pseudo-organic leaf/snowflake like shapes. It was all vector based, not terribly smooth, and (in my opinion) did not work all that well. This takes an even older graphics algorithm I worked out, tweaks it a bit, and uses it to create a similar effect. The basic idea is that the generator picks an origin point and some parameters for a sine wave. It then lays a second sine wave on top of the first; their periods do not have to match. The result is a perturbed, vaguely symmetrical shape radiating from a point. This gives us a line. For every point in the problem domain, we extend a ray from the origin, through the point, until we hit the line. We then calculate the distance from the origin and the distance from the origin to the line, along that ray. The Z value is the distance from the point to the line, scaled proportionally to the distance from the line to the origin. If the point is outside the line, the value is 1/(distance + 1). Or something like that. Spinflake does its own texture-wrapping. The default wrapping just kills the contrast; we don't like that, so we wrap it our own way. */ #include "spinflake-gen.h" #include "genutils.h" #include #include enum sinepositivizingmethods { sineCompressMethod, sineTruncateMethod, sineAbsoluteMethod, sineSawbladeMethod, MAX_SINEPOS_METHODS }; enum twirlmethods { twirlNoneMethod, twirlCurveMethod, twirlSineMethod, twirlAccelMethod, MAX_TWIRL_METHODS }; #define MIDPOINT 0.5 #define MAX_TWIRL 14 #define MAX_SINEAMP 4.0 #define MAX_FLORETS 3 typedef struct floret { int sineposmethod; int backward; int spines; float spineradius; float twirlbase, twirlspeed, twirlamp, twirlmod; int twirlmethod; } floret; typedef struct spinflake { float originH, originV; float radius, squish, twist; int averageflorets; int florets; floret layer[MAX_FLORETS]; } spinflake; typedef struct SpinflakeGlobals { int spinflakes; spinflake flake[1]; } SpinflakeGlobals; void InitFloret(floret* it); void InitSpinflake(spinflake* it); static float calctheta(float h, float v, spinflake* it); static float calcwave(float theta, float origindist, floret* it); static float chopsin(float theta, floret* glb); static float rawpoint(float h, float v, spinflake* glb); static float vtiledpoint(float h, float v, SpinflakeGlobals* glb); void InitFloret(floret* it) { /* Pick a random packing method for the sine wave. We have several ways to use the sine function's range to produce a 0..1 value. */ it->sineposmethod = (rand() * MAX_SINEPOS_METHODS) / RAND_MAX; //If backward is true, we will flip the sine wave over. it->backward = maybe(); //Pick a random number of "spines" on the wave, from 1 to 16. it->spines = (rand() * 15 / RAND_MAX) + 1; //All modes but absolute-method require an even number of spines. if(it->sineposmethod != sineAbsoluteMethod && (it->spines & 1)) it->spines++; //Pick a height for the spines, similar to the range of the main radius. it->spineradius = frand(0.5); //Instead of aligning to the Y axis, twirl the flake a bit. it->twirlbase = frand(pi); //We use different methods to twirl the flake for unique effects. it->twirlmethod = (rand() * MAX_TWIRL_METHODS) / RAND_MAX; switch(it->twirlmethod) { case twirlNoneMethod: break; case twirlSineMethod: it->twirlspeed = frand(MAX_TWIRL * pi); it->twirlamp = frand(MAX_SINEAMP * 2) - MAX_SINEAMP; it->twirlmod = frand(1.0) - 0.5; break; case twirlCurveMethod: it->twirlspeed = frand(MAX_TWIRL * 2) - MAX_TWIRL; it->twirlamp = frand(MAX_SINEAMP * 2) - MAX_SINEAMP; break; } } void InitSpinflake(spinflake* it) { /* Pick a random location and size for this spinflake. Then calculate up some florets to add - without any, it would be an ordinary (and boring) circle. We like more complicated shapes. */ int ctr; //Pick somewhere for the flake to radiate from. it->originH = frand(1); it->originV = frand(1); //Pick a random radius for our main circle. it->radius = frand(0.5); //Squish it horizontally/vertically a bit. Just a small bit. it->squish = 0.25 + frand(2.75); it->twist = frand(pi); //Flip a coin - should we average out the values of our florets, or merely combine? it->averageflorets = maybe(); //Now fill out our florets. it->florets = ((rand() * MAX_FLORETS) / RAND_MAX) + 1; for(ctr = 0; ctr < it->florets; ctr++) { InitFloret(&it->layer[ctr]); } } void* SpinflakeInit(void) { /* Create a globals record and fill out all appropriate random values. */ SpinflakeGlobals* out; out = (SpinflakeGlobals*)malloc(sizeof(SpinflakeGlobals)); if(out) { InitSpinflake(&out->flake[0]); } return out; } void SpinflakeExit(void* refcon) { /* If we have a valid globals record, throw it away now. */ if(refcon) { free(refcon); } } float Spinflake(float h, float v, void* refcon) { float out; SpinflakeGlobals* glb = (SpinflakeGlobals*)refcon; if(glb) { float point, farpoint, weight, farweight; point = vtiledpoint(h, v, glb); if(h > 0.5) { farpoint = vtiledpoint(h - 1.0, v, glb); farweight = (h - 0.5) * 2.0; weight = 1.0 - farweight; out = (point * weight) + (farpoint * farweight); } else { out = point; } } return out; } static float chopsin(float theta, floret* glb) { float out = 0; out = sin(theta); switch(glb->sineposmethod) { case sineCompressMethod: out = (out + 1.0) / 2.0; break; case sineAbsoluteMethod: out = fabs(out); break; case sineTruncateMethod: if(out < 0) out += 1.0; break; case sineSawbladeMethod: theta = fmod(theta / 4.0, pi / 2.0); if(theta < 0) theta += (pi / 2.0); out = sin(theta); break; } if(glb->backward) { out = 1.0 - out; } return out; } static float vtiledpoint(float h, float v, SpinflakeGlobals* glb) { /* Return one data point, seamlessly-fused vertically. */ float out; float point, farpoint, weight, farweight, totalweight; point = rawpoint(h, v, &glb->flake[0]); if(v > 0.5) { farpoint = rawpoint(h, v - 1.0, &glb->flake[0]); farweight = (v - 0.5) * 2.0; weight = 1.0 - farweight; out = (point * weight) + (farpoint * farweight); } else { out = point; } return out; } static float rawpoint(float h, float v, spinflake* glb) { /* Calculate one raw data point. This does the calculations without worrying about seamless-tile wrapping. */ float pointangle, origindist, edgedist, proportiondist; float out; /* Rotate the point around our origin. This lets the squashed bulge-points on the sides of the squished spinflake point in random directions - not just aligned with the cartesian axes. */ float hypangle; h -= glb->originH; v -= glb->originV; hypangle = atan(v / h) + glb->twist; origindist = hypotf(h, v); h = (cos(hypangle) * origindist); v = (sin(hypangle) * origindist); //Calculate the distance from the origin to this point. Again. origindist = hypotf(h * glb->squish, v / glb->squish); //If we are at the origin, there is no need to do the computations. if(origindist) { int ctr; //The edge is (currently) a circle some radius units away. //Compute the angle this point represents to the origin. pointangle = calctheta(h, v, glb); edgedist = glb->radius; for(ctr = 0; ctr < glb->florets; ctr++) { edgedist += calcwave(pointangle, origindist, &glb->layer[ctr]); } if(glb->averageflorets) edgedist /= glb->florets; //Our return value is the distance from the edge, proportionate //to the distance from the origin to the edge. proportiondist = ((edgedist - origindist) / edgedist); //If the value is >=0, we are inside the shape. Otherwise, we're outside it. if(proportiondist >= 0) out = sqrt(proportiondist); else out = 1.0 - (1.0 / (1 - proportiondist)); } else out = 1.0; return out; } static float calcwave(float theta, float dist, floret* it) { /* Calculate the distance from centre this floret adds to the mix at the particular angle supplied. This is where we incorporate the floret's spines and twirling. Oddly, a spinflake's florets don't have to twirl in unison. This can get really interesting. If it doesn't work, migrate the twirl back to the spinflake instead. */ float cosparam; switch(it->twirlmethod) { case twirlCurveMethod: cosparam = theta * it->spines + it->twirlbase + (dist * (it->twirlspeed + (dist * it->twirlamp))); break; case twirlSineMethod: cosparam = (theta * it->spines + it->twirlbase) + (sin(dist * it->twirlspeed) * (it->twirlamp + (dist * it->twirlamp))); break; case twirlNoneMethod: default: //no twirl at all cosparam = theta * it->spines + it->twirlbase; break; } return chopsin(cosparam, it) * it->spineradius; } static float calctheta(float h, float v, spinflake* it) { /* Calculate the angle this point presents to the origin of the spinflake. We assume that the point is relative to the origin of the spinflake. We do this, because that's how rawpoint is coded. :-) */ return atan(v / h); } starfish-1.1/portable/generators/spinflake-gen.h100600 764 764 3702 7042177111 21430 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Starfish Snowflake Generator. Embosses rotationally symmetrical shapes. Mad ppatter! 1.6 introduced an attempt at creating crystalline, pseudo-organic leaf/snowflake like shapes. It was all vector based, not terribly smooth, and (in my opinion) did not work all that well. This takes a graphics algorithm I used in an even older program (Flakie, which generated snowflake-like shapes) and adds a third dimension for even more interesting effect. The basic idea is that the generator picks an origin point, a radius, and parameters for a sine wave. It then lays the wave on top of the circle for a doily/snowflake/wave effect. This gives us a curve. For every point in the domain, we extend a ray from the origin, through the point, until we hit the curve. We then calculate the distance from the origin and the distance from the origin to the curve, along that ray. The Z value is the distance from the point to the curve, scaled proportionally to the distance from the curve to the origin. If the point is outside the curve, the value is 1 - (1 / (1 - the distance)), which makes the value start at zero and grow slowly to infinity. */ void* SpinflakeInit(void); void SpinflakeExit(void* refcon); float Spinflake(float h, float v, void* refcon); starfish-1.1/portable/generators/galaxy-gen.c.orig100600 764 764 3101 7042177111 21664 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Galaxy Generator This works, and makes convincing-looking, perfectly spherical galaxies. It isn't too interesting or flexible, though. More of a novelty than a useful Starfish engine. */ #include "galaxy-gen.h" #include "genutils.h" #include #include typedef struct GalaxyGlobals { float rangemin; float rangemax; } GalaxyGlobals; typedef GalaxyGlobals* GalaxyRef; void* GalaxyInit(void) { GalaxyRef out = (GalaxyRef)malloc(sizeof(GalaxyGlobals)); if(out) { out->rangemin = frandge(0.0, 4.0); out->rangemax = frandge(1.0, 48.0); } return out; } void GalaxyExit(void* refcon) { if(refcon) free(refcon); } float Galaxy(float h, float v, void* refcon) { float dist; GalaxyRef it = (GalaxyRef)refcon; dist = sqrt(powf(h - 0.5, 2) + powf(v - 0.5, 2)); return 1.0 - dist * dist * frandge(it->rangemin, it->rangemax); } starfish-1.1/portable/generators.c100600 764 764 36656 7152645615 16751 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Starfish - Generator Manager Textures become complex by merging layers of simpler textures. Each basic layer is the result of a Generator - a function or algorithm that creates two-dimensional images. The generator manager creates a table of all installed generators. There are several different types of generators, and they produce graphics in different ways. The manager keeps track of all of this information and provides a uniform interface for the starfish engine itself. There are two ways to use this library. The easy way: Call Generate with a set of dimensions and your choice of generator. It will return a greybuf containing a texture created by that generator. Or there is the hard, but more configurable way: Create a layer, then ask it for pixel values at your leisure. When you're done asking your questions, throw the layer away. Or use it again, we don't really care. The advantage(s) to calling the generator library point-by-point are that it uses a fraction of the memory (since there is no need to allocate a greybuf to hold the image under construction) and that scheduling is under your control (you don't need to spawn off a separate thread to have more than one thing going on at a time). */ #include "greymap.h" #include "generators.h" #include /* We hard-link the generators for now. Eventually these will become dynamically loaded sharedlibs, picked out of a directory. Or maybe they won't. There doesn't seem to be much need for a pluggable system. The whole thing works not because of its diversity, but because of its carefully designed limitations. */ //#include "ramp-gen.h" //test lib, not used in production code #include "coswave-gen.h" #include "spinflake-gen.h" #include "rangefrac-gen.h" #include "flatwave-gen.h" #include "bubble-gen.h" //#include "branchfrac-gen.h" #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif /* Function to allocate storage & create values for the generator. The generator should use this opportunity to create random settings, allocate space, and otherwise get ready to spew out a bunch of data. The value the init function returns will be saved and passed back to the generator on every call from now on as the "refcon" value. This is designed to make it easier for generators to support multiple threads working on different output layers. */ typedef void* (*GenInitProc)(void); /* Function to clean up all the mess created by the InitProc. After the exit proc has been called, the refcon value will be discarded, so you'd better throw away everything you allocated and stored in it. */ typedef void (*GenExitProc)(void* refcon); /* This returns the value of one point. The assumed area covered by the output texture (the "interesting area") is 0..1 in both horizontal and vertical. You can ask for data outside the interesting area, but it's not guaranteed to have anything worth looking at. The generator is, however, required to return meaningful data UNLESS it handles its own seamless-wrapping. The process of wrapping the edges of a generator's output requires out-of-range values. The returned value will be from 0..1; if the generator screws up and sends you something outside that range, this module will simply cap it off at 0 or 1, as appropriate. */ typedef float (*GenPointProc)(float h, float v, void* refcon); //Description of one generator - everything we know about it. typedef struct GeneratorRec { int isAntiAliased; int isSeamless; GenInitProc init; //function to start up the generator GenExitProc exit; //function to close the generator down GenPointProc process; //processor function that does all the real work } GeneratorRec; //Structure to manage a list of all installed generators struct GeneratorList { int generatorCount; GeneratorRec* gen; }; //Structure keeping track of a single generator layer. typedef struct LayerRec { GeneratorRec* gencode; void* refcon; int hmax, vmax; int rollh, rollv; } LayerRec; #define CHANNELVAL_FMAX 255.0 static greybuf GeneratePointFunction(int h, int v, LayerRef gen); static float GetWrappedPoint(float hpos, float vpos, void* refcon, GeneratorRec* gen); static float GetAntiAliasedPoint(float hpos, float vpos, float fudge, void* refcon, GeneratorRec* gen); GenListRef LoadGenerators(void) { /* Seek out and load up all available generators. Someday, this will be a really neat, fancy routine that scans a directory looking for shared libraries. It'll load those libraries, interrogate them, and build a generator list from that. But, for now, this is a quick hack: we create the table by hand, using compiled-in code. */ int gencount; GenListRef out; size_t genlistsize; //Count the number of shared libraries in the directory. gencount = 5; //Create a genlist big enough to hold that many generators. out = malloc(sizeof(struct GeneratorList)); genlistsize = gencount * sizeof(GeneratorRec); if(out) out->gen = (GenListRef)malloc(genlistsize); if(out && out->gen) { //Poke in the generator count so we can get at it later. out->generatorCount = gencount; //Loop through the generators, filling out each record one by one. //Our first one is the workhorse Coswave. It can do anything. out->gen[0].isAntiAliased = false; out->gen[0].isSeamless = false; out->gen[0].init = &CoswaveInit; out->gen[0].exit = &CoswaveExit; out->gen[0].process = &Coswave; //Next is the spinflake generator, for more shapely patterns. out->gen[1].isAntiAliased = false; out->gen[1].isSeamless = true; out->gen[1].init = &SpinflakeInit; out->gen[1].exit = &SpinflakeExit; out->gen[1].process = &Spinflake; //The range fractal, which creates mountainous organic rough textures. out->gen[2].isAntiAliased = true; out->gen[2].isSeamless = true; out->gen[2].init = &RangefracInit; out->gen[2].exit = &RangefracExit; out->gen[2].process = &Rangefrac; //The flatwave generator, which creates interfering linear waves. out->gen[3].isAntiAliased = false; out->gen[3].isSeamless = false; out->gen[3].init = &FlatwaveInit; out->gen[3].exit = &FlatwaveExit; out->gen[3].process = &Flatwave; /* //The branch fractal, which creates vegetable structures out->gen[4].isAntiAliased = true; out->gen[4].isSeamless = true; out->gen[4].init = &BranchfracInit; out->gen[4].exit = &BranchfracExit; out->gen[4].process = &Branchfrac; */ //Bubble generator, which creates lumpy, curved turbulences. out->gen[4].isAntiAliased = true; out->gen[4].isSeamless = true; out->gen[4].init = &BubbleInit; out->gen[4].exit = &BubbleExit; out->gen[4].process = &Bubble; } return out; } void UnloadGenerators(GenListRef list) { /* Unload all generators and release the memory they occupied. For the moment, there is nothing we need to do to release the generators. All we have to do is throw away the memory occupied by the generator list. */ if(list) { if(list->gen) free(list->gen); free(list); list = NULL; } } int CountGenerators(GenListRef list) { /* How many generators are available? If this is a bogus list, the answer is necessarily zero. */ int out = 0; if(list) { out = list->generatorCount; } return out; } greybuf Generate(int ctr, int h, int v, GenListRef list) { /* Create a texture of appropriate dimensions from this generator. This is where all the interesting work starts getting done for the generators. Our job is to verify the request - make sure it is a valid generator, and that the input parameters are sane. The end result of Generate is either NULL, or a greybuf containing an anti-aliased, seamlessly wrapped greyscale 8-bit monolayer texture. We don't care what happens to the greybuf after we produce it. */ LayerRef layer = NULL; greybuf out = NULL; if(list) { //Create a new layer with the settings we were given. layer = MakeLayer(ctr, h, v, list); if(layer) { //Pass the layer to the greybuf creator to retrieve our image. out = GeneratePointFunction(h, v, layer); //Now throw away the layer, since we no longer need it. DumpLayer(layer); } } return out; } LayerRef MakeLayer(int genctr, int h, int v, GenListRef list) { /* Create a layer for later inspection. We store all the data about this layer that we know into a LayerRec. We also initialize the specific generator we are going to use. */ LayerRef out = NULL; //Verify our input parameters. //The following line was the source of an extremely stupid bug in 1.0 through 1.1d3. if(genctr >= 0 && genctr < CountGenerators(list) && h > 0 && v > 0) { out = (LayerRef)malloc(sizeof(LayerRec)); if(out) { //Put in all the info the caller gave us in parameters. out->gencode = &list->gen[genctr]; out->hmax = h; out->vmax = v; #if ROLL_TEXTURE out->rollh = (rand() * h) / RAND_MAX; out->rollv = (rand() * v) / RAND_MAX; #else out->rollh = out->rollv = 0; #endif //Now initialize our generator and save its refcon. out->refcon = out->gencode->init ? out->gencode->init() : NULL; } } return out; } channelval GetLayerPixel(int h, int v, LayerRef it) { /* Get a pixel value from the layer. If out of bounds, returns MIN_CHANVAL. There is no hard guarantee that if you ask for the same pixel twice, you will get exactly the same answer; however, the value should fit within its surrounding texture no matter when you ask for it. You don't have to ask for pixels in any specific order. */ channelval out = MIN_CHANVAL; if(it && h >= 0 && v >= 0) { if(h < it->hmax && v < it->vmax) { /* Calculate the point they wanted. Basically, we convert all of the coordinates into floating point values from 0 through 1. This lets the generators put out the same images regardless of the dimensions of the output data. Then we calculate the image, using the traditional old wrap/alias code. Then we convert the floating point value to a standard 0..255 value and return it to the caller. */ float fhpos, fvpos, fhmax, fvmax, pixelval, fudge; fhpos = ((h + it->rollh) < it->hmax) ? h + it->rollh : h + it->rollh - it->hmax; fvpos = ((v + it->rollv) < it->vmax) ? v + it->rollv : v + it->rollv - it->vmax; fhmax = it->hmax; fvmax = it->vmax; fudge = 1.0 / (fhmax + fvmax); out = GetAntiAliasedPoint(fhpos / fhmax, fvpos / fvmax, fudge, it->refcon, it->gencode) * CHANNELVAL_FMAX; } } return out; } void DumpLayer(LayerRef it) { /* We are done with this layer; throw it away. Also shut down the generator. */ if(it) { //Shut down the generator. if(it->gencode->exit) it->gencode->exit(it->refcon); //That's about all we have to do. free(it); it = NULL; } } static greybuf GeneratePointFunction(int hmax, int vmax, LayerRef it) { /* We've been given a layer. The caller wants a greybuf with the entire contents of the layer. We create a greybuf, iterate through the layer, and pick off all its pixel values. */ greybuf out = NULL; /* First order of business: Create a greybuf to hold our output. This will have the size and specifications given in the parameters. */ out = MakeGreyBuf(hmax, vmax); if(out) { /* Iterate through every pixel in the greybuf. For each pixel, grab a value from the layer function and install it as the value in the pixel. */ int hctr, vctr; //Iterate through each line of the texture, calculating points as we go. for(vctr = 0; vctr < vmax; vctr++) { for(hctr = 0; hctr < hmax; hctr++) { SetGreyBufPixel(out, hctr, vctr, GetLayerPixel(hctr, vctr, it)); } } } return out; } static float GetAntiAliasedPoint(float fhpos, float fvpos, float fudge, void* refcon, GeneratorRec* gen) { float pixelval; pixelval = GetWrappedPoint(fhpos, fvpos, refcon, gen); if(!gen->isAntiAliased) { /* This generator does not anti-alias itself. We need to do the anti-aliasing for it. The way we do this is to ask for a few more points, positioned between this point and the next one that will be computed. We then average all of these point values together. This does not affect the appearance of smooth gradients, but it significantly improves the way sharp transitions look. You can't see the individual pixels nearly so easily. */ pixelval += GetWrappedPoint(fhpos + fudge, fvpos, refcon, gen); pixelval += GetWrappedPoint(fhpos, fvpos + fudge, refcon, gen); pixelval += GetWrappedPoint(fhpos + fudge, fvpos + fudge, refcon, gen); pixelval /= 4; } return pixelval; } static float GetWrappedPoint(float fhpos, float fvpos, void* refcon, GeneratorRec* gen) { /* Get a point from this function. But don't just get the point - also get some out-of-band values and mix them in proportionately. This results in a seamlessly wrapped texture, where you can't see the edges. Some functions do this on their own; if that's the case, we let it do it. Otherwise, we do the computations ourself. */ float pixelval = 0; GenPointProc tempfn; tempfn = (GenPointProc)gen->process; pixelval = tempfn(fhpos, fvpos, refcon); /* If this function does not generate seamlessly-tiled textures, then it is our job to pull in out-of-band data and mix it in with the actual pixel to get a smooth edge. */ if(!gen->isSeamless) { /* We mix this pixel with out-of-band values from the opposite side of the tile. This is a "weighted average" proportionate to the pixel's distance from the edge of the tile. This creates a smoothly fading transition from one side of the texture to the other when the edges are tiled together. */ float farh, farv; float farval1, farval2, farval3; float totalweight, weight, farweight1, farweight2, farweight3; //The farh and farv are on the opposite side of the tile. farh = fhpos + 1.0; farv = fvpos + 1.0; //There are three pixel values to grab off the edges. farval1 = tempfn(fhpos, farv, refcon); farval2 = tempfn(farh, fvpos, refcon); farval3 = tempfn(farh, farv, refcon); //Calculate the weight factors for each far point. weight = fhpos * fvpos; farweight1 = fhpos * (2.0 - farv); farweight2 = (2.0 - farh) * fvpos; farweight3 = (2.0 - farh) * (2.0 - farv); totalweight = weight + farweight1 + farweight2 + farweight3; //Now average all the pixels together, weighting each one by the local vs far weights. pixelval = ((pixelval * weight) + (farval1 * farweight1) + (farval2 * farweight2) + (farval3 * farweight3)) / totalweight; } /* If the generator messes up and returns an out-of-range value, we clip it here. This way, curves that leap out of bounds simply get chopped off, instead of getting renormalized at the opposite end of the scale leading to big discontinuities and ugliness. This can mask bugs in a generator, but we aren't the generator so we don't care. If you're writing a generator it is your job to make your code work, and my job to make sure my code works even if yours doesn't. */ if(pixelval > 1.0) pixelval = 1.0; if(pixelval < 0.0) pixelval = 0.0; return pixelval; } starfish-1.1/portable/generators.h100600 764 764 5443 7042177111 16711 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Starfish - Generator Manager Textures become complex by merging layers of simpler textures. Each basic layer is the result of a Generator - a function or algorithm that creates two-dimensional images. The generator manager creates a table of all installed generators. There are several different types of generators, and they produce graphics in different ways. The manager keeps track of all of this information and provides a uniform interface for the starfish engine itself. Individual generator algorithms work in floating-point space. The generator works in pixelspace. There are two ways to use this library. The easy way: Call Generate with a set of dimensions and your choice of generator. It will return a greybuf containing a texture created by that generator. Or there is the hard, but more configurable way: Create a layer, then ask it for pixel values at your leisure. When you're done asking your questions, throw the layer away. Or use it again, we don't really care. */ #ifndef __starfish_generators__ #define __starfish_generators__ 0 #include "greymap.h" //Opaque reference to all of the available generators. typedef struct GeneratorList* GenListRef; //Reference to a generator instance with its package of settings. typedef struct LayerRec* LayerRef; //Seek out and load up all available generators. GenListRef LoadGenerators(void); //Unload all generators and release the memory they occupied. void UnloadGenerators(GenListRef list); //How many generators are available? int CountGenerators(GenListRef list); //Create a texture of appropriate dimensions from this generator. greybuf Generate(int ctr, int h, int v, GenListRef list); //Create a layer for later inspection. LayerRef MakeLayer(int ctr, int h, int v, GenListRef list); //Get a pixel value from the layer. If out of bounds, returns MIN_CHANVAL. channelval GetLayerPixel(int h, int v, LayerRef it); //We are done with this layer; throw it away. void DumpLayer(LayerRef it); //If ROLL_TEXTURE is set true, the generator will randomize the origin //point for each layer. #define ROLL_TEXTURE 1 #endif //__starfish_generators__ starfish-1.1/portable/genutils.c100600 764 764 5462 7042177111 16366 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Utilities common to generators I wrote these once and don't want to have to write them again. */ #include #include #include "genutils.h" float frand(float range) { float denom, max; denom = rand(); max = RAND_MAX; denom /= max; return range * denom; } float frandge(float min, float max) { return frand(max - min) + min; } int irand(int range) { return frand(range); } int irandge(int min, int max) { return irand(max - min) + min; } static int maybeshifter = 0; int maybe(void) { //Flip a coin. Returns a zero/nonzero answer with equal probability. if(maybeshifter > 31) maybeshifter = 0; return (rand() >> maybeshifter++) & 1; } int RandomPackMethod(void) { /* Pick a pack method at random and return it to the caller. Presumably, they will save it somewhere. */ return (rand() * PACK_METHOD_COUNT) / RAND_MAX; } float PackedCos(float distance, float scale, int packmethod) { /* Many of the generators use a scheme where a wave is applied over a line. Since the range of a cosine wave is -1..0..1 rather than the simpler 0..1 expected by Starfish, we have to devise some way of packing the curve into the available range. These methods live in PackedCos, where they can be shared between all modules using such schemes. In addition, when new pack methods are devised, they can be added to the entire Starfish generator set simply by placing them in here. */ float rawcos, out; rawcos = cos(distance * scale); switch(packmethod) { case flipSignToFit: //When the scale goes negative, turn it positive. out = (rawcos >= 0) ? rawcos : -rawcos; break; case truncateToFit: //When the scale goes negative, add 1 to it to bring it in range out = (rawcos >= 0) ? rawcos : rawcos + 1; break; case scaleToFit: //Compress the -1..0..1 range of the normal cosine into 0..1 out = (rawcos + 1.0) / 2.0; break; case slopeToFit: //use only the first half of the cycle. A saw-edge effect. out = (cos(fmod(distance * scale, pi)) + 1.0) / 2.0; break; default: //just to show me something's wrong out = 0.5; } return out; } starfish-1.1/portable/genutils.h100600 764 764 2323 7042177111 16364 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Generator Utilities A few small gadgets of use to the generator libraries. */ #ifndef __GENUTILS__ #define __GENUTILS__ 0 #define pi 3.141592653589 float frand(float range); float frandge(float min, float max); int irand(int range); int irandge(int min, int max); int maybe(void); enum packmethods { scaleToFit, flipSignToFit, truncateToFit, slopeToFit, PACK_METHOD_COUNT }; int RandomPackMethod(void); float PackedCos(float distance, float scale, int packmethod); #endif //__GENUTILS__ starfish-1.1/portable/pixels/ 42700 764 764 0 7042177111 15570 5ustar msaxmanmsaxmanstarfish-1.1/portable/pixels/.AppleDouble/ 42700 764 764 0 7042177111 20042 5ustar msaxmanmsaxmanstarfish-1.1/portable/pixels/.AppleDouble/.Parent100700 764 764 1115 7042177111 21370 0ustar msaxmanmsaxmanMVU - pixelsPZ?starfish-1.1/portable/pixels/.AppleDouble/bufferxform.c100600 764 764 1115 7042177111 22626 0ustar msaxmanmsaxmanMV U - bufferxform.cvTEXTCWIEstarfish-1.1/portable/pixels/.AppleDouble/bufferxform.h100600 764 764 1115 7042177111 22633 0ustar msaxmanmsaxmanMV U - bufferxform.h vTEXTCWIEastarfish-1.1/portable/pixels/.AppleDouble/greymap.c100600 764 764 1771 7042177111 21755 0ustar msaxmanmsaxmanMV U - greymap.cwTEXTCWIEZZR greymap.cPartSIT!PartSIT!k(H Monaco`c,A ( ( ZZR u5RMPSRMWBB* s4starfish-1.1/portable/pixels/.AppleDouble/greymap.h100600 764 764 1771 7042177111 21762 0ustar msaxmanmsaxmanMV U - greymap.h wTEXTCWIE ZZRm0LGATitleMixin.h greymap.hPartSIT!PartSIT!k(%mLGACmdIconSuiteControl.cp%mLGADialogBox.h%mIcon H Monaco`c,A ( ( ZZR u5RMPSRMWBB* s@starfish-1.1/portable/pixels/.AppleDouble/pixmap.c100600 764 764 1771 7042177111 21607 0ustar msaxmanmsaxmanMVU - pixmap.cxTEXTCWIE aZZRpixmap.cxPartSIT!PartSIT!k(H Monaco`c,A ( ( ZZR u5RMPSRMWBB* s8starfish-1.1/portable/pixels/.AppleDouble/pixmap.h100600 764 764 1115 7042177111 21604 0ustar msaxmanmsaxmanMVU - pixmap.h xTEXTCWIE starfish-1.1/portable/pixels/.AppleDouble/rasterliberrs.h100600 764 764 1115 7042177111 23171 0ustar msaxmanmsaxmanMVU - rasterliberrs.h xTEXTCWIE`starfish-1.1/portable/pixels/.AppleDouble/starfish-rasterlib.c100600 764 764 1115 7042177111 24111 0ustar msaxmanmsaxmanMVU - starfish-rasterlib.cxTEXTCWIE`astarfish-1.1/portable/pixels/.AppleDouble/starfish-rasterlib.h100600 764 764 1115 7042177111 24116 0ustar msaxmanmsaxmanMVU - starfish-rasterlib.h yTEXTCWIEastarfish-1.1/portable/pixels/bufferxform.c100600 764 764 24703 7042177111 20404 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Routines to transform entire buffers, of the grey or coloured variety. */ #include "bufferxform.h" #include "rasterliberrs.h" #include "pixmap.h" #include "greymap.h" static srl_result CopyGreyIntoPixBuf(greybuf src, pixbuf dest, int RGB, int alpha); srl_result CopyGreyIntoPixBuf(greybuf src, pixbuf dest, int RGB, int alpha) { /* Copy a greybuf into selected channels of a pixbuf. We do this the quick way: by running through peeked raster lines in both the pixbuf and greybuf. This is a really dumb-simple function. */ srl_result err = srl_noErr; if(src && dest) { //Make sure these two buffers are exactly the same size. if ( (GetGreyBufWidth(src) == GetPixBufWidth(dest)) && (GetGreyBufHeight(src) == GetPixBufHeight(dest)) ) { int vctr, vmax; int hctr, hmax; vmax = GetPixBufHeight(dest); hmax = GetPixBufWidth(dest); for(vctr = 0; vctr < vmax; vctr++) { channelline srcline; rasterline destline; srcline = PeekGreyRasterLine(src, vctr); destline = PeekRasterLine(dest, vctr); if(srcline && destline) { pixel* temppixel; channelval tempval; /* For each pixel in this row, read off the channel value from the greybuf. Then store this value into all four channels in the destination pixel. */ for(hctr = 0; hctr < hmax; hctr++) { temppixel = &destline[hctr]; tempval = srcline[hctr]; if(RGB) temppixel->red = temppixel->green = temppixel->blue = tempval; if(alpha) temppixel->alpha = tempval; } } else err = srl_bollixed; } } else err = srl_mismatchedSizes; } else err = srl_bogusBuffer; return err; } //Copy the contents of one pixbuf into another. srl_result CopyPixBuf(pixbuf src, pixbuf dest) { } //Copy one greybuf into another greybuf. srl_result CopyGreyBuf(greybuf src, greybuf dest) { } srl_result ExpandGreyIntoPixels(greybuf src, pixbuf dest) { //Copy a greybuf into both colour and alpha channels on the pixbuf return CopyGreyIntoPixBuf(src, dest, 1, 1); } srl_result CopyGreyIntoAlpha(greybuf src, pixbuf dest) { //Copy a greybuf into the pixbuf's alpha channel, leaving other data untouched. return CopyGreyIntoPixBuf(src, dest, 0, 1); } srl_result CopyGreyIntoRGB(greybuf src, pixbuf dest) { //Fill all *but* the alpha channel with the appropriate grey values. return CopyGreyIntoPixBuf(src, dest, 1, 0); } srl_result CopyGreyIntoGradient(greybuf src, pixbuf dest, const pixel* low, const pixel* high) { /* Expand the grey values into RGB using a colour gradient. This works a lot like CopyGreyIntoPixBuf does: it runs through rasterlines, copying grey channel values into colour. The trick, though, is that instead of running from black to white values, we run from the "low" to "high" colours. */ srl_result err = srl_noErr; if(src && dest) { //Make sure these two buffers are exactly the same size. if ( (GetGreyBufWidth(src) == GetPixBufWidth(dest)) && (GetGreyBufHeight(src) == GetPixBufHeight(dest)) ) { int vctr, vmax; int hctr, hmax; vmax = GetPixBufHeight(dest); hmax = GetPixBufWidth(dest); for(vctr = 0; vctr < vmax; vctr++) { channelline srcline; rasterline destline; srcline = PeekGreyRasterLine(src, vctr); destline = PeekRasterLine(dest, vctr); if(srcline && destline) { pixel* temppixel; channelval tempval; /* For each pixel in this row, read off the channel value from the greybuf. Then store this value into all four channels in the destination pixel. */ for(hctr = 0; hctr < hmax; hctr++) { float interval; temppixel = &destline[hctr]; tempval = srcline[hctr]; //Calculate the red channel of the pixel. interval = tempval; interval /= CHANNEL_RANGE; interval *= high->red - low->red; temppixel->red = interval + low->red; //Next calculate the green channel. interval = tempval; interval /= CHANNEL_RANGE; interval *= high->green - low->green; temppixel->green = interval + low->green; //Calculate the blue channel in the same fashion interval = tempval; interval /= CHANNEL_RANGE; interval *= high->blue - low->blue; temppixel->blue = interval + low->blue; //We ignore the alpha channel. } } else err = srl_bollixed; } } else err = srl_mismatchedSizes; } else err = srl_bogusBuffer; return err; } //Convert the alpha channel of a colour image into a greybuf. srl_result CopyAlphaIntoGreyBuf(pixbuf src, greybuf dest) { } //Average the RGB channels of a colour image into a greybuf srl_result CopyRGBIntoGreyBuf(pixbuf src, greybuf dest) { } srl_result MergePixBufs(pixbuf top, pixbuf bottom, pixbuf dest) { /* Merge two pixbufs into a third, merging alpha channels en route. This is like laying one slide on top of another, sort of. */ srl_result err = srl_noErr; if(top && bottom && dest) { //Make sure these two buffers are exactly the same size. if ( (GetPixBufWidth(top) == GetPixBufWidth(bottom)) && (GetPixBufHeight(top) == GetPixBufHeight(bottom)) && (GetPixBufWidth(bottom) == GetPixBufWidth(dest)) && (GetPixBufHeight(bottom) == GetPixBufHeight(dest)) ) { int vctr, vmax; int hctr, hmax; vmax = GetPixBufHeight(dest); hmax = GetPixBufWidth(dest); for(vctr = 0; vctr < vmax; vctr++) { rasterline topline; rasterline botline; rasterline destline; topline = PeekRasterLine(top, vctr); botline = PeekRasterLine(bottom, vctr); destline = PeekRasterLine(dest, vctr); if(topline && botline && destline) { pixel* toppixel; pixel* botpixel; pixel* destpixel; /* For each pixel in this row, read off the channel value from the greybuf. Then store this value into all four channels in the destination pixel. */ for(hctr = 0; hctr < hmax; hctr++) { destpixel = &destline[hctr]; toppixel = &topline[hctr]; botpixel = &botline[hctr]; //Calculate the red channel of the pixel. destpixel->red = ( (toppixel->red * toppixel->alpha) + (botpixel->red * (CHANNEL_RANGE - toppixel->alpha)) ) / (CHANNEL_RANGE); //Next calculate the green channel. destpixel->green = ( (toppixel->green * toppixel->alpha) + (botpixel->green * (CHANNEL_RANGE - toppixel->alpha)) ) / (CHANNEL_RANGE); //Calculate the blue channel in the same fashion destpixel->blue = ( (toppixel->blue * toppixel->alpha) + (botpixel->blue * (CHANNEL_RANGE - toppixel->alpha)) ) / (CHANNEL_RANGE); //The alpha channel is the sum of these alpha channels. 255 is max opaque. if(toppixel->alpha + botpixel->alpha > CHANNEL_RANGE) destpixel->alpha = CHANNEL_RANGE; else destpixel->alpha = toppixel->alpha + botpixel->alpha; } } else err = srl_bollixed; } } else err = srl_mismatchedSizes; } else err = srl_bogusBuffer; return err; } //Swaps a pixbuf both ways so the corners are in the centre. srl_result SwapPixBufCorners(pixbuf it) { /* Swap a pixbuf so that its corners are in its centre. Someday it might be nice to add an "offset" factor so the results don't land exactly in the middle, but are sort of crookedly wrapped. The purpose of this transformation is to fudge the wrapped edges of images around so that they don't become obvious when many layers are stacked up on top of each other, as tends to happen with Starfish. */ srl_result err = srl_noErr; if(it) { /* Iterate through all the rows of this pixbuf. Grab each row, one at a time, and exchange it with its neighbor on the opposite side of the pixbuf. */ rasterline tempstorage; rasterline peekline; pixel peekpixel; int vctr, vmax, vhalf; int hctr, hmax, hhalf; //Create a temporary storage line to hold the rasterline-in-transit. tempstorage = (rasterline)malloc(GetPixBufLineSize(it)); if(tempstorage) { vmax = GetPixBufHeight(it); vhalf = vmax / 2; hmax = GetPixBufWidth(it); hhalf = hmax / 2; for(vctr = 0; vctr < vhalf; vctr++) { //Copy the top line into our temporary buffer. err = GetRasterLine(it, 0, hmax, vctr, tempstorage); //Swap the contents of the both lines horizontally. //We kind of have a smashed loop here. peekline = PeekRasterLine(it, vctr + vhalf); for(hctr = 0; hctr < hhalf; hctr++) { peekpixel = tempstorage[hctr]; tempstorage[hctr] = tempstorage[hctr + hhalf]; tempstorage[hctr+hhalf] = peekpixel; peekpixel = peekline[hctr]; peekline[hctr] = peekline[hctr + hhalf]; peekline[hctr+hhalf] = peekpixel; } //Copy the bottom line into the top line. err = SetRasterLine(it, 0, hmax, vctr, peekline); //Now put our temporary buffer into the bottom line. err = SetRasterLine(it, 0, hmax, vctr + vhalf, tempstorage); } //Throw away the temporary storage line, since we need it no longer. free(tempstorage); tempstorage = NULL; } else err = srl_bollixed; } else err = srl_bogusBuffer; return err; } //Performs the same operation to a greybuf. srl_result SwapGreyBufCorners(greybuf it) { } srl_result InvertGreyBuf(greybuf it) { /* Invert the contents of a greybuf. Values from 0..255 become values from 255..0. Black becomes white and vice versa. */ channelline peekline; srl_result err = srl_noErr; int vctr, hctr, hmax, vmax; hmax = GetGreyBufWidth(it); vmax = GetGreyBufHeight(it); if(it) { for(vctr = 0; vctr < vmax; vctr++) { peekline = PeekGreyRasterLine(it, vctr); if(peekline) { for(hctr = 0; hctr < hmax; hctr++) { peekline[hctr] = MAX_CHANVAL - peekline[hctr]; } } else err = srl_bollixed; } } else err = srl_bogusBuffer; return err; } starfish-1.1/portable/pixels/bufferxform.h100600 764 764 4444 7042177111 20371 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Routines to transform entire buffers, of the grey or coloured variety. */ #ifndef __starfish_bufferxform__ #define __starfish_bufferxform__ 0 #include "rasterliberrs.h" #include "pixmap.h" #include "greymap.h" //Copy the contents of one pixbuf into another. srl_result CopyPixBuf(pixbuf src, pixbuf dest); //Copy one greybuf into another greybuf. srl_result CopyGreyBuf(greybuf src, greybuf dest); //Copy a greybuf into all channels of a pixbuf. srl_result ExpandGreyIntoPixels(greybuf src, pixbuf dest); //Copy a greybuf into the pixbuf's alpha channel, leaving other data untouched. srl_result CopyGreyIntoAlpha(greybuf src, pixbuf dest); //Fill all *but* the alpha channel with the appropriate grey values. srl_result CopyGreyIntoRGB(greybuf src, pixbuf dest); //Expand the grey values into RGB using a colour gradient. srl_result CopyGreyIntoGradient(greybuf src, pixbuf dest, const pixel* low, const pixel* high); //Convert the alpha channel of a colour image into a greybuf. srl_result CopyAlphaIntoGreyBuf(pixbuf src, greybuf dest); //Average the RGB channels of a colour image into a greybuf srl_result CopyRGBIntoGreyBuf(pixbuf src, greybuf dest); //Merge two pixbufs into a third, merging alpha channels en route. //The dest can be one of the src pixbufs. srl_result MergePixBufs(pixbuf top, pixbuf bottom, pixbuf dest); //Swaps a pixbuf both ways so the corners are in the centre. srl_result SwapPixBufCorners(pixbuf it); //Performs the same operation to a greybuf. srl_result SwapGreyBufCorners(greybuf it); //Inverts the contents of a greybuf. srl_result InvertGreyBuf(greybuf it); #endif starfish-1.1/portable/pixels/greymap.c100600 764 764 24375 7042177111 17530 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Code to create and access the contents of greymaps. A greymap is a pixel buffer where each pixel holds one 8-bit channel. It is parallel to a pixmap, but uses a different API. OOP would be nice here. */ #include #include #include "greymap.h" struct greybufrec { //How many pixels wide is one line? int horz; //How many rows tall is the buffer? int vert; //The block of data the pixels live in void* buffer; //An array of channellines pointing into the buffer #if defined(__MWERKS__) channelline linestart[]; #else channelline linestart[0]; #endif }; greybuf MakeGreyBuf(int horz, int vert) { /* Create a pixel buffer. We allocate a greybufrec, fill out its data, and give it a big block to store pixel data in. We also fill out the linestarts table. Once this is done, we give it back to the user. If we fail, we return NULL. */ size_t rasterlinesize, pixarraysize, greybufsize; void* pixelarray = NULL; greybuf out = NULL; /* Start out by creating a big array of bytes to store all the pixels in. We will separate this out into raster lines later. */ rasterlinesize = horz * sizeof(channelval); pixarraysize = vert * rasterlinesize; pixelarray = malloc(pixarraysize); if(pixelarray) { /* We got the pixel array. Now we can make the rest of the greybuffer: the record and linestarts array. The size of the block whose address we return varies by the number of rows in the buffer. This is because we create one row-pointer for each */ greybufsize = sizeof(struct greybufrec) + (sizeof(channelline) * vert); out = (greybuf)malloc(greybufsize); if(out) { /* We successfully created the greybuf record. Link the pixel array to this record, then fill out the addresses in the rasterline array. */ int rowctr; out->horz = horz; out->vert = vert; out->buffer = pixelarray; for(rowctr = 0; rowctr < vert; rowctr++) { out->linestart[rowctr] = (channelline)((long)pixelarray + (rasterlinesize * rowctr)); } } else { /* We were not able to allocate the greybuf record. So we have to throw away the pixel buffer we already created, in order to not cause a memory leak. */ free(pixelarray); pixelarray = NULL; } } return out; } srl_result DumpGreyBuf(greybuf it) { /* The user is done with the pixel buffer they created. Release all memory associated with this buffer. */ srl_result err = srl_noErr; if(it) { //Is there a pixel array in this greybuf? if(it->buffer) { //Free the buffer and clear out the field that held it. free(it->buffer); it->buffer = NULL; } //Free the greybuf as a whole. free(it); //It is now the caller's responsibility to stop using this greybuf. } else err = srl_bogusBuffer; return err; } srl_result FillGreyBuf(greybuf it, channelval src) { /* Fill the entire greybuf up with this value. This is good if you want to initialize it in one call. */ srl_result err = srl_noErr; if(it) { //Loop through all of the rasterlines. int rowctr; for(rowctr = 0; rowctr < it->vert; rowctr++) { channelline line; line = it->linestart[rowctr]; if(line) { //Now loop through all of the pixels in this line. int pixctr; for(pixctr = 0; pixctr < it->horz; pixctr++) { //Set this pixel to the value supplied. line[pixctr] = src; } } else err = srl_bollixed; } } else err = srl_bogusBuffer; return err; } size_t GetGreyBufLineSize(greybuf it) { /* How many pixels wide is one scan line? That would be: the width of the greybuf times the size of one pixel. */ size_t out = 0; if(it) { out = it->horz * sizeof(channelval); } return out; } int GetGreyBufHeight(greybuf it) { /* How many rows tall is the buffer? Simple accessor function. */ int out = 0; if(it) { out = it->vert; } return out; } int GetGreyBufWidth(greybuf it) { /* How many pixels wide is one raster line? Again, a simple accessor function. */ int out = 0; if(it) { out = it->horz; } return out; } srl_result GetGreyBufPixel(greybuf it, int horz, int vert, channelval* dest) { /* Retrieve one pixel from the buffer. We could do the math directly and retrieve the pixel from the pixelbuffer, but that assumes more about the way the greybuf system works than I really want to. Instead, we use the known item: the array of raster lines. If you grab a pixel out of bounds, the contents of dest are undefined. This is a very inefficient way to deal with the contents of the greybuf and should not be used if you care about speed. */ srl_result err = srl_noErr; if(it) { if ( (horz >= 0 && horz < it->horz) && (vert >= 0 && vert < it->vert) ) { /* The requested pixel is within the bounds of a valid greybuf. Look up the rasterline indicated by the pixel's row. */ channelline destline; destline = it->linestart[vert]; if(destline) { /* Now look up the individual pixel in this row and copy it to the caller's destination pixel. */ if(dest) { *dest = destline[horz]; } else err = srl_bogusParamPtr; } else err = srl_bollixed; } else err = srl_outOfBounds; } else err = srl_bogusBuffer; return err; } srl_result SetGreyBufPixel(greybuf it, int horz, int vert, channelval src) { /* Places the caller's pixel into the buffer. This uses identical logic to GetGreyBufPixel and, like that function, should not be used in critical loops. Or in any situation where you are dealing with more than just a few pixels. */ srl_result err = srl_noErr; if(it) { if ( (horz >= 0 && horz < it->horz) && (vert >= 0 && vert < it->vert) ) { /* The requested pixel is within the bounds of a valid greybuf. Look up the rasterline indicated by the pixel's row. */ channelline destline; destline = it->linestart[vert]; if(destline) { destline[horz] = src; } else err = srl_bollixed; } else err = srl_outOfBounds; } else err = srl_bogusBuffer; return err; } srl_result GetGreyRasterLine(greybuf it, int start, int count, int vert, channelline dest) { /* Copy a range of pixels from one rasterline in the buffer. It is your responsibility to make sure that your dest buffer can hold the number of pixels you ask for. If your request falls off either end of the rasterline, or you ask for a negative number of pixels, this function will return srl_outOfBounds. */ srl_result err = srl_noErr; if(it) { //Is the user's request sane? Do we have the pixels they ask for? if ( (start >= 0 && start < it->horz) && (count >= 0 && (start+count) <= it->horz) && (vert >= 0 && vert < it->vert) ) { /* Locate the line the caller wants to retrieve data from. Make sure it is valid and that we haven't gotten confused. */ channelline destline; destline = it->linestart[vert]; if(destline) { /* If they supplied a non-null pixel buffer, copy the pixels into it. */ if(dest) { memcpy(dest, &destline[start], count * sizeof(channelval)); } else err = srl_bogusParamPtr; } else err = srl_bollixed; } else err = srl_outOfBounds; } else err = srl_bogusBuffer; return err; } srl_result SetGreyRasterLine(greybuf it, int start, int count, int vert, const channelline src) { /* Modify a range of pixels in one rasterline in the buffer. Takes data from the pixel array passed in. If your request falls off either end of the rasterline, or you supply a negative number of pixels, this function will return srl_outOfBounds. */ srl_result err = srl_noErr; if(it) { /* Is the user's request sane? Will their request overwrite the legal area for this line? */ if ( (start >= 0 && start < it->horz) && (count >= 0 && (start+count) <= it->horz) && (vert >= 0 && vert < it->vert) ) { /* Locate the rasterline the caller wants to retrieve data from. Make sure it is valid and that we haven't gotten confused. */ channelline destline; destline = it->linestart[vert]; if(destline) { /* If the buffer they supplied is non-null, copy the data from it and into our rasterline. */ if(src) { memcpy(&destline[start], src, count * sizeof(channelval)); } else err = srl_bogusParamPtr; } else err = srl_bollixed; } else err = srl_outOfBounds; } else err = srl_bogusBuffer; return err; } channelline PeekGreyRasterLine(greybuf it, int vert) { /* If you want to examine all the pixels in a pixbuf, there are three ways to do it: iterate through each pixel, row by row, using GetRasterBufPixel on each one. This is miserably slow. Or you can iterate through each row, using GetRasterLine. This is still slow, since it is full of memcpy()s. Or, you can do it the right way: iterate through each row using PeekRasterLine to get direct access to the bits in the row. If you want to copy all of the data out of a pixbuf, use GetRasterLine; you won't save any time by using Peek. Or, if you want to wholesale change the contents of the pixbuf, use SetRasterLine. But if you want to read/modify/write most or all of the pixels in a pixbuf, use PeekRasterLine to get direct access and change the values by hand. The value you get back will either be NULL or a pointer to an array of pixels. If the latter, there will be precisely as many pixels in the array as there are columns in the pixbuf. If you write off the end of the rasterline, undefined things will happen. */ channelline out = NULL; if(it) { if (vert >= 0 && vert < it->vert) { out = it->linestart[vert]; } } return out; } starfish-1.1/portable/pixels/greymap.h100600 764 764 4717 7042177111 17513 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Code to manage Greymaps - pixmaps with only one 8-bit data channel */ #ifndef __starfish_greymap__ #define __starfish_greymap__ 0 #include #include "rasterliberrs.h" typedef struct greybufrec* greybuf; typedef unsigned char channelval; #define MIN_CHANVAL 0 #define MAX_CHANVAL 255 #define CHANNEL_RANGE 256 typedef channelval* channelline; //Create a new greybuf with the specified number of columns and rows. greybuf MakeGreyBuf(int horz, int vert); //Dispose of an already-existing greybuf. srl_result DumpGreyBuf(greybuf it); //Fill the buffer with this value. srl_result FillGreyBuf(greybuf it, channelval src); //The next three functions return zero if the greybuf is bogus. //How many pixels wide is the buffer? int GetGreyBufWidth(greybuf it); //How many rows tall is the buffer? int GetGreyBufHeight(greybuf it); //How many bytes does one raster line occupy? size_t GetGreyBufLineSize(greybuf it); //Retrieve one pixel from the buffer. srl_result GetGreyBufPixel(greybuf it, int horz, int vert, channelval* dest); //Place one pixel into the buffer. srl_result SetGreyBufPixel(greybuf it, int horz, int vert, channelval src); //Get part of one rasterline from the buffer. It is your responsibility to make sure //your buffer is big enough to hold the entire line. Use GetPixBufLineSize to check. srl_result GetGreyRasterLine(greybuf it, int start, int count, int vert, channelline dest); //Put this rasterline into the buffer. Again, your responsibility to make sure your //source buffer is big enough. srl_result SetGreyRasterLine(greybuf it, int start, int count, int vert, const channelline dest); //Returns the address of the specified raster line, if available. channelline PeekGreyRasterLine(greybuf it, int vert); #endif //__starfish_greymap__ starfish-1.1/portable/pixels/pixmap.c100600 764 764 26446 7042177111 17363 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. A set of routines used to manage a rudimentary pixmap library. Pixmaps are collections of raster lines, which are arrays of pixels. This lib creates such pixmaps and lets you access them row-at-a-time. Right now, the Starfish rasterlib assumes 32-bit pixels and fixed size buffers. It doesn't do all that much, really... */ #include #include #include "starfish-rasterlib.h" struct pixbufrec { //How many pixels wide is one raster line? int horz; //And how many rows tall is the buffer? int vert; //This is the block the pixel data lives in void* buffer; //And this is an array of raster lines. #if defined(__MWERKS__) rasterline linestart[]; #else rasterline linestart[0]; #endif }; pixbuf MakePixBuf(int horz, int vert) { /* Create a pixel buffer. We allocate a pixbufrec, fill out its data, and give it a big block to store pixel data in. We also fill out the linestarts table. Once this is done, we give it back to the user. If we fail, we return NULL. */ size_t rasterlinesize, pixarraysize, pixbufsize; void* pixelarray = NULL; pixbuf out = NULL; /* Start out by creating a big array of bytes to store all the pixels in. We will separate this out into raster lines later. */ rasterlinesize = horz * sizeof(pixel); pixarraysize = vert * rasterlinesize; pixelarray = malloc(pixarraysize); if(pixelarray) { /* We got the pixel array. Now we can make the rest of the pixbuffer: the record and linestarts array. The size of the block whose address we return varies by the number of rows in the buffer. This is because we create one row-pointer for each */ pixbufsize = sizeof(struct pixbufrec) + (sizeof(rasterline) * vert); out = (pixbuf)malloc(pixbufsize); if(out) { /* We successfully created the pixbuf record. Link the pixel array to this record, then fill out the addresses in the rasterline array. */ int rowctr; out->horz = horz; out->vert = vert; out->buffer = pixelarray; for(rowctr = 0; rowctr < vert; rowctr++) { out->linestart[rowctr] = (rasterline)((long)pixelarray + (rasterlinesize * rowctr)); } } else { /* We were not able to allocate the pixbuf record. So we have to throw away the pixel buffer we already created, in order to not cause a memory leak. */ free(pixelarray); pixelarray = NULL; } } return out; } srl_result DumpPixBuf(pixbuf it) { /* The user is done with the pixel buffer they created. Release all memory associated with this buffer. */ srl_result err = srl_noErr; if(it) { //Is there a pixel array in this pixbuf? if(it->buffer) { //Free the buffer and clear out the field that held it. free(it->buffer); it->buffer = NULL; } //Free the pixbuf as a whole. free(it); //It is now the caller's responsibility to stop using this pixbuf. } else err = srl_bogusBuffer; return err; } srl_result FillPixBuf(pixbuf it, const pixel* src) { /* Fill the entire pixbuf up with this pixel. This is good if you want to initialize it in one call. Or something like that. */ srl_result err = srl_noErr; if(it) { //Loop through all of the rasterlines. int rowctr; for(rowctr = 0; rowctr < it->vert; rowctr++) { rasterline line; line = it->linestart[rowctr]; if(line) { //Now loop through all of the pixels in this line. int pixctr; for(pixctr = 0; pixctr < it->horz; pixctr++) { //Set this pixel to the value supplied. line[pixctr] = *src; } } else err = srl_bollixed; } } else err = srl_bogusBuffer; return err; } srl_result GreyFillPixBuf(pixbuf it, unsigned char src) { /* Fill all channels in this buffer with the value specified. This essentially turns the buffer grey. */ srl_result err = srl_noErr; if(it) { //Loop through all of the rasterlines. int rowctr; for(rowctr = 0; rowctr < it->vert; rowctr++) { rasterline line; line = it->linestart[rowctr]; if(line) { //Now loop through all of the pixels in this line. int pixctr; pixel* dest; for(pixctr = 0; pixctr < it->horz; pixctr++) { //Set this pixel to the value supplied. dest = &line[pixctr]; dest->red = src; dest->green = src; dest->blue = src; dest->alpha = src; } } else err = srl_bollixed; } } else err = srl_bogusBuffer; return err; } size_t GetPixBufLineSize(pixbuf it) { /* How many pixels wide is one scan line? That would be: the width of the pixbuf times the size of one pixel. */ size_t out = 0; if(it) { out = it->horz * sizeof(pixel); } return out; } int GetPixBufHeight(pixbuf it) { /* How many rows tall is the buffer? Simple accessor function. */ int out = 0; if(it) { out = it->vert; } return out; } int GetPixBufWidth(pixbuf it) { /* How many pixels wide is one raster line? Again, a simple accessor function. */ int out = 0; if(it) { out = it->horz; } return out; } srl_result GetPixBufPixel(pixbuf it, int horz, int vert, pixel* dest) { /* Retrieve one pixel from the buffer. We could do the math directly and retrieve the pixel from the pixelbuffer, but that assumes more about the way the pixbuf system works than I really want to. Instead, we use the known item: the array of raster lines. If you grab a pixel out of bounds, the contents of dest are undefined. This is a very inefficient way to deal with the contents of the pixbuf and should not be used if you care about speed. */ srl_result err = srl_noErr; if(it) { if ( (horz >= 0 && horz < it->horz) && (vert >= 0 && vert < it->vert) ) { /* The requested pixel is within the bounds of a valid pixbuf. Look up the rasterline indicated by the pixel's row. */ rasterline destline; destline = it->linestart[vert]; if(destline) { /* Now look up the individual pixel in this row and copy it to the caller's destination pixel. */ if(dest) { *dest = destline[horz]; } else err = srl_bogusParamPtr; } else err = srl_bollixed; } else err = srl_outOfBounds; } else err = srl_bogusBuffer; return err; } srl_result SetPixBufPixel(pixbuf it, int horz, int vert, const pixel* src) { /* Places the caller's pixel into the buffer. This uses identical logic to GetPixBufPixel and, like that function, should not be used in critical loops. Or in any situation where you are dealing with more than just a few pixels. */ srl_result err = srl_noErr; if(it) { if ( (horz >= 0 && horz < it->horz) && (vert >= 0 && vert < it->vert) ) { /* The requested pixel is within the bounds of a valid pixbuf. Look up the rasterline indicated by the pixel's row. */ rasterline destline; destline = it->linestart[vert]; if(destline) { /* If the caller supplied a valid pixel record, copy its contents into the pixel specified in our buffer. */ if(src) { destline[horz] = *src; } else err = srl_bogusParamPtr; } else err = srl_bollixed; } else err = srl_outOfBounds; } else err = srl_bogusBuffer; return err; } srl_result GetRasterLine(pixbuf it, int start, int count, int vert, rasterline dest) { /* Retrieve a range of pixels from one rasterline in the buffer. It is your responsibility to make sure that your dest buffer can hold the number of pixels you ask for. If your request falls off either end of the rasterline, or you ask for a negative number of pixels, this function will return srl_outOfBounds. */ srl_result err = srl_noErr; if(it) { //Is the user's request sane? Do we have the pixels they ask for? if ( (start >= 0 && start < it->horz) && (count >= 0 && (start+count) <= it->horz) && (vert >= 0 && vert < it->vert) ) { /* Locate the rasterline the caller wants to retrieve data from. Make sure it is valid and that we haven't gotten confused. */ rasterline destline; destline = it->linestart[vert]; if(destline) { /* If they supplied a non-null pixel buffer, copy the pixels into it. */ if(dest) { memcpy(dest, &destline[start], count * sizeof(pixel)); } else err = srl_bogusParamPtr; } else err = srl_bollixed; } else err = srl_outOfBounds; } else err = srl_bogusBuffer; return err; } srl_result SetRasterLine(pixbuf it, int start, int count, int vert, const rasterline src) { /* Modify a range of pixels in one rasterline in the buffer. Takes data from the pixel array passed in. If your request falls off either end of the rasterline, or you supply a negative number of pixels, this function will return srl_outOfBounds. */ srl_result err = srl_noErr; if(it) { /* Is the user's request sane? Will their request overwrite the legal area for this line? */ if ( (start >= 0 && start < it->horz) && (count >= 0 && (start+count) <= it->horz) && (vert >= 0 && vert < it->vert) ) { /* Locate the rasterline the caller wants to retrieve data from. Make sure it is valid and that we haven't gotten confused. */ rasterline destline; destline = it->linestart[vert]; if(destline) { /* If the buffer they supplied is non-null, copy the data from it and into our rasterline. */ if(src) { memcpy(&destline[start], src, count * sizeof(pixel)); } else err = srl_bogusParamPtr; } else err = srl_bollixed; } else err = srl_outOfBounds; } else err = srl_bogusBuffer; return err; } rasterline PeekRasterLine(pixbuf it, int vert) { /* If you want to examine all the pixels in a pixbuf, there are three ways to do it: iterate through each pixel, row by row, using GetRasterBufPixel on each one. This is miserably slow. Or you can iterate through each row, using GetRasterLine. This is still slow, since it is full of memcpy()s. Or, you can do it the right way: iterate through each row using PeekRasterLine to get direct access to the bits in the row. If you want to copy all of the data out of a pixbuf, use GetRasterLine; you won't save any time by using Peek. Or, if you want to wholesale change the contents of the pixbuf, use SetRasterLine. But if you want to read/modify/write most or all of the pixels in a pixbuf, use PeekRasterLine to get direct access and change the values by hand. The value you get back will either be NULL or a pointer to an array of pixels. If the latter, there will be precisely as many pixels in the array as there are columns in the pixbuf. If you write off the end of the rasterline, undefined things will happen. */ rasterline out = NULL; if(it) { if (vert >= 0 && vert < it->vert) { out = it->linestart[vert]; } } return out; } starfish-1.1/portable/pixels/pixmap.h100600 764 764 5513 7042177111 17340 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. A set of routines used to manage a rudimentary pixmap library. Pixmaps are collections of raster lines, which are arrays of pixels. This lib creates such pixmaps and lets you access them. Normal pixmaps have 32-bit pixels: one 8-bit channel each for red, green, blue, and alpha. */ #ifndef __starfish_pixmaplib__ #define __starfish_pixmaplib__ 0 #include #include "rasterliberrs.h" typedef struct pixbufrec* pixbuf; typedef struct pixel { unsigned char red; unsigned char green; unsigned char blue; unsigned char alpha; } pixel; typedef pixel* rasterline; //Colour Pixel Buffers //Create a new pixbuf with a certain number of columns and rows. pixbuf MakePixBuf(int horz, int vert); //Dispose of an existing pixbuf. srl_result DumpPixBuf(pixbuf it); //Fill this buffer with the specified pixel. srl_result FillPixBuf(pixbuf it, const pixel* src); //Fill all channels in this pixbuf with this value. srl_result GreyFillPixBuf(pixbuf it, unsigned char src); //The following functions return zero if the pixbuf is invalid. //How many pixels wide is one scan line? int GetPixBufWidth(pixbuf it); //And how many rows tall is the buffer? int GetPixBufHeight(pixbuf it); //How many bytes long is one raster line? size_t GetPixBufLineSize(pixbuf it); //Get one pixel from the buffer. srl_result GetPixBufPixel(pixbuf it, int horz, int vert, pixel* dest); //Set one pixel into the buffer. srl_result SetPixBufPixel(pixbuf it, int horz, int vert, const pixel* dest); //Get part of one rasterline from the buffer. It is your responsibility to make sure //your buffer is big enough to hold the entire line. Use GetPixBufLineSize to check. srl_result GetRasterLine(pixbuf it, int start, int count, int vert, rasterline dest); //Put this rasterline into the buffer. Again, your responsibility to make sure your //source buffer is big enough. srl_result SetRasterLine(pixbuf it, int start, int count, int vert, const rasterline dest); //If you want real speed, you have to go direct. Use with caution. //Returns NULL if you ask for a rasterline that doesn't exist. rasterline PeekRasterLine(pixbuf it, int vert); #endif //__starfish_rasterlib__ starfish-1.1/portable/pixels/rasterliberrs.h100600 764 764 2137 7042177111 20724 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. A collection of error codes used throughout the starfish pixel routines */ #ifndef __rasterliberrs__ #define __rasterliberrs__ 0 enum starfishrasterliberrs { srl_noErr = 0, srl_outOfBounds, srl_bogusBuffer, srl_bogusParamPtr, srl_mismatchedSizes, srl_bollixed //data went inconsistent internally }; typedef enum starfishrasterliberrs srl_result; #endif //__rasterliberrs__ starfish-1.1/portable/pixels/starfish-rasterlib.c100600 764 764 2300 7042177111 21634 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. A set of routines used to manage a rudimentary pixmap library. Pixmaps are collections of raster lines, which are arrays of pixels. This lib creates such pixmaps and lets you access them row-at-a-time. Right now, the Starfish rasterlib assumes 32-bit pixels and fixed size buffers. It doesn't do all that much, really... */ #include #include #include "starfish-rasterlib.h" //Hmm. It doesn't appear that the rasterlib itself actually contains any code... starfish-1.1/portable/pixels/starfish-rasterlib.h100600 764 764 2063 7042177111 21647 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The rasterlib combines the pixmap, greymap, and transformation libraries. It is just a convenient "one-stop-shopping" header. */ #ifndef __starfish_rasterlib__ #define __starfish_rasterlib__ 0 #include #include "rasterliberrs.h" #include "pixmap.h" #include "greymap.h" #include "bufferxform.h" #endif //__starfish_rasterlib__ starfish-1.1/portable/starfish-engine.c100600 764 764 34646 7042177111 17650 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. This is the library that does what makes Starfish cool. Starfish textures are multilayered, seamless tiles. This is the main controller for the starfish engine. It doesn't do any direct mathematics to create textures; instead, it asks plug-in generators to do the math. Then it combines the simple, greyscale textures these generators create into complex, colourful, multilayered eye candy. Someday, there will be a way to give Starfish some kind of guidance as to what sort of texture you are looking for: how much contrast you want, how bright the colours should be, whether you prefer pastels or more intense hues. But for now, Starfish makes all of those decisions on its own. Starfish loads up a list of available generators and creates a colour palette. It initializes the output pixmap to black, then iterates through the following process: - Pick a generator at random and ask it for a texture. - Copy this grey texture into a colour scratchbuffer, using two randomly selected (but non-equal) colours from the palette to form a gradient. - 50% of the time, pick a new generator at random and ask it for a new texture. Copy this texture into the scratchbuffer's alpha channel. + 25% of the time, copy the greyscale version of the texture into the scratch buffer's alpha channel. + 25% of the time, invert the greyscale version of the texture and copy it into the scratch buffer's alpha channel. - Lay the scratch buffer on top of the output pixmap, using the scratch buffer's alpha channel to control transparency. - Return to the beginning. The loop ends after a randomly-chosen small number of iterations. I may at some point add an "alpha channel sampling" feature that continues iterating until the output image reaches a certain average opacity level. It recently dawned on me that if I made a few changes to the generators module, I could generate textures pixel-at-a-time instead of layer-at-a-time, allowing me to skip all the intermediate steps involving greybufs and merging and whatnot. This approach is faster and more memory efficient, since I do not have to do big operations with colossal image buffers all the time; I just do the math, one pixel at a time. The original monolithic "Starfish" function still works, but it is now expressed in terms of point-by-point image grabbing internally. */ #include "starfish-engine.h" #include "generators.h" #include "starfish-rasterlib.h" #include "genutils.h" #include #include #include #if TEST_MODE #define MAX_LAYERS 1 #define MIN_LAYERS 1 #else #define MAX_LAYERS 6 #define MIN_LAYERS 2 #endif typedef struct ColourLayerRec { //The image layer, a reference to a layer generator: LayerRef image; //The foreground colour, used for high image values. pixel fore; //The background colour, used for low image values. pixel back; //The mask image. If NULL, we use the image layer as its own mask. LayerRef mask; //If the flag is true, we invert the mask. int invertmask; } ColourLayerRec; typedef struct StarfishTexRec { /* A starfish texture is an array of colour layers. Count must be greater than 0 and less than or equal to MAX_LAYERS. tex[count] and above are undefined. */ int count; int width, height; int cutoff_threshold; GenListRef list; StarfishPalette colours; ColourLayerRec tex[MAX_LAYERS]; } StarfishTexRec; static void RandomPalettePixel(const StarfishPalette* colours, pixel* out); StarfishRef MakeStarfish(int hsize, int vsize, const StarfishPalette* colours) { /* Create a series of layers which we will later use to generate pixel data. These will contain the complete package of settings used to calculate image values. */ StarfishRef out = NULL; int dead = 0; //error flag we set if allocations failed out = (StarfishRef)malloc(sizeof(StarfishTexRec)); if(out) { int ctr; //How many layers are we going to use? out->count = irandge(MIN_LAYERS, MAX_LAYERS); out->width = hsize; out->height = vsize; out->cutoff_threshold = irand(MAX_CHANVAL / 16); //Copy in the colour palette, if we were given one. if(colours) { if(colours->colourcount > 1) { out->colours = *colours; if(out->colours.colourcount >= MAX_PALETTE_ENTRIES) { out->colours.colourcount = MAX_PALETTE_ENTRIES - 1; } } else out->colours.colourcount = 0; } else out->colours.colourcount = 0; //Load up all of the generators we can use. out->list = LoadGenerators(); //Make some texture layers to generate from. if(out->list) { /* Clear out the values in the array before we begin allocating things. This makes recovery a lot easier if we fail midway through the allocation. */ for(ctr = 0; ctr < out->count; ctr++) { out->tex[ctr].image = NULL; out->tex[ctr].mask = NULL; } /* Now allocate random layers to use for the image and mask of this layer. Half the time, we use the image as its own mask. Half the time, we invert the mask. */ for(ctr = 0; ctr < out->count; ctr++) { int genid; #if TEST_MODE genid = TEST_GENERATOR; #else genid = irand(CountGenerators(out->list)); #endif out->tex[ctr].image = MakeLayer(genid, hsize, vsize, out->list); //If we successfully created the image layer, see about creating a mask. //Otherwise, die now. if(!out->tex[ctr].image) { dead = !0; break; } //Flip a coin. If it lands heads-up, create another layer for use as a mask. if(maybe()) { out->tex[ctr].mask = MakeLayer((rand() * CountGenerators(out->list)) / RAND_MAX, hsize, vsize, out->list); } //Flip another coin. If it lands heads-up, set the flag so we invert this layer. out->tex[ctr].invertmask = (maybe()); //Now pick some random colours to use as fore and back of gradients. #if TEST_MODE out->tex[ctr].back.red = out->tex[ctr].back.green = out->tex[ctr].back.blue = MIN_CHANVAL; out->tex[ctr].fore.red = out->tex[ctr].fore.green = out->tex[ctr].fore.blue = MAX_CHANVAL; #else RandomPalettePixel(&out->colours, &out->tex[ctr].back); //The fore and back colours should NEVER be equal. //Keep picking random colours until they don't match. do { RandomPalettePixel(&out->colours, &out->tex[ctr].fore); } while ( out->tex[ctr].fore.red == out->tex[ctr].back.red && out->tex[ctr].fore.green == out->tex[ctr].back.green && out->tex[ctr].fore.blue == out->tex[ctr].back.blue ); #endif } } else dead = (!0); //we failed to load the list of generators /* Did we fail while setting up the layers? If so, throw away any layers we did successfully create. */ if(dead) { //If we have a generator list, unload it. if(out->list) UnloadGenerators(out->list); //Run through the list of colourtexlayers and throw away any grey layers //we managed to allocate. for(ctr = 0; ctr < out->count; ctr++) { if(out->tex[ctr].image) DumpLayer(out->tex[ctr].image); if(out->tex[ctr].mask) DumpLayer(out->tex[ctr].mask); } //Now throw away the out record, so we don't return anything to the caller. free(out); out = NULL; } } return out; } void GetStarfishPixel(int h, int v, StarfishRef texture, pixel* out) { /* Calculate one pixel. We start with a black pixel. Then we loop through all of the layers, calculating each one with its mask. We then merge each layer's resulting pixel onto the out image. Once we're done, we return the merged pixel. We use alpha kind of backwards: high values mean high opacity, low values mean low opacity. */ channelval imageval, maskval; pixel outval; //Start out by initializing the output data. outval.red = outval.green = outval.blue = outval.alpha = 0; //Did we get valid parameters? if(texture && out && h >= 0 && v >= 0 && h < texture->width && v < texture->height) { //All of our parameters check out. int ctr; for(ctr = 0; ctr < texture->count; ctr++) { pixel layerpixel; float interval; ColourLayerRec* layer = &texture->tex[ctr]; //Get the image value for this pixel, for this layer. imageval = GetLayerPixel(h, v, layer->image); #if TEST_MODE maskval = MAX_CHANVAL; #else //Do we have a mask texture? If we do, calculate its value. if(layer->mask) maskval = GetLayerPixel(h, v, layer->mask); else maskval = imageval; //Are we supposed to invert the mask value we got? if(layer->invertmask) maskval = MAX_CHANVAL - maskval; #endif /* Now we are ready. Calculate the image value for this layer. We use the image value as the proportion of the distance between two colours. We calculate this one channel at a time. This results in a smooth gradient of colour from min to max. */ //Calculate the red channel of the pixel. interval = imageval; interval /= CHANNEL_RANGE; interval *= layer->fore.red - layer->back.red; layerpixel.red = interval + layer->back.red; //Next calculate the green channel. interval = imageval; interval /= CHANNEL_RANGE; interval *= layer->fore.green - layer->back.green; layerpixel.green = interval + layer->back.green; //Calculate the blue channel in the same fashion interval = imageval; interval /= CHANNEL_RANGE; interval *= layer->fore.blue - layer->back.blue; layerpixel.blue = interval + layer->back.blue; //The alpha channel is merely the mask value. layerpixel.alpha = maskval; /* The image value for this layer is calculated. But the image is more than just this layer: it is the merged results of all the layers. So now we merge this value with the existing value calculated from the previous layers. We use the alpha channel to determine the proportion of blending. The new layer goes behind the existing layers; we use the existing alpha channel to determine what proportion of the new value shows through. */ //Calculate the red channel of the pixel. outval.red = ( (outval.red * outval.alpha) + (layerpixel.red * (CHANNEL_RANGE - outval.alpha)) ) / (CHANNEL_RANGE); //Next calculate the green channel. outval.green = ( (outval.green * outval.alpha) + (layerpixel.green * (CHANNEL_RANGE - outval.alpha)) ) / (CHANNEL_RANGE); //Calculate the blue channel in the same fashion outval.blue = ( (outval.blue * outval.alpha) + (layerpixel.blue * (CHANNEL_RANGE - outval.alpha)) ) / (CHANNEL_RANGE); /* Add the alpha channels (representing opacity); if the result is greater than 100% opacity, we just stop calculating (since no further layers will produce visible data). */ layerpixel.alpha = layerpixel.alpha * (MAX_CHANVAL - outval.alpha) / CHANNEL_RANGE; if(layerpixel.alpha + outval.alpha + texture->cutoff_threshold >= MAX_CHANVAL) { outval.alpha = MAX_CHANVAL; /* And now end the loop, because we've collected all the data we need. Calculating pixels from any of the deeper layers would just be a waste of time. */ break; } else outval.alpha += layerpixel.alpha; //And that, my friends, is that. } } //Return our modified pixel to the caller. *out = outval; } void DumpStarfish(StarfishRef it) { /* We are done with this starfish image. Throw away all the layers we allocated, and the array we used to keep track of them. */ if(it) { int ctr; //Walk through the array and throw away any layers we loaded. for(ctr = 0; ctr < it->count; ctr++) { if(it->tex[ctr].image) DumpLayer(it->tex[ctr].image); if(it->tex[ctr].mask) DumpLayer(it->tex[ctr].mask); } //Unload the list of generators. if(it->list) UnloadGenerators(it->list); //Throw away our data structure, now we're done with it. free(it); } } /* The Starfish function by itself rolls the above three functions into one step. Use this when you are in an environment with preemptive multitasking (or you just don't care how long it takes) and you want Starfish to create the pixel buffer for you. */ pixbuf Starfish(int horz, int vert, const StarfishPalette* colours) { /* Create a pixel buffer and fill it, using layers of algorithmically-created subtextures. The result, a complex blend of math, gradients, alpha blending, and fractals, will in theory be suitable for a wide variety of decorative purposes. This is basically the same code as MakeStarfish, GetStarfishPixel, and DumpStarfish all rolled together. */ pixbuf out = NULL; pixbuf templayer = NULL; StarfishRef it = NULL; //Create space for the destination texture. out = MakePixBuf(horz, vert); if(out) { //Create a starfish texture. it = MakeStarfish(horz, vert, colours); if(it) { //Now loop through all of the pixels of the scratchbox, filling in each one. int h, v; for(v = 0; v < vert; v++) { for(h = 0; h < horz; h++) { pixel temppixel; GetStarfishPixel(h, v, it, &temppixel); SetPixBufPixel(out, h, v, &temppixel); } } //Now we're done with the starfish texture, so throw it away. DumpStarfish(it); } else { //We couldn't make our starfish - throw the destination pixbuf away. DumpPixBuf(out); out = NULL; } } else { //Could not allocate the output pix buf. Uh oh. } return out; } /* A pair of trivial accessor functions */ int StarfishWidth(StarfishRef texture) { return texture ? texture->width : 0; } int StarfishHeight(StarfishRef texture) { return texture ? texture->height : 0; } static void RandomPalettePixel(const StarfishPalette* colours, pixel* out) { /* Pick a random pixel from this palette. If the palette is empty, create it from random values. */ if(out) { if(colours && colours->colourcount > 1) { int index; index = (rand() * colours->colourcount) / RAND_MAX; *out = colours->colour[index]; } else { out->red = irand(MAX_CHANVAL); out->green = irand(MAX_CHANVAL); out->blue = irand(MAX_CHANVAL); } } } starfish-1.1/portable/starfish-engine.h100600 764 764 5344 7042177111 17626 0ustar msaxmanmsaxman/* Copyright 1999 Mars Saxman All Rights Reserved This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef __starfish_engine__ #define __starfish_engine__ 0 #include "starfish-rasterlib.h" /* If you choose to supply a palette to MakeStarfish, it must be in the following format. While your palette may be longer than MAX_PALETTE_ENTRIES, only the first MAX_PALETTE_ENTRIES records will be used. It is not necessary to allocate more pixel records than you actually plan to use. */ #define MAX_PALETTE_ENTRIES 256 typedef struct StarfishPalette { int colourcount; pixel colour[MAX_PALETTE_ENTRIES]; } StarfishPalette; /* Feed Starfish the parameters you want, and it returns you a brand-new pixel buffer with a seamless, 24-bit texture inside. Yours to keep. h is the horizontal size, v is the vertical size, both in pixels. */ pixbuf Starfish(int hsize, int vsize, const StarfishPalette* colours); /* Create a starfish texture. Then ask for its pixels, using whatever pace and order you want. Once you are done, throw away the texture. This lets you control scheduling yourself, instead of having to spawn off extra threads, and requires far less memory. The StarfishPalette is read-only, and you needn't maintain it after calling MakeStarfish. The engine keeps its own internal copy of the palette. If you pass NULL, the engine uses the full colour spectrum. */ typedef struct StarfishTexRec* StarfishRef; StarfishRef MakeStarfish(int hsize, int vsize, const StarfishPalette* colours); void GetStarfishPixel(int h, int v, StarfishRef texture, pixel* out); void DumpStarfish(StarfishRef it); int StarfishWidth(StarfishRef texture); int StarfishHeight(StarfishRef texture); /* The starfish engine can be run in test mode. In this mode, its output is one single layer, scaled from black to white, of a specific generator. This is useful when generator code isn't working and you don't know exactly why. Set TEST_MODE to 1 if you want this, 0 otherwise. In testmode, the generator number TEST_GENERATOR in the list will be the one executed. There will be no colours */ #define TEST_MODE 0 #define TEST_GENERATOR 5 #endif //__starfish_engine__ starfish-1.1/unix/ 42700 764 764 0 7215777076 13461 5ustar msaxmanmsaxmanstarfish-1.1/unix/.AppleDouble/ 42700 764 764 0 7042177117 15717 5ustar msaxmanmsaxmanstarfish-1.1/unix/.AppleDouble/.Parent100700 764 764 1115 7042177117 17245 0ustar msaxmanmsaxmanMVU - unix׍!starfish-1.1/unix/.AppleDouble/Icon 100600 764 764 1553 7042177117 16650 0ustar msaxmanmsaxmanMVU - Icon ^^iconMACS@Icon :pmer%6%6%(starfish-1.1/unix/.AppleDouble/Makefile100600 764 764 4051 7042177117 17454 0ustar msaxmanmsaxmanMVU - Makefile5zTEXTR*ch avvfMakefilekTEXTR*ch@TEXTR*ch@sH Monaco`c, I0 A_e_e崆R*chHH(FG(HH(d'hMonaco  Helvetica ConfidentialHvvf u5fMPSRMWBB2BBST>Z s@starfish-1.1/unix/.AppleDouble/starfish100600 764 764 1115 7042177117 17560 0ustar msaxmanmsaxmanMVU - starfishzBINAUNIXstarfish-1.1/unix/.AppleDouble/starfish.c100600 764 764 1115 7042177117 20001 0ustar msaxmanmsaxmanMV U - starfish.c zBINAUNIXastarfish-1.1/unix/.AppleDouble/zut-1.5.tar.gz100600 764 764 1115 7042177117 20264 0ustar msaxmanmsaxmanMVU - zut-1.5.tar.gz׍׍TEXT????starfish-1.1/unix/.AppleDouble/zut100600 764 764 1115 7042177117 16557 0ustar msaxmanmsaxmanMVU - zut{{TEXTUNIXstarfish-1.1/unix/starfish.c100600 764 764 26607 7216004555 15562 0ustar msaxmanmsaxman/* Starfish A graphic texture generator. Copyright 1999-2000 Mars Saxman - All Rights Reserved This is the Unix version. It uses the starfish engine to create colourful and exotic desktop patterns and apply them to the X11 desktop at user-selected intervals. The starfish rendering code can be found in the 'portable' directory. starfish-engine.h contains the main control routines. Starfish can be run immediately as a command, or it can be launched as a daemon, in which case it will fork itself off into the background and produce patterns at regular intervals. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include "starfish-engine.h" #include "starfish-rasterlib.h" #include "setdesktop.h" #include "makepng.h" #include "genutils.h" void usage(void) { puts( "xstarfish 1.1\n" "Copyright (c) 1999-2000 Mars Saxman & others\n" "A simple hack to create tiled root window backgrounds.\n" "Usage: xstarfish [options...]\n" "Options include:\n" "-h,--help,--usage:\n" " Print the message you're reading now\n" "-d,--daemon: Fork off into the background. This offers two arguments.\n" " The first argument is an interval between patterns;\n" " Starfish will generate a pattern, sleep that many\n" " seconds, then repeat. The second argument specifies the\n" " units for the sleep interval: seconds, minutes, hours,\n" " days, weeks. Seconds are the default interval.\n" "-v/--version: current version of this program.\n" "-g/--geometry: size of desired image in WxH format. If you omit the height,\n" " a square pattern WxW will be generated.\n" "-o,--outfile: specify an output file. If you use this option,\n" " starfish will write a png file instead of setting the X11\n" " desktop.\n" "-s,--size: An approximate size in English. Valid size arguments are\n" " small, medium, large, full, and random. Full size creates\n" " patterns the exact size of your display's default monitor.\n" " Small, medium, and large are randomly sizes at appropriate\n" " fractions of the default monitor size. And random can be\n" " any size from 64x64 up to the whole monitor. Size always\n" " overrides geometry.\n" "-r,--random: specify seed for rand() call - for debugging.\n" "--display: one argument, name of the desired target display.\n" ); } void CalcRandomSize(int* width, int* height, const char* sizename, const char* displayname) { /* Figure out how big the default monitor is. Then come up with some reasonable size values based on that. Return them. */ int screen; int minH, maxH, minV, maxV; Display* display = XOpenDisplay(displayname); if(display) { screen = DefaultScreen(display); maxH = DisplayWidth(display, screen); maxV = DisplayHeight(display, screen); } else { /* In the case that someone tries to run this without X, we fabricate numbers based on the smallest common display. */ maxH = 640; maxV = 480; } minV = minH = 64; if(!strcmp(sizename, "full")) { minH = maxH; minV = maxV; } else if(!strcmp(sizename, "small")) { maxH /= 6; maxV /= 6; } else if(!strcmp(sizename, "medium")) { minH = maxH / 6; minV = maxV / 6; maxH /= 3; maxV /= 3; } else if(!strcmp(sizename, "large")) { minH = maxH / 3; minV = maxV / 3; maxH /= 2; maxV /= 2; } *width = irandge(minH, maxH); *height = irandge(minV, maxV); if(display) XCloseDisplay(display); } void ExtractGeometry(const char* geostr, int* width, int* height) { /* Turn the WWxHH string into width & height values. If there's no 'x', we use equal width and height. This is a cheap little string parser. */ *width = 0; *height = 0; while(isdigit(*geostr)) { *width *= 10; *width += *geostr - '0'; geostr++; } /* Is the next character an 'x' or 'X'? If yes, that means we have a height value following. If no, that means we have only a single value (width) which we will now copy into height. */ if(*geostr == 'x' || *geostr == 'X') { geostr++; while(isdigit(*geostr)) { *height *= 10; *height += *geostr - '0'; geostr++; } } else *height = *width; /* Is the next character null? If so, we ate our entire string and things are cool. If not, there's crap on the command line. */ if(*geostr) fprintf(stderr, "xstarfish: The geometry option is broken - \"%s\"\n", geostr); } int main(int argc, char** argv) { /* Default behaviour is non-daemon. Starfish simply starts up, does its thing, and quits. If daemon is specified but no time is given, Starfish uses 20 minutes interval. Default width and height are 256 pixels. Though the starfish engine supports colour palettes, there is currently no way to access that feature through the command line. mjs 13/12/2k - the following comment appeared in the original source but I never implemented the functionality it describes. It is unlikely it ever will get implemented but it was kind of a neat idea: If no outfile is specified, Starfish checks to see if isatty(stdout). If yes, it tries to set the X root window's background pixmap with its results. If no, it writes its results to stdout in either PPM or raw format (I haven't decided which). If an outfile is specified, Starfish dumps its output to the file in whatever pixel format is easiest to write. I may someday add a fancy algorithm that guesses what type of image to write by the file extension (foo.png would get written in PNG format, foo.jpeg in JPEG format...) but that sounds too "tricky". Probably will just use pixmap. */ /* PD 13/12/2000 The -o (--outfile) option now works, and writes a png file (no matter what the extension is). Needs libpng to build, but this is included with most distros. What about isatty(stdout)? Or checking that the extension is .png and writing raw bitmap data otherwise? */ int ctr; int width, height; int sleeptime; int daemon; StarfishRef texture; const char* displayName; const char* sizeName; const char* filename; char haveOutfile; /* Set up our defaults. These may be overridden by command line parameters. */ width = height = 256; sleeptime = 20 * 60; /* measured in seconds */ daemon = 0; displayName = NULL; sizeName = NULL; filename = NULL; haveOutfile = 0; srand(time(0)); /* we may override this when parsing the arguments */ for(ctr = 1; ctr < argc; ctr++) { if(argv[ctr][0] != '-') { fprintf(stderr, "xstarfish: parameter \"%s\" is bogus.\n", argv[ctr]); return 1; } if(!strcmp(argv[ctr], "-d") || !strcmp(argv[ctr], "--daemon")) { /* If the next parameter is numeric, grab it. We'll use it as our sleep time. Otherwise, we'll leave the default in place. */ if(ctr + 1 < argc && isdigit(argv[ctr + 1][0])) { sleeptime = atoi(argv[++ctr]); } daemon = 1; /* if we have more parameters, and the next one does not begin with -, we treat it as a units specifier */ if(ctr + 1 < argc && argv[ctr + 1][0] != '-') { ctr++; if(!strcmp(argv[ctr], "minutes")) sleeptime *= 60; else if(!strcmp(argv[ctr], "minute")) sleeptime *= 60; else if(!strcmp(argv[ctr], "hours")) sleeptime *= 3600; else if(!strcmp(argv[ctr], "hour")) sleeptime *= 3600; else if(!strcmp(argv[ctr], "days")) sleeptime *= 86400; else if(!strcmp(argv[ctr], "day")) sleeptime *= 86400; else if(!strcmp(argv[ctr], "weeks")) sleeptime *= 604800; else if(!strcmp(argv[ctr], "week")) sleeptime *= 604800; else if(!strcmp(argv[ctr], "seconds")) sleeptime *= 1; else if(!strcmp(argv[ctr], "second")) sleeptime *= 1; else { fprintf(stderr, "xstarfish: parameter \"%s\" is bogus.\n", argv[ctr]); return 1; } } } else if(!strcmp(argv[ctr], "-g") || !strcmp(argv[ctr], "--geometry")) { /* Parse a size string. The format is always WWxHH */ if(ctr + 1 < argc) ExtractGeometry(argv[++ctr], &width, &height); else fprintf(stderr, "xstarfish: geometry value is missing"); } else if(!strcmp(argv[ctr], "-o") || !strcmp(argv[ctr], "--outfile")) { /* The next parameter is an output file name. Grab it. */ if(ctr + 1 < argc) { filename = argv[++ctr]; haveOutfile = 1; } else { fprintf(stderr, "xstarfish: %s requires an argument.\n", argv[ctr]); } } else if(!strcmp(argv[ctr], "-r") || !strcmp(argv[ctr], "--random")) { /* If the next parameter is numeric, grab it. */ if(ctr + 1 < argc && isdigit(argv[ctr + 1][0])) { srand(atoi(argv[++ctr])); } else { fprintf(stderr, "xstarfish: \"-r\" requires an argument.\n"); } } else if(!strcmp(argv[ctr], "-h") || !strcmp(argv[ctr], "--usage") || !strcmp(argv[ctr], "--help")) { usage(); return 0; } else if(!strcmp(argv[ctr], "-v") || !strcmp(argv[ctr], "--version")) { fprintf(stderr, "xstarfish 1.1\n" "Copyright 1999-2000 Mars Saxman & others\n" "\n" "This program comes with NO WARRANTY, to the extent permitted by law.\n" "You may redistribute copies of this program under the terms of the\n" "GNU General Public License.\n" "For more information, see the file named COPYING or visit\n" "http://www.gnu.org/copyleft/gpl.html.\n" ); return 0; } else if(!strcmp(argv[ctr], "--display")) { ctr++; if(ctr < argc) displayName = argv[ctr]; } else if(!strcmp(argv[ctr], "-s") || !strcmp(argv[ctr], "--size")) { ctr++; if(ctr < argc) { if ( strcmp(argv[ctr], "small") && strcmp(argv[ctr], "medium") && strcmp(argv[ctr], "large") && strcmp(argv[ctr], "full") && strcmp(argv[ctr], "random") ) { fprintf(stderr, "xstarfish: size \"%s\" is bogus.\n", argv[ctr]); } else { sizeName = argv[ctr]; } } else { fprintf(stderr, "xstarfish: \"-s\" requires an argument.\n"); } } } /* This line relies on conditional evaluation. IIRC, that's in K&R, so it should be alright... */ if(daemon && fork()) return 0; /* Do the thing that makes Starfish worth installing. Create a seamlessly tiled, anti-aliased image. Then do with it whatever the user requested. If called with --output, we write the image to disk; otherwise, we set it as the X11 root background. */ //Make a starfish texture description we can pull pixels from. do { if(sizeName) CalcRandomSize(&width, &height, sizeName, displayName); texture = MakeStarfish(width, height, NULL); if(texture) { if(haveOutfile) MakePNGFile(texture, filename); else SetXDesktop(texture, displayName); DumpStarfish(texture); } else { fprintf(stderr, "xstarfish: was not able to create texture\n"); return 1; } if(daemon){sleep(sleeptime);} } while(daemon); return 0; } starfish-1.1/unix/setdesktop.o100664 764 764 15660 7042177117 16151 0ustar msaxmanmsaxmanELF4( U} }M ًU&M Ut&ÉUWVSM J(Xˉ]EE ;E|vEE;|PEURbEPEUЍPPBEPEUЍPP"UMʋ=M"O05u]u"^8]M]u"F4ÈEEGP(UE e[^_ÐUWVSEt&E ;E|vM J(xω}E EE;|PEUREáPEUЍPP&ơPEUЍPPMMM=}}f#_0=}}f#w85f#F4f<EEIt& e[^_ÍvU WVSEE ;E|vM J(xω}E EE;|oUUUM]ff]usf ف]usff f<EE놉Ke[^_ÍvUWVSEE ;E|vM J(xω}E EE;|PEUReáPEUЍPPFơPEUЍPP'MM=}}#_0=}}#w85#F4<<EENt&e[^_USM J(Xˉ]&E ;E|VM J(Xˉ]E PEPEP E륐t&]ÍvU WVSEE ;E|M J(xω}E E&E;|SvUUM]]us ]us ߉<EEce[^_ÍvUÍvU EE;|rEt&E;|Sv} uME EPEPEPEPEUEEUEEUEE릍EÐUPEPRERE PEPE}t/EPRERjjjjEPPEPEP(UUEPE PEP} E}t4EPE PEP EPEPE PEPÐUSEx,u* 9P(uEPU:PE}uh B,t) tvtK tfEx0u"x4ux8u EE`}t EEG&x0u%x4ux8u EEt&EPPEP7 PjEP]Ӄ U=uh*P,;t*P,RPh` Xt&x0tx4t x8uhP0U}u#vEEաP4U}u#vEEաP8U}u#vEEաx,tEx, t:x,t/x,t$P,Rh &1ÉUSE ʉT$=t:=t1=t(= tPh@]&=uEЅ}]}uL=u EtE= uEtEU)Ӊ]E EEPEEPPPPEPjj ʉT$R ʉT(RP(Pt+t&EPPPP ]ÐUE P=uhv ʉT$ ʉT ʉT,EPEPEPCP01.01starfish: could not allocate input bufferzut: XCreateImage failedstarfish: asked for %i bits per pixel, got %i instead starfish: could not get an RGB pixmapstarfish: image has %i bits per pixel, only supported values are 8, 16, 24 (hack) and 32 starfish: Error: bits_per_rgb is %i, only 8, 16, 24 (hack) or 32 is supported. starfish: Failed to open display GCC: (GNU) egcs-2.91.66 19990314/Linux (egcs-1.1.2 release).symtab.strtab.shstrtab.text.rel.text.data.bss.note.rodata.comment@ !  +< 1@ 6@ <`  D"=_Md0  #2+4;AJT_Lp`08l '[A\hup(  setdesktop.cgcc2_compiled.imagecomposeputlinegeneric8widthredshiftblueshiftgreenshiftputlinegeneric16putline16RGB565putlinegeneric32putlinegeneric24memcpyputline32RGB888putline_donothingfill_bufferheightGetStarfishPixelXCreatePixmapFromImagedepthXCreatePixmapgcXPutImageXSetWindowBackgroundImageXSetWindowBackgroundPixmapXFreePixmapXClearWindowfillimagemallocputsinitimagenbitsprintfmainloopdisplayscreenXCreateImagerootwinSetXDesktopXOpenDisplayStarfishWidthStarfishHeightXCloseDisplay> D |     1 q w      /    Q W y     @ F q w       :ft !"    (/ ;$NS%b        &6 =Ux % ' '(   (    J  Q  ]             (7 *= +Y '_ 'h 'q 'z ' '  ( '  ' ' ' '( 2 $C 'I O  ] *c + * + * ,    - * / * * ! (1 *= +B *H +d i *o + - * +  0  1  * 2starfish-1.1/unix/setdesktop.c100644 764 764 7451 7216001061 16075 0ustar msaxmanmsaxman/* Starfish X desktop setter Copyright (c) 2000 Mars Saxman Portions derived from Zut 1.5 and are copyright (C) 1999 Sebastien Loisel Thanks to Mr. Loisel for providing his code as free software. Thanks to Adrian Bridgett for fixing many bugs. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include "starfish-engine.h" Display *display; int screen,depth,bpp,width,height; Window rootwin; GC gc; XImage *image=0; int compose(int i, int shift) { return (shift<0) ? (i>>(-shift)) : (i<red_mask; redshift=-8; while(x) { x/=2; redshift++; } x=image->green_mask; greenshift=-8; while(x) { x/=2; greenshift++; } x=image->blue_mask; blueshift=-8; while(x) { x/=2; blueshift++; } for (y=0; yred_mask; value += compose(pixel.green,greenshift) & image->green_mask; value += compose(pixel.blue,blueshift) & image->blue_mask; XPutPixel(image,x,y,value); } } } void XSetWindowBackgroundImage(Display* display, Drawable window, XImage* image) { Pixmap out; if (out = XCreatePixmap(display, window, image->width, image->height, depth)) { XPutImage(display, out, gc, image, 0,0, 0,0, image->width, image->height); XSetWindowBackgroundPixmap(display, window, out); XFreePixmap(display, out); //Force the entire window to redraw itself. This shows our pixmap. XClearWindow(display, window); } } void mainloop(StarfishRef tex) { char *buf; int bpl; int n_pmf; int i; XPixmapFormatValues * pmf; pmf = XListPixmapFormats (display, &n_pmf); if (pmf) { for (i = 0; i < n_pmf; i++) { if (pmf[i].depth == depth) { int pad, pad_bytes; bpp = pmf[i].bits_per_pixel; bpl = width * bpp / 8; pad = pmf[i].scanline_pad; pad_bytes = pad / 8; /* make bpl a whole multiple of pad/8 */ bpl = (bpl + pad_bytes - 1) & ~(pad_bytes - 1); buf=malloc(height*bpl); image=XCreateImage(display,DefaultVisual(display,screen), depth, ZPixmap,0,buf,width,height,pad,bpl); if(!image) { puts("starfish: XCreateImage failed"); return; } break; } } XFree ((char *) pmf); } if (! XInitImage(image)) return; fillimage(tex); XSetWindowBackgroundImage(display, rootwin, image); XDestroyImage(image); } void SetXDesktop(StarfishRef tex, const char* displayname) { if (! (display = XOpenDisplay(displayname))) { fprintf(stderr, "xstarfish: Failed to open display\n"); return; } screen = DefaultScreen(display); depth = DefaultDepth(display, screen); rootwin = RootWindow(display, screen); gc=DefaultGC(display,screen); width = StarfishWidth(tex); height = StarfishHeight(tex); mainloop(tex); XCloseDisplay(display); return; } starfish-1.1/unix/setdesktop.h100664 764 764 1673 7042177117 16121 0ustar msaxmanmsaxman/* Starfish desktop setter Copyright (c) 1999-2000 Mars Saxman - All Rights Reserved This is what puts a Starfish texture onto the root window's wallpaper. Which is what the whole point of the program is anyway. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ void SetXDesktop(StarfishRef tex, const char* display); starfish-1.1/unix/makepng.c100664 764 764 7250 7216000667 15344 0ustar msaxmanmsaxman/* Copyright 2000 Philip Derrin All Rights Reserved This file is part of xstarfish This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "starfish-engine.h" /* takes a StarfishRef and returns a ptr to a 24-bit RGBA pixmap */ png_byte** PixFromStarfishTex(StarfishRef tex); /* frees a pixmap created by the above function */ void DestroyPix(png_byte** pixmap, int height); void MakePNGFile(StarfishRef tex, const char* filename) { FILE* theFile; int width, height, x, y; png_byte** pixmap = NULL; png_infop theInfoPtr = NULL; png_structp theWritePtr = NULL; /* create the file */ theFile = fopen(filename, "wb"); if(!theFile) { fprintf(stderr, "xstarfish: could not open output file.\n"); return; } /* turn the StarfishRef into something useable */ width = StarfishWidth(tex); height = StarfishHeight(tex); pixmap = PixFromStarfishTex(tex); /* set up libpng */ if(pixmap) { theWritePtr = png_create_write_struct (PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); if(!theWritePtr) { fprintf(stderr, "xstarfish: could not allocate png write struct\n"); return; } } if(theWritePtr) { theInfoPtr = png_create_info_struct(theWritePtr); if(!theInfoPtr) { fprintf(stderr, "xstarfish: could not allocate png info struct\n"); png_destroy_write_struct(&theWritePtr, (png_infopp)NULL); return; } } if(theInfoPtr) { /* set up the png error handling. */ if (setjmp(theWritePtr->jmpbuf)) { png_destroy_write_struct(&theWritePtr, &theInfoPtr); fclose(theFile); fprintf(stderr, "xstarfish: there was an error writing the PNG file.\n"); return; } /* tell libpng about the output file. */ png_init_io(theWritePtr, theFile); /* set up the image info... */ png_set_IHDR(theWritePtr, theInfoPtr, width, height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); /* ... and write it to the file. */ png_write_info(theWritePtr, theInfoPtr); /* now write the image data. */ png_write_image(theWritePtr, pixmap); /* clean up after libpng */ png_write_end(theWritePtr, NULL); png_destroy_write_struct(&theWritePtr, &theInfoPtr); } /* clean up our stuff */ DestroyPix(pixmap, height); fclose(theFile); return; } png_byte** PixFromStarfishTex(StarfishRef tex) { png_byte** pixmap; int height = StarfishHeight(tex), width = StarfishWidth(tex); int curRow, curPixel; pixel thePixel; pixmap = malloc(height * sizeof(png_byte*)); if( pixmap ) { for(curRow = 0; curRow < height; curRow++) { pixmap[curRow] = malloc(width * sizeof(png_byte) * 3); for(curPixel = 0; curPixel < width; curPixel++) { GetStarfishPixel(curPixel, curRow, tex, &thePixel); pixmap[curRow][curPixel * 3] = thePixel.red; pixmap[curRow][curPixel * 3 + 1] = thePixel.green; pixmap[curRow][curPixel * 3 + 2] = thePixel.blue; } } } return pixmap; } void DestroyPix(png_byte** pixmap, int height) { int curRow; for(curRow = 0; curRow < height; curRow++) free(pixmap[curRow]); free(pixmap); } starfish-1.1/unix/makepng.h100664 764 764 1473 7215777076 15370 0ustar msaxmanmsaxman/* Copyright 2000 Philip Derrin All Rights Reserved This file is part of xstarfish This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ void MakePNGFile(StarfishRef tex, const char* filename); starfish-1.1/Makefile100600 764 764 3067 7215777076 14241 0ustar msaxmanmsaxman# this is the shortest way to get the fastest code (on a K6/2 400) # seems to work fairly well on a P3-300 too CC = cc -O3 -funroll-all-loops -I ./portable -I ./portable/pixels/ \ -I ./portable/generators/ -I ./unix/ -g -D__USE_EXTERN_INLINES LDFLAGS = -L/usr/X11R6/lib -lm -lX11 -lpng VPATH = ./portable/:./portable/pixels/:./portable/generators/:./unix/ OBJECTS = starfish-engine.o generators.o genutils.o\ bufferxform.o greymap.o pixmap.o starfish-rasterlib.o \ coswave-gen.o spinflake-gen.o rangefrac-gen.o \ bubble-gen.o flatwave-gen.o setdesktop.o makepng.o starfish: $(OBJECTS) starfish-engine.o: starfish-engine.c starfish-engine.h generators.h \ starfish-rasterlib.h setdesktop.o: setdesktop.c genutils.h setdesktop.h makepng.o: makepng.c makepng.h starfish-engine.h generators.o: generators.c generators.h greymap.h \ coswave-gen.h spinflake-gen.h rangefrac-gen.h \ bubble-gen.h flatwave-gen.h genutils.o: genutils.c genutils.h bufferxform.o: bufferxform.c bufferxform.h pixmap.h greymap.h greymap.o: greymap.c greymap.h pixmap.o: pixmap.c pixmap.h starfish-rasterlib.h starfish-rasterlib.o: starfish-rasterlib.c starfish-rasterlib.h \ rasterliberrs.h pixmap.h greymap.h bufferxform.h coswave-gen.o: coswave-gen.c coswave-gen.h genutils.h spinflake-gen.o: spinflake-gen.c spinflake-gen.h genutils.h rangefrac-gen.o: rangefrac-gen.c rangefrac-gen.h genutils.h bubble-gen.o: bubble-gen.c bubble-gen.h genutils.h flatwave-gen.o: flatwave-gen.c flatwave-gen.h genutils.h clean: rm -f $(OBJECTS) starfish install: cp ./starfish /usr/local/bin/xstarfish starfish-1.1/COPYING100600 764 764 43130 7042177140 13627 0ustar msaxmanmsaxman GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. starfish-1.1/INSTALL100600 764 764 1416 7042200202 13570 0ustar msaxmanmsaxman(1) Read the README file if you want to find out how it works. (2) Type "make" to build the program. (3) If the program built successfully, type "make install" to copy the binary into /usr/local/bin/. This must be done as root. (4) If you like starfish and want it to run automatically, add a line that invokes Starfish with your favourite options to your ~/.Xsession file. This way starfish will be run every time you enter X. Have fun! This is known to build under linux using gcc. It uses no OS-specific calls or features that I know of, and should build & run properly on any machine with access to Xlib and a copy of fork() in its kernel. If it doesn't run on your unix, please let me know and I'll endeavour to fix whatever I did wrong. *** starfish-1.1/README100600 764 764 7750 7216001664 13444 0ustar msaxmanmsaxmanxstarfish: X wallpaper generator version 1.0, released 28 August 2000 Please read the COPYING file for information on the distribution terms for this program and its source code. Please read the BUGS file for information on problems known to exist with this and other releases of starfish. This software comes with ABSOLUTELY NO WARRANTY. Use it at your OWN RISK. I am NOT responsible for any damage it may cause. written by: Mars Saxman with help from: Sebastien Loisel's 'zut' Adrian Bridgett Philip Derrin "other peoples" current web site is: http://www.redplanetsw.com/starfish/ latest release lives at: ftp://ftp.redplanetsw.com/pub/marssoft/starfish/ Nomenclature: "Starfish", with capitals, is a wallpaper generator program. "xstarfish" is the unix port of this program. Neither of these entities has any connection to "starfish", the xscreensaver hack. I regret the confusion. Description: Starfish generates colourful, tiled images using random numbers fed through mathematical functions. It does not use source image files, so it can generate its images nearly forever without running out of material. Once it has created an image, Starfish applies it to the root window of your display as the background pixmap. Since Starfish images are seamlessly tiled, the pixmap will wrap around forming a "wallpaper" effect behind your windows. This allows you to customize your desktop, as often as you wish, with a new look and without much work. There is no GUI control panel, but Starfish is quite simple to control on a command line. There are not many options. In fact you can run Starfish without any command line options at all: xstarfish This will generate a 256 pixel by 256 pixel wallpaper pattern. If you don't like it, simply run Starfish again and it will replace the old pattern. Perhaps you have an older machine that runs slowly, or you don't like big bold patterns. You can instruct Starfish to create a smaller-than-normal pattern: xstarfish --size small Valid sizes are small, medium, large, and full. These sizes are all relative to the size of your screen, and they are all slightly randomized. While two "medium" patterns will be roughly similar, they are unlikely to come out exactly the same. "full" size, however, is always exactly the same size as your default screen. If you really don't care how big the patterns are and you just want variety, use xstarfish --size random While Starfish will happily create a new desktop pattern any time you ask for one, the ultimate lazy person's solution is to run Starfish in "daemon mode". In this mode, Starfish will create patterns automatically at a time interval you determine. Perhaps you want a new pattern every day: xstarfish --daemon 1 day Or you are a real graphics junkie and you want Starfish to spit out patterns more rapidly: xstarfish --daemon 30 seconds Recognized time units are days, weeks, seconds, and minutes. When you run Starfish in daemon mode, it will appear to quit immediately, taking you back to the command line. This is an illusion; Starfish has merely put itself in the background and will continue to create new patterns indefinitely. You can shut it down with the standard "killall" command, like this: killall xstarfish Finally, you can direct Starfish to save its output as a PNG file instead of applying it to the X root window: xstarfish --outfile wallpaper.png These are the basics. For a complete listing of Starfish command line options, type xstarfish --usage This will print out a list of Starfish's options and what they do, but will not create a new pattern. The MacOS Version: Starfish was originally written for the MacOS. The Mac source code is not included in this package, but is available at the Starfish web site on redplanetsw.com. Mac binaries are also available there. Copyright (c) 1999,2000 by Mars Saxman. Copyright (c) 1998 of the bits taken from zut by Sebastien Loisel. Copyright (c) 2000 (makepng.c) by Philip Derrin. starfish-1.1/TODO100600 764 764 546 7216001733 13225 0ustar msaxmanmsaxman- add control over colour palette used; support for this is already present in the generator code but there is no access to it in the unix UI. - add more cool texture algorithms - add 8-bit display support - change to use dithering in 16 bit mode - support more than the default screen on multiscreen displays - GUI front end like the Mac version has starfish-1.1/debian/ 42775 764 764 0 7152641003 13710 5ustar msaxmanmsaxmanstarfish-1.1/debian/changelog100664 764 764 3133 7152641003 15655 0ustar msaxmanmsaxmanstarfish (1.0.b1-6) unstable; urgency=low * fix several bugs for 24bit mode. ripped out all the junk and cleaned up what was left - should work everywhere (not sure if it's endian-clean) (closes: #64507) * added -r option to seed the random number generator for debugging * replaces sqrt(powf(x,2)+powf(y,2)) with hypotf(x,y) since it's stacks faster (17% in at least one case) * TODO: the argument handling needs rewriting using Getopt -- Adrian Bridgett Tue, 4 Jul 2000 20:24:56 +0100 starfish (1.0.b1-5) unstable; urgency=low * Add manpage (closes: #64423) -- Adrian Bridgett Sun, 28 May 2000 20:04:17 +0100 starfish (1.0.b1-4) unstable; urgency=low * X windows -> X in package description (thanks to Branden Robinson) -- Adrian Bridgett Tue, 25 Apr 2000 21:53:46 +0100 starfish (1.0.b1-3) unstable; urgency=low * fix thinko on "-s" fix * fix final (I hope) memory leak * renamed program (but not yet package) to xstarfish to avoid clash with xscreensaver (thanks to Owen Cameron ) -- Adrian Bridgett Wed, 19 Apr 2000 18:06:46 +0100 starfish (1.0.b1-2) unstable; urgency=low * fixed memory leak * doesn't segfault if passsed "-s" last -- Adrian Bridgett Tue, 18 Apr 2000 20:00:20 +0100 starfish (1.0.b1-1) unstable; urgency=low * initial release. -- Adrian Bridgett Wed, 12 Apr 2000 22:50:27 +0100 Local variables: mode: debian-changelog add-log-mailing-address: "bridgett@debian.org" End: starfish-1.1/debian/control100664 764 764 723 7152641003 15370 0ustar msaxmanmsaxmanSource: starfish Section: games Priority: optional Maintainer: Adrian Bridgett Standards-Version: 3.1.1.0 Package: starfish Architecture: any Depends: ${shlibs:Depends} Description: X wallpaper generator. Starfish generates colourful, tiled images for your background using random numbers fed through mathematical functions. It does not use source image files, so it can generate its images nearly forever without running out of material. starfish-1.1/debian/copyright100664 764 764 270 7152641003 15715 0ustar msaxmanmsaxmanstarfish (c) Mars Saxman released under the GPL. Packaged by Adrian Bridgett from sources obtained at http://www.redplanetsw.com/starfish starfish-1.1/debian/rules100664 764 764 1557 7152641003 15070 0ustar msaxmanmsaxman#!/usr/bin/make -f # This script uses debhelper by Joey Hess export DH_VERBOSE=1 export DH_COMPAT=2 DEB=debian/starfish build: build-stamp build-stamp: dh_testdir $(MAKE) LOCAL_LDFLAGS=-g touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp -$(MAKE) -i clean dh_clean install: build dh_testdir dh_testroot dh_clean -k dh_installdirs binary-indep: build install binary-arch: build install # dh_testversion 2 dh_testdir dh_testroot dh_installdebconf dh_installdirs usr/bin # move files into $(DEB) cp starfish $(DEB)/usr/bin/xstarfish # dh_link src dest src dest... dh_installdocs README TODO dh_installmenu dh_installmanpages dh_installchangelogs dh_strip dh_compress dh_fixperms dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary starfish-1.1/debian/menu100664 764 764 163 7152641003 14652 0ustar msaxmanmsaxman?package(starfish):command="/usr/bin/starfish" needs="X11" \ section="Games/Toys" title="Starfish" starfish-1.1/debian/TODO100664 764 764 65 7152641003 14434 0ustar msaxmanmsaxmanuse getopts - the argument handling code is horrible starfish-1.1/debian/xstarfish.1100664 764 764 3350 7152641003 16101 0ustar msaxmanmsaxman.TH XSTARFISH 6 .\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection .\" other parms are allowed: see man(7), man(1) .SH NAME xstarfish \- tiled root window wallpaper generator .SH SYNOPSIS .B xstarfish [ .I options ] .SH "DESCRIPTION" XStarfish generates colourful, tiled images using random numbers fed through mathematical functions and draws them on the background of your desktop. It does not use source image files, so it can generate its images nearly forever without running out of material. .SH OPTIONS .TP \fB-h\fR, \fB--usage\fR Print the message you're reading now .TP \fB-v\fR, \fB--version\fR Current version of the program .TP \fB-d\fR, \fB--daemon\fI INTERVAL\fR [\fIUNITS\fR] Fork off into the background. XStarfish will generate a pattern, sleep for \fIINTERVAL UNITS\fR, then repeat. Valid units are: \fIseconds\fR, \fIminutes\fR, \fIhours\fR, \fIdays\fR, \fIweeks\fR. Seconds are the default interval. .TP \fB--display\fI DISPLAY\fR Name of the target display .TP \fB-g\fR, \fB--geometry\fI W\fR[x\fIH]\fR Size of desired image. If you omit the height, a square pattern WxW will be generated. .TP \fB-s\fR, \fB--size\fI SIZE\fR An approximate size in English. Valid size arguments are \fIsmall\fR, \fImedium\fR, \fIlarge\fR, \fIfull\fR, and \fIrandom\fR. \fIFull\fR size creates patterns the exact size of your display's default monitor. \fISmall\fR, \fImedium\fR, and \fIlarge\fR are randomly sizes at appropriate fractions of the default monitor size. \fIRandom\fR can be any size from 64x64 up to the whole monitor. Size always overrides geometry. .TP \fB-r\fR, \fB--random\fI SEED\fR Seed for rand() call - for debugging purposes .PP .SH NOTES The default size is 256x256. .SH AUTHOR Mars Saxman starfish-1.1/.AppleDouble/ 42775 764 764 0 7200475146 14747 5ustar msaxmanmsaxmanstarfish-1.1/.AppleDouble/.Parent100664 764 764 1115 7200475146 16272 0ustar msaxmanmsaxmanMVU - starfish-1.0.b3<@