glViewport(0, 0, viewportWidth, viewportHeight)
38 | * glClearColor(clearColorR, G, B, A)
39 | * glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)
40 | */
41 | public static void glClearFrame(int viewportWidth, int viewportHeight, float clearColorR, float clearColorG, float clearColorB, float clearColorA) {
42 | glViewport(0, 0, viewportWidth, viewportHeight);
43 | glClearColor(clearColorR, clearColorG, clearColorB, clearColorA);
44 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
45 | }
46 |
47 | /**
48 | * Automatically configures NanoVG for rendering a single frame (nvgBeginFrame(context)
). If this is called, make sure endFrame()
is called at the end of the corresponding frame.
49 | *
50 | * @param windowWidth - the actual window width in pixels
51 | * @param windowHeight - the actual window height in pixels
52 | * @param framebufferWidth - the window framebuffer width (internal rendering)
53 | * @param framebufferHeight - the window framebuffer height (internal rendering)
54 | */
55 | public void beginFrame(int windowWidth, int windowHeight, int framebufferWidth, int framebufferHeight) {
56 | this.framebufferWidth = framebufferWidth;
57 | this.framebufferHeight = framebufferHeight;
58 |
59 | float pxRatio = (float) framebufferWidth / (float) windowHeight;
60 | nvgBeginFrame(nvgContext, windowWidth, windowHeight, pxRatio);
61 | }
62 |
63 | /**
64 | * Ends the current frame of rendering (nvgEndFrame(context)
)
65 | */
66 | public void endFrame() {
67 | nvgEndFrame(nvgContext);
68 | }
69 |
70 | /**
71 | * @return true if the machine this program is running on supports modern OpenGL (Version 3 and above)
72 | */
73 | public boolean isModernOpenGL() {
74 | return modernOpenGL;
75 | }
76 |
77 | /**
78 | * @return the NanoVG context long ID.
79 | */
80 | public long get() {
81 | return nvgContext;
82 | }
83 |
84 | /**
85 | * @return the framebuffer width of the window configured in beginFrame()
86 | */
87 | public int getFramebufferWidth() {
88 | return framebufferWidth;
89 | }
90 |
91 | /**
92 | * @return the framebuffer height of the window configured in beginFrame()
93 | */
94 | public int getFramebufferHeight() {
95 | return framebufferHeight;
96 | }
97 |
98 | /**
99 | * Disposes this NanoVG context.
100 | */
101 | public void dispose() {
102 | if (modernOpenGL) {
103 | NanoVGGL3.nvgDelete(nvgContext);
104 | } else {
105 | NanoVGGL2.nvgDelete(nvgContext);
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/apps/ClearInputApp.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.apps;
2 |
3 | import nokori.clear.vg.ClearApp;
4 | import nokori.clear.vg.ClearColor;
5 | import nokori.clear.vg.NanoVGContext;
6 | import nokori.clear.vg.font.Font;
7 | import nokori.clear.vg.font.FontStyle;
8 | import nokori.clear.vg.widget.ButtonAssembly;
9 | import nokori.clear.vg.widget.LabelWidget;
10 | import nokori.clear.vg.widget.assembly.RootWidgetAssembly;
11 | import nokori.clear.vg.widget.assembly.WidgetAssembly;
12 | import nokori.clear.vg.widget.assembly.WidgetClip;
13 | import nokori.clear.vg.widget.text.TextFieldWidget;
14 | import nokori.clear.windows.GLFWException;
15 | import nokori.clear.windows.Window;
16 | import nokori.clear.windows.WindowManager;
17 |
18 | import java.io.File;
19 | import java.io.IOException;
20 |
21 | /**
22 | * This ClearApp is an input window you can open and use to get user input. See ClearInputAppDemo.java to learn more about it.
23 | */
24 | public abstract class ClearInputApp extends ClearApp {
25 |
26 | private static final int FONT_SIZE = 16;
27 |
28 | private int width, height;
29 | private ClearApp parent;
30 | private ClearColor buttonOutline;
31 | private File fontLocation;
32 | private String title, message, defaultInput;
33 |
34 | public ClearInputApp(ClearApp parent, int windowWidth, int windowHeight, ClearColor buttonOutline, File fontLocation, String title, String message, String defaultInput) {
35 | this(parent.getWindowManager(), new RootWidgetAssembly(), parent, windowWidth, windowHeight, buttonOutline, fontLocation, title, message, defaultInput);
36 | }
37 |
38 | private ClearInputApp(WindowManager windowManager, WidgetAssembly rootWidgetAssembly,
39 | ClearApp parent, int windowWidth, int windowHeight, ClearColor buttonOutline, File fontLocation, String title, String message, String defaultInput) {
40 |
41 | super(windowManager, rootWidgetAssembly);
42 | this.parent = parent;
43 | this.width = windowWidth;
44 | this.height = windowHeight;
45 | this.buttonOutline = buttonOutline;
46 | this.fontLocation = fontLocation;
47 | this.title = title;
48 | this.message = message;
49 | this.defaultInput = defaultInput;
50 | }
51 |
52 | public void show() throws GLFWException {
53 | parent.setPaused(true);
54 | parent.queueLaunch(this);
55 | }
56 |
57 | @Override
58 | public void init(WindowManager windowManager, Window window, NanoVGContext context, WidgetAssembly rootWidgetAssembly, String[] args) {
59 |
60 | float xPadding = 20f;
61 | float yPadding = 20f;
62 |
63 | try {
64 | Font font = new Font(fontLocation).load(context);
65 |
66 | /*
67 | * Message
68 | */
69 |
70 | float widgetWidth = width - (xPadding * 2f);
71 |
72 | LabelWidget messageLabel = new LabelWidget(widgetWidth, ClearColor.LIGHT_BLACK, message, font, FontStyle.REGULAR, FONT_SIZE).calculateBounds(context);
73 | messageLabel.addChild(new WidgetClip(WidgetClip.Alignment.TOP_LEFT, xPadding, yPadding));
74 |
75 | rootWidgetAssembly.addChild(messageLabel);
76 |
77 | /*
78 | * Input field
79 | */
80 |
81 | TextFieldWidget inputField = new TextFieldWidget(widgetWidth, ClearColor.LIGHT_BLACK, defaultInput, font, FONT_SIZE);
82 | inputField.setBackgroundFill(ClearColor.LIGHT_GRAY);
83 | inputField.addChild(new WidgetClip(WidgetClip.Alignment.TOP_LEFT, xPadding, (yPadding * 2f) + messageLabel.getHeight()));
84 |
85 | rootWidgetAssembly.addChild(inputField);
86 |
87 | /*
88 | * Confirm button
89 | */
90 |
91 | float buttonSynchX = xPadding;
92 | float buttonSynchY = (yPadding * 4f) + messageLabel.getHeight() + inputField.getHeight();
93 |
94 | ButtonAssembly confirmButton = new ButtonAssembly(75, 25, ClearColor.LIGHT_GRAY, buttonOutline, 0f, font, FONT_SIZE, ClearColor.LIGHT_BLACK, "Confirm");
95 | confirmButton.addChild(new WidgetClip(WidgetClip.Alignment.TOP_LEFT, buttonSynchX, buttonSynchY));
96 |
97 | confirmButton.setOnMouseButtonEvent(e -> {
98 | if (confirmButton.isMouseWithin() && !e.isPressed()) {
99 | confirmButtonPressed(inputField.getTextBuilder().toString());
100 | window.requestClose();
101 | }
102 | });
103 |
104 | rootWidgetAssembly.addChild(confirmButton);
105 |
106 | /*
107 | * Exit button
108 | */
109 |
110 | ButtonAssembly exitButton = new ButtonAssembly(75, 25, ClearColor.LIGHT_GRAY, buttonOutline, 0f, font, FONT_SIZE, ClearColor.LIGHT_BLACK, "Cancel");
111 | exitButton.addChild(new WidgetClip(WidgetClip.Alignment.TOP_LEFT, buttonSynchX + confirmButton.getWidth() + xPadding, buttonSynchY));
112 |
113 | exitButton.setOnMouseButtonEvent(e -> {
114 | if (exitButton.isMouseWithin() && !e.isPressed()) {
115 | window.requestClose();
116 | }
117 | });
118 |
119 | rootWidgetAssembly.addChild(exitButton);
120 |
121 | } catch (IOException e) {
122 | e.printStackTrace();
123 | }
124 | }
125 |
126 | protected abstract void confirmButtonPressed(String text);
127 |
128 | @Override
129 | protected void endOfNanoVGApplicationCallback() {
130 | parent.setPaused(false);
131 | }
132 |
133 | @Override
134 | public Window createWindow(WindowManager windowManager) throws GLFWException {
135 | Window parentWindow = parent.getWindow();
136 |
137 | int centerX = parentWindow.getX() + parentWindow.getWidth()/2 - width/2;
138 | int centerY = parentWindow.getY() + parentWindow.getHeight()/2 - height/2;
139 |
140 | Window newWindow = windowManager.createWindow(title, centerX, centerY, width, height, false, true);
141 |
142 | if (parentWindow.getIconFiles() != null) {
143 | newWindow.setIcons(parentWindow.getIconFiles());
144 | }
145 |
146 | return newWindow;
147 | }
148 |
149 | @Override
150 | protected boolean exitProgramOnEndOfApplication() {
151 | return false;
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/font/Font.java:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SkyAphid/Clear/2c553ad948010a1259f9d5136f5079883ec7d31c/ClearVG/src/main/java/nokori/clear/vg/font/Font.java
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/font/FontStyle.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.font;
2 |
3 | public enum FontStyle {
4 | REGULAR, BOLD, LIGHT, ITALIC;
5 | }
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/transition/FillTransition.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.transition;
2 |
3 | import nokori.clear.vg.ClearColor;
4 |
5 | /**
6 | * This transition will transition the fill from one color to another smoothly over time.
7 | */
8 | public class FillTransition extends Transition {
9 |
10 | private ClearColor fromFill, toFill, storeFill;
11 |
12 | /**
13 | * Transitions one color to another. This constructor is simplified to where the color that the result is stored in is also the one that the transition starts at.
14 | *
15 | * @param durationInMillis - time in milliseconds for the transition to occur
16 | * @param fromAndStoreFill - the starting fill and the fill to store the blend results in
17 | * @param toFill - the destination fill
18 | */
19 | public FillTransition(long durationInMillis, ClearColor fromAndStoreFill, ClearColor toFill) {
20 | this(durationInMillis, fromAndStoreFill, toFill, fromAndStoreFill);
21 | }
22 |
23 | /**
24 | * Transitions one color to another and stores the result in a third color. If you set a Control's fill with the storeFill, it should be automatically updated
25 | * as this Transition progresses (if you're using an immutable color, use copy() when setting it on the Control to ensure that it's recycled).
26 | *
27 | * @param durationInMillis - time in milliseconds for the transition to occur
28 | * @param fromFill - the starting fill
29 | * @param toFill - the destination fill
30 | * @param storeFill - the fill to store the blend results in
31 | */
32 | public FillTransition(long durationInMillis, ClearColor fromFill, ClearColor toFill, ClearColor storeFill) {
33 | super(durationInMillis);
34 | this.fromFill = fromFill;
35 | this.toFill = toFill;
36 | this.storeFill = storeFill;
37 | }
38 |
39 | @Override
40 | public void tick(float progress) {
41 | blend(fromFill, toFill, storeFill, progress);
42 | }
43 |
44 | protected void blend(ClearColor fromFill, ClearColor toFill, ClearColor storeFill, float progress) {
45 | ClearColor.blend(fromFill, toFill, storeFill, progress);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/transition/SizeTransition.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.transition;
2 |
3 | /**
4 | * This transition is used to resize objects to various sizes.
5 | */
6 | public abstract class SizeTransition extends Transition {
7 | private float targetWidth, targetHeight;
8 |
9 | public SizeTransition(long durationInMillis, float targetWidth, float targetHeight) {
10 | super(durationInMillis);
11 | this.targetWidth = targetWidth;
12 | this.targetHeight = targetHeight;
13 | }
14 |
15 | @Override
16 | public void tick(float progress) {
17 | setWidth(changeSize(progress, getCurrentWidth(), targetWidth));
18 | setHeight(changeSize(progress, getCurrentHeight(), targetHeight));
19 | }
20 |
21 | private float changeSize(float progress, float current, float target) {
22 | if (current > target) {
23 | float d = (current- target);
24 | return (target + (d * (1f - progress)));
25 | } else {
26 | float d = (target - current);
27 | return (current + (d * progress));
28 | }
29 | }
30 |
31 | /**
32 | * Override this to return the current width of whatever element is being affected by this transition so that the iteration works correctly.
33 | */
34 | protected abstract float getCurrentWidth();
35 |
36 | /**
37 | * Override this to return the current height of whatever element is being affected by this transition so that the iteration works correctly.
38 | */
39 | protected abstract float getCurrentHeight();
40 |
41 | /**
42 | * This is the callback for the width size changes.
43 | */
44 | protected abstract void setWidth(float width);
45 |
46 | /**
47 | * This is the callback for the height size changes.
48 | */
49 | protected abstract void setHeight(float height);
50 | }
51 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/transition/Transition.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.transition;
2 |
3 | import nokori.clear.windows.util.Stopwatch;
4 |
5 | /**
6 | * Transitions are objects that allow the smooth animation of Nodes via the use of timestamps.
7 | *
8 | * By creating multipliers of duration from 0 to 1, it's possible to create a variety of animations that can improve the polish of a Node.
9 | *
10 | */
11 | public abstract class Transition {
12 |
13 | private long durationInMillis;
14 |
15 | private boolean isPlaying = false;
16 | private Stopwatch stopwatch = new Stopwatch();
17 |
18 | private Object linkedObject = null;
19 |
20 | TransitionCompletedCallback completedCallback = null;
21 |
22 | public Transition(long durationInMillis) {
23 | this.durationInMillis = durationInMillis;
24 | }
25 |
26 | public long getDurationInMillis() {
27 | return durationInMillis;
28 | }
29 |
30 | public void setDurationInMillis(long durationInMillis) {
31 | this.durationInMillis = durationInMillis;
32 | }
33 |
34 | /**
35 | * Will start this transition. If it's already playing, it will be reset.
36 | */
37 | public Transition play() {
38 | if (isPlaying) {
39 | stop();
40 | }
41 |
42 | TransitionManager.removeLinkedTransitions(this, linkedObject);
43 |
44 | stopwatch.timeInMilliseconds(durationInMillis);
45 | TransitionManager.add(this);
46 | isPlaying = true;
47 |
48 | return this;
49 | }
50 |
51 | /**
52 | * Stops this Transition from playing. This function will not call the onCompletedCallback unless this transition has finished.
53 | * @return
54 | */
55 | public Transition stop() {
56 | if (isFinished() && completedCallback != null) {
57 | completedCallback.callback(this);
58 | }
59 |
60 | TransitionManager.remove(this);
61 | isPlaying = false;
62 | return this;
63 | }
64 |
65 | /**
66 | * Called by the TransitionManager regularly.
67 | *
68 | * @param progress - the progress of the Transition to completion (between 0-1, where 1 is 100% complete)
69 | */
70 | public abstract void tick(float progress);
71 |
72 | public void setOnCompleted(TransitionCompletedCallback completedCallback) {
73 | this.completedCallback = completedCallback;
74 | }
75 |
76 | public interface TransitionCompletedCallback {
77 | public void callback(Transition t);
78 | };
79 |
80 | /**
81 | * @return a value from 0 to 1 based on the transition time.
82 | */
83 | public float getProgress() {
84 | return stopwatch.getNormalizedDistanceBetweenTime();
85 | }
86 |
87 | public boolean isFinished() {
88 | return (isPlaying && stopwatch.isCurrentTimePassedEndTime());
89 | }
90 |
91 | /**
92 | * @return the linked Object
93 | * @see setLinkedObject(object)
94 | */
95 | public Object getLinkedObject() {
96 | return linkedObject;
97 | }
98 |
99 | /**
100 | * Setting a linked object will cause this Transition to be associated with that object. If you attempt to make another Transition of the same class
101 | * and play it when it has the same linkedObject, then this Transition will be stopped and deleted automatically by the TransitionManager.
102 | *
103 | * The purpose of this system is to prevent two contradicting Transitions (e.g. fading in/fading out) from playing at the same time,
104 | * so that the user doesn't have to manually check for this.
105 | *
106 | * @param linkedObject
107 | */
108 | public void setLinkedObject(Object linkedObject) {
109 | this.linkedObject = linkedObject;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/transition/TransitionImpl.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.transition;
2 |
3 | /**
4 | * This Transition can be used to track a value going from the start value to the end value via the normalized progress variable.
5 | * It's useful for creating basic transitions.
6 | *
7 | */
8 | public class TransitionImpl extends Transition {
9 |
10 | private float start, end;
11 | private float currentValue;
12 |
13 | private ProgressCallback callback = null;
14 | private CurveProcessor curveProcessor = null;
15 |
16 | public TransitionImpl(long durationInMillis, float start, float end, ProgressCallback callback, CurveProcessor curveProcessor) {
17 | this(durationInMillis, start, end, callback);
18 | this.curveProcessor = curveProcessor;
19 | }
20 |
21 | public TransitionImpl(long durationInMillis, float start, float end, ProgressCallback callback) {
22 | this(durationInMillis, start, end);
23 | this.callback = callback;
24 | }
25 |
26 | public TransitionImpl(long durationInMillis, float start, float end) {
27 | super(durationInMillis);
28 | this.start = start;
29 | this.end = end;
30 | currentValue = start;
31 | }
32 |
33 | public void setStartAndEnd(float start, float end) {
34 | this.start = start;
35 | this.end = end;
36 | }
37 |
38 | public float getStart() {
39 | return start;
40 | }
41 |
42 | public void setStart(float start) {
43 | this.start = start;
44 | }
45 |
46 | public float getEnd() {
47 | return end;
48 | }
49 |
50 | public void setEnd(float end) {
51 | this.end = end;
52 | }
53 |
54 | @Override
55 | public void tick(float progress) {
56 | currentValue = start + ((end - start) * progress);
57 |
58 | if (curveProcessor != null) {
59 | currentValue = curveProcessor.modifyValue(currentValue);
60 | }
61 |
62 | if (callback != null) {
63 | callback.callback(currentValue);
64 | }
65 | }
66 |
67 | /**
68 | * Sets a callback that is called as the transitioning value changes. The value passed through the callback is the current value during its transition.
69 | */
70 | public void setProgressCallback(ProgressCallback callback) {
71 | this.callback = callback;
72 | }
73 |
74 | /**
75 | * Sets a processor for the value produced by this Transition, allowing you to tweak its curve
76 | * @param curveProcessor
77 | */
78 | public void setCurveProcessor(CurveProcessor curveProcessor) {
79 | this.curveProcessor = curveProcessor;
80 | }
81 |
82 | public float getCurrent() {
83 | return currentValue;
84 | }
85 |
86 | public interface ProgressCallback {
87 | public void callback(float value);
88 | }
89 |
90 | public interface CurveProcessor {
91 | public float modifyValue(float value);
92 | };
93 | }
94 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/transition/TransitionManager.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.transition;
2 |
3 | import java.util.ArrayList;
4 |
5 | public class TransitionManager {
6 | private static ArrayListtick()
automatically,
90 | * but if desired, this can be called manually if the bounds are needed immediately.
91 | *
92 | * @param context
93 | * @return - this LabelWidget (for pretty code purposes)
94 | */
95 | public LabelWidget calculateBounds(NanoVGContext context) {
96 | //Calculate the line split and then derive the height from that
97 | if (lines == null) {
98 | font.split(context, lines = new ArrayListClearDraggableWidgetDemo.java
to see an example of this in action.
17 | */
18 | public class DraggableWidgetAssembly extends WidgetAssembly {
19 |
20 | private Vector2f anchor = new Vector2f();
21 | private boolean dragging = false;
22 | private Vector2f startPos = new Vector2f();
23 |
24 | private boolean requiresMouseToBeWithinWidgetToDrag = true;
25 | private boolean ignoreChildrenWidgets = false;
26 |
27 | public DraggableWidgetAssembly() {
28 | this(0f, 0f, 0f, 0f);
29 | }
30 |
31 | public DraggableWidgetAssembly(float x, float y, float width, float height) {
32 | super(x, y, width, height);
33 |
34 | setOnInternalMouseButtonEvent(e -> {
35 | boolean bDragging = dragging;
36 | dragging = ((dragging || canDrag(e.getWindow(), 1.0f)) && isFocusedOrCanFocus(this) && isDragButtonEvent(e));
37 | startPos.set(getClippedX(), getClippedY());
38 |
39 | /*System.err.println(this + ": " + canDrag(e.getWindow()) + " " + isFocusedOrCanFocus(this) + " " + isDragButtonEvent(e)
40 | + " = " + dragging
41 | + " | Dimensions: " + DraggableWidgetAssembly.this.getWidth() + "/" + DraggableWidgetAssembly.this.getHeight());*/
42 |
43 | //If we start dragging, focus on this widget
44 | if (!bDragging && dragging) {
45 | //The anchor is a relative X/Y value as to where the mouse was inside of the Widget when we clicked.
46 | //That way we can factor this into dragging calculations by subtracting the anchor from the mouseX/Y
47 | //(Preventing the widget from snapping to the mouse coordinates from the upper-left)
48 | draggingAnchorCallback(e);
49 | setFocusedWidget(this);
50 | }
51 |
52 | //If dragging stops, unfocus if applicable
53 | if (!dragging) {
54 | clearFocusIfApplicable(this);
55 | draggingReleaseCallback(e, (startPos.x != getClippedX() || startPos.y != getClippedY()));
56 | }
57 | });
58 |
59 | setOnInternalMouseMotionEvent(e -> {
60 | if (dragging && isFocusedOrCanFocus(this)) {
61 | //Calculating the coordinates like this instead of using the mouse event DX/DY means that the user will have more freedom in how they use move()
62 | //E.G. calculating it like this will allow the user to modify move to allow for grid snapping without any issues arising from the new X/Y values
63 | //System.err.println(this + " Dragging: " + getX() + "/" + getY() + " " + anchor.x() + "/" + anchor.y());
64 |
65 | draggingCallback(e);
66 | }
67 | });
68 | }
69 |
70 | /**
71 | * This is split into its own function so that it can be overriden separately from clipDraggingAnchor()
72 | * @param e
73 | */
74 | protected void draggingAnchorCallback(MouseButtonEvent e) {
75 | clipDraggingAnchor((float) e.getScaledMouseX(scaler.getScale()), (float) e.getScaledMouseY(scaler.getScale()));
76 | }
77 |
78 | /**
79 | * This is split into its own function so that it can be overriden separately from move()
80 | * @param e
81 | */
82 | protected void draggingCallback(MouseMotionEvent e) {
83 | move(getDragX(e.getScaledMouseX(scaler.getScale())), getDragY(e.getScaledMouseY(scaler.getScale())));
84 | }
85 |
86 | protected void draggingReleaseCallback(MouseButtonEvent e, boolean wasMoved) {
87 |
88 | }
89 |
90 | public float getDragX(double mouseX) {
91 | return (float) (getX() + (mouseX - getX()) - anchor.x());
92 | }
93 |
94 | public float getDragY(double mouseY) {
95 | return (float) (getY() + (mouseY - getY()) - anchor.y());
96 | }
97 |
98 | /**
99 | * This function handles moving the widget assembly when the dragging controls are used. Extension and overriding of this function will allow for the
100 | * modification of the movement behavior.
101 | *
102 | * @param newX - the requested new X value for the widget
103 | * @param newY - the requested new Y value for the widget
104 | */
105 | public void move(float newX, float newY) {
106 | setX(newX);
107 | setY(newY);
108 | }
109 |
110 | protected boolean canDrag(Window window, float scale) {
111 | //We won't let the user drag the widget if the mouse is hovering one of its draggable widget assembly children (normal children don't count)
112 | boolean hoveringChildren = false;
113 |
114 | if (!ignoreChildrenWidgets) {
115 | for (int i = 0; i < children.size(); i++) {
116 | Widget w = children.get(i);
117 |
118 | if (w.isMouseIntersectingThisWidget(window) && w.isInputEnabled()) {
119 | hoveringChildren = true;
120 | break;
121 | }
122 | }
123 | }
124 |
125 | //System.err.println("canDrag() -> " + hoveringChildren + " " + isMouseWithinThisWidget(window) + " " + requiresMouseToBeWithinWidgetToDrag);
126 |
127 | return ((isMouseIntersectingThisWidget(window) || !requiresMouseToBeWithinWidgetToDrag) && !hoveringChildren);
128 | }
129 |
130 | /**
131 | * @return true if the mouseButton is the button used for dragging.
132 | */
133 | protected boolean isDragButtonEvent(MouseButtonEvent e) {
134 | return (e.getButton() == GLFW.GLFW_MOUSE_BUTTON_LEFT && e.isPressed());
135 | }
136 |
137 | /**
138 | * This value determines whether or not the mouse has to actually be within the bounds of this Widget for the dragging functionality to be activated.
139 | * Disabling this can have some advantages, such as when you want to be able to drag an entire canvas around.
140 | */
141 | public boolean requiresMouseToBeWithinWidgetToDrag() {
142 | return requiresMouseToBeWithinWidgetToDrag;
143 | }
144 |
145 | /**
146 | * This value determines whether or not the mouse has to actually be within the bounds of this Widget for the dragging functionality to be activated.
147 | * Disabling this can have some advantages, such as when you want to be able to drag an entire canvas (widget assembly containing multiple nodes) around
148 | * without worrying about the input not being recognized because you tried to drag outside of its bounds.
149 | *
150 | * @param requiresMouseToBeWithinWidgetToDrag
151 | */
152 | public void setRequiresMouseToBeWithinWidgetToDrag(boolean requiresMouseToBeWithinWidgetToDrag) {
153 | this.requiresMouseToBeWithinWidgetToDrag = requiresMouseToBeWithinWidgetToDrag;
154 | }
155 |
156 | /**
157 | * If this is set to true, this widget won't take into consideration whether or not the mouse is hovering one of its children widgets before allowing
158 | * the user to drag it. Otherwise, if this is false, you won't be able to drag the widget if the mouse is hovering another widget within this widget.
159 | */
160 | public boolean ignoreChildrenWidgets() {
161 | return ignoreChildrenWidgets;
162 | }
163 |
164 | /**
165 | * If this is set to true, this widget won't take into consideration whether or not the mouse is hovering one of its children widgets before allowing
166 | * the user to drag it. Otherwise, if this is false, you won't be able to drag the widget if the mouse is hovering another widget within this widget.
167 | *
168 | * @param ignoreChildrenWidgets
169 | */
170 | public void setIgnoreChildrenWidgets(boolean ignoreChildrenWidgets) {
171 | this.ignoreChildrenWidgets = ignoreChildrenWidgets;
172 | }
173 |
174 | /**
175 | * @return true if this DraggableWidgetAssembly is being dragged via user input.
176 | */
177 | public boolean isDragging() {
178 | return dragging;
179 | }
180 |
181 | /**
182 | * @return the current dragging anchor. This is a value of the relative X/Y coordinate of the mouse to the widget X/Y when it's clicked for the first time for dragging.
183 | */
184 | public Vector2f getDraggingAnchor() {
185 | return anchor;
186 | }
187 |
188 | /**
189 | * Sets the dragging anchor for this DraggableWidgetAssembly (the relative X/Y coordinate of the mouse to the widget X/Y). Setting it manually may be useful for instances
190 | * where you need to drag multiple Widgets at the same time.
191 | *
192 | * @param mouseX
193 | * @param mouseY
194 | */
195 | public void clipDraggingAnchor(float mouseX, float mouseY) {
196 | anchor.set(mouseX - getX(), mouseY - getY());
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/widget/assembly/RootWidgetAssembly.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.widget.assembly;
2 |
3 | /**
4 | * This is just a WidgetAssembly configured for the typical use-case of a root WidgetAssembly uses in a ClearApplication
5 | * @author Brayden
6 | *
7 | */
8 | public class RootWidgetAssembly extends WidgetAssembly {
9 | public RootWidgetAssembly() {
10 | super(new WidgetSynch(WidgetSynch.Mode.WITH_FRAMEBUFFER));
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/widget/assembly/WidgetAssembly.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.widget.assembly;
2 |
3 | import nokori.clear.vg.ClearColor;
4 | import nokori.clear.vg.NanoVGContext;
5 | import org.lwjgl.nanovg.NanoVG;
6 |
7 | /**
8 | * This is an empty generic implementation of a Widget that can be used primarily as a container for other Widgets.
9 | */
10 | public class WidgetAssembly extends Widget {
11 |
12 | private ClearColor backgroundFill = null;
13 |
14 |
15 | /**
16 | * Initializes the WidgetAssembly with the coordinates (0, 0) and the dimensions (0, 0).
17 | */
18 | public WidgetAssembly() {
19 | super(0f, 0f, 0f, 0f);
20 | }
21 |
22 | /**
23 | * Creates a WidgetAssembly configured to be synchronized to its parent with a WidgetSynch.
24 |
25 | * @param widgetSynch - the WidgetSynch to add to this WidgetAssembly.
26 | */
27 | public WidgetAssembly(WidgetSynch widgetSynch) {
28 | this();
29 | addChild(widgetSynch);
30 | }
31 |
32 | /**
33 | * Creates a WidgetAssembly with the given dimensions.
34 | *
35 | * @param x
36 | * @param y
37 | * @param width
38 | * @param height
39 | */
40 | public WidgetAssembly(float x, float y, float width, float height) {
41 | super(x, y, width, height);
42 | }
43 |
44 | /**
45 | * Creates a WidgetAssembly with the given width and height and configures it to use the given WidgetClip for positioning.
46 | *
47 | * @param width
48 | * @param height
49 | * @param widgetClip
50 | */
51 | public WidgetAssembly(float width, float height, WidgetClip widgetClip) {
52 | super(0, 0, width, height);
53 | addChild(widgetClip);
54 | }
55 |
56 | @Override
57 | public void tick(NanoVGContext context, WidgetAssembly rootWidgetAssembly) {}
58 |
59 | @Override
60 | public void render(NanoVGContext context, WidgetAssembly rootWidgetAssembly) {
61 | if (backgroundFill != null) {
62 | backgroundFill.tallocNVG(fill -> {
63 | long vg = context.get();
64 | float x = getClippedX();
65 | float y = getClippedY();
66 | float w = getWidth();
67 | float h = getHeight();
68 |
69 | NanoVG.nvgBeginPath(vg);
70 | NanoVG.nvgRoundedRect(vg, x, y, w, h, 0);
71 | NanoVG.nvgFillColor(vg, fill);
72 | NanoVG.nvgFill(vg);
73 | NanoVG.nvgClosePath(vg);
74 | });
75 | }
76 | }
77 |
78 | public void setBackgroundFill(ClearColor backgroundFill) {
79 | this.backgroundFill = backgroundFill;
80 | }
81 |
82 | public ClearColor getBackgroundFill() {
83 | return backgroundFill;
84 | }
85 |
86 | @Override
87 | public void dispose() {}
88 | }
89 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/widget/assembly/WidgetClip.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.widget.assembly;
2 |
3 | import nokori.clear.vg.NanoVGContext;
4 |
5 | public class WidgetClip extends Widget {
6 |
7 | public enum Alignment {
8 | TOP_LEFT, TOP_CENTER, TOP_RIGHT,
9 | CENTER_LEFT, CENTER, CENTER_RIGHT,
10 | BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT
11 | };
12 |
13 | private Alignment alignment;
14 | private float xPadding, yPadding;
15 |
16 | private boolean xModdingEnabled;
17 | private boolean yModdingEnabled;
18 |
19 | public WidgetClip(Alignment alignment) {
20 | this(alignment, 0f, 0f);
21 | }
22 |
23 | public WidgetClip(Alignment alignment, float xPadding, float yPadding) {
24 | this(alignment, xPadding, yPadding, true, true);
25 | }
26 |
27 | public WidgetClip(Alignment alignment, float xPadding, float yPadding, boolean xModdingEnabled, boolean yModdingEnabled) {
28 | this.alignment = alignment;
29 | this.xPadding = xPadding;
30 | this.yPadding = yPadding;
31 | this.xModdingEnabled = xModdingEnabled;
32 | this.yModdingEnabled = yModdingEnabled;
33 | }
34 |
35 | @Override
36 | public void tick(NanoVGContext context, WidgetAssembly rootWidgetAssembly) {
37 | if (parent == null || parent.parent == null) {
38 | System.err.println("WARNING: WidgetClip isn't attached to another Widget, or that Widget isn't attached to another Widget!"
39 | + "\nBoth must be present for a WidgetClip to work correctly! (Heirarchy: Widget -> Child Widget -> Widget Clip)");
40 | return;
41 | }
42 |
43 | float containerWidth = parent.parent.getWidth();
44 | float containerHeight = parent.parent.getHeight();
45 |
46 | float centerX = containerWidth/2 - parent.getWidth()/2;
47 | float centerY = containerHeight/2 - parent.getHeight()/2;
48 |
49 | float leftX = 0f;
50 | float rightX = containerWidth - parent.getWidth();
51 |
52 | float topY = 0f;
53 | float bottomY = containerHeight - parent.getHeight();
54 |
55 | float clipX = parent.getX();
56 | float clipY = parent.getY();
57 |
58 | switch(alignment) {
59 | case BOTTOM_CENTER:
60 | clipX = centerX;
61 | clipY = bottomY;
62 | break;
63 | case BOTTOM_LEFT:
64 | clipX = leftX;
65 | clipY = bottomY;
66 | break;
67 | case BOTTOM_RIGHT:
68 | clipX = rightX;
69 | clipY = bottomY;
70 | break;
71 | case CENTER:
72 | clipX = centerX;
73 | clipY = centerY;
74 | break;
75 | case CENTER_LEFT:
76 | clipX = leftX;
77 | clipY = centerY;
78 | break;
79 | case CENTER_RIGHT:
80 | clipX = rightX;
81 | clipY = centerY;
82 | break;
83 | case TOP_CENTER:
84 | clipX = centerX;
85 | clipY = topY;
86 | break;
87 | case TOP_LEFT:
88 | clipX = leftX;
89 | clipY = topY;
90 | break;
91 | case TOP_RIGHT:
92 | clipX = rightX;
93 | clipY = topY;
94 | break;
95 | default:
96 | break;
97 | }
98 |
99 | clipX += xPadding;
100 | clipY += yPadding;
101 |
102 | if (xModdingEnabled) {
103 | parent.setX(clipX);
104 | }
105 |
106 | if (yModdingEnabled) {
107 | parent.setY(clipY);
108 | }
109 | }
110 |
111 | public Alignment getAlignment() {
112 | return alignment;
113 | }
114 |
115 | public void setAlignment(Alignment alignment) {
116 | this.alignment = alignment;
117 | }
118 |
119 | public float getxPadding() {
120 | return xPadding;
121 | }
122 |
123 | public void setxPadding(float xPadding) {
124 | this.xPadding = xPadding;
125 | }
126 |
127 | public float getyPadding() {
128 | return yPadding;
129 | }
130 |
131 | public void setyPadding(float yPadding) {
132 | this.yPadding = yPadding;
133 | }
134 |
135 | public boolean isxModdingEnabled() {
136 | return xModdingEnabled;
137 | }
138 |
139 | public void setxModdingEnabled(boolean xModdingEnabled) {
140 | this.xModdingEnabled = xModdingEnabled;
141 | }
142 |
143 | public boolean isyModdingEnabled() {
144 | return yModdingEnabled;
145 | }
146 |
147 | public void setyModdingEnabled(boolean yModdingEnabled) {
148 | this.yModdingEnabled = yModdingEnabled;
149 | }
150 |
151 | @Override
152 | public void render(NanoVGContext context, WidgetAssembly rootWidgetAssembly) {}
153 |
154 | @Override
155 | public void dispose() {
156 |
157 | }
158 |
159 | }
160 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/vg/widget/assembly/WidgetUtils.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.vg.widget.assembly;
2 |
3 | import nokori.clear.vg.ClearColor;
4 | import nokori.clear.vg.NanoVGContext;
5 | import nokori.clear.windows.Window;
6 | import org.lwjgl.nanovg.NVGColor;
7 | import org.lwjgl.nanovg.NanoVG;
8 |
9 | import static org.lwjgl.nanovg.NanoVG.*;
10 |
11 | public class WidgetUtils {
12 |
13 | /**
14 | * Shorthand way to render rectangles with NanoVG.
15 | *
16 | * @param context
17 | * @param fill
18 | * @param x
19 | * @param y
20 | * @param width
21 | * @param height
22 | */
23 | public static void nvgRect(NanoVGContext context, NVGColor fill, float x, float y, float width, float height) {
24 | nvgRect(context.get(), fill, x, y, width, height);
25 | }
26 |
27 | public static void nvgRect(long vg, float x, float y, float width, float height) {
28 | nvgRect(vg, (NVGColor) null, x, y, width, height);
29 | }
30 |
31 | public static void nvgRect(long vg, ClearColor fill, float x, float y, float width, float height) {
32 | fill.tallocNVG(f -> {
33 | nvgRect(vg, f, x, y, width, height);
34 | });
35 | }
36 |
37 | /**
38 | * Shorthand way to render rectangles with NanoVG.
39 | *
40 | * @param vg - handle for NanoVG context
41 | * @param fill
42 | * @param x
43 | * @param y
44 | * @param width
45 | * @param height
46 | */
47 | public static void nvgRect(long vg, NVGColor fill, float x, float y, float width, float height) {
48 | nvgBeginPath(vg);
49 |
50 | if (fill != null) {
51 | nvgFillColor(vg, fill);
52 | }
53 |
54 | NanoVG.nvgRect(vg, x, y, width, height);
55 | nvgFill(vg);
56 | nvgClosePath(vg);
57 | }
58 |
59 | public static void nvgShape(long vg, NVGColor fill, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
60 | nvgBeginPath(vg);
61 |
62 | if (fill != null) {
63 | nvgFillColor(vg, fill);
64 | }
65 |
66 | nvgMoveTo(vg, x1, y1);
67 | nvgLineTo(vg, x2, y2);
68 | nvgLineTo(vg, x3, y3);
69 | nvgLineTo(vg, x4, y4);
70 | nvgFill(vg);
71 | nvgClosePath(vg);
72 | }
73 |
74 | /**
75 | * Checks if the two given rectangles are intersecting.
76 | * tick()
is called for the first time).
17 | */
18 | public TextFieldWidget(float width, ClearColor fill, String text, Font font, float fontSize) {
19 | this(0, 0, width, fill, text, font, fontSize);
20 | }
21 |
22 | /**
23 | * This constructor allows the widget to be initialized without the NanoVGContext but comes at the cost of
24 | * not initializing the widget height right away (it will be zero until tick()
is called for the first time).
25 | */
26 | public TextFieldWidget(float x, float y, float width, ClearColor fill, String text, Font font, float fontSize) {
27 | this(null, x, y, width, fill, text, font, fontSize);
28 | }
29 |
30 | /**
31 | * This shortened version of the primary constructor will calculate the widget height automatically by using the NanoVGContext.
32 | */
33 | public TextFieldWidget(NanoVGContext context, float width, ClearColor fill, String text, Font font, float fontSize) {
34 | this(context, width, new NanoVGScaler(), fill, text, font, fontSize);
35 | }
36 |
37 | public TextFieldWidget(NanoVGContext context, float width, NanoVGScaler scaler, ClearColor fill, String text, Font font, float fontSize) {
38 | this(context, 0, 0, width, scaler, fill, text, font, fontSize);
39 | }
40 |
41 | public TextFieldWidget(NanoVGContext context, float x, float y, float width, ClearColor fill, String text, Font font, float fontSize) {
42 | this(context, x, y, width, new NanoVGScaler(), fill, text, font, fontSize);
43 | }
44 |
45 | /**
46 | * This is the primary constructor which allows full and complete customization of the TextFieldWidget. Additionally, the widget's height will be
47 | * calculated at initialization thanks to the inclusion of a NanoVGContext.
48 | */
49 | public TextFieldWidget(NanoVGContext context, float x, float y, float width, NanoVGScaler scaler, ClearColor fill, String text, Font font, float fontSize) {
50 | super(x, y, width, 0f, scaler, fill, text, font, fontSize);
51 |
52 | if (context != null) {
53 | calculateHeight(context);
54 | }
55 |
56 | setWordWrappingEnabled(false);
57 | setLineNumbersEnabled(false);
58 |
59 | getInputSettings().setVerticalScrollbarEnabled(false);
60 | getInputSettings().setHorizontalScrollbarEnabled(false);
61 | getInputSettings().setReturnEnabled(false);
62 | getInputSettings().setReturnEndsEditing(true);
63 | getInputSettings().setTabEnabled(false);
64 | }
65 |
66 |
67 | @Override
68 | public void tick(NanoVGContext context, WidgetAssembly rootWidgetAssembly) {
69 | super.tick(context, rootWidgetAssembly);
70 | calculateHeight(context);
71 | }
72 |
73 | /**
74 | * Calculates the height for this TextFieldWidget by getting the height of the font configured to this widget.
75 | * This is called automatically in the tick()
function, however it can be called manually in instances
76 | * where you're initializing it in a constructor and want the most up-to-date data immediately.
77 | */
78 | public void calculateHeight(NanoVGContext context) {
79 | setHeight(getFont().getHeight(context, getFontSize(), TEXT_AREA_ALIGNMENT, getDefaultFontStyle()));
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/ClearVG/src/main/java/nokori/clear/windows/event/vg/MouseEnteredEvent.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.windows.event.vg;
2 |
3 | import nokori.clear.windows.Window;
4 | import nokori.clear.windows.event.EventImpl;
5 | import nokori.clear.windows.pool.Pool;
6 |
7 | public class MouseEnteredEvent extends EventImpl {
8 |
9 | private static final Pool
65 | * If running on windows it will start the sleep timer fix.
66 | */
67 | private static void initialise() {
68 | initialised = true;
69 |
70 | sleepDurations.init(1000 * 1000);
71 | yieldDurations.init((int) (-(getTime() - getTime()) * 1.333));
72 |
73 | nextFrame = getTime();
74 |
75 | String osName = System.getProperty("os.name");
76 |
77 | if (osName.startsWith("Win")) {
78 | // On windows the sleep functions can be highly inaccurate by
79 | // over 10ms making in unusable. However it can be forced to
80 | // be a bit more accurate by running a separate sleeping daemon
81 | // thread.
82 | Thread timerAccuracyThread = new Thread(new Runnable() {
83 | public void run() {
84 | try {
85 | Thread.sleep(Long.MAX_VALUE);
86 | } catch (Exception e) {
87 | }
88 | }
89 | });
90 |
91 | timerAccuracyThread.setName("LWJGL Timer");
92 | timerAccuracyThread.setDaemon(true);
93 | timerAccuracyThread.start();
94 | }
95 | }
96 |
97 | /**
98 | * Get the system time in nano seconds
99 | *
100 | * @return will return the current time in nano's
101 | */
102 | private static long getTime() {
103 | return (long) (GLFW.glfwGetTime() * NANOS_IN_SECOND);
104 | }
105 |
106 | private static class RunningAvg {
107 | private final long[] slots;
108 | private int offset;
109 |
110 | private static final long DAMPEN_THRESHOLD = 10 * 1000L * 1000L; // 10ms
111 | private static final float DAMPEN_FACTOR = 0.9f; // don't change: 0.9f is exactly right!
112 |
113 | public RunningAvg(int slotCount) {
114 | this.slots = new long[slotCount];
115 | this.offset = 0;
116 | }
117 |
118 | public void init(long value) {
119 | while (this.offset < this.slots.length) {
120 | this.slots[this.offset++] = value;
121 | }
122 | }
123 |
124 | public void add(long value) {
125 | this.slots[this.offset++ % this.slots.length] = value;
126 | this.offset %= this.slots.length;
127 | }
128 |
129 | public long avg() {
130 | long sum = 0;
131 | for (int i = 0; i < this.slots.length; i++) {
132 | sum += this.slots[i];
133 | }
134 | return sum / this.slots.length;
135 | }
136 |
137 | public void dampenForLowResTicker() {
138 | if (this.avg() > DAMPEN_THRESHOLD) {
139 | for (int i = 0; i < this.slots.length; i++) {
140 | this.slots[i] *= DAMPEN_FACTOR;
141 | }
142 | }
143 | }
144 | }
145 | }
--------------------------------------------------------------------------------
/ClearWindows/src/main/java/nokori/clear/windows/GLFWException.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.windows;
2 |
3 | public class GLFWException extends Exception {
4 |
5 | private static final long serialVersionUID = 1L;
6 |
7 | public GLFWException(String message) {
8 | super(message);
9 | }
10 | }
--------------------------------------------------------------------------------
/ClearWindows/src/main/java/nokori/clear/windows/Joystick.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.windows;
2 |
3 | import nokori.clear.windows.callback.JoystickCallback;
4 |
5 | import java.nio.ByteBuffer;
6 | import java.nio.FloatBuffer;
7 |
8 | import static org.lwjgl.glfw.GLFW.*;
9 |
10 | public class Joystick {
11 |
12 | private int index;
13 | private String name;
14 |
15 | private float[] axes;
16 | private boolean[] buttons;
17 |
18 | private JoystickCallback callback;
19 |
20 | public Joystick(int index) {
21 |
22 | this.index = index;
23 |
24 | name = glfwGetJoystickName(index);
25 |
26 | FloatBuffer axisData = glfwGetJoystickAxes(index);
27 | axes = new float[axisData.remaining()];
28 | for (int i = 0; i < axes.length; i++) {
29 | axes[i] = axisData.get(i);
30 | }
31 |
32 | ByteBuffer buttonData = glfwGetJoystickButtons(index);
33 | buttons = new boolean[buttonData.remaining()];
34 | for (int i = 0; i < buttons.length; i++) {
35 | buttons[i] = buttonData.get(i) == GLFW_PRESS;
36 | }
37 |
38 | callback = null;
39 | }
40 |
41 | public void setCallback(JoystickCallback callback) {
42 | this.callback = callback;
43 | }
44 |
45 | void poll(long timestamp) {
46 |
47 | FloatBuffer axisData = glfwGetJoystickAxes(index);
48 | if (axisData != null) {
49 | for (int i = 0; i < axes.length; i++) {
50 |
51 | float newValue = axisData.get(i);
52 | if (callback != null && axes[i] != newValue) {
53 | callback.axisMoved(this, timestamp, i, newValue);
54 | }
55 | axes[i] = newValue;
56 | }
57 | }
58 |
59 | ByteBuffer buttonData = glfwGetJoystickButtons(index);
60 |
61 | if (buttonData != null) {
62 | for (int i = 0; i < buttons.length; i++) {
63 | boolean newValue = buttonData.get(i) == GLFW_PRESS;
64 |
65 | if (callback != null && buttons[i] != newValue) {
66 | callback.buttonStateChanged(this, timestamp, i, newValue);
67 | }
68 | buttons[i] = newValue;
69 | }
70 | }
71 | }
72 |
73 | public int getIndex() {
74 | return index;
75 | }
76 |
77 | public String getName() {
78 | return name;
79 | }
80 |
81 | public int getAxisCount() {
82 | return axes.length;
83 | }
84 |
85 | public int getButtonCount() {
86 | return buttons.length;
87 | }
88 | }
--------------------------------------------------------------------------------
/ClearWindows/src/main/java/nokori/clear/windows/Monitor.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.windows;
2 |
3 | import org.lwjgl.glfw.GLFWVidMode;
4 |
5 | import java.nio.IntBuffer;
6 | import java.util.ArrayList;
7 |
8 | import static org.lwjgl.glfw.GLFW.*;
9 | import static org.lwjgl.system.MemoryStack.*;
10 |
11 | public class Monitor {
12 |
13 | private static final double MM_TO_INCHES = 0.0393700787;
14 |
15 | private long pointer;
16 | private boolean primaryMonitor;
17 |
18 | private String name;
19 |
20 | private int virtualX, virtualY;
21 |
22 | private int physicalWidth, physicalHeight;
23 | private double physicalDiagonalInches;
24 |
25 | private ArrayList
5 | WindowSizeCallback
)
7 | */
8 | public interface WindowFramebufferSizeCallback extends InputCallback {
9 | public void windowSizeEvent(Window window, long timestamp, int width, int height);
10 | }
11 |
--------------------------------------------------------------------------------
/ClearWindows/src/main/java/nokori/clear/windows/callback/WindowPosCallback.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.windows.callback;
2 |
3 | import nokori.clear.windows.Window;
4 |
5 | /**
6 | * This is a callback for the Window's pixel position on the desktop.
7 | */
8 | public interface WindowPosCallback extends InputCallback {
9 | public void windowPositionEvent(Window window, long timestamp, int x, int y);
10 | }
11 |
--------------------------------------------------------------------------------
/ClearWindows/src/main/java/nokori/clear/windows/callback/WindowSizeCallback.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.windows.callback;
2 |
3 | import nokori.clear.windows.Window;
4 |
5 | /**
6 | * This is a callback for the window's actual pixel width and height (not the internal rendering dimensions - that's handled by WindowFramebufferSizeCallback
)
7 | */
8 | public interface WindowSizeCallback extends InputCallback {
9 | public void windowSizeEvent(Window window, long timestamp, int width, int height);
10 | }
11 |
--------------------------------------------------------------------------------
/ClearWindows/src/main/java/nokori/clear/windows/event/CharEvent.java:
--------------------------------------------------------------------------------
1 | package nokori.clear.windows.event;
2 |
3 | import nokori.clear.windows.Window;
4 | import nokori.clear.windows.pool.Pool;
5 |
6 | public class CharEvent extends EventImpl {
7 |
8 | private static final Pool
15 | * Your java program must return after calling this method if it returns true as to prevent your application from running twice.
16 | *
17 | * To implement this method, simply put it on the first line of your main(args) function.
18 | *
19 | * Credit goes to Spasi on JGO for making this utility.
20 | *
21 | * Example of usage (first line in main() method):
22 | * if (LWJGUIUtil.restartJVMOnFirstThread(true, args)) {
23 | * return;
24 | * }
25 | *
26 | * @param needsOutput - Whether or not the JVM should print to System.out.println
27 | * @param args - the usual String[] args used in the main method
28 | * @return true if the JVM was successfully restarted.
29 | */
30 | public static boolean restartJVMOnFirstThread(boolean needsOutput, String... args) {
31 | // Figure out the right class to call
32 | StackTraceElement[] cause = Thread.currentThread().getStackTrace();
33 |
34 | boolean foundThisMethod = false;
35 | String callingClassName = null;
36 | for (StackTraceElement se : cause) {
37 | // Skip entries until we get to the entry for this class
38 | String className = se.getClassName();
39 | String methodName = se.getMethodName();
40 | if (foundThisMethod) {
41 | callingClassName = className;
42 | break;
43 | } else if (JVMUtil.class.getName().equals(className) && "restartJVMOnFirstThread".equals(methodName)) {
44 | foundThisMethod = true;
45 | }
46 | }
47 |
48 | if (callingClassName == null) {
49 | throw new RuntimeException("Error: unable to determine main class");
50 | }
51 |
52 | try {
53 | Class> theClass = Class.forName(callingClassName, true, Thread.currentThread().getContextClassLoader());
54 |
55 | return restartJVMOnFirstThread(needsOutput, theClass, args);
56 | } catch (ClassNotFoundException e) {
57 | e.printStackTrace();
58 | }
59 |
60 | return false;
61 | }
62 |
63 | /**
64 | * Restarts the Java virtual machine and forces it to run on the first thread IF and only IF it is not currently on the first thread. This allows your LWJGL3 program to run on Mac properly.
65 | *
66 | * To implement this method, simply put it on the first line of your main(args) function.
67 | *
68 | * Credit goes to Spasi on JGO for making this utility.
69 | *
70 | * Example of usage (first line in main() method):
71 | * if (LWJGUIUtil.restartJVMOnFirstThread(true, class, args)) {
72 | * return;
73 | * }
74 | *
75 | * @param needsOutput - Whether or not the JVM should print to System.out.println
76 | * @param customClass - Class where the main method is stored
77 | * @param args - the usual String[] args used in the main method
78 | * @return true if the JVM was successfully restarted.
79 | */
80 | public static boolean restartJVMOnFirstThread(boolean needsOutput, Class> customClass, String... args) {
81 |
82 | // If we're already on the first thread, return
83 | String startOnFirstThread = System.getProperty("XstartOnFirstThread");
84 | if (startOnFirstThread != null && startOnFirstThread.equals("true"))
85 | return false;
86 |
87 | // if not a mac then we're already on first thread, return.
88 | String osName = System.getProperty("os.name");
89 | if (!osName.startsWith("Mac") && !osName.startsWith("Darwin")) {
90 | return false;
91 | }
92 |
93 | // get current jvm process pid
94 | String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
95 | // get environment variable on whether XstartOnFirstThread is enabled
96 | String env = System.getenv("JAVA_STARTED_ON_FIRST_THREAD_" + pid);
97 |
98 | // if environment variable is "1" then XstartOnFirstThread is enabled
99 | if (env != null && env.equals("1")) {
100 | return false;
101 | }
102 |
103 | // restart jvm with -XstartOnFirstThread
104 | String separator = System.getProperty("file.separator");
105 | String classpath = System.getProperty("java.class.path");
106 | String mainClass = System.getenv("JAVA_MAIN_CLASS_" + pid);
107 | String jvmPath = System.getProperty("java.home") + separator + "bin" + separator + "java";
108 |
109 | List
6 |