parent
7024fb4402
commit
ec64ad21fc
@ -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(); |
||||||
|
} |
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
@ -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); |
|
||||||
} |
|
||||||
} |
} |
||||||
|
Loading…
Reference in new issue