【问题标题】:Cloning 60FPS game into four screen将60FPS游戏克隆成四屏
【发布时间】:2020-02-19 09:17:01
【问题描述】:

我有多个游戏以每秒 60 帧的速度运行。我需要捕获每一帧并使用特定的过滤器克隆到四个不同的屏幕中。

软件将在双屏显示器上运行,主屏幕和副屏幕将分别负责运行游戏和显示四个过滤视图。

应用过滤器的限制:

  • 过滤器仅适用于图像。
  • 过滤器是用java编写的,几乎不可能重写。

所以我正在应用如下逻辑:

import java.awt.*;    
import javax.swing.ImageIcon;
import javax.swing.JFrame;    
import com.sun.jna.platform.win32.GDI32Util;
import com.sun.jna.platform.win32.WinDef.HWND;

import java.awt.image.BufferedImage;

public class MultiFrameApplet implements Runnable
{     
    public JFrame currentFrame = null;
    public PanelPaint currentCanvas = null; 
    public BufferedImage screenshotImage = null;
    com.sun.jna.platform.win32.User32 user32 = null;
    HWND hwnd = null;
    Thread th = null;
    String CurrentFrameText = "";
    private long lastTime;
    private double fps; //could be int or long for integer values
    public MultiFrameApplet(int filtertype)
    { 
        main(null,filtertype);      
    }     

    public void main(String[] argv,int filtertype) 
    {   
        try
        {
           GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
           GraphicsDevice[] gd = ge.getScreenDevices();

           //First Screen
           GraphicsConfiguration gcFirst = gd[0].getDefaultConfiguration();
           Toolkit toolkit = Toolkit.getDefaultToolkit();
           if (toolkit == null) 
           {
               return;
           }       
           Rectangle screenRectFirst = gcFirst.getBounds();
           Insets screenInsetsFirst = toolkit.getScreenInsets(gcFirst);
           screenRectFirst.x = screenInsetsFirst.left;
           screenRectFirst.y = screenInsetsFirst.top;

           Robot robot = new Robot(gcFirst.getDevice());

           //Second Screen
           GraphicsConfiguration gcSecond = gd[1].getDefaultConfiguration();               
           Rectangle screenRectSecond = gcSecond.getBounds();
           Insets screenInsetsSecond = Toolkit.getDefaultToolkit().getScreenInsets(gcSecond);       
           Rectangle effectiveScreenArea = new Rectangle();

           /*Remove start bar area*/
           effectiveScreenArea.x = screenRectSecond.x + screenInsetsSecond.left;
           effectiveScreenArea.y = screenRectSecond.y + screenInsetsSecond.top;
           effectiveScreenArea.height = screenRectSecond.height - screenInsetsSecond.top - screenInsetsSecond.bottom;        
           effectiveScreenArea.width = screenRectSecond.width - screenInsetsSecond.left - screenInsetsSecond.right;

           //Scaling will decide capture image needs to shrink or not.!
           double xscaling = 0;
           double yscaling = 0;

           screenshotImage = robot.createScreenCapture(screenRectFirst);

           int differenceWidth = screenRectSecond.width / screenRectFirst.width;
           int differenceheight = screenRectSecond.height / screenRectFirst.height;
           xscaling = differenceWidth / 2.0;
           yscaling = differenceheight / 2.0;   

            yscaling = yscaling - 0.018;

           currentFrame =  new JFrame(); 

           currentFrame.setSize((int)effectiveScreenArea.width/2, (int)effectiveScreenArea.height/2); 
           if(filtertype == 0)
           {
               currentFrame.setLocation(effectiveScreenArea.x, effectiveScreenArea.y); 
               currentFrame.setTitle("First");
               CurrentFrameText = "First";
           }
           else if(filtertype == 1)
           {
               currentFrame.setLocation(effectiveScreenArea.x + ((int)effectiveScreenArea.width/2), effectiveScreenArea.y); 
               currentFrame.setTitle("Second");
               CurrentFrameText = "Second";
           }
           else if(filtertype == 2)
           {
               currentFrame.setLocation(effectiveScreenArea.x + ((int)effectiveScreenArea.width/2), effectiveScreenArea.y); 
               currentFrame.setTitle("Third");
               CurrentFrameText = "Third";
           } 
           else if(filtertype == 3)
           {
               currentFrame.setLocation(effectiveScreenArea.x + ((int)effectiveScreenArea.width/2),effectiveScreenArea.y + ((int)effectiveScreenArea.height/2)); 
               currentFrame.setTitle("Forth");
               CurrentFrameText = "Forth";
           } 


           currentCanvas = new PanelPaint((int)effectiveScreenArea.width/2,(int)effectiveScreenArea.height/2,xscaling,yscaling,CurrentFrameText); 
           currentCanvas.xpos = (int)effectiveScreenArea.width/2;
           currentCanvas.ypos = (int)effectiveScreenArea.height/2;
           currentFrame.getContentPane().add(currentCanvas); 


           currentFrame.setUndecorated(true);        
           currentFrame.setVisible(true);       

            user32 = com.sun.jna.platform.win32.User32.INSTANCE;
           hwnd = user32.GetDesktopWindow();

           th = new Thread(this);
           th.start();     

        }
        catch (AWTException e) 
        {
           // TODO Auto-generated catch block
           e.printStackTrace();
        }
        catch (Exception e) 
        { 
            // TODO Auto-generated catch block
             e.printStackTrace();

        }
    }       
    public void close()
    { 
        currentFrame.dispose();
        currentFrame = null;
        currentCanvas.close();
        currentCanvas = null;   
        screenshotImage = null;
        user32 = null;
        hwnd = null;
        th = null;
    }

