parent
6892f5006b
commit
22e5a8a12e
@ -0,0 +1,13 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<classpath> |
||||
<classpathentry kind="src" path="src"/> |
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/> |
||||
<classpathentry combineaccessrules="false" kind="src" path="/GameCore"/> |
||||
<classpathentry combineaccessrules="false" kind="src" path="/MightyUtils"/> |
||||
<classpathentry kind="lib" path="lib/jogg-0.0.7.jar" sourcepath="lib/lwjgl-source-2.8.4.zip"/> |
||||
<classpathentry kind="lib" path="lib/jorbis-0.0.15.jar" sourcepath="lib/lwjgl-source-2.8.4.zip"/> |
||||
<classpathentry kind="lib" path="lib/lwjgl_util.jar" sourcepath="lib/lwjgl-source-2.8.4.zip"/> |
||||
<classpathentry kind="lib" path="lib/lwjgl.jar" sourcepath="lib/lwjgl-source-2.8.4.zip"/> |
||||
<classpathentry kind="lib" path="lib/slick-util.jar" sourcepath="lib/slick-util-src.zip"/> |
||||
<classpathentry kind="output" path="bin"/> |
||||
</classpath> |
@ -0,0 +1,17 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<projectDescription> |
||||
<name>GameCore-LWJGL</name> |
||||
<comment></comment> |
||||
<projects> |
||||
</projects> |
||||
<buildSpec> |
||||
<buildCommand> |
||||
<name>org.eclipse.jdt.core.javabuilder</name> |
||||
<arguments> |
||||
</arguments> |
||||
</buildCommand> |
||||
</buildSpec> |
||||
<natures> |
||||
<nature>org.eclipse.jdt.core.javanature</nature> |
||||
</natures> |
||||
</projectDescription> |
@ -0,0 +1,11 @@ |
||||
eclipse.preferences.version=1 |
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled |
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 |
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve |
||||
org.eclipse.jdt.core.compiler.compliance=1.7 |
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate |
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate |
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate |
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error |
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error |
||||
org.eclipse.jdt.core.compiler.source=1.7 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,52 @@ |
||||
package mightypork.gamecore.backends.lwjgl; |
||||
|
||||
|
||||
import java.nio.FloatBuffer; |
||||
|
||||
import org.lwjgl.BufferUtils; |
||||
|
||||
|
||||
/** |
||||
* Calc subclass with buffer utils. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public class BufferHelper { |
||||
|
||||
/** |
||||
* Create java.nio.FloatBuffer of given floats, and flip it. |
||||
* |
||||
* @param obj floats or float array |
||||
* @return float buffer |
||||
*/ |
||||
public static FloatBuffer mkFillBuff(float... obj) |
||||
{ |
||||
return (FloatBuffer) BufferUtils.createFloatBuffer(obj.length).put(obj).flip(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Fill java.nio.FloatBuffer with floats or float array |
||||
* |
||||
* @param buff |
||||
* @param obj |
||||
*/ |
||||
public static void fill(FloatBuffer buff, float... obj) |
||||
{ |
||||
buff.put(obj); |
||||
buff.flip(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Create new java.nio.FloatBuffer of given length |
||||
* |
||||
* @param count elements |
||||
* @return the new java.nio.FloatBuffer |
||||
*/ |
||||
public static FloatBuffer alloc(int count) |
||||
{ |
||||
return BufferUtils.createFloatBuffer(count); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,38 @@ |
||||
package mightypork.gamecore.backends.lwjgl; |
||||
|
||||
|
||||
import mightypork.gamecore.core.InitTask; |
||||
import mightypork.gamecore.core.OptionalInitTask; |
||||
import mightypork.utils.logging.writers.LogWriter; |
||||
|
||||
|
||||
/** |
||||
* Initializer that redirects slick logging to main logger. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
@OptionalInitTask |
||||
public class InitTaskRedirectSlickLog extends InitTask { |
||||
|
||||
@Override |
||||
public void run() |
||||
{ |
||||
LogWriter ml = mightypork.utils.logging.Log.getMainLogger(); |
||||
SlickLogRedirector slr = new SlickLogRedirector(ml); |
||||
org.newdawn.slick.util.Log.setLogSystem(slr); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String getName() |
||||
{ |
||||
return "slick_log"; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public String[] getDependencies() |
||||
{ |
||||
return new String[] { "log" }; |
||||
} |
||||
} |
@ -0,0 +1,58 @@ |
||||
package mightypork.gamecore.backends.lwjgl; |
||||
|
||||
|
||||
import mightypork.gamecore.audio.AudioModule; |
||||
import mightypork.gamecore.backends.lwjgl.audio.SlickAudioModule; |
||||
import mightypork.gamecore.backends.lwjgl.graphics.LwjglGraphicsModule; |
||||
import mightypork.gamecore.core.AppBackend; |
||||
import mightypork.gamecore.graphics.GraphicsModule; |
||||
import mightypork.gamecore.input.InputModule; |
||||
|
||||
|
||||
/** |
||||
* Game backend using LWJGL and SlickUtil |
||||
* |
||||
* @author MightyPork |
||||
*/ |
||||
public class LwjglBackend extends AppBackend { |
||||
|
||||
private LwjglGraphicsModule graphics; |
||||
private SlickAudioModule audio; |
||||
private LwjglInputModule input; |
||||
|
||||
|
||||
@Override |
||||
public void initialize() |
||||
{ |
||||
addChildClient(graphics = new LwjglGraphicsModule()); |
||||
addChildClient(audio = new SlickAudioModule()); |
||||
addChildClient(input = new LwjglInputModule()); |
||||
|
||||
graphics.init(); |
||||
audio.init(); |
||||
input.init(); |
||||
|
||||
app.addInitTask(new InitTaskRedirectSlickLog()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public GraphicsModule getGraphics() |
||||
{ |
||||
return graphics; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public AudioModule getAudio() |
||||
{ |
||||
return audio; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public InputModule getInput() |
||||
{ |
||||
return input; |
||||
} |
||||
} |
@ -0,0 +1,302 @@ |
||||
package mightypork.gamecore.backends.lwjgl; |
||||
|
||||
|
||||
import mightypork.gamecore.core.App; |
||||
import mightypork.gamecore.input.InputModule; |
||||
import mightypork.gamecore.input.Key; |
||||
import mightypork.gamecore.input.Keys; |
||||
import mightypork.gamecore.input.events.KeyEvent; |
||||
import mightypork.gamecore.input.events.MouseButtonEvent; |
||||
import mightypork.gamecore.input.events.MouseMotionEvent; |
||||
import mightypork.utils.interfaces.Updateable; |
||||
import mightypork.utils.math.constraints.vect.Vect; |
||||
import mightypork.utils.math.constraints.vect.var.VectVar; |
||||
|
||||
import org.lwjgl.LWJGLException; |
||||
import org.lwjgl.input.Keyboard; |
||||
import org.lwjgl.input.Mouse; |
||||
import org.lwjgl.opengl.Display; |
||||
|
||||
|
||||
/** |
||||
* Lwjgl Input Module. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public class LwjglInputModule extends InputModule implements Updateable { |
||||
|
||||
/** Current mouse position */ |
||||
private static final Vect mousePos = new Vect() { |
||||
|
||||
@Override |
||||
public double x() |
||||
{ |
||||
if (!Mouse.isInsideWindow()) return Integer.MIN_VALUE; |
||||
|
||||
return Mouse.getX(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double y() |
||||
{ |
||||
if (!Mouse.isInsideWindow()) return Integer.MIN_VALUE; |
||||
// flip Y axis
|
||||
return Display.getHeight() - Mouse.getY(); |
||||
} |
||||
}; |
||||
|
||||
|
||||
@Override |
||||
protected void initDevices() |
||||
{ |
||||
try { |
||||
Mouse.create(); |
||||
Keyboard.create(); |
||||
Keyboard.enableRepeatEvents(false); |
||||
} catch (final LWJGLException e) { |
||||
throw new RuntimeException("Failed to initialize input devices.", e); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected void initKeyCodes() |
||||
{ |
||||
Keys.NONE.setCode(Keyboard.KEY_NONE); |
||||
|
||||
Keys.NUM_1.setCode(Keyboard.KEY_1); |
||||
Keys.NUM_2.setCode(Keyboard.KEY_2); |
||||
Keys.NUM_3.setCode(Keyboard.KEY_3); |
||||
Keys.NUM_4.setCode(Keyboard.KEY_4); |
||||
Keys.NUM_5.setCode(Keyboard.KEY_5); |
||||
Keys.NUM_6.setCode(Keyboard.KEY_6); |
||||
Keys.NUM_7.setCode(Keyboard.KEY_7); |
||||
Keys.NUM_8.setCode(Keyboard.KEY_8); |
||||
Keys.NUM_9.setCode(Keyboard.KEY_9); |
||||
Keys.NUM_0.setCode(Keyboard.KEY_0); |
||||
|
||||
Keys.Q.setCode(Keyboard.KEY_Q); |
||||
Keys.W.setCode(Keyboard.KEY_W); |
||||
Keys.E.setCode(Keyboard.KEY_E); |
||||
Keys.R.setCode(Keyboard.KEY_R); |
||||
Keys.T.setCode(Keyboard.KEY_T); |
||||
Keys.Y.setCode(Keyboard.KEY_Y); |
||||
Keys.U.setCode(Keyboard.KEY_U); |
||||
Keys.I.setCode(Keyboard.KEY_I); |
||||
Keys.O.setCode(Keyboard.KEY_O); |
||||
Keys.P.setCode(Keyboard.KEY_P); |
||||
Keys.A.setCode(Keyboard.KEY_A); |
||||
Keys.S.setCode(Keyboard.KEY_S); |
||||
Keys.D.setCode(Keyboard.KEY_D); |
||||
Keys.F.setCode(Keyboard.KEY_F); |
||||
Keys.G.setCode(Keyboard.KEY_G); |
||||
Keys.H.setCode(Keyboard.KEY_H); |
||||
Keys.J.setCode(Keyboard.KEY_J); |
||||
Keys.K.setCode(Keyboard.KEY_K); |
||||
Keys.L.setCode(Keyboard.KEY_L); |
||||
Keys.Z.setCode(Keyboard.KEY_Z); |
||||
Keys.X.setCode(Keyboard.KEY_X); |
||||
Keys.C.setCode(Keyboard.KEY_C); |
||||
Keys.V.setCode(Keyboard.KEY_V); |
||||
Keys.B.setCode(Keyboard.KEY_B); |
||||
Keys.N.setCode(Keyboard.KEY_N); |
||||
Keys.M.setCode(Keyboard.KEY_M); |
||||
|
||||
Keys.MINUS.setCode(Keyboard.KEY_MINUS); |
||||
Keys.EQUALS.setCode(Keyboard.KEY_EQUALS); |
||||
Keys.SLASH.setCode(Keyboard.KEY_SLASH); |
||||
Keys.BACKSLASH.setCode(Keyboard.KEY_BACKSLASH); |
||||
Keys.BRACKET_LEFT.setCode(Keyboard.KEY_LBRACKET); |
||||
Keys.BRACKET_RIGHT.setCode(Keyboard.KEY_RBRACKET); |
||||
Keys.SEMICOLON.setCode(Keyboard.KEY_SEMICOLON); |
||||
Keys.APOSTROPHE.setCode(Keyboard.KEY_APOSTROPHE); |
||||
Keys.GRAVE.setCode(Keyboard.KEY_GRAVE); |
||||
Keys.COMMA.setCode(Keyboard.KEY_COMMA); |
||||
Keys.PERIOD.setCode(Keyboard.KEY_PERIOD); |
||||
|
||||
Keys.SPACE.setCode(Keyboard.KEY_SPACE); |
||||
Keys.BACKSPACE.setCode(Keyboard.KEY_BACK); |
||||
Keys.TAB.setCode(Keyboard.KEY_TAB); |
||||
Keys.ESCAPE.setCode(Keyboard.KEY_ESCAPE); |
||||
|
||||
Keys.APPS.setCode(Keyboard.KEY_APPS); |
||||
Keys.POWER.setCode(Keyboard.KEY_POWER); |
||||
Keys.SLEEP.setCode(Keyboard.KEY_SLEEP); |
||||
//Keys.MENU.setCode(Keyboard.KEY_MENU); // not defined
|
||||
|
||||
Keys.F1.setCode(Keyboard.KEY_F1); |
||||
Keys.F2.setCode(Keyboard.KEY_F2); |
||||
Keys.F3.setCode(Keyboard.KEY_F3); |
||||
Keys.F4.setCode(Keyboard.KEY_F4); |
||||
Keys.F5.setCode(Keyboard.KEY_F5); |
||||
Keys.F6.setCode(Keyboard.KEY_F6); |
||||
Keys.F7.setCode(Keyboard.KEY_F7); |
||||
Keys.F8.setCode(Keyboard.KEY_F8); |
||||
Keys.F9.setCode(Keyboard.KEY_F9); |
||||
Keys.F10.setCode(Keyboard.KEY_F10); |
||||
Keys.F11.setCode(Keyboard.KEY_F11); |
||||
Keys.F12.setCode(Keyboard.KEY_F12); |
||||
Keys.F13.setCode(Keyboard.KEY_F13); |
||||
Keys.F14.setCode(Keyboard.KEY_F14); |
||||
Keys.F15.setCode(Keyboard.KEY_F15); |
||||
|
||||
Keys.CAPS_LOCK.setCode(Keyboard.KEY_CAPITAL); |
||||
Keys.SCROLL_LOCK.setCode(Keyboard.KEY_SCROLL); |
||||
Keys.NUM_LOCK.setCode(Keyboard.KEY_NUMLOCK); |
||||
|
||||
Keys.NUMPAD_MINUS.setCode(Keyboard.KEY_SUBTRACT); |
||||
Keys.NUMPAD_PLUSS.setCode(Keyboard.KEY_ADD); |
||||
Keys.NUMPAD_0.setCode(Keyboard.KEY_NUMPAD0); |
||||
Keys.NUMPAD_1.setCode(Keyboard.KEY_NUMPAD1); |
||||
Keys.NUMPAD_2.setCode(Keyboard.KEY_NUMPAD2); |
||||
Keys.NUMPAD_3.setCode(Keyboard.KEY_NUMPAD3); |
||||
Keys.NUMPAD_4.setCode(Keyboard.KEY_NUMPAD4); |
||||
Keys.NUMPAD_5.setCode(Keyboard.KEY_NUMPAD5); |
||||
Keys.NUMPAD_6.setCode(Keyboard.KEY_NUMPAD6); |
||||
Keys.NUMPAD_7.setCode(Keyboard.KEY_NUMPAD7); |
||||
Keys.NUMPAD_8.setCode(Keyboard.KEY_NUMPAD8); |
||||
Keys.NUMPAD_9.setCode(Keyboard.KEY_NUMPAD9); |
||||
Keys.NUMPAD_DECIMAL.setCode(Keyboard.KEY_DECIMAL); |
||||
Keys.NUMPAD_ENTER.setCode(Keyboard.KEY_NUMPADENTER); |
||||
Keys.NUMPAD_DIVIDE.setCode(Keyboard.KEY_DIVIDE); |
||||
Keys.NUMPAD_MULTIPLY.setCode(Keyboard.KEY_MULTIPLY); |
||||
|
||||
Keys.CONTROL_LEFT.setCode(Keyboard.KEY_LCONTROL); |
||||
Keys.CONTROL_RIGHT.setCode(Keyboard.KEY_RCONTROL); |
||||
Keys.ALT_LEFT.setCode(Keyboard.KEY_LMENU); |
||||
Keys.ALT_RIGHT.setCode(Keyboard.KEY_RMENU); |
||||
Keys.SHIFT_LEFT.setCode(Keyboard.KEY_LSHIFT); |
||||
Keys.SHIFT_RIGHT.setCode(Keyboard.KEY_RSHIFT); |
||||
Keys.META_LEFT.setCode(Keyboard.KEY_LMETA); |
||||
Keys.META_RIGHT.setCode(Keyboard.KEY_RMETA); |
||||
|
||||
Keys.UP.setCode(Keyboard.KEY_UP); |
||||
Keys.DOWN.setCode(Keyboard.KEY_DOWN); |
||||
Keys.LEFT.setCode(Keyboard.KEY_LEFT); |
||||
Keys.RIGHT.setCode(Keyboard.KEY_RIGHT); |
||||
|
||||
Keys.HOME.setCode(Keyboard.KEY_HOME); |
||||
Keys.END.setCode(Keyboard.KEY_END); |
||||
|
||||
Keys.PAGE_UP.setCode(Keyboard.KEY_PRIOR); |
||||
Keys.PAGE_DOWN.setCode(Keyboard.KEY_NEXT); |
||||
|
||||
Keys.RETURN.setCode(Keyboard.KEY_RETURN); |
||||
Keys.PAUSE.setCode(Keyboard.KEY_PAUSE); |
||||
Keys.INSERT.setCode(Keyboard.KEY_INSERT); |
||||
Keys.DELETE.setCode(Keyboard.KEY_DELETE); |
||||
Keys.SYSRQ.setCode(Keyboard.KEY_SYSRQ); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void destroy() |
||||
{ |
||||
Mouse.destroy(); |
||||
Keyboard.destroy(); |
||||
} |
||||
|
||||
private final VectVar mouseMove = Vect.makeVar(); |
||||
private final VectVar mouseLastPos = Vect.makeVar(); |
||||
|
||||
|
||||
@Override |
||||
public synchronized void update(double delta) |
||||
{ |
||||
// was destroyed or not initialized
|
||||
if (!Display.isCreated()) return; |
||||
if (!Mouse.isCreated()) return; |
||||
if (!Keyboard.isCreated()) return; |
||||
|
||||
Display.processMessages(); |
||||
|
||||
// sum the moves
|
||||
mouseMove.reset(); |
||||
mouseLastPos.reset(); |
||||
boolean wasMouse = false; |
||||
while (Mouse.next()) { |
||||
onMouseEvent(mouseMove, mouseLastPos); |
||||
wasMouse = true; |
||||
} |
||||
|
||||
if (wasMouse && !mouseMove.isZero()) { |
||||
App.bus().send(new MouseMotionEvent(mouseLastPos, mouseMove)); |
||||
} |
||||
|
||||
while (Keyboard.next()) { |
||||
onKeyEvent(); |
||||
} |
||||
|
||||
if (Display.isCloseRequested()) { |
||||
App.shutdown(); |
||||
} |
||||
} |
||||
|
||||
|
||||
private void onMouseEvent(VectVar moveSum, VectVar lastPos) |
||||
{ |
||||
final int button = Mouse.getEventButton(); |
||||
final boolean down = Mouse.getEventButtonState(); |
||||
|
||||
final VectVar pos = Vect.makeVar(Mouse.getEventX(), Mouse.getEventY()); |
||||
final VectVar move = Vect.makeVar(Mouse.getEventDX(), Mouse.getEventDY()); |
||||
|
||||
final int wheeld = Mouse.getEventDWheel(); |
||||
|
||||
// flip Y axis
|
||||
pos.setY(Display.getHeight() - pos.y()); |
||||
|
||||
if (button != -1 || wheeld != 0) { |
||||
App.bus().send(new MouseButtonEvent(pos.freeze(), button, down, wheeld)); |
||||
} |
||||
|
||||
moveSum.setTo(moveSum.add(move)); |
||||
lastPos.setTo(pos); |
||||
} |
||||
|
||||
|
||||
private void onKeyEvent() |
||||
{ |
||||
final int key = Keyboard.getEventKey(); |
||||
final boolean down = Keyboard.getEventKeyState(); |
||||
final char c = Keyboard.getEventCharacter(); |
||||
|
||||
App.bus().send(new KeyEvent(key, c, down)); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Vect getMousePos() |
||||
{ |
||||
return mousePos; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isMouseInside() |
||||
{ |
||||
return Mouse.isInsideWindow(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void grabMouse(boolean grab) |
||||
{ |
||||
Mouse.setGrabbed(grab); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isKeyDown(Key key) |
||||
{ |
||||
return key.isDefined() && Keyboard.isKeyDown(key.getCode()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isMouseButtonDown(int button) |
||||
{ |
||||
return Mouse.isButtonDown(button); |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
package mightypork.gamecore.backends.lwjgl; |
||||
|
||||
|
||||
import java.util.logging.Level; |
||||
|
||||
import mightypork.utils.logging.writers.LogWriter; |
||||
|
||||
|
||||
/** |
||||
* Used to redirect slick log into main logger. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
class SlickLogRedirector implements org.newdawn.slick.util.LogSystem { |
||||
|
||||
LogWriter writer; |
||||
|
||||
|
||||
/** |
||||
* @param log log to redirect into |
||||
*/ |
||||
public SlickLogRedirector(LogWriter log) { |
||||
this.writer = log; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void error(String msg, Throwable e) |
||||
{ |
||||
writer.log(Level.SEVERE, msg, e); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void error(Throwable e) |
||||
{ |
||||
writer.log(Level.SEVERE, null, e); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void error(String msg) |
||||
{ |
||||
writer.log(Level.SEVERE, msg); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void warn(String msg) |
||||
{ |
||||
writer.log(Level.WARNING, msg); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void warn(String msg, Throwable e) |
||||
{ |
||||
writer.log(Level.WARNING, msg, e); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void info(String msg) |
||||
{ |
||||
writer.log(Level.INFO, msg); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void debug(String msg) |
||||
{ |
||||
writer.log(Level.FINEST, msg); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,146 @@ |
||||
package mightypork.gamecore.backends.lwjgl.audio; |
||||
|
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
import mightypork.gamecore.audio.DeferredAudio; |
||||
import mightypork.utils.files.FileUtil; |
||||
|
||||
import org.lwjgl.openal.AL10; |
||||
import org.newdawn.slick.openal.Audio; |
||||
import org.newdawn.slick.openal.SoundStore; |
||||
|
||||
|
||||
/** |
||||
* SlickUtil-based deferred audio resource. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public class SlickAudio extends DeferredAudio { |
||||
|
||||
private double pauseLoopPosition = 0; |
||||
private boolean looping = false; |
||||
private boolean paused = false; |
||||
private double lastPlayPitch = 1; |
||||
private double lastPlayGain = 1; |
||||
|
||||
/** Audio resource */ |
||||
private Audio backingAudio = null; |
||||
private int sourceID; |
||||
|
||||
|
||||
public SlickAudio(String resourceName) { |
||||
super(resourceName); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected void loadResource(String resource) throws IOException |
||||
{ |
||||
final String ext = FileUtil.getExtension(resource); |
||||
|
||||
try (final InputStream stream = FileUtil.getResource(resource)) { |
||||
|
||||
if (ext.equalsIgnoreCase("ogg")) { |
||||
backingAudio = SoundStore.get().getOgg(resource, stream); |
||||
|
||||
} else if (ext.equalsIgnoreCase("wav")) { |
||||
backingAudio = SoundStore.get().getWAV(resource, stream); |
||||
|
||||
} else if (ext.equalsIgnoreCase("aif")) { |
||||
backingAudio = SoundStore.get().getAIF(resource, stream); |
||||
|
||||
} else if (ext.equalsIgnoreCase("mod")) { |
||||
backingAudio = SoundStore.get().getMOD(resource, stream); |
||||
|
||||
} else { |
||||
throw new RuntimeException("Invalid audio file extension."); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void pauseLoop() |
||||
{ |
||||
if (!ensureLoaded()) return; |
||||
|
||||
if (isPlaying() && looping) { |
||||
pauseLoopPosition = backingAudio.getPosition(); |
||||
stop(); |
||||
paused = true; |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void resumeLoop() |
||||
{ |
||||
if (!ensureLoaded()) return; |
||||
|
||||
if (looping && paused) { |
||||
sourceID = backingAudio.playAsSoundEffect((float) lastPlayPitch, (float) lastPlayGain, true); |
||||
backingAudio.setPosition((float) pauseLoopPosition); |
||||
paused = false; |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void adjustGain(double gain) |
||||
{ |
||||
AL10.alSourcef(sourceID, AL10.AL_GAIN, (float) gain); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void stop() |
||||
{ |
||||
if (!isLoaded()) return; |
||||
|
||||
backingAudio.stop(); |
||||
paused = false; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isPlaying() |
||||
{ |
||||
if (!isLoaded()) return false; |
||||
|
||||
return backingAudio.isPlaying(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isPaused() |
||||
{ |
||||
if (!isLoaded()) return false; |
||||
|
||||
return backingAudio.isPaused(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void play(double pitch, double gain, boolean loop, double x, double y, double z) |
||||
{ |
||||
if (!ensureLoaded()) return; |
||||
|
||||
this.lastPlayPitch = pitch; |
||||
this.lastPlayGain = gain; |
||||
looping = loop; |
||||
|
||||
sourceID = backingAudio.playAsSoundEffect((float) pitch, (float) gain, loop, (float) x, (float) y, (float) z); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void destroy() |
||||
{ |
||||
if (!isLoaded() || backingAudio == null) return; |
||||
|
||||
backingAudio.release(); |
||||
backingAudio = null; |
||||
} |
||||
} |
@ -0,0 +1,75 @@ |
||||
package mightypork.gamecore.backends.lwjgl.audio; |
||||
|
||||
|
||||
import java.nio.FloatBuffer; |
||||
|
||||
import mightypork.gamecore.audio.AudioModule; |
||||
import mightypork.gamecore.audio.DeferredAudio; |
||||
import mightypork.gamecore.backends.lwjgl.BufferHelper; |
||||
import mightypork.utils.math.constraints.vect.Vect; |
||||
import mightypork.utils.math.constraints.vect.var.VectVar; |
||||
|
||||
import org.lwjgl.openal.AL; |
||||
import org.lwjgl.openal.AL10; |
||||
import org.newdawn.slick.openal.SoundStore; |
||||
|
||||
|
||||
/** |
||||
* SlickUtil-based audio module |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public class SlickAudioModule extends AudioModule { |
||||
|
||||
private final VectVar listenerPos = Vect.makeVar(); |
||||
|
||||
|
||||
@Override |
||||
public void init() |
||||
{ |
||||
SoundStore.get().setMaxSources(256); |
||||
SoundStore.get().init(); |
||||
setListenerPos(Vect.ZERO); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setListenerPos(Vect pos) |
||||
{ |
||||
listenerPos.setTo(pos); |
||||
final FloatBuffer buf3 = BufferHelper.alloc(3); |
||||
final FloatBuffer buf6 = BufferHelper.alloc(6); |
||||
buf3.clear(); |
||||
BufferHelper.fill(buf3, (float) pos.x(), (float) pos.y(), (float) pos.z()); |
||||
AL10.alListener(AL10.AL_POSITION, buf3); |
||||
buf3.clear(); |
||||
BufferHelper.fill(buf3, 0, 0, 0); |
||||
AL10.alListener(AL10.AL_VELOCITY, buf3); |
||||
buf6.clear(); |
||||
BufferHelper.fill(buf6, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f); |
||||
AL10.alListener(AL10.AL_ORIENTATION, buf6); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Vect getListenerPos() |
||||
{ |
||||
return listenerPos; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected void deinitSoundSystem() |
||||
{ |
||||
SoundStore.get().clear(); |
||||
AL.destroy(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected DeferredAudio doCreateResource(String res) |
||||
{ |
||||
return new SlickAudio(res); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,84 @@ |
||||
package mightypork.gamecore.backends.lwjgl.graphics; |
||||
|
||||
|
||||
import java.awt.image.BufferedImage; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.ByteBuffer; |
||||
|
||||
import javax.imageio.ImageIO; |
||||
|
||||
import mightypork.gamecore.graphics.Screenshot; |
||||
|
||||
|
||||
/** |
||||
* Screenshot object, can be used to extract image or write to file.<br> |
||||
* Screenshot, once taken, can be safely processed in separate thread.<br> |
||||
* Based on {@link BufferedImage} and {@link ImageIO}. |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public class AwtScreenshot implements Screenshot { |
||||
|
||||
private final int width; |
||||
private final int height; |
||||
private final int bpp; |
||||
private final ByteBuffer bytes; |
||||
private BufferedImage image; |
||||
|
||||
|
||||
/** |
||||
* @param width image width |
||||
* @param height image height |
||||
* @param bpp bits per pixel (typically 4) |
||||
* @param buffer |
||||
*/ |
||||
public AwtScreenshot(int width, int height, int bpp, ByteBuffer buffer) { |
||||
this.width = width; |
||||
this.height = height; |
||||
this.bpp = bpp; |
||||
this.bytes = buffer; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Extract to an image.<br> |
||||
* Subsequent calls will use a cached value. |
||||
* |
||||
* @return image |
||||
*/ |
||||
public BufferedImage getImage() |
||||
{ |
||||
if (image != null) return image; |
||||
|
||||
image = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_RGB); |
||||
|
||||
// convert to a buffered image
|
||||
for (int x = 0; x < this.width; x++) { |
||||
for (int y = 0; y < this.height; y++) { |
||||
final int i = (x + (this.width * y)) * this.bpp; |
||||
final int r = this.bytes.get(i) & 0xFF; |
||||
final int g = this.bytes.get(i + 1) & 0xFF; |
||||
final int b = this.bytes.get(i + 2) & 0xFF; |
||||
image.setRGB(x, this.height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); |
||||
} |
||||
} |
||||
|
||||
return image; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Save to a file.<br> |
||||
* Cached value is used if any. |
||||
* |
||||
* @param file target file |
||||
* @throws IOException on error writing to file |
||||
*/ |
||||
@Override |
||||
public void save(File file) throws IOException |
||||
{ |
||||
file.getParentFile().mkdirs(); |
||||
ImageIO.write(getImage(), "PNG", file); |
||||
} |
||||
} |
@ -0,0 +1,620 @@ |
||||
package mightypork.gamecore.backends.lwjgl.graphics; |
||||
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
import java.util.Stack; |
||||
|
||||
import mightypork.gamecore.core.App; |
||||
import mightypork.gamecore.graphics.GraphicsModule; |
||||
import mightypork.gamecore.graphics.Screenshot; |
||||
import mightypork.gamecore.graphics.textures.DeferredTexture; |
||||
import mightypork.gamecore.graphics.textures.TxQuad; |
||||
import mightypork.gamecore.gui.events.ViewportChangeEvent; |
||||
import mightypork.utils.logging.Log; |
||||
import mightypork.utils.math.color.Color; |
||||
import mightypork.utils.math.color.Grad; |
||||
import mightypork.utils.math.color.pal.RGB; |
||||
import mightypork.utils.math.constraints.rect.Rect; |
||||
import mightypork.utils.math.constraints.rect.caching.RectDigest; |
||||
import mightypork.utils.math.constraints.vect.Vect; |
||||
import mightypork.utils.math.timing.FpsMeter; |
||||
|
||||
import org.lwjgl.BufferUtils; |
||||
import org.lwjgl.LWJGLException; |
||||
import org.lwjgl.opengl.Display; |
||||
import org.lwjgl.opengl.DisplayMode; |
||||
import org.lwjgl.opengl.GL11; |
||||
|
||||
|
||||
/** |
||||
* LWJGL rendering module |
||||
* |
||||
* @author MightyPork |
||||
*/ |
||||
public class LwjglGraphicsModule extends GraphicsModule { |
||||
|
||||
/** Currently binded color */ |
||||
private Color activeColor = null; |
||||
/** Currently binded color's alpha multiplier */ |
||||
private double activeColorAlpha = 1; |
||||
/** Stack of pushed colors */ |
||||
private Stack<Color> colorPushStack = new Stack<>(); |
||||
/** Currently binded texture */ |
||||
private SlickTexture activeTexture; |
||||
|
||||
/** Display mode used currently for the window */ |
||||
private DisplayMode windowDisplayMode; |
||||
/** FPS the user wants */ |
||||
private int targetFps; |
||||
/** FPS meter used for measuring actual FPS */ |
||||
private FpsMeter fpsMeter = new FpsMeter(); |
||||
|
||||
/** Flag that at the end of frame, fullscreen should be toggled. */ |
||||
private boolean fullscreenToggleRequested; |
||||
/** Flag that at the end of frame, fullscreen should be set. */ |
||||
private boolean fullscreenSetRequested; |
||||
/** State to which fullscreen should be set. */ |
||||
private boolean fullscreenSetState; |
||||
|
||||
/** Current screen size */ |
||||
private static final Vect screenSize = new Vect() { |
||||
|
||||
@Override |
||||
public double y() |
||||
{ |
||||
return Display.getHeight(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double x() |
||||
{ |
||||
return Display.getWidth(); |
||||
} |
||||
}; |
||||
|
||||
/** Current screen rectangle */ |
||||
private static final Rect rect = Rect.make(screenSize); |
||||
|
||||
|
||||
@Override |
||||
public void init() |
||||
{ |
||||
try { |
||||
Display.create(); |
||||
} catch (final Exception e) { |
||||
throw new RuntimeException("Could not initialize display.", e); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setColor(Color color) |
||||
{ |
||||
setColor(color, 1); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setColor(Color color, double alpha) |
||||
{ |
||||
if (color == null) color = RGB.WHITE; |
||||
|
||||
// color components can change over time - must use equals()
|
||||
if (activeColorAlpha == alpha && color.equals(activeColor)) return; |
||||
|
||||
activeColor = color; |
||||
activeColorAlpha = alpha; |
||||
GL11.glColor4d(color.r(), color.g(), color.b(), alpha * color.a()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void translate(double x, double y) |
||||
{ |
||||
glTranslated(x, y, 0); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void translate(double x, double y, double z) |
||||
{ |
||||
glTranslated(x, y, z); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void translate(Vect offset) |
||||
{ |
||||
glTranslated(offset.x(), offset.y(), offset.z()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void translateXY(Vect offset) |
||||
{ |
||||
glTranslated(offset.x(), offset.y(), 0); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void scale(double x, double y) |
||||
{ |
||||
glScaled(x, y, 0); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void scale(double x, double y, double z) |
||||
{ |
||||
glScaled(x, y, z); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void scale(Vect scale) |
||||
{ |
||||
glScaled(scale.x(), scale.y(), scale.z()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void scaleXY(double scale) |
||||
{ |
||||
glScaled(scale, scale, 1); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void scaleX(double scale) |
||||
{ |
||||
glScaled(scale, 1, 1); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void scaleY(double scale) |
||||
{ |
||||
glScaled(1, scale, 1); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void scaleZ(double scale) |
||||
{ |
||||
glScaled(1, 1, scale); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void rotateX(double angle) |
||||
{ |
||||
rotate(angle, AXIS_X); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void rotateY(double angle) |
||||
{ |
||||
rotate(angle, AXIS_Y); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void rotateZ(double angle) |
||||
{ |
||||
rotate(angle, AXIS_Z); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void rotate(double angle, Vect axis) |
||||
{ |
||||
final Vect vec = axis.norm(1); |
||||
glRotated(angle, vec.x(), vec.y(), vec.z()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void pushState() |
||||
{ |
||||
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS); |
||||
GL11.glPushClientAttrib(GL11.GL_ALL_CLIENT_ATTRIB_BITS); |
||||
GL11.glPushMatrix(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void popState() |
||||
{ |
||||
GL11.glPopMatrix(); |
||||
GL11.glPopClientAttrib(); |
||||
GL11.glPopAttrib(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void pushGeometry() |
||||
{ |
||||
GL11.glPushMatrix(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void popGeometry() |
||||
{ |
||||
GL11.glPopMatrix(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void pushColor() |
||||
{ |
||||
colorPushStack.push(activeColor); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void popColor() |
||||
{ |
||||
setColor(colorPushStack.pop()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void quad(Rect rect) |
||||
{ |
||||
final RectDigest q = rect.digest(); |
||||
|
||||
// disable texture
|
||||
if (activeTexture != null) { |
||||
activeTexture = null; |
||||
glDisable(GL_TEXTURE_2D); |
||||
} |
||||
|
||||
// quad
|
||||
glBegin(GL_QUADS); |
||||
glVertex2d(q.left, q.bottom); |
||||
glVertex2d(q.right, q.bottom); |
||||
glVertex2d(q.right, q.top); |
||||
glVertex2d(q.left, q.top); |
||||
glEnd(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void quad(Rect rect, Color color) |
||||
{ |
||||
setColor(color); |
||||
quad(rect); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void quad(Rect rect, Grad grad) |
||||
{ |
||||
final RectDigest r = rect.digest(); |
||||
|
||||
// disable texture
|
||||
if (activeTexture != null) { |
||||
activeTexture = null; |
||||
glDisable(GL_TEXTURE_2D); |
||||
} |
||||
|
||||
// quad
|
||||
glBegin(GL_QUADS); |
||||
setColor(grad.leftBottom); |
||||
glVertex2d(r.left, r.bottom); |
||||
|
||||
setColor(grad.rightBottom); |
||||
glVertex2d(r.right, r.bottom); |
||||
|
||||
setColor(grad.rightTop); |
||||
glVertex2d(r.right, r.top); |
||||
|
||||
setColor(grad.leftTop); |
||||
glVertex2d(r.left, r.top); |
||||
glEnd(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void quad(Rect rect, TxQuad txquad) |
||||
{ |
||||
quad(rect, txquad, RGB.WHITE); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void quad(Rect rect, TxQuad txquad, Color color) |
||||
{ |
||||
// texture is loaded uniquely -> can compare with ==
|
||||
if (activeTexture != txquad.tx) { |
||||
glEnable(GL_TEXTURE_2D); |
||||
activeTexture = (SlickTexture) txquad.tx; |
||||
activeTexture.bind(); |
||||
} |
||||
|
||||
glBegin(GL_QUADS); |
||||
setColor(color); |
||||
|
||||
final RectDigest q = rect.digest(); |
||||
final RectDigest u = txquad.uvs.digest(); |
||||
|
||||
final double offs = 0.0001;// hack to avoid white stitching
|
||||
|
||||
double tL = u.left + offs, tR = u.right - offs, tT = u.top + offs, tB = u.bottom - offs; |
||||
|
||||
// handle flip
|
||||
if (txquad.isFlippedY()) { |
||||
final double swap = tT; |
||||
tT = tB; |
||||
tB = swap; |
||||
} |
||||
|
||||
if (txquad.isFlippedX()) { |
||||
final double swap = tL; |
||||
tL = tR; |
||||
tR = swap; |
||||
} |
||||
|
||||
final double w = activeTexture.getWidth01(); |
||||
final double h = activeTexture.getHeight01(); |
||||
|
||||
// quad with texture
|
||||
glTexCoord2d(tL * w, tB * h); |
||||
glVertex2d(q.left, q.bottom); |
||||
|
||||
glTexCoord2d(tR * w, tB * h); |
||||
glVertex2d(q.right, q.bottom); |
||||
|
||||
glTexCoord2d(tR * w, tT * h); |
||||
glVertex2d(q.right, q.top); |
||||
|
||||
glTexCoord2d(tL * w, tT * h); |
||||
glVertex2d(q.left, q.top); |
||||
|
||||
glEnd(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setupProjection() |
||||
{ |
||||
// fix projection for changed size
|
||||
glMatrixMode(GL_PROJECTION); |
||||
glLoadIdentity(); |
||||
|
||||
int w = Display.getWidth(); |
||||
int h = Display.getHeight(); |
||||
|
||||
glViewport(0, 0, w, h); |
||||
glOrtho(0, w, h, 0, -1000, 1000); |
||||
|
||||
// back to modelview
|
||||
glMatrixMode(GL_MODELVIEW); |
||||
|
||||
glLoadIdentity(); |
||||
|
||||
glDisable(GL_LIGHTING); |
||||
|
||||
glClearDepth(1f); |
||||
glEnable(GL_DEPTH_TEST); |
||||
glDepthFunc(GL_LEQUAL); |
||||
|
||||
glEnable(GL_NORMALIZE); |
||||
|
||||
glShadeModel(GL_SMOOTH); |
||||
|
||||
glEnable(GL_BLEND); |
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public DeferredTexture getLazyTexture(String path) |
||||
{ |
||||
return new SlickTexture(path); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void destroy() |
||||
{ |
||||
Display.destroy(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setTargetFps(int fps) |
||||
{ |
||||
this.targetFps = fps; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setFullscreen(boolean fs) |
||||
{ |
||||
fullscreenSetRequested = true; |
||||
fullscreenSetState = fs; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void switchFullscreen() |
||||
{ |
||||
fullscreenToggleRequested = true; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isFullscreen() |
||||
{ |
||||
return Display.isFullscreen(); |
||||
} |
||||
|
||||
|
||||
private void doToggleFullscreen() |
||||
{ |
||||
doSetFullscreen(!Display.isFullscreen()); |
||||
} |
||||
|
||||
|
||||
private void doSetFullscreen(boolean fs) |
||||
{ |
||||
try { |
||||
|
||||
if (Display.isFullscreen() == fs) return; // no work
|
||||
|
||||
if (fs) { |
||||
Log.f3("Entering fullscreen."); |
||||
// save window resize
|
||||
windowDisplayMode = new DisplayMode(Display.getWidth(), Display.getHeight()); |
||||
|
||||
Display.setDisplayMode(Display.getDesktopDisplayMode()); |
||||
Display.setFullscreen(true); |
||||
Display.update(); |
||||
} else { |
||||
Log.f3("Leaving fullscreen."); |
||||
Display.setDisplayMode(windowDisplayMode); |
||||
Display.update(); |
||||
} |
||||
|
||||
App.bus().send(new ViewportChangeEvent(getSize())); |
||||
|
||||
} catch (final Throwable t) { |
||||
Log.e("Failed to change fullscreen mode.", t); |
||||
try { |
||||
Display.setDisplayMode(windowDisplayMode); |
||||
Display.update(); |
||||
} catch (final Throwable t1) { |
||||
throw new RuntimeException("Failed to revert failed fullscreen toggle.", t1); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Screenshot takeScreenshot() |
||||
{ |
||||
glReadBuffer(GL_FRONT); |
||||
final int width = Display.getWidth(); |
||||
final int height = Display.getHeight(); |
||||
final int bpp = 4; |
||||
final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp); |
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); |
||||
|
||||
final AwtScreenshot sc = new AwtScreenshot(width, height, bpp, buffer); |
||||
|
||||
return sc; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void beginFrame() |
||||
{ |
||||
// handle resize
|
||||
if (Display.wasResized()) { |
||||
App.bus().send(new ViewportChangeEvent(getSize())); |
||||
} |
||||
|
||||
if (fullscreenToggleRequested) { |
||||
fullscreenToggleRequested = false; |
||||
doToggleFullscreen(); |
||||
} |
||||
|
||||
if (fullscreenSetRequested) { |
||||
fullscreenSetRequested = false; |
||||
doSetFullscreen(fullscreenSetState); |
||||
} |
||||
|
||||
glLoadIdentity(); |
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
||||
fpsMeter.frame(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void endFrame() |
||||
{ |
||||
Display.update(false); // don't poll input devices
|
||||
Display.sync(targetFps); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setSize(int width, int height) |
||||
{ |
||||
try { |
||||
Display.setDisplayMode(windowDisplayMode = new DisplayMode(width, height)); |
||||
} catch (LWJGLException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setTitle(String title) |
||||
{ |
||||
Display.setTitle(title); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setVSync(boolean vsync) |
||||
{ |
||||
Display.setVSyncEnabled(vsync); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setResizable(boolean resizable) |
||||
{ |
||||
Display.setResizable(resizable); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Rect getRect() |
||||
{ |
||||
return rect; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public long getFps() |
||||
{ |
||||
return fpsMeter.getFPS(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Vect getCenter() |
||||
{ |
||||
return rect.center(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getWidth() |
||||
{ |
||||
return Display.getWidth(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getHeight() |
||||
{ |
||||
return Display.getHeight(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Vect getSize() |
||||
{ |
||||
return screenSize; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,194 @@ |
||||
package mightypork.gamecore.backends.lwjgl.graphics; |
||||
|
||||
|
||||
import java.io.IOException; |
||||
|
||||
import mightypork.gamecore.graphics.textures.DeferredTexture; |
||||
import mightypork.gamecore.resources.loading.MustLoadInRenderingContext; |
||||
import mightypork.utils.annotations.Alias; |
||||
import mightypork.utils.exceptions.IllegalValueException; |
||||
import mightypork.utils.files.FileUtil; |
||||
import mightypork.utils.logging.Log; |
||||
|
||||
import org.lwjgl.opengl.GL11; |
||||
import org.newdawn.slick.opengl.Texture; |
||||
import org.newdawn.slick.opengl.TextureLoader; |
||||
|
||||
|
||||
/** |
||||
* Deferred texture |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
@Alias(name = "Texture") |
||||
@MustLoadInRenderingContext |
||||
public class SlickTexture extends DeferredTexture { |
||||
|
||||
private org.newdawn.slick.opengl.Texture backingTexture; |
||||
private boolean alpha; |
||||
private boolean alphal; |
||||
|
||||
|
||||
/** |
||||
* @param resourcePath resource path |
||||
*/ |
||||
public SlickTexture(String resourcePath) { |
||||
super(resourcePath); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected synchronized void loadResource(String path) |
||||
{ |
||||
try { |
||||
final String ext = FileUtil.getExtension(path).toUpperCase(); |
||||
|
||||
final int filtering; |
||||
switch (filter) { |
||||
case NEAREST: |
||||
filtering = GL11.GL_NEAREST; |
||||
break; |
||||
case LINEAR: |
||||
filtering = GL11.GL_LINEAR; |
||||
break; |
||||
default: |
||||
throw new IllegalValueException("Unsupported filtering mode."); |
||||
} |
||||
|
||||
final Texture texture = TextureLoader.getTexture(ext, FileUtil.getResource(path), false, filtering); |
||||
|
||||
if (texture == null) { |
||||
Log.w("Texture " + path + " could not be loaded."); |
||||
} |
||||
|
||||
backingTexture = texture; |
||||
|
||||
} catch (final IOException e) { |
||||
Log.e("Loading of texture " + path + " failed.", e); |
||||
throw new RuntimeException("Could not load texture " + path + ".", e); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean hasAlpha() |
||||
{ |
||||
if (!ensureLoaded()) return false; |
||||
|
||||
if (!alphal) { |
||||
alphal = true; |
||||
alpha = backingTexture.hasAlpha(); |
||||
} |
||||
|
||||
return alpha; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Bind to GL context, applying the filters prescribed. |
||||
*/ |
||||
public void bind() |
||||
{ |
||||
if (!ensureLoaded()) return; |
||||
|
||||
//GL11.glEnable(GL11.GL_TEXTURE_2D);
|
||||
|
||||
GL11.glBindTexture(GL11.GL_TEXTURE_2D, getTextureID()); |
||||
|
||||
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE); |
||||
|
||||
final int wrapping; |
||||
switch (wrap) { |
||||
case CLAMP: |
||||
wrapping = GL11.GL_CLAMP; |
||||
break; |
||||
case REPEAT: |
||||
wrapping = GL11.GL_REPEAT; |
||||
break; |
||||
default: |
||||
throw new IllegalValueException("Unsupported wrapping mode."); |
||||
} |
||||
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrapping); |
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrapping); |
||||
|
||||
final int filtering; |
||||
switch (filter) { |
||||
case NEAREST: |
||||
filtering = GL11.GL_NEAREST; |
||||
break; |
||||
case LINEAR: |
||||
filtering = GL11.GL_LINEAR; |
||||
break; |
||||
default: |
||||
throw new IllegalValueException("Unsupported filtering mode."); |
||||
} |
||||
|
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filtering); |
||||
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filtering); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getImageHeight() |
||||
{ |
||||
if (!ensureLoaded()) return 0; |
||||
|
||||
return backingTexture.getImageHeight(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getImageWidth() |
||||
{ |
||||
if (!ensureLoaded()) return 0; |
||||
|
||||
return backingTexture.getImageWidth(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void destroy() |
||||
{ |
||||
if (!isLoaded()) return; |
||||
|
||||
backingTexture.release(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the height of the texture, 0..1.<br> |
||||
* |
||||
* @return height 0..1 |
||||
*/ |
||||
public float getHeight01() |
||||
{ |
||||
if (!ensureLoaded()) return 0; |
||||
|
||||
return backingTexture.getHeight(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get the width of the texture, 0..1.<br> |
||||
* |
||||
* @return width 0..1 |
||||
*/ |
||||
public float getWidth01() |
||||
{ |
||||
if (!ensureLoaded()) return 0; |
||||
|
||||
return backingTexture.getWidth(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* @return OpenGL texture ID |
||||
*/ |
||||
public int getTextureID() |
||||
{ |
||||
if (!ensureLoaded()) return -1; |
||||
|
||||
return backingTexture.getTextureID(); |
||||
} |
||||
} |
@ -0,0 +1,143 @@ |
||||
package mightypork.gamecore.backends.lwjgl.graphics.font; |
||||
|
||||
|
||||
import java.awt.Font; |
||||
import java.awt.FontFormatException; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
|
||||
import mightypork.gamecore.graphics.fonts.DeferredFont; |
||||
import mightypork.gamecore.graphics.fonts.IFont; |
||||
import mightypork.gamecore.resources.loading.MustLoadInRenderingContext; |
||||
import mightypork.utils.annotations.Alias; |
||||
import mightypork.utils.files.FileUtil; |
||||
import mightypork.utils.math.color.Color; |
||||
import mightypork.utils.math.constraints.vect.Vect; |
||||
|
||||
|
||||
/** |
||||
* Font obtained from a resource file (TTF). |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
@MustLoadInRenderingContext |
||||
@Alias(name = "Font") |
||||
public class DeferredLwjglFont extends DeferredFont { |
||||
|
||||
private IFont font = null; |
||||
|
||||
|
||||
/** |
||||
* A font from resource |
||||
* |
||||
* @param resourcePath resource to load |
||||
* @param chars chars to load; null to load basic chars only |
||||
* @param size size (px) |
||||
*/ |
||||
public DeferredLwjglFont(String resourcePath, String chars, double size) { |
||||
super(resourcePath); |
||||
this.size = size; |
||||
this.chars = chars; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected synchronized final void loadResource(String path) throws IOException |
||||
{ |
||||
final Font awtFont = getAwtFont(path, (float) size, style.numval); |
||||
|
||||
font = new LwjglTextureBackedFont(awtFont, antialias, filter, chars); |
||||
font.setDiscardRatio(discardTop, discardBottom); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get a font for a resource path / name |
||||
* |
||||
* @param resource resource to load |
||||
* @param size font size (pt) |
||||
* @param style font style |
||||
* @return the {@link Font} |
||||
* @throws IOException |
||||
*/ |
||||
protected Font getAwtFont(String resource, float size, int style) throws IOException |
||||
{ |
||||
try (InputStream in = FileUtil.getResource(resource)) { |
||||
|
||||
Font awtFont = Font.createFont(Font.TRUETYPE_FONT, in); |
||||
|
||||
awtFont = awtFont.deriveFont(size); |
||||
awtFont = awtFont.deriveFont(style); |
||||
|
||||
return awtFont; |
||||
} catch (final FontFormatException e) { |
||||
throw new IOException("Could not load font, bad format.", e); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Draw string |
||||
* |
||||
* @param str string to draw |
||||
* @param color draw color |
||||
*/ |
||||
@Override |
||||
public void draw(String str, Color color) |
||||
{ |
||||
if (!ensureLoaded()) return; |
||||
|
||||
font.draw(str, color); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get size needed to render give string |
||||
* |
||||
* @param text string to check |
||||
* @return coord (width, height) |
||||
*/ |
||||
@Override |
||||
public Vect getNeededSpace(String text) |
||||
{ |
||||
if (!ensureLoaded()) return Vect.ZERO; |
||||
|
||||
return font.getNeededSpace(text); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* @return font height |
||||
*/ |
||||
@Override |
||||
public int getLineHeight() |
||||
{ |
||||
if (!ensureLoaded()) return 0; |
||||
|
||||
return font.getLineHeight(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getFontSize() |
||||
{ |
||||
if (!ensureLoaded()) return 0; |
||||
|
||||
return font.getFontSize(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getWidth(String text) |
||||
{ |
||||
return font.getWidth(text); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void destroy() |
||||
{ |
||||
// this will have to suffice
|
||||
font = null; |
||||
} |
||||
} |
@ -0,0 +1,36 @@ |
||||
package mightypork.gamecore.backends.lwjgl.graphics.font; |
||||
|
||||
|
||||
import java.awt.Font; |
||||
import java.io.IOException; |
||||
|
||||
import mightypork.utils.annotations.Alias; |
||||
|
||||
|
||||
/** |
||||
* Font obtained from the OS |
||||
* |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
@Alias(name = "FontNative") |
||||
public class DeferredLwjglFontFromSystem extends DeferredLwjglFont { |
||||
|
||||
/** |
||||
* A font from OS, found by name |
||||
* |
||||
* @param fontName font family name |
||||
* @param chars chars to load; null to load basic chars only |
||||
* @param size size (pt) |
||||
*/ |
||||
public DeferredLwjglFontFromSystem(String fontName, String chars, double size) { |
||||
super(fontName, chars, size); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected Font getAwtFont(String resource, float size, int style) throws IOException |
||||
{ |
||||
return new Font(resource, style, (int) size); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,494 @@ |
||||
package mightypork.gamecore.backends.lwjgl.graphics.font; |
||||
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*; |
||||
|
||||
import java.awt.FontMetrics; |
||||
import java.awt.Graphics2D; |
||||
import java.awt.RenderingHints; |
||||
import java.awt.image.BufferedImage; |
||||
import java.awt.image.DataBuffer; |
||||
import java.awt.image.DataBufferByte; |
||||
import java.awt.image.DataBufferInt; |
||||
import java.nio.ByteBuffer; |
||||
import java.nio.ByteOrder; |
||||
import java.nio.IntBuffer; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
import mightypork.gamecore.graphics.fonts.IFont; |
||||
import mightypork.gamecore.graphics.textures.FilterMode; |
||||
import mightypork.utils.exceptions.IllegalValueException; |
||||
import mightypork.utils.logging.Log; |
||||
import mightypork.utils.math.color.Color; |
||||
import mightypork.utils.math.constraints.vect.Vect; |
||||
import mightypork.utils.math.constraints.vect.VectConst; |
||||
|
||||
import org.lwjgl.BufferUtils; |
||||
import org.lwjgl.util.glu.GLU; |
||||
import org.newdawn.slick.opengl.GLUtils; |
||||
|
||||
|
||||
/** |
||||
* A TrueType font renderer with backing texture. |
||||
* |
||||
* @author James Chambers (Jimmy) |
||||
* @author Jeremy Adams (elias4444) |
||||
* @author Kevin Glass (kevglass) |
||||
* @author Peter Korzuszek (genail) |
||||
* @author David Aaron Muhar (bobjob) |
||||
* @author Ondřej Hruška (MightyPork) |
||||
*/ |
||||
public class LwjglTextureBackedFont implements IFont { |
||||
|
||||
private class CharTile { |
||||
|
||||
public int width; |
||||
public int height; |
||||
public int texPosX; |
||||
public int texPosY; |
||||
} |
||||
|
||||
/* char bank */ |
||||
private final Map<Character, CharTile> chars = new HashMap<>(255); |
||||
|
||||
/* use antialiasing for rendering */ |
||||
private final boolean antiAlias; |
||||
|
||||
/* loaded font size (requested) */ |
||||
private final int fontSize; |
||||
|
||||
/* actual height of drawn glyphs */ |
||||
private int fontHeight; |
||||
|
||||
/* texture id */ |
||||
private int textureID; |
||||
|
||||
/* texture width */ |
||||
private int textureWidth; |
||||
|
||||
/* texture height */ |
||||
private int textureHeight; |
||||
|
||||
/* AWT font source */ |
||||
private final java.awt.Font font; |
||||
|
||||
private final FilterMode filter; |
||||
|
||||
private double discardTop; |
||||
|
||||
private double discardBottom; |
||||
|
||||
|
||||
/** |
||||
* Make a font |
||||
* |
||||
* @param font original awt font to load |
||||
* @param antialias use antialiasing when rendering to cache texture |
||||
* @param filter used Gl filter |
||||
* @param chars chars to load |
||||
*/ |
||||
public LwjglTextureBackedFont(java.awt.Font font, boolean antialias, FilterMode filter, String chars) { |
||||
this(font, antialias, filter, (" " + chars).toCharArray()); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Make a font |
||||
* |
||||
* @param font original awt font to load |
||||
* @param antialias use antialiasing when rendering to cache texture |
||||
* @param filter used Gl filter |
||||
* @param chars chars to load |
||||
*/ |
||||
public LwjglTextureBackedFont(java.awt.Font font, boolean antialias, FilterMode filter, char[] chars) { |
||||
GLUtils.checkGLContext(); |
||||
|
||||
this.font = font; |
||||
this.filter = filter; |
||||
this.fontSize = font.getSize(); |
||||
this.antiAlias = antialias; |
||||
|
||||
createSet(chars); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Create a BufferedImage of the given character |
||||
* |
||||
* @param ch the character |
||||
* @return BufferedImage containing the drawn character |
||||
*/ |
||||
private BufferedImage getFontImage(char ch) |
||||
{ |
||||
FontMetrics metrics; |
||||
BufferedImage img; |
||||
Graphics2D g; |
||||
|
||||
// Create a temporary image to extract the character's size
|
||||
img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); |
||||
|
||||
g = (Graphics2D) img.getGraphics(); |
||||
if (antiAlias == true) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
||||
g.setFont(font); |
||||
|
||||
metrics = g.getFontMetrics(); |
||||
|
||||
final int charwidth = Math.max(1, metrics.charWidth(ch)); |
||||
final int charheight = Math.max(fontSize, metrics.getHeight()); |
||||
|
||||
// Create another image holding the character we are creating
|
||||
final BufferedImage fontImage = new BufferedImage(charwidth, charheight, BufferedImage.TYPE_INT_ARGB); |
||||
|
||||
g = (Graphics2D) fontImage.getGraphics(); |
||||
if (antiAlias == true) g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
||||
g.setFont(font); |
||||
g.setColor(java.awt.Color.WHITE); |
||||
g.drawString(String.valueOf(ch), 0, metrics.getAscent()); |
||||
|
||||
return fontImage; |
||||
} |
||||
|
||||
|
||||
private void createSet(char[] charsToLoad) |
||||
{ |
||||
try { |
||||
class LoadedGlyph { |
||||
|
||||
public char c; |
||||
public BufferedImage image; |
||||
public int width; |
||||
public int height; |
||||
|
||||
|
||||
public LoadedGlyph(char c, BufferedImage image) { |
||||
this.image = image; |
||||
this.c = c; |
||||
this.width = image.getWidth(); |
||||
this.height = image.getHeight(); |
||||
} |
||||
} |
||||
|
||||
final List<LoadedGlyph> glyphs = new ArrayList<>(); |
||||
final List<Character> loaded = new ArrayList<>(); |
||||
for (final char ch : charsToLoad) { |
||||
if (!loaded.contains(ch)) { |
||||
glyphs.add(new LoadedGlyph(ch, getFontImage(ch))); |
||||
loaded.add(ch); |
||||
} |
||||
} |
||||
|
||||
int lineHeight = 0; |
||||
|
||||
int beginX = 0, beginY = 0; |
||||
int canvasW = 128, canvasH = 128; |
||||
|
||||
boolean needsLarger = false; |
||||
|
||||
// find smallest 2^x size for texture
|
||||
while (true) { |
||||
needsLarger = false; |
||||
|
||||
for (final LoadedGlyph glyph : glyphs) { |
||||
if (beginX + glyph.width > canvasW) { |
||||
beginY += lineHeight; |
||||
lineHeight = 0; |
||||
beginX = 0; |
||||
} |
||||
|
||||
if (lineHeight < glyph.height) { |
||||
lineHeight = glyph.height; |
||||
} |
||||
|
||||
if (beginY + lineHeight > canvasH) { |
||||
needsLarger = true; |
||||
break; |
||||
} |
||||
|
||||
// draw.
|
||||
beginX += glyph.width; |
||||
} |
||||
|
||||
if (needsLarger) { |
||||
canvasW *= 2; |
||||
canvasH *= 2; |
||||
beginX = 0; |
||||
beginY = 0; |
||||
lineHeight = 0; |
||||
} else { |
||||
Log.f3(String.format("Generating font texture: %d×%d", canvasW, canvasH)); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
textureWidth = canvasW; |
||||
textureHeight = canvasH; |
||||
|
||||
BufferedImage imag = new BufferedImage(textureWidth, textureHeight, BufferedImage.TYPE_INT_ARGB); |
||||
final Graphics2D g = (Graphics2D) imag.getGraphics(); |
||||
|
||||
g.setColor(new java.awt.Color(0, 0, 0, 1)); |
||||
g.fillRect(0, 0, textureWidth, textureHeight); |
||||
|
||||
int rowHeight = 0, posX = 0, posY = 0; |
||||
|
||||
for (final LoadedGlyph glyph : glyphs) { |
||||
final CharTile cht = new CharTile(); |
||||
|
||||
cht.width = glyph.width; |
||||
cht.height = glyph.height; |
||||
|
||||
if (posX + cht.width >= textureWidth) { |
||||
posX = 0; |
||||
posY += rowHeight; |
||||
rowHeight = 0; |
||||
} |
||||
|
||||
cht.texPosX = posX; |
||||
cht.texPosY = posY; |
||||
|
||||
if (cht.height > fontHeight) { |
||||
fontHeight = cht.height; |
||||
} |
||||
|
||||
if (cht.height > rowHeight) { |
||||
rowHeight = cht.height; |
||||
} |
||||
|
||||
// Draw it here
|
||||
g.drawImage(glyph.image, posX, posY, null); |
||||
|
||||
posX += cht.width; |
||||
|
||||
chars.put(glyph.c, cht); |
||||
} |
||||
|
||||
textureID = loadImage(imag); |
||||
|
||||
imag = null; |
||||
|
||||
} catch (final Throwable t) { |
||||
Log.e("Failed to load font.", t); |
||||
} |
||||
} |
||||
|
||||
|
||||
private int loadImage(BufferedImage bufferedImage) |
||||
{ |
||||
try { |
||||
final short width = (short) bufferedImage.getWidth(); |
||||
final short height = (short) bufferedImage.getHeight(); |
||||
final int bpp = (byte) bufferedImage.getColorModel().getPixelSize(); |
||||
|
||||
ByteBuffer byteBuffer; |
||||
final DataBuffer db = bufferedImage.getData().getDataBuffer(); |
||||
if (db instanceof DataBufferInt) { |
||||
final int intI[] = ((DataBufferInt) (bufferedImage.getData().getDataBuffer())).getData(); |
||||
final byte newI[] = new byte[intI.length * 4]; |
||||
for (int i = 0; i < intI.length; i++) { |
||||
final byte b[] = intToByteArray(intI[i]); |
||||
final int newIndex = i * 4; |
||||
|
||||
newI[newIndex] = b[1]; |
||||
newI[newIndex + 1] = b[2]; |
||||
newI[newIndex + 2] = b[3]; |
||||
newI[newIndex + 3] = b[0]; |
||||
} |
||||
|
||||
byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(newI); |
||||
} else { |
||||
byteBuffer = ByteBuffer.allocateDirect(width * height * (bpp / 8)).order(ByteOrder.nativeOrder()).put(((DataBufferByte) (bufferedImage.getData().getDataBuffer())).getData()); |
||||
} |
||||
|
||||
byteBuffer.flip(); |
||||
|
||||
final int internalFormat = GL_RGBA8, format = GL_RGBA; |
||||
final IntBuffer textureId = BufferUtils.createIntBuffer(1); |
||||
|
||||
glGenTextures(textureId); |
||||
glBindTexture(GL_TEXTURE_2D, textureId.get(0)); |
||||
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); |
||||
|
||||
final int filtering; |
||||
switch (filter) { |
||||
case NEAREST: |
||||
filtering = GL_NEAREST; |
||||
break; |
||||
case LINEAR: |
||||
filtering = GL_LINEAR; |
||||
break; |
||||
default: |
||||
throw new IllegalValueException("Unsupported filtering mode."); |
||||
} |
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); |
||||
|
||||
GLU.gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, width, height, format, GL_UNSIGNED_BYTE, byteBuffer); |
||||
return textureId.get(0); |
||||
|
||||
} catch (final Throwable t) { |
||||
Log.e("Failed to load font.", t); |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
|
||||
private static byte[] intToByteArray(int value) |
||||
{ |
||||
return new byte[] { (byte) (value >>> 24), (byte) (value >>> 16), (byte) (value >>> 8), (byte) value }; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Get size needed to draw given string |
||||
* |
||||
* @param text drawn text |
||||
* @return needed width |
||||
*/ |
||||
@Override |
||||
public int getWidth(String text) |
||||
{ |
||||
int totalwidth = 0; |
||||
CharTile ch = null; |
||||
for (int i = 0; i < text.length(); i++) { |
||||
|
||||
ch = chars.get(text.charAt(i)); |
||||
|
||||
if (ch != null) totalwidth += ch.width; |
||||
} |
||||
return totalwidth; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getLineHeight() |
||||
{ |
||||
return (int) Math.round(fontHeight * ((1 - discardTop) - discardBottom)); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getFontSize() |
||||
{ |
||||
return fontSize; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void draw(String text, Color color) |
||||
{ |
||||
GLUtils.checkGLContext(); |
||||
|
||||
// PUSH
|
||||
glPushAttrib(GL_ENABLE_BIT); |
||||
|
||||
glEnable(GL_TEXTURE_2D); |
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textureID); |
||||
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); |
||||
|
||||
final int filtering; |
||||
switch (filter) { |
||||
case NEAREST: |
||||
filtering = GL_NEAREST; |
||||
break; |
||||
case LINEAR: |
||||
filtering = GL_LINEAR; |
||||
break; |
||||
default: |
||||
throw new IllegalValueException("Unsupported filtering mode."); |
||||
} |
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering); |
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering); |
||||
|
||||
glColor4d(color.r(), color.g(), color.b(), color.a()); |
||||
|
||||
glBegin(GL_QUADS); |
||||
|
||||
CharTile chtx = null; |
||||
char charCurrent; |
||||
int minx = 0; |
||||
|
||||
for (int i = 0; i < text.length(); i++) { |
||||
charCurrent = text.charAt(i); |
||||
|
||||
chtx = chars.get(charCurrent); |
||||
|
||||
if (chtx != null) { |
||||
|
||||
// draw quad
|
||||
|
||||
final float txmin = chtx.texPosX; |
||||
final float tymin = chtx.texPosY; |
||||
final float draw_width = minx + chtx.width - minx; |
||||
final float draw_height = chtx.height; |
||||
final float drawy0 = (float) (0f - draw_height * discardTop); |
||||
|
||||
final float txmin01 = txmin / textureWidth; |
||||
final float tymin01 = tymin / textureHeight; |
||||
final float twidth01 = ((chtx.texPosX + chtx.width - txmin) / textureWidth); |
||||
final float theight01 = ((chtx.texPosY + chtx.height - tymin) / textureHeight); |
||||
|
||||
glTexCoord2f(txmin01, tymin01); |
||||
glVertex2f(minx, drawy0); |
||||
|
||||
glTexCoord2f(txmin01, tymin01 + theight01); |
||||
glVertex2f(minx, drawy0 + draw_height); |
||||
|
||||
glTexCoord2f(txmin01 + twidth01, tymin01 + theight01); |
||||
glVertex2f(minx + draw_width, drawy0 + draw_height); |
||||
|
||||
glTexCoord2f(txmin01 + twidth01, tymin01); |
||||
glVertex2f(minx + draw_width, drawy0); |
||||
minx += chtx.width; |
||||
} |
||||
} |
||||
|
||||
glEnd(); |
||||
|
||||
// POP
|
||||
glPopAttrib(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public VectConst getNeededSpace(String text) |
||||
{ |
||||
return Vect.make(getWidth(text), getLineHeight()); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public void setDiscardRatio(double top, double bottom) |
||||
{ |
||||
discardTop = top; |
||||
discardBottom = bottom; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double getTopDiscardRatio() |
||||
{ |
||||
return discardTop; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public double getBottomDiscardRatio() |
||||
{ |
||||
return discardBottom; |
||||
} |
||||
} |
Loading…
Reference in new issue