Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.1 Updates #1

Merged
merged 14 commits into from
Jun 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions ChannelShiftGUI.pde
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import g4p_controls.*;

// Input File ------------------------------------------------------------------
// Default image to load on start
String defaultImgName = "test1";
String defaultImgName = "test" + int(random(0,2));
String defaultImgPath = "demo/" + defaultImgName + ".jpg";

// Globals =====================================================================
Expand Down Expand Up @@ -53,19 +53,17 @@ void shiftChannel(PImage sourceImg, PImage targetImg, int xShift, int yShift, in
for (int x = 0; x < targetImg.width; x++) {
int yOffset = mod(shiftTypeManager.calculateShiftOffset(x, y, targetImg.width, targetImg.height, yShift, false), targetImg.height);
int xOffset = mod(shiftTypeManager.calculateShiftOffset(x, y, targetImg.width, targetImg.height, xShift, true), targetImg.width);

// Get source pixel and its RGB vals
int sourceIndex = yOffset * sourceImg.width + xOffset;
color sourcePixel = sourcePixels[sourceIndex];
float[] sourceRGB = new float[]{ red(sourcePixel), green(sourcePixel), blue(sourcePixel) };

// Get target pixel and its RGB vals
int targetIndex = y * targetImg.width + x;
color targetPixel = targetPixels[targetIndex];
float[] targetRGB = new float[]{ red(targetPixel), green(targetPixel), blue(targetPixel) };

// Swap source channel w/ target channel
targetRGB[targetChannel] = sourceRGB[sourceChannel];
// TODO !!! targetRGB[sourceChannel] = sourceRGB[targetChannel] ???
targetPixels[targetIndex] = color(targetRGB[0], targetRGB[1], targetRGB[2]);
}
}
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2019 Connor de la Cruz
Copyright (c) 2021 Connor de la Cruz

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ manipulating RGB color channels.
* [XY Multiply](#xy-multiply)
* [Options](#options-3)
* [Shift Calculation](#shift-calculation-3)
* [Noise](#noise)
* [Options](#options-4)
* [Shift Calculation](#shift-calculation-4)

<!-- vim-markdown-toc -->

Expand Down Expand Up @@ -368,3 +371,39 @@ Where:
corresponding dimension


### Noise

![Noise shift type](../assets/samples/noise.png?raw=true)

Apply [Perlin noise](https://en.wikipedia.org/wiki/Perlin_noise) to the shift amount.

#### Options

- **X Start:** Starting value for x noise
- **Y Start:** Starting value for y noise
- **X Step:** Amount to increment x by each time `noise()` is called. Use a smaller number for smoother results
- **Y Step:** Amount to increment y by each time `noise()` is called. Use a smaller number for smoother results
- **Noise Multiplier:** Value to multiply result of `noise()` by. Higher values create more drastic effects

#### Shift Calculation

**Horizontal Offset:**

```
x + shift + (int)(noiseMultiplier * noise(xNoise, yNoise))
```

**Vertical Offset:**


```
y + shift + (int)(noiseMultiplier * noise(xNoise, yNoise))
```

Where:

- `x` and `y`: the coordinates of the pixel
- `shift`: the horizontal/vertical shift amount
- `noiseMultiplier`: the noise multiplier value
- `xNoise` and `yNoise`: noise coordinates, calculated by adding offset to start value each time the corresponding coordinate (`x` or `y`) is incremented

232 changes: 80 additions & 152 deletions advanced.pde
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,26 @@
// Globals, logic, and event handlers related to advanced shift type options
// =============================================================================

// Constants ===================================================================

// GLOBALS =====================================================================
// Names of different shift types
String[] SHIFT_TYPES = new String[]{"Default", "Scale", "Linear", "Skew", "XY Multiply"};
String[] SHIFT_TYPES = new String[]{"Default", "Scale", "Linear", "Skew", "XY Multiply", "Noise"};
// Indexes
int TYPE_DEFAULT = 0;
int TYPE_SCALE = 1;
int TYPE_LINEAR = 2;
int TYPE_SKEW = 3;
int TYPE_XYMULT = 4;
int TYPE_NOISE = 5;
// Total # of shift types
int TOTAL_SHIFT_TYPES = SHIFT_TYPES.length;


// Manager/State Classes =======================================================
// SHIFT TYPES =================================================================

// Shift Type Interface --------------------------------------------------------

public interface ShiftTypeState {
// TODO add public String typeName
// Calculate offset for this shift type
public int calculateShiftOffset(int x, int y, int width, int height, int shift, boolean horizontal);
// String representation of this step
Expand All @@ -45,7 +46,6 @@ public class DefaultShiftType implements ShiftTypeState {
public class ScaleShiftType implements ShiftTypeState {
// Multiplier values specific to this shift type
public float xMultiplier, yMultiplier;
// TODO negative multipliers?

public ScaleShiftType(float xMult, float yMult) {
xMultiplier = xMult;
Expand Down Expand Up @@ -213,7 +213,6 @@ public class XYMultShiftType implements ShiftTypeState {
this(true, true, false, true);
}

// TODO flip divisor? (w/o dividing by 0)
public int calculateShiftOffset(int x, int y, int width, int height, int shift, boolean horizontal) {
if (horizontal)
return x + shift + (multX ? (int)(xSign*x*y / height) : 0);
Expand Down Expand Up @@ -243,7 +242,52 @@ public class XYMultShiftType implements ShiftTypeState {
public boolean isPositiveY() { return ySign > 0.0; }
}

// Manager ---------------------------------------------------------------------
// Noise -----------------------------------------------------------------------

public class NoiseShiftType implements ShiftTypeState {
public float xNoiseStart, yNoiseStart;
public float xNoiseIncrement, yNoiseIncrement;
public float noiseMultiplier;

// TODO: noiseSeed??
public NoiseShiftType(float xNoiseStart, float yNoiseStart, float xNoiseIncrement, float yNoiseIncrement, float noiseMultiplier) {
this.xNoiseStart = xNoiseStart;
this.yNoiseStart = yNoiseStart;
this.xNoiseIncrement = xNoiseIncrement;
this.yNoiseIncrement = yNoiseIncrement;
this.noiseMultiplier = noiseMultiplier;
}

public NoiseShiftType() {
this(0.01, 0.01, 0.01, 0.01, 20.0);
}

public int calculateShiftOffset(int x, int y, int width, int height, int shift, boolean horizontal) {
float xNoise = xNoiseStart + (xNoiseIncrement * x);
float yNoise = yNoiseStart + (yNoiseIncrement * y);
return (horizontal ? x : y) + shift + (int)(noiseMultiplier * noise(xNoise, yNoise));
}

public String stringifyStep() {
String step = "-noise-x" + xNoiseStart + "+" + xNoiseIncrement + "-y" + yNoiseStart + "+" + yNoiseIncrement + "mult" + noiseMultiplier;
return step;
}

// Setters
public void setXNoiseStart(float val) { xNoiseStart = val; }
public void setYNoiseStart(float val) { yNoiseStart = val; }
public void setXNoiseIncrement(float val) { xNoiseIncrement = val; }
public void setYNoiseIncrement(float val) { yNoiseIncrement = val; }
public void setNoiseMultiplier(float val) { noiseMultiplier = val; }
// Getters
public float getXNoiseStart() { return xNoiseStart; }
public float getYNoiseStart() { return yNoiseStart; }
public float getXNoiseIncrement() { return xNoiseIncrement; }
public float getYNoiseIncrement() { return yNoiseIncrement; }
public float getNoiseMultiplier() { return noiseMultiplier; }
}

// Manager =====================================================================

public class ShiftTypeManager {
// Array of state objects
Expand All @@ -259,6 +303,7 @@ public class ShiftTypeManager {
shiftTypes[TYPE_LINEAR] = new LinearShiftType();
shiftTypes[TYPE_SKEW] = new SkewShiftType();
shiftTypes[TYPE_XYMULT] = new XYMultShiftType();
shiftTypes[TYPE_NOISE] = new NoiseShiftType();
// Start w/ default
state = TYPE_DEFAULT;
}
Expand Down Expand Up @@ -346,154 +391,37 @@ public class ShiftTypeManager {
return ((XYMultShiftType)shiftTypes[TYPE_XYMULT]).isPositiveY();
}

}


// Event Handlers ==============================================================

// Shift Type ------------------------------------------------------------------

public void shiftTypeSelect_change(GDropList source, GEvent event) {
// Hide previously selected panel
hideShiftTypePanel(shiftTypeConfigPanels[shiftTypeManager.state]);
shiftTypeManager.setShiftType(source.getSelectedIndex());
// Show newly selected panel
showShiftTypePanel(shiftTypeConfigPanels[shiftTypeManager.state]);
showPreview();
}

// Scale Configs ---------------------------------------------------------------

void multiplierInputEventHandler(GTextField source, GEvent event, boolean horizontal) {
switch(event) {
case ENTERED:
// Unfocus on enter, then do same actions as LOST_FOCUS case
source.setFocus(false);
case LOST_FOCUS:
// Sanitize and update manager
float val = sanitizeFloatInputValue(source);
if (val > -1.0) {
shiftTypeManager.scale_setMultiplier(val, horizontal);
showPreview();
}
// Update input text to match sanitized input
// Also reverts input text in the event that it was not a valid numeric
// value after parsing
source.setText("" + shiftTypeManager.scale_getMultiplier(horizontal));
break;
default:
break;
// Noise
public void noise_setXNoiseStart(float val) {
((NoiseShiftType)shiftTypes[TYPE_NOISE]).setXNoiseStart(val);
}
}

public void xMultiplierInput_change(GTextField source, GEvent event) {
multiplierInputEventHandler(source, event, true);
}

public void yMultiplierInput_change(GTextField source, GEvent event) {
multiplierInputEventHandler(source, event, false);
}

// Linear Configs --------------------------------------------------------------

public void linearYEquals_clicked(GOption source, GEvent event) {
shiftTypeManager.linear_setEquationType(true);
showPreview();
}

public void linearXEquals_clicked(GOption source, GEvent event) {
shiftTypeManager.linear_setEquationType(false);
showPreview();
}

public void linearCoeffInput_change(GTextField source, GEvent event) {
switch(event) {
case ENTERED:
// Unfocus on enter, then do same actions as LOST_FOCUS case
source.setFocus(false);
case LOST_FOCUS:
// Sanitize and update manager
float val = sanitizeFloatInputValue(source);
if (val > -1.0) {
shiftTypeManager.linear_setCoefficient(val);
showPreview();
}
// Update input text to match sanitized input
// Also reverts input text in the event that it was not a valid numeric
// value after parsing
source.setText("" + shiftTypeManager.linear_getCoefficient());
break;
default:
break;
public float noise_xNoiseStart() {
return ((NoiseShiftType)shiftTypes[TYPE_NOISE]).getXNoiseStart();
}
}

public void linearNegativeCoeffCheckbox_click(GCheckbox source, GEvent event) {
shiftTypeManager.linear_setCoefficientSign(!source.isSelected());
showPreview();
}

// Skew Configs ----------------------------------------------------------------

void skewInputEventHandler(GTextField source, GEvent event, boolean horizontal) {
switch(event) {
case ENTERED:
// Unfocus on enter, then do same actions as LOST_FOCUS case
source.setFocus(false);
case LOST_FOCUS:
// Sanitize and update manager
float val = sanitizeFloatInputValue(source);
if (val > -1.0) {
shiftTypeManager.skew_setSkew(val, horizontal);
showPreview();
}
// Update input text to match sanitized input
// Also reverts input text in the event that it was not a valid numeric
// value after parsing
source.setText("" + shiftTypeManager.skew_getSkew(horizontal));
break;
default:
break;
public void noise_setYNoiseStart(float val) {
((NoiseShiftType)shiftTypes[TYPE_NOISE]).setYNoiseStart(val);
}
public float noise_yNoiseStart() {
return ((NoiseShiftType)shiftTypes[TYPE_NOISE]).getYNoiseStart();
}
public void noise_setXNoiseIncrement(float val) {
((NoiseShiftType)shiftTypes[TYPE_NOISE]).setXNoiseIncrement(val);
}
public float noise_xNoiseIncrement() {
return ((NoiseShiftType)shiftTypes[TYPE_NOISE]).getXNoiseIncrement();
}
public void noise_setYNoiseIncrement(float val) {
((NoiseShiftType)shiftTypes[TYPE_NOISE]).setYNoiseIncrement(val);
}
public float noise_yNoiseIncrement() {
return ((NoiseShiftType)shiftTypes[TYPE_NOISE]).getYNoiseIncrement();
}
public void noise_setNoiseMultiplier(float val) {
((NoiseShiftType)shiftTypes[TYPE_NOISE]).setNoiseMultiplier(val);
}
public float noise_noiseMultiplier() {
return ((NoiseShiftType)shiftTypes[TYPE_NOISE]).getNoiseMultiplier();
}
}

public void xSkewInput_change(GTextField source, GEvent event) {
skewInputEventHandler(source, event, true);
}

public void xSkewNegativeCheckbox_click(GCheckbox source, GEvent event) {
shiftTypeManager.skew_setSign(!source.isSelected(), true);
showPreview();
}

public void ySkewInput_change(GTextField source, GEvent event) {
skewInputEventHandler(source, event, false);
}

public void ySkewNegativeCheckbox_click(GCheckbox source, GEvent event) {
shiftTypeManager.skew_setSign(!source.isSelected(), false);
showPreview();
}

// X*Y Configs -----------------------------------------------------------------

public void multXCheckbox_click(GCheckbox source, GEvent event) {
shiftTypeManager.xymult_setMultX(source.isSelected());
showPreview();
}

public void multXNegativeCheckbox_click(GCheckbox source, GEvent event) {
shiftTypeManager.xymult_setXSign(!source.isSelected());
showPreview();
}

public void multYCheckbox_click(GCheckbox source, GEvent event) {
shiftTypeManager.xymult_setMultY(source.isSelected());
showPreview();
}

public void multYNegativeCheckbox_click(GCheckbox source, GEvent event) {
shiftTypeManager.xymult_setYSign(!source.isSelected());
showPreview();
}

Binary file modified code/G4P.jar
Binary file not shown.
Loading