code style and arrangement change

This commit is contained in:
DaniTheSkunk 2022-11-22 22:10:56 +00:00
parent 7339ca69a7
commit 45344c589c
53 changed files with 1703 additions and 1447 deletions

View File

@ -4,6 +4,10 @@
<option name="RIGHT_MARGIN" value="80" />
<option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="true" />
<option name="ENABLE_SECOND_REFORMAT" value="true" />
<JavaCodeStyleSettings>
<option name="ANNOTATION_PARAMETER_WRAP" value="5" />
<option name="NEW_LINE_AFTER_LPAREN_IN_ANNOTATION" value="true" />
</JavaCodeStyleSettings>
<editorconfig>
<option name="ENABLED" value="false" />
</editorconfig>
@ -26,12 +30,301 @@
<option name="PARENTHESES_EXPRESSION_LPAREN_WRAP" value="true" />
<option name="PARENTHESES_EXPRESSION_RPAREN_WRAP" value="true" />
<option name="BINARY_OPERATION_WRAP" value="5" />
<option name="FOR_STATEMENT_WRAP" value="5" />
<option name="FOR_STATEMENT_RPAREN_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
<option name="WRAP_LONG_LINES" value="true" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
<arrangement>
<groups />
<rules>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PUBLIC>true</PUBLIC>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PROTECTED>true</PROTECTED>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PRIVATE>true</PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PUBLIC>true</PUBLIC>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PROTECTED>true</PROTECTED>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PRIVATE>true</PRIVATE>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
<STATIC>true</STATIC>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PUBLIC>true</PUBLIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PROTECTED>true</PROTECTED>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<FINAL>true</FINAL>
<PRIVATE>true</PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PUBLIC>true</PUBLIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PROTECTED>true</PROTECTED>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PACKAGE_PRIVATE>true</PACKAGE_PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<FIELD>true</FIELD>
<PRIVATE>true</PRIVATE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<FIELD>true</FIELD>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<INITIALIZER_BLOCK>true</INITIALIZER_BLOCK>
</match>
</rule>
</section>
<section>
<rule>
<match>
<CONSTRUCTOR>true</CONSTRUCTOR>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<METHOD>true</METHOD>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<METHOD>true</METHOD>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<ENUM>true</ENUM>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<INTERFACE>true</INTERFACE>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<CLASS>true</CLASS>
<STATIC>true</STATIC>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<CLASS>true</CLASS>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="Markdown">
<option name="RIGHT_MARGIN" value="60" />

View File

