Light Table

This commit is contained in:
manongjohn 2023-09-20 23:59:49 -04:00
parent 580fc67bdc
commit 24ae8225fa
12 changed files with 130 additions and 12 deletions

View file

@ -46,7 +46,8 @@ public:
};
public:
OnionSkinMask() : m_enabled(false), m_wholeScene(false) {}
OnionSkinMask()
: m_enabled(false), m_wholeScene(false), m_LightTableStatus(false) {}
void clear();
@ -106,6 +107,10 @@ since underlying onion-skinned drawings must be visible.
bool isShiftTraceEnabled() const { return m_shiftTraceStatus != DISABLED; }
bool getLightTableStatus() const { return m_LightTableStatus; }
void setLightTableStatus(bool status) { m_LightTableStatus = status; }
bool isLightTableEnabled() const { return m_LightTableStatus; }
const TAffine getShiftTraceGhostAff(int index) const {
return m_ghostAff[index];
}
@ -144,6 +149,8 @@ private:
int m_ghostFrame[2]; // relative frame position of the ghosts
QList<int> m_ghostFlipKeys; // If F1, F2 or F3 key is pressed, then only
// display the corresponding ghost
bool m_LightTableStatus;
};
//***************************************************************************

View file

@ -114,6 +114,8 @@ public:
TPixel32 m_filterColor;
static bool m_isLightTableEnabled;
public:
Player();

View file

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="100%"
height="100%"
viewBox="0 0 16 16"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
id="svg5"
sodipodi:docname="light_table.svg"
inkscape:version="1.1.2 (b8e25be833, 2022-02-05)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs9" /><sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="true"
inkscape:snap-grids="false"
inkscape:zoom="44.9375"
inkscape:cx="6.6870654"
inkscape:cy="7.8553547"
inkscape:window-width="1920"
inkscape:window-height="1141"
inkscape:window-x="-7"
inkscape:window-y="-7"
inkscape:window-maximized="1"
inkscape:current-layer="shift_and_trace"><inkscape:grid
type="xygrid"
id="grid925" /></sodipodi:namedview>
<g
id="shift_and_trace"
transform="matrix(0.70097357,0,0,0.70097357,4.7970567,4.7844228)">
<rect
id="bg"
x="0"
y="0"
width="16"
height="16"
style="fill:#878787;fill-opacity:0" />
<path
id="shift"
d="M 6.7356647,15.103979 C 6.7366076,14.708023 6.4077051,14.386477 6.0017421,14.386474 l -2.9357132,-2.1e-5 c -0.4059627,-3e-6 -0.7339308,0.320617 -0.7339339,0.717493 -3.2e-6,0.396874 0.3288994,0.718419 0.7339226,0.717504 l 2.935713,2.2e-5 c 0.4059629,3e-6 0.7348705,-0.321536 0.7339341,-0.717493 z m 1.5323108,-2.458773 c 3.9e-6,-0.395036 -0.3288994,-0.716582 -0.7339224,-0.717503 l -5.8723656,8.74e-4 c -0.4050232,-9.23e-4 -0.73393072,0.320616 -0.73393388,0.717493 -9.4291e-4,0.395956 0.32795958,0.717501 0.73392248,0.717505 l 5.8714266,4.4e-5 c 0.4059627,3e-6 0.7348701,-0.321537 0.7348728,-0.718413 z M 3.1243079,5.7720927 C 3.4229159,4.0536703 -1.7838071,0.85467468 4.9496525,-3.9481261 6.3818544,-5.9935125 3.0365196,-4.9663296 3.2084716,-4.9709792 0.83890767,-3.6812481 -1.6710515,-1.6572026 -1.0966028,2.5446016 1.371745,6.9013165 2.5293574,6.5043151 3.1243079,5.7720927 Z m -6.6009662,-3.8644872 9.454e-4,-0.7174986 c -9.049e-4,-4.357358 3.61613962,-7.8933773 8.0742136,-7.8933432 4.4561948,3.39e-5 8.0731833,3.5361084 8.0740863,7.8934664 -9.48e-4,1.0868129 -0.361813,2.1433065 -1.028085,3.0133031 L 8.2670796,8.6058816 8.2670651,9.5761849 C 8.267998,10.369017 7.6101835,11.012097 6.7991968,11.011172 l -4.4035696,-3.4e-5 C 1.5855809,11.011132 0.92776981,10.368042 0.92778222,9.5761299 L 0.92779742,8.6058258 -2.8893415,3.6301583 C -3.2708676,3.1340615 -3.4766633,2.5286417 -3.4766583,1.9076055 c 0.6810244,5.2e-6 0.6810244,0 0,0 z"
style="stroke-width:1.31402"
sodipodi:nodetypes="ccsscscscccccscccccccscccccsscccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -2332,6 +2332,8 @@ void MainWindow::defineActions() {
"view_vector_as_raster");
else
RasterizePliToggleAction = 0;
createToggle(MI_ToggleLightTable, QT_TR_NOOP("Light Table"), "", false,
MenuViewCommandType, "light_table");
// Menu - Panes

