More refactoring towards backend system

master
Ondřej Hruška 11 years ago
parent 7024fb4402
commit ec64ad21fc
  1. 34
      src/mightypork/gamecore/backend/Backend.java
  2. 32
      src/mightypork/gamecore/backend/BackendModule.java
  3. 85
      src/mightypork/gamecore/backend/lwjgl/AwtScreenshot.java
  4. 37
      src/mightypork/gamecore/backend/lwjgl/LwjglBackend.java
  5. 641
      src/mightypork/gamecore/backend/lwjgl/LwjglRenderModule.java
  6. 142
      src/mightypork/gamecore/backend/lwjgl/SlickLazyTexture.java
  7. 85
      src/mightypork/gamecore/core/modules/App.java
  8. 10
      src/mightypork/gamecore/core/modules/BaseApp.java
  9. 4
      src/mightypork/gamecore/gui/components/painters/ImagePainter.java
  10. 34
      src/mightypork/gamecore/gui/components/painters/QuadPainter.java
  11. 25
      src/mightypork/gamecore/gui/components/painters/TextPainter.java
  12. 11
      src/mightypork/gamecore/gui/screens/Screen.java
  13. 6
      src/mightypork/gamecore/render/DisplaySystem.java
  14. 31
      src/mightypork/gamecore/render/Grad.java
  15. 17
      src/mightypork/gamecore/render/GradH.java
  16. 17
      src/mightypork/gamecore/render/GradV.java
  17. 5
      src/mightypork/gamecore/render/Render.java
  18. 420
      src/mightypork/gamecore/render/RenderModule.java
  19. 80
      src/mightypork/gamecore/render/Screenshot.java
  20. 14
      src/mightypork/gamecore/render/TaskTakeScreenshot.java
  21. 4
      src/mightypork/gamecore/resources/Res.java
  22. 10
      src/mightypork/gamecore/resources/fonts/FontRenderer.java
  23. 2
      src/mightypork/gamecore/resources/fonts/impl/TextureBackedFont.java
  24. 2
      src/mightypork/gamecore/resources/textures/ITexture.java
  25. 118
      src/mightypork/gamecore/resources/textures/LazyTexture.java
  26. 4
      src/mightypork/gamecore/resources/textures/QuadGrid.java
  27. 15
      src/mightypork/gamecore/resources/textures/TextureRegistry.java
  28. 10
      src/mightypork/gamecore/resources/textures/TxQuad.java
  29. 3
      src/mightypork/rogue/RogueApp.java
  30. 4
      src/mightypork/rogue/RogueResources.java

@ -0,0 +1,34 @@
package mightypork.gamecore.backend;
import mightypork.gamecore.render.RenderModule;
import mightypork.utils.eventbus.BusAccess;
import mightypork.utils.eventbus.clients.RootBusNode;
/**
* Application backend interface (set of core modules)
*
* @author MightyPork
*/
public abstract class Backend extends RootBusNode {
public Backend(BusAccess busAccess) {
super(busAccess);
}
/**
* Initialize backend modules, add them to event bus.<br>
* Event bus must already be available in the BusAccess.
*/
public abstract void initialize();
/**
* Get graphics module (renderer)
*
* @return graphics module
*/
public abstract RenderModule getRenderer();
}

@ -0,0 +1,32 @@
package mightypork.gamecore.backend;
import mightypork.utils.annotations.DefaultImpl;
import mightypork.utils.eventbus.BusAccess;
import mightypork.utils.eventbus.clients.BusNode;
import mightypork.utils.interfaces.Destroyable;
/**
* Abstract application backend module.
*
* @author MightyPork
*/
public abstract class BackendModule extends BusNode implements Destroyable {
/**
* Create a module with bus access
*
* @param busAccess
*/
public BackendModule(BusAccess busAccess) {
super(busAccess);
}
@Override
@DefaultImpl
public void destroy()
{
}
}

@ -0,0 +1,85 @@
package mightypork.gamecore.backend.lwjgl;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
import mightypork.gamecore.render.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,37 @@
package mightypork.gamecore.backend.lwjgl;
import mightypork.gamecore.backend.Backend;
import mightypork.gamecore.render.RenderModule;
import mightypork.utils.eventbus.BusAccess;
/**
* Game backend using LWJGL
*
* @author MightyPork
*/
public class LwjglBackend extends Backend {
public LwjglBackend(BusAccess busAccess) {
super(busAccess);
}
private LwjglRenderModule renderer;
@Override
public void initialize()
{
addChildClient(renderer = new LwjglRenderModule(this));
}
@Override
public RenderModule getRenderer()
{
return renderer;
}
}

