Adjusted for the web port
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Shattered Pixel Dungeon
|
# Shattered Pixel Dungeon
|
||||||
|
|
||||||
|
This is a fork of Shattered Pixel Dungeon that can also compile for the web. Inspired by [this](https://github.com/gnojus/pixel-dungeon-gdx) web port for the original Pixel Dungeon.
|
||||||
|
|
||||||
|
## Libraries Used
|
||||||
|
This project uses the following libraries:
|
||||||
|
- [TeaVM](https://teavm.org), licensed under the Apache License, Version 2.0.
|
||||||
|
- [gdx-teavm](https://github.com/xpenatan/gdx-teavm), licensed under the Apache License, Version 2.0.
|
||||||
|
|
||||||
[Shattered Pixel Dungeon](https://shatteredpixel.com/shatteredpd/) is an open-source traditional roguelike dungeon crawler with randomized levels and enemies, and hundreds of items to collect and use. It's based on the [source code of Pixel Dungeon](https://github.com/00-Evan/pixel-dungeon-gradle), by [Watabou](https://www.watabou.ru).
|
[Shattered Pixel Dungeon](https://shatteredpixel.com/shatteredpd/) is an open-source traditional roguelike dungeon crawler with randomized levels and enemies, and hundreds of items to collect and use. It's based on the [source code of Pixel Dungeon](https://github.com/00-Evan/pixel-dungeon-gradle), by [Watabou](https://www.watabou.ru).
|
||||||
|
|
||||||
Shattered Pixel Dungeon currently compiles for Android, iOS, and Desktop platforms. You can find official releases of the game on:
|
Shattered Pixel Dungeon currently compiles for Android, iOS, and Desktop platforms. You can find official releases of the game on:
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ package com.watabou.glwrap;
|
|||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
|
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
|
import com.watabou.utils.DeviceCompat;
|
||||||
|
|
||||||
public class Attribute {
|
public class Attribute {
|
||||||
|
|
||||||
@@ -37,19 +39,21 @@ public class Attribute {
|
|||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final GL20 activeGL = (DeviceCompat.isWeb()) ? Gdx.gl30 : Gdx.gl;
|
||||||
|
|
||||||
public void enable() {
|
public void enable() {
|
||||||
Gdx.gl.glEnableVertexAttribArray( location );
|
activeGL.glEnableVertexAttribArray( location );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disable() {
|
public void disable() {
|
||||||
Gdx.gl.glDisableVertexAttribArray( location );
|
activeGL.glDisableVertexAttribArray( location );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void vertexPointer( int size, int stride, FloatBuffer ptr ) {
|
public void vertexPointer( int size, int stride, FloatBuffer ptr ) {
|
||||||
Gdx.gl.glVertexAttribPointer( location, size, Gdx.gl.GL_FLOAT, false, stride * 4, ptr );
|
activeGL.glVertexAttribPointer( location, size, GL20.GL_FLOAT, false, stride * 4, ptr );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void vertexBuffer( int size, int stride, int offset) {
|
public void vertexBuffer( int size, int stride, int offset) {
|
||||||
Gdx.gl.glVertexAttribPointer(location, size, Gdx.gl.GL_FLOAT, false, stride * 4, offset * 4);
|
activeGL.glVertexAttribPointer( location, size, GL20.GL_FLOAT, false, stride * 4, offset * 4 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
package com.watabou.noosa;
|
package com.watabou.noosa;
|
||||||
|
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
|
import com.watabou.utils.DeviceCompat;
|
||||||
import com.watabou.glscripts.Script;
|
import com.watabou.glscripts.Script;
|
||||||
import com.watabou.glwrap.Attribute;
|
import com.watabou.glwrap.Attribute;
|
||||||
import com.watabou.glwrap.Quad;
|
import com.watabou.glwrap.Quad;
|
||||||
@@ -34,6 +36,8 @@ import java.nio.ShortBuffer;
|
|||||||
|
|
||||||
public class NoosaScript extends Script {
|
public class NoosaScript extends Script {
|
||||||
|
|
||||||
|
private static final GL20 activeGL = (DeviceCompat.isWeb()) ? Gdx.gl30 : Gdx.gl20;
|
||||||
|
|
||||||
public Uniform uCamera;
|
public Uniform uCamera;
|
||||||
public Uniform uModel;
|
public Uniform uModel;
|
||||||
public Uniform uTex;
|
public Uniform uTex;
|
||||||
@@ -44,6 +48,7 @@ public class NoosaScript extends Script {
|
|||||||
|
|
||||||
private Camera lastCamera;
|
private Camera lastCamera;
|
||||||
|
|
||||||
|
private int vertexBufferId;
|
||||||
public NoosaScript() {
|
public NoosaScript() {
|
||||||
|
|
||||||
super();
|
super();
|
||||||
@@ -60,6 +65,12 @@ public class NoosaScript extends Script {
|
|||||||
Quad.setupIndices();
|
Quad.setupIndices();
|
||||||
Quad.bindIndices();
|
Quad.bindIndices();
|
||||||
|
|
||||||
|
if (DeviceCompat.isWeb()) {
|
||||||
|
vertexBufferId = Gdx.gl30.glGenBuffer();
|
||||||
|
Gdx.gl30.glBindBuffer(Gdx.gl30.GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
Gdx.gl30.glBufferData(Gdx.gl30.GL_ARRAY_BUFFER, 16384, null, Gdx.gl30.GL_DYNAMIC_DRAW);
|
||||||
|
Gdx.gl30.glBindBuffer(Gdx.gl30.GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -73,27 +84,50 @@ public class NoosaScript extends Script {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void drawElements( FloatBuffer vertices, ShortBuffer indices, int size ) {
|
public void drawElements( FloatBuffer vertices, ShortBuffer indices, int size ) {
|
||||||
|
if (DeviceCompat.isWeb()) {
|
||||||
|
Gdx.gl30.glBindBuffer(Gdx.gl30.GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
((Buffer)vertices).position( 0 );
|
||||||
|
Gdx.gl30.glBufferSubData(Gdx.gl30.GL_ARRAY_BUFFER, 0, vertices.remaining() * 4, vertices);
|
||||||
|
|
||||||
((Buffer)vertices).position( 0 );
|
aXY.vertexBuffer(2, 4, 0);
|
||||||
aXY.vertexPointer( 2, 4, vertices );
|
aUV.vertexBuffer(2, 4, 2);
|
||||||
|
|
||||||
((Buffer)vertices).position( 2 );
|
Quad.releaseIndices();
|
||||||
aUV.vertexPointer( 2, 4, vertices );
|
Gdx.gl30.glDrawElements( Gdx.gl30.GL_TRIANGLES, size, Gdx.gl30.GL_UNSIGNED_SHORT, indices );
|
||||||
|
Quad.bindIndices();
|
||||||
|
Gdx.gl30.glBindBuffer(Gdx.gl30.GL_ARRAY_BUFFER, 0);
|
||||||
|
} else {
|
||||||
|
((Buffer)vertices).position( 0 );
|
||||||
|
aXY.vertexPointer( 2, 4, vertices );
|
||||||
|
|
||||||
Quad.releaseIndices();
|
((Buffer)vertices).position( 2 );
|
||||||
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, size, Gdx.gl20.GL_UNSIGNED_SHORT, indices );
|
aUV.vertexPointer( 2, 4, vertices );
|
||||||
Quad.bindIndices();
|
|
||||||
|
Quad.releaseIndices();
|
||||||
|
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, size, Gdx.gl20.GL_UNSIGNED_SHORT, indices );
|
||||||
|
Quad.bindIndices();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawQuad( FloatBuffer vertices ) {
|
public void drawQuad( FloatBuffer vertices ) {
|
||||||
|
if (DeviceCompat.isWeb()) {
|
||||||
|
Gdx.gl30.glBindBuffer(Gdx.gl30.GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
((Buffer)vertices).position( 0 );
|
||||||
|
Gdx.gl30.glBufferSubData(Gdx.gl30.GL_ARRAY_BUFFER, 0, vertices.remaining() * 4, vertices);
|
||||||
|
|
||||||
((Buffer)vertices).position( 0 );
|
Gdx.gl30.glVertexAttribPointer(aXY.location(), 2, Gdx.gl30.GL_FLOAT, false, 4 * 4, 0);
|
||||||
aXY.vertexPointer( 2, 4, vertices );
|
Gdx.gl30.glVertexAttribPointer(aUV.location(), 2, Gdx.gl30.GL_FLOAT, false, 4 * 4, 2 * 4);
|
||||||
|
Gdx.gl30.glDrawElements( Gdx.gl30.GL_TRIANGLES, Quad.SIZE, Gdx.gl30.GL_UNSIGNED_SHORT, 0 );
|
||||||
|
Gdx.gl30.glBindBuffer(Gdx.gl30.GL_ARRAY_BUFFER, 0);
|
||||||
|
} else {
|
||||||
|
((Buffer)vertices).position( 0 );
|
||||||
|
aXY.vertexPointer( 2, 4, vertices );
|
||||||
|
|
||||||
((Buffer)vertices).position( 2 );
|
((Buffer)vertices).position( 2 );
|
||||||
aUV.vertexPointer( 2, 4, vertices );
|
aUV.vertexPointer( 2, 4, vertices );
|
||||||
|
|
||||||
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE, Gdx.gl20.GL_UNSIGNED_SHORT, 0 );
|
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE, Gdx.gl20.GL_UNSIGNED_SHORT, 0 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawQuad( Vertexbuffer buffer ) {
|
public void drawQuad( Vertexbuffer buffer ) {
|
||||||
@@ -107,7 +141,7 @@ public class NoosaScript extends Script {
|
|||||||
|
|
||||||
buffer.release();
|
buffer.release();
|
||||||
|
|
||||||
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE, Gdx.gl20.GL_UNSIGNED_SHORT, 0 );
|
activeGL.glDrawElements( GL20.GL_TRIANGLES, Quad.SIZE, GL20.GL_UNSIGNED_SHORT, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawQuadSet( FloatBuffer vertices, int size ) {
|
public void drawQuadSet( FloatBuffer vertices, int size ) {
|
||||||
@@ -116,13 +150,26 @@ public class NoosaScript extends Script {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
((Buffer)vertices).position( 0 );
|
if (DeviceCompat.isWeb()) {
|
||||||
aXY.vertexPointer( 2, 4, vertices );
|
Gdx.gl30.glBindBuffer(Gdx.gl30.GL_ARRAY_BUFFER, vertexBufferId);
|
||||||
|
((Buffer)vertices).position( 0 );
|
||||||
|
Gdx.gl30.glBufferSubData(Gdx.gl30.GL_ARRAY_BUFFER, 0, vertices.remaining() * 4, vertices);
|
||||||
|
|
||||||
((Buffer)vertices).position( 2 );
|
Gdx.gl30.glVertexAttribPointer(aXY.location(), 2, Gdx.gl30.GL_FLOAT, false, 4 * 4, 0);
|
||||||
aUV.vertexPointer( 2, 4, vertices );
|
Gdx.gl30.glVertexAttribPointer(aUV.location(), 2, Gdx.gl30.GL_FLOAT, false, 4 * 4, 2 * 4);
|
||||||
|
|
||||||
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE * size, Gdx.gl20.GL_UNSIGNED_SHORT, 0 );
|
Gdx.gl30.glDrawElements( Gdx.gl30.GL_TRIANGLES, Quad.SIZE * size, Gdx.gl30.GL_UNSIGNED_SHORT, 0 );
|
||||||
|
|
||||||
|
Gdx.gl30.glBindBuffer(Gdx.gl30.GL_ARRAY_BUFFER, 0);
|
||||||
|
} else {
|
||||||
|
((Buffer)vertices).position( 0 );
|
||||||
|
aXY.vertexPointer( 2, 4, vertices );
|
||||||
|
|
||||||
|
((Buffer)vertices).position( 2 );
|
||||||
|
aUV.vertexPointer( 2, 4, vertices );
|
||||||
|
|
||||||
|
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE * size, Gdx.gl20.GL_UNSIGNED_SHORT, 0 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawQuadSet( Vertexbuffer buffer, int length, int offset ){
|
public void drawQuadSet( Vertexbuffer buffer, int length, int offset ){
|
||||||
@@ -140,7 +187,7 @@ public class NoosaScript extends Script {
|
|||||||
|
|
||||||
buffer.release();
|
buffer.release();
|
||||||
|
|
||||||
Gdx.gl20.glDrawElements( Gdx.gl20.GL_TRIANGLES, Quad.SIZE * length, Gdx.gl20.GL_UNSIGNED_SHORT, Quad.SIZE * Short.SIZE/8 * offset );
|
activeGL.glDrawElements( GL20.GL_TRIANGLES, Quad.SIZE * length, GL20.GL_UNSIGNED_SHORT, Quad.SIZE * Short.SIZE/8 * offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void lighting( float rm, float gm, float bm, float am, float ra, float ga, float ba, float aa ) {
|
public void lighting( float rm, float gm, float bm, float am, float ra, float ga, float ba, float aa ) {
|
||||||
@@ -161,7 +208,7 @@ public class NoosaScript extends Script {
|
|||||||
uCamera.valueM4( camera.matrix );
|
uCamera.valueM4( camera.matrix );
|
||||||
|
|
||||||
if (!camera.fullScreen) {
|
if (!camera.fullScreen) {
|
||||||
Gdx.gl20.glEnable( Gdx.gl20.GL_SCISSOR_TEST );
|
activeGL.glEnable( GL20.GL_SCISSOR_TEST );
|
||||||
|
|
||||||
//This fixes pixel scaling issues on some hidpi displays (mainly on macOS)
|
//This fixes pixel scaling issues on some hidpi displays (mainly on macOS)
|
||||||
// because for some reason all other openGL operations work on virtual pixels
|
// because for some reason all other openGL operations work on virtual pixels
|
||||||
@@ -169,13 +216,13 @@ public class NoosaScript extends Script {
|
|||||||
float xScale = (Gdx.graphics.getBackBufferWidth() / (float)Game.width );
|
float xScale = (Gdx.graphics.getBackBufferWidth() / (float)Game.width );
|
||||||
float yScale = ((Gdx.graphics.getBackBufferHeight()-Game.bottomInset) / (float)Game.height );
|
float yScale = ((Gdx.graphics.getBackBufferHeight()-Game.bottomInset) / (float)Game.height );
|
||||||
|
|
||||||
Gdx.gl20.glScissor(
|
activeGL.glScissor(
|
||||||
Math.round(camera.x * xScale),
|
Math.round(camera.x * xScale),
|
||||||
Math.round((Game.height - camera.screenHeight - camera.y) * yScale) + Game.bottomInset,
|
Math.round((Game.height - camera.screenHeight - camera.y) * yScale) + Game.bottomInset,
|
||||||
Math.round(camera.screenWidth * xScale),
|
Math.round(camera.screenWidth * xScale),
|
||||||
Math.round(camera.screenHeight * yScale));
|
Math.round(camera.screenHeight * yScale));
|
||||||
} else {
|
} else {
|
||||||
Gdx.gl20.glDisable( Gdx.gl20.GL_SCISSOR_TEST );
|
activeGL.glDisable( GL20.GL_SCISSOR_TEST );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -189,8 +236,41 @@ public class NoosaScript extends Script {
|
|||||||
return SHADER;
|
return SHADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String SHADER =
|
private static String SHADER;
|
||||||
|
static {
|
||||||
|
if (DeviceCompat.isWeb()) {
|
||||||
|
SHADER =
|
||||||
|
//vertex shader
|
||||||
|
"#version 300 es\n" +
|
||||||
|
"uniform mat4 uCamera;\n" +
|
||||||
|
"uniform mat4 uModel;\n" +
|
||||||
|
"in vec4 aXYZW;\n" +
|
||||||
|
"in vec2 aUV;\n" +
|
||||||
|
"out vec2 vUV;\n" +
|
||||||
|
"void main() {\n" +
|
||||||
|
" gl_Position = uCamera * uModel * aXYZW;\n" +
|
||||||
|
" vUV = aUV;\n" +
|
||||||
|
"}\n" +
|
||||||
|
|
||||||
|
//this symbol separates the vertex and fragment shaders (see Script.compile)
|
||||||
|
"//\n" +
|
||||||
|
|
||||||
|
//fragment shader
|
||||||
|
//preprocessor directives let us define precision on GLES platforms, and ignore it elsewhere
|
||||||
|
"#version 300 es\n" +
|
||||||
|
"#ifdef GL_ES\n" +
|
||||||
|
" precision mediump float;\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"in vec2 vUV;\n" +
|
||||||
|
"uniform sampler2D uTex;\n" +
|
||||||
|
"uniform vec4 uColorM;\n" +
|
||||||
|
"uniform vec4 uColorA;\n" +
|
||||||
|
"out vec4 fragColor;\n" +
|
||||||
|
"void main() {\n" +
|
||||||
|
" fragColor = texture( uTex, vUV ) * uColorM + uColorA;\n" +
|
||||||
|
"}\n";
|
||||||
|
} else {
|
||||||
|
SHADER =
|
||||||
//vertex shader
|
//vertex shader
|
||||||
"uniform mat4 uCamera;\n" +
|
"uniform mat4 uCamera;\n" +
|
||||||
"uniform mat4 uModel;\n" +
|
"uniform mat4 uModel;\n" +
|
||||||
@@ -217,4 +297,6 @@ public class NoosaScript extends Script {
|
|||||||
"void main() {\n" +
|
"void main() {\n" +
|
||||||
" gl_FragColor = texture2D( uTex, vUV ) * uColorM + uColorA;\n" +
|
" gl_FragColor = texture2D( uTex, vUV ) * uColorM + uColorA;\n" +
|
||||||
"}\n";
|
"}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
package com.watabou.noosa;
|
package com.watabou.noosa;
|
||||||
|
|
||||||
import com.watabou.glscripts.Script;
|
import com.watabou.glscripts.Script;
|
||||||
|
import com.watabou.utils.DeviceCompat;
|
||||||
|
|
||||||
//This class should be used on heavy pixel-fill based loads when lighting is not needed.
|
//This class should be used on heavy pixel-fill based loads when lighting is not needed.
|
||||||
// It skips the lighting component of the fragment shader, giving a significant performance boost
|
// It skips the lighting component of the fragment shader, giving a significant performance boost
|
||||||
@@ -44,8 +45,40 @@ public class NoosaScriptNoLighting extends NoosaScript {
|
|||||||
return SHADER;
|
return SHADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String SHADER =
|
private static String SHADER;
|
||||||
|
|
||||||
|
static {
|
||||||
|
if (DeviceCompat.isWeb()) {
|
||||||
|
SHADER =
|
||||||
|
//vertex shader
|
||||||
|
"#version 300 es\n" +
|
||||||
|
"uniform mat4 uCamera;\n" +
|
||||||
|
"uniform mat4 uModel;\n" +
|
||||||
|
"in vec4 aXYZW;\n" +
|
||||||
|
"in vec2 aUV;\n" +
|
||||||
|
"out vec2 vUV;\n" +
|
||||||
|
"void main() {\n" +
|
||||||
|
" gl_Position = uCamera * uModel * aXYZW;\n" +
|
||||||
|
" vUV = aUV;\n" +
|
||||||
|
"}\n" +
|
||||||
|
|
||||||
|
//this symbol separates the vertex and fragment shaders (see Script.compile)
|
||||||
|
"//\n" +
|
||||||
|
|
||||||
|
//fragment shader
|
||||||
|
//preprocessor directives let us define precision on GLES platforms, and ignore it elsewhere
|
||||||
|
"#version 300 es\n" +
|
||||||
|
"#ifdef GL_ES\n" +
|
||||||
|
" precision mediump float;\n" +
|
||||||
|
"#endif\n" +
|
||||||
|
"in vec2 vUV;\n" +
|
||||||
|
"uniform sampler2D uTex;\n" +
|
||||||
|
"out vec4 fragColor;\n" +
|
||||||
|
"void main() {\n" +
|
||||||
|
" fragColor = texture( uTex, vUV );\n" +
|
||||||
|
"}\n";
|
||||||
|
} else {
|
||||||
|
SHADER =
|
||||||
//vertex shader
|
//vertex shader
|
||||||
"uniform mat4 uCamera;\n" +
|
"uniform mat4 uCamera;\n" +
|
||||||
"uniform mat4 uModel;\n" +
|
"uniform mat4 uModel;\n" +
|
||||||
@@ -70,4 +103,6 @@ public class NoosaScriptNoLighting extends NoosaScript {
|
|||||||
"void main() {\n" +
|
"void main() {\n" +
|
||||||
" gl_FragColor = texture2D( uTex, vUV );\n" +
|
" gl_FragColor = texture2D( uTex, vUV );\n" +
|
||||||
"}\n";
|
"}\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import com.badlogic.gdx.math.Affine2;
|
|||||||
import com.badlogic.gdx.math.Matrix4;
|
import com.badlogic.gdx.math.Matrix4;
|
||||||
import com.watabou.glwrap.Matrix;
|
import com.watabou.glwrap.Matrix;
|
||||||
import com.watabou.glwrap.Quad;
|
import com.watabou.glwrap.Quad;
|
||||||
|
import com.watabou.utils.DeviceCompat;
|
||||||
|
|
||||||
import java.nio.Buffer;
|
import java.nio.Buffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
@@ -79,9 +80,11 @@ public class RenderedText extends Image {
|
|||||||
|
|
||||||
private synchronized void measure(){
|
private synchronized void measure(){
|
||||||
|
|
||||||
|
if (!DeviceCompat.isWeb()) {
|
||||||
if (Thread.currentThread().getName().equals("SHPD Actor Thread")){
|
if (Thread.currentThread().getName().equals("SHPD Actor Thread")){
|
||||||
throw new RuntimeException("Text measured from the actor thread!");
|
throw new RuntimeException("Text measured from the actor thread!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( text == null || text.equals("") ) {
|
if ( text == null || text.equals("") ) {
|
||||||
text = "";
|
text = "";
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import com.watabou.glwrap.Quad;
|
|||||||
import com.watabou.glwrap.Vertexbuffer;
|
import com.watabou.glwrap.Vertexbuffer;
|
||||||
import com.watabou.utils.Rect;
|
import com.watabou.utils.Rect;
|
||||||
import com.watabou.utils.RectF;
|
import com.watabou.utils.RectF;
|
||||||
|
import com.watabou.utils.DeviceCompat;;
|
||||||
|
|
||||||
import java.nio.Buffer;
|
import java.nio.Buffer;
|
||||||
import java.nio.FloatBuffer;
|
import java.nio.FloatBuffer;
|
||||||
@@ -197,7 +198,9 @@ public class Tilemap extends Visual {
|
|||||||
public void draw() {
|
public void draw() {
|
||||||
|
|
||||||
super.draw();
|
super.draw();
|
||||||
|
if (DeviceCompat.isWeb()) {
|
||||||
|
fullUpdate = true;
|
||||||
|
}
|
||||||
if (!updated.isEmpty()) {
|
if (!updated.isEmpty()) {
|
||||||
updateVertices();
|
updateVertices();
|
||||||
if (buffer == null)
|
if (buffer == null)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.badlogic.gdx.utils.JsonReader;
|
|||||||
import com.badlogic.gdx.utils.JsonValue;
|
import com.badlogic.gdx.utils.JsonValue;
|
||||||
import com.badlogic.gdx.utils.JsonWriter;
|
import com.badlogic.gdx.utils.JsonWriter;
|
||||||
import com.watabou.noosa.Game;
|
import com.watabou.noosa.Game;
|
||||||
|
import com.watabou.utils.DeviceCompat;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
@@ -484,7 +485,15 @@ public class Bundle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//useful to turn this off for save data debugging.
|
//useful to turn this off for save data debugging.
|
||||||
private static final boolean compressByDefault = true;
|
private static final boolean compressByDefault;
|
||||||
|
|
||||||
|
static {
|
||||||
|
if (DeviceCompat.isWeb()) {
|
||||||
|
compressByDefault = false;
|
||||||
|
} else {
|
||||||
|
compressByDefault = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final int GZIP_BUFFER = 1024*4; //4 kb
|
private static final int GZIP_BUFFER = 1024*4; //4 kb
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import com.badlogic.gdx.Gdx;
|
|||||||
import com.badlogic.gdx.Input;
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.utils.SharedLibraryLoader;
|
import com.badlogic.gdx.utils.SharedLibraryLoader;
|
||||||
import com.watabou.noosa.Game;
|
import com.watabou.noosa.Game;
|
||||||
|
import com.badlogic.gdx.Application;
|
||||||
|
|
||||||
//TODO migrate to platformSupport class
|
//TODO migrate to platformSupport class
|
||||||
public class DeviceCompat {
|
public class DeviceCompat {
|
||||||
@@ -49,15 +50,22 @@ public class DeviceCompat {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isAndroid(){
|
public static boolean isAndroid(){
|
||||||
return SharedLibraryLoader.isAndroid;
|
return Gdx.app.getType() == Application.ApplicationType.Android;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isiOS(){
|
public static boolean isiOS(){
|
||||||
return SharedLibraryLoader.isIos;
|
return Gdx.app.getType() == Application.ApplicationType.iOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isDesktop(){
|
public static boolean isDesktop(){
|
||||||
return SharedLibraryLoader.isWindows || SharedLibraryLoader.isMac || SharedLibraryLoader.isLinux;
|
return System.getProperty("os.name").toLowerCase().contains("win") ||
|
||||||
|
System.getProperty("os.name").toLowerCase().contains("mac") ||
|
||||||
|
System.getProperty("os.name").toLowerCase().contains("nux") ||
|
||||||
|
Gdx.app.getType() == Application.ApplicationType.WebGL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isWeb(){
|
||||||
|
return Gdx.app.getType() == Application.ApplicationType.WebGL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasHardKeyboard(){
|
public static boolean hasHardKeyboard(){
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ allprojects {
|
|||||||
gdxVersion = '1.12.1'
|
gdxVersion = '1.12.1'
|
||||||
gdxControllersVersion = '2.2.4-SNAPSHOT'
|
gdxControllersVersion = '2.2.4-SNAPSHOT'
|
||||||
robovmVersion = '2.3.21'
|
robovmVersion = '2.3.21'
|
||||||
|
|
||||||
|
gdxTeaVMVersion = '1.0.5'
|
||||||
|
teaVMVersion = '0.11.0'
|
||||||
}
|
}
|
||||||
version = appVersionName
|
version = appVersionName
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import com.watabou.noosa.Game;
|
|||||||
import com.watabou.utils.Bundlable;
|
import com.watabou.utils.Bundlable;
|
||||||
import com.watabou.utils.Bundle;
|
import com.watabou.utils.Bundle;
|
||||||
import com.watabou.utils.FileUtils;
|
import com.watabou.utils.FileUtils;
|
||||||
|
import com.watabou.utils.DeviceCompat;;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
@@ -56,6 +57,7 @@ import java.util.Locale;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
public enum Rankings {
|
public enum Rankings {
|
||||||
|
|
||||||
@@ -65,6 +67,11 @@ public enum Rankings {
|
|||||||
|
|
||||||
public static final String RANKINGS_FILE = "rankings.dat";
|
public static final String RANKINGS_FILE = "rankings.dat";
|
||||||
|
|
||||||
|
private static String generateUUID() {
|
||||||
|
Random random = new Random();
|
||||||
|
return Long.toHexString(random.nextLong()) + "-" + Long.toHexString(random.nextLong());
|
||||||
|
}
|
||||||
|
|
||||||
public ArrayList<Record> records;
|
public ArrayList<Record> records;
|
||||||
public int lastRecord;
|
public int lastRecord;
|
||||||
public int totalNumber;
|
public int totalNumber;
|
||||||
@@ -116,7 +123,11 @@ public enum Rankings {
|
|||||||
|
|
||||||
INSTANCE.saveGameData(rec);
|
INSTANCE.saveGameData(rec);
|
||||||
|
|
||||||
|
if (DeviceCompat.isWeb()) {
|
||||||
|
rec.gameID = generateUUID();
|
||||||
|
} else {
|
||||||
rec.gameID = UUID.randomUUID().toString();
|
rec.gameID = UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
if (rec.daily){
|
if (rec.daily){
|
||||||
if (Dungeon.dailyReplay){
|
if (Dungeon.dailyReplay){
|
||||||
@@ -533,7 +544,11 @@ public enum Rankings {
|
|||||||
if (bundle.contains(DATA)) gameData = bundle.getBundle(DATA);
|
if (bundle.contains(DATA)) gameData = bundle.getBundle(DATA);
|
||||||
if (bundle.contains(ID)) gameID = bundle.getString(ID);
|
if (bundle.contains(ID)) gameID = bundle.getString(ID);
|
||||||
|
|
||||||
|
if (DeviceCompat.isWeb()) {
|
||||||
|
if (gameID == null) gameID = generateUUID();
|
||||||
|
} else {
|
||||||
if (gameID == null) gameID = UUID.randomUUID().toString();
|
if (gameID == null) gameID = UUID.randomUUID().toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -643,11 +643,13 @@ public class GameScene extends PixelScene {
|
|||||||
public void destroy() {
|
public void destroy() {
|
||||||
|
|
||||||
//tell the actor thread to finish, then wait for it to complete any actions it may be doing.
|
//tell the actor thread to finish, then wait for it to complete any actions it may be doing.
|
||||||
|
if (!DeviceCompat.isWeb()) {
|
||||||
if (!waitForActorThread( 4500, true )){
|
if (!waitForActorThread( 4500, true )){
|
||||||
Throwable t = new Throwable();
|
Throwable t = new Throwable();
|
||||||
t.setStackTrace(actorThread.getStackTrace());
|
t.setStackTrace(actorThread.getStackTrace());
|
||||||
throw new RuntimeException("timeout waiting for actor thread! ", t);
|
throw new RuntimeException("timeout waiting for actor thread! ", t);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Emitter.freezeEmitters = false;
|
Emitter.freezeEmitters = false;
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ public class v3_X_Changes {
|
|||||||
changes.hardlight(Window.TITLE_COLOR);
|
changes.hardlight(Window.TITLE_COLOR);
|
||||||
changeInfos.add(changes);
|
changeInfos.add(changes);
|
||||||
|
|
||||||
if (DeviceCompat.isDesktop() && SharedLibraryLoader.isLinux) {
|
if (DeviceCompat.isDesktop() && System.getProperty("os.name").toLowerCase().contains("nux")) {
|
||||||
changes.addButton(new ChangeButton(Icons.DISPLAY.get(), "A Note for Steam Deck users",
|
changes.addButton(new ChangeButton(Icons.DISPLAY.get(), "A Note for Steam Deck users",
|
||||||
"A bug was fixed in this patch which affected display scaling on Steam Deck. Due to a quirk in how the Steam Deck reported display dimensions, the game incorrectly thought Steam Deck's screen was about 4\", instead of 7\".\n" +
|
"A bug was fixed in this patch which affected display scaling on Steam Deck. Due to a quirk in how the Steam Deck reported display dimensions, the game incorrectly thought Steam Deck's screen was about 4\", instead of 7\".\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
|
|||||||
154
html/build.gradle
Normal file
154
html/build.gradle
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
apply plugin: 'java-library'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "com.badlogicgames.gdx:gdx:$gdxVersion"
|
||||||
|
implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion"
|
||||||
|
implementation "com.github.xpenatan.gdx-teavm:backend-teavm:$gdxTeaVMVersion"
|
||||||
|
implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||||
|
implementation "com.github.xpenatan.gdx-teavm:gdx-freetype-teavm:$gdxTeaVMVersion"
|
||||||
|
implementation project(':core')
|
||||||
|
implementation "org.teavm:teavm-jso:$teaVMVersion"
|
||||||
|
implementation "org.teavm:teavm-core:$teaVMVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
maven { url 'https://teavm.org/maven/repository' }
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('compileClient', JavaExec) {
|
||||||
|
classpath(sourceSets.main.runtimeClasspath)
|
||||||
|
mainClass.set('com.shatteredpixel.shatteredpixeldungeon.html.Compile')
|
||||||
|
jvmArgs('-Xms8g', '-Xmx14g', '-Xss16m', '-XX:MaxMetaspaceSize=12g', '-Dfile.encoding=UTF-8')
|
||||||
|
outputs.dir '../release/webapp'
|
||||||
|
doFirst {
|
||||||
|
println "Running compileClient..."
|
||||||
|
}
|
||||||
|
doLast {
|
||||||
|
println "compileClient completed!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task modifyHtml {
|
||||||
|
doLast {
|
||||||
|
def htmlFile = file("../release/webapp/index.html")
|
||||||
|
def destinationDir = file("../release/webapp/assets")
|
||||||
|
def sourceFavicon = file("../desktop/src/main/assets/icons/windows.ico")
|
||||||
|
def sourceGif = file("../html/src/main/assets/logo.gif")
|
||||||
|
def destinationStartupLogo = file("../release/webapp/startup-logo.png")
|
||||||
|
|
||||||
|
// copy windows.ico
|
||||||
|
if (sourceFavicon.exists()) {
|
||||||
|
def destinationFile = new File(destinationDir, "windows.ico")
|
||||||
|
sourceFavicon.withInputStream { input ->
|
||||||
|
destinationFile.withOutputStream { output ->
|
||||||
|
output << input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println "Copied windows.ico to assets folder."
|
||||||
|
} else {
|
||||||
|
println "windows.ico does not exist. Skipping copy step."
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourceGif.exists()) {
|
||||||
|
destinationStartupLogo.parentFile.mkdirs()
|
||||||
|
sourceGif.withInputStream { input ->
|
||||||
|
destinationStartupLogo.withOutputStream { output ->
|
||||||
|
output << input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println "Replaced startup-logo.png with a gif."
|
||||||
|
} else {
|
||||||
|
println "Gif does not exist. Skipping replacement step."
|
||||||
|
}
|
||||||
|
|
||||||
|
if (htmlFile.exists()) {
|
||||||
|
def faviconLink = '<link rel="icon" href="assets/windows.ico" type="image/x-icon">'
|
||||||
|
def content = htmlFile.text
|
||||||
|
|
||||||
|
// add a link for the favicon
|
||||||
|
if (content.contains("</head>")) {
|
||||||
|
content = content.replace("</head>", faviconLink + "\n</head>")
|
||||||
|
println "Favicon link added to index.html."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change page title
|
||||||
|
if (content.contains("<title>")) {
|
||||||
|
content = content.replaceFirst("<title>.*?</title>", "<title>Shattered Pixel Dungeon</title>")
|
||||||
|
println "Title updated to 'Shattered Pixel Dungeon'."
|
||||||
|
} else {
|
||||||
|
println "No <title> tag found in index.html. Skipping title update."
|
||||||
|
}
|
||||||
|
|
||||||
|
if (content.contains("<style>") && content.contains("</style>")) {
|
||||||
|
content = content.replaceAll(
|
||||||
|
"(?s)<style>.*?</style>",
|
||||||
|
"""<style>
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: #000;
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#progress {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#progress-img {
|
||||||
|
display: flex;
|
||||||
|
width: 850px;
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: -20px;
|
||||||
|
}
|
||||||
|
#progress-box {
|
||||||
|
background: rgba(255,255,255,0.1);
|
||||||
|
border: 2px solid #fff;
|
||||||
|
display: flex;
|
||||||
|
margin-top: -20px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
height: 30px;
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
#progress-bar {
|
||||||
|
display: block;
|
||||||
|
background: #44FF82;
|
||||||
|
height: 20px;
|
||||||
|
width: 0%;
|
||||||
|
}
|
||||||
|
</style>"""
|
||||||
|
)
|
||||||
|
|
||||||
|
println "Successfully replaced the <style> block in index.html."
|
||||||
|
} else {
|
||||||
|
println "No <style> block found in index.html. Skipping style replacement."
|
||||||
|
}
|
||||||
|
|
||||||
|
htmlFile.text = content
|
||||||
|
} else {
|
||||||
|
println "index.html does not exist. Skipping favicon injection."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('modifyHtml') {
|
||||||
|
mustRunAfter('compileClient')
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named('build') {
|
||||||
|
dependsOn 'compileClient'
|
||||||
|
finalizedBy 'modifyHtml'
|
||||||
|
}
|
||||||
7
html/buildTestWeb.sh
Executable file
7
html/buildTestWeb.sh
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
../gradlew :html:build
|
||||||
|
wait
|
||||||
|
if [[ -d ../release/webapp/ ]]; then
|
||||||
|
python3 -m http.server 8100 -d ../release/webapp/
|
||||||
|
fi
|
||||||
BIN
html/src/main/assets/logo.gif
Normal file
BIN
html/src/main/assets/logo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 776 KiB |
62
html/src/main/java/Compile.java
Normal file
62
html/src/main/java/Compile.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* This file is derived from micronaut-libgdx-teavm (https://github.com/hollingsworthd/micronaut-libgdx-teavm),
|
||||||
|
* originally licensed under the Apache License, Version 2.0.
|
||||||
|
*
|
||||||
|
* Modifications made by Konsthol on 13/4/25:
|
||||||
|
* - Adjusted to compile Shattered Pixel Dungeon
|
||||||
|
*
|
||||||
|
* Copyright 2022 Daniel Hollingsworth
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.html;
|
||||||
|
|
||||||
|
import com.github.xpenatan.gdx.backends.teavm.config.AssetFileHandle;
|
||||||
|
import com.github.xpenatan.gdx.backends.teavm.config.TeaBuildConfiguration;
|
||||||
|
import com.github.xpenatan.gdx.backends.teavm.config.TeaBuilder;
|
||||||
|
import com.github.xpenatan.gdx.backends.teavm.gen.SkipClass;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.teavm.tooling.TeaVMTool;
|
||||||
|
import org.teavm.vm.TeaVMOptimizationLevel;
|
||||||
|
|
||||||
|
@SkipClass
|
||||||
|
public class Compile {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
deleteDir(new File("../release/webapp"));
|
||||||
|
|
||||||
|
TeaBuildConfiguration conf = new TeaBuildConfiguration();
|
||||||
|
|
||||||
|
conf.webappPath = new File("../release").getAbsolutePath();
|
||||||
|
conf.assetsPath.add(new AssetFileHandle("../core/src/main/assets"));
|
||||||
|
|
||||||
|
TeaVMTool tool = TeaBuilder.config(conf);
|
||||||
|
tool.setMainClass(TeaVMLauncher.class.getName());
|
||||||
|
tool.setOptimizationLevel(TeaVMOptimizationLevel.ADVANCED);
|
||||||
|
tool.setObfuscated(true);
|
||||||
|
tool.setShortFileNames(true);
|
||||||
|
tool.setSourceFilesCopied(false);
|
||||||
|
tool.setStrict(false);
|
||||||
|
tool.setSourceMapsFileGenerated(false);
|
||||||
|
tool.setDebugInformationGenerated(false);
|
||||||
|
tool.setIncremental(false);
|
||||||
|
|
||||||
|
TeaBuilder.build(tool);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void deleteDir(File dir) {
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
deleteDir(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dir.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
122
html/src/main/java/HtmlPlatformSupport.java
Normal file
122
html/src/main/java/HtmlPlatformSupport.java
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
package com.shatteredpixel.shatteredpixeldungeon.html;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.Graphics;
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.PixmapPacker;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
|
||||||
|
import com.watabou.input.ControllerHandler;
|
||||||
|
import com.watabou.noosa.Game;
|
||||||
|
import com.watabou.utils.PlatformSupport;
|
||||||
|
import org.teavm.jso.JSBody;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class HtmlPlatformSupport extends PlatformSupport {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateDisplaySize() {
|
||||||
|
if (Gdx.app == null || Gdx.graphics == null) {
|
||||||
|
System.err.println("Gdx is not initialized yet. Skipping display size update.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSystemUI() {
|
||||||
|
Gdx.app.postRunnable( new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Object canvas = getCanvasElement("canvas");
|
||||||
|
if (SPDSettings.fullscreen()) {
|
||||||
|
System.out.println("Requesting fullscreen.");
|
||||||
|
requestFullscreen("canvas");
|
||||||
|
} else {
|
||||||
|
System.out.println("Exiting fullscreen.");
|
||||||
|
exitFullscreen();
|
||||||
|
setCanvasSize("canvas", SPDSettings.windowResolution().x, SPDSettings.windowResolution().y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@JSBody(script = ""
|
||||||
|
+ "document.body.addEventListener('click', function() {"
|
||||||
|
+ " console.log('User clicked. Triggering fullscreen and audio...');"
|
||||||
|
+ " document.getElementById('canvas').requestFullscreen();"
|
||||||
|
+ " if (!window.audioContext) {"
|
||||||
|
+ " window.audioContext = new (window.AudioContext || window.webkitAudioContext)();"
|
||||||
|
+ " }"
|
||||||
|
+ " window.audioContext.resume().then(() => {"
|
||||||
|
+ " console.log('AudioContext resumed successfully.');"
|
||||||
|
+ " }).catch((err) => {"
|
||||||
|
+ " console.error('Failed to resume AudioContext:', err);"
|
||||||
|
+ " });"
|
||||||
|
+ "}, { once: true });")
|
||||||
|
public static native void setupClickListener();
|
||||||
|
|
||||||
|
@JSBody(params = {"id"}, script = "document.getElementById(id).requestFullscreen();")
|
||||||
|
private static native void requestFullscreen(String id);
|
||||||
|
|
||||||
|
@JSBody(params = {"id"}, script = "return document.getElementById(id);")
|
||||||
|
private static native Object getCanvasElement(String id);
|
||||||
|
|
||||||
|
@JSBody(params = {}, script = "document.exitFullscreen();")
|
||||||
|
private static native void exitFullscreen();
|
||||||
|
|
||||||
|
@JSBody(params = {"id", "width", "height"}, script = "var canvas = document.getElementById(id); canvas.width = width; canvas.height = height;")
|
||||||
|
private static native void setCanvasSize(String id, int width, int height);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean connectedToUnmeteredNetwork() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsVibration() {
|
||||||
|
return ControllerHandler.vibrationSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FreeTypeFontGenerator basicFontGenerator;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupFontGenerators(int pageSize, boolean systemfont) {
|
||||||
|
//don't bother doing anything if nothing has changed
|
||||||
|
if (fonts != null && this.pageSize == pageSize && this.systemfont == systemfont) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
this.systemfont = systemfont;
|
||||||
|
|
||||||
|
resetGenerators(false);
|
||||||
|
fonts = new HashMap<>();
|
||||||
|
|
||||||
|
basicFontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/pixel_font.ttf"));
|
||||||
|
|
||||||
|
fonts.put(basicFontGenerator, new HashMap<>());
|
||||||
|
|
||||||
|
packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FreeTypeFontGenerator getGeneratorForString( String input ) {
|
||||||
|
return basicFontGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Pattern regularsplitter = Pattern.compile("(?<=\n)|(?=\n)|(?<=_)|(?=_)|(?<=\\*\\*)|(?=\\*\\*)");
|
||||||
|
|
||||||
|
private final Pattern regularsplitterMultiline = Pattern.compile("(?<= )|(?= )|(?<=\n)|(?=\n)|(?<=_)|(?=_)|(?<=\\*\\*)|(?=\\*\\*)");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] splitforTextBlock(String text, boolean multiline) {
|
||||||
|
if (multiline) {
|
||||||
|
return regularsplitterMultiline.split(text);
|
||||||
|
} else {
|
||||||
|
return regularsplitter.split(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
html/src/main/java/TeaVMLauncher.java
Normal file
46
html/src/main/java/TeaVMLauncher.java
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
package com.shatteredpixel.shatteredpixeldungeon.html;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Files;
|
||||||
|
import com.watabou.noosa.Game;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
|
||||||
|
import com.github.xpenatan.gdx.backends.teavm.TeaApplicationConfiguration;
|
||||||
|
import com.github.xpenatan.gdx.backends.teavm.TeaApplication;
|
||||||
|
import com.watabou.utils.FileUtils;
|
||||||
|
|
||||||
|
public class TeaVMLauncher {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
TeaApplicationConfiguration config = new TeaApplicationConfiguration("canvas");
|
||||||
|
config.width = 0;
|
||||||
|
config.height = 0;
|
||||||
|
config.useGL30 = true;
|
||||||
|
config.preloadListener = assetLoader -> {
|
||||||
|
try {
|
||||||
|
assetLoader.loadScript("freetype.js");
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Error loading freetype.js: " + e.getMessage());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
initializeServices();
|
||||||
|
FileUtils.setDefaultFileProperties(Files.FileType.Local, "");
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
HtmlPlatformSupport platformSupport = new HtmlPlatformSupport();
|
||||||
|
|
||||||
|
platformSupport.setupClickListener();
|
||||||
|
|
||||||
|
new TeaApplication(new ShatteredPixelDungeon(platformSupport), config);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("Error launching TeaApplication: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void initializeServices() {
|
||||||
|
Game.version = "3.0.2";
|
||||||
|
Game.versionCode = 833;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ include ':core'
|
|||||||
include ':android'
|
include ':android'
|
||||||
include ':ios'
|
include ':ios'
|
||||||
include ':desktop'
|
include ':desktop'
|
||||||
|
include ':html'
|
||||||
|
|
||||||
//service modules
|
//service modules
|
||||||
include ':services'
|
include ':services'
|
||||||
|
|||||||
Reference in New Issue
Block a user