GUI: new pattern cursor logic, part 8
the mega-commit
This commit is contained in:
parent
33dec5ff1d
commit
7a4582d5bd
|
@ -330,6 +330,12 @@ void FurnaceGUI::doSelectAll() {
|
||||||
if (!m.effect) continue; \
|
if (!m.effect) continue; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define touch(_y,_order) \
|
||||||
|
if (opTouched[(e->curOrders->ord[iCoarse][_order]<<8)|(_y)]) continue; \
|
||||||
|
opTouched[(e->curOrders->ord[iCoarse][_order]<<8)|(_y)]=true;
|
||||||
|
|
||||||
|
#define resetTouches memset(opTouched,0,DIV_MAX_PATTERNS*DIV_MAX_ROWS);
|
||||||
|
|
||||||
void FurnaceGUI::doDelete() {
|
void FurnaceGUI::doDelete() {
|
||||||
finishSelection();
|
finishSelection();
|
||||||
prepareUndo(GUI_UNDO_PATTERN_DELETE);
|
prepareUndo(GUI_UNDO_PATTERN_DELETE);
|
||||||
|
@ -337,24 +343,28 @@ void FurnaceGUI::doDelete() {
|
||||||
|
|
||||||
int iCoarse=selStart.xCoarse;
|
int iCoarse=selStart.xCoarse;
|
||||||
int iFine=selStart.xFine;
|
int iFine=selStart.xFine;
|
||||||
int jOrder=selStart.order;
|
|
||||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||||
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
maskOut(opMaskDelete,iFine);
|
maskOut(opMaskDelete,iFine);
|
||||||
|
resetTouches;
|
||||||
for (; jOrder<=selEnd.order; jOrder++) {
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
for (int j=selStart.y; (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
touch(jOrder,j);
|
||||||
if (iFine==0) {
|
if (iFine==0) {
|
||||||
pat->data[j][iFine]=0;
|
pat->data[j][iFine]=0;
|
||||||
if (selStart.y==selEnd.y) pat->data[j][2]=-1;
|
if (selStart.y==selEnd.y && selStart.order==selEnd.order) pat->data[j][2]=-1;
|
||||||
}
|
}
|
||||||
pat->data[j][iFine+1]=(iFine<1)?0:-1;
|
pat->data[j][iFine+1]=(iFine<1)?0:-1;
|
||||||
|
|
||||||
if (selStart.y==selEnd.y && iFine>2 && iFine&1 && settings.effectDeletionAltersValue) {
|
if (selStart.y==selEnd.y && selStart.order==selEnd.order && iFine>2 && iFine&1 && settings.effectDeletionAltersValue) {
|
||||||
pat->data[j][iFine+2]=-1;
|
pat->data[j][iFine+2]=-1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
j=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iFine=0;
|
iFine=0;
|
||||||
|
@ -367,7 +377,7 @@ void FurnaceGUI::doPullDelete() {
|
||||||
finishSelection();
|
finishSelection();
|
||||||
|
|
||||||
if (selStart.order!=selEnd.order) {
|
if (selStart.order!=selEnd.order) {
|
||||||
showError("You can only pull delete within the same order.");
|
showError(_("you can only pull delete within the same order."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,7 +451,7 @@ void FurnaceGUI::doInsert() {
|
||||||
finishSelection();
|
finishSelection();
|
||||||
|
|
||||||
if (selStart.order!=selEnd.order) {
|
if (selStart.order!=selEnd.order) {
|
||||||
showError("You can only insert/push within the same order.");
|
showError(_("you can only insert/push within the same order."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,10 +502,15 @@ void FurnaceGUI::doTranspose(int amount, OperationMask& mask) {
|
||||||
int iFine=selStart.xFine;
|
int iFine=selStart.xFine;
|
||||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
|
||||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||||
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
maskOut(mask,iFine);
|
maskOut(mask,iFine);
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
resetTouches;
|
||||||
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
touch(jOrder,j);
|
||||||
if (iFine==0) {
|
if (iFine==0) {
|
||||||
int origNote=pat->data[j][0];
|
int origNote=pat->data[j][0];
|
||||||
int origOctave=(signed char)pat->data[j][1];
|
int origOctave=(signed char)pat->data[j][1];
|
||||||
|
@ -536,6 +551,8 @@ void FurnaceGUI::doTranspose(int amount, OperationMask& mask) {
|
||||||
pat->data[j][iFine+1]=MIN(top,MAX(0,pat->data[j][iFine+1]+amount));
|
pat->data[j][iFine+1]=MIN(top,MAX(0,pat->data[j][iFine+1]+amount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
iFine=0;
|
iFine=0;
|
||||||
}
|
}
|
||||||
|
@ -552,8 +569,11 @@ String FurnaceGUI::doCopy(bool cut, bool writeClipboard, const SelectionPoint& s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String clipb=fmt::sprintf("org.tildearrow.furnace - Pattern Data (%d)\n%d",DIV_ENGINE_VERSION,sStart.xFine);
|
String clipb=fmt::sprintf("org.tildearrow.furnace - Pattern Data (%d)\n%d",DIV_ENGINE_VERSION,sStart.xFine);
|
||||||
|
int jOrder=sStart.order;
|
||||||
|
int j=sStart.y;
|
||||||
|
|
||||||
for (int j=sStart.y; j<=sEnd.y; j++) {
|
for (; jOrder<=sEnd.order; jOrder++) {
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=sEnd.y || jOrder<sEnd.order); j++) {
|
||||||
int iCoarse=sStart.xCoarse;
|
int iCoarse=sStart.xCoarse;
|
||||||
int iFine=sStart.xFine;
|
int iFine=sStart.xFine;
|
||||||
if (iFine>3 && !(iFine&1)) {
|
if (iFine>3 && !(iFine&1)) {
|
||||||
|
@ -562,7 +582,7 @@ String FurnaceGUI::doCopy(bool cut, bool writeClipboard, const SelectionPoint& s
|
||||||
clipb+='\n';
|
clipb+='\n';
|
||||||
for (; iCoarse<=sEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=sEnd.xCoarse; iCoarse++) {
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<sEnd.xCoarse || iFine<=sEnd.xFine); iFine++) {
|
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<sEnd.xCoarse || iFine<=sEnd.xFine); iFine++) {
|
||||||
if (iFine==0) {
|
if (iFine==0) {
|
||||||
clipb+=noteNameNormal(pat->data[j][0],pat->data[j][1]);
|
clipb+=noteNameNormal(pat->data[j][0],pat->data[j][1]);
|
||||||
|
@ -585,6 +605,8 @@ String FurnaceGUI::doCopy(bool cut, bool writeClipboard, const SelectionPoint& s
|
||||||
iFine=0;
|
iFine=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
|
|
||||||
if (writeClipboard) {
|
if (writeClipboard) {
|
||||||
SDL_SetClipboardText(clipb.c_str());
|
SDL_SetClipboardText(clipb.c_str());
|
||||||
|
@ -737,6 +759,7 @@ void FurnaceGUI::doPasteFurnace(PasteMode mode, int arg, bool readClipboard, Str
|
||||||
if (settings.cursorPastePos) {
|
if (settings.cursorPastePos) {
|
||||||
makeCursorUndo();
|
makeCursorUndo();
|
||||||
cursor.y=j;
|
cursor.y=j;
|
||||||
|
cursor.order=curOrder;
|
||||||
if (cursor.y>=e->curSubSong->patLen) cursor.y=e->curSubSong->patLen-1;
|
if (cursor.y>=e->curSubSong->patLen) cursor.y=e->curSubSong->patLen-1;
|
||||||
selStart=cursor;
|
selStart=cursor;
|
||||||
selEnd=cursor;
|
selEnd=cursor;
|
||||||
|
@ -1205,6 +1228,7 @@ void FurnaceGUI::doPasteMPT(PasteMode mode, int arg, bool readClipboard, String
|
||||||
if (settings.cursorPastePos) {
|
if (settings.cursorPastePos) {
|
||||||
makeCursorUndo();
|
makeCursorUndo();
|
||||||
cursor.y=j;
|
cursor.y=j;
|
||||||
|
cursor.order=curOrder;
|
||||||
if (cursor.y>=e->curSubSong->patLen) cursor.y=e->curSubSong->patLen-1;
|
if (cursor.y>=e->curSubSong->patLen) cursor.y=e->curSubSong->patLen-1;
|
||||||
selStart=cursor;
|
selStart=cursor;
|
||||||
selEnd=cursor;
|
selEnd=cursor;
|
||||||
|
@ -1295,13 +1319,20 @@ void FurnaceGUI::doChangeIns(int ins) {
|
||||||
|
|
||||||
int iCoarse=selStart.xCoarse;
|
int iCoarse=selStart.xCoarse;
|
||||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||||
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
resetTouches;
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
touch(jOrder,j);
|
||||||
if (pat->data[j][2]!=-1 || !((pat->data[j][0]==0 || pat->data[j][0]==100 || pat->data[j][0]==101 || pat->data[j][0]==102) && pat->data[j][1]==0)) {
|
if (pat->data[j][2]!=-1 || !((pat->data[j][0]==0 || pat->data[j][0]==100 || pat->data[j][0]==101 || pat->data[j][0]==102) && pat->data[j][1]==0)) {
|
||||||
pat->data[j][2]=ins;
|
pat->data[j][2]=ins;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
makeUndo(GUI_UNDO_PATTERN_CHANGE_INS);
|
makeUndo(GUI_UNDO_PATTERN_CHANGE_INS);
|
||||||
|
@ -1311,52 +1342,86 @@ void FurnaceGUI::doInterpolate() {
|
||||||
finishSelection();
|
finishSelection();
|
||||||
prepareUndo(GUI_UNDO_PATTERN_INTERPOLATE);
|
prepareUndo(GUI_UNDO_PATTERN_INTERPOLATE);
|
||||||
|
|
||||||
|
// first: fixed point, 8-bit order.row
|
||||||
|
// second: value
|
||||||
std::vector<std::pair<int,int>> points;
|
std::vector<std::pair<int,int>> points;
|
||||||
int iCoarse=selStart.xCoarse;
|
int iCoarse=selStart.xCoarse;
|
||||||
int iFine=selStart.xFine;
|
int iFine=selStart.xFine;
|
||||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
|
||||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||||
maskOut(opMaskInterpolate,iFine);
|
maskOut(opMaskInterpolate,iFine);
|
||||||
points.clear();
|
points.clear();
|
||||||
|
resetTouches;
|
||||||
if (iFine!=0) {
|
if (iFine!=0) {
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
touch(jOrder,j);
|
||||||
if (pat->data[j][iFine+1]!=-1) {
|
if (pat->data[j][iFine+1]!=-1) {
|
||||||
points.emplace(points.end(),j,pat->data[j][iFine+1]);
|
points.emplace(points.end(),j|(jOrder<<8),pat->data[j][iFine+1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
|
|
||||||
if (points.size()>1) for (size_t j=0; j<points.size()-1; j++) {
|
if (points.size()>1) for (size_t j=0; j<points.size()-1; j++) {
|
||||||
std::pair<int,int>& curPoint=points[j];
|
std::pair<int,int>& curPoint=points[j];
|
||||||
std::pair<int,int>& nextPoint=points[j+1];
|
std::pair<int,int>& nextPoint=points[j+1];
|
||||||
double distance=nextPoint.first-curPoint.first;
|
int distance=(
|
||||||
for (int k=0; k<(nextPoint.first-curPoint.first); k++) {
|
((nextPoint.first&0xff)+((nextPoint.first>>8)*e->curSubSong->patLen))-
|
||||||
pat->data[k+curPoint.first][iFine+1]=curPoint.second+((nextPoint.second-curPoint.second)*(double)k/distance);
|
((curPoint.first&0xff)+((curPoint.first>>8)*e->curSubSong->patLen))
|
||||||
|
);
|
||||||
|
for (int k=0, k_p=curPoint.first; k<distance; k++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][(k_p>>8)&0xff],true);
|
||||||
|
pat->data[k_p&0xff][iFine+1]=curPoint.second+((nextPoint.second-curPoint.second)*(double)k/(double)distance);
|
||||||
|
k_p++;
|
||||||
|
if ((k_p&0xff)>=e->curSubSong->patLen) {
|
||||||
|
k_p&=~0xff;
|
||||||
|
k_p+=0x100;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
touch(jOrder,j);
|
||||||
if (pat->data[j][0]!=0 || pat->data[j][1]!=0) {
|
if (pat->data[j][0]!=0 || pat->data[j][1]!=0) {
|
||||||
if (pat->data[j][0]!=100 && pat->data[j][0]!=101 && pat->data[j][0]!=102) {
|
if (pat->data[j][0]!=100 && pat->data[j][0]!=101 && pat->data[j][0]!=102) {
|
||||||
points.emplace(points.end(),j,pat->data[j][0]+(signed char)pat->data[j][1]*12);
|
points.emplace(points.end(),j|(jOrder<<8),pat->data[j][0]+(signed char)pat->data[j][1]*12);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
|
|
||||||
if (points.size()>1) for (size_t j=0; j<points.size()-1; j++) {
|
if (points.size()>1) for (size_t j=0; j<points.size()-1; j++) {
|
||||||
std::pair<int,int>& curPoint=points[j];
|
std::pair<int,int>& curPoint=points[j];
|
||||||
std::pair<int,int>& nextPoint=points[j+1];
|
std::pair<int,int>& nextPoint=points[j+1];
|
||||||
double distance=nextPoint.first-curPoint.first;
|
int distance=(
|
||||||
for (int k=0; k<(nextPoint.first-curPoint.first); k++) {
|
((nextPoint.first&0xff)+((nextPoint.first>>8)*e->curSubSong->patLen))-
|
||||||
int val=curPoint.second+((nextPoint.second-curPoint.second)*(double)k/distance);
|
((curPoint.first&0xff)+((curPoint.first>>8)*e->curSubSong->patLen))
|
||||||
pat->data[k+curPoint.first][0]=val%12;
|
);
|
||||||
pat->data[k+curPoint.first][1]=val/12;
|
for (int k=0, k_p=curPoint.first; k<distance; k++) {
|
||||||
if (pat->data[k+curPoint.first][0]==0) {
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][(k_p>>8)&0xff],true);
|
||||||
pat->data[k+curPoint.first][0]=12;
|
int val=curPoint.second+((nextPoint.second-curPoint.second)*(double)k/(double)distance);
|
||||||
pat->data[k+curPoint.first][1]--;
|
pat->data[k_p&0xff][0]=val%12;
|
||||||
|
pat->data[k_p&0xff][1]=val/12;
|
||||||
|
if (pat->data[k_p&0xff][0]==0) {
|
||||||
|
pat->data[k_p&0xff][0]=12;
|
||||||
|
pat->data[k_p&0xff][1]--;
|
||||||
|
}
|
||||||
|
pat->data[k_p&0xff][1]&=255;
|
||||||
|
k_p++;
|
||||||
|
if ((k_p&0xff)>=e->curSubSong->patLen) {
|
||||||
|
k_p&=~0xff;
|
||||||
|
k_p+=0x100;
|
||||||
}
|
}
|
||||||
pat->data[k+curPoint.first][1]&=255;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1373,11 +1438,18 @@ void FurnaceGUI::doFade(int p0, int p1, bool mode) {
|
||||||
|
|
||||||
int iCoarse=selStart.xCoarse;
|
int iCoarse=selStart.xCoarse;
|
||||||
int iFine=selStart.xFine;
|
int iFine=selStart.xFine;
|
||||||
|
int distance=(
|
||||||
|
(selEnd.y+(selEnd.order*e->curSubSong->patLen))-
|
||||||
|
(selStart.y+(selStart.order*e->curSubSong->patLen))
|
||||||
|
);
|
||||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
|
||||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||||
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
|
int j_p=0;
|
||||||
maskOut(opMaskFade,iFine);
|
maskOut(opMaskFade,iFine);
|
||||||
|
resetTouches;
|
||||||
if (iFine!=0) {
|
if (iFine!=0) {
|
||||||
int absoluteTop=255;
|
int absoluteTop=255;
|
||||||
if (iFine==1) {
|
if (iFine==1) {
|
||||||
|
@ -1386,9 +1458,11 @@ void FurnaceGUI::doFade(int p0, int p1, bool mode) {
|
||||||
} else if (iFine==2) { // volume
|
} else if (iFine==2) { // volume
|
||||||
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
||||||
}
|
}
|
||||||
if (selEnd.y-selStart.y<1) continue;
|
if (distance<1) continue;
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
double fraction=double(j-selStart.y)/double(selEnd.y-selStart.y);
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
double fraction=double(j_p)/double(distance);
|
||||||
int value=p0+double(p1-p0)*fraction;
|
int value=p0+double(p1-p0)*fraction;
|
||||||
if (mode) { // nibble
|
if (mode) { // nibble
|
||||||
value&=15;
|
value&=15;
|
||||||
|
@ -1396,6 +1470,9 @@ void FurnaceGUI::doFade(int p0, int p1, bool mode) {
|
||||||
} else { // byte
|
} else { // byte
|
||||||
pat->data[j][iFine+1]=MIN(absoluteTop,value);
|
pat->data[j][iFine+1]=MIN(absoluteTop,value);
|
||||||
}
|
}
|
||||||
|
j_p++;
|
||||||
|
}
|
||||||
|
j=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1413,9 +1490,11 @@ void FurnaceGUI::doInvertValues() {
|
||||||
int iFine=selStart.xFine;
|
int iFine=selStart.xFine;
|
||||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
|
||||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||||
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
maskOut(opMaskInvertVal,iFine);
|
maskOut(opMaskInvertVal,iFine);
|
||||||
|
resetTouches;
|
||||||
if (iFine!=0) {
|
if (iFine!=0) {
|
||||||
int top=255;
|
int top=255;
|
||||||
if (iFine==1) {
|
if (iFine==1) {
|
||||||
|
@ -1424,10 +1503,15 @@ void FurnaceGUI::doInvertValues() {
|
||||||
} else if (iFine==2) { // volume
|
} else if (iFine==2) { // volume
|
||||||
top=e->getMaxVolumeChan(iCoarse);
|
top=e->getMaxVolumeChan(iCoarse);
|
||||||
}
|
}
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
touch(jOrder,j);
|
||||||
if (pat->data[j][iFine+1]==-1) continue;
|
if (pat->data[j][iFine+1]==-1) continue;
|
||||||
pat->data[j][iFine+1]=top-pat->data[j][iFine+1];
|
pat->data[j][iFine+1]=top-pat->data[j][iFine+1];
|
||||||
}
|
}
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iFine=0;
|
iFine=0;
|
||||||
|
@ -1444,9 +1528,11 @@ void FurnaceGUI::doScale(float top) {
|
||||||
int iFine=selStart.xFine;
|
int iFine=selStart.xFine;
|
||||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
|
||||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||||
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
maskOut(opMaskScale,iFine);
|
maskOut(opMaskScale,iFine);
|
||||||
|
resetTouches;
|
||||||
if (iFine!=0) {
|
if (iFine!=0) {
|
||||||
int absoluteTop=255;
|
int absoluteTop=255;
|
||||||
if (iFine==1) {
|
if (iFine==1) {
|
||||||
|
@ -1455,10 +1541,15 @@ void FurnaceGUI::doScale(float top) {
|
||||||
} else if (iFine==2) { // volume
|
} else if (iFine==2) { // volume
|
||||||
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
||||||
}
|
}
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
touch(jOrder,j);
|
||||||
if (pat->data[j][iFine+1]==-1) continue;
|
if (pat->data[j][iFine+1]==-1) continue;
|
||||||
pat->data[j][iFine+1]=MIN(absoluteTop,(double)pat->data[j][iFine+1]*(top/100.0f));
|
pat->data[j][iFine+1]=MIN(absoluteTop,(double)pat->data[j][iFine+1]*(top/100.0f));
|
||||||
}
|
}
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iFine=0;
|
iFine=0;
|
||||||
|
@ -1475,9 +1566,11 @@ void FurnaceGUI::doRandomize(int bottom, int top, bool mode, bool eff, int effVa
|
||||||
int iFine=selStart.xFine;
|
int iFine=selStart.xFine;
|
||||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
|
||||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||||
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
maskOut(opMaskRandomize,iFine);
|
maskOut(opMaskRandomize,iFine);
|
||||||
|
resetTouches;
|
||||||
if (iFine!=0) {
|
if (iFine!=0) {
|
||||||
int absoluteTop=255;
|
int absoluteTop=255;
|
||||||
if (iFine==1) {
|
if (iFine==1) {
|
||||||
|
@ -1486,9 +1579,12 @@ void FurnaceGUI::doRandomize(int bottom, int top, bool mode, bool eff, int effVa
|
||||||
} else if (iFine==2) { // volume
|
} else if (iFine==2) { // volume
|
||||||
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
absoluteTop=e->getMaxVolumeChan(iCoarse);
|
||||||
}
|
}
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
int value=0;
|
int value=0;
|
||||||
int value2=0;
|
int value2=0;
|
||||||
|
touch(jOrder,j);
|
||||||
if (top-bottom<=0) {
|
if (top-bottom<=0) {
|
||||||
value=MIN(absoluteTop,bottom);
|
value=MIN(absoluteTop,bottom);
|
||||||
value2=MIN(absoluteTop,bottom);
|
value2=MIN(absoluteTop,bottom);
|
||||||
|
@ -1507,6 +1603,8 @@ void FurnaceGUI::doRandomize(int bottom, int top, bool mode, bool eff, int effVa
|
||||||
pat->data[j][iFine+1]=effVal;
|
pat->data[j][iFine+1]=effVal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iFine=0;
|
iFine=0;
|
||||||
|
@ -1515,29 +1613,54 @@ void FurnaceGUI::doRandomize(int bottom, int top, bool mode, bool eff, int effVa
|
||||||
makeUndo(GUI_UNDO_PATTERN_RANDOMIZE);
|
makeUndo(GUI_UNDO_PATTERN_RANDOMIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PatBufferEntry {
|
||||||
|
short data[DIV_MAX_COLS];
|
||||||
|
};
|
||||||
|
|
||||||
void FurnaceGUI::doFlip() {
|
void FurnaceGUI::doFlip() {
|
||||||
finishSelection();
|
finishSelection();
|
||||||
prepareUndo(GUI_UNDO_PATTERN_FLIP);
|
prepareUndo(GUI_UNDO_PATTERN_FLIP);
|
||||||
|
|
||||||
DivPattern patBuffer;
|
std::vector<PatBufferEntry> patBuffer;
|
||||||
int iCoarse=selStart.xCoarse;
|
int iCoarse=selStart.xCoarse;
|
||||||
int iFine=selStart.xFine;
|
int iFine=selStart.xFine;
|
||||||
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
for (; iCoarse<=selEnd.xCoarse; iCoarse++) {
|
||||||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
patBuffer.clear();
|
||||||
|
|
||||||
|
int jOrder=selStart.order;
|
||||||
|
int j=selStart.y;
|
||||||
|
|
||||||
|
// collect pattern
|
||||||
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
PatBufferEntry put;
|
||||||
|
memcpy(put.data,pat->data[j],DIV_MAX_COLS*sizeof(short));
|
||||||
|
patBuffer.push_back(put);
|
||||||
|
}
|
||||||
|
j=0;
|
||||||
|
}
|
||||||
|
|
||||||
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
for (; iFine<3+e->curPat[iCoarse].effectCols*2 && (iCoarse<selEnd.xCoarse || iFine<=selEnd.xFine); iFine++) {
|
||||||
maskOut(opMaskFlip,iFine);
|
maskOut(opMaskFlip,iFine);
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
resetTouches;
|
||||||
|
jOrder=selStart.order;
|
||||||
|
j=selStart.y;
|
||||||
|
int j_i=patBuffer.size();
|
||||||
|
|
||||||
|
// insert flipped version
|
||||||
|
for (; jOrder<=selEnd.order; jOrder++) {
|
||||||
|
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][jOrder],true);
|
||||||
|
for (; j<e->curSubSong->patLen && (j<=selEnd.y || jOrder<selEnd.order); j++) {
|
||||||
|
j_i--;
|
||||||
|
touch(jOrder,j);
|
||||||
if (iFine==0) {
|
if (iFine==0) {
|
||||||
patBuffer.data[j][0]=pat->data[j][0];
|
pat->data[j][0]=patBuffer[j_i].data[0];
|
||||||
}
|
}
|
||||||
patBuffer.data[j][iFine+1]=pat->data[j][iFine+1];
|
pat->data[j][iFine+1]=patBuffer[j_i].data[iFine+1];
|
||||||
}
|
}
|
||||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
j=0;
|
||||||
if (iFine==0) {
|
|
||||||
pat->data[j][0]=patBuffer.data[selEnd.y-j+selStart.y][0];
|
|
||||||
}
|
|
||||||
pat->data[j][iFine+1]=patBuffer.data[selEnd.y-j+selStart.y][iFine+1];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iFine=0;
|
iFine=0;
|
||||||
|
@ -1552,6 +1675,10 @@ void FurnaceGUI::doCollapse(int divider, const SelectionPoint& sStart, const Sel
|
||||||
showError(_("can't collapse any further!"));
|
showError(_("can't collapse any further!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (sStart.order!=sEnd.order) {
|
||||||
|
showError(_("can't collapse across orders."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
finishSelection();
|
finishSelection();
|
||||||
prepareUndo(GUI_UNDO_PATTERN_COLLAPSE);
|
prepareUndo(GUI_UNDO_PATTERN_COLLAPSE);
|
||||||
|
@ -1609,6 +1736,10 @@ void FurnaceGUI::doCollapse(int divider, const SelectionPoint& sStart, const Sel
|
||||||
|
|
||||||
void FurnaceGUI::doExpand(int multiplier, const SelectionPoint& sStart, const SelectionPoint& sEnd) {
|
void FurnaceGUI::doExpand(int multiplier, const SelectionPoint& sStart, const SelectionPoint& sEnd) {
|
||||||
if (multiplier<2) return;
|
if (multiplier<2) return;
|
||||||
|
if (sStart.order!=sEnd.order) {
|
||||||
|
showError(_("can't expand across orders."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
finishSelection();
|
finishSelection();
|
||||||
prepareUndo(GUI_UNDO_PATTERN_EXPAND);
|
prepareUndo(GUI_UNDO_PATTERN_EXPAND);
|
||||||
|
|
Loading…
Reference in a new issue