Esempio n. 1
0
// Executes a linear mouse movement animation. It can be a simple cursor
// move or a drag depending on what is passed to `type`.
static
void
mouse_animate(
	      CGEventType type,
	      CGMouseButton button,
	      CGPoint start_point,
	      CGPoint end_point,
	      double duration
	      )
{
  CFDateRef current_time = NULL;
  CGPoint current_point  = start_point;
  double     xstep = (end_point.x - start_point.x) / (duration * FPS);
  double     ystep = (end_point.y - start_point.y) / (duration * FPS);
  CFDateRef  start = NOW;
  double remaining = 0.0;

  while (!CLOSE_ENOUGH(current_point, end_point)) {
    remaining  = end_point.x - current_point.x;
    current_point.x += abs(xstep) > abs(remaining) ? remaining : xstep;

    remaining  = end_point.y - current_point.y;
    current_point.y += abs(ystep) > abs(remaining) ? remaining : ystep;

    POSTRELEASE(NEW_EVENT(type, current_point, button));

    mouse_sleep(1);
    current_time = NOW;

    // this is a safety
    if (CFDateGetTimeIntervalSinceDate(NOW, start) > (duration + 1))
      break;

    RELEASE(current_time);
    current_time = NULL;

    current_point = mouse_current_position();
  }

  RELEASE(start);
  if (current_time)
    RELEASE(current_time);
}
Esempio n. 2
0
void stepEdges(ActiveEdgeList *ael, const rb_red_blk_tree* activePrims){
	static int scanLine;
	const static Comparator leftToRight = {(CompareF)(&leftToRightF), &scanLine};
	LinkN **aelHead = &(ael->activeEdges);
	scanLine = ++(ael->scanLine);
	{
		LinkN *i, *p, *nextP;
		for(p = NULL, i = ael->activeEdges; i; (p = i),(i = nextP)){
			const EdgeListEntry *const entry = i->data;
			Point **const edge = entry->edge;
			const float ys = edge[START]->y,
			ye = edge[END]->y,
			edgeEnd = max(ys, ye);
			nextP = i->tail;
			if(edgeEnd < scanLine){
#ifndef NDEBUG
				{
					const char* msg = "Deactivating %s with y-span: %f -> %f with x-span: %f -> %f(true: %f -> %f)\n",
					*color = fmtColor(entry->owner->color);
					const float lowEnd = min(ys, ye),
					mnX = getMinXForLine(entry, scanLine), mxX = getMaxXForLine(entry, scanLine),
					sX = edge[START]->x, eX = edge[END]->x;
					dPrintf((msg, color, lowEnd, edgeEnd, mnX, mxX, sX, eX));
				}
#endif
				/* Entries don't own the primitives they point to,
				 * so we can get away with a simple free  */
				freeLink(removeLink(aelHead, i, p), &free);
				i = p; /* We don't want to advance p into garbage data */
			}
		}
	}
	{
		const rb_red_blk_node *i;
		for(i = activePrims->first; i != activePrims->sentinel; i = TreeSuccessor(activePrims, i)){
			Primitive *const prim = i->key;
			const size_t jMax = prim->arity;
			size_t j;
			for(j = 0; j < jMax; ++j){
				Point **const e = prim->boundary + j;
				const float sy = e[START]->y,
				ey = e[END]->y,
				mnY = min(sy, ey),
				mxY = max(sy, ey);
				const bool singleton = prim->arity == 1;
				if((roundOwn(mnY) == scanLine && (!CLOSE_ENOUGH(sy,ey) || (singleton /* newEdge.isSingleton() */)))
				   || (scanLine == 0 && mnY < 0 && mxY > 0)){
					LinkN* newEdge = makeLinkEZ(e, prim);
#ifndef NDEBUG
					{
						const char* msg = "Activating %s with y-span: %f -> %f with x-span: %f -> %f(true: %f -> %f)\n",
						*color = fmtColor(prim->color);
						const float mnX = getMinXForLine(newEdge->data, scanLine),
						mxX = getMaxXForLine(newEdge->data, scanLine),
						sX = e[START]->x, eX = e[END]->x;
						dPrintf((msg, color, mnY, mxY, mnX, mxX, sX, eX));
					}
#endif
					linkFront(aelHead, newEdge);
					if (singleton) {
						dPrintf(("\t->Activating dummy end\n"));
						linkFront(aelHead, makeLink(e, prim, true));
					}
				}
			}
		}
	}
	mergeSort(&(ael->activeEdges), &leftToRight);
}
void render(PaletteRef *raster, int lineWidth, int numLines, const rb_red_blk_tree *scanLinePrimBuckets){
	static OntoProj screenPlaneData = {offsetof(Point, z), 0};
	static const Transformation screenPlane = {(TransformationF)(&snapOntoProj), &screenPlaneData};
	{
		int line;
		rb_red_blk_tree activePrimSet;
		ActiveEdgeList ael = freshAEL();
		rb_red_blk_map_tree inFlags;
		rb_red_blk_tree deFlags;
		/* This ensures that both trees are initialized and in a cleared state */
		RBTreeMapInit(&inFlags, pointerDiffF, NULL, &RBMapNodeAlloc, NULL);
		RBTreeInit(&deFlags, pointerDiffF, NULL, &RBNodeAlloc);
		RBTreeInit(&activePrimSet, pointerDiffF, NULL, &RBNodeAlloc);
		dPrintf(("Scanning line: 0\n"));
		for(line = 0; line < numLines; (++line), (raster += lineWidth)) {
			rb_red_blk_node *primIt, *p = NULL, *nextP;
			dPrintf(("\tUpdating activePrimSet\n"));
			for (primIt = activePrimSet.first; primIt != activePrimSet.sentinel; (p = primIt), (primIt = nextP)) {
				const Primitive* prim = primIt->key;
				const int top = roundOwn(topMostPoint(prim));
				nextP = TreeSuccessor(&activePrimSet, primIt);
				if(top < line){
#ifndef NDEBUG
					{
						const int bottom = roundOwn(bottomMostPoint(prim));
						dPrintf(("\t\t%d -> %d ( %s ) is not valid here: %d\n",top,bottom,fmtColor(prim->color), line));
					}
#endif
					RBDelete(&activePrimSet, primIt);
					primIt = p; /* We don't want to advance p into garbage data */
				}
			}
			{
				const rb_red_blk_tree *bucket = scanLinePrimBuckets + line;
				const rb_red_blk_node *node;
				for(node = bucket->first; node != bucket->sentinel; node = TreeSuccessor(bucket, node)) {
					Primitive * prim = node->key;
#ifndef NDEBUG
					{
						const int top = roundOwn(topMostPoint(prim)),
						bottom = roundOwn(bottomMostPoint(prim));
						dPrintf(("\t\t%d -> %d ( %s ) is added here: %d\n",top,bottom,fmtColor(prim->color), line));
					}
#endif
					RBTreeInsert(&activePrimSet, prim);
				}
			}
			stepEdges(&ael, &activePrimSet);
			{
				int curPixel = 0;
				const Primitive *curDraw = NULL;
				EdgeListEntry *nextEdge;
				LinkN* i = ael.activeEdges;
				if(i){
					nextEdge = i->data;
					while(nextEdge && curPixel < lineWidth){
						EdgeListEntry *const startEdge = nextEdge;
						Primitive *const startOwner = startEdge->owner;
						int startX = roundOwn(getSmartXForLine(startEdge, line)), nextX;
						rb_red_blk_map_node *inFlag = (rb_red_blk_map_node *)RBExactQuery((rb_red_blk_tree*)(&inFlags), startOwner);
						
						if(inFlag){
							static Point localPoints[6]; /* We don't recurse, so this is fine */
							static Edge flatHere = {localPoints, localPoints + 1},
							flatIn = {localPoints + 2, localPoints + 3},
							vert = {localPoints + 4, localPoints + 5};
							const EdgeListEntry *const edgeInEntry = inFlag->info;
							Point **const edgeHere = startEdge->edge, **edgeIn = edgeInEntry->edge;
							const Point *const s = edgeHere[START],
							*const e = edgeHere[END];
							Point here;
							bool sV, eV, v;
							float dotH, dotIn;
							transformEdge(&screenPlane, edgeHere, flatHere);
							transformEdge(&screenPlane, edgeIn, flatIn);
							INIT_POINT(here, startX, line, 0);
							sV = contains(edgeIn, s);
							eV = contains(edgeIn, e);
							v = (sV || eV) && contains(flatIn, &here) && contains(flatHere, &here) && (startOwner->arity != 1);
							vert[START] = &here;
							INIT_POINT(*(vert[END]), startX, line+1, 0);
							dotH = v ? dotEdge(vert, flatHere) : 0;
							dotIn = v ? dotEdge(vert, flatIn) : 0;
							if(!v || dotH * dotIn > 0){
								dPrintf(("\tNot *in* old %s at %f\n", fmtColor(startEdge->owner->color), getSmartXForLine(startEdge, line)));
								RBSetAdd(&deFlags, startOwner);
							} else {
								dPrintf(("\tFound horizontal vertex %s at %f. Don't delete it yet\n",fmtColor(startEdge->owner->color), getSmartXForLine(startEdge, line)));
							}
						} else {
							dPrintf(("\tNow *in* new %s at %f\n",fmtColor(startEdge->owner->color), getSmartXForLine(startEdge, line)));
							/* This might happen if a polygon is parallel to the x-axis */
							RBMapPut(&inFlags, startOwner, startEdge);
						}
						
						if(curPixel < startX){
							dPrintf(("\tcurPixel has fallen behind, dragging from %d to %d\n",curPixel, startX));
							curPixel = startX;
						}
						
						i = i->tail;
						if(i){
							nextEdge = i->data;
							nextX = roundOwn(getSmartXForLine(nextEdge, line));
							dPrintf(("\tNext edges @ x = %d from %s\n",nextX, fmtColor(nextEdge->owner->color)));
						} else {
							dPrintf(("\tNo more edges\n"));
							nextEdge = NULL;
							nextX = 0;
						}
						
						nextX = min(nextX, lineWidth);
						while ((!nextEdge && curPixel < lineWidth) || (curPixel < nextX)) {
							bool zFight = false, solitary = false;
							float bestZ = HUGE_VAL;
							const rb_red_blk_node *node;
							curDraw = NULL;
							dPrintf(("\tTesting depth:\n"));
							for(node = inFlags.tree.first; node != inFlags.tree.sentinel; node = TreeSuccessor((rb_red_blk_tree*)(&inFlags), node)) {
								const Primitive *prim = node->key;
								/* We need sub-pixel accuracy */
								const float testZ = getZForXY(prim, curPixel, line);
								if(testZ <= bestZ + PT_EPS){
									dPrintf(("\t\tHit: %f <= %f for %s\n",testZ, bestZ, fmtColor(prim->color)));
									if (CLOSE_ENOUGH(testZ, bestZ)) {
										if (prim->arity == 1) {
											zFight = curDraw && curDraw->arity == 1;
											curDraw = prim;
											solitary = RBSetContains(&deFlags, prim);
										} else {
											zFight = curDraw && curDraw->arity != 1;
										}
									} else {
										zFight = false;
										bestZ = testZ;
										curDraw = prim;
										solitary = RBSetContains(&deFlags, prim);
									}
								} else {
									dPrintf(("\t\tMiss: %f > %f for %s\n",testZ, bestZ, fmtColor(prim->color)));
								}
							}
							
							if(curDraw){
#ifndef NDEBUG
								if(nextEdge || solitary){
#endif
									const int drawWidth =  (zFight || solitary) ? 1 : ((nextEdge ? nextX : lineWidth) - curPixel),
									stopPixel = curPixel + min(lineWidth - curPixel,
															   max(0, drawWidth));
									const PaletteRef drawColor = /*(uint16_t)roundOwn(63 * bestZ / 100) << 5;*/decodeColor(curDraw->color);
									dPrintf(("Drawing %d @ (%d, %d)\n",drawWidth,curPixel,line));
									dPrintf(("Drawing %d @ (%d, %d)\n",stopPixel - curPixel,curPixel,line));
									while(curPixel < stopPixel){
										raster[curPixel++] = drawColor;
									}
#ifndef NDEBUG
								} else {
									dPrintf(("Warning: we probably shouldn't have to draw if there are no more edges to turn us off. Look for parity errors\n");
											RBTreeClear((rb_red_blk_tree*)&inFlags));
								}
#endif
							} else if(!inFlags.tree.size && nextEdge){
								/* fast forward, we aren't in any polys */
								dPrintf(("Not in any polys at the moment, fast-forwarding(1) to %d\n", nextX));
								curPixel = nextX;
							} else {
								/* Nothing left */
								dPrintf(("Nothing to draw at end of line\n"));
								curPixel = lineWidth;
							}
							
							for(node = deFlags.first; node != deFlags.sentinel; node = TreeSuccessor(&deFlags, node)){
								RBMapRemove(&inFlags, node->key);
							}
							RBTreeClear(&deFlags);
						}
						if (!inFlags.tree.size && nextEdge) {
							dPrintf(("Not in any polys at the moment, fast-forwarding(2) to %d\n", nextX));
							curPixel = nextX;
						}
					}
				}
			}
#ifndef NDEBUG
			{
				dPrintf(("Scanning line: %d\n", line+1));
				if(inFlags.tree.size){
					rb_red_blk_node *node;
					dPrintf(("\tGarbage left in inFlags:\n"));
					for (node = inFlags.tree.first; node != inFlags.tree.sentinel; node = TreeSuccessor((rb_red_blk_tree*)&inFlags, node)) {
						dPrintf(("\t\t%s\n",fmtColor(((const Primitive*)node->key)->color)));
					}
				}
			}
#endif
			RBTreeClear(&deFlags);
			RBTreeClear((rb_red_blk_tree*)(&inFlags));
		}
		RBTreeDestroy(&activePrimSet, false);
		RBTreeDestroy(&deFlags, false);
		RBTreeDestroy((rb_red_blk_tree*)(&inFlags), false);
	}