diff --git a/README.md b/README.md index ba1d0e9..c7f9a9d 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,8 @@ now sets the home position. Zooming and movement keys now work in the second view. Perfectly duplicates lines are now culled during DRC by the `V` key. Rows and columns are now stored as sorted lists intead of sets. Rows and columns are now in a consistent order in the file -export. 30% speed-up on bit marking. +export. Performance boosts in bit marking, background bit marking +and alignment. 2024-07-14 -- Fixes crash when deleting a double-selected item. Delete and backspace now delete objects like `D`. Multiple disassemblers. diff --git a/main.cpp b/main.cpp index 4085667..61139fb 100644 --- a/main.cpp +++ b/main.cpp @@ -147,6 +147,7 @@ int main(int argc, char *argv[]){ //Don't print anything because the function takes care of it for us. mrt.enableVerbose(); } + a.processEvents(); mrt.show(); for(int i=0; iscenepos); statusBar()->showMessage(tr("Forced a bit.")); } break; @@ -706,8 +707,7 @@ void MaskRomTool::keyPressEvent(QKeyEvent *event){ duplicateItem(item); } } - //Update bits when done. - markBits(false); + //Don't bother forcing an update. That can come later. }else if(none){ //Delete foreach(QGraphicsItem* item, scene->selection){ removeItem(item); @@ -770,13 +770,10 @@ void MaskRomTool::keyPressEvent(QKeyEvent *event){ //These operate on the loaded data. case Qt::Key_M: //Mark Bits. - markBits(true); - if(asciiDialog.isVisible()) - on_asciiButton_triggered(); - statusBar()->showMessage(tr("Marked bits.")); + //This kicks off the state machine to redraw all bits. + clearBits(false); if(shift){ on_actionHexView_triggered(); - statusBar()->showMessage(tr("Decoded bits.")); } break; } @@ -1422,7 +1419,7 @@ void MaskRomTool::markLine(RomLineItem* line){ * rather than just one type. */ - foreach(QGraphicsItem* item, scene->collidingItems(line)){ + if(!line->marked) foreach(QGraphicsItem* item, scene->collidingItems(line)){ //We are only looking for columns that collide with rows here. All other collisions are irrelevant. if(line->linetype==RomLineItem::LINEROW && item->type()==item->UserType+1 //Is the colliding item a column? @@ -1437,6 +1434,8 @@ void MaskRomTool::markLine(RomLineItem* line){ } } + line->marked=true; + updateCrosshairAngle(line); } @@ -1518,35 +1517,39 @@ void MaskRomTool::moveList(QList list, QPointF offset){ } //Mark up all of the bits where rows and columns collide. -void MaskRomTool::markBits(bool full){ +bool MaskRomTool::markBits(bool full){ bool bitswerevisible=bitsVisible; bool lineswerevisible=linesVisible; + uint64_t count=0; + + state=STATE_MARKING; - //Exit early if there's nothing to do. - if(!markingdirty) return; + //Exit quick and early if there's nothing to do. + //This is needed because partial updates are called in rendering loop. + if(!markingdirty) return true; if(!lineswerevisible) setLinesVisible(true); - //We're blowing away the alignment here, will need to rebuild it later. - alignmentdirty=true; - - //First we remove all the old bits. This is very slow. - if(verbose) qDebug()<<"Clearing bits."; - clearBits(); - - bitcount=0; setBitsVisible(false); //Mark every line collision. - if(verbose) qDebug()<<"Marking bits."; - foreach (RomLineItem* line, cols) + foreach (RomLineItem* line, cols){ + if(!line->marked && count++>50 && !full){ + //Show the bits if--and only if--we've set that style. + setBitsVisible(bitswerevisible); + //Same for the lines. + setLinesVisible(lineswerevisible); + return false; + } + if(!line->marked) alignmentdirty=true; markLine(line); - if(verbose) qDebug()<<"Sorting bits."; - sortBits(); + } + //Now our marking is clean, if unsorted. + markingdirty=false; + sortBits(); //Mark all the fixes. - if(verbose) qDebug()<<"Marking fixes."; markFixes(); if(verbose) qDebug()<<"Restoring visibility."; @@ -1555,37 +1558,54 @@ void MaskRomTool::markBits(bool full){ //Same for the lines. setLinesVisible(lineswerevisible); - if(verbose) - qDebug()<<"Marked"<removeItem(item); delete item; + bitcount--; + if(!full) + //For partial work, we need to remove the items. + bits.removeOne(item); + if(!full && count++>10000) + //We'll finish this off later. + return; } + + //For a full erase, we eliminate items in bulk. bits.clear(); assert(bits.isEmpty()); + //Reset the markers so we can start again. foreach (RomLineItem* line, rows) line->marked=false; foreach (RomLineItem* line, cols) line->marked=false; + //Next step is to mark the bits. bitcount=0; markingdirty=true; alignmentdirty=true; + state=STATE_MARKING; } //Marks the bit fixes. @@ -1595,13 +1615,16 @@ void MaskRomTool::markFixes(){ * overlaps a fix than every fix that overlaps a bit. */ bool bitswerevisible=bitsVisible; + setBitsVisible(true); foreach (RomBitFix* fix, bitfixes){ RomBitItem* bit=getBit(fix->pos()); if(bit) // Apply the fix. bit->setFix(fix); - else // Destroy fixes that don't match bits. + else if(!markingdirty) + // Destroy fixes that don't match bits. removeItem(fix); + } setBitsVisible(bitswerevisible); } @@ -1621,6 +1644,11 @@ void MaskRomTool::remarkBits(){ RomBitItem* MaskRomTool::markBitTable(){ static RomBitItem* firstbit=0; + //qDebug()<<"Aligning table of"<marked); + } + //Make sure all the bits are ready. if(alignmentdirty || markingdirty){ markBits(true); @@ -1633,6 +1661,7 @@ RomBitItem* MaskRomTool::markBitTable(){ if(!firstbit) alignmentdirty=true; + //qDebug()<<"Updating counts."; //If we have a bit, update the counts. rowcount=colcount=0; RomBitItem* bit=firstbit; @@ -1646,6 +1675,7 @@ RomBitItem* MaskRomTool::markBitTable(){ bit=bit->nexttoright; } + state=STATE_IDLE; return firstbit; } diff --git a/maskromtool.h b/maskromtool.h index a898368..547d6a4 100644 --- a/maskromtool.h +++ b/maskromtool.h @@ -93,12 +93,18 @@ class MaskRomTool : public QMainWindow{ void setBitsVisible(bool b=true); //Show or hide the bits. void setViolationsVisible(bool b=true); //Show or hide the DRC violations. + /* The state of GUI is whether it is marking bits, clearing them, + * or aligning them. This lets us mark bits in the background without + * hogging the rendering thread. + */ + enum {STATE_IDLE, STATE_CLEARING, STATE_MARKING} state=STATE_IDLE; + //Marks all of the bit positions, but not their connections. - void markBits(bool full=true); + bool markBits(bool full=true); //Sorts the bits from the left. Fast if already sorted. void sortBits(); //Clears all bits. Useful when we want them out of the way for a bit. - void clearBits(); + void clearBits(bool full=true); //Re-marks bits at all of the old positions, but new samples. void remarkBits(); //Marks one bit. diff --git a/romscene.cpp b/romscene.cpp index a9940bb..2e2e0b0 100644 --- a/romscene.cpp +++ b/romscene.cpp @@ -148,11 +148,6 @@ void RomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent){ updateCrosshairs(mouseEvent->buttons()==Qt::LeftButton); - /* Whenever the mouse moves, we also update the status bar - * to show our position and size. - */ - updateStatus(); - //here instead of on release so we can have preview if(mouseEvent->buttons()==Qt::RightButton){ QPointF dpos = mouseEvent->scenePos() - presspos; @@ -160,7 +155,25 @@ void RomScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent){ // update because we already moved it presspos = scenepos; + }else{ + //Update some of the bits if they aren't finished. + + switch(maskRomTool->state){ + case MaskRomTool::STATE_MARKING: + maskRomTool->markBits(false); + break; + case MaskRomTool::STATE_CLEARING: + maskRomTool->clearBits(false); + break; + case MaskRomTool::STATE_IDLE: + break; + } } + + /* Whenever the mouse moves, we also update the status bar + * to show our position and size. + */ + updateStatus(); } void RomScene::setRowAngle(qreal angle){ @@ -264,8 +277,11 @@ void RomScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent){ * arrangement. As a workaround, we remark the bits after releasing the * button from a moving drag. */ - if(maskRomTool->bitsVisible) - maskRomTool->markBits(); + if(maskRomTool->bitsVisible){ + //Clear the old bits in the background. + //This will continue until redrawing them. + maskRomTool->clearBits(false); + } } }