Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (535)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  AffineTransform totally breaks drawing  (Read 1298 times)
0 Members and 1 Guest are viewing this topic.
Offline swpalmer

JGO Coder




Where's the Kaboom?


« Posted 2004-06-22 13:58:38 »

I didn't believe how broken this was until I saw it with my own eyes.

With an Affine Transfrom drawImage does not work. Period.  It is completely broken such that I can't possibly imagine how it passes any tests that Sun might have.  (Tested on Windows XP)
I've tested with 1.4.2_04 and 1.5.0 beta 3 build 56
same results on both.
Try this code,  drag the windows over each other, off the screen edge etc.  Note how the 'stretched' window simply doesn't paint properly if at all, while the un-stretched window is fine.
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;

/*
 * Created on 22-Jun-2004
 *
 * @author scott.palmer
 */

public class TransformTest
{
      public static void main(String[] args)
      {
            JFrame frameNT = new JFrame("Transform Test - Plain");
            MenuScreen screenNT = new MenuScreen(720,480,false);
            frameNT.getContentPane().add( screenNT, BorderLayout.CENTER );
            
            JFrame frameT = new JFrame("Transform Test - With Transform");
            MenuScreen screenT = new MenuScreen(720,480,true);
            frameT.getContentPane().add( screenT, BorderLayout.CENTER );

            frameNT.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frameT.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frameNT.pack();
            frameT.pack();
            frameNT.show();
            frameT.show();
      }
}

class MenuScreen extends JPanel
{
      public MenuScreen(int width, int height, boolean anamorphic)
      {
            compositeImage = new BufferedImage(width, height,
                        BufferedImage.TYPE_INT_ARGB);
            size.width = width;
            size.height = height;
            this.anamorphic = anamorphic;
            
            setDoubleBuffered(false);
            setOpaque(true);
      }

      protected void paintComponent(Graphics g)
      {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            AffineTransform savedAT = null;
            if(anamorphic)
            {
                  // 4:3 -> 16:9
                 savedAT = g2.getTransform();
                  g2.setTransform(AffineTransform.getScaleInstance(4.0 / 3.0, 1.0));
                  g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            }
            if( dirty )
                  rebuildCompositeImage(0);
            g2.drawImage(compositeImage, 0, 0, null);
            if(savedAT != null)
                  g2.setTransform(savedAT);
      }

      protected void rebuildCompositeImage(int fromItem)
      {
            // TODO account for insets
           Graphics2D g2 = (Graphics2D) compositeImage.getGraphics();
            g2.setBackground(getBackground());
            g2.clearRect(0, 0, getWidth(), getHeight());

            // leave some space around the edges
           int safeTitleX = (int) ((size.width - (size.width* 0.8 )) / 2.0 + 0.5);
            int safeTitleY = (int) ((size.height - (size.height* 0.8 )) / 2.0 + 0.5);
            int safeWidth = size.width - safeTitleX * 2;
            int safeHeight = size.height - safeTitleY * 2;
            int titleLines = 1;

            g2.setColor( textColor );
            g2.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON );
            g2.setRenderingHint( RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON );
            g2.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY );
            // draw title
           FontMetrics fm = g2.getFontMetrics(titleFont);
            int tHeight = fm.getHeight();
            if( title != null )
            {
                  int tWidth = fm.stringWidth(title);
                  g2.setFont(titleFont);
                  g2.drawString(title, safeTitleX + (safeWidth - tWidth) / 2, safeTitleY + fm.getAscent());
            }
            // draw Menu items
           fm = g2.getFontMetrics(chapterFont);
            int menuThumbHeight = 60;
            int menuRowHeight = fm.getHeight() + menuThumbHeight;
            int chapsPerRow = 4;
            int chapWidth = (safeWidth/chapsPerRow);
            int zz = fromItem + 1;
            for(int j = 0; j < 4; j++)
            {
                  for(int i = 0; i < 4; i++)
                  {
                        String str = "Menu Item "+zz;
                        int ctPos = (chapWidth - fm.stringWidth(str))/2; // center chapter title
                       int x = safeTitleX + i * chapWidth + ctPos;
                        int y = safeTitleY + (tHeight * titleLines) + menuThumbHeight + fm.getAscent() + j * menuRowHeight;
                        g2.drawString(str,x,y);
                        zz++;
                  }
            }
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2.dispose();
            dirty = false;
      }
      
      public Dimension getPreferredSize()
      {
            return anamorphic ? anamorphicSize : size;
      }

      public Dimension getMinimumSize() {      return getPreferredSize(); }
      public Dimension getMaximumSize() { return getPreferredSize(); }

      private boolean dirty = true; // need to rebuild the image
     private Dimension size = new Dimension(720, 480);
      private Dimension anamorphicSize = new Dimension(720 * 4 / 3, 480);
      private boolean anamorphic;
      private BufferedImage compositeImage;
      private Color textColor = Color.BLACK;
      
      private String title = "Painting Bugs with AffineTransform";
      private Font titleFont = new Font("SansSerif", Font.PLAIN, 20);
      private Font chapterFont = new Font("SansSerif", Font.PLAIN, 18);
}