@ -0,0 +1,641 @@
package mightypork.gamecore.backend.lwjgl;
import static org.lwjgl.opengl.GL11.*;
import java.nio.ByteBuffer;
import java.util.Stack;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import mightypork.gamecore.render.Grad;
import mightypork.gamecore.render.RenderModule;
import mightypork.gamecore.render.Screenshot;
import mightypork.gamecore.render.events.DisplayReadyEvent;
import mightypork.gamecore.render.events.ViewportChangeEvent;
import mightypork.gamecore.resources.textures.ITexture;
import mightypork.gamecore.resources.textures.LazyTexture;
import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.utils.eventbus.BusAccess;
import mightypork.utils.logging.Log;
import mightypork.utils.math.color.Color;
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;
/**
* LWJGL rendering module
*
* @author MightyPork
*/
public class LwjglRenderModule extends RenderModule {
public LwjglRenderModule(BusAccess busAccess) {
super(busAccess);
}
/** 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 ITexture 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;
/** 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 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 = 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 = txquad.tx.getWidth01();
final double h = txquad.tx.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(Vect screenSize)
{
// fix projection for changed size
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, screenSize.xi(), screenSize.yi());
glOrtho(0, screenSize.xi(), screenSize.yi(), 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 LazyTexture getLazyTexture(String path)
{
return new SlickLazyTexture(path);
}
@Override
public void destroy()
{
Display.destroy();
}
@Override
public void setTargetFps(int fps)
{
this.targetFps = fps;
}
@Override
public void createDisplay()
{
if (Display.isCreated()) throw new IllegalStateException("Display already created.");
try {
Display.create();
fpsMeter = new FpsMeter();
if (fullscreenSetRequested && fullscreenSetState) {
doToggleFullscreen();
Display.update();
fullscreenSetRequested = false;
}
getEventBus().send(new DisplayReadyEvent());
} catch (final Exception e) {
throw new RuntimeException("Could not initialize display.", e);
}
}
@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();
}
getEventBus().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 boolean isCloseRequested()
{
return Display.isCloseRequested();
}
@Override
public void beginFrame()
{
// handle resize
if (Display.wasResized()) {
getEventBus().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,142 @@
package mightypork.gamecore.backend.lwjgl;
import java.io.IOException;
import mightypork.gamecore.resources.TextureBasedResource;
import mightypork.gamecore.resources.textures.*;
import mightypork.utils.annotations.Alias;
import mightypork.utils.files.FileUtils;
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")
@TextureBasedResource
public class SlickLazyTexture extends LazyTexture {
private org.newdawn.slick.opengl.Texture backingTexture;
private boolean alpha;
private boolean alphal;
/**
* @param resourcePath resource path
*/
public SlickLazyTexture(String resourcePath) {
super(resourcePath);
}
@Override
protected synchronized void loadResource(String path)
{
try {
final String ext = FileUtils.getExtension(path).toUpperCase();
final Texture texture = TextureLoader.getTexture(ext, FileUtils.getResource(path), false, filter.num);
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;
}
@Override
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);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrap.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrap.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter.num);
}
@Override
public int getImageHeight()
{
if (!ensureLoaded()) return 0;
return backingTexture.getImageHeight();
}
@Override
public int getImageWidth()
{
if (!ensureLoaded()) return 0;
return backingTexture.getImageWidth();
}
@Override
public float getHeight01()
{
if (!ensureLoaded()) return 0;
return backingTexture.getHeight();
}
@Override
public float getWidth01()
{
if (!ensureLoaded()) return 0;
return backingTexture.getWidth();
}
@Override
public void destroy()
{
if (!isLoaded()) return;
backingTexture.release();
}
@Override
public int getTextureID()
{
if (!ensureLoaded()) return -1;
return backingTexture.getTextureID();
}
}

@ -0,0 +1,85 @@
package mightypork.gamecore.core.modules;
import mightypork.gamecore.backend.Backend;
import mightypork.gamecore.render.RenderModule;
/**
* Game base class & static subsystem access
*
* @author MightyPork
*/
public class App {
private static App runningInstance;
private static Backend backend;
public App() {
if (App.isInitialized()) throw new IllegalStateException("App already initialized");
// store current instance in static field
App.runningInstance = this;
}
/**
* Create app with given backend.
*
* @param backend backend to use
*/
public void setBackend(Backend backend)
{
// store used backend in static field
App.backend = backend;
// initialize the backend
App.backend.initialize();
}
/**
* Throw error if app is not initialized
*/
protected static void assertInitialized()
{
if (!App.isInitialized()) throw new IllegalStateException("App is not initialized.");
if (backend == null) throw new IllegalStateException("No backend set!");
}
/**
* Check whether the app is initialized (backend assigned).
*
* @return is initialized
*/
public static boolean isInitialized()
{
return runningInstance != null;
}
/**
* Get current backend
*
* @return the backend
*/
public static Backend getBackend()
{
assertInitialized();
return backend;
}
/**
* Get renderer instance from the backend
*
* @return backend
*/
public static RenderModule gfx()
{
assertInitialized();
return backend.getRenderer();
}
}

