int round(int x) { return ipart(x + 128); }
void drawLine(sf::RenderTarget& target, float x1, float y1, float x2, float y2, const sf::Color& color) { float dx = x2 - x1; float dy = y2 - y1; // Store all points in an arrry sf::VertexArray va(sf::Points); if (std::fabs(dx) > std::fabs(dy)) { if(x2 < x1) { std::swap(x1, x2); std::swap(y1, y2); } float gradient = dy / dx; float xend = static_cast<float>(round(x1)); float yend = y1 + gradient * (xend - x1); float xgap = rfpart(x1 + 0.5f); int xpxl1 = static_cast<int>(xend); int ypxl1 = ipart(yend); // Add the first endpoint plot(va, xpxl1, ypxl1, rfpart(yend) * xgap, color); plot(va, xpxl1, ypxl1 + 1, fpart(yend) * xgap, color); float intery = yend + gradient; xend = static_cast<float>(round(x2)); yend = y2 + gradient * (xend - x2); xgap = fpart(x2 + 0.5f); int xpxl2 = static_cast<int>(xend); int ypxl2 = ipart(yend); // Add the second endpoint plot(va, xpxl2, ypxl2, rfpart(yend) * xgap, color); plot(va, xpxl2, ypxl2 + 1, fpart(yend) * xgap, color); // Add all the points between the endpoints for(int x = xpxl1 + 1; x <= xpxl2 - 1; ++x) { plot(va, x, ipart(intery), rfpart(intery), color); plot(va, x, ipart(intery) + 1, fpart(intery), color); intery += gradient; } } else { if(y2 < y1) { std::swap(x1, x2); std::swap(y1, y2); } float gradient = dx / dy; float yend = static_cast<float>(round(y1)); float xend = x1 + gradient * (yend - y1); float ygap = rfpart(y1 + 0.5f); int ypxl1 = static_cast<int>(yend); int xpxl1 = ipart(xend); // Add the first endpoint plot(va, xpxl1, ypxl1, rfpart(xend) * ygap, color); plot(va, xpxl1, ypxl1 + 1, fpart(xend) * ygap, color); float interx = xend + gradient; yend = static_cast<float>(round(y2)); xend = x2 + gradient * (yend - y2); ygap = fpart(y2 + 0.5f); int ypxl2 = static_cast<int>(yend); int xpxl2 = ipart(xend); // Add the second endpoint plot(va, xpxl2, ypxl2, rfpart(xend) * ygap, color); plot(va, xpxl2, ypxl2 + 1, fpart(xend) * ygap, color); // Add all the points between the endpoints for(int y = ypxl1 + 1; y <= ypxl2 - 1; ++y) { plot(va, ipart(interx), y, rfpart(interx), color); plot(va, ipart(interx) + 1, y, fpart(interx), color); interx += gradient; } } target.draw(va); }
// --------------------------------------------------------------------------------------------------------------------- void WuLine(pixel* frame, Fix16 x1, Fix16 y1, Fix16 x2, Fix16 y2, ColourChoice cc) { byte r = 0; byte g = 0; Fix16 dx = x2 - x1; Fix16 dy = y2 - y1; bool swapXY = false; if (Fix16::abs(dx) < Fix16::abs(dy)) { XORByteSwap(x1.value, y1.value); XORByteSwap(x2.value, y2.value); XORByteSwap(dx.value, dy.value); swapXY = true; } if (x2 < x1) { XORByteSwap(x1.value, x2.value); XORByteSwap(y1.value, y2.value); } Fix16 gradient = dy / dx; Fix16 xend = round(x1); Fix16 yend = y1 + gradient * (xend - x1); Fix16 xgap = rfpart(x1 + 0.5f); int16_t xpxl1 = xend.asInt(); // this will be used in the main loop int16_t ypxl1 = ipart(yend).asInt(); GetBasicColour(rfpart(yend) * xgap, cc, r, g); setLED(frame, xpxl1, ypxl1, r, g, true, swapXY); GetBasicColour(fpart(yend) * xgap, cc, r, g); setLED(frame, xpxl1, ypxl1 + 1, r, g, true, swapXY); Fix16 intery = yend + gradient; // first y-intersection for the main loop // handle second endpoint xend = round(x2); yend = y2 + gradient * (xend - x2); xgap = fpart(x2 + 0.5f); int16_t xpxl2 = xend.asInt(); // this will be used in the main loop int16_t ypxl2 = ipart(yend).asInt(); GetBasicColour(rfpart(yend) * xgap, cc, r, g); setLED(frame, xpxl2, ypxl2, r, g, true, swapXY); GetBasicColour(fpart(yend) * xgap, cc, r, g); setLED(frame, xpxl2, ypxl2 + 1, r, g, true, swapXY); int16_t xa = xpxl1 + 1; int16_t xb = xpxl2 - 1; if (xb - xa > 120) return; for (; xa <= xb; xa ++) { GetBasicColour(rfpart(intery), cc, r, g); setLED(frame, xa, ipart(intery).asInt(), r, g, true, swapXY); GetBasicColour(fpart(intery), cc, r, g); setLED(frame, xa, ipart(intery).asInt() + 1, r, g, true, swapXY); intery = intery + gradient; } }
static float fpart(float x) { return x - ipart(x); }
static int round(float x) { return ipart(x + 0.5f); }
void muiBBWindow::DrawLineFloat(float x0, float y0, float x1, float y1, muiColor clr) // Xiaolin Wu's line algorithm { if (!pclrBitmap) return; int ix, iy, ie; float dx = x1 - x0, x; float dy = y1 - y0, y; float c, v, gradient, xend, yend, gap; if (fabsf(dx) > fabsf(dy)) { // Handle "horizontal" lines if (x1 < x0) { swap(x0, x1); swap(y0, y1); } gradient = dy / dx; // Handle 1st endpoint xend = fround(x0); yend = y0 + gradient * (xend - x0); gap = rfpart(x0 + 0.5f); ix = int(floorf(xend)); iy = int(floorf(yend)); c = fpart(yend); DrawPixelBlend({ ix, iy++ }, clr, (1.0f - c) * gap); DrawPixelBlend({ ix++, iy }, clr, (c)* gap); y = yend + gradient; // first y-intersection for the main loop // Handle 2nd endpoint xend = fround(x1); yend = y1 + gradient * (xend - x1); gap = fpart(x1 + 0.5f); ie = int(ipart(xend)); iy = int(ipart(yend)); c = fpart(yend); DrawPixelBlend({ ie, iy++ }, clr, (1.0f - c) * gap); DrawPixelBlend({ ie--, iy }, clr, (c)* gap); // Handle mid-points while (ix <= ie) { v = ipart(y); iy = int(v); c = y - v; y += gradient; DrawPixelBlend({ ix, iy++ }, clr, (1.0f - c)); DrawPixelBlend({ ix++, iy }, clr, (c)); } } else { // Handle "vertical" lines if (y1 < y0) { swap(y0, y1); swap(x0, x1); } gradient = dx / dy; // Handle 1st endpoint yend = fround(y0); xend = x0 + gradient * (yend - y0); gap = rfpart(y0 + 0.5f); iy = int(ipart(yend)); ix = int(ipart(xend)); c = fpart(xend); DrawPixelBlend({ ix++, iy }, clr, (1.0f - c) * gap); DrawPixelBlend({ ix, iy++ }, clr, (c)* gap); x = xend + gradient; // first x-intersection for the main loop // Handle 2nd endpoint yend = fround(y1); xend = x1 + gradient * (yend - y1); gap = fpart(y1 + 0.5f); ie = int(ipart(yend)); ix = int(ipart(xend)); c = fpart(xend); DrawPixelBlend({ ix++, ie }, clr, (1.0f - c) * gap); DrawPixelBlend({ ix, ie-- }, clr, (c)* gap); // Handle mid-points while (iy <= ie) { v = ipart(x); ix = int(v); c = x - v; x += gradient; DrawPixelBlend({ ix++, iy }, clr, (1.0f - c)); DrawPixelBlend({ ix, iy++ }, clr, (c)); } } }
// --------------------------------------------------------------------------------------------------------------------- bool tick(const FrameInput& input, FXState& state, FrameOutput& output) { switch (gCurrentInterfaceStage) { case InterfaceStage::IS_GUI: { output.clear(); if (input.dialChange[1] == 0) ticksSinceAdjust ++; else ticksSinceAdjust = 0; const int16_t radioLen = sizeof(radioGUI) / sizeof(gui_entry); Fix16 max_target = fix16_from_int(radioLen); Fix16 max_value = fix16_from_int(radioLen - 1); Fix16 dial16 = fix16_from_int( input.dialChange[1] ); Fix16 pt05 = fix16_from_float(-1.0f); vTargetA += dial16 * fix16_from_float(0.2f); if (vTargetA < fix16_neg_one) vTargetA = fix16_neg_one; if (vTargetA > max_target) vTargetA = max_target; vCurA += (vTargetA - vCurA) * fix16_from_float(0.035f); if (vCurA < fix16_zero) vCurA = fix16_zero; if (vCurA > max_value) vCurA = max_value; if (ticksSinceAdjust > 30) { vTargetA -= fpart(vTargetA); } int16_t off = ipart(vCurA).asInt(); if (off < 0) off = 0; if (off > radioLen - 1) off = radioLen - 1; const gui_entry* guient[3] = {&radioGUI[off], &radioGUI[off], &radioGUI[off]}; if (off - 1 >= 0) guient[2] = &radioGUI[off - 1]; if (off + 1 <= radioLen - 1) guient[1] = &radioGUI[off + 1]; Fix16 charASlide = fpart(vCurA); charASlide *= Fix16(-16.0f); int16_t slideAInt = charASlide.asInt(); IconGlyph(output.frame, guient[0]->gly, slideAInt, 0, true); IconGlyph(output.frame, guient[1]->gly, 16 + slideAInt, 0, false); if (off > 0) IconGlyph(output.frame, guient[2]->gly, slideAInt - 16, 0, false); if (fadeTick < 15) { fadeTick ++; output.fade(15 - fadeTick); } if (input.dialClick) { gCurrentInterfaceStage = InterfaceStage::IS_FADETO; gNextDisplayMode = guient[0]->mode; } } break; case InterfaceStage::IS_FADETO: { output.fade(1); fadeTick --; if (fadeTick <= 0) { vTargetA = vCurA; gCurrentDisplayMode = gNextDisplayMode; for(int i = 0; i < Constants::MemoryPool; ++i) state.store[i] = 0xFF; DisplayMode::doInitFor(gCurrentDisplayMode, state); fadeTick = 0; gCurrentInterfaceStage = InterfaceStage::IS_FX; } } break; case InterfaceStage::IS_FX: { DisplayMode::doTickFor(gCurrentDisplayMode, input, output, state); if (fadeTick < 15) { fadeTick ++; output.fade(15 - fadeTick); } if (input.dialClick) { gCurrentInterfaceStage = InterfaceStage::IS_FADEFROM; } } break; case InterfaceStage::IS_FADEFROM: { DisplayMode::doTickFor(gCurrentDisplayMode, input, output, state); output.fade(15 - fadeTick); fadeTick --; if (fadeTick <= 0) { gCurrentInterfaceStage = InterfaceStage::IS_GUI; fadeTick = 0; } } break; } // /* dial --; if (dial <= 0) { // clear the frame output.clear(); for (int y=0; y<Constants::FrameHeight; y++) { for (int x=0; x<Constants::FrameWidth; x++) { int32_t RR = state.rng.genInt32(-4, 4); if (RR<0) RR =0; int32_t GG = state.rng.genInt32(-4, 4); if (GG<0) GG =0; setLED(output.frame, x, y, RR, GG); } } dial = 6; } */ /* byte red, green; for (int y=0; y<Constants::FrameHeight; y++) { for (int x=0; x<Constants::FrameWidth; x++) { pixel &LEDpixel = output.frame[y * Constants::FrameWidth + x]; DecodeByte(LEDpixel, red, green); if (red > 0) red --; if (green > 0) green --; LEDpixel = red | (green << 4); } } vTargetA += fix16_from_int( input.dialChange[1] ); vTargetB += fix16_from_int( input.dialChange[2] ); vCurA += (vTargetA - vCurA) * fix16_from_float(0.05f); vCurB += (vTargetB - vCurB) * fix16_from_float(0.05f); Fix16 xo = fix16_from_float(8.0f); Fix16 yo = fix16_from_float(8.0f); Fix16 ss1 = fix16_sin(vCurA * fix16_from_float(0.1f)); Fix16 cc1 = fix16_cos(vCurA * fix16_from_float(0.1f)); Fix16 ss2 = fix16_sin(vCurB * fix16_from_float(0.1f)); Fix16 cc2 = fix16_cos(vCurB * fix16_from_float(0.1f)); Fix16 rad1(-2.0f), rad2(12.0f); draw::WuLine( output.frame, xo + (ss1 * rad1), yo + (cc1 * rad1), xo + (ss1 * rad2), yo + (cc1 * rad2), Red); draw::WuLine( output.frame, xo + (ss2 * rad1), yo + (cc2 * rad1), xo + (ss2 * rad2), yo + (cc2 * rad2), Green); */ return true; }
// Draw antialiased line using Wu's algorithm. void Line::lineWu(int x0, int y0, int x1, int y1, std::vector<Point>& points, std::vector<float>& alpha) { bool bSteep = abs(int(y1 - y0)) > abs(int(x1 - x0)); if(bSteep) { std::swap(x0, y0); std::swap(x1, y1); } if(x0 > x1) { std::swap(x0, x1); std::swap(y0, y1); } float dx = float(x1 - x0); float dy = float(y1 - y0); float gradient = float(dy) / dx; // handle first endpoint uint xend = round(float(x0)); float yend = y0 + gradient * (xend - x0); float xgap = rfpart(x0 + 0.5f); uint xpxl1 = xend; //this will be used in the main loop uint ypxl1 = ipart(yend); if(bSteep) { points.push_back(Point(ypxl1, xpxl1)); alpha.push_back(rfpart(yend) * xgap); points.push_back(Point(ypxl1+1, xpxl1)); alpha.push_back(fpart(yend) * xgap); } else { points.push_back(Point(xpxl1, ypxl1)); alpha.push_back(rfpart(yend) * xgap); points.push_back(Point(xpxl1, ypxl1+1)); alpha.push_back(fpart(yend) * xgap); } float intery = yend + gradient; // first y-intersection for the main loop // handle second endpoint xend = round(float(x1)); yend = y1 + gradient * (xend - x1); xgap = fpart(x1 + 0.5f); uint xpxl2 = xend; //this will be used in the main loop uint ypxl2 = ipart(yend); if(bSteep) { points.push_back(Point(ypxl2, xpxl2)); alpha.push_back(rfpart(yend) * xgap); points.push_back(Point(ypxl2+1, xpxl2)); alpha.push_back(fpart(yend) * xgap); } else { points.push_back(Point(xpxl2, ypxl2)); alpha.push_back(rfpart(yend) * xgap); points.push_back(Point(xpxl2, ypxl2+1)); alpha.push_back(fpart(yend) * xgap); } // main loop for(uint x = xpxl1 + 1; x < xpxl2; ++x) { if(bSteep) { points.push_back(Point(ipart(intery), x)); alpha.push_back(rfpart(intery)); points.push_back(Point(ipart(intery)+1, x)); alpha.push_back(fpart(intery)); } else { points.push_back(Point(x, ipart(intery))); alpha.push_back(rfpart(intery)); points.push_back(Point(x, ipart(intery)+1)); alpha.push_back(fpart(intery)); } intery = intery + gradient; } }