diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..408914c4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,100 @@ +Stipple Effect - End-User License Agreement + +This End-User License Agreement ("EULA") is a legal agreement between you +(either an individual or a single entity) and Jordan Bunke (hereinafter +referred to as "Licensor"), for the software product(s) identified above +which may include associated software components, media, printed materials, +and "online" or electronic documentation ("SOFTWARE PRODUCT"). By installing, +copying, or otherwise using the SOFTWARE PRODUCT, you agree to be bound by the +terms of this EULA. This license agreement represents the entire agreement +concerning the program between You and the Licensor, and it supersedes any +prior proposal, representation, or understanding between the parties. If you +do not agree to the terms of this EULA, do not install or use the SOFTWARE PRODUCT. + +The SOFTWARE PRODUCT is protected by copyright laws and international +copyright treaties, as well as other intellectual property laws and treaties. +The SOFTWARE PRODUCT is licensed, not sold. + +1. GRANT OF LICENSE. +The SOFTWARE PRODUCT is licensed as follows: + +(a) Installation and Use. +The Licensor grants you the right to install and use copies of the SOFTWARE +PRODUCT on your computer running a validly licensed copy of the operating +system for which the SOFTWARE PRODUCT was designed. + +(b) Backup Copies. +You may also make copies of the SOFTWARE PRODUCT as may be necessary for +backup and archival purposes. + +2. DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS. + +(a) Maintenance of Copyright Notices. +You must not remove or alter any copyright notices on any and all copies of +the SOFTWARE PRODUCT. + +(b) Distribution. +You may not distribute copies of the SOFTWARE PRODUCT to third parties. +Pre-release versions of the SOFTWARE PRODUCT available for download free of +charge from the Licensor's websites may be freely distributed. + +(c) Prohibition on Reverse Engineering, Decompilation, and Disassembly. +You may not reverse engineer, decompile, or disassemble the SOFTWARE PRODUCT, +except and only to the extent that such activity is expressly permitted by +applicable law notwithstanding this limitation. + +(d) Rental. +You may not rent, lease, or lend the SOFTWARE PRODUCT. + +(e) Support Services. +The Licensor may provide you with support services related to the SOFTWARE +PRODUCT ("Support Services"). Any supplemental software code provided to you +as part of the Support Services shall be considered part of the SOFTWARE +PRODUCT and subject to the terms and conditions of this EULA. + +(f) Compliance with Applicable Laws. +You must comply with all applicable laws regarding use of the SOFTWARE PRODUCT. + +(g) Source code. +You may only compile and modify the source code of the SOFTWARE PRODUCT for +your own personal purpose or to propose a contribution to the SOFTWARE PRODUCT. + +3. TERMINATION +Without prejudice to any other rights, the Licensor may terminate this EULA +if you fail to comply with the terms and conditions of this EULA. In such +event, you must destroy all copies of the SOFTWARE PRODUCT in your possession. + +4. COPYRIGHT +All title, including but not limited to copyrights, in and to the SOFTWARE +PRODUCT and any copies thereof are owned by the Licensor or its suppliers. +All title and intellectual property rights in and to the content which may be +accessed through use of the SOFTWARE PRODUCT is the property of the respective +content owner and may be protected by applicable copyright or other +intellectual property laws and treaties. This EULA grants you no rights to use +such content. All rights not expressly granted are reserved by the Licensor. + +5. NO WARRANTIES +The Licensor expressly disclaims any warranty for the SOFTWARE PRODUCT. The +SOFTWARE PRODUCT is provided 'As Is' without any express or implied warranty +of any kind, including but not limited to any warranties of merchantability, +noninfringement, or fitness of a particular purpose. The Licensor does not +warrant or assume responsibility for the accuracy or completeness of any +information, text, graphics, links or other items contained within the +SOFTWARE PRODUCT. The Licensor makes no warranties respecting any harm that +may be caused by the transmission of a computer virus, worm, time bomb, logic +bomb, or other such computer program. The Licensor further expressly disclaims +any warranty or representation to Authorized Users or to any third party. + +6. LIMITATION OF LIABILITY +In no event shall the Licensor be liable for any damages (including, without +limitation, lost profits, business interruption, or lost information) rising +out of 'Authorized Users' use of or inability to use the SOFTWARE PRODUCT, +even if the Licensor has been advised of the possibility of such damages. In +no event will the Licensor be liable for loss of data or for indirect, +special, incidental, consequential (including lost profit), or other damages +based in contract, tort or otherwise. The Licensor shall have no liability +with respect to the content of the SOFTWARE PRODUCT or any part thereof, +including but not limited to errors or omissions contained therein, libel, +infringements of rights of publicity, privacy, trademark rights, business +interruption, personal injury, loss of privacy, moral rights or the disclosure +of confidential information. diff --git a/README.md b/README.md index 75ab1031..ea76be7a 100644 --- a/README.md +++ b/README.md @@ -49,3 +49,26 @@ _Stipple Effect_ supports scripting for three different use cases: **automation* * [Delta Time](https://github.com/jbunke/delta-time) - my lightweight graphics library that handles GUI and execution loop boilerplate * [ANTLR v4](https://github.com/antlr/antlr4) - lexing and parsing library that powers the _DeltaScript_ interpreter * [Animation Encoder](https://github.com/jbunke/animation-encoder) - my wrapper for Square's [gifencoder](https://github.com/square/gifencoder) and for [jcodec](https://github.com/jcodec/jcodec) + +## License + +*Stipple Effect* is distributed under an end-user license agreement (EULA). Read it [here](LICENSE) to understand your rights and responsibilities as a user. + +## Compile from source instructions + +For those who do not have the means to buy *Stipple Effect*, the program can be compiled from source for free: + +### Instructions + +1. Clone this repository +2. Download and configure external dependencies in your development environment + 1. **Delta Time**: [download JAR - instructions in README](https://github.com/jbunke/delta-time) + 2. **Animation Encoder**: [download JAR - instructions in README](https://github.com/jbunke/animation-encoder) + 3. **ANTLR v4**: *Stipple Effect* uses version 4.13.1 of the ANTLR 4 Runtime. You can download the library from the Maven Repository or configure it manually. Find the artifact's dependency information [here](https://mvnrepository.com/artifact/org.antlr/antlr4-runtime/4.13.1). +3. Set up the project and run configuration with the following details: + 1. **JRE / JDK / Language level**: Java 17 or later + 2. **Main class**: `com.jordanbunke.stipple_effect.StippleEffect` +4. Build and run in the Java development environment of your choice! + +### Note: +*Please keep in mind that you are liable to the terms of the EULA whether you buy the program or compile it from source.* diff --git a/changelog.md b/changelog.md index e96af333..5d4e8f74 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,15 @@ # Changelog +## **1.0.0** - Official Release - 2024-06-13 + +### Changed: +* Optimized Move Selection tool preview overlay +* Optimized selection overlay rendering +* Updated program logo + +### Fixed: +* Bug: Breadth tool overlays are not redrawn at a zoom level of 100% + ## **0.5.1** - 2024-06-12 ### Fixed: diff --git a/res/blurbs/__changelog.txt b/res/blurbs/__changelog.txt index 94076dca..1227c4bc 100644 --- a/res/blurbs/__changelog.txt +++ b/res/blurbs/__changelog.txt @@ -1,3 +1,13 @@ +{1.0.0} - Official Release - 2024-06-13 + +Changed: +> Optimized Move Selection tool preview overlay +> Optimized selection overlay rendering +> Updated program logo + +Fixed: +> Bug: Breadth tool overlays are not redrawn at a zoom level of 100% + {0.5.1} - 2024-06-12 Fixed: diff --git a/res/blurbs/script_brush.txt b/res/blurbs/script_brush.txt index b1fb53d9..e1ee197d 100644 --- a/res/blurbs/script_brush.txt +++ b/res/blurbs/script_brush.txt @@ -1,6 +1,6 @@ Shortcut: {Q} -The script brush paints applies a color script transformation to the pixel that it paints over. +The script brush applies a color script transformation to the pixel that it paints over. Use existing color as input: {Click & Drag} diff --git a/res/program b/res/program index d9d9ef62..25017fb7 100644 --- a/res/program +++ b/res/program @@ -1,5 +1,5 @@ name:{Stipple Effect} -version:{0.5.1} +version:{1.0.0} devbuild:{false} native_standard:{1.2} palette_standard:{1.0} diff --git a/res/splash/logo_anim_0.png b/res/splash/logo_anim_0.png index c3be31d3..b6fe46fb 100644 Binary files a/res/splash/logo_anim_0.png and b/res/splash/logo_anim_0.png differ diff --git a/res/splash/logo_anim_1.png b/res/splash/logo_anim_1.png index 822fb6c3..6a3e3471 100644 Binary files a/res/splash/logo_anim_1.png and b/res/splash/logo_anim_1.png differ diff --git a/res/splash/logo_anim_10.png b/res/splash/logo_anim_10.png index aaf48be5..21fbfb08 100644 Binary files a/res/splash/logo_anim_10.png and b/res/splash/logo_anim_10.png differ diff --git a/res/splash/logo_anim_11.png b/res/splash/logo_anim_11.png index 84983419..de8ad218 100644 Binary files a/res/splash/logo_anim_11.png and b/res/splash/logo_anim_11.png differ diff --git a/res/splash/logo_anim_12.png b/res/splash/logo_anim_12.png index 79576bf3..f8950093 100644 Binary files a/res/splash/logo_anim_12.png and b/res/splash/logo_anim_12.png differ diff --git a/res/splash/logo_anim_13.png b/res/splash/logo_anim_13.png index aa66682a..1644efa6 100644 Binary files a/res/splash/logo_anim_13.png and b/res/splash/logo_anim_13.png differ diff --git a/res/splash/logo_anim_14.png b/res/splash/logo_anim_14.png index 5a5a00ba..fef6b8fc 100644 Binary files a/res/splash/logo_anim_14.png and b/res/splash/logo_anim_14.png differ diff --git a/res/splash/logo_anim_15.png b/res/splash/logo_anim_15.png index c09abf43..49be3c8a 100644 Binary files a/res/splash/logo_anim_15.png and b/res/splash/logo_anim_15.png differ diff --git a/res/splash/logo_anim_16.png b/res/splash/logo_anim_16.png index 3c43001e..393705b6 100644 Binary files a/res/splash/logo_anim_16.png and b/res/splash/logo_anim_16.png differ diff --git a/res/splash/logo_anim_17.png b/res/splash/logo_anim_17.png index f73423dc..065cfcaf 100644 Binary files a/res/splash/logo_anim_17.png and b/res/splash/logo_anim_17.png differ diff --git a/res/splash/logo_anim_18.png b/res/splash/logo_anim_18.png index 3e8b4cb8..9517e5f1 100644 Binary files a/res/splash/logo_anim_18.png and b/res/splash/logo_anim_18.png differ diff --git a/res/splash/logo_anim_19.png b/res/splash/logo_anim_19.png index 1b1cf81d..3d0bae6d 100644 Binary files a/res/splash/logo_anim_19.png and b/res/splash/logo_anim_19.png differ diff --git a/res/splash/logo_anim_2.png b/res/splash/logo_anim_2.png index c28603e0..8ef2eef3 100644 Binary files a/res/splash/logo_anim_2.png and b/res/splash/logo_anim_2.png differ diff --git a/res/splash/logo_anim_20.png b/res/splash/logo_anim_20.png index abea0044..14fdbfb1 100644 Binary files a/res/splash/logo_anim_20.png and b/res/splash/logo_anim_20.png differ diff --git a/res/splash/logo_anim_21.png b/res/splash/logo_anim_21.png index ce57d506..868d65e8 100644 Binary files a/res/splash/logo_anim_21.png and b/res/splash/logo_anim_21.png differ diff --git a/res/splash/logo_anim_22.png b/res/splash/logo_anim_22.png index 315e1981..3e0a5b82 100644 Binary files a/res/splash/logo_anim_22.png and b/res/splash/logo_anim_22.png differ diff --git a/res/splash/logo_anim_23.png b/res/splash/logo_anim_23.png index 51b0b65e..8fe28e93 100644 Binary files a/res/splash/logo_anim_23.png and b/res/splash/logo_anim_23.png differ diff --git a/res/splash/logo_anim_24.png b/res/splash/logo_anim_24.png index 4f5b796c..1f809355 100644 Binary files a/res/splash/logo_anim_24.png and b/res/splash/logo_anim_24.png differ diff --git a/res/splash/logo_anim_3.png b/res/splash/logo_anim_3.png index 49e3b220..3f07b5c0 100644 Binary files a/res/splash/logo_anim_3.png and b/res/splash/logo_anim_3.png differ diff --git a/res/splash/logo_anim_4.png b/res/splash/logo_anim_4.png index 3de99b6a..7b6ae674 100644 Binary files a/res/splash/logo_anim_4.png and b/res/splash/logo_anim_4.png differ diff --git a/res/splash/logo_anim_5.png b/res/splash/logo_anim_5.png index 014d363c..e3aef40c 100644 Binary files a/res/splash/logo_anim_5.png and b/res/splash/logo_anim_5.png differ diff --git a/res/splash/logo_anim_6.png b/res/splash/logo_anim_6.png index 99dc3858..c0320816 100644 Binary files a/res/splash/logo_anim_6.png and b/res/splash/logo_anim_6.png differ diff --git a/res/splash/logo_anim_7.png b/res/splash/logo_anim_7.png index 4e8bd62a..7128cc40 100644 Binary files a/res/splash/logo_anim_7.png and b/res/splash/logo_anim_7.png differ diff --git a/res/splash/logo_anim_8.png b/res/splash/logo_anim_8.png index 09323bea..5000230c 100644 Binary files a/res/splash/logo_anim_8.png and b/res/splash/logo_anim_8.png differ diff --git a/res/splash/logo_anim_9.png b/res/splash/logo_anim_9.png index c3b4a953..1bbbd3b3 100644 Binary files a/res/splash/logo_anim_9.png and b/res/splash/logo_anim_9.png differ diff --git a/src/com/jordanbunke/stipple_effect/project/RenderInfo.java b/src/com/jordanbunke/stipple_effect/project/RenderInfo.java index 726aaf9c..3144b98b 100644 --- a/src/com/jordanbunke/stipple_effect/project/RenderInfo.java +++ b/src/com/jordanbunke/stipple_effect/project/RenderInfo.java @@ -53,7 +53,7 @@ private void adjustAnchorFromZoom( public void setZoomLevel(final ZoomLevel zoomLevel) { final boolean redrawOverlays = this.zoomLevel != zoomLevel && - zoomLevel.z > Constants.ZOOM_FOR_OVERLAY; + zoomLevel.z >= Constants.ZOOM_FOR_OVERLAY; this.zoomLevel = zoomLevel; diff --git a/src/com/jordanbunke/stipple_effect/selection/SelectionOverlay.java b/src/com/jordanbunke/stipple_effect/selection/SelectionOverlay.java index 604a0c97..63dec8d1 100644 --- a/src/com/jordanbunke/stipple_effect/selection/SelectionOverlay.java +++ b/src/com/jordanbunke/stipple_effect/selection/SelectionOverlay.java @@ -8,17 +8,13 @@ import com.jordanbunke.stipple_effect.visual.GraphicsUtils; import java.awt.*; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Function; -import java.util.function.Predicate; public final class SelectionOverlay { private static final int TL = 0, BR = 1, DIM = 2, TRP = 3, BOUNDS = 4; + private static final short INIT = 1, + L_PRM = 3, R_PRM = 5, T_PRM = 7, B_PRM = 11; - // directional frontiers - private final Set left, right, top, bottom; + private final short[][] frontier; private final GameImage filled; private Coord2D tl; private final int w, h; @@ -41,30 +37,34 @@ public SelectionOverlay(final Selection selection) { lastWW = 0; lastWH = 0; - left = new HashSet<>(); - right = new HashSet<>(); - top = new HashSet<>(); - bottom = new HashSet<>(); - tl = selection.topLeft; w = selection.bounds.width(); h = selection.bounds.height(); + final int fillC = Settings.getTheme().selectionFill.getRGB(); filled = new GameImage(w, h); - final Color fillC = Settings.getTheme().selectionFill; - filled.setColor(fillC); - - selection.unboundedPixelAlgorithm((x, y) -> { - final Coord2D px = new Coord2D(x, y); - - if (!selection.selected(x - 1, y)) left.add(px); - if (!selection.selected(x + 1, y)) right.add(px); - if (!selection.selected(x, y - 1)) top.add(px); - if (!selection.selected(x, y + 1)) bottom.add(px); - - filled.dot(x - tl.x, y - tl.y); - }); + frontier = new short[w][h]; + + for (int x = 0; x < w; x++) + for (int y = 0; y < h; y++) { + frontier[x][y] = INIT; + + final int px = tl.x + x, py = tl.y + y; + + if (selection.selected(px, py)) { + filled.setRGB(x, y, fillC); + + if (!selection.selected(px - 1, py)) + frontier[x][y] *= L_PRM; + if (!selection.selected(px + 1, py)) + frontier[x][y] *= R_PRM; + if (!selection.selected(px, py - 1)) + frontier[x][y] *= T_PRM; + if (!selection.selected(px, py + 1)) + frontier[x][y] *= B_PRM; + } + } filled.free(); } @@ -72,20 +72,6 @@ public SelectionOverlay(final Selection selection) { public void updateTL(final Selection selection) { lastTL = tl; tl = selection.topLeft; - - if (!lastTL.equals(tl)) { - final Coord2D displacement = new Coord2D( - tl.x - lastTL.x, tl.y - lastTL.y); - - final List> dirs = List.of(left, right, top, bottom); - - for (Set dir : dirs) { - final Set bank = new HashSet<>(dir); - dir.clear(); - - bank.forEach(p -> dir.add(p.displace(displacement))); - } - } } public GameImage draw( @@ -124,39 +110,32 @@ public GameImage draw( outside = Settings.getTheme().highlightOutline; final int zint = (int) z; - final Predicate inBounds = p -> { - final Coord2D adj = p.displace(-tl.x, -tl.y); - - return adj.x >= bounds[TL].x && adj.y >= bounds[TL].y && - adj.x <= bounds[BR].x && adj.y <= bounds[BR].y; - }; - final Function renderCoord = c -> - render.displace(c.x * zint, c.y * zint); - - left.stream().filter(inBounds).forEach(p -> { - final Coord2D c = renderCoord.apply(p); - - overlay.fillRectangle(inside, c.x, c.y, 1, zint); - overlay.fillRectangle(outside, c.x - 1, c.y, 1, zint); - }); - right.stream().filter(inBounds).forEach(p -> { - final Coord2D c = renderCoord.apply(p).displace(zint, 0); - - overlay.fillRectangle(inside, c.x - 1, c.y, 1, zint); - overlay.fillRectangle(outside, c.x, c.y, 1, zint); - }); - top.stream().filter(inBounds).forEach(p -> { - final Coord2D c = renderCoord.apply(p); - - overlay.fillRectangle(inside, c.x, c.y, zint, 1); - overlay.fillRectangle(outside, c.x, c.y - 1, zint, 1); - }); - bottom.stream().filter(inBounds).forEach(p -> { - final Coord2D c = renderCoord.apply(p).displace(0, zint); - - overlay.fillRectangle(inside, c.x, c.y - 1, zint, 1); - overlay.fillRectangle(outside, c.x, c.y, zint, 1); - }); + + for (int x = bounds[TL].x; x < bounds[BR].x; x++) { + for (int y = bounds[TL].y; y < bounds[BR].y; y++) { + final int px = tl.x + x, py = tl.y + y; + final Coord2D c = render.displace(px * zint, py * zint); + + final short fp = frontier[x][y]; + + if (fp % L_PRM == 0) { + overlay.fillRectangle(inside, c.x, c.y, 1, zint); + overlay.fillRectangle(outside, c.x - 1, c.y, 1, zint); + } + if (fp % R_PRM == 0) { + overlay.fillRectangle(inside, c.x + zint - 1, c.y, 1, zint); + overlay.fillRectangle(outside, c.x + zint, c.y, 1, zint); + } + if (fp % T_PRM == 0) { + overlay.fillRectangle(inside, c.x, c.y, zint, 1); + overlay.fillRectangle(outside, c.x, c.y - 1, zint, 1); + } + if (fp % B_PRM == 0) { + overlay.fillRectangle(inside, c.x, c.y + zint - 1, zint, 1); + overlay.fillRectangle(outside, c.x, c.y + zint, zint, 1); + } + } + } if (canTransform) { final GameImage NODE = GraphicsUtils.TRANSFORM_NODE; diff --git a/src/com/jordanbunke/stipple_effect/tools/MoveSelection.java b/src/com/jordanbunke/stipple_effect/tools/MoveSelection.java index 46c27159..55d0aa06 100644 --- a/src/com/jordanbunke/stipple_effect/tools/MoveSelection.java +++ b/src/com/jordanbunke/stipple_effect/tools/MoveSelection.java @@ -12,8 +12,6 @@ import com.jordanbunke.stipple_effect.visual.theme.Theme; import java.awt.*; -import java.util.HashSet; -import java.util.Set; public final class MoveSelection extends MoverTool { private static final MoveSelection INSTANCE; @@ -81,7 +79,8 @@ GameImage updateToolContentPreview( final GameImage toolContentPreview = new GameImage(w, h); - final Set frontier = new HashSet<>(); + final Theme t = Settings.getTheme(); + final Color fill = t.highlightOverlay, outline = t.highlightOutline; transformation.pixelAlgorithm(w, h, (x, y) -> { final boolean @@ -94,16 +93,11 @@ GameImage updateToolContentPreview( bl = !transformation.selected(x - 1, y + 1), br = !transformation.selected(x + 1, y + 1); - if (left || right || top || bottom || tl || tr || bl || br) - frontier.add(new Coord2D(x, y)); - }); + final boolean frontier = left || right || top || bottom || + tl || tr || bl || br; - final Theme t = Settings.getTheme(); - final Color fill = t.highlightOverlay, outline = t.highlightOutline; - - transformation.pixelAlgorithm(w, h, - (x, y) -> toolContentPreview.dot(fill, x, y)); - frontier.forEach(p -> toolContentPreview.dot(outline, p.x, p.y)); + toolContentPreview.setRGB(x, y, (frontier ? outline : fill).getRGB()); + }); return toolContentPreview.submit(); } diff --git a/src/com/jordanbunke/stipple_effect/visual/DialogAssembly.java b/src/com/jordanbunke/stipple_effect/visual/DialogAssembly.java index 895f9020..dee5fea6 100644 --- a/src/com/jordanbunke/stipple_effect/visual/DialogAssembly.java +++ b/src/com/jordanbunke/stipple_effect/visual/DialogAssembly.java @@ -1958,7 +1958,7 @@ public static void setDialogToSplashScreen() { // subtitle final GameImage subtitle = GraphicsUtils.uiText(t.splashText) .addText(t.subtitle).addLineBreak() - .addText("Jordan Bunke, 2023-2024") + .addText("Copyright (c) 2023-2024 Jordan Bunke") .build().draw(); mb.add(new StaticMenuElement(new Coord2D(w / 2, h - (version.getHeight() * 2)),