Merge pull request #163 from LAX1DUDE/image-maps

Image maps
This commit is contained in:
LAX1DUDE 2022-05-14 18:37:04 -07:00 committed by GitHub
commit 75cdac50a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 349 additions and 24 deletions

View File

@ -40,7 +40,7 @@ public class VideoMapPacketCodec {
this.requiresFullResetPacket = true;
this.isDisabled = true;
}
/**
* @param mapIds 2D grid of map IDs that make up the screen (mapIds[y][x])
* @param posX audio playback X coord
@ -48,7 +48,14 @@ public class VideoMapPacketCodec {
* @param posZ audio playback Z coord
*/
public VideoMapPacketCodec(int[][] mapIds, double posX, double posY, double posZ) {
this(mapIds, posX, posY, posZ, 1.0f);
this(mapIds, posX, posY, posZ, 0.5f);
}
/**
* @param mapIds 2D grid of map IDs that make up the screen (mapIds[y][x])
*/
public VideoMapPacketCodec(int[][] mapIds) {
this(mapIds, 0, 100, 0, 0.5f);
}
/**
@ -167,7 +174,7 @@ public class VideoMapPacketCodec {
/**
* @param url URL to an MP4 or other HTML5 supported video file
* @param loop If the video file should loop
* @param durationSeconds duration of the video in seconds
* @param duration duration of the video in seconds
* @return packet to send to players
*/
public byte[] beginPlayback(String url, boolean loop, float duration) {

View File

@ -20,7 +20,7 @@ public class VideoMapPacketCodecBukkit extends VideoMapPacketCodec {
public VideoMapPacketCodecBukkit(int[][] mapIds, double posX, double posY, double posZ, float volume) {
super(mapIds, posX, posY, posZ, volume);
}
/**
* @param mapIds 2D grid of map IDs that make up the screen (mapIds[y][x])
* @param posX audio playback X coord
@ -28,13 +28,23 @@ public class VideoMapPacketCodecBukkit extends VideoMapPacketCodec {
* @param posZ audio playback Z coord
*/
public VideoMapPacketCodecBukkit(int[][] mapIds, double posX, double posY, double posZ) {
super(mapIds, posX, posY, posZ, 1.0f);
super(mapIds, posX, posY, posZ);
}
/**
* @param mapIds 2D grid of map IDs that make up the screen (mapIds[y][x])
*/
public VideoMapPacketCodecBukkit(int[][] mapIds) {
super(mapIds);
}
public static class VideoMapPacket {
protected final Object packet;
protected VideoMapPacket(byte[] packet) {
this.packet = new Packet131ItemData((short)104, (short)0, packet);
this(packet, false);
}
protected VideoMapPacket(byte[] packet, boolean image) {
this.packet = new Packet131ItemData((short)(104 + (image ? 1 : 0)), (short)0, packet);
}
public Object getNativePacket() {
return packet;
@ -72,7 +82,15 @@ public class VideoMapPacketCodecBukkit extends VideoMapPacketCodec {
public VideoMapPacket disableVideoBukkit() {
return new VideoMapPacket(disableVideo());
}
/**
* unloads image and resets all map object to vanilla renderer
* @return packet to send to players
*/
public VideoMapPacket disableImageBukkit() {
return new VideoMapPacket(disableVideo(), true);
}
/**
* syncs the server side video timestamp with players
* @return packet to send to players
@ -80,7 +98,15 @@ public class VideoMapPacketCodecBukkit extends VideoMapPacketCodec {
public VideoMapPacket syncPlaybackWithPlayersBukkit() {
return new VideoMapPacket(syncPlaybackWithPlayers());
}
/**
* syncs the server side image with players
* @return packet to send to players
*/
public VideoMapPacket syncPlaybackWithPlayersImageBukkit() {
return new VideoMapPacket(syncPlaybackWithPlayers(), true);
}
/**
* @param url URL to an MP4 or other HTML5 supported video file
* @param loop If the video file should loop
@ -90,7 +116,15 @@ public class VideoMapPacketCodecBukkit extends VideoMapPacketCodec {
public VideoMapPacket beginPlaybackBukkit(String url, boolean loop, float duration) {
return new VideoMapPacket(beginPlayback(url, loop, duration));
}
/**
* @param url URL to a PNG, JPEG, GIF, or other HTML5 supported image file
* @return packet to send to players
*/
public VideoMapPacket beginPlaybackImageBukkit(String url) {
return new VideoMapPacket(beginPlayback(url));
}
/**
* Tells the browser to pre-load a URL to a video to be played in the future
* @param url the URL of the video
@ -101,6 +135,16 @@ public class VideoMapPacketCodecBukkit extends VideoMapPacketCodec {
return new VideoMapPacket(bufferVideo(url, ttl));
}
/**
* Tells the browser to pre-load a URL to an image to be played in the future
* @param url the URL of the image
* @param ttl the amount of time the image should stay loaded
* @return packet to send to players
*/
public static VideoMapPacket bufferImageBukkit(String url, int ttl) {
return new VideoMapPacket(bufferVideo(url, ttl), true);
}
/**
* @param time time in seconds to seek the video to
*/

View File

@ -675,6 +675,43 @@ public class EaglerAdapterImpl2 {
throw new UnsupportedOperationException("Video is not supported in LWJGL runtime");
}
public static final boolean isImageSupported() {
return false;
}
public static final void loadImage(String src) {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final void loadImage(String src, String setJavascriptPointer) {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final void loadImage(String src, String setJavascriptPointer, String javascriptOnloadFunction) {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final void bufferImage(String src, int ttl) {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final void unloadImage() {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final boolean isImageLoaded() {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final void updateImageTexture() {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final void bindImageTexture() {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final int getImageWidth() {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final int getImageHeight() {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
public static final void setImageFrameRate(float seconds) {
throw new UnsupportedOperationException("Image is not supported in LWJGL runtime");
}
// =======================================================================================
// =======================================================================================
// =======================================================================================

View File

@ -360,4 +360,64 @@ public class ItemMap extends ItemMapBase {
e.printStackTrace();
}
}
public static void processImageMap(WorldClient theWorld, byte[] data) {
if(!EaglerAdapter.isImageSupported()) {
return;
}
try {
DataInputStream dat = new DataInputStream(new ByteArrayInputStream(data));
int op = dat.read();
if(op == 0) {
int count = dat.read();
int w = (count >> 4) & 0xF;
int h = count & 0xF;
for(int y = 0; y < h; ++y) {
for(int x = 0; x < w; ++x) {
getMapById(theWorld, dat.readUnsignedShort()).enableVideoPlayback = false;
}
}
EaglerAdapter.unloadImage();
}else if(op == 8) {
int ttl = dat.readInt();
String src = dat.readUTF();
EaglerAdapter.bufferImage(src, ttl);
}else {
boolean fullResetPacket = (op & 2) == 2;
boolean positionPacket = (op & 4) == 4;
int fps = 0;
int len = 0;
String url = null;
if(fullResetPacket) {
int count = dat.read();
int w = (count >> 4) & 0xF;
int h = count & 0xF;
float wf = 1.0f / w;
float hf = 1.0f / h;
for(int y = 0; y < h; ++y) {
for(int x = 0; x < w; ++x) {
MapData mp = getMapById(theWorld, dat.readUnsignedShort());
mp.videoX1 = x * wf;
mp.videoY1 = y * hf;
mp.videoX2 = mp.videoX1 + wf;
mp.videoY2 = mp.videoY1 + hf;
mp.enableVideoPlayback = true;
}
}
fps = dat.read();
len = dat.readInt();
url = dat.readUTF();
}
if(fullResetPacket) {
EaglerAdapter.setImageFrameRate(fps);
EaglerAdapter.loadImage(url);
}
}
}catch(IOException e) {
System.err.println("Failed to read image map packet! " + e.toString());
e.printStackTrace();
}
}
}

View File

@ -1,6 +1,5 @@
package net.minecraft.src;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;

View File

@ -30,7 +30,9 @@ public class MapItemRenderer {
float texX2 = 1.0f;
float texY1 = 0.0f;
float texY2 = 1.0f;
boolean isVideoMode = EaglerAdapter.isVideoSupported() && par3MapData.enableVideoPlayback && EaglerAdapter.isVideoLoaded();
boolean isVideoOrImageMode = EaglerAdapter.isVideoSupported() && par3MapData.enableVideoPlayback;
boolean isVideoMode = isVideoOrImageMode && EaglerAdapter.isVideoLoaded();
boolean isImageMode = isVideoOrImageMode && EaglerAdapter.isImageLoaded();
if(isVideoMode) {
EaglerAdapter.glEnable(EaglerAdapter.EAG_SWAP_RB);
EaglerAdapter.updateVideoTexture();
@ -39,32 +41,40 @@ public class MapItemRenderer {
texY1 = par3MapData.videoY1;
texX2 = par3MapData.videoX2;
texY2 = par3MapData.videoY2;
}else if(isImageMode) {
EaglerAdapter.glEnable(EaglerAdapter.EAG_SWAP_RB);
EaglerAdapter.updateImageTexture();
EaglerAdapter.bindImageTexture();
texX1 = par3MapData.videoX1;
texY1 = par3MapData.videoY1;
texX2 = par3MapData.videoX2;
texY2 = par3MapData.videoY2;
}else {
if(par3MapData.enableAyunami) {
System.arraycopy(par3MapData.ayunamiPixels, 0, intArray, 0, intArray.length);
}else {
for (int var4 = 0; var4 < 16384; ++var4) {
byte var5 = par3MapData.colors[var4];
if (var5 / 4 == 0) {
this.intArray[var4] = (var4 + var4 / 128 & 1) * 8 + 16 << 24;
} else {
int var6 = MapColor.mapColorArray[var5 / 4].colorValue;
int var7 = var5 & 3;
short var8 = 220;
if (var7 == 2) {
var8 = 255;
}
if (var7 == 0) {
var8 = 180;
}
int var9 = (var6 >> 16 & 255) * var8 / 255;
int var10 = (var6 >> 8 & 255) * var8 / 255;
int var11 = (var6 & 255) * var8 / 255;
if (this.gameSettings.anaglyph) {
int var12 = (var9 * 30 + var10 * 59 + var11 * 11) / 100;
int var13 = (var9 * 30 + var10 * 70) / 100;
@ -73,14 +83,14 @@ public class MapItemRenderer {
var10 = var13;
var11 = var14;
}
this.intArray[var4] = -16777216 | var9 << 16 | var10 << 8 | var11;
}
}
}
par2RenderEngine.createTextureFromBytes(this.intArray, 128, 128, this.bufferedImage);
}
byte var15 = 0;
byte var16 = 0;
Tessellator var17 = Tessellator.instance;
@ -97,15 +107,15 @@ public class MapItemRenderer {
EaglerAdapter.glEnable(EaglerAdapter.GL_ALPHA_TEST);
EaglerAdapter.glDisable(EaglerAdapter.GL_BLEND);
par2RenderEngine.resetBoundTexture();
if(isVideoMode) {
if(isVideoMode || isImageMode) {
EaglerAdapter.glDisable(EaglerAdapter.EAG_SWAP_RB);
}
if(!par3MapData.enableAyunami && !isVideoMode) {
if(!par3MapData.enableAyunami && !(isVideoMode || isImageMode)) {
mapicons.bindTexture();
int var19 = 0;
for (Iterator var20 = par3MapData.playersVisibleOnMap.values().iterator(); var20.hasNext(); ++var19) {
MapCoord var21 = (MapCoord) var20.next();
EaglerAdapter.glPushMatrix();

View File

@ -1017,6 +1017,8 @@ public class NetClientHandler extends NetHandler {
ItemMap.readAyunamiMapPacket(this.mc.theWorld, par1Packet131MapData.uniqueID, par1Packet131MapData.itemData);
} else if (par1Packet131MapData.itemID == 104) {
ItemMap.processVideoMap(this.mc.theWorld, par1Packet131MapData.itemData);
} else if (par1Packet131MapData.itemID == 105) {
ItemMap.processImageMap(this.mc.theWorld, par1Packet131MapData.itemData);
} else {
System.err.println("Unknown itemid: " + par1Packet131MapData.itemID);
}

View File

@ -35,6 +35,7 @@ import org.teavm.jso.dom.html.HTMLCanvasElement;
import org.teavm.jso.dom.html.HTMLDocument;
import org.teavm.jso.dom.html.HTMLElement;
import org.teavm.jso.dom.html.HTMLVideoElement;
import org.teavm.jso.dom.html.HTMLImageElement;
import org.teavm.jso.media.MediaError;
import org.teavm.jso.typedarrays.ArrayBuffer;
import org.teavm.jso.typedarrays.Float32Array;
@ -886,7 +887,7 @@ public class EaglerAdapterImpl2 {
public static final boolean isWindows() {
return getString("window.navigator.platform").toLowerCase().contains("win");
}
private static HTMLVideoElement currentVideo = null;
private static TextureGL videoTexture = null;
private static boolean videoIsLoaded = false;
@ -1188,6 +1189,171 @@ public class EaglerAdapterImpl2 {
frameRate = 1;
}
}
private static HTMLImageElement currentImage = null;
private static TextureGL imageTexture = null;
private static boolean imageIsLoaded = false;
private static boolean imageTexIsInitialized = false;
private static int imageFrameRate = 33;
private static long imageFrameTimer = 0l;
public static final boolean isImageSupported() {
return true;
}
public static final void loadImage(String src) {
loadImage(src, null);
}
public static final void loadImage(String src, String setJavascriptPointer) {
loadImage(src, setJavascriptPointer, null);
}
@JSBody(params = { "ptr", "el" }, script = "window[ptr] = el;")
private static native void setImagePointer(String ptr, HTMLImageElement el);
@JSBody(params = { "ptr", "el" }, script = "window[ptr](el);")
private static native void callImageLoadEvent(String ptr, HTMLImageElement el);
public static final void loadImage(String src, String setJavascriptPointer, final String javascriptOnloadFunction) {
imageIsLoaded = false;
imageTexIsInitialized = false;
if(imageTexture == null) {
imageTexture = _wglGenTextures();
}
if(currentImage != null) {
currentImage.setSrc("");
}
BufferedImageElem img = imagesBuffer.get(src);
if(img != null) {
currentImage = img.imageElement;
imagesBuffer.remove(src);
}else {
currentImage = (HTMLImageElement) win.getDocument().createElement("img");
currentImage.setAttribute("crossorigin", "anonymous");
}
if(setJavascriptPointer != null) {
setImagePointer(setJavascriptPointer, currentImage);
}
currentImage.addEventListener("load", new EventListener<Event>() {
@Override
public void handleEvent(Event evt) {
imageIsLoaded = true;
if(javascriptOnloadFunction != null) {
callImageLoadEvent(javascriptOnloadFunction, currentImage);
}
}
});
if(img == null) {
currentImage.setSrc(src);
}
}
private static class BufferedImageElem {
protected final HTMLImageElement imageElement;
protected final String url;
protected final long requestedTime;
protected final int ttl;
public BufferedImageElem(HTMLImageElement imageElement, String url, int ttl) {
this.imageElement = imageElement;
this.url = url;
this.requestedTime = System.currentTimeMillis();
this.ttl = ttl;
}
}
private static final HashMap<String, BufferedImageElem> imagesBuffer = new HashMap();
public static final void bufferImage(String src, int ttl) {
if(!imagesBuffer.containsKey(src)) {
HTMLImageElement image = (HTMLImageElement) win.getDocument().createElement("img");
image.setAttribute("crossorigin", "anonymous");
image.setSrc(src);
imagesBuffer.put(src, new BufferedImageElem(image, src, ttl));
}
}
public static final void unloadImage() {
if(imageTexture != null) {
_wglDeleteTextures(imageTexture);
imageTexture = null;
}
if(currentImage != null) {
currentImage.setSrc("");
currentImage = null;
}
}
public static final boolean isImageLoaded() {
return imageTexture != null && currentImage != null && imageIsLoaded;
}
@JSBody(
params = {"ctx", "target", "internalformat", "format", "type", "image"},
script = "ctx.texImage2D(target, 0, internalformat, format, type, image);"
)
private static native void html5ImageTexImage2D(WebGL2RenderingContext ctx, int target, int internalformat, int format, int type, HTMLImageElement image);
@JSBody(
params = {"ctx", "target", "format", "type", "image"},
script = "ctx.texSubImage2D(target, 0, 0, 0, format, type, image);"
)
private static native void html5ImageTexSubImage2D(WebGL2RenderingContext ctx, int target, int format, int type, HTMLImageElement image);
public static final void updateImageTexture() {
long ms = System.currentTimeMillis();
if(ms - imageFrameTimer < imageFrameRate && imageTexIsInitialized) {
return;
}
imageFrameTimer = ms;
if(currentImage != null && imageTexture != null && imageIsLoaded) {
try {
_wglBindTexture(_wGL_TEXTURE_2D, imageTexture);
if(imageTexIsInitialized) {
html5ImageTexSubImage2D(webgl, _wGL_TEXTURE_2D, _wGL_RGBA, _wGL_UNSIGNED_BYTE, currentImage);
}else {
html5ImageTexImage2D(webgl, _wGL_TEXTURE_2D, _wGL_RGBA, _wGL_RGBA, _wGL_UNSIGNED_BYTE, currentImage);
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_S, _wGL_CLAMP);
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_WRAP_T, _wGL_CLAMP);
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MIN_FILTER, _wGL_LINEAR);
_wglTexParameteri(_wGL_TEXTURE_2D, _wGL_TEXTURE_MAG_FILTER, _wGL_LINEAR);
imageTexIsInitialized = true;
}
}catch(Throwable t) {
// rip
}
}
}
public static final void bindImageTexture() {
if(imageTexture != null) {
_wglBindTexture(_wGL_TEXTURE_2D, imageTexture);
}
}
public static final int getImageWidth() {
if(currentImage != null && imageIsLoaded) {
return currentImage.getWidth();
}else {
return -1;
}
}
public static final int getImageHeight() {
if(currentImage != null && imageIsLoaded) {
return currentImage.getHeight();
}else {
return -1;
}
}
public static final void setImageFrameRate(float fps) {
frameRate = (int)(1000.0f / fps);
if(frameRate < 1) {
frameRate = 1;
}
}
private static MouseEvent currentEvent = null;
private static KeyboardEvent currentEventK = null;