Libgdx 来自像素图的图像绘制为纯黑色
Libgdx images from pixmaps are drawn solid black
首先,我知道 libgdx 主要用于游戏。我刚刚发现它并想尝试给它一个额外的(可能的)用途,例如一个简单的相框。下面的代码只是概念验证的一部分,当它 运行 应该演变成更大的应用程序时。
下面我发布了一个非常简单的 class 我目前的状态。它所做的是每隔 [num] 秒,在不同的线程中,它从磁盘加载图像,将其放入像素图中并在 GL 线程上从中创建纹理(如果我理解正确的话)。
经过反复试验,我找到了这段代码,我花了一个小时才发现应该在 OpenGL 线程中创建纹理。当在线程外创建纹理时,图像中只有没有加载纹理的大黑框。
好吧,当我 运行 这个 class 版本在线程上创建纹理时,我终于看到了图像显示,并且每隔 [num] 秒就很好地淡化。
但是,在执行 15 次之后,图像开始再次显示为黑框,就好像纹理是在 GL 线程之外创建的一样。我没有在控制台中打印任何异常。
应用程序 运行 在 Raspberry Pi 上运行,内存拆分为 128/128。图像是 1920*1080(非渐进)的 jpeg 图像。内存占用根据top如下:
VIRT:249 米
分辨率:37m
SHR:10m
命令行是:java -Xmx128M -DPI=true -DLWJGJ_BACKEND=GLES -Djava.library.path=libs:/opt/vc/lib:。 -class路径*:. org.pidome.raspberry.mirrorclient.BootStrapper
我看到加载新图像时 RES 上升,但加载后又回到 37。
System.out.println("Swap counter: " +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());
}
}
}
}
提前致谢并干杯,
约翰.
我能够自己解决这个问题,几分钟前我突然想到我必须处理纹理。我相信删除图像也会删除纹理。它显然没有(或者我必须更新到更新的版本)。
所以我所做的是创建一个新的 class 扩展图像 class:
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());
}
}
}
在我引用图片的所有位置上 class 我将其更改为这张图片 class。 class 修改了一些现在看起来像:
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。如果有人在思考感谢您的宝贵时间!
首先,我知道 libgdx 主要用于游戏。我刚刚发现它并想尝试给它一个额外的(可能的)用途,例如一个简单的相框。下面的代码只是概念验证的一部分,当它 运行 应该演变成更大的应用程序时。
下面我发布了一个非常简单的 class 我目前的状态。它所做的是每隔 [num] 秒,在不同的线程中,它从磁盘加载图像,将其放入像素图中并在 GL 线程上从中创建纹理(如果我理解正确的话)。
经过反复试验,我找到了这段代码,我花了一个小时才发现应该在 OpenGL 线程中创建纹理。当在线程外创建纹理时,图像中只有没有加载纹理的大黑框。
好吧,当我 运行 这个 class 版本在线程上创建纹理时,我终于看到了图像显示,并且每隔 [num] 秒就很好地淡化。
但是,在执行 15 次之后,图像开始再次显示为黑框,就好像纹理是在 GL 线程之外创建的一样。我没有在控制台中打印任何异常。
应用程序 运行 在 Raspberry Pi 上运行,内存拆分为 128/128。图像是 1920*1080(非渐进)的 jpeg 图像。内存占用根据top如下:
VIRT:249 米
分辨率:37m
SHR:10m
命令行是:java -Xmx128M -DPI=true -DLWJGJ_BACKEND=GLES -Djava.library.path=libs:/opt/vc/lib:。 -class路径*:. org.pidome.raspberry.mirrorclient.BootStrapper
我看到加载新图像时 RES 上升,但加载后又回到 37。
System.out.println("Swap counter: " +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());
}
}
}
}
提前致谢并干杯, 约翰.
我能够自己解决这个问题,几分钟前我突然想到我必须处理纹理。我相信删除图像也会删除纹理。它显然没有(或者我必须更新到更新的版本)。
所以我所做的是创建一个新的 class 扩展图像 class:
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());
}
}
}
在我引用图片的所有位置上 class 我将其更改为这张图片 class。 class 修改了一些现在看起来像:
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。如果有人在思考感谢您的宝贵时间!