Skip to content

Commit

Permalink
Merge pull request #155 from jbunke/dev-branch
Browse files Browse the repository at this point in the history
1.2.1 development changes
  • Loading branch information
jbunke authored Sep 6, 2024
2 parents 6d5c0c9 + 497beea commit d8eb2f3
Show file tree
Hide file tree
Showing 15 changed files with 445 additions and 147 deletions.
13 changes: 13 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## **1.2.1** - 2024-09-06

### Added:
* Minimum values are enforced on startup for settings that could lead to crashes
* Extended the Color Picker tool with two alternate modes
* Holding **Shift** searches layer by layer for the highest non-transparent color at the specified pixel; does nothing if no such pixel is found
* Holding **Ctrl** samples the pixel from the flattened project
* Normal map color sampler with quantization option

### Fixed:
* Bug: Attempting to validate a script with no return type crashes the program
* Bug: Crashes due to impossible layout/sizing logic

## **1.2.0** - 2024-09-03

### Added:
Expand Down
14 changes: 14 additions & 0 deletions res/blurbs/__changelog.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
{1.2.1} - 2024-09-06

Added:
> Minimum values are enforced on startup for settings that could lead to crashes
> Extended the Color Picker tool with two alternate modes
> Holding {Shift} searches layer by layer for the highest non-transparent color at the specified
pixel; does nothing if no such pixel is found
> Holding {Ctrl} samples the pixel from the flattened project
> Normal map color sampler with quantization option

Fixed:
> Bug: Attempting to validate a script with no return type crashes the program
> Bug: Crashes due to impossible layout/sizing logic

{1.2.0} - 2024-09-03

Added:
Expand Down
5 changes: 5 additions & 0 deletions res/blurbs/color_picker.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ pixel that was clicked.

Assign to primary: {Left Click}
Assign to secondary: {Right Click}

Hold {Shift} to search layer by layer for the highest non-transparent color at the specified pixel;
does nothing if no such pixel is found.

Hold {Ctrl} to sample the pixel from the flattened project.
2 changes: 1 addition & 1 deletion res/program
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name:{Stipple Effect}
version:{1.2.0}
version:{1.2.1}
devbuild:{false}
native_standard:{1.3}
palette_standard:{1.0}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public static boolean validateColorScript(final HeadFuncNode script) {
final TypeNode COL_TYPE = TypeNode.getColor();

return script.paramsMatch(new TypeNode[] { COL_TYPE }) &&
script.getReturnType().equals(COL_TYPE);
COL_TYPE.equals(script.getReturnType());
}