    @Override
    public void run() 
    {
        while(true)
        {
            lastTime = System.nanoTime();
            screenshotImage  = GDI32Util.getScreenshot(hwnd);       
            ///screenshotImage = screenshotImage.Convert();   //Place where filter applied
            currentCanvas.setImg(screenshotImage,fps);
            java.awt.EventQueue.invokeLater(currentCanvas::repaint); 
            fps = 1000000000.0 / (System.nanoTime() - lastTime); //one second(nano) divided by amount of time it takes for one frame to finish
            lastTime = System.nanoTime();
        }
    }

} 

@SuppressWarnings("serial")
class PanelPaint extends javax.swing.JPanel
{
    public int xpos = 0;
    public int ypos = 0;
    BufferedImage img = null;
    java.awt.Graphics2D gc  = null;
    Font currentFont = null;
    double fps = 0;
    String CurrentFrameText;
    PanelPaint(int xpos,int ypos,double sx,double sy,String argCurrentFrameText)
    {
        img = new BufferedImage(xpos, ypos, BufferedImage.TYPE_INT_ARGB);
        gc = img.createGraphics();
        gc.scale(sx, sy);
        currentFont = new Font("default", Font.BOLD, 30);
        CurrentFrameText =  argCurrentFrameText;    
        gc.setFont(currentFont);
        gc.setColor(Color.RED);

    }
    @Override
    public Dimension getPreferredSize()
    {
        return new Dimension(xpos, ypos);
    }

    public void setImg(BufferedImage img,double argfps)
    {
        gc.drawImage(img, 0, 0, null);
        gc.drawString(CurrentFrameText + ": " + (int)fps, 25, 25);
        fps = argfps;
    }

    @Override
    public void paint(java.awt.Graphics g)
    {
        g.drawImage(img, 0, 0, null);   
    }
    public void close()
    { 
        img = null;
        gc  = null;
        currentFont = null;
    }
}

对于高对比度图像,上述速度较慢,“g.drawImage(img, 0, 0, null);”代码需要时间。 绘制图像的性能可以提高吗?

【问题讨论】:

    标签: java performance swing jpanel rendering


    【解决方案1】:

    您可以使用 OpenGL 片段着色器进行过滤,然后将源图像作为纹理传送到 4 个屏幕作为屏幕四边形(正交投影到四边形多边形上)。

    这是迄今为止满足您要求的最佳解决方案。如果您的游戏是基于 OpenGL 的,它会更快,因为您不必使用 Robot 包作为中间包 - 您可以简单地直接渲染游戏纹理(不需要图像转换)。

    这也将允许完全控制片段着色器中的过滤器。有关许多出色的滤镜着色器,请参阅 ShaderToy.com。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-05
      • 1970-01-01
      相关资源
      最近更新 更多