View file

@ -613,6 +613,7 @@ void TopBar::loadMenubar() {
addMenuItem(viewMenu, MI_GCheck);
addMenuItem(viewMenu, MI_ACheck);
viewMenu->addSeparator();
addMenuItem(viewMenu, MI_ToggleLightTable);
addMenuItem(viewMenu, MI_ShiftTrace);
addMenuItem(viewMenu, MI_EditShift);
addMenuItem(viewMenu, MI_NoShift);

View file

@ -511,4 +511,6 @@
#define MI_PrevTaggedFrame "MI_PrevTaggedFrame"
#define MI_ClearTags "MI_ClearTags"
#define MI_ToggleLightTable "MI_ToggleLightTable"
#endif

View file

@ -766,6 +766,25 @@ public:
}
} flipPrevStrokeDirectionCommand;
class TLightTableToggleCommand final : public MenuItemHandler {
public:
TLightTableToggleCommand() : MenuItemHandler(MI_ToggleLightTable) {}
void execute() override {
CommandManager *cm = CommandManager::instance();
QAction *action = cm->getAction(MI_ToggleLightTable);
OnionSkinMask osm =
TApp::instance()->getCurrentOnionSkin()->getOnionSkinMask();
osm.setLightTableStatus(action->isChecked());
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
TApp::instance()->getCurrentOnionSkin()->setOnionSkinMask(osm);
}
bool isChecked(CommandId id) const {
QAction *action = CommandManager::instance()->getAction(id);
return action != 0 && action->isChecked();
}
} TLightTableToggleCommand;
//=============================================================================
// SceneViewer
//-----------------------------------------------------------------------------

View file

@ -474,6 +474,8 @@
<file>icons/dark/actions/16/shift_and_trace_no_shift.svg</file>
<file>icons/dark/actions/16/shift_and_trace_reset.svg</file>
<file>icons/dark/actions/16/light_table.svg</file>
<!-- Folders -->
<file>icons/dark/actions/18/folder.svg</file>
<file>icons/dark/actions/18/folder_on.svg</file>

View file