Offline barfy

Junior Member




The evidence of things not seen


« Reply #1 - Posted 2004-06-22 21:43:58 »

I think I know where your problem lies.

You should have concatenated your scaled AffineTransform with the Graphics context current AffineTransform object before calling setTransform(). More conveniently, you can just save a copy of the current AffineTransform and call g2d.scale(4.0/3.0, 1.0), do your drawing, then restore the saved copy.

I believe that the Swing renderer would have translated the Graphics context prior to any repainting of the dirty areas of the window/frame when it was obscured.

Offline swpalmer

JGO Coder




Where's the Kaboom?


« Reply #2 - Posted 2004-06-23 02:05:05 »

I was thinking "That can't be it."  If the Swing renderer ever translated the origin prior to calling paintComponent it would screw up the coordinate system for painting - how would the code possibly know what to paint if the origin was secretly moved?  It will set the clipping region, sure... but it  can't move the origin.

Then I went "Ahhhhhhh"   the true origin of the graphics context is that of the clip rect, and it is translating the origin back to where it should be for the whole component.. I must be undoing that correction....

Is that behaviour documented?Huh?


Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline barfy

Junior Member




The evidence of things not seen


« Reply #3 - Posted 2004-06-23 03:40:35 »

Quote
Then I went "Ahhhhhhh"   the true origin of the graphics context is that of the clip rect, and it is translating the origin back to where it should be for the whole component.. I must be undoing that correction....


That is what I THINK is happening, since if you try moving another (heavyweight) window over the stretched window, and then click/focus on the stretched window to bring it to the front, you would notice that the transformed image is actually drawn with a translation similar in size to the distance between the left edges of the two windows.

Again, my guess is that the Swing renderer:

1. Is notified of a paint() request by the native paint sub-system to repaint the dirty regions

2. calls Graphics.create(int x, int y, int width, int height) to get a "sub" Graphics object with a new clip and origin (and adjusts the translation to reflect the original Graphics origin) and propagates that "sub" Graphics object down the paint() heirachy instead.

I'm very curious as to why they didn't just clip the original Graphics object if that's the case  Roll Eyes .

Quote

Is that behaviour documented?Huh?


I haven't seen any myself, therefore I can only make reasonable speculations. Hopefully someone else can confirm.

Maybe it's only a Swing quirk. Does AWT work differently?
Offline swpalmer

JGO Coder




Where's the Kaboom?


« Reply #4 - Posted 2004-06-23 16:47:56 »

Quote
I'm very curious as to why they didn't just clip the original Graphics object if that's the case  Roll Eyes .


Well that does appear to be the case, so I'm curious as well... I had assumed that clipping of the original graphics object is what would have happened.  I'm guessing that using the smaller graphics context saves memory and can lead to better native support for clipping.

Anyway my program is fixed, and I should appologise for jumping to conclusions.  draing with an AffineTransform is obviously not broken - my brain is Smiley.  Thanks for cluing me in.

Offline pepe

Junior Member




Nothing unreal exists


« Reply #5 - Posted 2004-07-05 05:27:53 »

[edit] oops, misread.. sorry

Home page: http://frederic.barachant.com
------------------------------------------------------
GoSub: java2D gamechmark http://frederic.barachant.com/GoSub/GoSub.jnlp
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

pw (37 views)
2014-07-24 01:59:36

Riven (38 views)
2014-07-23 21:16:32

Riven (26 views)
2014-07-23 21:07:15

Riven (28 views)
2014-07-23 20:56:16

ctomni231 (59 views)
2014-07-18 06:55:21

Zero Volt (50 views)
2014-07-17 23:47:54

danieldean (42 views)
2014-07-17 23:41:23

MustardPeter (44 views)
2014-07-16 23:30:00

Cero (60 views)
2014-07-16 00:42:17

Riven (57 views)
2014-07-14 18:02:53
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!