@ -10,6 +10,7 @@ import java.util.logging.Level;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import mightypork.gamecore.backend.Backend;
import mightypork.gamecore.core.WorkDir; import mightypork.gamecore.core.WorkDir;
import mightypork.gamecore.core.WorkDir.RouteSetup; import mightypork.gamecore.core.WorkDir.RouteSetup;
import mightypork.gamecore.core.config.Config; import mightypork.gamecore.core.config.Config;
@ -45,7 +46,7 @@ import mightypork.utils.math.algo.Move;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler { public abstract class BaseApp extends App implements AppAccess, UncaughtExceptionHandler {
/** /**
* Init options holder class * Init options holder class
@ -176,8 +177,8 @@ public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler {
} }
public BaseApp(File workdir, boolean singleInstance) public BaseApp(File workdir, boolean singleInstance) {
{
WorkDir.init(workdir); WorkDir.init(workdir);
opt.sigleInstance = singleInstance; opt.sigleInstance = singleInstance;
@ -240,7 +241,6 @@ public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler {
org.newdawn.slick.util.Log.setLogSystem(new SlickLogRedirector(log)); org.newdawn.slick.util.Log.setLogSystem(new SlickLogRedirector(log));
writeLogHeader(); writeLogHeader();
Log.i("=== Starting initialization sequence ==="); Log.i("=== Starting initialization sequence ===");
// pre-init hook // pre-init hook
@ -367,7 +367,6 @@ public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler {
}); });
Ion.registerIndirect(254, new IonizerBinary<Move>() { Ion.registerIndirect(254, new IonizerBinary<Move>() {
@Override @Override
@ -478,7 +477,6 @@ public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler {
* Triggered when lock cannot be obtained.<br> * Triggered when lock cannot be obtained.<br>
* App should terminate gracefully. * App should terminate gracefully.
*/ */
protected void onLockError() protected void onLockError()
{ {
Log.e("Could not obtain lock file.\nOnly one instance can run at a time."); Log.e("Could not obtain lock file.\nOnly one instance can run at a time.");

@ -1,9 +1,9 @@
package mightypork.gamecore.gui.components.painters; package mightypork.gamecore.gui.components.painters;
import mightypork.gamecore.core.modules.App;
import mightypork.gamecore.gui.components.BaseComponent; import mightypork.gamecore.gui.components.BaseComponent;
import mightypork.gamecore.gui.components.DynamicWidthComponent; import mightypork.gamecore.gui.components.DynamicWidthComponent;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxQuad; import mightypork.gamecore.resources.textures.TxQuad;
@ -29,7 +29,7 @@ public class ImagePainter extends BaseComponent implements DynamicWidthComponent
@Override @Override
public void renderComponent() public void renderComponent()
{ {
Render.quadTextured(this, txQuad); App.gfx().quad(this, txQuad);
} }

@ -1,8 +1,9 @@
package mightypork.gamecore.gui.components.painters; package mightypork.gamecore.gui.components.painters;
import mightypork.gamecore.core.modules.App;
import mightypork.gamecore.gui.components.BaseComponent; import mightypork.gamecore.gui.components.BaseComponent;
import mightypork.gamecore.render.Render; import mightypork.gamecore.render.Grad;
import mightypork.utils.annotations.FactoryMethod; import mightypork.utils.annotations.FactoryMethod;
import mightypork.utils.math.color.Color; import mightypork.utils.math.color.Color;
@ -27,10 +28,7 @@ public class QuadPainter extends BaseComponent {
return new QuadPainter(colorTop, colorTop, colorBottom, colorBottom); return new QuadPainter(colorTop, colorTop, colorBottom, colorBottom);
} }
private final Color colorHMinVMin; private final Grad grad;
private final Color colorHMaxVMin;
private final Color colorHMaxVMax;
private final Color colorHMinVMax;
/** /**
@ -38,35 +36,27 @@ public class QuadPainter extends BaseComponent {
* *
* @param color * @param color
*/ */
public QuadPainter(Color color) public QuadPainter(Color color) {
{ this.grad = new Grad(color, color, color, color);
this.colorHMinVMin = color;
this.colorHMaxVMin = color;
this.colorHMaxVMax = color;
this.colorHMinVMax = color;
} }
/** /**
* Painter with coloured vertices. * Painter with coloured vertices.
* *
* @param colorHMinVMin * @param leftTop
* @param colorHMaxVMin * @param rightTop
* @param colorHMaxVMax * @param leftBottom
* @param colorHMinVMax * @param rightBottom
*/ */
public QuadPainter(Color colorHMinVMin, Color colorHMaxVMin, Color colorHMaxVMax, Color colorHMinVMax) public QuadPainter(Color leftTop, Color rightTop, Color leftBottom, Color rightBottom) {
{ this.grad = new Grad(leftTop, rightTop, rightBottom, leftBottom);
this.colorHMinVMin = colorHMinVMin;
this.colorHMaxVMin = colorHMaxVMin;
this.colorHMaxVMax = colorHMaxVMax;
this.colorHMinVMax = colorHMinVMax;
} }
@Override @Override
public void renderComponent() public void renderComponent()
{ {
Render.quadColor(getRect(), colorHMinVMin, colorHMaxVMin, colorHMaxVMax, colorHMinVMax); App.gfx().quad(getRect(), grad);
} }
} }

@ -1,10 +1,10 @@
package mightypork.gamecore.gui.components.painters; package mightypork.gamecore.gui.components.painters;
import mightypork.gamecore.core.modules.App;
import mightypork.gamecore.gui.AlignX; import mightypork.gamecore.gui.AlignX;
import mightypork.gamecore.gui.components.BaseComponent; import mightypork.gamecore.gui.components.BaseComponent;
import mightypork.gamecore.gui.components.DynamicWidthComponent; import mightypork.gamecore.gui.components.DynamicWidthComponent;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.fonts.FontRenderer; import mightypork.gamecore.resources.fonts.FontRenderer;
import mightypork.gamecore.resources.fonts.GLFont; import mightypork.gamecore.resources.fonts.GLFont;
import mightypork.utils.math.color.Color; import mightypork.utils.math.color.Color;
@ -39,38 +39,32 @@ public class TextPainter extends BaseComponent implements DynamicWidthComponent
/** /**
* @param font font to use * @param font font to use
*/ */
public TextPainter(GLFont font) public TextPainter(GLFont font) {
{
this(font, AlignX.LEFT, RGB.WHITE); this(font, AlignX.LEFT, RGB.WHITE);
} }
public TextPainter(GLFont font, Color color, String text) public TextPainter(GLFont font, Color color, String text) {
{
this(font, AlignX.LEFT, color, new StringWrapper(text)); this(font, AlignX.LEFT, color, new StringWrapper(text));
} }
public TextPainter(GLFont font, Color color, StringProvider text) public TextPainter(GLFont font, Color color, StringProvider text) {
{
this(font, AlignX.LEFT, color, text); this(font, AlignX.LEFT, color, text);
} }
public TextPainter(GLFont font, Color color) public TextPainter(GLFont font, Color color) {
{
this(font, AlignX.LEFT, color, (StringProvider) null); this(font, AlignX.LEFT, color, (StringProvider) null);
} }
public TextPainter(GLFont font, AlignX align, Color color, String text) public TextPainter(GLFont font, AlignX align, Color color, String text) {
{
this(font, align, color, new StringWrapper(text)); this(font, align, color, new StringWrapper(text));
} }
public TextPainter(GLFont font, AlignX align, Color color, StringProvider text) public TextPainter(GLFont font, AlignX align, Color color, StringProvider text) {
{
this.font = new FontRenderer(font); this.font = new FontRenderer(font);
this.color = color; this.color = color;
this.align = align; this.align = align;
@ -78,8 +72,7 @@ public class TextPainter extends BaseComponent implements DynamicWidthComponent
} }
public TextPainter(GLFont font, AlignX align, Color color) public TextPainter(GLFont font, AlignX align, Color color) {
{
this(font, align, color, (StringProvider) null); this(font, align, color, (StringProvider) null);
} }
@ -102,7 +95,7 @@ public class TextPainter extends BaseComponent implements DynamicWidthComponent
final Rect r = (shadow ? rect.move(shadowOffset.neg()) : rect).round(); final Rect r = (shadow ? rect.move(shadowOffset.neg()) : rect).round();
font.draw(str, r, align, color); font.draw(str, r, align, color);
if (DEBUG_FONT_RENDER) Render.quadColor(r, RGB.PINK.withAlpha(0.4)); if (DEBUG_FONT_RENDER) App.gfx().quad(r, RGB.PINK.withAlpha(0.4));
} }

