0

首先,我知道 libgdx 主要用于游戏。我刚刚发现它并想尝试给它一个额外的(可能的)目的,例如一个简单的相框。下面的代码只是概念证明的一部分,当它运行时它应该演变成一个更大的应用程序。

下面我发布了一个非常简单的课程。它所做的是每隔 [num] 秒,在不同的线程中,它从磁盘加载图像,将其放入像素图中并在 GL 线程上从它创建纹理(如果我正确理解所有内容)。

经过大量试验和错误后,我得到了这段代码,我花了一个小时才发现应该在 OpenGL 线程中创建纹理。当纹理在线程外部创建时,图像中只有大黑框而没有加载纹理。

好吧,当我用线程上创建的纹理运行这个类版本时,我终于看到图像显示,并且每隔 [num] 秒就会很好地褪色。

但是,在 15 次执行之后,图像开始再次显示为黑框,就好像纹理是在 GL 线程之外创建的一样。我没有在控制台中打印任何异常。

该应用程序在内存拆分为 128/128 的 Raspberry Pi 上运行。图像是 1920*1080 的 jpeg 图像(非渐进式)。内存使用按照top如下:
VIRT: 249m
RES: 37m
SHR: 10m 命令行为:java -Xmx128M -DPI=true -DLWJGJ_BACKEND=GLES -Djava.library.path=libs:/opt/vc/lib:。-类路径 *:。org.pidome.raspberry.mirrorclient.BootStrapper

我看到加载新图像时 RES 上升,但加载后又回到 37。

System.out.println("交换计数器:" +swapCounter); 线程运行时不断给我输出。

你们中的某个人能否指出我正确的方向来解决在 15 次迭代后纹理不再显示并且图像为纯黑色的问题?

这是我当前的代码(名称 PhotosActor 具有误导性,首先尝试将其作为 Actor 的结果):

public class PhotosActor {

    List<Image> images = new ArrayList<>();

    private String imgDir = "appimages/photos/";
    List<String> fileSet = new ArrayList<>();

    private final ScheduledExecutorService changeExecutor = Executors.newSingleThreadScheduledExecutor();

    Stage stage;

    int swapCounter = 0;

    public PhotosActor(Stage stage) {
        this.stage = stage;
    }

    public final void preload(){
        loadFileSet();
        changeExecutor.scheduleAtFixedRate(switchimg(), 10, 10, TimeUnit.SECONDS);
    }

    private Runnable switchimg(){
        Runnable run = () -> {
            try {
                swapCounter++;
                FileInputStream input = new FileInputStream(fileSet.get(new Random().nextInt(fileSet.size())));
                Gdx2DPixmap gpm = new Gdx2DPixmap(input, Gdx2DPixmap.GDX2D_FORMAT_RGB888);
                input.close();
                Pixmap map = new Pixmap(gpm);
                Gdx.app.postRunnable(() -> {
                    System.out.println("Swap counter: " +swapCounter);
                    Texture tex = new Texture(map);
                    map.dispose();
                    Image newImg = new Image(tex);
                    newImg.addAction(Actions.sequence(Actions.alpha(0),Actions.fadeIn(1f),Actions.delay(5),Actions.run(() -> {
                        if(images.size()>1){
                            Image oldImg = images.remove(1);
                            oldImg.getActions().clear();
                            oldImg.remove();
                        }
                    })));
                    images.add(0,newImg);
                    stage.addActor(newImg);
                    newImg.toBack();
                    if(images.size()>1){ images.get(1).toBack(); }
                });
            } catch (Exception ex) {
                Logger.getLogger(PhotosActor.class.getName()).log(Level.SEVERE, null, ex);
            }
        };
        return run;
    }

    private void loadFileSet(){
        File[] files = new File(imgDir).listFiles();
        for (File file : files) {
            if (file.isFile()) {
                System.out.println("Loading: " + imgDir + file.getName());
                fileSet.add(imgDir + file.getName());
            }
        }
    }


}

提前感谢和欢呼,约翰。

4

1 回答 1

1

我能够自己解决这个问题,几分钟前我突然意识到我必须处理纹理。我相信删除图像也会删除纹理。它显然没有(或者我必须更新到更新的版本)。

所以我所做的是创建一个扩展图像类的新类:

public class PhotoImage extends Image {

    Texture tex;

    public PhotoImage(Texture tex){
        super(tex);
        this.tex = tex;
    }