@ -13,13 +13,13 @@ import com.danitheskunk.skunkworks.nodes.NodeRoot;
import org.lwjgl.glfw.GLFW;
public abstract class BaseGame {
protected Engine engine;
protected AudioEngine audioEngine;
protected IFont debugFont;
protected Engine engine;
protected Mixer mixer;
protected NodeRoot rootNode;
protected SamplePlayer samplePlayer;
protected IWindow window;
protected IFont debugFont;
protected NodeRoot rootNode;
public BaseGame(Vec2i windowSize, String windowTitle) {
this.audioEngine = new AudioEngine(44100, 256, 8);
@ -36,6 +36,39 @@ public abstract class BaseGame {
init();
}
protected void init() {
}
protected ISample loadSample(String path) {
return audioEngine.loadSample(path);
}
protected ITexture loadTexture(String path) {
return window.loadTexture(path);
}
protected void playSample(ISample sample) {
samplePlayer.play(sample);
}
protected void playSample(ISample sample, boolean looping) {
samplePlayer.play(sample, looping);
}
protected void render(IRenderContext rc) {
//rc.drawString(new Vec2i(8, 8), "Welcome to Skunkworks, please
// overide the render method to get started", debugFont, Color
// .LIGHT_GRAY);
}
protected void render3D(IRenderContext3D rc3d) {
}
protected void renderPre(IRenderContext rc) {
}
public void run() {
double lastTime, currentTime, delta;
@ -63,40 +96,7 @@ public abstract class BaseGame {
}
}
protected void render3D(IRenderContext3D rc3d) {
}
protected void init() {
}
protected void renderPre(IRenderContext rc) {
}
protected void render(IRenderContext rc) {
//rc.drawString(new Vec2i(8, 8), "Welcome to Skunkworks, please
// overide the render method to get started", debugFont, Color
// .LIGHT_GRAY);
}
protected void update(double delta) {
}
protected ISample loadSample(String path) {
return audioEngine.loadSample(path);
}
protected void playSample(ISample sample) {
samplePlayer.play(sample);
}
protected void playSample(ISample sample, boolean looping) {
samplePlayer.play(sample, looping);
}
protected ITexture loadTexture(String path) {
return window.loadTexture(path);
}
}

View File

@ -20,6 +20,13 @@ abstract public class BaseWindow implements IWindow {
return engine;
}
@Override
public IFont loadFontTTF(String path, float size) {
var bytes = engine.loadBytes(path);
return new FontTTF(bytes, size, this);
}
@Override
public IFont loadFontTileset(String path) {
var img = engine.loadImage(path);
@ -29,13 +36,6 @@ abstract public class BaseWindow implements IWindow {
return new FontTileset(tex);
}
@Override
public IFont loadFontTTF(String path, float size) {
var bytes = engine.loadBytes(path);
return new FontTTF(bytes, size, this);
}
@Override
public NineSlice loadNineSlice(Image image) {
int x1 = -1;
@ -73,34 +73,29 @@ abstract public class BaseWindow implements IWindow {
}
var tl = image.getSubImage(new Recti(1, 1, x1 - 1, y1 - 1));
var top = image.getSubImage(new Recti(x1, 1, x2 - x1, y1 - 1));
var tr = image.getSubImage(new Recti(
x2,
var tr = image.getSubImage(new Recti(x2,
1,
image.getWidth() - x2,
y1 - 1
));
var left = image.getSubImage(new Recti(1, y1, x1 - 1, y2 - y1));
var center = image.getSubImage(new Recti(x1, y1, x2 - x1, y2 - y1));
var right = image.getSubImage(new Recti(
x2,
var right = image.getSubImage(new Recti(x2,
y1,
image.getWidth() - x2,
y2 - y1
));
var bl = image.getSubImage(new Recti(
1,
var bl = image.getSubImage(new Recti(1,
y2,
x1 - 1,
image.getHeight() - y2
));
var bottom = image.getSubImage(new Recti(
x1,
var bottom = image.getSubImage(new Recti(x1,
y2,
x2 - x1,
image.getHeight() - y2
));
var br = image.getSubImage(new Recti(
x2,
var br = image.getSubImage(new Recti(x2,
y2,
image.getWidth() - x2,
image.getHeight() - y2

View File

@ -1,16 +1,13 @@
package com.danitheskunk.skunkworks;
import java.io.BufferedInputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
public class Data {
private LinkedHashMap<String, LinkedHashMap<String, String>> data;
private String currentCategory;
private Runnable callback;
private String currentCategory;
private final LinkedHashMap<String, LinkedHashMap<String, String>> data;
public Data(ByteBuffer data) {
this.data = new LinkedHashMap<>();
@ -19,13 +16,8 @@ public class Data {
StandardCharsets.UTF_8.decode(data).toString().lines().forEach(this::processLine);
}
public void reload(ByteBuffer data) {
this.data.clear();
this.data.put("", new LinkedHashMap<>());
StandardCharsets.UTF_8.decode(data).toString().lines().forEach(this::processLine);
if(callback != null) {
callback.run();
}
public String get(String category, String key) {
return data.get(category).get(key);
}
public void onReload(Runnable callback) {
@ -44,7 +36,12 @@ public class Data {
}
}
public String get(String category, String key) {
return data.get(category).get(key);
public void reload(ByteBuffer data) {
this.data.clear();
this.data.put("", new LinkedHashMap<>());
StandardCharsets.UTF_8.decode(data).toString().lines().forEach(this::processLine);
if(callback != null) {
callback.run();
}
}
}

View File

@ -17,9 +17,9 @@ import static com.danitheskunk.skunkworks.gfx.GraphicsBackend.OPENGL;
public class Engine {
private final GraphicsBackend graphicsBackend;
private final WatchService watchService;
private final Map<WatchKey, Callable<Boolean>> watchCallbacks;
private final Map<WatchKey, Path> watchPaths;
private final WatchService watchService;
//Constructors
public Engine() {
@ -52,10 +52,6 @@ public class Engine {
return buf;
}
public Image loadImage(String path) {
return new Image(loadBytes(path));
}
public Data loadData(String path) {
return new Data(loadBytes(path));
}
@ -69,19 +65,8 @@ public class Engine {
return data;
}
//requires engine.tick() to be called regularly
public void watchFile(String path, Callable<Boolean> callback) {
var p = Paths.get(path);
var dir = p.getParent();
try {
var key = dir.register(watchService,
StandardWatchEventKinds.ENTRY_MODIFY
);
watchCallbacks.put(key, callback);
watchPaths.put(key, p.getFileName());
} catch(IOException e) {
throw new RuntimeException(e);
}
public Image loadImage(String path) {
return new Image(loadBytes(path));
}
public IWindow openWindow(Vec2i size, String title) {
@ -107,4 +92,19 @@ public class Engine {
}
}
}
//requires engine.tick() to be called regularly
public void watchFile(String path, Callable<Boolean> callback) {
var p = Paths.get(path);
var dir = p.getParent();
try {
var key = dir.register(watchService,
StandardWatchEventKinds.ENTRY_MODIFY
);
watchCallbacks.put(key, callback);
watchPaths.put(key, p.getFileName());
} catch(IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -8,10 +8,16 @@ import java.util.List;
public interface IWindow {
Engine getEngine();
IFont loadFontTileset(String path);
Vec2i getMousePos();
boolean isMouseClicked(int button);
boolean isMouseDown(int button);
IFont loadFontTTF(String path, float size);
IFont loadFontTileset(String path);
NineSlice loadNineSlice(Image image);
NineSlice loadNineSlice(String path);
@ -26,10 +32,10 @@ public interface IWindow {
void renderFinish(IRenderContext context);
IRenderContext renderStart();
void renderFinish3D(IRenderContext3D context);
IRenderContext renderStart();
IRenderContext3D renderStart3D();
//needs to be run after rendering
@ -37,15 +43,9 @@ public interface IWindow {
void setDebug(boolean on);
boolean shouldClose();
void setStretchMode(WindowStretchMode mode);
Vec2i getMousePos();
boolean isMouseClicked(int button);
boolean isMouseDown(int button);
boolean shouldClose();
void tick();
}

View File

@ -11,26 +11,6 @@ public final class Mat4f {
set(3, 3, 1.0);
}
public double get(int x, int y) {
return data[x + y * 4];
}
public void set(int x, int y, double val) {
data[x + y * 4] = val;
}
public double[] asArray() {
return data;
}
public float[] asFloatArray() {
var arr = new float[16];
for(int i = 0; i < 16; ++i) {
arr[i] = (float)data[i];
}
return arr;
}
public static Mat4f perspective(
double fovy, double aspect, double zNear, double zFar
) {
@ -65,4 +45,24 @@ public final class Mat4f {
//mat.set(3, 3, 0);
return mat;
}
public double[] asArray() {
return data;
}
public float[] asFloatArray() {
var arr = new float[16];
for(int i = 0; i < 16; ++i) {
arr[i] = (float) data[i];
}
return arr;
}
public double get(int x, int y) {
return data[x + y * 4];
}
public void set(int x, int y, double val) {
data[x + y * 4] = val;
}
}

View File

@ -14,37 +14,12 @@ public final class Recti {
this.size = size;
}
//getters
public Vec2i getPos() {
return pos;
}
public Vec2i getSize() {
return size;
}
public int getX() {
return pos.getX();
}
public int getY() {
return pos.getY();
}
public int getWidth() {
return size.getX();
}
public int getHeight() {
return size.getY();
}
public Vec2i getTopLeft() {
return pos;
}
public Vec2i getTopRight() {
return new Vec2i(pos.getX() + size.getX(), pos.getY());
public boolean contains(Vec2i vec) {
var br = getBottomRight();
return vec.getX() >= pos.getX() &&
vec.getY() >= pos.getY() &&
vec.getX() < br.getX() &&
vec.getY() < br.getY();
}
public Vec2i getBottomLeft() {
@ -55,11 +30,36 @@ public final class Recti {
return Vec2i.add(pos, size);
}
public boolean contains(Vec2i vec) {
var br = getBottomRight();
return vec.getX() >= pos.getX() &&
vec.getY() >= pos.getY() &&
vec.getX() < br.getX() &&
vec.getY() < br.getY();
public int getHeight() {
return size.getY();
}
//getters
public Vec2i getPos() {
return pos;
}
public Vec2i getSize() {
return size;
}
public Vec2i getTopLeft() {
return pos;
}
public Vec2i getTopRight() {
return new Vec2i(pos.getX() + size.getX(), pos.getY());
}
public int getWidth() {
return size.getX();
}
public int getX() {
return pos.getX();
}
public int getY() {
return pos.getY();
}
}

View File

@ -1,6 +1,5 @@
package com.danitheskunk.skunkworks;
import com.danitheskunk.skunkworks.gfx.IRenderContext;
import com.danitheskunk.skunkworks.gfx.IRenderContext3D;
public class Test3D extends BaseGame {

View File

@ -4,8 +4,8 @@ import com.danitheskunk.skunkworks.audio.ISample;
import com.danitheskunk.skunkworks.nodes.NodeSprite;
public class TestNode extends BaseGame {
NodeSprite sprite;
ISample kick;
NodeSprite sprite;
public TestNode() {
super(new Vec2i(1280, 720), "Skunkworks");

View File

@ -5,21 +5,9 @@ import com.danitheskunk.skunkworks.audio.nodes.Mixer;
import com.danitheskunk.skunkworks.audio.nodes.Node;
import com.danitheskunk.skunkworks.audio.nodes.SamplePlayer;
import com.danitheskunk.skunkworks.audio.nodes.Sine;
import org.lwjgl.openal.AL;
import org.lwjgl.openal.ALC;
import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import static org.lwjgl.openal.AL10.*;
import static org.lwjgl.openal.ALC10.*;
public class TestSound {
public static void main(String args[]) throws InterruptedException {
public static void main(String[] args) throws InterruptedException {
var engine = new AudioEngine(44100, 256, 16);
var mix = new Mixer(engine, 4);
var sin1 = new Sine(engine, 440);

View File

@ -15,25 +15,10 @@ public final class Vec2f {
return new Vec2f(a.x + b.x, a.y + b.y);
}
public static Vec2f sub(Vec2f a, Vec2f b) {
return new Vec2f(a.x - b.x, a.y - b.y);
}
public static Vec2f mul(Vec2f a, double b) {
return new Vec2f(a.x * b, a.y * b);
}
public static Vec2f div(Vec2f a, double b) {
return new Vec2f(a.x / b, a.y / b);
}
public static Vec2f tween(Vec2f a, Vec2f b, double amount) {
return new Vec2f(
Util.tweenDouble(a.x, b.x, amount),
Util.tweenDouble(a.y, b.y, amount)
);
}
public static Vec2f div(Vec2i a, Vec2i b) {
return new Vec2f(
(double) a.getX() / (double) b.getX(),
@ -41,6 +26,21 @@ public final class Vec2f {
);
}
public static Vec2f mul(Vec2f a, double b) {
return new Vec2f(a.x * b, a.y * b);
}
public static Vec2f sub(Vec2f a, Vec2f b) {
return new Vec2f(a.x - b.x, a.y - b.y);
}
public static Vec2f tween(Vec2f a, Vec2f b, double amount) {
return new Vec2f(
Util.tweenDouble(a.x, b.x, amount),
Util.tweenDouble(a.y, b.y, amount)
);
}
//getters and setters
public double getX() {
return x;

View File

@ -28,19 +28,6 @@ public final class Vec2i {
return new Vec2i(a.x + b.x + c.x + d.x, a.y + b.y + c.y + d.y);
}
public static Vec2i sub(Vec2i a, Vec2i b) {
return new Vec2i(a.x - b.x, a.y - b.y);
}
public static Vec2i mul(Vec2i a, int b) {
return new Vec2i(a.x * b, a.y * b);
}
public static Vec2i mul(Vec2i a, Vec2i b) {
return new Vec2i(a.x * b.x, a.y * b.y);
}
public static Vec2i div(Vec2i a, int b) {
return new Vec2i(a.x / b, a.y / b);
}
@ -65,18 +52,20 @@ public final class Vec2i {
return new Vec2f(a.x / (double) b.x, a.y / (double) b.y);
}
public static Vec2i min(Vec2i a, Vec2i b) {
return new Vec2i(Math.min(a.x, b.x), Math.min(a.y, b.y));
}
public static Vec2i max(Vec2i a, Vec2i b) {
return new Vec2i(Math.max(a.x, b.x), Math.max(a.y, b.y));
}
public static Vec2i tween(Vec2i a, Vec2i b, double amount) {
return new Vec2i(Util.tweenInt(a.x, b.x, amount),
Util.tweenInt(a.y, b.y, amount)
);
public static Vec2i min(Vec2i a, Vec2i b) {
return new Vec2i(Math.min(a.x, b.x), Math.min(a.y, b.y));
}
public static Vec2i mul(Vec2i a, int b) {
return new Vec2i(a.x * b, a.y * b);
}
public static Vec2i mul(Vec2i a, Vec2i b) {
return new Vec2i(a.x * b.x, a.y * b.y);
}
public static Vec2i mul(Vec2f a, Vec2i b) {
@ -89,6 +78,15 @@ public final class Vec2i {
return new Vec2i((int) (a.x / b), (int) (a.y / b));
}
public static Vec2i sub(Vec2i a, Vec2i b) {
return new Vec2i(a.x - b.x, a.y - b.y);
}
public static Vec2i tween(Vec2i a, Vec2i b, double amount) {
return new Vec2i(Util.tweenInt(a.x, b.x, amount),
Util.tweenInt(a.y, b.y, amount)
);
}
public int getX() {
return x;
@ -99,6 +97,6 @@ public final class Vec2i {
}
public Vec2f toVec2f() {
return new Vec2f((double) x, (double) y);
return new Vec2f(x, y);
}
}

View File

@ -1,8 +1,8 @@
package com.danitheskunk.skunkworks;
public final class Vec3f {
public static Vec3f ZERO = new Vec3f(0, 0, 0);
public static Vec3f ONE = new Vec3f(1, 1, 1);
public static Vec3f ZERO = new Vec3f(0, 0, 0);
private final double x, y, z;
public Vec3f(double x, double y, double z) {

View File

@ -1,14 +1,22 @@
package com.danitheskunk.skunkworks.audio;
public class AudioBuffer {
private double[] left;
private double[] right;
private final double[] left;
private final double[] right;
public AudioBuffer(int size) {
left = new double[size];
right = new double[size];
}
public double getLeft(int pos) {
return left[pos];
}
public double getRight(int pos) {
return right[pos];
}
public int getSize() {
return left.length;
}
@ -17,12 +25,4 @@ public class AudioBuffer {
this.left[pos] = left;
this.right[pos] = right;
}
public double getLeft(int pos) {
return left[pos];
}
public double getRight(int pos) {
return right[pos];
}
}

View File

@ -18,13 +18,14 @@ import static org.lwjgl.openal.AL10.*;
import static org.lwjgl.openal.ALC10.*;
public class AudioEngine {
private int sampleRate;
private int bufferSize;
private int bufferCount;
private long device;
private long context;
private int source;
private final int bufferCount;
private final int bufferSize;
private final long context;
private final long device;
private Node node;
private final int sampleRate;
private final int source;
public AudioEngine(int sampleRate, int bufferSize, int bufferCount) {
this.sampleRate = sampleRate;
this.bufferSize = bufferSize;
@ -50,8 +51,10 @@ public class AudioEngine {
alSourcePlay(source);
}
public int getBufferSize() {
return bufferSize;
private void addEmptyBuffer() {
var buf = alGenBuffers();
fillBuffer(buf);
alSourceQueueBuffers(source, buf);
}
public void close() {
@ -72,37 +75,16 @@ public class AudioEngine {
alBufferData(buffer, AL_FORMAT_STEREO16, shortBuffer, sampleRate);
}
private void addEmptyBuffer() {
var buf = alGenBuffers();
fillBuffer(buf);
alSourceQueueBuffers(source, buf);
}
public void refill() {
var bufCount = alGetSourcei(source, AL_BUFFERS_PROCESSED);
var bufs = new int[bufCount];
alSourceUnqueueBuffers(source, bufs);
for(int i = 0; i < bufCount; ++i) {
fillBuffer(bufs[i]);
alSourceQueueBuffers(source, bufs[i]);
}
if(alGetSourcei(source, AL_SOURCE_STATE) != AL_PLAYING) {
System.out.println("buffer underrun, addng buffer");
addEmptyBuffer();
alSourcePlay(source);
}
}
public int getSampleRate() {
return sampleRate;
public int getBufferSize() {
return bufferSize;
}
public Node getNode() {
return node;
}
public void setNode(Node node) {
this.node = node;
public int getSampleRate() {
return sampleRate;
}
public ISample loadSample(String path) {
@ -154,4 +136,23 @@ public class AudioEngine {
}
return sample;
}
public void refill() {
var bufCount = alGetSourcei(source, AL_BUFFERS_PROCESSED);
var bufs = new int[bufCount];
alSourceUnqueueBuffers(source, bufs);
for(int i = 0; i < bufCount; ++i) {
fillBuffer(bufs[i]);
alSourceQueueBuffers(source, bufs[i]);
}
if(alGetSourcei(source, AL_SOURCE_STATE) != AL_PLAYING) {
System.out.println("buffer underrun, addng buffer");
addEmptyBuffer();
alSourcePlay(source);
}
}
public void setNode(Node node) {
this.node = node;
}
}

View File

@ -8,9 +8,9 @@ public interface ISample {
double getSampleRight(int pos);
void setSamplei(int pos, short left);
boolean isStereo();
void setSamplei(int pos, short left, short right);
boolean isStereo();
void setSamplei(int pos, short left);
}

View File

@ -1,8 +1,8 @@
package com.danitheskunk.skunkworks.audio;
public class Samplei implements ISample {
private short[] left;
private short[] right;
private final short[] left;
private final short[] right;
public Samplei(int length, boolean stereo) {
left = new short[length];
@ -30,8 +30,8 @@ public class Samplei implements ISample {
}
@Override
public void setSamplei(int pos, short left) {
this.left[pos] = left;
public boolean isStereo() {
return left != right;
}
@Override
@ -41,7 +41,7 @@ public class Samplei implements ISample {
}
@Override
public boolean isStereo() {
return left != right;
public void setSamplei(int pos, short left) {
this.left[pos] = left;
}
}

View File

@ -4,7 +4,7 @@ import com.danitheskunk.skunkworks.audio.AudioBuffer;
import com.danitheskunk.skunkworks.audio.AudioEngine;
public class Mixer extends Node {
private int channels;
private final int channels;
public Mixer(AudioEngine engine, int channels) {
super(engine, channels, 1);

View File

@ -4,12 +4,12 @@ import com.danitheskunk.skunkworks.audio.AudioBuffer;
import com.danitheskunk.skunkworks.audio.AudioEngine;
public abstract class Node {
private int inCount;
private int outCount;
private boolean[] isOutConnected;
private Node[] inConnections;
private int[] inConnectionSlots;
private AudioEngine engine;
private final AudioEngine engine;
private final int[] inConnectionSlots;
private final Node[] inConnections;
private final int inCount;
private final boolean[] isOutConnected;
private final int outCount;
public Node(AudioEngine engine, int inCount, int outCount) {
this.inCount = inCount;
@ -43,6 +43,13 @@ public abstract class Node {
dst.inConnectionSlots[dstSlot] = srcSlot;
}
public abstract AudioBuffer getBuffer(int slot);
protected AudioBuffer getBufferFromInput(int inSlot) {
if(inConnections[inSlot] == null) return null;
return inConnections[inSlot].getBuffer(inConnectionSlots[inSlot]);
}
public AudioEngine getEngine() {
return engine;
}
@ -54,11 +61,4 @@ public abstract class Node {
public int getOutCount() {
return outCount;
}
public abstract AudioBuffer getBuffer(int slot);
protected AudioBuffer getBufferFromInput(int inSlot) {
if(inConnections[inSlot] == null) return null;
return inConnections[inSlot].getBuffer(inConnectionSlots[inSlot]);
}
}

View File

@ -8,7 +8,7 @@ import java.util.ArrayList;
import java.util.List;
public class SamplePlayer extends Node {
private List<PlayingSample> samples;
private final List<PlayingSample> samples;
public SamplePlayer(AudioEngine engine) {
super(engine, 0, 1);
@ -57,8 +57,8 @@ public class SamplePlayer extends Node {
}
private static class PlayingSample {
boolean loop;
ISample sample;
int tick;
boolean loop;
}
}

View File

@ -4,8 +4,8 @@ import com.danitheskunk.skunkworks.audio.AudioBuffer;
import com.danitheskunk.skunkworks.audio.AudioEngine;
public class Sine extends Node {
private final double freq;
private int tick;
private double freq;
public Sine(AudioEngine engine, double freq) {
super(engine, 0, 1);

View File

@ -3,9 +3,9 @@ package com.danitheskunk.skunkworks.backends.gl;
import static org.lwjgl.opengl.GL46.*;
public class Program {
Shader vertex;
Shader fragment;
int program;
Shader vertex;
public Program(String vertexSource, String fragmentSource) {
vertex = new Shader(vertexSource, GL_VERTEX_SHADER);
@ -17,14 +17,14 @@ public class Program {
glLinkProgram(program);
}
public void use() {
glUseProgram(program);
}
public int getAttribLocation(String attrib) {
return glGetAttribLocation(program, attrib);
}
public Shader getFragment() {
return fragment;
}
public int getUniformLocation(String attrib) {
return glGetUniformLocation(program, attrib);
}
@ -33,7 +33,7 @@ public class Program {
return vertex;
}
public Shader getFragment() {
return fragment;
public void use() {
glUseProgram(program);
}
}

View File

@ -41,15 +41,17 @@ class RenderContext extends BaseRenderContext implements IRenderContext {
var size = rect.getSize();
drawTexture(pos, slice.getTopLeft());
drawTexture(
new Vec2i(pos.getX() + slice.getLeft().getWidth() + centerWidth,
drawTexture(new Vec2i(pos.getX() +
slice.getLeft().getWidth() +
centerWidth,
pos.getY()
),
slice.getTopRight()
);
drawTexture(new Vec2i(pos.getX(),
), slice.getTopRight());
drawTexture(
new Vec2i(pos.getX(),
pos.getY() + slice.getTop().getHeight() + centerHeight
), slice.getBottomLeft());
),
slice.getBottomLeft()
);
drawTexture(Vec2i.add(pos,
slice.getTopLeft().getSize(),
new Vec2i(centerWidth, centerHeight)

View File

@ -2,6 +2,7 @@ package com.danitheskunk.skunkworks.backends.gl;
import com.danitheskunk.skunkworks.Vec3f;
import com.danitheskunk.skunkworks.gfx.BaseRenderContext3D;
import static org.lwjgl.opengl.GL46.*;
public class RenderContext3D extends BaseRenderContext3D {

View File

@ -3,8 +3,8 @@ package com.danitheskunk.skunkworks.backends.gl;
import static org.lwjgl.opengl.GL46.*;
public class Shader {
private int shader;
private int type;
private final int shader;
private final int type;
public Shader(String source, int type) {
this.type = type;

View File

@ -14,6 +14,11 @@ class Texture implements ITexture {
this.img = img;
}
@Override
public int getHeight() {
return img.getHeight();
}
//setters
Image getImg() {
return img;
@ -24,20 +29,15 @@ class Texture implements ITexture {
return this.img.getSize();
}
Recti getTexArea() {
return texArea;
}
@Override
public int getWidth() {
return img.getWidth();
}
@Override
public int getHeight() {
return img.getHeight();
}
Recti getTexArea() {
return texArea;
}
void setTexArea(Recti texArea) {
this.texArea = texArea;
}

View File

@ -13,11 +13,11 @@ import java.util.List;
import static org.lwjgl.opengl.GL11.*;
class TextureAtlas {
final private int textureID;
private final List<Texture> textures;
private Texture atlasTexture; //for debugging
private Image img;
private boolean shouldUpdate;
final private int textureID;
TextureAtlas() {
img = new Image(new Vec2i(32, 32));
@ -33,15 +33,10 @@ class TextureAtlas {
}
public void bind() {
glBindTexture(GL_TEXTURE_2D, textureID);
}
ITexture addTexture(Image img) {
//todo: do the actual texture stuff
//this.img = img;
var texture = new Texture(
new Recti(new Vec2i(0, 0), img.getSize()),
var texture = new Texture(new Recti(new Vec2i(0, 0), img.getSize()),
img
);
textures.add(texture);
@ -49,23 +44,25 @@ class TextureAtlas {
return texture;
}
public void bind() {
glBindTexture(GL_TEXTURE_2D, textureID);
}
void doubleAtlasSize() {
img = new Image(Vec2i.mul(img.getSize(), 2));
System.out.printf(
"Resized atlas to %dx%d\n",
System.out.printf("Resized atlas to %dx%d\n",
img.getSize().getX(),
img.getSize().getY()
);
atlasTexture = new Texture(new Recti(Vec2i.ZERO, img.getSize()), img);
}
public void update() {
if(shouldUpdate) {
repack();
updateImage();
uploadToGpu();
shouldUpdate = false;
public Texture getAtlasTexture() {
return atlasTexture;
}
public Vec2i getSize() {
return img.getSize();
}
void repack() {
@ -108,6 +105,15 @@ class TextureAtlas {
}
}
public void update() {
if(shouldUpdate) {
repack();
updateImage();
uploadToGpu();
shouldUpdate = false;
}
}
void updateImage() {
for(var tex : textures) {
img.drawImage(tex.getImg(), tex.getTexArea().getPos());
@ -131,14 +137,6 @@ class TextureAtlas {
);
}
public Texture getAtlasTexture() {
return atlasTexture;
}
public Vec2i getSize() {
return img.getSize();
}
private static class TextureHeightComparator implements Comparator<Texture> {
@Override
public int compare(Texture o1, Texture o2) {

View File

@ -18,18 +18,7 @@ import static org.lwjgl.opengl.GL46.*;
import static org.lwjgl.system.MemoryUtil.NULL;
public class Window extends BaseWindow {
private static String vertexSource = """
#version 450
layout(location = 0) in vec2 pos;
layout(location = 1) in ivec2 texCoord;
layout(location = 2) uniform vec2 windowSize;
layout(location = 1) out vec2 out_texCoord;
void main() {
gl_Position = vec4(pos / windowSize * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f);
out_texCoord = texCoord;
}
""";
private static String fragmentSource = """
private static final String fragmentSource = """
#version 450
layout(location = 1) in vec2 texCoord;
layout(binding = 0) uniform sampler2D tex;
@ -47,18 +36,7 @@ public class Window extends BaseWindow {
}
}
""";
private static String vertexSource3D = """
#version 450
layout(location = 0) in vec3 pos;
//layout(location = 1) in ivec2 texCoord;
layout(location = 2) uniform mat4 projection;
layout(location = 1) out vec2 out_texCoord;
void main() {
gl_Position = projection * vec4(pos, 1.0f);
out_texCoord.x = pos.z;
}
""";
private static String fragmentSource3D = """
private static final String fragmentSource3D = """
#version 450
layout(location = 1) in vec2 texCoord;
//layout(binding = 0) uniform sampler2D tex;
@ -69,18 +47,7 @@ public class Window extends BaseWindow {
color = vec4(1.0, texCoord.x / 2, 1.0, 1.0);
}
""";
private static String vertexSourceScaler = """
#version 450
layout(location = 0) in vec2 pos;
layout(location = 1) in vec2 texCoord;
layout(location = 2) uniform vec2 windowSize;
layout(location = 1) out vec2 out_texCoord;
void main() {
gl_Position = vec4(pos / windowSize * vec2(2.0f, 2.0f) + vec2(-1.0f, -1.0f), 0.0f, 1.0f);
out_texCoord = texCoord;
}
""";
private static String fragmentSourceScaler = """
private static final String fragmentSourceScaler = """
#version 450
layout(location = 1) in vec2 texCoord;
layout(binding = 0) uniform sampler2D tex;
@ -96,22 +63,55 @@ public class Window extends BaseWindow {
//color = vec4(texCoord.xy, 0.0, 1.0);
}
""";
private static final String vertexSource = """
#version 450
layout(location = 0) in vec2 pos;
layout(location = 1) in ivec2 texCoord;
layout(location = 2) uniform vec2 windowSize;
layout(location = 1) out vec2 out_texCoord;
void main() {
gl_Position = vec4(pos / windowSize * vec2(2.0f, -2.0f) + vec2(-1.0f, 1.0f), 0.0f, 1.0f);
out_texCoord = texCoord;
}
""";
private static final String vertexSource3D = """
#version 450
layout(location = 0) in vec3 pos;
//layout(location = 1) in ivec2 texCoord;
layout(location = 2) uniform mat4 projection;
layout(location = 1) out vec2 out_texCoord;
void main() {
gl_Position = projection * vec4(pos, 1.0f);
out_texCoord.x = pos.z;
}
""";
private static final String vertexSourceScaler = """
#version 450
layout(location = 0) in vec2 pos;
layout(location = 1) in vec2 texCoord;
layout(location = 2) uniform vec2 windowSize;
layout(location = 1) out vec2 out_texCoord;
void main() {
gl_Position = vec4(pos / windowSize * vec2(2.0f, 2.0f) + vec2(-1.0f, -1.0f), 0.0f, 1.0f);
out_texCoord = texCoord;
}
""";
private final int framebuffer;
private final int framebufferTex;
private final Program program;
private final Program program3D;
private final Program programScaler;
private final RenderContext renderContext;
private final RenderContext3D renderContext3D;
private final Vec2i size;
private Vec2i windowSize;
private final TextureAtlas textureAtlas;
private final long window;
private boolean debug;
private final Mat4f projection;
private boolean shouldClose;
private final int framebuffer;
private final int framebufferTex;
private boolean[] stateMouseClicked;
private boolean[] stateMouseDown;
private Mat4f projection;
private final boolean[] stateMouseClicked;
private final boolean[] stateMouseDown;
private Vec2i windowSize;
public Window(Vec2i size, String title, Engine engine) {
super(engine);
@ -201,26 +201,53 @@ public class Window extends BaseWindow {
System.out.println(GL11.glGetInteger(GL_MAX_TEXTURE_SIZE));
}
private void mouseButtonCallback(
long window, int button, int action, int mods
) {
switch(action) {
case GLFW_PRESS -> {
this.stateMouseClicked[button] = true;
this.stateMouseDown[button] = true;
@Override
public Vec2i getMousePos() {
//todo: scale mouse to stretchMode
double[] x = {0.0};
double[] y = {0.0};
glfwGetCursorPos(window, x, y);
var mousePos = new Vec2i((int) x[0], (int) y[0]);
var scaledMousePos = switch(this.stretchMode) {
case STRETCH -> {
var stretch = Vec2f.div(this.size, this.windowSize);
yield Vec2i.mul(stretch, mousePos);
}
case GLFW_RELEASE -> {
this.stateMouseDown[button] = false;
case ASPECT -> {
var scale = Vec2f.div(this.size, this.windowSize);
var scalef = Math.max(scale.getX(), scale.getY());
var off = Vec2f.div(Vec2i.sub(windowSize,
Vec2f.mul(size.toVec2f(), 1.0 / scalef).toVec2i()
).toVec2f(), 2).toVec2i();
yield Vec2i.mul(Vec2i.sub(mousePos, off), 1.0 / scalef);
}
case INTEGER -> {
var scale = Vec2i.div(this.windowSize, this.size);
var scalei = Math.max(1, Math.min(scale.getX(), scale.getY()));
var off = Vec2i.div(Vec2i.sub(windowSize,
Vec2i.mul(size, scalei)
), 2);
yield Vec2i.div(Vec2i.sub(mousePos, off), scalei);
}
};
return Vec2i.max(Vec2i.ZERO,
Vec2i.min(Vec2i.sub(size, new Vec2i(1, 1)), scaledMousePos)
);
}
private void windowSizeCallback(long window, int width, int height) {
System.out.printf("new window size %d x %d\n", width, height);
windowSize = new Vec2i(width, height);
glViewport(0, 0, width, height);
//glLoadIdentity();
//glOrtho(0.0f, width, height, 0.0f, 0.0f, 1.0f);
@Override
public boolean isMouseClicked(int button) {
return this.stateMouseClicked[button];
}
@Override
public boolean isMouseDown(int button) {
return this.stateMouseDown[button];
}
@Override
@ -258,6 +285,20 @@ public class Window extends BaseWindow {
return loadTextureArray(img, tileSize);
}
private void mouseButtonCallback(
long window, int button, int action, int mods
) {
switch(action) {
case GLFW_PRESS -> {
this.stateMouseClicked[button] = true;
this.stateMouseDown[button] = true;
}
case GLFW_RELEASE -> {
this.stateMouseDown[button] = false;
}
}
}
@Override
public void renderFinish(IRenderContext context) {
if(debug) {
@ -268,6 +309,10 @@ public class Window extends BaseWindow {
}
}
public void renderFinish3D(IRenderContext3D context) {
}
@Override
public IRenderContext renderStart() {
program.use();
@ -281,10 +326,6 @@ public class Window extends BaseWindow {
return renderContext;
}
public void renderFinish3D(IRenderContext3D context) {
}
@Override
public IRenderContext3D renderStart3D() {
program3D.use();
@ -295,8 +336,7 @@ public class Window extends BaseWindow {
glClearColor(0.f, 1.f, 0.f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glBegin(GL_TRIANGLES);
glUniformMatrix4fv(
program3D.getUniformLocation("projection"),
glUniformMatrix4fv(program3D.getUniformLocation("projection"),
true,
projection.asFloatArray()
);
@ -391,7 +431,6 @@ public class Window extends BaseWindow {
glfwSwapBuffers(window);
}
@Override
public void setDebug(boolean on) {
this.debug = on;
@ -402,55 +441,6 @@ public class Window extends BaseWindow {
return shouldClose;
}
@Override
public Vec2i getMousePos() {
//todo: scale mouse to stretchMode
double[] x = {0.0};
double[] y = {0.0};
glfwGetCursorPos(window, x, y);
var mousePos = new Vec2i((int) x[0], (int) y[0]);
var scaledMousePos = switch(this.stretchMode) {
case STRETCH -> {
var stretch = Vec2f.div(this.size, this.windowSize);
yield Vec2i.mul(stretch, mousePos);
}
case ASPECT -> {
var scale = Vec2f.div(this.size, this.windowSize);
var scalef = Math.max(scale.getX(), scale.getY());
var off = Vec2f.div(Vec2i.sub(windowSize,
Vec2f.mul(size.toVec2f(), 1.0 / scalef).toVec2i()
).toVec2f(), 2).toVec2i();
yield Vec2i.mul(Vec2i.sub(mousePos, off), 1.0 / scalef);
}
case INTEGER -> {
var scale = Vec2i.div(this.windowSize, this.size);
var scalei = Math.max(1, Math.min(scale.getX(), scale.getY()));
var off = Vec2i.div(Vec2i.sub(windowSize,
Vec2i.mul(size, scalei)
), 2);
yield Vec2i.div(Vec2i.sub(mousePos, off), scalei);
}
};
return Vec2i.max(Vec2i.ZERO,
Vec2i.min(Vec2i.sub(size, new Vec2i(1, 1)), scaledMousePos)
);
}
@Override
public boolean isMouseClicked(int button) {
return this.stateMouseClicked[button];
}
@Override
public boolean isMouseDown(int button) {
return this.stateMouseDown[button];
}
@Override
public void tick() { //one tick per update call?
glfwMakeContextCurrent(window);
@ -462,4 +452,12 @@ public class Window extends BaseWindow {
Arrays.fill(stateMouseClicked, false);
glfwPollEvents();
}
private void windowSizeCallback(long window, int width, int height) {
System.out.printf("new window size %d x %d\n", width, height);
windowSize = new Vec2i(width, height);
glViewport(0, 0, width, height);
//glLoadIdentity();
//glOrtho(0.0f, width, height, 0.0f, 0.0f, 1.0f);
}
}

View File

@ -33,10 +33,12 @@ abstract public class BaseRenderContext implements IRenderContext {
int ch = buf.get(i);
var tex = font.getTexture(ch);
var off = font.getOffset(ch);
drawTextureRectangle(new Recti(
Vec2i.add(new Vec2i(x, y), off),
tex.getSize()
), tex, color, true);
drawTextureRectangle(
new Recti(Vec2i.add(new Vec2i(x, y), off), tex.getSize()),
tex,
color,
true
);
x += font.getXAdvance(ch);
}
}
@ -63,22 +65,18 @@ abstract public class BaseRenderContext implements IRenderContext {
drawTexture(pixelPos, fullFont.getTexture(0xdb), bgColor);
if(isHalfWidth && halfFont != null) {
drawTexture(
pixelPos,
drawTexture(pixelPos,
halfFont.getTexture(terminal.getLeftHalfChar(charPos)),
fgColor
);
drawTexture(
new Vec2i(
pixelPos.getX() + halfCharSize.getX(),
drawTexture(new Vec2i(pixelPos.getX() + halfCharSize.getX(),
pixelPos.getY()
),
halfFont.getTexture(terminal.getRightHalfChar(charPos)),
fgColor
);
} else {
drawTexture(
pixelPos,
drawTexture(pixelPos,
fullFont.getTexture(terminal.getChar(charPos)),
fgColor
);

View File

@ -1,7 +1,5 @@
package com.danitheskunk.skunkworks.gfx;
import com.danitheskunk.skunkworks.Mat4f;
abstract public class BaseRenderContext3D implements IRenderContext3D {
}

View File

@ -1,18 +1,18 @@
package com.danitheskunk.skunkworks.gfx;
public final class Color {
public final static Color WHITE = new Color(255, 255, 255);
public final static Color LIGHT_GRAY = new Color(192, 192, 192);
public final static Color GRAY = new Color(128, 128, 128);
public final static Color DARK_GRAY = new Color(64, 64, 64);
public final static Color BLACK = new Color(0, 0, 0);
public final static Color RED = new Color(255, 0, 0);
public final static Color GREEN = new Color(0, 255, 0);
public final static Color BLUE = new Color(0, 0, 255);
public final static Color YELLOW = new Color(255, 255, 0);
public final static Color MAGENTA = new Color(255, 0, 255);
public final static Color CYAN = new Color(0, 255, 255);
public final static Color DARK_GRAY = new Color(64, 64, 64);
public final static Color GRAY = new Color(128, 128, 128);
public final static Color GREEN = new Color(0, 255, 0);
public final static Color LIGHT_GRAY = new Color(192, 192, 192);
public final static Color MAGENTA = new Color(255, 0, 255);
public final static Color RED = new Color(255, 0, 0);
public final static Color TRANS_BLACK = new Color(0, 0, 0, 0);
public final static Color WHITE = new Color(255, 255, 255);
public final static Color YELLOW = new Color(255, 255, 0);
private final int r, g, b, a;
@ -30,20 +30,20 @@ public final class Color {
this.a = a;
}
public int getR() {
return r;
}
public int getG() {
return g;
public int getA() {
return a;
}
public int getB() {
return b;
}
public int getA() {
return a;
public int getG() {
return g;
}
public int getR() {
return r;
}
@Override

View File

@ -14,17 +14,18 @@ public interface IRenderContext {
void drawString(Vec2i pos, String string, IFont font, Color color);
void drawTerminal(Terminal terminal);
void drawTerminal(Terminal terminal, Vec2i pos);
void drawTexture(Vec2i pos, ITexture texture);
void drawTexture(Vec2i pos, ITexture texture, Color color);
void drawTextureRectangle(Recti rect, ITexture texture, boolean repeat);
void drawTextureRectangle(Recti rect, ITexture texture, Color color,
boolean repeat);
void drawTerminal(Terminal terminal);
void drawTerminal(Terminal terminal, Vec2i pos);
void drawTextureRectangle(
Recti rect, ITexture texture, Color color, boolean repeat
);
//todo: drawTextureRectangleRepeat
}

View File

@ -3,9 +3,9 @@ package com.danitheskunk.skunkworks.gfx;
import com.danitheskunk.skunkworks.Vec2i;
public interface ITexture {
int getHeight();
Vec2i getSize();
int getWidth();
int getHeight();
}

View File

@ -32,41 +32,6 @@ public class Image {
this.size = size;
}
//getters
public byte[] getData() {
return data;
}
public Vec2i getSize() {
return size;
}
public int getWidth() {
return size.getX();
}
public int getHeight() {
return size.getY();
}
public Color getPixel(Vec2i pos) {
int i = pos.getX() * 4 + pos.getY() * 4 * size.getX();
return new Color(
((int) data[i]) & 0xFF,
((int) data[i + 1]) & 0xFF,
((int) data[i + 2]) & 0xFF,
((int) data[i + 3]) & 0xFF
);
}
public void setPixel(Vec2i pos, Color col) {
int i = pos.getX() * 4 + pos.getY() * 4 * size.getX();
data[i] = (byte) (col.getR() & 0xFF);
data[i + 1] = (byte) (col.getG() & 0xFF);
data[i + 2] = (byte) (col.getB() & 0xFF);
data[i + 3] = (byte) (col.getA() & 0xFF);
}
public void drawImage(Image srcImage, Vec2i destPos) {
drawImage(srcImage, destPos, new Recti(Vec2i.ZERO,
srcImage.getSize()));
@ -85,9 +50,43 @@ public class Image {
}
}
//getters
public byte[] getData() {
return data;
}
public int getHeight() {
return size.getY();
}
public Color getPixel(Vec2i pos) {
int i = pos.getX() * 4 + pos.getY() * 4 * size.getX();
return new Color(((int) data[i]) & 0xFF,
((int) data[i + 1]) & 0xFF,
((int) data[i + 2]) & 0xFF,
((int) data[i + 3]) & 0xFF
);
}
public Vec2i getSize() {
return size;
}
public Image getSubImage(Recti rect) {
Image img = new Image(rect.getSize());
img.drawImage(this, Vec2i.ZERO, rect);
return img;
}
public int getWidth() {
return size.getX();
}
public void setPixel(Vec2i pos, Color col) {
int i = pos.getX() * 4 + pos.getY() * 4 * size.getX();
data[i] = (byte) (col.getR() & 0xFF);
data[i + 1] = (byte) (col.getG() & 0xFF);
data[i + 2] = (byte) (col.getB() & 0xFF);
data[i + 3] = (byte) (col.getA() & 0xFF);
}
}

View File

@ -1,19 +1,21 @@
package com.danitheskunk.skunkworks.gfx;
public class NineSlice {
private ITexture topLeft;
private ITexture topRight;
private ITexture bottomLeft;
private ITexture bottomRight;
private ITexture top;
private ITexture right;
private ITexture bottom;
private ITexture left;
private ITexture center;
private final ITexture bottom;
private final ITexture bottomLeft;
private final ITexture bottomRight;
private final ITexture center;
private final ITexture left;
private final ITexture right;
private final ITexture top;
private final ITexture topLeft;
private final ITexture topRight;
public NineSlice(ITexture topLeft, ITexture topRight, ITexture bottomLeft,
public NineSlice(
ITexture topLeft, ITexture topRight, ITexture bottomLeft,
ITexture bottomRight, ITexture top, ITexture right, ITexture bottom,
ITexture left, ITexture center) {
ITexture left, ITexture center
) {
this.topLeft = topLeft;
this.topRight = topRight;
this.bottomLeft = bottomLeft;
@ -25,12 +27,8 @@ public class NineSlice {
this.center = center;
}
public ITexture getTopLeft() {
return topLeft;
}
public ITexture getTopRight() {
return topRight;
public ITexture getBottom() {
return bottom;
}
public ITexture getBottomLeft() {
@ -41,23 +39,27 @@ public class NineSlice {
return bottomRight;
}
public ITexture getTop() {
return top;
}
public ITexture getRight() {
return right;
}
public ITexture getBottom() {
return bottom;
public ITexture getCenter() {
return center;
}
public ITexture getLeft() {
return left;
}
public ITexture getCenter() {
return center;
public ITexture getRight() {
return right;
}
public ITexture getTop() {
return top;
}
public ITexture getTopLeft() {
return topLeft;
}
public ITexture getTopRight() {
return topRight;
}
}

View File

@ -2,48 +2,48 @@ package com.danitheskunk.skunkworks.gfx.font;
public class Cp437 {
public final static int BOX_DOUBLE_BOTTOM_LEFT = 0xBB;
public final static int BOX_DOUBLE_BOTTOM_SINGLE_LEFT = 0xB7;
public final static int BOX_DOUBLE_CROSS = 0xCE;
public final static int BOX_DOUBLE_HORIZONTAL = 0xCD;
public final static int BOX_DOUBLE_HORIZONTAL_BOTTOM = 0xCB;
public final static int BOX_DOUBLE_HORIZONTAL_SINGLE_BOTTOM = 0xD1;
public final static int BOX_DOUBLE_HORIZONTAL_SINGLE_TOP = 0xCF;
public final static int BOX_DOUBLE_RIGHT_BOTTOM = 0xC9;
public final static int BOX_DOUBLE_RIGHT_SINGLE_BOTTOM = 0xD5;
public final static int BOX_DOUBLE_TOP_LEFT = 0xBC;
public final static int BOX_DOUBLE_TOP_RIGHT = 0xC8;
public final static int BOX_DOUBLE_TOP_SINGLE_LEFT = 0xBD;
public final static int BOX_DOUBLE_TOP_SINGLE_RIGHT = 0xD3;
public final static int BOX_DOUBLE_VERTICAL = 0xBA;
public final static int BOX_DOUBLE_VERTICAL_LEFT = 0xB9;
public final static int BOX_DOUBLE_VERTICAL_RIGHT = 0xCC;
public final static int BOX_DOUBLE_VERTICAL_SINGLE_HORIZONTAL = 0xD7;
public final static int BOX_DOUBLE_VERTICAL_SINGLE_LEFT = 0xB6;
public final static int BOX_DOUBLE_VERTICAL_SINGLE_RIGHT = 0xC7;
public final static int BOX_DOUBlE_HORIZONTAL_TOP = 0xCA;
public final static int BOX_SINGLE_BOTTOM_DOUBLE_LEFT = 0xB8;
public final static int BOX_SINGLE_BOTTOM_LEFT = 0xBF;
public final static int BOX_SINGLE_CROSS = 0xC5;
public final static int BOX_SINGLE_HORIZONTAL = 0xC4;
public final static int BOX_SINGLE_HORIZONTAL_BOTTOM = 0xC2;
public final static int BOX_SINGLE_HORIZONTAL_DOUBLE_BOTTOM = 0xD2;
public final static int BOX_SINGLE_HORIZONTAL_DOUBLE_TOP = 0xD0;
public final static int BOX_SINGLE_HORIZONTAL_TOP = 0xC1;
public final static int BOX_SINGLE_RIGHT_BOTTOM = 0xDA;
public final static int BOX_SINGLE_RIGHT_DOUBLE_BOTTOM = 0xD6;
public final static int BOX_SINGLE_TOP_DOUBLE_LEFT = 0xBE;
public final static int BOX_SINGLE_TOP_DOUBLE_RIGHT = 0xD4;
public final static int BOX_SINGLE_TOP_LEFT = 0xD9;
public final static int BOX_SINGLE_TOP_RIGHT = 0xC0;
//box drawing names... name part priority: (SINGLE/DOUBLE modifier first,
// only when it changes), CROSS, VERTICAL, HORIZONTAL, TOP, RIGHT, BOTTOM,
// LEFT
public final static int BOX_SINGLE_VERTICAL = 0xB3;
public final static int BOX_SINGLE_VERTICAL_LEFT = 0xB4;
public final static int BOX_SINGLE_VERTICAL_DOUBLE_LEFT = 0xB5;
public final static int BOX_DOUBLE_VERTICAL_SINGLE_LEFT = 0xB6;
public final static int BOX_DOUBLE_BOTTOM_SINGLE_LEFT = 0xB7;
public final static int BOX_SINGLE_BOTTOM_DOUBLE_LEFT = 0xB8;
public final static int BOX_DOUBLE_VERTICAL_LEFT = 0xB9;
public final static int BOX_DOUBLE_VERTICAL = 0xBA;
public final static int BOX_DOUBLE_BOTTOM_LEFT = 0xBB;
public final static int BOX_DOUBLE_TOP_LEFT = 0xBC;
public final static int BOX_DOUBLE_TOP_SINGLE_LEFT = 0xBD;
public final static int BOX_SINGLE_TOP_DOUBLE_LEFT = 0xBE;
public final static int BOX_SINGLE_BOTTOM_LEFT = 0xBF;
public final static int BOX_SINGLE_TOP_RIGHT = 0xC0;
public final static int BOX_SINGLE_HORIZONTAL_TOP = 0xC1;
public final static int BOX_SINGLE_HORIZONTAL_BOTTOM = 0xC2;
public final static int BOX_SINGLE_VERTICAL_RIGHT = 0xC3;
public final static int BOX_SINGLE_HORIZONTAL = 0xC4;
public final static int BOX_SINGLE_CROSS = 0xC5;
public final static int BOX_SINGLE_VERTICAL_DOUBLE_RIGHT = 0xC6;
public final static int BOX_DOUBLE_VERTICAL_SINGLE_RIGHT = 0xC7;
public final static int BOX_DOUBLE_TOP_RIGHT = 0xC8;
public final static int BOX_DOUBLE_RIGHT_BOTTOM = 0xC9;
public final static int BOX_DOUBlE_HORIZONTAL_TOP = 0xCA;
public final static int BOX_DOUBLE_HORIZONTAL_BOTTOM = 0xCB;
public final static int BOX_DOUBLE_VERTICAL_RIGHT = 0xCC;
public final static int BOX_DOUBLE_HORIZONTAL = 0xCD;
public final static int BOX_DOUBLE_CROSS = 0xCE;
public final static int BOX_DOUBLE_HORIZONTAL_SINGLE_TOP = 0xCF;
public final static int BOX_SINGLE_HORIZONTAL_DOUBLE_TOP = 0xD0;
public final static int BOX_DOUBLE_HORIZONTAL_SINGLE_BOTTOM = 0xD1;
public final static int BOX_SINGLE_HORIZONTAL_DOUBLE_BOTTOM = 0xD2;
public final static int BOX_DOUBLE_TOP_SINGLE_RIGHT = 0xD3;
public final static int BOX_SINGLE_TOP_DOUBLE_RIGHT = 0xD4;
public final static int BOX_DOUBLE_RIGHT_SINGLE_BOTTOM = 0xD5;
public final static int BOX_SINGLE_RIGHT_DOUBLE_BOTTOM = 0xD6;
public final static int BOX_DOUBLE_VERTICAL_SINGLE_HORIZONTAL = 0xD7;
public final static int BOX_SINGLE_VERTICAL_DOUBLE_HORIZONTAL = 0xD8;
public final static int BOX_SINGLE_TOP_LEFT = 0xD9;
public final static int BOX_SINGLE_RIGHT_BOTTOM = 0xDA;
public final static int BOX_SINGLE_VERTICAL_DOUBLE_LEFT = 0xB5;
public final static int BOX_SINGLE_VERTICAL_DOUBLE_RIGHT = 0xC6;
public final static int BOX_SINGLE_VERTICAL_LEFT = 0xB4;
public final static int BOX_SINGLE_VERTICAL_RIGHT = 0xC3;
}

View File

@ -13,10 +13,10 @@ import static org.lwjgl.stb.STBTruetype.*;
public class FontTTF implements IFont {
HashMap<Integer, Char> chars;
STBTTFontinfo info;
int lineHeight;
float size;
float unscaled_size;
STBTTFontinfo info;
IWindow window;
public FontTTF(ByteBuffer buffer, float size, IWindow window) {
@ -39,9 +39,10 @@ public class FontTTF implements IFont {
this.size = stbtt_ScaleForPixelHeight(info, size);
//precache ascii characters
for(int i = 32; i < 128; ++i)
for(int i = 32; i < 128; ++i) {
cacheChar(i);
}
}
void cacheChar(int ch) {
if(chars.containsKey(ch)) return;
@ -54,8 +55,7 @@ public class FontTTF implements IFont {
int[] leftSideBearing = {0};
ITexture tex;
var bufmono = stbtt_GetCodepointBitmap(
info,
var bufmono = stbtt_GetCodepointBitmap(info,
size,
size,
ch,
@ -74,22 +74,43 @@ public class FontTTF implements IFont {
buf.put(b);
}
buf.flip();
tex = window.loadTexture(new Image(
buf,
tex = window.loadTexture(new Image(buf,
new Vec2i(width[0], height[0])
));
} else {
tex = window.loadTexture(new Image(Vec2i.ZERO));
}
stbtt_GetCodepointHMetrics(info, ch, advanceWidth, leftSideBearing);
var c = new Char(
tex,
var c = new Char(tex,
(int) (advanceWidth[0] * size),
new Vec2i(xoff[0], yoff[0])
);
chars.put(ch, c);
}
@Override
public int getLineHeight(int ch) {
cacheChar(ch);
return lineHeight;
}
@Override
public Vec2i getMonospaceSize() {
throw new RuntimeException("Not a monospace font");
}
@Override
public Vec2i getOffset(int ch) {
cacheChar(ch);
return chars.get(ch).off;
}
@Override
public ITexture getTexture(int ch) {
cacheChar(ch);
return chars.get(ch).tex;
}
@Override
public int getXAdvance(int ch) {
cacheChar(ch);
@ -106,33 +127,10 @@ public class FontTTF implements IFont {
return false;
}
@Override
public Vec2i getMonospaceSize() {
throw new RuntimeException("Not a monospace font");
}
@Override
public int getLineHeight(int ch) {
cacheChar(ch);
return lineHeight;
}
@Override
public Vec2i getOffset(int ch) {
cacheChar(ch);
return chars.get(ch).off;
}
@Override
public ITexture getTexture(int ch) {
cacheChar(ch);
return chars.get(ch).tex;
}
private class Char {
ITexture tex;
int advance;
Vec2i off;
ITexture tex;
Char(ITexture tex, int advance, Vec2i off) {
this.tex = tex;

View File

@ -6,14 +6,37 @@ import com.danitheskunk.skunkworks.gfx.ITexture;
import java.util.List;
public class FontTileset implements IFont {
private List<ITexture> textures;
private Vec2i charSize;
private final Vec2i charSize;
private final List<ITexture> textures;
public FontTileset(List<ITexture> textures) {
this.textures = textures;
this.charSize = textures.get(0).getSize();
}
@Override
public int getLineHeight(int ch) {
return charSize.getY();
}
@Override
public Vec2i getMonospaceSize() {
return charSize;
}
@Override
public Vec2i getOffset(int ch) {
return Vec2i.ZERO;
}
@Override
public ITexture getTexture(int ch) {
if(ch >= 256 || ch < 0) {
ch = 0;
}
return textures.get(ch);
}
@Override
public int getXAdvance(int ch) {
return charSize.getX();
@ -28,27 +51,4 @@ public class FontTileset implements IFont {
public boolean isMonospace() {
return true;
}
@Override
public Vec2i getMonospaceSize() {
return charSize;
}
@Override
public int getLineHeight(int ch) {
return charSize.getY();
}
@Override
public Vec2i getOffset(int ch) {
return Vec2i.ZERO;
}
@Override
public ITexture getTexture(int ch) {
if(ch >= 256 || ch < 0) {
ch = 0;
}
return textures.get(ch);
}
}

View File

@ -6,6 +6,8 @@ import com.danitheskunk.skunkworks.gfx.ITexture;
public interface IFont {
int getLineHeight(int ch);
Vec2i getMonospaceSize();
Vec2i getOffset(int ch);
ITexture getTexture(int ch);
@ -15,6 +17,4 @@ public interface IFont {
boolean isCP437();
boolean isMonospace();
Vec2i getMonospaceSize();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,9 @@
package com.danitheskunk.skunkworks.nodes;
public abstract class BaseTween {
protected int endFrame;
protected double progress;
protected int startFrame;
protected int endFrame;
protected Runnable thenFunc;
public BaseTween() {
@ -11,9 +11,7 @@ public abstract class BaseTween {
thenFunc = null;
}
public void setProgress(double progress) {
this.progress = progress;
}
protected abstract void apply();
public BaseTween delay(int frames) {
startFrame += frames;
@ -21,10 +19,12 @@ public abstract class BaseTween {
return this;
}
public void setProgress(double progress) {
this.progress = progress;
}
public BaseTween then(Runnable func) {
thenFunc = func;
return this;
}
protected abstract void apply();
}

View File

@ -20,18 +20,6 @@ public class Node implements Iterable<Node> {
pos = Vec2f.ZERO;
}
public Node getParent() {
return parent;
}
public Vec2f getPos() {
return pos;
}
public void setPos(Vec2f pos) {
this.pos = pos;
}
public void add(Node node) {
if(node.parent != null) {
throw new RuntimeException("Can't add node to two nodes");
@ -40,22 +28,23 @@ public class Node implements Iterable<Node> {
children.add(node);
}
public void remove(Node node) {
node.parent = null;
children.remove(node);
}
public void render(IRenderContext rc) {
for(var child : this) {
child.render(rc);
}
}
public Vec2f getAbsolutePos() {
if(parent == null) return pos;
return Vec2f.add(parent.getAbsolutePos(), pos);
}
public int getCurrentFrame() {
return getRoot().getCurrentFrame();
}
public Node getParent() {
return parent;
}
public Vec2f getPos() {
return pos;
}
public NodeRoot getRoot() {
var node = this;
while(node.parent != null) {
@ -70,16 +59,27 @@ public class Node implements Iterable<Node> {
return children.iterator();
}
public int getCurrentFrame() {
return getRoot().getCurrentFrame();
}
protected void prepareTween(BaseTween tween, int frames) {
var root = getRoot();
tween.startFrame = root.getCurrentFrame();
tween.endFrame = tween.startFrame + frames;
}
public void remove(Node node) {
node.parent = null;
children.remove(node);
}
public void render(IRenderContext rc) {
for(var child : this) {
child.render(rc);
}
}
public void setPos(Vec2f pos) {
this.pos = pos;
}
public TweenPos tweenPos(Vec2f to, int frames) {
var tween = new TweenPos();
tween.start = pos;
@ -91,8 +91,8 @@ public class Node implements Iterable<Node> {
public class TweenPos extends BaseTween {
private Vec2f start;
private Vec2f end;
private Vec2f start;
@Override
protected void apply() {

View File

@ -1,10 +1,9 @@
package com.danitheskunk.skunkworks.nodes;
import com.danitheskunk.skunkworks.Timestep;
import com.danitheskunk.skunkworks.Vec2f;
public class NodeRoot extends Node {
private Tweener tweener;
private final Tweener tweener;
public NodeRoot() {
tweener = new Tweener(Timestep.FIXED);
@ -15,11 +14,11 @@ public class NodeRoot extends Node {
return tweener.getCurrentFrame();
}
public void tick() {
tweener.tick();
}
public Tweener getTweener() {
return tweener;
}
public void tick() {
tweener.tick();
}
}

View File

@ -15,12 +15,12 @@ public class NodeSprite extends Node {
return texture;
}
public void setTexture(ITexture texture) {
this.texture = texture;
}
@Override
public void render(IRenderContext rc) {
rc.drawTexture(getAbsolutePos().toVec2i(), texture);
}
public void setTexture(ITexture texture) {
this.texture = texture;
}
}

View File

@ -6,9 +6,9 @@ import java.util.ArrayList;
import java.util.List;
public class Tweener {
private Timestep timestepMode;
private List<BaseTween> tweens;
private int currentFrame;
private final Timestep timestepMode;
private final List<BaseTween> tweens;
public Tweener(Timestep timestepMode) {
this.timestepMode = timestepMode;
@ -16,6 +16,10 @@ public class Tweener {
this.currentFrame = 0;
}
public void add(BaseTween tween) {
tweens.add(tween);
}
public int getCurrentFrame() {
return currentFrame;
}
@ -43,8 +47,4 @@ public class Tweener {
}
++currentFrame;
}
public void add(BaseTween tween) {
tweens.add(tween);
}
}

View File

@ -8,45 +8,44 @@ import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.win32.W32APIOptions;
public interface Dwm extends Library {
Dwm INSTANCE = Native.load(
"dwmapi",
WinDef.DWORD DWMWA_ALLOW_NCPAINT = new WinDef.DWORD(4);
WinDef.DWORD DWMWA_CAPTION_BUTTON_BOUNDS = new WinDef.DWORD(5);
WinDef.DWORD DWMWA_CLOAK = new WinDef.DWORD(13);
WinDef.DWORD DWMWA_CLOAKED = new WinDef.DWORD(14);
WinDef.DWORD DWMWA_DISALLOW_PEEK = new WinDef.DWORD(11);
WinDef.DWORD DWMWA_EXCLUDED_FROM_PEEK = new WinDef.DWORD(12);
WinDef.DWORD DWMWA_EXTENDED_FRAME_BOUNDS = new WinDef.DWORD(9);
WinDef.DWORD DWMWA_FLIP3D_POLICY = new WinDef.DWORD(8);
WinDef.DWORD DWMWA_FORCE_ICONIC_REPRESENTATION = new WinDef.DWORD(7);
WinDef.DWORD DWMWA_FREEZE_REPRESENTATION = new WinDef.DWORD(15);
WinDef.DWORD DWMWA_HAS_ICONIC_BITMAP = new WinDef.DWORD(10);
WinDef.DWORD DWMWA_LAST = new WinDef.DWORD(16);
WinDef.DWORD DWMWA_NCRENDERING_ENABLED = new WinDef.DWORD(1);
WinDef.DWORD DWMWA_NCRENDERING_POLICY = new WinDef.DWORD(2);
WinDef.DWORD DWMWA_NONCLIENT_RTL_LAYOUT = new WinDef.DWORD(6);
WinDef.DWORD DWMWA_TRANSITIONS_FORCEDISABLED = new WinDef.DWORD(3);
WinDef.DWORD DWMWA_WINDOW_CORNER_PREFERENCE = new WinDef.DWORD(33);
WinDef.DWORD DWMWCP_DEFAULT = new WinDef.DWORD(0);
//todo: fix/complete DWMWA list
WinDef.DWORD DWMWCP_DONOTROUND = new WinDef.DWORD(1);
WinDef.DWORD DWMWCP_ROUND = new WinDef.DWORD(2);
WinDef.DWORD DWMWCP_ROUNDSMALL = new WinDef.DWORD(3);
Dwm INSTANCE = Native.load("dwmapi",
Dwm.class,
W32APIOptions.DEFAULT_OPTIONS
);
WinNT.HRESULT DwmExtendFrameIntoClientArea(
WinDef.HWND hwnd, MARGINS pMarInset
);
WinDef.DWORD DWMWA_NCRENDERING_ENABLED = new WinDef.DWORD(1);
WinDef.DWORD DWMWA_NCRENDERING_POLICY = new WinDef.DWORD(2);
WinDef.DWORD DWMWA_TRANSITIONS_FORCEDISABLED = new WinDef.DWORD(3);
WinDef.DWORD DWMWA_ALLOW_NCPAINT = new WinDef.DWORD(4);
WinDef.DWORD DWMWA_CAPTION_BUTTON_BOUNDS = new WinDef.DWORD(5);
WinDef.DWORD DWMWA_NONCLIENT_RTL_LAYOUT = new WinDef.DWORD(6);
WinDef.DWORD DWMWA_FORCE_ICONIC_REPRESENTATION = new WinDef.DWORD(7);
WinDef.DWORD DWMWA_FLIP3D_POLICY = new WinDef.DWORD(8);
WinDef.DWORD DWMWA_EXTENDED_FRAME_BOUNDS = new WinDef.DWORD(9);
WinDef.DWORD DWMWA_HAS_ICONIC_BITMAP = new WinDef.DWORD(10);
WinDef.DWORD DWMWA_DISALLOW_PEEK = new WinDef.DWORD(11);
WinDef.DWORD DWMWA_EXCLUDED_FROM_PEEK = new WinDef.DWORD(12);
WinDef.DWORD DWMWA_CLOAK = new WinDef.DWORD(13);
WinDef.DWORD DWMWA_CLOAKED = new WinDef.DWORD(14);
WinDef.DWORD DWMWA_FREEZE_REPRESENTATION = new WinDef.DWORD(15);
WinDef.DWORD DWMWA_LAST = new WinDef.DWORD(16);
WinDef.DWORD DWMWA_WINDOW_CORNER_PREFERENCE = new WinDef.DWORD(33);
//todo: fix/complete DWMWA list
WinNT.HRESULT DwmGetWindowAttribute(
WinDef.HWND hwnd, WinDef.DWORD dwAttribute, Pointer pvAttribute,
WinDef.DWORD cbAttribute
);
WinDef.DWORD DWMWCP_DEFAULT = new WinDef.DWORD(0);
WinDef.DWORD DWMWCP_DONOTROUND = new WinDef.DWORD(1);
WinDef.DWORD DWMWCP_ROUND = new WinDef.DWORD(2);
WinDef.DWORD DWMWCP_ROUNDSMALL = new WinDef.DWORD(3);
WinNT.HRESULT DwmExtendFrameIntoClientArea(WinDef.HWND hwnd,
MARGINS pMarInset);
WinNT.HRESULT DwmGetWindowAttribute(WinDef.HWND hwnd,
WinDef.DWORD dwAttribute, Pointer pvAttribute,
WinDef.DWORD cbAttribute);
WinNT.HRESULT DwmSetWindowAttribute(WinDef.HWND hwnd,
WinDef.DWORD dwAttribute, Pointer pvAttribute,
WinDef.DWORD cbAttribute);
WinNT.HRESULT DwmSetWindowAttribute(
WinDef.HWND hwnd, WinDef.DWORD dwAttribute, Pointer pvAttribute,
WinDef.DWORD cbAttribute
);
}

View File

@ -9,13 +9,12 @@ public class MARGINS extends Structure implements Structure.ByReference {
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
public int cyTopHeight;
@Override
protected List<String> getFieldOrder() {
return Arrays.asList(
"cxLeftWidth",
return Arrays.asList("cxLeftWidth",
"cxRightWidth",
"cyTopHeight",
"cyBottomHeight"

View File

@ -5,15 +5,15 @@ import com.sun.jna.platform.win32.WinDef;
@Structure.FieldOrder({"cbSize", "rcTitleBar", "rgstate"})
public class TITLEBARINFO extends Structure {
// Index constants
public static final int TITLE_BAR = 0;
public static final int RESERVED = 1;
public static final int MINIMIZE_BUTTON = 2;
public static final int MAXIMIZE_BUTTON = 3;
public static final int HELP_BUTTON = 4;
public static final int CLOSE_BUTTON = 5;
// Child amount constant
public static final int CCHILDREN_TITLEBAR = 5;
public static final int CLOSE_BUTTON = 5;
public static final int HELP_BUTTON = 4;
public static final int MAXIMIZE_BUTTON = 3;
public static final int MINIMIZE_BUTTON = 2;
public static final int RESERVED = 1;
// Index constants
public static final int TITLE_BAR = 0;
public int cbSize;
public WinDef.RECT rcTitleBar;
public int[] rgstate;

View File

@ -6,19 +6,26 @@ import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.win32.W32APIOptions;
public interface User32Extra extends User32 {
User32Extra INSTANCE = Native.load(
"user32",
int HSHELL_WINDOWCREATED = 1;
User32Extra INSTANCE = Native.load("user32",
User32Extra.class,
W32APIOptions.DEFAULT_OPTIONS
);
int PM_NOREMOVE = 0x00;
int PM_NOYIELD = 0x02;
int PM_REMOVE = 0x01;
// States
int STATE_SYSTEM_FOCUSABLE = 0x00100000;
int STATE_SYSTEM_INVISIBLE = 0x00008000;
int STATE_SYSTEM_OFFSCREEN = 0x00010000;
int STATE_SYSTEM_UNAVAILABLE = 0x00000001;
int STATE_SYSTEM_PRESSED = 0x00000008;
int STATE_SYSTEM_UNAVAILABLE = 0x00000001;
// https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes
int VK_LBUTTON = 0x01;
int VK_MBUTTON = 0x04;
int VK_RBUTTON = 0x02;
int WH_SHELL = 10;
int WM_TIMER = 0x0113;
// Extended Styles
// https://docs.microsoft.com/en-gb/windows/desktop/winmsg/extended-window-styles
int WS_EX_ACCEPTFILES = 0x00000010;
@ -46,40 +53,23 @@ public interface User32Extra extends User32 {
int WS_EX_TOPMOST = 0x00000008;
int WS_EX_TRANSPARENT = 0x00000020;
int WS_EX_WINDOWEDGE = 0x00000100;
long WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE);
long WS_EX_PALETTEWINDOW = (
WS_EX_WINDOWEDGE |
WS_EX_TOOLWINDOW |
WS_EX_TOPMOST
WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST
);
int WH_SHELL = 10;
int WM_TIMER = 0x0113;
int HSHELL_WINDOWCREATED = 1;
// https://docs.microsoft.com/en-us/windows/desktop/inputdev/virtual-key-codes
int VK_LBUTTON = 0x01;
int VK_RBUTTON = 0x02;
int VK_MBUTTON = 0x04;
int PM_NOREMOVE = 0x00;
int PM_REMOVE = 0x01;
int PM_NOYIELD = 0x02;
// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-gettitlebarinfo
boolean GetTitleBarInfo(WinDef.HWND hwnd, TITLEBARINFO titlebarinfo);
HCURSOR GetCursor();
// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getlastactivepopup
WinDef.HWND GetLastActivePopup(WinDef.HWND hwnd);
// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-isiconic
boolean IsIconic(WinDef.HWND hwnd);
HCURSOR GetCursor();
// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-gettitlebarinfo
boolean GetTitleBarInfo(WinDef.HWND hwnd, TITLEBARINFO titlebarinfo);
WinDef.HWND GetTopWindow(HWND hWnd);
WinDef.HWND GetWindow(HWND hWnd, int flag);
// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-isiconic
boolean IsIconic(WinDef.HWND hwnd);
}

View File

@ -6,12 +6,12 @@ import com.sun.jna.win32.W32APIOptions;
public interface WinUserExtra extends WinUser,
com.sun.jna.win32.StdCallLibrary {
WinUserExtra INSTANCE = Native.load(
"user32",
WinUserExtra INSTANCE = Native.load("user32",
WinUserExtra.class,
W32APIOptions.DEFAULT_OPTIONS
);
//todo: lpTimerFunc should be TIMERPROC
UINT_PTR SetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, PVOID lpTimerFunc);
UINT_PTR SetTimer(HWND hWnd, UINT_PTR nIDEvent, UINT uElapse,
PVOID lpTimerFunc);
}

View File

@ -12,7 +12,7 @@ import java.util.ArrayList;
import java.util.List;
public class Window {
private WinDef.HWND hwnd;
private final WinDef.HWND hwnd;
public Window(WinDef.HWND hwnd) {
this.hwnd = hwnd;
@ -62,13 +62,13 @@ public class Window {
public static void onKey() {
var user32 = User32Extra.INSTANCE;
var kernel32 = Kernel32.INSTANCE;
var res = user32.SetWindowsHookEx(
User32Extra.WH_KEYBOARD_LL,
var res = user32.SetWindowsHookEx(User32Extra.WH_KEYBOARD_LL,
new WinUser.HOOKPROC() {
public WinDef.LRESULT callback(int nCode, WinDef.WPARAM wparam
, WinDef.LPARAM lparam) {
var kb = new WinUser.KBDLLHOOKSTRUCT().newInstance(
WinUser.KBDLLHOOKSTRUCT.class,
public WinDef.LRESULT callback(
int nCode, WinDef.WPARAM wparam, WinDef.LPARAM lparam
) {
var kb =
new WinUser.KBDLLHOOKSTRUCT().newInstance(WinUser.KBDLLHOOKSTRUCT.class,
lparam.toPointer()
);
System.out.println(kb.vkCode);
@ -105,11 +105,11 @@ public class Window {
var kernel32 = Kernel32.INSTANCE;
var hmod = kernel32.GetModuleHandle("kernel32.dll");
//todo: try RegisterShellHookWindow instead
var res = user32.SetWindowsHookEx(
User32Extra.WH_SHELL,
var res = user32.SetWindowsHookEx(User32Extra.WH_SHELL,
new WinUser.HOOKPROC() {
public WinDef.LRESULT callback(int nCode, WinDef.WPARAM wparam
, WinDef.LPARAM lparam) {
public WinDef.LRESULT callback(
int nCode, WinDef.WPARAM wparam, WinDef.LPARAM lparam
) {
System.out.println("got some message b");
if(nCode == User32Extra.HSHELL_WINDOWCREATED) {
System.out.println("window created");
@ -163,7 +163,7 @@ public class Window {
if((style & User32.WS_TILED) != 0) str.append("ws_tiled, ");
if((style & User32.WS_VISIBLE) != 0) str.append("ws_visible, ");
if((style & User32.WS_VSCROLL) != 0) str.append("ws_vscroll, ");
System.out.println(str.toString());
System.out.println(str);
}
public void debugPrintStylesEx() {
@ -218,7 +218,184 @@ public class Window {
"ws_ex_transparent, ");
if((style & User32Extra.WS_EX_WINDOWEDGE) != 0) str.append(
"ws_ex_windowedge, ");
System.out.println(str.toString());
System.out.println(str);
}
@Override
public boolean equals(Object o) {
if(!(o instanceof Window)) {
return false;
}
return ((Window) o).hwnd.equals(this.hwnd);
}
public String getClassName() {
var user32 = User32Extra.INSTANCE;
char[] chars = new char[1024];
user32.GetClassName(hwnd, chars, 1024);
return Util.nullTerminatedCharArrayToString(chars);
}
public String getExecutableName() {
var user32 = User32Extra.INSTANCE;
var kernel32 = Kernel32.INSTANCE;
var handle =
kernel32.OpenProcess(WinNT.PROCESS_QUERY_LIMITED_INFORMATION,
false,
getProcessId()
);
char[] chars = new char[1024];
var len = new IntByReference();
len.setValue(1024);
kernel32.QueryFullProcessImageName(handle, 0, chars, len);
return Util.nullTerminatedCharArrayToString(chars);
}
public String getKey() {
return getExecutableName() + " $ " + getClassName();
}
private int getProcessId() {
var user32 = User32Extra.INSTANCE;
var ref = new IntByReference();
user32.GetWindowThreadProcessId(hwnd, ref);
return ref.getValue();
}
private int getStyle() {
var user32 = User32Extra.INSTANCE;
return user32.GetWindowLong(hwnd, WinUser.GWL_STYLE);
}
private int getStyleEx() {
var user32 = User32Extra.INSTANCE;
return user32.GetWindowLong(hwnd, WinUser.GWL_EXSTYLE);
}
public String getTitle() {
var user32 = User32Extra.INSTANCE;
char[] chars = new char[1024];
user32.GetWindowText(hwnd, chars, 1024);
return Util.nullTerminatedCharArrayToString(chars);
}
private TITLEBARINFO getTitleBarInfo() {
var user32 = User32Extra.INSTANCE;
var tb = new TITLEBARINFO();
user32.GetTitleBarInfo(hwnd, tb);
return tb;
}
public boolean isClass(String str) {
return str.equals(getClassName());
}
public boolean isDwmCloaked() {
var user32 = User32Extra.INSTANCE;
var dwm = Dwm.INSTANCE;
var out = new IntByReference();
dwm.DwmGetWindowAttribute(hwnd,
Dwm.DWMWA_CLOAKED,
out.getPointer(),
new WinDef.DWORD(WinDef.DWORD.SIZE)
);
var val = out.getValue();
return val != 0;
}
public boolean isExecutableName(String str) {
return str.equals(getExecutableName());
}
public boolean isInAltTabList() {
var user32 = User32Extra.INSTANCE;
var walk = user32.GetAncestor(hwnd, WinUser.GA_ROOTOWNER);
WinDef.HWND test;
var window = new Window(hwnd);
if(walk == null) return false;
return walk.equals(hwnd) &&
user32.IsWindowVisible(hwnd) &&
window.getTitle().length() > 0 &&
!window.isToolWindow() &&
!window.isDwmCloaked() &&
!window.getClassName().equals("Progman");
}
private boolean isTitleBarVisible() {
var tb = getTitleBarInfo();
return (tb.rgstate[0] & User32Extra.STATE_SYSTEM_INVISIBLE) == 0;
}
public boolean isToolWindow() {
return (getStyleEx() & User32Extra.WS_EX_TOOLWINDOW) != 0;
}
public void move(Recti rectangle) {
var user32 = User32Extra.INSTANCE;
var dwm = Dwm.INSTANCE;
var pos = rectangle.getPos();
var size = rectangle.getSize();
var rect_with_shadow = new WinDef.RECT();
var rect_without_shadow = new WinDef.RECT();
var rect = new WinDef.RECT();
user32.GetWindowRect(hwnd, rect_with_shadow);
dwm.DwmGetWindowAttribute(hwnd,
Dwm.DWMWA_EXTENDED_FRAME_BOUNDS,
rect_without_shadow.getPointer(),
new WinDef.DWORD(rect_without_shadow.size())
);
rect_without_shadow.read();
var left_shadow = rect_without_shadow.left - rect_with_shadow.left;
var right_shadow = rect_with_shadow.right - rect_without_shadow.right;
var top_shadow = rect_without_shadow.top - rect_with_shadow.top;
var bottom_shaddow = rect_with_shadow.bottom -
rect_without_shadow.bottom;
rect.left = pos.getX() - left_shadow;
rect.top = pos.getY() - top_shadow;
rect.right = pos.getX() + size.getX() + right_shadow;
rect.bottom = pos.getY() + size.getY() + bottom_shaddow;
//user32.AdjustWindowRect(rect, new WinDef.DWORD(WinUser
// .WS_OVERLAPPEDWINDOW), new WinDef.BOOL(false));
//var style = getStyle();
//var styleex = getStyleEx();
//style &= ~(User32Extra.WS_CAPTION | User32Extra.WS_MINIMIZEBOX |
// User32Extra.WS_SYSMENU);
//styleex &= ~(User32Extra.WS_EX_DLGMODALFRAME | User32Extra
// .WS_EX_CLIENTEDGE | User32Extra.WS_EX_STATICEDGE);
//style |= User32Extra.WS_POPUP;
//user32.AdjustWindowRectEx(rect, new WinDef.DWORD(style), new WinDef
// .BOOL(false), new WinDef.DWORD(styleex));
user32.MoveWindow(hwnd,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
true
);
//user32.MoveWindow(hwnd, pos.getX(), pos.getY(), size.getX(), size
// .getY(), true);
user32.SetWindowPos(hwnd,
null,
0,
0,
0,
0,
WinUser.SWP_FRAMECHANGED |
WinUser.SWP_NOZORDER |
WinUser.SWP_NOOWNERZORDER |
WinUser.SWP_NOMOVE |
WinUser.SWP_NOSIZE |
WinUser.SWP_NOACTIVATE
);
}
public void setBorder(boolean border) {
@ -259,202 +436,20 @@ public class Window {
public void setBorderRounded(boolean rounded) {
var round = rounded ? Dwm.DWMWCP_ROUND : Dwm.DWMWCP_DONOTROUND;
var roundref = new WinDef.DWORDByReference(round);
Dwm.INSTANCE.DwmSetWindowAttribute(
hwnd,
Dwm.INSTANCE.DwmSetWindowAttribute(hwnd,
Dwm.DWMWA_WINDOW_CORNER_PREFERENCE,
roundref.getPointer(),
new WinDef.DWORD(WinDef.DWORD.SIZE)
);
}
public String getClassName() {
var user32 = User32Extra.INSTANCE;
char[] chars = new char[1024];
user32.GetClassName(hwnd, chars, 1024);
return Util.nullTerminatedCharArrayToString(chars);
}
public String getExecutableName() {
var user32 = User32Extra.INSTANCE;
var kernel32 = Kernel32.INSTANCE;
var handle = kernel32.OpenProcess(
WinNT.PROCESS_QUERY_LIMITED_INFORMATION,
false,
getProcessId()
);
char[] chars = new char[1024];
var len = new IntByReference();
len.setValue(1024);
kernel32.QueryFullProcessImageName(handle, 0, chars, len);
return Util.nullTerminatedCharArrayToString(chars);
}
public String getKey() {
return getExecutableName() + " $ " + getClassName();
}
private int getStyle() {
var user32 = User32Extra.INSTANCE;
return user32.GetWindowLong(hwnd, WinUser.GWL_STYLE);
}
private void setStyle(int style) {
var user32 = User32Extra.INSTANCE;
user32.SetWindowLong(hwnd, WinUser.GWL_STYLE, style);
}
private int getStyleEx() {
var user32 = User32Extra.INSTANCE;
return user32.GetWindowLong(hwnd, WinUser.GWL_EXSTYLE);
}
private void setStyleEx(int style) {
var user32 = User32Extra.INSTANCE;
user32.SetWindowLong(hwnd, WinUser.GWL_EXSTYLE, style);
}
private boolean isTitleBarVisible() {
var tb = getTitleBarInfo();
return (tb.rgstate[0] & User32Extra.STATE_SYSTEM_INVISIBLE) == 0;
}
public String getTitle() {
var user32 = User32Extra.INSTANCE;
char[] chars = new char[1024];
user32.GetWindowText(hwnd, chars, 1024);
return Util.nullTerminatedCharArrayToString(chars);
}
private TITLEBARINFO getTitleBarInfo() {
var user32 = User32Extra.INSTANCE;
var tb = new TITLEBARINFO();
user32.GetTitleBarInfo(hwnd, tb);
return tb;
}
private int getProcessId() {
var user32 = User32Extra.INSTANCE;
var ref = new IntByReference();
user32.GetWindowThreadProcessId(hwnd, ref);
return ref.getValue();
}
public boolean isDwmCloaked() {
var user32 = User32Extra.INSTANCE;
var dwm = Dwm.INSTANCE;
var out = new IntByReference();
dwm.DwmGetWindowAttribute(
hwnd,
Dwm.DWMWA_CLOAKED,
out.getPointer(),
new WinDef.DWORD(WinDef.DWORD.SIZE)
);
var val = out.getValue();
return val != 0;
}
public boolean isClass(String str) {
return str.equals(getClassName());
}
public boolean isExecutableName(String str) {
return str.equals(getExecutableName());
}
public boolean isInAltTabList() {
var user32 = User32Extra.INSTANCE;
var walk = user32.GetAncestor(hwnd, WinUser.GA_ROOTOWNER);
WinDef.HWND test;
var window = new Window(hwnd);
if(walk == null) return false;
return walk.equals(hwnd) &&
user32.IsWindowVisible(hwnd) &&
window.getTitle().length() > 0 &&
!window.isToolWindow() &&
!window.isDwmCloaked() &&
!window.getClassName().equals("Progman");
}
public boolean isToolWindow() {
return (getStyleEx() & User32Extra.WS_EX_TOOLWINDOW) != 0;
}
public void move(Recti rectangle) {
var user32 = User32Extra.INSTANCE;
var dwm = Dwm.INSTANCE;
var pos = rectangle.getPos();
var size = rectangle.getSize();
var rect_with_shadow = new WinDef.RECT();
var rect_without_shadow = new WinDef.RECT();
var rect = new WinDef.RECT();
user32.GetWindowRect(hwnd, rect_with_shadow);
dwm.DwmGetWindowAttribute(
hwnd,
Dwm.DWMWA_EXTENDED_FRAME_BOUNDS,
rect_without_shadow.getPointer(),
new WinDef.DWORD(rect_without_shadow.size())
);
rect_without_shadow.read();
var left_shadow = rect_without_shadow.left - rect_with_shadow.left;
var right_shadow = rect_with_shadow.right - rect_without_shadow.right;
var top_shadow = rect_without_shadow.top - rect_with_shadow.top;
var bottom_shaddow = rect_with_shadow.bottom -
rect_without_shadow.bottom;
rect.left = pos.getX() - left_shadow;
rect.top = pos.getY() - top_shadow;
rect.right = pos.getX() + size.getX() + right_shadow;
rect.bottom = pos.getY() + size.getY() + bottom_shaddow;
//user32.AdjustWindowRect(rect, new WinDef.DWORD(WinUser
// .WS_OVERLAPPEDWINDOW), new WinDef.BOOL(false));
//var style = getStyle();
//var styleex = getStyleEx();
//style &= ~(User32Extra.WS_CAPTION | User32Extra.WS_MINIMIZEBOX |
// User32Extra.WS_SYSMENU);
//styleex &= ~(User32Extra.WS_EX_DLGMODALFRAME | User32Extra
// .WS_EX_CLIENTEDGE | User32Extra.WS_EX_STATICEDGE);
//style |= User32Extra.WS_POPUP;
//user32.AdjustWindowRectEx(rect, new WinDef.DWORD(style), new WinDef
// .BOOL(false), new WinDef.DWORD(styleex));
user32.MoveWindow(
hwnd,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
true
);
//user32.MoveWindow(hwnd, pos.getX(), pos.getY(), size.getX(), size
// .getY(), true);
user32.SetWindowPos(
hwnd,
null,
0,
0,
0,
0,
WinUser.SWP_FRAMECHANGED |
WinUser.SWP_NOZORDER |
WinUser.SWP_NOOWNERZORDER |
WinUser.SWP_NOMOVE |
WinUser.SWP_NOSIZE |
WinUser.SWP_NOACTIVATE
);
}
@Override
public boolean equals(Object o) {
if(!(o instanceof Window)) {
return false;
}
return ((Window) o).hwnd.equals(this.hwnd);
}
}