@ -1,6 +1,7 @@
package mightypork.gamecore.gui.screens; package mightypork.gamecore.gui.screens;
import mightypork.gamecore.core.modules.App;
import mightypork.gamecore.core.modules.AppAccess; import mightypork.gamecore.core.modules.AppAccess;
import mightypork.gamecore.core.modules.AppSubModule; import mightypork.gamecore.core.modules.AppSubModule;
import mightypork.gamecore.gui.events.LayoutChangeEvent; import mightypork.gamecore.gui.events.LayoutChangeEvent;
@ -10,7 +11,6 @@ import mightypork.gamecore.input.KeyBindingPool;
import mightypork.gamecore.input.KeyStroke; import mightypork.gamecore.input.KeyStroke;
import mightypork.gamecore.input.KeyStroke.Edge; import mightypork.gamecore.input.KeyStroke.Edge;
import mightypork.gamecore.render.DisplaySystem; import mightypork.gamecore.render.DisplaySystem;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.render.Renderable; import mightypork.gamecore.render.Renderable;
import mightypork.utils.annotations.DefaultImpl; import mightypork.utils.annotations.DefaultImpl;
import mightypork.utils.math.constraints.rect.Rect; import mightypork.utils.math.constraints.rect.Rect;
@ -33,8 +33,7 @@ public abstract class Screen extends AppSubModule implements Renderable, RectBou
/** /**
* @param app app access * @param app app access
*/ */
public Screen(AppAccess app) public Screen(AppAccess app) {
{
super(app); super(app);
// disable events initially // disable events initially
@ -123,14 +122,14 @@ public abstract class Screen extends AppSubModule implements Renderable, RectBou
if (!isActive()) return; if (!isActive()) return;
if (needSetupViewport) { if (needSetupViewport) {
Render.setupOrtho(DisplaySystem.getSize()); App.gfx().setupProjection(DisplaySystem.getSize());
} }
Render.pushState(); App.gfx().pushState();
renderScreen(); renderScreen();
Render.popState(); App.gfx().popState();
} }