@ -1408,6 +1408,7 @@ void RowArea::contextMenuEvent(QContextMenuEvent *event) {
menu->addAction(cmdManager->getAction(MI_DrawingSubForward));
menu->addAction(cmdManager->getAction(MI_DrawingSubBackward));
menu->addSeparator();
menu->addAction(cmdManager->getAction(MI_ToggleLightTable));
menu->addAction(cmdManager->getAction(MI_ShiftTrace));
menu->addAction(cmdManager->getAction(MI_EditShift));
menu->addAction(cmdManager->getAction(MI_NoShift));

View file

@ -936,6 +936,7 @@ void Stage::visit(Visitor &visitor, const VisitArgs &args) {
Player::m_firstBackOnionSkin = 0;
Player::m_lastBackVisibleSkin = 0;
Player::m_isShiftAndTraceEnabled = osm->isShiftTraceEnabled();
Player::m_isLightTableEnabled = osm->isLightTableEnabled();
sb.addFrame(sb.m_players, scene, xsh, row, 0, args.m_onlyVisible,
args.m_checkPreviewVisibility);
@ -980,6 +981,7 @@ void Stage::visit(Visitor &visitor, TXshSimpleLevel *level, const TFrameId &fid,
Player::m_firstBackOnionSkin = 0;
Player::m_lastBackVisibleSkin = 0;
Player::m_isShiftAndTraceEnabled = osm.isShiftTraceEnabled();
Player::m_isLightTableEnabled = osm.isLightTableEnabled();
sb.addSimpleLevelFrame(sb.m_players, level, fid);
updateOnionSkinSize(sb.m_players);
sb.visit(sb.m_players, visitor, isPlaying);

View file

@ -25,6 +25,7 @@ double Player::m_firstFrontOnionSkin = 0;
double Player::m_firstBackOnionSkin = 0;
double Player::m_lastBackVisibleSkin = 0;
bool Player::m_isShiftAndTraceEnabled = false;
bool Player::m_isLightTableEnabled = false;
//-----------------------------------------------------------------------------

View file

@ -857,6 +857,10 @@ void RasterPainter::onVectorImage(TVectorImage *vi,
int oldFrame = vPalette->getFrame();
vPalette->setFrame(player.m_frame);
UCHAR useOpacity = player.m_opacity;
if (player.m_isLightTableEnabled && !player.m_isCurrentColumn)
useOpacity *= 0.30;
if (player.m_onionSkinDistance != c_noOnionSkin) {
TPixel32 frontOnionColor, backOnionColor;
@ -875,6 +879,8 @@ void RasterPainter::onVectorImage(TVectorImage *vi,
((player.m_onionSkinDistance == 0)
? 0.1
: OnionSkinMask::getOnionSkinFade(player.m_onionSkinDistance));
if (player.m_isLightTableEnabled && !player.m_isCurrentColumn) m[3] *= 0.30;
c[0] = (1.0 - m[3]) * bgColor.r, c[1] = (1.0 - m[3]) * bgColor.g,
c[2] = (1.0 - m[3]) * bgColor.b;
c[3] = 0.0;
@ -882,10 +888,10 @@ void RasterPainter::onVectorImage(TVectorImage *vi,
cf = new TGenericColorFunction(m, c);
} else if (player.m_filterColor != TPixel::Black) {
TPixel32 colorScale = player.m_filterColor;
colorScale.m = player.m_opacity;
colorScale.m = useOpacity;
cf = new TColumnColorFilterFunction(colorScale);
} else if (player.m_opacity < 255)
cf = new TTranspFader(player.m_opacity / 255.0);
} else if (useOpacity < 255)
cf = new TTranspFader(useOpacity / 255.0);
TVectorRenderData rd(m_viewAff * player.m_placement, TRect(), vPalette, cf,
true // alpha enabled
@ -1011,6 +1017,10 @@ void RasterPainter::onRasterImage(TRasterImage *ri,
bbox *= convert(m_clipRect);
if (bbox.isEmpty()) return;
UCHAR useOpacity = player.m_opacity;
if (player.m_isLightTableEnabled && !player.m_isCurrentColumn)
useOpacity *= 0.30;
int alpha = 255;
Node::OnionMode onionMode = Node::eOnionSkinNone;
if (player.m_onionSkinDistance != c_noOnionSkin) {
@ -1023,6 +1033,8 @@ void RasterPainter::onRasterImage(TRasterImage *ri,
? 0.9
: (1.0 - OnionSkinMask::getOnionSkinFade(
player.m_onionSkinDistance));
if (player.m_isLightTableEnabled && !player.m_isCurrentColumn)
onionSkiFade *= 0.30;
alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255);
if (player.m_isShiftAndTraceEnabled &&
!Preferences::instance()->areOnionColorsUsedForShiftAndTraceGhosts())
@ -1034,8 +1046,8 @@ void RasterPainter::onRasterImage(TRasterImage *ri,
: ((player.m_onionSkinDistance < 0) ? Node::eOnionSkinBack
: Node::eOnionSkinNone);
}
} else if (player.m_opacity < 255)
alpha = player.m_opacity;
} else if (useOpacity < 255)
alpha = useOpacity;
TXshSimpleLevel *sl = player.m_sl;
bool doPremultiply = false;
bool whiteTransp = false;
@ -1074,6 +1086,10 @@ void RasterPainter::onToonzImage(TToonzImage *ti, const Stage::Player &player) {
bbox *= convert(m_clipRect);
if (bbox.isEmpty()) return;
UCHAR useOpacity = player.m_opacity;
if (player.m_isLightTableEnabled && !player.m_isCurrentColumn)
useOpacity *= 0.30;
int alpha = 255;
Node::OnionMode onionMode = Node::eOnionSkinNone;
if (player.m_onionSkinDistance != c_noOnionSkin) {
@ -1086,6 +1102,8 @@ void RasterPainter::onToonzImage(TToonzImage *ti, const Stage::Player &player) {
? 0.9
: (1.0 - OnionSkinMask::getOnionSkinFade(
player.m_onionSkinDistance));
if (player.m_isLightTableEnabled && !player.m_isCurrentColumn)
onionSkiFade *= 0.30;
alpha = tcrop(tround(onionSkiFade * 255.0), 0, 255);
if (player.m_isShiftAndTraceEnabled &&
@ -1099,8 +1117,8 @@ void RasterPainter::onToonzImage(TToonzImage *ti, const Stage::Player &player) {
: Node::eOnionSkinNone);
}
} else if (player.m_opacity < 255)
alpha = player.m_opacity;
} else if (useOpacity < 255)
alpha = useOpacity;
m_nodes.push_back(Node(r, ti->getPalette(), alpha, aff, ti->getSavebox(),
bbox, player.m_frame, player.m_isCurrentColumn,
@ -1436,6 +1454,10 @@ void onMeshImage(TMeshImage *mi, const Stage::Player &player,
}
}
UCHAR useOpacity = player.m_opacity;
if (player.m_isLightTableEnabled && !player.m_isCurrentColumn)
useOpacity *= 0.30;
if (deformation) {
// Retrieve the associated plastic deformers data (this may eventually
// update the deforms)
@ -1455,7 +1477,7 @@ void onMeshImage(TMeshImage *mi, const Stage::Player &player,
// Draw edges next
if (drawMeshes) {
glColor4d(0.0, 1.0, 0.0, 0.7 * player.m_opacity / 255.0); // Green
glColor4d(0.0, 1.0, 0.0, 0.7 * useOpacity / 255.0); // Green
tglDrawEdges(*mi, dataGroup); // The mesh must be deformed
}
} else {
@ -1469,7 +1491,7 @@ void onMeshImage(TMeshImage *mi, const Stage::Player &player,
// Just draw the mesh image next
if (drawMeshes) {
glColor4d(0.0, 1.0, 0.0, 0.7 * player.m_opacity / 255.0); // Green
glColor4d(0.0, 1.0, 0.0, 0.7 * useOpacity / 255.0); // Green
tglDrawEdges(*mi);
}
}
@ -1494,6 +1516,10 @@ void onPlasticDeformedImage(TStageObject *playerObj,
// Deal with color scaling due to transparency / onion skin
double pixScale[4] = {1.0, 1.0, 1.0, 1.0};
UCHAR useOpacity = player.m_opacity;
if (player.m_isLightTableEnabled && !player.m_isCurrentColumn)
useOpacity *= 0.30;
if (doOnionSkin) {
if (onionSkinImage) {
TPixel32 frontOnionColor, backOnionColor;
@ -1512,8 +1538,8 @@ void onPlasticDeformedImage(TStageObject *playerObj,
pixScale[1] = (refColor.g / 255.0) * pixScale[3];
pixScale[2] = (refColor.b / 255.0) * pixScale[3];
}
} else if (player.m_opacity < 255) {
pixScale[3] = player.m_opacity / 255.0;
} else if (useOpacity < 255) {
pixScale[3] = useOpacity / 255.0;
pixScale[0] = pixScale[1] = pixScale[2] = 0.0;
}