this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

AssetsPanel: add transparent map thumbnails

+149 -77
+3 -1
src/main/java/app/Environment.java
··· 49 49 import project.ui.ProjectSwitcherDialog; 50 50 import assets.AssetExtractor; 51 51 import assets.ExpectedAsset; 52 + import assets.ui.MapAsset; 52 53 import dev.kdl.parse.KdlParseException; 53 54 import game.ProjectDatabase; 54 55 import game.entity.EntityExtractor; ··· 262 263 ProjectListing listing = chooseProject(); 263 264 if (listing == null) 264 265 exit(); 265 - LoadingBar.show("Loading " + listing.getName(), true); 266 + LoadingBar.show("Loading " + listing.getName(), Priority.MILESTONE, false); 266 267 boolean validProject = loadProject(listing); 267 268 if (!validProject) 268 269 exit(1); ··· 539 540 540 541 reloadIcons(); 541 542 ProjectDatabase.initialize(); 543 + MapAsset.generateMissingThumbnails(); 542 544 543 545 ProjectManager.getInstance().recordProjectOpened(project); 544 546 return true;
-28
src/main/java/app/StarRodMain.java
··· 379 379 dialog.startBuild(); 380 380 } 381 381 382 - private void action_captureThumbnails() 383 - { 384 - new EditorWorker(() -> { 385 - Logger.log("Capturing missing map thumbnails...", Priority.MILESTONE); 386 - MapEditor editor = null; 387 - 388 - try { 389 - editor = new MapEditor(false); 390 - 391 - for (File f : AssetManager.getMapSources()) { 392 - String mapName = FilenameUtils.getBaseName(f.getName()); 393 - File thumbFile = new File(PROJ_THUMBNAIL + mapName + ".jpg"); 394 - if (thumbFile.exists()) 395 - continue; 396 - Logger.log("Capturing thumbnail for " + mapName + "...", Priority.MILESTONE); 397 - editor.generateThumbnail(f, thumbFile); 398 - } 399 - } 400 - catch (Exception e) { 401 - Logger.printStackTrace(e); 402 - } 403 - finally { 404 - if (editor != null) 405 - editor.shutdownThumbnail(); 406 - } 407 - }); 408 - } 409 - 410 382 private void action_openDir(File dir) 411 383 { 412 384 if (dir.exists()) {
+29
src/main/java/app/pane/AssetsPanel.java
··· 7 7 import java.awt.Font; 8 8 import java.awt.Graphics; 9 9 import java.awt.Graphics2D; 10 + import java.awt.Image; 10 11 import java.awt.RenderingHints; 11 12 import java.awt.event.MouseAdapter; 12 13 import java.awt.event.MouseEvent; 14 + import java.awt.image.BufferedImage; 13 15 import java.io.File; 14 16 import java.io.IOException; 15 17 import java.nio.file.FileSystems; ··· 21 23 import java.util.ArrayList; 22 24 import java.util.List; 23 25 26 + import javax.swing.ImageIcon; 24 27 import javax.swing.JLabel; 25 28 import javax.swing.JPanel; 26 29 import javax.swing.JScrollPane; 27 30 import javax.swing.SwingUtilities; 31 + import javax.swing.SwingWorker; 28 32 import javax.swing.UIManager; 29 33 30 34 import app.Environment; ··· 250 254 JPanel panel = createItemPanel(); 251 255 252 256 JLabel icon = new JLabel(ThemedIcon.PACKAGE_24); 257 + 258 + // Load thumbnail asynchronously 259 + new SwingWorker<BufferedImage, Void>() { 260 + @Override 261 + protected BufferedImage doInBackground() 262 + { 263 + return asset.loadThumbnail(); 264 + } 265 + 266 + @Override 267 + protected void done() 268 + { 269 + try { 270 + BufferedImage thumb = get(); 271 + if (thumb != null) { 272 + Image scaled = thumb.getScaledInstance(64, -1, Image.SCALE_FAST); 273 + icon.setIcon(new ImageIcon(scaled)); 274 + panel.revalidate(); 275 + } 276 + } 277 + catch (Exception e) { 278 + // ignore — keep default icon 279 + } 280 + } 281 + }.execute(); 253 282 254 283 JLabel name = new JLabel(asset.getAssetName()); 255 284 name.setPreferredSize(new Dimension(80, 20));
+9
src/main/java/assets/AssetHandle.java
··· 1 1 package assets; 2 2 3 + import java.awt.image.BufferedImage; 3 4 import java.io.File; 4 5 5 6 import assets.ui.BackgroundAsset; ··· 34 35 } 35 36 36 37 public String getAssetDescription() { 38 + return null; 39 + } 40 + 41 + /** 42 + * Loads a thumbnail image for this asset. 43 + * Returns null if no thumbnail is available. 44 + */ 45 + public BufferedImage loadThumbnail() { 37 46 return null; 38 47 } 39 48
+6
src/main/java/assets/ui/BackgroundAsset.java
··· 27 27 } 28 28 } 29 29 30 + @Override 31 + public BufferedImage loadThumbnail() 32 + { 33 + return thumbnail; 34 + } 35 + 30 36 private static BufferedImage resizeImage(BufferedImage src, int targetHeight) 31 37 { 32 38 float ratio = ((float) src.getHeight() / (float) src.getWidth());
+52
src/main/java/assets/ui/MapAsset.java
··· 1 1 package assets.ui; 2 2 3 + import static app.Directories.PROJ_THUMBNAIL; 4 + 5 + import java.awt.image.BufferedImage; 3 6 import java.io.BufferedReader; 7 + import java.io.File; 4 8 import java.io.FileReader; 5 9 import java.io.IOException; 10 + 6 11 import java.util.regex.Matcher; 7 12 import java.util.regex.Pattern; 8 13 14 + import javax.imageio.ImageIO; 15 + 9 16 import app.Environment; 10 17 import assets.AssetHandle; 11 18 import assets.AssetManager; 12 19 import game.map.Map; 20 + import game.map.editor.MapEditor; 13 21 import util.Logger; 22 + import util.Priority; 14 23 15 24 public class MapAsset extends AssetHandle 16 25 { ··· 73 82 @Override 74 83 public String getAssetDescription() { 75 84 return desc; 85 + } 86 + 87 + @Override 88 + public BufferedImage loadThumbnail() 89 + { 90 + File thumbFile = new File(PROJ_THUMBNAIL + assetPath + ".png"); 91 + if (thumbFile.exists()) { 92 + try { 93 + return ImageIO.read(thumbFile); 94 + } 95 + catch (IOException e) { 96 + return null; 97 + } 98 + } 99 + return null; 100 + } 101 + 102 + /** 103 + * Generates thumbnails for all maps that don't already have one. 104 + * Creates a MapEditor instance, so must not be called while one is open. 105 + */ 106 + public static void generateMissingThumbnails() 107 + { 108 + MapEditor editor = null; 109 + 110 + try { 111 + for (AssetHandle asset : AssetManager.getMapSources()) { 112 + File thumbFile = new File(PROJ_THUMBNAIL + asset.assetPath + ".png"); 113 + if (thumbFile.exists()) 114 + continue; 115 + Logger.log("Capturing thumbnail for " + asset.assetPath + "...", Priority.MILESTONE); 116 + if (editor == null) 117 + editor = new MapEditor(false); 118 + editor.generateThumbnail(asset, thumbFile); 119 + } 120 + } 121 + catch (Exception e) { 122 + Logger.printStackTrace(e); 123 + } 124 + finally { 125 + if (editor != null) 126 + editor.shutdownThumbnail(); 127 + } 76 128 } 77 129 }
+26 -40
src/main/java/game/map/editor/MapEditor.java
··· 4 4 import static game.map.MapKey.*; 5 5 import static game.map.editor.EditorShortcut.*; 6 6 import static org.lwjgl.opengl.GL11.*; 7 + import static org.lwjgl.opengl.GL30.*; 7 8 8 9 import java.awt.Dimension; 9 - import java.awt.Graphics2D; 10 10 import java.awt.KeyEventDispatcher; 11 11 import java.awt.KeyboardFocusManager; 12 - import java.awt.RenderingHints; 13 12 import java.awt.Toolkit; 14 13 import java.awt.Window; 15 14 import java.awt.event.KeyEvent; ··· 3446 3445 public RenderingOptions getRenderingOptions() 3447 3446 { 3448 3447 RenderingOptions opts = new RenderingOptions(); 3449 - opts.canvasSizeX = glCanvasPixelWidth(); 3450 - opts.canvasSizeY = glCanvasPixelHeight(); 3448 + if (thumbnailMode) { 3449 + opts.canvasSizeX = THUMBNAIL_SIZE; 3450 + opts.canvasSizeY = THUMBNAIL_SIZE; 3451 + } 3452 + else { 3453 + opts.canvasSizeX = glCanvasPixelWidth(); 3454 + opts.canvasSizeY = glCanvasPixelHeight(); 3455 + } 3451 3456 opts.editorMode = getEditorMode(); 3452 3457 opts.selectionMode = selectionManager.getSelectionMode(); 3453 3458 opts.worldFogEnabled = map.scripts.worldFogSettings.enabled.get(); ··· 3576 3581 obj.prepareVertexBuffers(opts); 3577 3582 } 3578 3583 3584 + private static final int THUMBNAIL_SIZE = 64; 3585 + 3579 3586 private void initThumbnail() 3580 3587 { 3581 3588 enableXDivider = false; ··· 3593 3600 useTextureLOD = true; 3594 3601 useMapBackgroundColor = true; 3595 3602 3603 + perspectiveView.resize(0, 0, THUMBNAIL_SIZE, THUMBNAIL_SIZE); 3604 + 3596 3605 thumbnailMode = true; 3597 3606 } 3598 3607 3599 3608 private void renderThumbnail(File thumbFile) 3600 3609 { 3601 3610 runInContext(() -> { 3602 - glReadBuffer(GL_FRONT); 3603 - int width = perspectiveView.maxX - perspectiveView.minX; 3604 - int height = perspectiveView.maxY - perspectiveView.minY; 3611 + glBindFramebuffer(GL_READ_FRAMEBUFFER, perspectiveView.getSceneFrameBuffer()); 3612 + glReadBuffer(GL_COLOR_ATTACHMENT0); 3605 3613 int bpp = 4; 3606 - ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * bpp); 3607 - glReadPixels(perspectiveView.minX, perspectiveView.minY, width, height, 3614 + ByteBuffer buffer = BufferUtils.createByteBuffer(THUMBNAIL_SIZE * THUMBNAIL_SIZE * bpp); 3615 + glReadPixels(0, 0, THUMBNAIL_SIZE, THUMBNAIL_SIZE, 3608 3616 GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, buffer); 3617 + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 3609 3618 3610 - BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); 3611 - for (int x = 0; x < width; x++) { 3612 - for (int y = 0; y < height; y++) { 3613 - int i = (x + (width * y)) * bpp; 3619 + BufferedImage image = new BufferedImage(THUMBNAIL_SIZE, THUMBNAIL_SIZE, BufferedImage.TYPE_INT_ARGB); 3620 + for (int x = 0; x < THUMBNAIL_SIZE; x++) { 3621 + for (int y = 0; y < THUMBNAIL_SIZE; y++) { 3622 + int i = (x + (THUMBNAIL_SIZE * y)) * bpp; 3614 3623 int r = buffer.get(i) & 0xFF; 3615 3624 int g = buffer.get(i + 1) & 0xFF; 3616 3625 int b = buffer.get(i + 2) & 0xFF; 3617 - image.setRGB(x, height - (y + 1), (0xFF << 24) | (r << 16) | (g << 8) | b); 3626 + int a = buffer.get(i + 3) & 0xFF; 3627 + image.setRGB(x, THUMBNAIL_SIZE - (y + 1), (a << 24) | (r << 16) | (g << 8) | b); 3618 3628 } 3619 3629 } 3620 - 3621 - image = resizeImage(image, 480); 3622 3630 3623 3631 try { 3624 - FileUtils.touch(thumbFile); 3625 - ImageIO.write(image, "JPG", thumbFile); 3632 + FileUtils.forceMkdirParent(thumbFile); 3633 + ImageIO.write(image, "PNG", thumbFile); 3626 3634 } 3627 3635 catch (IOException e) { 3628 3636 Logger.printStackTrace(e); 3629 3637 } 3630 3638 }); 3631 - } 3632 - 3633 - private static BufferedImage resizeImage(BufferedImage src, int targetSize) 3634 - { 3635 - if (targetSize <= 0) { 3636 - return src; // this can't be resized 3637 - } 3638 - int targetWidth = targetSize; 3639 - int targetHeight = targetSize; 3640 - float ratio = ((float) src.getHeight() / (float) src.getWidth()); 3641 - if (ratio <= 1) { // square or landscape-oriented image 3642 - targetHeight = (int) Math.ceil(targetWidth * ratio); 3643 - } 3644 - else { // portrait image 3645 - targetWidth = Math.round(targetHeight / ratio); 3646 - } 3647 - BufferedImage bi = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB); 3648 - Graphics2D g2d = bi.createGraphics(); 3649 - g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 3650 - g2d.drawImage(src, 0, 0, targetWidth, targetHeight, null); 3651 - g2d.dispose(); 3652 - return bi; 3653 3639 } 3654 3640 3655 3641 private void setViewMode(ViewMode mode)
+14 -6
src/main/java/game/map/editor/camera/PerspectiveViewport.java
··· 41 41 super(editor, renderer, ViewType.PERSPECTIVE); 42 42 wireframeMode = false; 43 43 44 - sceneBuffer = new FrameBuffer(true); 44 + sceneBuffer = new FrameBuffer(true, true); 45 45 effectBufferA = new FrameBuffer(false); 46 46 effectBufferB = new FrameBuffer(false); 47 47 } ··· 51 51 super(editor, renderer, ViewType.PERSPECTIVE, minX, minY, maxX, maxY); 52 52 wireframeMode = false; 53 53 camera = new PerspFreeCamera(this); 54 + } 55 + 56 + public int getSceneFrameBuffer() 57 + { 58 + return sceneBuffer.getFrameBuffer(); 54 59 } 55 60 56 61 public void setCamera(PerspBaseCamera cam) ··· 88 93 89 94 // clear whole buffer 90 95 RenderState.setViewport(0, 0, opts.canvasSizeX, opts.canvasSizeY); 91 - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 96 + glClearColor(0.0f, 0.0f, 0.0f, opts.thumbnailMode ? 0.0f : 1.0f); 92 97 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 93 98 94 99 // draw the actual viewport contents ··· 143 148 144 149 // set viewport to final position and clear 145 150 RenderState.setViewport(minX, minY, sizeX, sizeY); 146 - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 151 + glClearColor(0.0f, 0.0f, 0.0f, opts.thumbnailMode ? 0.0f : 1.0f); 147 152 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 148 153 149 154 // render final viewport ··· 182 187 } 183 188 184 189 ScriptData scriptData = editor.map.scripts; 185 - if (editor.useMapBackgroundColor) 190 + if (opts.thumbnailMode) 191 + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); 192 + else if (editor.useMapBackgroundColor) 186 193 glClearColor(scriptData.bgColorR.get() / 255.0f, scriptData.bgColorG.get() / 255.0f, scriptData.bgColorB.get() / 255.0f, 1.0f); 187 194 else 188 195 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); ··· 190 197 191 198 Renderer.setFogEnabled(editor.map.scripts, editor.usingInGameCameraProperties()); 192 199 193 - if (!wireframeMode && (editor.map.hasBackground || !editor.useMapBackgroundColor)) 200 + if (!opts.thumbnailMode && !wireframeMode && (editor.map.hasBackground || !editor.useMapBackgroundColor)) 194 201 camera.drawBackground(); 195 202 196 203 camera.glLoadProjection(); ··· 288 295 if (opts.screenFade != 0.0f) 289 296 renderFade(0.0f, 0.0f, 0.0f, opts.screenFade); 290 297 291 - renderUI(); 298 + if (!opts.thumbnailMode) 299 + renderUI(); 292 300 293 301 if (doPerspProfiling) 294 302 profiler.record("lines");
+10 -2
src/main/java/renderer/FrameBuffer.java
··· 13 13 { 14 14 private final int frameBuffer; 15 15 private final boolean hasDepth; 16 + private final boolean hasAlpha; 16 17 17 18 private int colorTexture; 18 19 private int depthTexture; ··· 26 27 public int viewMaxY; 27 28 28 29 public FrameBuffer(boolean hasDepth) 30 + { 31 + this(hasDepth, false); 32 + } 33 + 34 + public FrameBuffer(boolean hasDepth, boolean hasAlpha) 29 35 { 30 36 this.hasDepth = hasDepth; 37 + this.hasAlpha = hasAlpha; 31 38 32 39 frameBuffer = glGenFramebuffers(); 33 40 glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer); ··· 45 52 glDeleteTextures(colorTexture); 46 53 glDeleteTextures(depthTexture); 47 54 55 + int colorFormat = hasAlpha ? GL_RGBA : GL_RGB; 48 56 colorTexture = glGenTextures(); 49 57 glBindTexture(GL_TEXTURE_2D, colorTexture); 50 - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, sizeX, sizeY, 51 - 0, GL_RGB, GL_UNSIGNED_BYTE, (ByteBuffer) null); 58 + glTexImage2D(GL_TEXTURE_2D, 0, colorFormat, sizeX, sizeY, 59 + 0, colorFormat, GL_UNSIGNED_BYTE, (ByteBuffer) null); 52 60 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 53 61 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 54 62 glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colorTexture, 0);