将60FPS游戏分为四个屏幕

问题描述 投票:0回答:1

我有多个游戏以每秒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 jpanel rendering drawimage
1个回答
0
投票

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

到目前为止,这是满足您要求的最佳解决方案。如果您的游戏是基于OpenGL的,它将更快,因为您不必使用Robot软件包作为中间产品-您可以直接直接渲染游戏纹理(不需要图像转换)。

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

© www.soinside.com 2019 - 2024. All rights reserved.