Fix some max iterations bugs
[maximus:sft.git] / SuperFractalThing / source / SftComponent.java
1 //      SFTComponent
2 //
3 //
4 //    Copyright 2013 Kevin Martin
5 //
6 //    This file is part of SuperFractalThing.
7 //
8 //    SuperFractalThing is free software: you can redistribute it and/or modify
9 //    it under the terms of the GNU General Public License as published by
10 //    the Free Software Foundation, either version 3 of the License, or
11 //    any later version.
12 //
13 //    SuperFractalThing is distributed in the hope that it will be useful,
14 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //    GNU General Public License for more details.
17 //
18 //    You should have received a copy of the GNU General Public License
19 //    along with SuperFractalThing.  If not, see <http://www.gnu.org/licenses/>.
20 //
21
22 import java.awt.event.ActionEvent;
23 import java.awt.event.ActionListener;
24 import java.awt.event.MouseEvent;
25 import java.awt.image.BufferedImage;
26 import java.awt.*;
27 import java.math.BigDecimal;
28 import java.math.MathContext;
29
30 import javax.swing.Timer;
31 import javax.swing.event.MouseInputListener;
32
33
34
35 public class SftComponent extends Component implements MouseInputListener, Runnable, ActionListener, IPaletteChangeNotify
36 {
37         private static final long serialVersionUID = 0;//get rid of warning
38         BufferedImage mImage;
39         BigDecimal mPos,mPosi;
40         BigDecimal mSize;
41         int mMax_iterations;
42         int mResolution_x;
43         int mResolution_y;
44         SFTGui mGui;
45         Timer mTimer;
46         boolean mProcessing;
47         IndexBuffer2D mBuffer;
48         IndexBuffer2D mExport_buffer;
49         IPalette mPalette;
50         CalculationManager mCalculation;
51         SuperSampleType mSuper_sample_type;
52         int mNum_threads;
53         long mStart_time;
54         boolean mPressed;
55         int mPressed_x;
56         int mPressed_y;
57         int mSelected_x;
58         int mSelected_y;
59         int mDragged_size;
60         
61         public SftComponent(SFTGui aGui)
62         {
63                 mGui = aGui;
64         }
65         public void CreateImage()
66         {
67                 mResolution_x = 1024;
68                 mResolution_y = 768;
69                 mSize = new BigDecimal(3.0);
70                 mPos = new BigDecimal(-0.75,MathContext.DECIMAL128);
71                 mPosi= new BigDecimal(0,MathContext.DECIMAL128);
72                 mMax_iterations = 1024;
73                 
74                 mGui.SetCoords(mSize,mPos,mPosi,mMax_iterations);
75                 
76         mImage = new BufferedImage(mResolution_x, mResolution_y, BufferedImage.TYPE_INT_ARGB);
77         
78         UpdateImage();
79         }
80         
81         void SetPalette( IPalette aPalette)
82         {
83                 mPalette = aPalette;
84         }
85         
86         void SetSuperSampleType(SuperSampleType aType)
87         {
88                 mSuper_sample_type = aType;
89         }
90         void SetNumThreads(int aNumber)
91         {
92                 mNum_threads = aNumber;
93                 if (mNum_threads<1)
94                         mNum_threads=1;
95                 if (mNum_threads>1024)
96                         mNum_threads=1024;
97         }       
98         
99         @Override
100         public void PaletteChanged()
101         {
102                 mImage = mBuffer.MakeTexture(mPalette, mSuper_sample_type);
103                 repaint();
104         }
105         
106         public BufferedImage GetImage()
107         {
108                 return mImage;
109         }
110         
111         public void run()
112         {
113                 UpdateImage();
114                 mProcessing=false;
115         }
116         
117         void Refresh()
118         {
119                 SetMaxIterations();
120                 DoCalculation();
121         }
122         
123         void DoCalculation()
124         {
125                 mBuffer = DoCalculation(mResolution_x, mResolution_y, mSuper_sample_type);
126         }
127
128         void ExportCalculation(int aResolution_x, int aResolution_y, SuperSampleType aSuper_sample)
129         {
130                 mExport_buffer = DoCalculation(aResolution_x, aResolution_y, aSuper_sample);
131         }
132         
133         IndexBuffer2D DoCalculation(int aResolution_x, int aResolution_y, SuperSampleType aSuper_sample)
134         {
135                 BigDecimal coords[] = new BigDecimal[2];
136                 
137                 mGui.StartProcessing();
138                 mStart_time = System.currentTimeMillis();
139                 mGui.SetCalculationTime( -1);
140                 coords = mGui.GetCoords();
141                 mMax_iterations = mGui.GetIterations();
142                 mSize = mGui.GetTheSize();
143                 mPos = coords[0];
144                 mPosi = coords[1];      
145                 int scale = mGui.GetTheSize().scale();
146                 int precision = mGui.GetTheSize().precision();
147                 int expo=0;
148                 precision = scale -precision + 8;
149                 
150                 IndexBuffer2D buffer=null;
151                 
152                 switch (aSuper_sample)
153                 {
154                 case SUPER_SAMPLE_NONE:
155                         buffer = new IndexBuffer2D(aResolution_x,aResolution_y);
156                         break;
157                 case SUPER_SAMPLE_2X:
158                         buffer = new IndexBuffer2D(aResolution_x+1,aResolution_y*2+1);
159                         break;
160                 case SUPER_SAMPLE_4X:
161                         buffer = new IndexBuffer2D(aResolution_x*2,aResolution_y*2);
162                         break;
163                 case SUPER_SAMPLE_4X_9:
164                         buffer = new IndexBuffer2D(aResolution_x*2+1,aResolution_y*2+1);
165                         break;
166                 case SUPER_SAMPLE_9X:
167                         buffer = new IndexBuffer2D(aResolution_x*3,aResolution_y*3);
168                         break;
169                 
170                 }
171         
172                 CalculationManager calc = new CalculationManager();
173                 mCalculation = calc;
174                 
175                 double size;
176                 BigDecimal bd280 = new BigDecimal(1e-280);
177                 if (mSize.compareTo( bd280)<0)
178                 {
179                         BigDecimal mod_size = mSize;
180                         while (mod_size.compareTo( bd280)<0)
181                         {
182                                 mod_size=mod_size.movePointRight(1);
183                                 expo+=1;
184                         }
185                         size = mod_size.doubleValue();
186                                 
187                 }
188                 else
189                 {
190                         size = mSize.doubleValue();
191                 }
192                 
193                 calc.SetCoordinates(mPos,mPosi,(size/2*mResolution_x)/mResolution_y,expo, new MathContext(precision));
194                 calc.SetBuffer(buffer, aSuper_sample);
195                 calc.SetIterationLimit(mMax_iterations);
196                 calc.SetAccuracy(1);
197                 calc.ThreadedCalculation(mNum_threads);
198                 
199                 if (mTimer==null)
200                 {
201                         mTimer = new Timer(100, this);
202                         mTimer.setInitialDelay(100);
203                 }
204                 mTimer.start(); 
205                 return buffer;
206         }
207         
208         void UpdateImage()
209         {               
210                 BigDecimal coords[] = new BigDecimal[2];
211                 
212                 coords = mGui.GetCoords();
213                 mMax_iterations = mGui.GetIterations();
214                 mSize = mGui.GetTheSize();
215                 mPos = coords[0];
216                 mPosi = coords[1];
217                 
218                 BigDecimal bigx  = mPos;
219                 BigDecimal bigy  = mPosi;
220                 
221                 int scale = mGui.GetTheSize().scale();
222                 int precision = mGui.GetTheSize().precision();
223                 int expo=0;
224                 
225                 precision = scale -precision + 8;
226                 
227                 mSuper_sample_type = SuperSampleType.SUPER_SAMPLE_2X;
228                 
229                 switch (mSuper_sample_type)
230                 {
231                 case SUPER_SAMPLE_NONE:
232                         mBuffer = new IndexBuffer2D(mResolution_x,mResolution_y);
233                         break;
234                 case SUPER_SAMPLE_2X:
235                         mBuffer = new IndexBuffer2D(mResolution_x+1,mResolution_y*2+1);
236                         break;
237                 case SUPER_SAMPLE_4X:
238                         mBuffer = new IndexBuffer2D(mResolution_x*2,mResolution_y*2);
239                         break;
240                 case SUPER_SAMPLE_4X_9:
241                         mBuffer = new IndexBuffer2D(mResolution_x*2+1,mResolution_y*2+1);
242                         break;
243                 case SUPER_SAMPLE_9X:
244                         mBuffer = new IndexBuffer2D(mResolution_x*3,mResolution_y*3);
245                         break;
246                 
247                 }
248
249                 double size;
250                 BigDecimal bd280 = new BigDecimal(1e-280);
251                 if (mSize.compareTo( bd280)<0)
252                 {
253                         BigDecimal mod_size = mSize;
254                         while (mod_size.compareTo( bd280)<0)
255                         {
256                                 mod_size=mod_size.movePointRight(1);
257                                 expo+=1;
258                         }
259                         size = mod_size.doubleValue();
260                                 
261                 }
262                 else
263                 {
264                         size = mSize.doubleValue();
265                 }
266                 
267                 CalculationManager calc = new CalculationManager();
268                 calc.SetCoordinates(bigx,bigy,(size/2*mResolution_x)/mResolution_y,expo, new MathContext(precision));
269                 calc.SetBuffer(mBuffer, mSuper_sample_type);
270                 calc.SetIterationLimit(mMax_iterations);
271                 calc.SetAccuracy(1);
272                 calc.InitialiseCalculation();
273                 calc.CalculateSector(0,1,1);
274                 mGui.AddToUndoBuffer();
275                 
276         mImage = mBuffer.MakeTexture(mPalette, mSuper_sample_type);
277         }
278         
279     public void paint(Graphics g) {
280         Graphics2D g2 = (Graphics2D) g;
281         
282         g2.drawImage(mImage,0,0,null);
283         g2.setColor (Color.gray);
284         
285         if (mDragged_size>0)
286         {
287                 int width = mDragged_size;
288                 int height = (mDragged_size * 768)/1024;
289                 g2.draw3DRect(mPressed_x-width/2, mPressed_y - height/2, width, height,true);
290             
291         }
292     }
293     
294     public Dimension getPreferredSize(){
295         return new Dimension(1024, 768);
296     }
297     
298     
299         @Override
300         public void mouseClicked(MouseEvent arg0) {
301                 // TODO Auto-generated method stub
302
303                 if (mCalculation!=null && mCalculation.GetIsProcessing())
304                         return;
305                 if (mTimer!=null && mTimer.isRunning())
306                         return;
307                 
308                 int x = arg0.getX()-getX();
309                 int y = arg0.getY()-getY();
310                 
311                 if (arg0.getClickCount()==2)
312                 {
313                         mMax_iterations = mGui.GetIterations();
314                         if (mCalculation!=null)
315                         {
316                                 mMax_iterations= Math.max(mMax_iterations, mCalculation.GetNewLimit());
317                                 mGui.SetIterations(mMax_iterations);
318                         }
319                         
320                         double x_mul = x*1.0/mResolution_y - mResolution_x * 0.5/mResolution_y;
321                         double y_mul = (0.5*mResolution_y - y)/mResolution_y;
322                         
323                         BigDecimal x_offset = mSize.multiply(new BigDecimal(x_mul));
324                         BigDecimal y_offset = mSize.multiply(new BigDecimal(y_mul));
325                         
326                         int size_scale = mSize.scale();
327                         if (x_offset.scale() > size_scale+4)
328                                 x_offset = x_offset.setScale( size_scale+4, BigDecimal.ROUND_HALF_DOWN);
329                         if (y_offset.scale() > size_scale+4)
330                                 y_offset = y_offset.setScale( size_scale+4, BigDecimal.ROUND_HALF_DOWN);
331                         
332                         mPos = mPos.add( x_offset );
333                         mPosi = mPosi.add( y_offset );
334                         mSize = mSize.multiply(new BigDecimal(0.2));
335                         
336                         mPos = mPos.stripTrailingZeros();
337                         mPosi = mPosi.stripTrailingZeros();
338                         mSize = mSize.stripTrailingZeros();
339                         
340                         //mPos = mPos.add( new BigDecimal((x) * mSize/mResolution_y - mSize*mResolution_x/mResolution_y/2) );
341                         //mPosi = mPosi.add( new BigDecimal((mResolution_y/2-y) * mSize/mResolution_y));
342                         //mSize *= 0.2;
343                         
344                         //mSize_box.setText(Double.toString(mSize));
345                         mGui.SetCoords(mSize,mPos,mPosi, mMax_iterations);
346                         
347                         mGui.AddToUndoBuffer();
348                         DoCalculation();
349                         repaint();
350                 }
351                 else
352                 {
353                         if (mDragged_size>0)
354                         {
355                                 int s = mDragged_size/2;
356                                 if (x - mSelected_x <= s && mSelected_x -x <= s)
357                                 {
358                                         s = (mDragged_size*768)/1024/2;
359                                         if (y - mSelected_y < s && mSelected_y-y < s)
360                                         {
361                                                 double x_mul = mSelected_x*1.0/mResolution_y - mResolution_x * 0.5/mResolution_y;
362                                                 double y_mul = (0.5*mResolution_y - mSelected_y)/mResolution_y;
363                                                 
364                                                 BigDecimal x_offset = mSize.multiply(new BigDecimal(x_mul));
365                                                 BigDecimal y_offset = mSize.multiply(new BigDecimal(y_mul));
366                                                 
367                                                 int size_scale = mSize.scale();
368                                                 if (x_offset.scale() > size_scale+4)
369                                                         x_offset = x_offset.setScale( size_scale+4, BigDecimal.ROUND_HALF_DOWN);
370                                                 if (y_offset.scale() > size_scale+4)
371                                                         y_offset = y_offset.setScale( size_scale+4, BigDecimal.ROUND_HALF_DOWN);
372
373                                                 mPos = mPos.add( x_offset);
374                                                 mPosi = mPosi.add( y_offset);
375                                                 mSize = mSize.multiply(new BigDecimal(mDragged_size/1024.0));
376
377                                                 mPos = mPos.stripTrailingZeros();
378                                                 mPosi = mPosi.stripTrailingZeros();
379                                                 mSize = mSize.stripTrailingZeros();
380                                                 
381                                                 //mPos = mPos.add( new BigDecimal((mSelected_x) * mSize/mResolution_y - mSize*mResolution_x/mResolution_y/2) );
382                                                 //mPosi = mPosi.add( new BigDecimal((mResolution_y/2-mSelected_y) * mSize/mResolution_y));
383                                                 //mSize *= mDragged_size/1024.0;
384                                                 mGui.SetCoords(mSize,mPos,mPosi, mMax_iterations);
385                                                 mGui.AddToUndoBuffer();
386                                                 DoCalculation();
387                                                 repaint();
388                                         }
389                                 }
390                         }
391                 }
392                 if (mDragged_size!=0)
393                 {
394                         mDragged_size = 0;
395                         repaint();
396                 }
397         }
398         @Override
399         public void mouseEntered(MouseEvent arg0) {
400                 // TODO Auto-generated method stub
401                 
402         }
403         @Override
404         public void mouseExited(MouseEvent arg0) {
405                 // TODO Auto-generated method stub
406                 
407         }
408         @Override
409         public void mousePressed(MouseEvent arg0)
410         {
411                 mPressed = true;
412                 mPressed_x = arg0.getX()-getX();
413                 mPressed_y = arg0.getY()-getY();
414                 
415         }
416         @Override
417         public void mouseReleased(MouseEvent arg0)
418         {
419                 mPressed = false;               
420         }
421         @Override
422         public void mouseDragged(MouseEvent arg0)
423         {
424                 int x = arg0.getX()-getX();
425                 int y = arg0.getY()-getY();
426                 
427                 mDragged_size =2*Math.abs(x-mPressed_x);
428                 int ds2 = (Math.abs(y-mPressed_y)*2*1024)/768;
429                 mDragged_size = Math.max(mDragged_size, ds2);
430                 repaint();
431                 mSelected_x = mPressed_x;
432                 mSelected_y = mPressed_y;
433         }
434         @Override
435         public void mouseMoved(MouseEvent arg0)
436         {
437                 if (mCalculation!=null && mCalculation.GetIsProcessing())
438                         return;
439                 
440                 int x = arg0.getX()-getX();
441                 int y = mResolution_y - arg0.getY()-getY();
442                 
443                 if (x<0 || x>=mResolution_x || y<0 || y>=mResolution_y)
444                         return;
445                 
446                 if (mSuper_sample_type == SuperSampleType.SUPER_SAMPLE_4X)
447                 {
448                         x*=2;
449                         y*=2;
450                 }
451                 else if (mSuper_sample_type == SuperSampleType.SUPER_SAMPLE_4X_9)
452                 {
453                         x=x*2+1;
454                         y=y*2+1;
455                 }
456                 else if (mSuper_sample_type == SuperSampleType.SUPER_SAMPLE_9X)
457                 {
458                         x=x*3+1;
459                         y=y*3+1;
460                 }
461                 
462                 if (mBuffer!=null && y<mBuffer.GetHeight() && x<mBuffer.GetWidth())
463                 {
464                         int index = mBuffer.GetValue(x,y);
465                         mGui.SetHoverIndex(index);
466                 }               
467         }
468         @Override
469         public void actionPerformed(ActionEvent arg0)
470         {
471                 if (!mCalculation.GetIsProcessing())
472                 {
473                         if (mExport_buffer!=null)
474                         {
475                         BufferedImage image = mExport_buffer.MakeTexture(mPalette, mCalculation.GetSuperSampleType());
476                         if (image==null)
477                         {
478                                 mExport_buffer = null;
479                                 mGui.OutOfMemory();
480                         }
481                         else
482                         {
483                                 mExport_buffer = null;
484                                         mGui.ExportImage(image);
485                         }
486                         }
487                         else
488                         {
489                         mImage = mBuffer.MakeTexture(mPalette, mSuper_sample_type);
490                                 repaint();
491                                 //mMax_iterations = mCalculation.GetNewLimit();
492                         }
493                         mTimer.stop();
494                         mGui.EndProcessing();
495                         mGui.SetCalculationTime( System.currentTimeMillis() - mStart_time);
496                 }
497                 else
498                 {
499                         if (mExport_buffer!=null)
500                                 mGui.SetProgress(mCalculation.GetProgress(), mExport_buffer.GetWidth()* mExport_buffer.GetHeight());
501                         else
502                                 mGui.SetProgress(mCalculation.GetProgress(), mBuffer.GetWidth()* mBuffer.GetHeight());
503                 }
504         }
505         
506         void Cancel()
507         {
508                 if (mCalculation!=null)
509                 {
510                         mCalculation.Cancel();
511                 }
512         }
513 }