@ -5,6 +5,7 @@ import static org.lwjgl.opengl.GL11.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import mightypork.gamecore.backend.lwjgl.AwtScreenshot;
import mightypork.gamecore.core.modules.AppAccess; import mightypork.gamecore.core.modules.AppAccess;
import mightypork.gamecore.core.modules.AppModule; import mightypork.gamecore.core.modules.AppModule;
import mightypork.gamecore.render.events.DisplayReadyEvent; import mightypork.gamecore.render.events.DisplayReadyEvent;
@ -26,6 +27,7 @@ import org.lwjgl.opengl.DisplayMode;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@Deprecated
public class DisplaySystem extends AppModule implements RectBound { public class DisplaySystem extends AppModule implements RectBound {
private DisplayMode windowDisplayMode; private DisplayMode windowDisplayMode;
@ -161,7 +163,7 @@ public class DisplaySystem extends AppModule implements RectBound {
* *
* @return screenshot object * @return screenshot object
*/ */
public static Screenshot prepareScreenshot() public static AwtScreenshot prepareScreenshot()
{ {
glReadBuffer(GL_FRONT); glReadBuffer(GL_FRONT);
final int width = Display.getWidth(); final int width = Display.getWidth();
@ -170,7 +172,7 @@ public class DisplaySystem extends AppModule implements RectBound {
final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp); final ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
final Screenshot sc = new Screenshot(width, height, bpp, buffer); final AwtScreenshot sc = new AwtScreenshot(width, height, bpp, buffer);
return sc; return sc;
} }

@ -0,0 +1,31 @@
package mightypork.gamecore.render;
import mightypork.utils.math.color.Color;
/**
* Linear gradient (each vertex can have different color)
*
* @author MightyPork
*/
public class Grad {
public final Color leftTop, rightTop, rightBottom, leftBottom;
/**
* Create a gradient
*
* @param leftTop left top color
* @param rightTop right top color
* @param rightBottom right bottom color
* @param leftBottom left bottom color
*/
public Grad(Color leftTop, Color rightTop, Color rightBottom, Color leftBottom) {
this.leftTop = leftTop;
this.rightTop = rightTop;
this.rightBottom = rightBottom;
this.leftBottom = leftBottom;
}
}

@ -0,0 +1,17 @@
package mightypork.gamecore.render;
import mightypork.utils.math.color.Color;
/**
* Linear horizontal gradient
*
* @author MightyPork
*/
public class GradH extends Grad {
public GradH(Color left, Color right) {
super(left, right, right, left);
}
}

@ -0,0 +1,17 @@
package mightypork.gamecore.render;
import mightypork.utils.math.color.Color;
/**
* Linear vertical gradient
*
* @author MightyPork
*/
public class GradV extends Grad {
public GradV(Color top, Color bottom) {
super(top, top, bottom, bottom);
}
}

@ -6,7 +6,7 @@ import static org.lwjgl.opengl.GL11.*;
import java.io.IOException; import java.io.IOException;
import mightypork.gamecore.resources.textures.FilterMode; import mightypork.gamecore.resources.textures.FilterMode;
import mightypork.gamecore.resources.textures.GLTexture; import mightypork.gamecore.resources.textures.ITexture;
import mightypork.gamecore.resources.textures.TxQuad; import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.utils.files.FileUtils; import mightypork.utils.files.FileUtils;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
@ -27,6 +27,7 @@ import org.newdawn.slick.opengl.TextureLoader;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@Deprecated
public class Render { public class Render {
public static final VectConst AXIS_X = Vect.make(1, 0, 0); public static final VectConst AXIS_X = Vect.make(1, 0, 0);
@ -525,7 +526,7 @@ public class Render {
} }
public static void enterBatchTexturedQuadMode(GLTexture texture) public static void enterBatchTexturedQuadMode(ITexture texture)
{ {
texture.bind(); texture.bind();
glBegin(GL11.GL_QUADS); glBegin(GL11.GL_QUADS);

@ -0,0 +1,420 @@
package mightypork.gamecore.render;
import mightypork.gamecore.backend.BackendModule;
import mightypork.gamecore.resources.textures.LazyTexture;
import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.utils.eventbus.BusAccess;
import mightypork.utils.math.color.Color;
import mightypork.utils.math.constraints.rect.Rect;
import mightypork.utils.math.constraints.vect.Vect;
import mightypork.utils.math.constraints.vect.VectConst;
import mightypork.utils.math.timing.FpsMeter;
/**
* Render and display backend module.<br>
* This module takes care of setting and getting screen size and parameters,
* drawing on screen and timing render frames.
*
* @author MightyPork
*/
public abstract class RenderModule extends BackendModule {
public RenderModule(BusAccess busAccess) {
super(busAccess);
}
protected static final VectConst AXIS_X = Vect.make(1, 0, 0);
protected static final VectConst AXIS_Y = Vect.make(0, 1, 0);
protected static final VectConst AXIS_Z = Vect.make(0, 0, 1);
/**
* Set drawing color
*
* @param color color
*/
public abstract void setColor(Color color);
/**
* Set drawing color, adjust alpha
*
* @param color color
* @param alpha alpha multiplier
*/
public abstract void setColor(Color color, double alpha);
/**
* Translate by x, y
*
* @param x x offset
* @param y y offset
*/
public abstract void translate(double x, double y);
/**
* Translate by x, y, z
*
* @param x x offset
* @param y y offset
* @param z z offset
*/
public abstract void translate(double x, double y, double z);
/**
* Translate by offset vector
*
* @param offset offset coordinate
*/
public abstract void translate(Vect offset);
/**
* Translate by offset vector, ignore Z
*
* @param offset offset coordinate
*/
public abstract void translateXY(Vect offset);
/**
* Set scale for translations and coordinates
*
* @param x x scale
* @param y y scale
*/
public abstract void scale(double x, double y);
/**
* Set scale for translations and coordinates
*
* @param x x scale
* @param y y scale
* @param z z scale
*/
public abstract void scale(double x, double y, double z);
/**
* Set scale for translations and coordinates
*
* @param scale vector
*/
public abstract void scale(Vect scale);
/**
* Set scale for translations and coordinates (same value for X and Y scale)
*
* @param scale scaling factor
*/
public abstract void scaleXY(double scale);
/**
* Set X scale for translations and coordinates
*
* @param scale scaling factor
*/
public abstract void scaleX(double scale);
/**
* Set Y scale for translations and coordinates
*
* @param scale scaling factor
*/
public abstract void scaleY(double scale);
/**
* Set Z scale for translations and coordinates
*
* @param scale scaling factor
*/
public abstract void scaleZ(double scale);
/**
* Rotate coordinate system around X axis
*
* @param angle rotation (in degrees)
*/
public abstract void rotateX(double angle);
/**
* Rotate coordinate system around Y axis
*
* @param angle rotation (in degrees)
*/
public abstract void rotateY(double angle);
/**
* Rotate coordinate system around Z axis
*
* @param angle rotation (in degrees)
*/
public abstract void rotateZ(double angle);
/**
* Rotate coordinate system around given axis
*
* @param angle rotation angle
* @param axis rotation axis (unit vector)
*/
public abstract void rotate(double angle, Vect axis);
/**
* Store render state on stack<br>
* This includes pushGeometry and pushColor.
*/
public abstract void pushState();
/**
* Restore state from stack (must be pushed first)<br>
* This includes popColor and popGeometry.
*/
public abstract void popState();
/**
* Store current rotation and translation on stack
*/
public abstract void pushGeometry();
/**
* Restore rotation and translation from stack
*/
public abstract void popGeometry();
/**
* Store color on stack (so it can later be restored)
*/
public abstract void pushColor();
/**
* Restore color from stack (must be pushed first)
*/
public abstract void popColor();
/**
* Render 2D quad with currently set color
*
* @param rect drawn rect
*/
public abstract void quad(Rect rect);
/**
* Render 2D quad with given color.<br>
* This may change current drawing color.
*
* @param rect rectangle
* @param color draw color
*/
public abstract void quad(Rect rect, Color color);
/**
* Render 2D quad with gradient.<br>
* This may change current drawing color.
*
* @param rect rectangle
* @param grad gradient
*/
public abstract void quad(Rect rect, Grad grad);
/**
* Render textured quad with current color
*
* @param rect rectangle to draw
* @param txquad texture quad
*/
public abstract void quad(Rect rect, TxQuad txquad);
/**
* Render textured quad with given color
*
* @param rect rectangle to draw
* @param txquad texture instance
* @param color color tint
*/
public abstract void quad(Rect rect, TxQuad txquad, Color color);
/**
* Setup projection for 2D graphics
*
* @param screenSize current viewport size
*/
public abstract void setupProjection(Vect screenSize);
/**
* Get backend-flavoured lazy texture
*
* @param path path to texture
* @return the lazy texture
*/
public abstract LazyTexture getLazyTexture(String path);
/**
* Set target fps (for syncing in endFrame() call).<br>
* With vsync enabled, the target fps may not be met.
*
* @param fps requested fps
*/
public abstract void setTargetFps(int fps);
/**
* Create a main window
*/
public abstract void createDisplay();
/**
* Set fullscreen
*
* @param fs true for fullscreen
*/
public abstract void setFullscreen(boolean fs);
/**
* Request fullscreen toggle (eg. at the end of render frame)
*/
public abstract void switchFullscreen();
/**
* Get fullscreen state
*
* @return is fullscreen
*/
public abstract boolean isFullscreen();
/**
* Take screenshot (expensive processing should be done in separate thread
* when screenshot is saved).
*
* @return screenshot object
*/
public abstract Screenshot takeScreenshot();
/**
* FIXME This should be moved to inout module
*
* @return true if close was requested recently (i.e. click on cross)
*/
public abstract boolean isCloseRequested();
/**
* Start a render frame - clear buffers, prepare rendering context etc.
*/
public abstract void beginFrame();
/**
* End a render frame: flip buffers, sync to fps...
*/
public abstract void endFrame();
/**
* Set display dimensions
*
* @param width display width (pixels)
* @param height display height (pixels)
*/
public abstract void setSize(int width, int height);
/**
* Set titlebar text
*
* @param title titlebar text
*/
public abstract void setTitle(String title);
/**
* Enable or disable VSync
*
* @param vsync true for vsync enabled
*/
public abstract void setVSync(boolean vsync);
/**
* Set window resizable / fixed
*
* @param resizable true for resizable
*/
public abstract void setResizable(boolean resizable);
/**
* Get screen rect. Should always return the same Vect instance.
*
* @return the rect
*/
public abstract Rect getRect();
/**
* Get current FPS (eg. measured by a {@link FpsMeter})
*
* @return current FPS
*/
public abstract long getFps();
/**
* Get screen center. Should always return the same Vect instance.
*
* @return screen center.
*/
public abstract Vect getCenter();
/**
* @return screen width
*/
public abstract int getWidth();
/**
* @return screen height
*/
public abstract int getHeight();
/**
* Get screen size. Should always return the same Vect instance.
*
* @return size
*/
public abstract Vect getSize();
}

@ -1,81 +1,33 @@
package mightypork.gamecore.render; package mightypork.gamecore.render;
import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer;
import javax.imageio.ImageIO;
/** /**
* Screenshot object, can be used to extract image or write to file.<br> * <p>
* Screenshot, once taken, can be safely processed in separate thread. * Screenshot object, can be used to save image to file.
* </p>
* <p>
* Screenshot typically takes a byte buffer and converts it to image before
* saving to file. This image can be cached to speed up repeated saving.
* </p>
* <p>
* Once created (passing byte buffer in constructor), the Screenshot should be
* safe to process (call the save() method) in separate thread.
* </p>
* *
* @author Ondřej Hruška (MightyPork) * @author MightyPork
*/ */
public class Screenshot { public interface 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 Screenshot(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> * Process byte buffer and write image to a file.<br>
* Cached value is used if any. * Image can be cached for future save.
* *
* @param file target file * @param file target file
* @throws IOException on error writing to file * @throws IOException on error writing to file
*/ */
public void save(File file) throws IOException void save(File file) throws IOException;
{
file.getParentFile().mkdirs();
ImageIO.write(getImage(), "PNG", file);
}
} }

@ -4,22 +4,30 @@ package mightypork.gamecore.render;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import mightypork.gamecore.backend.lwjgl.AwtScreenshot;
import mightypork.gamecore.core.WorkDir; import mightypork.gamecore.core.WorkDir;
import mightypork.gamecore.core.modules.App;
import mightypork.utils.Support; import mightypork.utils.Support;
import mightypork.utils.logging.Log; import mightypork.utils.logging.Log;
import org.newdawn.slick.opengl.GLUtils; import org.newdawn.slick.opengl.GLUtils;
/**
* Task that takes screenshot and asynchronously saves it to a file.<br>
* Can be run in a separate thread, but must be instantiated in the render
* thread.
*
* @author MightyPork
*/
public class TaskTakeScreenshot implements Runnable { public class TaskTakeScreenshot implements Runnable {
private final Screenshot scr; private final Screenshot scr;
public TaskTakeScreenshot() public TaskTakeScreenshot() {
{
GLUtils.checkGLContext(); GLUtils.checkGLContext();
scr = DisplaySystem.prepareScreenshot(); scr = App.gfx().takeScreenshot();
} }

@ -7,7 +7,7 @@ import mightypork.gamecore.resources.audio.players.EffectPlayer;
import mightypork.gamecore.resources.audio.players.LoopPlayer; import mightypork.gamecore.resources.audio.players.LoopPlayer;
import mightypork.gamecore.resources.fonts.FontRegistry; import mightypork.gamecore.resources.fonts.FontRegistry;
import mightypork.gamecore.resources.fonts.GLFont; import mightypork.gamecore.resources.fonts.GLFont;
import mightypork.gamecore.resources.textures.GLTexture; import mightypork.gamecore.resources.textures.ITexture;
import mightypork.gamecore.resources.textures.TextureRegistry; import mightypork.gamecore.resources.textures.TextureRegistry;
import mightypork.gamecore.resources.textures.TxQuad; import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.gamecore.resources.textures.TxSheet; import mightypork.gamecore.resources.textures.TxSheet;
@ -43,7 +43,7 @@ public final class Res {
} }
public static GLTexture getTexture(String key) public static ITexture getTexture(String key)
{ {
return textures.getTexture(key); return textures.getTexture(key);
} }

@ -1,8 +1,8 @@
package mightypork.gamecore.resources.fonts; package mightypork.gamecore.resources.fonts;
import mightypork.gamecore.core.modules.App;
import mightypork.gamecore.gui.AlignX; import mightypork.gamecore.gui.AlignX;
import mightypork.gamecore.render.Render;
import mightypork.utils.math.color.Color; import mightypork.utils.math.color.Color;
import mightypork.utils.math.color.pal.RGB; import mightypork.utils.math.color.pal.RGB;
import mightypork.utils.math.constraints.rect.Rect; import mightypork.utils.math.constraints.rect.Rect;
@ -105,16 +105,16 @@ public class FontRenderer {
*/ */
public void draw(String text, Vect pos, double height, Color color) public void draw(String text, Vect pos, double height, Color color)
{ {
Render.pushMatrix(); App.gfx().pushGeometry();
final double sc = getScale(height); final double sc = getScale(height);
Render.translate(pos.x(), pos.y()); App.gfx().translate(pos.x(), pos.y());
Render.scaleXY(sc); App.gfx().scaleXY(sc);
font.draw(text, color); font.draw(text, color);
Render.popMatrix(); App.gfx().popGeometry();
} }

@ -379,8 +379,6 @@ public class TextureBackedFont implements GLFont {
{ {
GLUtils.checkGLContext(); GLUtils.checkGLContext();
LazyTexture.lastBind = null; // needs rebind.
// PUSH // PUSH
glPushAttrib(GL_ENABLE_BIT); glPushAttrib(GL_ENABLE_BIT);

@ -10,7 +10,7 @@ import mightypork.utils.math.constraints.rect.Rect;
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
public interface GLTexture extends Destroyable { public interface ITexture extends Destroyable {
/** /**
* Set filter for scaling * Set filter for scaling

@ -1,38 +1,29 @@
package mightypork.gamecore.resources.textures; package mightypork.gamecore.resources.textures;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.BaseLazyResource; import mightypork.gamecore.resources.BaseLazyResource;
import mightypork.gamecore.resources.TextureBasedResource; import mightypork.gamecore.resources.TextureBasedResource;
import mightypork.utils.annotations.Alias; import mightypork.utils.annotations.Alias;
import mightypork.utils.math.constraints.rect.Rect; import mightypork.utils.math.constraints.rect.Rect;
import org.lwjgl.opengl.GL11;
/** /**
* Deferred texture * Deferred texture (to be extended by backend texture)
* *
* @author Ondřej Hruška (MightyPork) * @author Ondřej Hruška (MightyPork)
*/ */
@Alias(name = "Texture") @Alias(name = "Texture")
@TextureBasedResource @TextureBasedResource
public class LazyTexture extends BaseLazyResource implements GLTexture { public abstract class LazyTexture extends BaseLazyResource implements ITexture {
public static LazyTexture lastBind = null;
private org.newdawn.slick.opengl.Texture backingTexture; protected FilterMode filter = FilterMode.NEAREST;
private FilterMode filter = FilterMode.NEAREST; protected WrapMode wrap = WrapMode.CLAMP;
private WrapMode wrap = WrapMode.CLAMP;
private boolean alpha;
private boolean alphal;
/** /**
* @param resourcePath resource path * @param resourcePath resource path
*/ */
public LazyTexture(String resourcePath) public LazyTexture(String resourcePath) {
{
super(resourcePath); super(resourcePath);
} }
@ -44,105 +35,6 @@ public class LazyTexture extends BaseLazyResource implements GLTexture {
} }
@Override
protected synchronized void loadResource(String path)
{
backingTexture = Render.loadSlickTexture(path, filter);
}
@Override
public boolean hasAlpha()
{
if (!ensureLoaded()) return false;
if (!alphal) {
alphal = true;
alpha = backingTexture.hasAlpha();
}
return alpha;
}
@Override
public void bind()
{
if (!ensureLoaded()) return;
GL11.glEnable(GL11.GL_TEXTURE_2D);
if (lastBind != this) {
lastBind = this;
GL11.glBindTexture(GL11.GL_TEXTURE_2D, getTextureID());
GL11.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, wrap.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, wrap.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter.num);
GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter.num);
}
}
@Override
public int getImageHeight()
{
if (!ensureLoaded()) return 0;
return backingTexture.getImageHeight();
}
@Override
public int getImageWidth()
{
if (!ensureLoaded()) return 0;
return backingTexture.getImageWidth();
}
@Override
public float getHeight01()
{
if (!ensureLoaded()) return 0;
return backingTexture.getHeight();
}
@Override
public float getWidth01()
{
if (!ensureLoaded()) return 0;
return backingTexture.getWidth();
}
@Override
public void destroy()
{
if (!isLoaded()) return;
backingTexture.release();
}
@Override
public int getTextureID()
{
if (!ensureLoaded()) return -1;
return backingTexture.getTextureID();
}
@Override @Override
public void setFilter(FilterMode filterMin) public void setFilter(FilterMode filterMin)
{ {

@ -11,14 +11,14 @@ import mightypork.utils.math.constraints.rect.Rect;
*/ */
public class QuadGrid { public class QuadGrid {
private final GLTexture tx; private final ITexture tx;
private final int txHeight; private final int txHeight;
private final int txWidth; private final int txWidth;
private final double tileW; private final double tileW;
private final double tileH; private final double tileH;
public QuadGrid(GLTexture tx, int tilesX, int tilesY) public QuadGrid(ITexture tx, int tilesX, int tilesY)
{ {
this.tx = tx; this.tx = tx;
this.txWidth = tilesX; this.txWidth = tilesX;

@ -4,6 +4,7 @@ package mightypork.gamecore.resources.textures;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import mightypork.gamecore.core.modules.App;
import mightypork.gamecore.core.modules.AppAccess; import mightypork.gamecore.core.modules.AppAccess;
import mightypork.gamecore.core.modules.AppAccessAdapter; import mightypork.gamecore.core.modules.AppAccessAdapter;
import mightypork.gamecore.resources.ResourceLoadRequest; import mightypork.gamecore.resources.ResourceLoadRequest;
@ -19,7 +20,7 @@ import mightypork.utils.math.constraints.rect.Rect;
*/ */
public class TextureRegistry extends AppAccessAdapter { public class TextureRegistry extends AppAccessAdapter {
private final Map<String, GLTexture> textures = new HashMap<>(); private final Map<String, ITexture> textures = new HashMap<>();
private final Map<String, TxSheet> sheets = new HashMap<>(); private final Map<String, TxSheet> sheets = new HashMap<>();
@ -41,7 +42,7 @@ public class TextureRegistry extends AppAccessAdapter {
* @param wrap * @param wrap
* @return texture reference * @return texture reference
*/ */
public GLTexture addTexture(String resourcePath, FilterMode filter, WrapMode wrap) public ITexture addTexture(String resourcePath, FilterMode filter, WrapMode wrap)
{ {
return addTexture(resourcePath, resourcePath, filter, wrap); return addTexture(resourcePath, resourcePath, filter, wrap);
} }
@ -57,11 +58,11 @@ public class TextureRegistry extends AppAccessAdapter {
* @param wrap * @param wrap
* @return texture reference * @return texture reference
*/ */
public GLTexture addTexture(String key, String resourcePath, FilterMode filter, WrapMode wrap) public ITexture addTexture(String key, String resourcePath, FilterMode filter, WrapMode wrap)
{ {
if (key != null) if (textures.containsKey(key)) throw new KeyAlreadyExistsException(); if (key != null) if (textures.containsKey(key)) throw new KeyAlreadyExistsException();
final LazyTexture texture = new LazyTexture(resourcePath); final LazyTexture texture = App.gfx().getLazyTexture(resourcePath);
texture.setFilter(filter); texture.setFilter(filter);
texture.setWrap(wrap); texture.setWrap(wrap);
@ -118,14 +119,14 @@ public class TextureRegistry extends AppAccessAdapter {
/** /**
* Get a loaded {@link GLTexture} * Get a loaded {@link ITexture}
* *
* @param key texture key * @param key texture key
* @return the texture * @return the texture
*/ */
public GLTexture getTexture(String key) public ITexture getTexture(String key)
{ {
final GLTexture tx = textures.get(key); final ITexture tx = textures.get(key);
if (tx == null) throw new RuntimeException("There's no texture called \"" + key + "\"!"); if (tx == null) throw new RuntimeException("There's no texture called \"" + key + "\"!");

@ -13,7 +13,7 @@ import mightypork.utils.math.constraints.rect.RectConst;
public class TxQuad { public class TxQuad {
/** The texture */ /** The texture */
public final GLTexture tx; public final ITexture tx;
/** Coords in texture (0-1) */ /** Coords in texture (0-1) */
public final RectConst uvs; public final RectConst uvs;
@ -31,7 +31,7 @@ public class TxQuad {
* @param heightPx area height (0-1) * @param heightPx area height (0-1)
* @return new TxQuad * @return new TxQuad
*/ */
public static TxQuad fromSizePx(GLTexture tx, double xPx, double yPx, double widthPx, double heightPx) public static TxQuad fromSizePx(ITexture tx, double xPx, double yPx, double widthPx, double heightPx)
{ {
final double w = tx.getImageWidth(); final double w = tx.getImageWidth();
final double h = tx.getImageHeight(); final double h = tx.getImageHeight();
@ -50,7 +50,7 @@ public class TxQuad {
* @param height area height (0-1) * @param height area height (0-1)
* @return new TxQuad * @return new TxQuad
*/ */
public static TxQuad fromSize(GLTexture tx, double x1, double y1, double width, double height) public static TxQuad fromSize(ITexture tx, double x1, double y1, double width, double height)
{ {
return new TxQuad(tx, x1, y1, x1 + width, y1 + height); return new TxQuad(tx, x1, y1, x1 + width, y1 + height);
} }
@ -65,7 +65,7 @@ public class TxQuad {
* @param x2 right bottom X (0-1) * @param x2 right bottom X (0-1)
* @param y2 right bottom Y (0-1) * @param y2 right bottom Y (0-1)
*/ */
public TxQuad(GLTexture tx, double x1, double y1, double x2, double y2) public TxQuad(ITexture tx, double x1, double y1, double x2, double y2)
{ {
this(tx, Rect.make(x1, y1, x2, y2)); this(tx, Rect.make(x1, y1, x2, y2));
} }
@ -75,7 +75,7 @@ public class TxQuad {
* @param tx Texture * @param tx Texture
* @param uvs Rect of texture UVs (0-1); will be frozen. * @param uvs Rect of texture UVs (0-1); will be frozen.
*/ */
public TxQuad(GLTexture tx, Rect uvs) public TxQuad(ITexture tx, Rect uvs)
{ {
this.tx = tx; this.tx = tx;
this.uvs = uvs.freeze(); this.uvs = uvs.freeze();

@ -3,6 +3,7 @@ package mightypork.rogue;
import java.io.File; import java.io.File;
import mightypork.gamecore.backend.lwjgl.LwjglBackend;
import mightypork.gamecore.core.config.Config; import mightypork.gamecore.core.config.Config;
import mightypork.gamecore.core.events.MainLoopRequest; import mightypork.gamecore.core.events.MainLoopRequest;
import mightypork.gamecore.core.events.ShudownRequest; import mightypork.gamecore.core.events.ShudownRequest;
@ -45,6 +46,8 @@ public final class RogueApp extends BaseApp implements ViewportChangeListener, S
{ {
super(workdir, singleInstance); super(workdir, singleInstance);
setBackend(new LwjglBackend(this));
AppInitOptions opt = getInitOptions(); AppInitOptions opt = getInitOptions();
opt.addRoutes(new RogueRoutes()); opt.addRoutes(new RogueRoutes());

@ -7,7 +7,7 @@ import mightypork.gamecore.resources.fonts.FontRegistry;
import mightypork.gamecore.resources.fonts.Glyphs; import mightypork.gamecore.resources.fonts.Glyphs;
import mightypork.gamecore.resources.fonts.impl.LazyFont; import mightypork.gamecore.resources.fonts.impl.LazyFont;
import mightypork.gamecore.resources.textures.FilterMode; import mightypork.gamecore.resources.textures.FilterMode;
import mightypork.gamecore.resources.textures.GLTexture; import mightypork.gamecore.resources.textures.ITexture;
import mightypork.gamecore.resources.textures.QuadGrid; import mightypork.gamecore.resources.textures.QuadGrid;
import mightypork.gamecore.resources.textures.TextureRegistry; import mightypork.gamecore.resources.textures.TextureRegistry;
import mightypork.gamecore.resources.textures.WrapMode; import mightypork.gamecore.resources.textures.WrapMode;
@ -76,7 +76,7 @@ public class RogueResources implements ResourceSetup {
@Override @Override
public void addTextures(TextureRegistry textures) public void addTextures(TextureRegistry textures)
{ {
GLTexture texture; ITexture texture;
QuadGrid grid; QuadGrid grid;
// gui // gui

Loading…
Cancel
Save