Home > Blockchain >  Change to painting method caused texturing algorithm to run really slowly?
Change to painting method caused texturing algorithm to run really slowly?

Time:04-02

I am making a 3D game, and the way I used to draw to the screen was to add a JLabel containing the "game screen" as a BufferedImage to the JPanel, and changing individual pixels using BufferedImage.setRGB(). However, I decided to switch into drawing into the JPanel directly using PaintComponent(). After making the switch and not touching the texturing algorithm (outside of changes like adding the wanted pixel color into a screen buffer instead of directly changing the color, so if anything, it should be faster), it now runs really slowly (it takes about 0.3 seconds and sometimes even more to finish the texturing algorithm, with everything else being pretty much instant). Is there anyway to fix it? Also, if you see other problems with the code, feel free to let me know.

    public CanvasPanel(JFrame frame, int width, int height)
    {
        this.frame = frame;
        setPreferredSize(new Dimension(width, height));
        setSize(width, height);
        trianglesToDraw = new ArrayList<>();
        //add(label);
        keysPressed = new boolean[9];
        addKeyListener(new KeyListener()
        {
            @Override
            public void keyTyped(KeyEvent e)
            {
            
            }
            
            @Override
            public void keyPressed(KeyEvent e)
            {
                int key = e.getKeyCode();
                
                if (key == KeyEvent.VK_W)
                {
                    keysPressed[0] = true;
                }
                else if (key == KeyEvent.VK_A)
                {
                    keysPressed[1] = true;
                }
                else if (key == KeyEvent.VK_S)
                {
                    keysPressed[2] = true;
                }
                else if (key == KeyEvent.VK_D)
                {
                    keysPressed[3] = true;
                }
                else if (key == KeyEvent.VK_SPACE)
                {
                    keysPressed[4] = true;
                }
            }
            
            @Override
            public void keyReleased(KeyEvent e)
            {
                int key = e.getKeyCode();
                
                if (key == KeyEvent.VK_W)
                {
                    keysPressed[0] = false;
                }
                else if (key == KeyEvent.VK_A)
                {
                    keysPressed[1] = false;
                }
                else if (key == KeyEvent.VK_S)
                {
                    keysPressed[2] = false;
                }
                else if (key == KeyEvent.VK_D)
                {
                    keysPressed[3] = false;
                }
                else if (key == KeyEvent.VK_SPACE)
                {
                    keysPressed[4] = false;
                }
            }
        });
        objects = new ArrayList<>();
        Hyperrectangle ground = new Hyperrectangle(new Vector(-10.0f, -10.0f, -10.0f), new Vector(10.0f, 10.0f, 10.0f), true);
        objects.add(ground);
        if (objects.get(0).textured)
        {
            try
            {
                objects.get(0).texture = ImageIO.read(new File(texturePath));
                crosshair = ImageIO.read(new File("src/res/crosshair.png"));
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }

        float aspectRatio = (float) getHeight() / (float) getWidth();
        float zNear = 0.1f;
        float zFar = 1000.0f;
        float fov = 90.0f;
        projectionMatrix = MathUtils.makeProjectionMatrix(fov, aspectRatio, zNear, zFar);
        depthBuffer = new float[getWidth()][getHeight()];
        screenBuffer = new int[getWidth()][getHeight()];
        try
        {
            robot = new Robot();
        }
        catch (AWTException e)
        {
            e.printStackTrace();
        }
        
        BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
        Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor(cursorImg, new Point(0, 0), "blank cursor");
        frame.getContentPane().setCursor(blankCursor);
    
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int centerX = (int) screenSize.getWidth() / 2;
        int centerY = (int) screenSize.getHeight() / 2;
        robot.mouseMove(centerX, centerY);
        
        for (int i = 0; i < getWidth(); i  )
        {
            for (int j = 0; j < getHeight(); j  )
            {
                depthBuffer[i][j] = 0.0f;
                screenBuffer[i][j] = 0;
            }
        }
        
        Timer timer = new Timer(30, e -> newFrame(projectionMatrix));
        timer.start();
    }

    private void newFrame(float[][] projectionMatrix)
    {
        trianglesToDraw.clear();
        for (int i = 0; i < getWidth(); i  )
        {
            for (int j = 0; j < getHeight(); j  )
            {
                depthBuffer[i][j] = 0.0f;
                screenBuffer[i][j] = 0;
            }
        }
        
        Vector up = new Vector(0.0f, 1.0f, 0.0f);
        float cameraSpeed = 0.5f;
        Vector target = MathUtils.multiply(camera.lookDirection, cameraSpeed);
        target.y = 0.0f;
    
        Point mousePosition = MouseInfo.getPointerInfo().getLocation();
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int centerX = (int) screenSize.getWidth() / 2;
        int centerY = (int) screenSize.getHeight() / 2;
        robot.mouseMove(centerX, centerY);
        float dx = mousePosition.x - centerX;
        float dy = mousePosition.y - centerY;
    
        float newYaw = camera.yaw   cameraSpeed * dx;
        float newPitch = camera.pitch   cameraSpeed * dy;
        
        if (!Double.isNaN(dx))
        {
            camera.yaw = newYaw;
        }
        if (!Double.isNaN(dy))
        {
            if (newPitch < 180.0f && newPitch > -180.0f)
            {
                camera.pitch = newPitch;
            }
        }
        
        if (keysPressed[0]) // W, move forward
        {
            camera.origin.add(target);
        }
        if (keysPressed[1]) // A, strafe left
        {
            Vector right = MathUtils.cross(target, up);
            camera.origin.subtract(right);
        }
        if (keysPressed[2]) // S, move backward
        {
            camera.origin.subtract(target);
        }
        if (keysPressed[3]) // D, strafe right
        {
            Vector right = MathUtils.cross(target, up);
            camera.origin.add(right);
        }
        if (keysPressed[4]) // SPACE, teleport to origin
        {
            camera.origin = new Vector(0.0f);
        }
        
        float[][] xWorldRotationMatrix = MathUtils.makeXRotationMatrix(0.0f);
        float[][] yWorldRotationMatrix = MathUtils.makeYRotationMatrix(0.0f);
        float[][] zWorldRotationMatrix = MathUtils.makeZRotationMatrix(0.0f);
        float[][] worldRotationMatrix = MathUtils.multiply(MathUtils.multiply(yWorldRotationMatrix, xWorldRotationMatrix), zWorldRotationMatrix);
        float[][] translationMatrix = MathUtils.makeTranslationMatrix(0.0f, 0.0f, 20.0f);
        float[][] worldMatrix = MathUtils.multiply(worldRotationMatrix, translationMatrix);
        
        float[][] xCameraRotationMatrix = MathUtils.makeXRotationMatrix(camera.pitch);
        float[][] yCameraRotationMatrix = MathUtils.makeYRotationMatrix(camera.yaw);
        float[][] zCameraRotationMatrix = MathUtils.makeZRotationMatrix(0.0f);
        float[][] cameraRotationMatrix = MathUtils.multiply(MathUtils.multiply(yCameraRotationMatrix, xCameraRotationMatrix), zCameraRotationMatrix);
        
        Vector forward = new Vector(0.0f, 0.0f, 1.0f);
        camera.lookDirection = MathUtils.multiply(cameraRotationMatrix, forward);
        forward = MathUtils.add(camera.origin, camera.lookDirection);
        
        float[][] cameraMatrix = (MathUtils.inverseMatrix(camera.pointAt(forward, up)));
        
        for (GameObject object : objects)
        {
            for (Triangle triangle : object.triangles)
            {
                calculateTriangles(triangle, worldMatrix, projectionMatrix, cameraMatrix);
            }
        }
    
        for (Triangle t : trianglesToDraw)
        {
            t.draw(this, objects.get(0).texture);
        }
        
        repaint();
    }

    void draw(CanvasPanel viewport, BufferedImage texture)
    {
        int x1 = (int) this.points[0].x, x2 = (int) this.points[1].x, x3 = (int) this.points[2].x;
        int y1 = (int) this.points[0].y, y2 = (int) this.points[1].y, y3 = (int) this.points[2].y;
        float u1 = this.textureCoordinates[0].u, u2 = this.textureCoordinates[1].u, u3 = this.textureCoordinates[2].u;
        float v1 = this.textureCoordinates[0].v, v2 = this.textureCoordinates[1].v, v3 = this.textureCoordinates[2].v;
        float w1 = this.textureCoordinates[0].w, w2 = this.textureCoordinates[1].w, w3 = this.textureCoordinates[2].w;
        int temp1;
        float temp2;
        
        if (y2 < y1)
        {
            temp1 = y1;
            y1 = y2;
            y2 = temp1;
            
            temp1 = x1;
            x1 = x2;
            x2 = temp1;
            
            temp2 = u1;
            u1 = u2;
            u2 = temp2;
            
            temp2 = v1;
            v1 = v2;
            v2 = temp2;
            
            temp2 = w1;
            w1 = w2;
            w2 = temp2;
        }
        
        if (y3 < y1)
        {
            temp1 = y1;
            y1 = y3;
            y3 = temp1;
            
            temp1 = x1;
            x1 = x3;
            x3 = temp1;
            
            temp2 = u1;
            u1 = u3;
            u3 = temp2;
            
            temp2 = v1;
            v1 = v3;
            v3 = temp2;
            
            temp2 = w1;
            w1 = w3;
            w3 = temp2;
        }
        
        if (y3 < y2)
        {
            temp1 = y2;
            y2 = y3;
            y3 = temp1;
            
            temp1 = x2;
            x2 = x3;
            x3 = temp1;
            
            temp2 = u2;
            u2 = u3;
            u3 = temp2;
            
            temp2 = v2;
            v2 = v3;
            v3 = temp2;
            
            temp2 = w2;
            w2 = w3;
            w3 = temp2;
        }
        
        int dy1 = y2 - y1;
        int dx1 = x2 - x1;
        float du1 = u2 - u1;
        float dv1 = v2 - v1;
        float dw1 = w2 - w1;
        
        int dy2 = y3 - y1;
        int dx2 = x3 - x1;
        float dv2 = v3 - v1;
        float du2 = u3 - u1;
        float dw2 = w3 - w1;
        
        float uTexture, vTexture, wTexture;
        float dx1Step = 0, dx2Step = 0, du1Step = 0, du2Step = 0, dv1Step = 0, dv2Step = 0, dw1Step = 0, dw2Step = 0;

        if (dy1 != 0)
        {
            dx1Step = dx1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            dx2Step = dx2 / (float) Math.abs(dy2);
        }
        if (dy1 != 0)
        {
            du1Step = du1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            du2Step = du2 / (float) Math.abs(dy2);
        }
        if (dy1 != 0)
        {
            dv1Step = dv1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            dv2Step = dv2 / (float) Math.abs(dy2);
        }
        if (dy1 != 0)
        {
            dw1Step = dw1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            dw2Step = dw2 / (float) Math.abs(dy2);
        }
    
        if (dy1 != 0)
        {
            for (int y = y1; y <= y2; y  )
            {
                int xStart = (int) (x1   (y - y1) * dx1Step);
                int xEnd = (int) (x1   (y - y1) * dx2Step);
                
                float uStart = u1   (y - y1) * du1Step;
                float uEnd = u1   (y - y1) * du2Step;
                
                float vStart = v1   (y - y1) * dv1Step;
                float vEnd = v1   (y - y1) * dv2Step;
                
                float wStart = w1   (y - y1) * dw1Step;
                float wEnd = w1   (y - y1) * dw2Step;
                
                if (xStart > xEnd)
                {
                    temp1 = xStart;
                    xStart = xEnd;
                    xEnd = temp1;
                    
                    temp2 = uStart;
                    uStart = uEnd;
                    uEnd = temp2;
                    
                    temp2 = vStart;
                    vStart = vEnd;
                    vEnd = temp2;
                    
                    temp2 = wStart;
                    wStart = wEnd;
                    wEnd = temp2;
                }
                
                float tStep = 1.0f / (xEnd - xStart);
                float t = 0.0f;
    
                for (int x = xStart; x < xEnd; x  )
                {
                    uTexture = (1.0f - t) * uStart   t * uEnd;
                    vTexture = (1.0f - t) * vStart   t * vEnd;
                    wTexture = (1.0f - t) * wStart   t * wEnd;
                    
                    if (uTexture / wTexture >= 1 || vTexture / wTexture >= 1) // Temporary fix
                    {
                        uTexture = 0.0f;
                        vTexture = 0.0f;
                    }

                    int pixelColor;

                    if (textured)
                    {
                        int uTextureCoordinates = (int) ((uTexture / wTexture) * texture.getWidth());
                        int vTextureCoordinates = (int) ((vTexture / wTexture) * texture.getHeight());
                        try
                        {
                            pixelColor = texture.getRGB(uTextureCoordinates, vTextureCoordinates);
                        }
                        catch (ArrayIndexOutOfBoundsException e)
                        {
                            pixelColor = Color.black.getRGB();
                        }
                    }
                    else
                    {
                        pixelColor = color.getRGB();
                    }

                    if (wTexture > viewport.depthBuffer[x][y])
                    {
                        viewport.screenBuffer[x][y] = pixelColor;
                        viewport.depthBuffer[x][y] = wTexture;
                    }
                    
                    t  = tStep;
                }
            }
        }
        
        
        dy1 = y3 - y2;
        dx1 = x3 - x2;
        du1 = u3 - u2;
        dv1 = v3 - v2;
        dw1 = w3 - w2;
        
        if (dy1 != 0)
        {
            dx1Step = dx1 / (float) Math.abs(dy1);
        }
        if (dy2 != 0)
        {
            dx2Step = dx2 / (float) Math.abs(dy2);
        }
        if (dy1 != 0)
        {
            du1Step = du1 / (float) Math.abs(dy1);
        }
        if (dy1 != 0)
        {
            dv1Step = dv1 / (float) Math.abs(dy1);
        }
        if (dy1 != 0)
        {
            dw1Step = dw1 / (float) Math.abs(dy1);
        }
        
        if (dy1 != 0)
        {
            for (int y = y2; y <= y3; y  )
            {
                int xStart = (int) (x2   (y - y2) * dx1Step);
                int xEnd = (int) (x1   (y - y1) * dx2Step);
                
                float uStart = u2   (y - y2) * du1Step;
                float uEnd = u1   (y - y1) * du2Step;
                
                float vStart = v2   (y - y2) * dv1Step;
                float vEnd = v1   (y - y1) * dv2Step;
                
                float wStart = w2   (y - y2) * dw1Step;
                float wEnd = w1   (y - y1) * dw2Step;
                
                if (xStart > xEnd)
                {
                    temp1 = xStart;
                    xStart = xEnd;
                    xEnd = temp1;
                    
                    temp2 = uStart;
                    uStart = uEnd;
                    uEnd = temp2;
                    
                    temp2 = vStart;
                    vStart = vEnd;
                    vEnd = temp2;
                    
                    temp2 = wStart;
                    wStart = wEnd;
                    wEnd = temp2;
                }
                
                float tStep = 1.0f / (xEnd - xStart);
                float t = 0.0f;
                
                for (int x = xStart; x < xEnd; x  )
                {
                    uTexture = (1.0f - t) * uStart   t * uEnd;
                    vTexture = (1.0f - t) * vStart   t * vEnd;
                    wTexture = (1.0f - t) * wStart   t * wEnd;
    
                    if (uTexture / wTexture >= 1 || vTexture / wTexture >= 1) // Temporary fix
                    {
                        uTexture = 0.0f;
                        vTexture = 0.0f;
                    }
                    
                    int pixelColor;
                    
                    if (textured)
                    {
                        int uTextureCoordinates = (int) ((uTexture / wTexture) * texture.getWidth());
                        int vTextureCoordinates = (int) ((vTexture / wTexture) * texture.getHeight());
                        try
                        {
                            pixelColor = texture.getRGB(uTextureCoordinates, vTextureCoordinates);
                        }
                        catch (ArrayIndexOutOfBoundsException e)
                        {
                            pixelColor = Color.black.getRGB();
                        }
                    }
                    else
                    {
                        pixelColor = color.getRGB();
                    }
                    
                    if (wTexture > viewport.depthBuffer[x][y])
                    {
                        viewport.screenBuffer[x][y] = pixelColor;
                        viewport.depthBuffer[x][y] = wTexture;
                    }
    
                    t  = tStep;
                }
            }
        }
    }

    @Override
    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        
        for (int i = 0; i < getWidth(); i  )
        {
            for (int j = 0; j < getHeight(); j  )
            {
                g.setColor(getColorFromRGBCode(screenBuffer[i][j]));
                g.drawLine(i, j, i, j);
            }
        }
        
        g.drawImage(crosshair, getWidth() / 2 - crosshair.getWidth() / 2, getHeight() / 2 - crosshair.getHeight() / 2, null);
    }

CodePudding user response:

Well, it turns out that using BufferedImage is just better, so I changed the screen buffer to one and it works well again.

  • Related