public static boolean validatePreviewScript(
Expand All @@ -65,8 +65,8 @@ public static boolean validatePreviewScript(
IMG_ARRAY_TYPE = TypeNode.arrayOf(IMG_TYPE),
returnType = script.getReturnType();

final boolean imgReturn = returnType.equals(IMG_TYPE),
arrayReturn = returnType.equals(IMG_ARRAY_TYPE),
final boolean imgReturn = IMG_TYPE.equals(returnType),
arrayReturn = IMG_ARRAY_TYPE.equals(returnType),
imgParam = script.paramsMatch(new TypeNode[] { IMG_TYPE }),
arrayParam = script.paramsMatch(new TypeNode[] { IMG_ARRAY_TYPE });

Expand Down
70 changes: 66 additions & 4 deletions src/com/jordanbunke/stipple_effect/tools/ColorPicker.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,57 @@
import com.jordanbunke.delta_time.events.GameMouseEvent;
import com.jordanbunke.delta_time.utility.math.Coord2D;
import com.jordanbunke.stipple_effect.StippleEffect;
import com.jordanbunke.stipple_effect.layer.SELayer;
import com.jordanbunke.stipple_effect.project.SEContext;

import java.awt.*;
import java.util.List;

public final class ColorPicker extends Tool {
public final class ColorPicker extends Tool
implements SnappableTool, ToggleModeTool {
private static final ColorPicker INSTANCE;

private Mode mode;
private boolean ctrl, shift;

static {
INSTANCE = new ColorPicker();
}

private enum Mode {
REGULAR, COMPOSED, LAYERS;

public Color get(final Coord2D tp, final SEContext c) {
return switch (this) {
case REGULAR -> c.getState().getActiveCel()
.getColorAt(tp.x, tp.y);
case LAYERS -> {
final int frameIndex = c.getState().getFrameIndex();
final List<SELayer> layers = c.getState().getLayers();

for (int l = layers.size() - 1; l >= 0; l--) {
final Color sampled = layers.get(l)
.getCel(frameIndex).getColorAt(tp.x, tp.y);
if (sampled.getAlpha() > 0)
yield sampled;
}

yield null;
}
case COMPOSED -> {
final int frameIndex = c.getState().getFrameIndex();
yield c.getState().draw(false, false,
frameIndex).getColorAt(tp.x, tp.y);
}
};
}
}

private ColorPicker() {
mode = Mode.REGULAR;

ctrl = false;
shift = true;
}

public static ColorPicker get() {
Expand All @@ -35,10 +73,34 @@ public void onMouseDown(final SEContext context, final GameMouseEvent me) {
final int index = me.button == GameMouseEvent.Button.LEFT
? StippleEffect.PRIMARY : StippleEffect.SECONDARY;

final Color c = context.getState().getActiveCel()
.getColorAt(tp.x, tp.y);
final Color c = mode.get(tp, context);

StippleEffect.get().setColorIndexAndColor(index, c);
if (c != null)
StippleEffect.get().setColorIndexAndColor(index, c);
}
}

@Override
public void setSnap(final boolean snap) {
shift = snap;
updateMode();
}

@Override
public boolean isSnap() {
return shift;
}

@Override
public void setMode(final boolean mode) {
ctrl = mode;
updateMode();
}

private void updateMode() {
if (ctrl ^ shift)
mode = ctrl ? Mode.COMPOSED : Mode.LAYERS;
else
mode = Mode.REGULAR;
}
}
5 changes: 3 additions & 2 deletions src/com/jordanbunke/stipple_effect/utility/Layout.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ public final class Layout {
public static final int
COLLAPSED_PROJECTS_H = 27, BOTTOM_BAR_H = 24, TOOL_OPTIONS_BAR_H = 30,
COLOR_COMP_W_ALLOWANCE = RIGHT_PANEL_W, SCREEN_H_BUFFER = 120,
MAX_WINDOW_H = Toolkit.getDefaultToolkit().getScreenSize().height - SCREEN_H_BUFFER,
MIN_WINDOW_H = 788,
MAX_WINDOW_W = (int)(MAX_WINDOW_H * (16 / 9.)),
MAX_WINDOW_H = Math.max(MIN_WINDOW_H,
Toolkit.getDefaultToolkit().getScreenSize().height - SCREEN_H_BUFFER),
MIN_WINDOW_W = (int)(MIN_WINDOW_H * (16 / 9.)),
MAX_WINDOW_W = Math.max(MIN_WINDOW_W, (int)(MAX_WINDOW_H * (16 / 9.))),
TEXT_Y_OFFSET = -4, TOOL_TIP_OFFSET = 8,
TEXT_CARET_W = 1, TEXT_CARET_H = 23,
TEXT_CARET_Y_OFFSET = -11, TEXT_LINE_PX_H = TEXT_CARET_H + 2,
Expand Down
3 changes: 2 additions & 1 deletion src/com/jordanbunke/stipple_effect/utility/SamplerMode.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.jordanbunke.stipple_effect.visual.menu_elements.colors.ColorComponent;

public enum SamplerMode {
RGB_SLIDERS, HSV_SLIDERS, SV_MATRIX, COLOR_WHEEL;
RGB_SLIDERS, HSV_SLIDERS, SV_MATRIX, COLOR_WHEEL, NORMAL;

@Override
public String toString() {
Expand All @@ -13,6 +13,7 @@ public String toString() {
case HSV_SLIDERS -> "HSV sliders";
case SV_MATRIX -> "SV matrix";
case COLOR_WHEEL -> "Color wheel";
case NORMAL -> "Normal map";
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,26 @@ private <T> void set(final T value) {
}

private void read(final String value) {
setting.setFromRead(value);
switch (this) {
case WINDOWED_W -> readWithMinimum(value, Layout.MIN_WINDOW_W);
case WINDOWED_H -> readWithMinimum(value, Layout.MIN_WINDOW_H);
case DEFAULT_CANVAS_W_PX, DEFAULT_CANVAS_H_PX,
CHECKERBOARD_W_PX, CHECKERBOARD_H_PX,
PIXEL_GRID_X_PX, PIXEL_GRID_Y_PX,
DEFAULT_TOOL_BREADTH -> readWithMinimum(value, 1);
default -> setting.setFromRead(value);
}
}

private void readWithMinimum(final String value, final int minimum) {
try {
final int dim = Integer.parseInt(value);

if (dim >= minimum)
setting.setFromRead(value);
} catch (NumberFormatException ignored) {

}
}
}

Expand Down
19 changes: 18 additions & 1 deletion src/com/jordanbunke/stipple_effect/visual/MenuAssembly.java
Original file line number Diff line number Diff line change
Expand Up @@ -642,11 +642,14 @@ public static Menu buildColorsMenu() {
samplerContentMap.put(SamplerMode.SV_MATRIX,
new MenuElementGrouping(matrix, mHue, mAlpha));

// color wheel
// color wheels
final int wheelWidth = contentWidthAllowance(
panelPos.x, pw, samplerStartingPos.x);
final ColorWheel wheel = new ColorWheel(samplerStartingPos,
new Bounds2D(wheelWidth, biggestIncY * 3));
final NormalMapSampler normalMap =
new NormalMapSampler(samplerStartingPos,
new Bounds2D(wheelWidth, biggestIncY * 3));

final Coord2D wValuePos = samplerStartingPos.displace(
0, wheel.getHeight()),
Expand All @@ -657,6 +660,20 @@ public static Menu buildColorsMenu() {
samplerContentMap.put(SamplerMode.COLOR_WHEEL,
new MenuElementGrouping(wheel, wValue, wAlpha));

final TextLabel quantLabel = TextLabel.make(
wValuePos.displace(0, DIALOG_CONTENT_INC_Y / 2), "Quantize");
final IncrementalRangeElements<Integer> q =
IncrementalRangeElements.makeForInt(quantLabel,
quantLabel.getY() + DIALOG_CONTENT_COMP_OFFSET_Y,
quantLabel.getY(), 1,
NormalMapSampler.NONE, NormalMapSampler.MAX,
normalMap::setQuantization, normalMap::getQuantization,
i -> i, i -> i, i -> "", "");

samplerContentMap.put(SamplerMode.NORMAL,
new MenuElementGrouping(normalMap, quantLabel,
q.decButton, q.incButton, q.slider, q.value, wAlpha));


// sampler manager
mb.add(new SamplerManager(samplerContentMap));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package com.jordanbunke.stipple_effect.visual.menu_elements.colors;

import com.jordanbunke.delta_time.image.GameImage;
import com.jordanbunke.delta_time.utility.math.Bounds2D;
import com.jordanbunke.delta_time.utility.math.Coord2D;
import com.jordanbunke.stipple_effect.StippleEffect;
import com.jordanbunke.stipple_effect.utility.Layout;
import com.jordanbunke.stipple_effect.utility.settings.Settings;
import com.jordanbunke.stipple_effect.visual.theme.SEColors;
import com.jordanbunke.stipple_effect.visual.theme.Theme;

import java.awt.*;

public abstract class AbstractColorMap extends TwoDimSampler {
private GameImage wheel;
final GameImage background;

final int radius;
final Coord2D localOffset, middle;

AbstractColorMap(final Coord2D position, final Bounds2D dimensions) {
super(position, dimensions);

final int w = dimensions.width(), h = dimensions.height(),
minDim = Math.min(w, h);
radius = (minDim / 2) - BUFFER_PX;

localOffset = new Coord2D(BUFFER_PX + ((w - minDim) / 2),
BUFFER_PX + ((h - minDim) / 2));
middle = localOffset.displace(radius, radius);

background = drawBackground();
updateAssets(StippleEffect.get().getSelectedColor());
}

void setWheel(final GameImage wheel) {
this.wheel = wheel;
}

@Override
final GameImage drawBackground() {
final Theme t = Settings.getTheme();
final int w = getWidth(),
h = getHeight();
final GameImage background = new GameImage(w, h);

final Color light = t.checkerboard1, dark = t.checkerboard2;

final int squareDim = Layout.SLIDER_OFF_DIM / 4;

for (int x = 0; x < w; x += squareDim) {
for (int y = 0; y < h; y += squareDim) {
final Color square = (x + y) % 2 == 0 ? light : dark;

background.fillRectangle(square, x, y, squareDim, squareDim);
}
}

for (int x = 0; x < w; x++)
for (int y = 0; y < h; y++)
if (Coord2D.unitDistanceBetween(middle,
new Coord2D(x, y)) >= radius)
background.setRGB(x, y, SEColors.transparent().getRGB());

return background.submit();
}

@Override
final void updateAssets(final Color c) {
final int w = getWidth(), h = getHeight(),
ew = getEffectiveWidth(), eh = getEffectiveHeight();
final GameImage wheel = new GameImage(w, h);

// border
final int ox = localOffset.x, oy = localOffset.y;
wheel.drawOval(Settings.getTheme().buttonOutline,
2f * BORDER_PX, ox, oy, ew, eh);

// background
wheel.draw(background);

// wheel
for (int x = ox; x < ox + ew; x++) {
for (int y = oy; y < oy + eh; y++) {
final Coord2D p = new Coord2D(x, y);

if (Coord2D.unitDistanceBetween(middle, p) > radius)
continue;

final Color pixel = getPixelColor(c, p);
wheel.dot(pixel, x, y);
}
}

// pointer
final Coord2D nodePos = getNodePos(c);
drawNode(wheel, nodePos.x, nodePos.y);

setWheel(wheel.submit());
}

@Override
final int getEffectiveWidth() {
return radius * 2;
}

@Override
final int getEffectiveHeight() {
return radius * 2;
}

@Override
public final void render(final GameImage canvas) {
draw(wheel, canvas);
}
}
Loading

0 comments on commit d8eb2f3

Please sign in to comment.