diff --git a/docs/src/progress/renderertodo.md b/docs/src/progress/renderertodo.md index 1198230e..e72bf300 100644 --- a/docs/src/progress/renderertodo.md +++ b/docs/src/progress/renderertodo.md @@ -1303,6 +1303,7 @@ Fix server terrain physics entity positioning Disable client fluid draw cell loading gate Properly differentiate local/world bone attach point calculation Floating origin implementation for collision engine +Improve initial asset loading performance @@ -1310,8 +1311,6 @@ Floating origin implementation for collision engine -Fix physics breaking at far-off locations - - separately simulated regions of physics that dynamically merge/unmerge based on chunk loading Implement gadgets - Chemistry System @@ -1332,6 +1331,10 @@ Implement gadgets - Torch - Throwable potions +Floating world origin + - Better criteria to update floating world origin in collision engine (can't run every frame cause very very expensive, but need to periodically check so it doesn't become irrelevant) + - Separately simulated regions of physics that dynamically merge/unmerge based on chunk loading + Bug Fixes - Fix hitbox placement does not scale with entity scale on server - Calculate bounding sphere for meshes by deforming vertices with bone default pose instead of no bone deform diff --git a/src/main/java/electrosphere/client/terrain/foliage/FoliageModel.java b/src/main/java/electrosphere/client/terrain/foliage/FoliageModel.java index 63b0b4d3..e54aa44f 100644 --- a/src/main/java/electrosphere/client/terrain/foliage/FoliageModel.java +++ b/src/main/java/electrosphere/client/terrain/foliage/FoliageModel.java @@ -15,6 +15,7 @@ import org.lwjgl.BufferUtils; import electrosphere.client.terrain.cache.ChunkData; import electrosphere.engine.Globals; import electrosphere.engine.assetmanager.queue.QueuedTexture; +import electrosphere.engine.assetmanager.queue.QueuedTexture.QueuedTextureType; import electrosphere.entity.ClientEntityUtils; import electrosphere.entity.Entity; import electrosphere.entity.EntityCreationUtils; @@ -214,7 +215,7 @@ public class FoliageModel { int textureWidth = (1 + (drawCount / MAX_TEXTURE_HEIGHT)) * (SINGLE_FOLIAGE_DATA_SIZE_BYTES / 4); //construct data texture - QueuedTexture queuedAsset = new QueuedTexture(buffer,textureWidth,textureHeight); + QueuedTexture queuedAsset = new QueuedTexture(QueuedTextureType.DATA_BUFF,buffer,textureWidth,textureHeight); Globals.assetManager.queuedAsset(queuedAsset); TextureInstancedActor.attachTextureInstancedActor(rVal, foliageType.getGraphicsTemplate().getModel().getPath(), vertexPath, fragmentPath, queuedAsset, drawCount, textureHeight); diff --git a/src/main/java/electrosphere/engine/assetmanager/queue/QueuedTexture.java b/src/main/java/electrosphere/engine/assetmanager/queue/QueuedTexture.java index e1834f03..8f5e99b3 100644 --- a/src/main/java/electrosphere/engine/assetmanager/queue/QueuedTexture.java +++ b/src/main/java/electrosphere/engine/assetmanager/queue/QueuedTexture.java @@ -3,6 +3,8 @@ package electrosphere.engine.assetmanager.queue; import java.awt.image.BufferedImage; import java.nio.ByteBuffer; +import org.lwjgl.BufferUtils; + import electrosphere.engine.Globals; import electrosphere.renderer.texture.Texture; @@ -11,6 +13,25 @@ import electrosphere.renderer.texture.Texture; */ public class QueuedTexture implements QueuedAsset { + /** + * The type of loading to perform with this queued texture + */ + public static enum QueuedTextureType { + /** + * Loading raw data as a texture + */ + DATA_BUFF, + /** + * Loading an actual image as a texture + */ + IMG_BUFF, + } + + /** + * The type of queued texture + */ + QueuedTextureType type; + /** * True if loaded */ @@ -46,34 +67,91 @@ public class QueuedTexture implements QueuedAsset { */ String promisedPath; - - /** - * Creates the queued texture object - * @param image the image to load to gpu - */ - public QueuedTexture(BufferedImage image){ - this.data = image; - } - /** * Creates the queued texture object * @param buffer The data to buffer * @param width The width of the buffer * @param height The height of the buffer */ - public QueuedTexture(ByteBuffer buffer, int width, int height){ + public QueuedTexture(QueuedTextureType type, ByteBuffer buffer, int width, int height){ + this.type = type; this.buffer = buffer; this.width = width; this.height = height; } + /** + * Creates the queued texture object + * @param image the image to load to gpu + */ + public static QueuedTexture createFromImage(BufferedImage bufferedImage){ + ByteBuffer data; + int width = 1; + int height = 1; + BufferedImage image_data = bufferedImage; + boolean hasTransparency = false; + if ( + image_data.getType() == BufferedImage.TYPE_3BYTE_BGR || + image_data.getType() == BufferedImage.TYPE_INT_RGB + ){ + hasTransparency = false; + } else if( + image_data.getType() == BufferedImage.TYPE_4BYTE_ABGR || + image_data.getType() == BufferedImage.TYPE_INT_ARGB + ){ + hasTransparency = true; + } + width = image_data.getWidth(); + height = image_data.getHeight(); + if(hasTransparency){ + data = BufferUtils.createByteBuffer(width * height * 4); + } else { + data = BufferUtils.createByteBuffer(width * height * 3); + } + for(int y = height - 1; y > -1; y--){ + for(int x = 0; x < width; x++){ + int color = image_data.getRGB(x, y); + + // data.put((byte)temp.getRed()); + // data.put((byte)temp.getGreen()); + // data.put((byte)temp.getBlue()); + if(hasTransparency){ + int blue = color & 0xff; + int green = (color & 0xff00) >> 8; + int red = (color & 0xff0000) >> 16; + int alpha = (color & 0xff000000) >>> 24; + data.put((byte)red); + data.put((byte)green); + data.put((byte)blue); + data.put((byte)alpha); + } else { + int blue = color & 0xff; + int green = (color & 0xff00) >> 8; + int red = (color & 0xff0000) >> 16; + data.put((byte)red); + data.put((byte)green); + data.put((byte)blue); + } + } + } + if(data.position() > 0){ + data.flip(); + } + QueuedTexture rVal = new QueuedTexture(QueuedTextureType.IMG_BUFF, data, width, height); + rVal.data = bufferedImage; + return rVal; + } + @Override public void load() { - if(data != null){ - texture = new Texture(Globals.renderingEngine.getOpenGLState(), data); - } else if(buffer != null){ - texture = new Texture(Globals.renderingEngine.getOpenGLState(),buffer,width,height); - this.buffer = null; + switch(this.type){ + case DATA_BUFF: { + texture = new Texture(Globals.renderingEngine.getOpenGLState(),buffer,width,height); + this.buffer = null; + } break; + case IMG_BUFF: { + texture = new Texture(Globals.renderingEngine.getOpenGLState(), data, buffer); + } break; } hasLoaded = true; } diff --git a/src/main/java/electrosphere/engine/loadingthreads/InitialAssetLoading.java b/src/main/java/electrosphere/engine/loadingthreads/InitialAssetLoading.java index 773141dc..0ccf9032 100644 --- a/src/main/java/electrosphere/engine/loadingthreads/InitialAssetLoading.java +++ b/src/main/java/electrosphere/engine/loadingthreads/InitialAssetLoading.java @@ -79,7 +79,7 @@ public class InitialAssetLoading { Globals.profiler.endCpuSample(); //queue to asset manager - atlasQueuedTexture = new QueuedTexture(image); + atlasQueuedTexture = QueuedTexture.createFromImage(image); Globals.assetManager.queuedAsset(atlasQueuedTexture); @@ -130,7 +130,7 @@ public class InitialAssetLoading { Globals.profiler.endCpuSample(); //queue to asset manager - atlasQueuedTexture = new QueuedTexture(image); + atlasQueuedTexture = QueuedTexture.createFromImage(image); Globals.assetManager.queuedAsset(atlasQueuedTexture); @@ -210,7 +210,7 @@ public class InitialAssetLoading { Globals.profiler.endCpuSample(); //queue to asset manager - atlasQueuedTexture = new QueuedTexture(image); + atlasQueuedTexture = QueuedTexture.createFromImage(image); Globals.assetManager.queuedAsset(atlasQueuedTexture); diff --git a/src/main/java/electrosphere/renderer/texture/Texture.java b/src/main/java/electrosphere/renderer/texture/Texture.java index bc37eee3..0840a72a 100644 --- a/src/main/java/electrosphere/renderer/texture/Texture.java +++ b/src/main/java/electrosphere/renderer/texture/Texture.java @@ -6,7 +6,6 @@ import electrosphere.renderer.OpenGLState; import electrosphere.renderer.RenderingEngine; import electrosphere.util.FileUtils; -import java.awt.Color; import java.awt.image.BufferedImage; import java.io.IOException; import java.nio.ByteBuffer; @@ -78,6 +77,7 @@ public class Texture { Globals.renderingEngine.checkError(); } + @Deprecated /** * Creates an in engine texture object from a java bufferedimage object * @param bufferedImage The java bufferedimage object @@ -120,13 +120,27 @@ public class Texture { } for(int y = height - 1; y > -1; y--){ for(int x = 0; x < width; x++){ - Color temp = new Color(image_data.getRGB(x, y), true); + int color = image_data.getRGB(x, y); - data.put((byte)temp.getRed()); - data.put((byte)temp.getGreen()); - data.put((byte)temp.getBlue()); + // data.put((byte)temp.getRed()); + // data.put((byte)temp.getGreen()); + // data.put((byte)temp.getBlue()); if(hasTransparency){ - data.put((byte)temp.getAlpha()); + int blue = color & 0xff; + int green = (color & 0xff00) >> 8; + int red = (color & 0xff0000) >> 16; + int alpha = (color & 0xff000000) >>> 24; + data.put((byte)red); + data.put((byte)green); + data.put((byte)blue); + data.put((byte)alpha); + } else { + int blue = color & 0xff; + int green = (color & 0xff00) >> 8; + int red = (color & 0xff0000) >> 16; + data.put((byte)red); + data.put((byte)green); + data.put((byte)blue); } } } @@ -156,6 +170,62 @@ public class Texture { openGlState.glBindTexture(GL_TEXTURE_2D, 0); } + /** + * Creates an in engine texture object from a java bufferedimage object + * @param bufferedImage The java bufferedimage object + * @param data The pre-parsed buffer of data from the buffered image + */ + public Texture(OpenGLState openGlState, BufferedImage bufferedImage, ByteBuffer data){ + this.texturePointer = GL40.glGenTextures(); + Globals.renderingEngine.checkError(); + //bind the new texture + openGlState.glBindTexture(GL_TEXTURE_2D, texturePointer); + //how are we gonna wrap the texture?? + this.setWrap(openGlState, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); + this.setWrap(openGlState, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); + //set the border color to black + this.setBorderColor(openGlState, new float[]{ 0.0f, 0.0f, 0.0f, 1.0f }); + //set magnification and minification operation sampling strategies + this.setMinFilter(openGlState, GL_LINEAR); + this.setMagFilter(openGlState, GL_LINEAR); + //load the image here + BufferedImage image_data = bufferedImage; + if ( + image_data.getType() == BufferedImage.TYPE_3BYTE_BGR || + image_data.getType() == BufferedImage.TYPE_INT_RGB + ){ + hasTransparency = false; + } else if( + image_data.getType() == BufferedImage.TYPE_4BYTE_ABGR || + image_data.getType() == BufferedImage.TYPE_INT_ARGB + ){ + hasTransparency = true; + } + width = image_data.getWidth(); + height = image_data.getHeight(); + //call if width != height so opengl figures out how to unpack it properly + if(width != height){ + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + } + //buffer the texture information + if(hasTransparency){ + this.pixelFormat = GL_RGBA; + this.datatype = GL_UNSIGNED_BYTE; + this.glTexImage2D(openGlState, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); + } else { + this.pixelFormat = GL_RGB; + this.datatype = GL_UNSIGNED_BYTE; + this.glTexImage2D(openGlState, width, height, GL_RGB, GL_UNSIGNED_BYTE, data); + } + glGenerateMipmap(GL_TEXTURE_2D); + //check build status + String errorMessage = RenderingEngine.getErrorInEnglish(Globals.renderingEngine.getError()); + if(errorMessage != null){ + LoggerInterface.loggerRenderer.ERROR(new IllegalStateException("Texture Constructor[from bufferedimage]: " + errorMessage)); + } + openGlState.glBindTexture(GL_TEXTURE_2D, 0); + } + /** * Creates a texture from an existing file * @param path The path to the image file