void draw_line(fixedPointCoord start, fixedPointCoord end) { fixedPoint dx = end.x - start.x; fixedPoint dy = end.y - start.y; //pick the mode that will increment along the correct dimension if (absint(dx) >= absint(dy)) { //we are now incrementing along the x direction line_algorithm(start, end, 0); } else { fixedPointCoord start_t; fixedPointCoord end_t; start_t.x = start.y; start_t.y = start.x; end_t.x = end.y; end_t.y = end.x; //we use the transpose indicator to flip the algorithm to increment along the y direction line_algorithm(start_t, end_t, 1); } }
//----------------------------------------- // devuelve la distancia entre dos angulos. //----------------------------------------- s32 distAngle(s32 s1, s32 s2){ s32 temp; if (s2 >= s1) temp = s2 - s1; else temp = s1 - s2; if (temp > 30) temp -= 360; return absint(temp); }//fin de la función.
//subpixel line drawing is pretty: http://www.antigrain.com/doc/introduction/introduction.agdoc.html (Bresenham's) void line_algorithm(fixedPointCoord start, fixedPointCoord end, int8_t transpose) { //transpose make x and y be flipped when written (for incrementing in the y direction //initialise and draw the first pointcurrent fixedPoint dx = end.x - start.x; fixedPoint dy = end.y - start.y; fixedPoint d = fip(dy)/dx; //be careful of divides and multiplies uintCoord current; //records the current pixel we are writing to if (end.x < start.x) { fixedPointCoord tmp = start; start = end; end = tmp; d=(-1)*d; } current.x = roundfip(start.x); fixedPoint yf = start.y + roundfip(d * (fip(current.x) - start.x)); //because of multiplying, we have to take a layer of fipping off - roundfip does this current.y = roundfip(yf); yf = yf - fip(current.y); LCD_set_pixel_tr(current, transpose); //make sure the iteration goes the right way int y_dir = 1; if (end.y < start.y) { y_dir = -1; yf = -1 * yf; //we will be only be incrementing Yf as it it simply a reference to proportion through the pixel we are. If we are moving negatively through y, we should move yf to the other end of its range } while (fip(current.x) < (end.x - fip(0.5))) { current.x += 1; yf += absint(d); if (yf > fip(0.5)) { current.y += y_dir; yf -= fip(1); } LCD_set_pixel_tr(current, transpose); } }
//------------------------------------------------------------------------------ // Esta función nos permite pintar los muros que forman parte del mapa definido. //------------------------------------------------------------------------------ void renderWalls(){ u32 loop; s16 curAngle; s32 gridX; // coordenada X en el mapa s32 gridY; // coordenada Y en el MAPA u16* destBuffer = videoBuffer; // apunta al buffer donde se pintan los muros. u8 x,y; double horzLength; // distancia al muro en horizontal (desde el pto de perpectiva del tio que anda.) double vertLength; // distancia al muro en vertical (desde el pto de perpectiva del tio que anda.) double* minLength; u32 lineLength; char darkgray = 0; // vertical --> darkgray, horzontal --> lightgray double fdistNextX; double fdistNextY; int ndistNextX; int ndistNextY; int horzY; double horzX; int vertX; double vertY; curAngle = nPlayerAngle + 30; // angulo de inicio. if (curAngle >= 360) curAngle -= 360; // 4 = SCREENWIDTH / 64 (TILEHEIGHT) for (loop = 0; loop < SCREENWIDTH; loop+=4) { // calcula la distancia horizontal. if (curAngle == 0 || curAngle == 180){ // no hay un muro en la dirección horizontal horzLength = 9999999.00; } else{ if (curAngle < 180){ horzY = (nPlayerY/64) * 64; ndistNextY = -64; double amountChange = ((s32) (horzY - nPlayerY) ) * tableINVTAN[curAngle]; if (curAngle < 90 || curAngle > 270){ if (amountChange < 0) amountChange *= -1; } else { if (amountChange > 0) amountChange *= -1; } horzX = nPlayerX + amountChange; horzY--; } else { horzY = (nPlayerY/64) * 64 + 64; ndistNextY = 64; double amountChange = ((s32)(horzY - nPlayerY)) * tableINVTAN[curAngle]; if (curAngle < 90 || curAngle > 270){ if (amountChange < 0) amountChange *= -1; // should be pos } else { if (amountChange > 0) amountChange *= -1; } horzX = nPlayerX + amountChange; } fdistNextX = (64.00 * tableINVTAN[curAngle]); if ( (curAngle < 90) || (curAngle>270) ){ if (fdistNextX < 0) fdistNextX *= -1; // distancia positiva al siguiente bloque } else{ if (fdistNextX > 0) fdistNextX *= -1; // distancia negativa al siguiente bloque } while (true){ gridX = (s32)(horzX / 64); gridY = (s32)(horzY / 64); if (gridX >= MAPWIDTH || gridY >= MAPHEIGHT || gridX < 0 || gridY < 0) { horzLength = 9999999.00; break; } else if (fMap[gridX+gridY*MAPHEIGHT]) { horzLength = (horzX - nPlayerX) * tableINVCOS[curAngle]; break; } horzX += fdistNextX; horzY += ndistNextY; } } // calcula la distancia vertical. if (curAngle == 90 || curAngle == 270){ vertLength = 9999999.00; } else{ if (curAngle < 90 || curAngle > 270){ vertX = (nPlayerX/64) * 64 + 64; ndistNextX = 64; double amountChange = tableTAN[curAngle]*((s32)(vertX-nPlayerX)); if (curAngle < 180){ if (amountChange > 0) amountChange *= -1; } else { if (amountChange < 0) amountChange *= -1; } vertY = nPlayerY + amountChange; } else{ vertX = (nPlayerX/64) * 64; ndistNextX = -64; double amountChange = tableTAN[curAngle]*((s32)(vertX-nPlayerX)); if (curAngle < 180){ if (amountChange > 0) amountChange *= -1; } else{ if (amountChange < 0) amountChange *= -1; } vertY = nPlayerY + amountChange; vertX--; } fdistNextY = 64.00 * tableTAN[curAngle]; if (curAngle < 180) { if (fdistNextY > 0) fdistNextY *= -1; } else{ if (fdistNextY < 0) fdistNextY *= -1; } while (true){ gridX = (s32)(vertX / 64); gridY = (s32)(vertY / 64); if (gridX >= MAPWIDTH || gridY >= MAPHEIGHT || gridX < 0 || gridY < 0) { vertLength = 9999999.00; break; } else if (fMap[gridX+gridY*MAPHEIGHT]) { vertLength = (vertY - nPlayerY) * tableINVSIN[curAngle]; break; } vertX += ndistNextX; vertY += fdistNextY; } } if (vertLength < 0) vertLength *= -1; if (horzLength < 0) horzLength *= -1; if (vertLength < horzLength){ minLength = &vertLength; darkgray = 1; } else{ darkgray = 0; minLength = &horzLength; } //arreglar la distorsión. (*minLength) = (*minLength) * tableCOS[distAngle(curAngle, nPlayerAngle)]; lineLength = absint((s32)((64.00 / *minLength) * PLAY_LENGTH) ); int end = (80 - lineLength/2); int start; if (end < 0){ end = 160; start = 0; } else{ start = end; end += lineLength; } u32 where = loop/2 + start*120; if (darkgray){ for(y = start; y<end; y++) { destBuffer[where] = 0x0f0f; destBuffer[where+1] = 0x0f0f; where += 120; } } else{ for(y = start; y<end; y++){ destBuffer[where] = 0x0e0e; destBuffer[where+1] = 0x0e0e; where += 120; } } curAngle -= 1; if (curAngle < 0) curAngle += 360; } }//fin de la función.
/* monLen -- length of array. numMon -- index into array to set */ void setMonitorPosition( Monitor *mon[], int monLen, int numMon, int x, int y, double threshold ) { int i; int left, top, right, bottom; Monitor *monTemp; boolean overlapping; mon[numMon]->x = x; mon[numMon]->y = y; i = 0; overlapping = FALSE; while( i < monLen && overlapping == FALSE ) { if( mon[i] != NULL && mon[i] != mon[numMon] ) { overlapping = doesOverlap( mon[numMon], mon[i] ); } i++; } /* Remove overlaps */ if( overlapping == TRUE ) { int dleft, dtop, dright, dbot; /* Remove current monitor so it doesn't contribute to bounding box */ monTemp = mon[numMon]; mon[numMon] = NULL; getBoundingRectangle( mon, monLen, &left, &top, &right, &bottom ); mon[numMon] = monTemp; dleft = mon[numMon]->x + mon[numMon]->width - left; dtop = mon[numMon]->y + mon[numMon]->height - top; dright = right - mon[numMon]->x; dbot = bottom - mon[numMon]->y; if( MINARG( absint( dleft ), absint( dtop ), absint( dright ), absint( dbot ) ) == absint( dleft ) ) { mon[numMon]->x = left - mon[numMon]->width - 1; } else if( MINARG( absint( dleft ), absint( dtop ), absint( dbot ), absint( dright ) ) == absint( dtop ) ) { mon[numMon]->y = top - mon[numMon]->height - 1; } else if( MINARG( absint( dleft ), absint( dtop ), absint( dbot ), absint( dright ) ) == absint( dbot ) ) { mon[numMon]->y = bottom + 1; } else { mon[numMon]->x = right + 1; } } /* Now that overlaps are gone, snap the rectangles together to make sure that at least one of their sides are touching */ for( i = 0; i < monLen; i++ ) { int dleft, dtop, dright, dbot, j; dleft = dtop = dright = dbot = 0; if( mon[i] != NULL ) { for( j = 0; j < monLen; j++ ) { if( mon[j] != NULL && mon[j] != mon[i] ) { if( dleft == 0 || absint( mon[j]->x + mon[j]->width - mon[i]->x ) < absint( dleft ) ) { dleft = mon[i]->x - ( mon[j]->x + mon[j]->width ); } if( dright == 0 || absint( mon[j]->x - ( mon[i]->x + mon[i]->width ) ) < absint( dright ) ) { dright = mon[j]->x - ( mon[i]->x + mon[i]->width ); } if( dtop == 0 || absint( mon[j]->y + mon[j]->height - mon[i]->y ) < absint( dtop ) ) { dtop = mon[i]->y - ( mon[j]->y + mon[j]->height ); } if( dbot == 0 || absint( mon[j]->y - (mon[i]->y + mon[i]->height ) ) < absint( dbot ) ) { dbot = mon[j]->y - ( mon[i]->y + mon[i]->height ); } } } if( MINARG( absint( dleft ), absint( dtop ), absint( dbot ), absint( dright ) ) == absint( dleft ) || absint( dleft ) < mon[i]->width * threshold ) { if( dleft != 0 ) /* 0 means no other monitors present */ { mon[i]->x = mon[i]->x - dleft + 1; } } if( MINARG( absint( dleft ), absint( dtop ), absint( dbot ), absint( dright ) ) == absint( dtop ) || absint( dtop ) < mon[i]->height * threshold ) { if( dtop != 0 ) { mon[i]->y = mon[i]->y - dtop + 1; } } if( MINARG( absint( dleft ), absint( dtop ), absint( dbot ), absint( dright ) ) == absint( dbot ) || absint( dbot ) < mon[i]->height * threshold ) { if( dbot != 0 ) { mon[i]->y = mon[i]->y + dbot - 1; } } if( MINARG( absint( dleft ), absint( dtop ), absint( dbot ), absint( dright ) ) == absint( dright ) || absint( dright ) < mon[i]->width * threshold ) { if( dright != 0 ) { mon[i]->x = mon[i]->x + dright - 1; } } printf(" Monitor %d final position: x = %d y = %d\n", i, mon[i]->x, mon[i]->y ); } } monTemp = mon[numMon]; mon[numMon] = NULL; getBoundingRectangle( mon, monLen, &left, &top, &right, &bottom ); mon[numMon] = monTemp; /* At least one side is in line, now ensure that they are actually touching */ /*for( i = 0; i < monLen; i++ ) { if( mon[i] != NULL && mon[i] != mon[numMon] ) { Check to see which edge of bounding box it is against and then which edge of rectangle it is against. Once found, align this monitor with the found monitor if( ( left == mon[numMon]->x + mon[numMon]->width + 1 && mon[numMon]->x + mon[numMon]->width - mon[i]->x == -1 ) || ( right == mon[numMon]->x - 1 && mon[numMon]->x - ( mon[i]->x + mon[i]->width ) == 1 ) ) { printf("Snapping 1\n"); if( ( mon[numMon]->y + mon[numMon]->width < mon[i]->y ) || ( mon[numMon]->y > mon[i]->y + mon[i]->height ) ) { mon[numMon]->y = mon[i]->y; } } else if( ( top == mon[numMon]->y + mon[numMon]->width + 1 && mon[numMon]->y + mon[numMon]->height - mon[i]->y == -1 ) || ( bottom == mon[numMon]->y - 1 && mon[numMon]->y - ( mon[i]->y + mon[i]->height ) == 1 )) { printf("Snapping 2\n"); if( ( mon[numMon]->x + mon[numMon]->width < mon[i]->x ) || ( mon[numMon]->x > mon[i]->x + mon[i]->width ) ) { mon[numMon]->x = mon[i]->x; } } } }*/ }