Skip to content

Commit

Permalink
Merge pull request #1 from connordelacruz/develop
Browse files Browse the repository at this point in the history
1.1 Updates
  • Loading branch information
connordelacruz authored Jun 15, 2021
2 parents 0fec414 + b12e8c6 commit 1e3732b
Show file tree
Hide file tree
Showing 7 changed files with 660 additions and 288 deletions.
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

0 comments on commit 1e3732b

Please sign in to comment.