    public void dispose(){
        try {
            this.tex.dispose();
        } catch(Exception ex){
            System.out.println(ex.getMessage());
        }
    }
}

在我引用图像类的所有位置上,我将其更改为这个 PhotoImage 类。类修改了一些现在看起来像:

public class PhotosActor {

    List<PhotoImage> images = new ArrayList<>();

    private String imgDir = "appimages/photos/";
    List<String> fileSet = new ArrayList<>();

    private final ScheduledExecutorService changeExecutor = Executors.newSingleThreadScheduledExecutor();

    Stage stage;

    int swapCounter = 0;

    public PhotosActor(Stage stage) {
        this.stage = stage;
    }

    public final void preload(){
        loadFileSet();
        changeExecutor.scheduleAtFixedRate(switchimg(), 10, 10, TimeUnit.SECONDS);
    }

    private Runnable switchimg(){
        Runnable run = () -> {
            try {
                swapCounter++;
                byte[] byteResult = readLocalRandomFile();
                Pixmap map = new Pixmap(byteResult, 0, byteResult.length);
                Gdx.app.postRunnable(() -> {
                    System.out.println("Swap counter: " +swapCounter);
                    Texture tex = new Texture(map);
                    map.dispose();
                    PhotoImage newImg = new PhotoImage(tex);
                    images.add(0,newImg);
                    stage.addActor(newImg);
                    addTransform(newImg);
                });
            } catch (Exception ex) {
                Logger.getLogger(PhotosActor.class.getName()).log(Level.SEVERE, null, ex);
            }
        };
        return run;
    }

    public void addTransform(Image img){
        switch(new Random().nextInt(3)){
            case 0:
                img.toBack();
                if(images.size()>1){ images.get(1).toBack(); }
                img.addAction(Actions.sequence(Actions.alpha(0),Actions.fadeIn(1f),Actions.delay(5),Actions.run(() -> {
                    removeOldImg();
                })));
            break;
            case 1:
                img.toBack();
                if(images.size()>1){ images.get(1).toBack(); }
                img.setPosition(1920f, 1080f);
                img.addAction(Actions.sequence(Actions.moveTo(0f, 0f, 5f),Actions.run(() -> {
                    removeOldImg();
                })));
            break;
            case 2:
                img.toBack();
                if(images.size()>1){ images.get(1).toBack(); }
                img.setScale(0f, 0f);
                img.setPosition(960f, 540f);
                img.addAction(Actions.sequence(Actions.parallel(Actions.scaleTo(1f, 1f, 5f), Actions.moveTo(0f, 0f, 5f)),Actions.run(() -> {
                    removeOldImg();
                })));
            break;
        }
    }

    private void removeOldImg(){
        if(images.size()>1){
            PhotoImage oldImg = images.remove(1);
            oldImg.remove();
            oldImg.getActions().clear();
            oldImg.dispose();
        }
        System.out.println("Amount of images: " + images.size());
    }

    private byte[] readLocalRandomFile() throws Exception{
        FileInputStream input = null;
        try {
            input = new FileInputStream(fileSet.get(new Random().nextInt(fileSet.size())));
            ByteArrayOutputStream out;
            try (InputStream in = new BufferedInputStream(input)) {
                out = new ByteArrayOutputStream();
                byte[] buf = new byte[1024];
                int n = 0;
                while (-1 != (n = in.read(buf))) {
                    out.write(buf, 0, n);
                }   
                out.close();
                return out.toByteArray();
            } catch (IOException ex) {
                Logger.getLogger(PhotosActor.class.getName()).log(Level.SEVERE, null, ex);
            }
        } catch (FileNotFoundException ex) {
            Logger.getLogger(PhotosActor.class.getName()).log(Level.SEVERE, null, ex);
        }
        throw new Exception("No data");
    }

    private void loadFileSet(){
        File[] files = new File(imgDir).listFiles();
        for (File file : files) {
            if (file.isFile()) {
                System.out.println("Loading: " + imgDir + file.getName());
                fileSet.add(imgDir + file.getName());
            }
        }
    }


}

在我现在添加的删除功能中

oldImg.dispose();

摆脱纹理。图像转换现在可以在 Raspberry Pi 上以 50+ fps 的速度运行,并且图像旋转计数器开启:现在为 88。如果那里有人想谢谢你的时间!

于 2015-01-31T19:25:56.083 回答