Esempio n. 1
0
void Container::FrameResized(const Size& size)
{
    int dx = size.width - m_oldSize.width;
    int dy = size.height - m_oldSize.height;

    uint count = CountChildren();

    for (int i = 0; i < count; ++i)
    {
        View* view = m_childList[i];

        if (view->Parent() == nullptr)
            continue;

        uint alignMode = view->AlignMode();
        Rect frame = Frame();

        if (TestBits(alignMode, ALIGN_LEFT_RIGHT))
            frame.ResizeBy(dx, 0);
        else if (TestBits(alignMode, ALIGN_RIGHT))
            frame.OffsetBy(dx, 0);

        if (TestBits(alignMode, ALIGN_TOP_BOTTOM))
            frame.ResizeBy(0, dy);
        else if (TestBits(alignMode, ALIGN_BOTTOM))
            frame.OffsetBy(0, dy);

        view->SetFrame(frame);
    }

    m_oldSize = size;
}
Esempio n. 2
0
void WinGraphics::DrawText(const Rect& frame, String text, uint flags)
{
    RECT r;
    UINT format = 0;

    SetRect(&r, frame);

    if (TestBits(flags, SINGLELINE_TEXT))
        format |= DT_SINGLELINE;
    else
        format |= DT_WORDBREAK;

    if (TestBits(flags, ALIGN_RIGHT))
        format |= DT_RIGHT;
    else if (TestBits(flags, ALIGN_H_CENTER))
        format |= DT_CENTER;
    else if (TestBits(flags, ALIGN_LEFT))
        format |= DT_LEFT;

    if (TestBits(flags, ALIGN_TOP))
        format |= DT_TOP;
    else if (TestBits(flags, ALIGN_BOTTOM))
        format |= DT_BOTTOM;
    else if (TestBits(flags, ALIGN_V_CENTER))
        format |= DT_VCENTER;

    ::DrawTextA(m_dc, text.CStr(), -1, &r, format);
}
Esempio n. 3
0
void WinGraphics::SetFont(const Font& font)
{
    int height = -MulDiv(font.height, ::GetDeviceCaps(m_dc, LOGPIXELSY), 72);

    uint italic = TestBits(font.flags, Font::ITALIC) ? 1 : 0;
    uint underline = TestBits(font.flags, Font::UNDERLINE) ? 1 : 0;
    uint strikeOut = TestBits(font.flags, Font::STRIKE_OUT) ? 1 : 0;
    uint pitch = TestBits(font.flags, Font::FIXED_WIDTH) ?  FIXED_PITCH : DEFAULT_PITCH;
    uint family = font_family_table[font.family];

    m_font = ::CreateFont(height, font.width, font.escapement, font.orientation,
                         font.weight, italic, underline, strikeOut, ANSI_CHARSET,
                         OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY,
                         family | pitch, font.name.CStr());

    HFONT xfont = (HFONT) ::SelectObject(m_dc, m_font);

    if (xfont != 0 && xfont != m_oldFont)
        ::DeleteObject(xfont);
}
Esempio n. 4
0
bool nsHTMLElement::IsMemberOf(int32_t aSet) const
{
  return TestBits(aSet,mParentBits);
}
Esempio n. 5
0
bool Via::IrqEnabled() const {
    return TestBits(GetInterruptFlagValue(), InterruptFlag::IrqEnabled);
}
Esempio n. 6
0
void Via::Write(uint16_t address, uint8_t value) {
    auto UpdateIntegrators = [&] {
        const bool muxEnabled = !TestBits(m_portB, PortB::MuxDisabled);

        if (muxEnabled) {
            switch (ReadBitsWithShift(m_portB, PortB::MuxSelMask, PortB::MuxSelShift)) {
            case 0: // Y-axis integrator
                m_screen.SetIntegratorY(static_cast<int8_t>(m_portA));
                break;
            case 1: // X,Y Axis integrator offset
                m_screen.SetIntegratorXYOffset(static_cast<int8_t>(m_portA));
                break;
            case 2: // Z Axis (Vector Brightness) level
                m_screen.SetBrightness(m_portA);
                break;
            case 3: // Connected to sound output line via divider network
                m_directAudioSamples.Add(static_cast<int8_t>(m_portA) / 128.f); // [-1,1]
                break;
            default:
                FAIL();
                break;
            }
        }

        // Always output to X-axis integrator
        m_screen.SetIntegratorX(static_cast<int8_t>(m_portA));
    };

    auto UpdatePsg = [&] {
        const bool muxEnabled = !TestBits(m_portB, PortB::MuxDisabled);

        if (!muxEnabled) {
            m_psg.SetBC1(TestBits(m_portB, PortB::SoundBC1));
            m_psg.SetBDIR(TestBits(m_portB, PortB::SoundBDir));
            // @TODO: not sure if we should always send port A value to PSG's DA bus, or just when
            // MUX disabled
            m_psg.WriteDA(m_portA);
        }
    };

    const uint16_t index = MemoryMap::Via.MapAddress(address);
    switch (index) {
    case Register::PortB:
        m_portB = value;
        UpdateIntegrators();
        UpdatePsg();
        break;

    case Register::PortA:
        m_ca1InterruptFlag = false; // Cleared by read/write of Port A

        // Port A is connected directly to the DAC, which in turn is connected to both a MUX with 4
        // outputs, and to the X-axis integrator.
        m_portA = value;
        if (m_dataDirA == 0xFF) {
            UpdateIntegrators();
        }
        break;

    case Register::DataDirB:
        m_dataDirB = value;
        break;

    case Register::DataDirA:
        m_dataDirA = value;
        ASSERT_MSG(m_dataDirA == 0 || m_dataDirA == 0xFF,
                   "Expecting DDR for A to be either all 0s or all 1s");
        break;

    case Register::Timer1Low:
        m_timer1.WriteCounterLow(value);
        break;

    case Register::Timer1High:
        m_timer1.WriteCounterHigh(value);
        break;

    case Register::Timer1LatchLow:
        m_timer1.WriteLatchLow(value);
        break;

    case Register::Timer1LatchHigh:
        m_timer1.WriteLatchHigh(value);
        break;

    case Register::Timer2Low:
        m_timer2.WriteCounterLow(value);
        break;

    case Register::Timer2High:
        m_timer2.WriteCounterHigh(value);
        break;

    case Register::Shift:
        m_shiftRegister.SetValue(value);
        break;

    case Register::AuxCntl: {
        // For now just read the shift register mode, which will assert if it's invalid/unexpected
        auto shiftRegisterMode = AuxCntl::GetShiftRegisterMode(value);
        (void)shiftRegisterMode;

        ASSERT_MSG(AuxCntl::GetTimer1Mode(value) == TimerMode::OneShot,
                   "t1 assumed always on one-shot mode");
        ASSERT_MSG(AuxCntl::GetTimer2Mode(value) == TimerMode::OneShot,
                   "t2 assumed always on one-shot mode");
        m_timer1.SetTimerMode(AuxCntl::GetTimer1Mode(value));
        m_timer2.SetTimerMode(AuxCntl::GetTimer2Mode(value));

        m_timer1.SetPB7Flag(TestBits(value, AuxCntl::PB7Flag));

    } break;

    case Register::PeriphCntl: {
        ASSERT_MSG(ReadBitsWithShift(value, PeriphCntl::CA2Mask, PeriphCntl::CA2Shift) == 0b110 ||
                       ReadBitsWithShift(value, PeriphCntl::CA2Mask, PeriphCntl::CA2Shift) == 0b111,
                   "Unexpected value for CA2 bits");

        ASSERT_MSG(ReadBitsWithShift(value, PeriphCntl::CB2Mask, PeriphCntl::CB2Shift) == 0b110 ||
                       ReadBitsWithShift(value, PeriphCntl::CB2Mask, PeriphCntl::CB2Shift) == 0b111,
                   "Top 2 bits should always be 1 (right?)");

        m_periphCntl = value;
        if (!m_shiftRegister.Enabled()) {
            m_screen.SetBlankEnabled(PeriphCntl::IsBlankEnabled(m_periphCntl));
        }
    } break;

    case Register::InterruptFlag:
        // Clear interrupt flags for any bits that are enabled
        //@TODO: validate if this is the correct behaviour

        // Assert if trying to clear an interrupt we don't handle yet
#define ASSERT_UNHANDLED(flag)                                                                     \
    ASSERT_MSG(!TestBits(value, flag), "Write to clear interrupt not supported yet: %s", #flag)
        ASSERT_UNHANDLED(InterruptFlag::CA2);
        ASSERT_UNHANDLED(InterruptFlag::CB1);
        ASSERT_UNHANDLED(InterruptFlag::CB2);
#undef ASSERT_UNHANDLED

        if (TestBits(value, InterruptFlag::CA1))
            m_ca1InterruptFlag = false;
        if (TestBits(value, InterruptFlag::Shift))
            m_shiftRegister.SetInterruptFlag(false);
        if (TestBits(value, InterruptFlag::Timer2))
            m_timer2.SetInterruptFlag(false);
        if (TestBits(value, InterruptFlag::Timer1))
            m_timer1.SetInterruptFlag(false);
        break;

    case Register::InterruptEnable: {
        // When bit 7 = 0 : Each 1 in a bit position is cleared (disabled).
        // When bit 7 = 1 : Each 1 in a bit position enables that bit.
        // (Zeros in bit positions are left unchanged)
        SetBits(m_interruptEnable, (value & 0x7F), TestBits(value, BITS(7)));

        // Assert if trying to enable interrupt we don't handle yet
#define ASSERT_UNHANDLED(flag)                                                                     \
    ASSERT_MSG(!TestBits(m_interruptEnable, flag),                                                 \
               "Write to enable interrupt not supported yet: %s", #flag)
        ASSERT_UNHANDLED(InterruptFlag::CA2);
        ASSERT_UNHANDLED(InterruptFlag::CB1);
        ASSERT_UNHANDLED(InterruptFlag::CB2);
#undef ASSERT_UNHANDLED

    } break;

    case Register::PortANoHandshake:
        FAIL_MSG("A without handshake not implemented yet");
        break;

    default:
        FAIL();
        break;
    }
}
Esempio n. 7
0
uint8_t Via::Read(uint16_t address) const {
    const uint16_t index = MemoryMap::Via.MapAddress(address);
    switch (index) {
    case Register::PortB: {
        uint8_t result = m_portB;

        // Set comparator bit to port A (DAC) value < joystick POT value
        int8_t portASigned = static_cast<int8_t>(m_portA);
        SetBits(result, PortB::Comparator, portASigned < m_joystickPot);

        SetBits(result, PortB::SoundBC1, m_psg.BC1());
        SetBits(result, PortB::SoundBDir, m_psg.BDIR());

        return result;
    }
    case Register::PortA: {
        m_ca1InterruptFlag = false; // Cleared by read/write of Port A

        uint8_t result = m_portA;

        // @TODO: Vectrex probably only ever reads from PSG to read joystick state. Right now we're
        // reading joystick inputs directly here in the Via, so we'll skip reading DA value from PSG
        // here. Eventually, we should move the joystick reading logic into PSG and clean this up.

        // Digital input
        if (!TestBits(m_portB, PortB::SoundBDir) && TestBits(m_portB, PortB::SoundBC1)) {
            if (m_dataDirA == 0) { // Input mode

                // @TODO: in this mode, we're reading the PSG's port A, not the
                // VIA's DAC, so this is probably wrong
                result = m_joystickButtonState;
            }
        }

        return result;
    }
    case Register::DataDirB:
        return m_dataDirB;

    case Register::DataDirA:
        return m_dataDirA;

    case Register::Timer1Low:
        return m_timer1.ReadCounterLow();

    case Register::Timer1High:
        return m_timer1.ReadCounterHigh();

    case Register::Timer1LatchLow:
        return m_timer1.ReadLatchLow();

    case Register::Timer1LatchHigh:
        return m_timer1.ReadLatchHigh();

    case Register::Timer2Low:
        return m_timer2.ReadCounterLow();

    case Register::Timer2High:
        return m_timer2.ReadCounterHigh();

    case Register::Shift:
        return m_shiftRegister.ReadValue();

    case Register::AuxCntl: {
        uint8_t auxCntl = 0;
        SetBits(auxCntl, 0b110 << AuxCntl::ShiftRegisterModeShift, true); //@HACK
        SetBits(auxCntl, AuxCntl::Timer1FreeRunning, m_timer1.Mode() == TimerMode::FreeRunning);
        SetBits(auxCntl, AuxCntl::Timer2PulseCounting, m_timer2.Mode() == TimerMode::PulseCounting);
        SetBits(auxCntl, AuxCntl::PB7Flag, m_timer1.PB7Flag());
        return auxCntl;
    }
    case Register::PeriphCntl:
        return m_periphCntl;

    case Register::InterruptFlag:
        return GetInterruptFlagValue();

    case Register::InterruptEnable:
        return m_interruptEnable;

    case Register::PortANoHandshake:
        FAIL_MSG("A without handshake not implemented yet");
        break;

    default:
        FAIL();
        break;
    }
    return 0;
}
Esempio n. 8
0
void Via::DoSync(cycles_t cycles, const Input& input, RenderContext& renderContext,
                 AudioContext& audioContext) {
    // Update cached input state
    m_joystickButtonState = input.ButtonStateMask();

    // Analog input: update POT value if MUX is enabled, otherwise it keeps its last value
    const bool muxEnabled = !TestBits(m_portB, PortB::MuxDisabled);
    if (muxEnabled) {
        uint8_t muxSel = ReadBitsWithShift(m_portB, PortB::MuxSelMask, PortB::MuxSelShift);
        m_joystickPot = input.AnalogStateMask(muxSel);
    }

    // CA1 is set when joystick 2 button 4 is pressed, which is usually always on for peripherals
    // like the 3D imager goggles. Interrupt flag for CA1 is set when CA1 line goes from disabled to
    // enabled, and is cleared by read/write on Port A.
    const auto ca1Prev = m_ca1Enabled;
    m_ca1Enabled = input.IsButtonDown(1, 3);
    if (!ca1Prev && m_ca1Enabled)
        m_ca1InterruptFlag = true;

    m_firqEnabled = input.IsButtonDown(0, 3);

    // Audio update
    for (cycles_t i = 0; i < cycles; ++i) {
        m_psg.Update(1);
        m_psgAudioSamples.Add(m_psg.Sample());

        if (++m_elapsedAudioCycles >= audioContext.CpuCyclesPerAudioSample) {
            m_elapsedAudioCycles -= audioContext.CpuCyclesPerAudioSample;

            // Need a target sample...

            float psgSample = m_psgAudioSamples.AverageAndReset();
            float directSample = m_directAudioSamples.AverageAndReset();

            //@TODO: Is this right? Averaging means getting half the volume when only one source is
            // playing, which is most of the time.
            float targetSample = directSample != 0 ? directSample : psgSample;
            // float targetSample = (psgSample + directSample) / 2.f;

            audioContext.samples.push_back(targetSample);
        }
    }

    //@TODO: Move this code into a Clock() function and call it cycles number of times
    // For cycle-accurate drawing, we update our timers, shift register, and beam movement 1 cycle
    // at a time
    cycles_t cyclesLeft = cycles;
    cycles = 1;
    while (cyclesLeft-- > 0) {
        m_timer1.Update(cycles);
        m_timer2.Update(cycles);
        m_shiftRegister.Update(cycles);

        // Shift register's CB2 line drives /BLANK
        //@TODO: check some flag on the shift register to know whether it's active
        if (m_shiftRegister.Enabled()) {
            m_screen.SetBlankEnabled(m_shiftRegister.CB2Active());
        }

        // If the Timer1 PB7 flag is set, then PB7 drives /RAMP
        if (m_timer1.PB7Flag()) {
            SetBits(m_portB, PortB::RampDisabled, !m_timer1.PB7SignalLow());
        }

        if (PeriphCntl::IsZeroEnabled(m_periphCntl)) {
            m_screen.ZeroBeam();
        }

        // Integrators are enabled while RAMP line is active (low)
        m_screen.SetIntegratorsEnabled(!TestBits(m_portB, PortB::RampDisabled));

        // Update screen, which populates the lines in the renderContext
        m_screen.Update(cycles, renderContext);
    }
}