PageRenderTime 213ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/trunk/src/SunflowGUI.java

https://bitbucket.org/sandos/sunflow-patches
Java | 1252 lines | 1187 code | 39 blank | 26 comment | 207 complexity | 05548873f683fcd968a86211799e7a82 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. import java.awt.BorderLayout;
  2. import java.awt.Dimension;
  3. import java.awt.FlowLayout;
  4. import java.awt.Toolkit;
  5. import java.awt.datatransfer.DataFlavor;
  6. import java.awt.datatransfer.Transferable;
  7. import java.awt.event.ActionEvent;
  8. import java.awt.event.ActionListener;
  9. import java.beans.PropertyVetoException;
  10. import java.io.BufferedReader;
  11. import java.io.File;
  12. import java.io.FileNotFoundException;
  13. import java.io.FileReader;
  14. import java.io.FileWriter;
  15. import java.io.IOException;
  16. import java.util.List;
  17. import javax.swing.BorderFactory;
  18. import javax.swing.JButton;
  19. import javax.swing.JCheckBoxMenuItem;
  20. import javax.swing.JComponent;
  21. import javax.swing.JDesktopPane;
  22. import javax.swing.JFileChooser;
  23. import javax.swing.JInternalFrame;
  24. import javax.swing.JMenu;
  25. import javax.swing.JMenuBar;
  26. import javax.swing.JMenuItem;
  27. import javax.swing.JOptionPane;
  28. import javax.swing.JPanel;
  29. import javax.swing.JProgressBar;
  30. import javax.swing.JScrollPane;
  31. import javax.swing.JSeparator;
  32. import javax.swing.JTextArea;
  33. import javax.swing.KeyStroke;
  34. import javax.swing.ScrollPaneConstants;
  35. import javax.swing.SwingUtilities;
  36. import javax.swing.TransferHandler;
  37. import javax.swing.filechooser.FileFilter;
  38. import javax.swing.plaf.metal.DefaultMetalTheme;
  39. import javax.swing.plaf.metal.MetalLookAndFeel;
  40. import org.sunflow.Benchmark;
  41. import org.sunflow.RealtimeBenchmark;
  42. import org.sunflow.SunflowAPI;
  43. import org.sunflow.core.Display;
  44. import org.sunflow.core.TextureCache;
  45. import org.sunflow.core.accel.KDTree;
  46. import org.sunflow.core.display.FileDisplay;
  47. import org.sunflow.core.display.FrameDisplay;
  48. import org.sunflow.core.display.ImgPipeDisplay;
  49. import org.sunflow.core.primitive.TriangleMesh;
  50. import org.sunflow.system.ImagePanel;
  51. import org.sunflow.system.Timer;
  52. import org.sunflow.system.UI;
  53. import org.sunflow.system.UserInterface;
  54. import org.sunflow.system.UI.Module;
  55. import org.sunflow.system.UI.PrintLevel;
  56. @SuppressWarnings("serial")
  57. public class SunflowGUI extends javax.swing.JFrame implements UserInterface {
  58. private static final int DEFAULT_WIDTH = 1024;
  59. private static final int DEFAULT_HEIGHT = 768;
  60. private JPanel jPanel3;
  61. private JScrollPane jScrollPane1;
  62. private JMenuItem exitMenuItem;
  63. private JSeparator jSeparator2;
  64. private JPanel jPanel1;
  65. private JButton renderButton;
  66. private JMenuItem jMenuItem4;
  67. private JSeparator jSeparator1;
  68. private JMenuItem fitWindowMenuItem;
  69. private JMenuItem tileWindowMenuItem;
  70. private JSeparator jSeparator5;
  71. private JMenuItem consoleWindowMenuItem;
  72. private JMenuItem editorWindowMenuItem;
  73. private JMenuItem imageWindowMenuItem;
  74. private JMenu windowMenu;
  75. private JInternalFrame consoleFrame;
  76. private JInternalFrame editorFrame;
  77. private JInternalFrame imagePanelFrame;
  78. private JDesktopPane desktop;
  79. private JCheckBoxMenuItem smallTrianglesMenuItem;
  80. private JMenuItem textureCacheClearMenuItem;
  81. private JSeparator jSeparator4;
  82. private JMenuItem resetZoomMenuItem;
  83. private JMenu imageMenu;
  84. private ImagePanel imagePanel;
  85. private JPanel jPanel6;
  86. private JCheckBoxMenuItem clearLogMenuItem;
  87. private JPanel jPanel5;
  88. private JButton taskCancelButton;
  89. private JProgressBar taskProgressBar;
  90. private JSeparator jSeparator3;
  91. private JCheckBoxMenuItem autoBuildMenuItem;
  92. private JMenuItem iprMenuItem;
  93. private JMenuItem renderMenuItem;
  94. private JMenuItem buildMenuItem;
  95. private JMenu sceneMenu;
  96. private JTextArea editorTextArea;
  97. private JTextArea consoleTextArea;
  98. private JButton clearConsoleButton;
  99. private JPanel jPanel4;
  100. private JScrollPane jScrollPane2;
  101. private JButton iprButton;
  102. private JButton buildButton;
  103. private JMenuItem saveAsMenuItem;
  104. private JMenuItem saveMenuItem;
  105. private JMenuItem openFileMenuItem;
  106. private JMenuItem newFileMenuItem;
  107. private JMenu fileMenu;
  108. private JMenuBar jMenuBar1;
  109. // non-swing items
  110. private String currentFile;
  111. private String currentTask;
  112. private int currentTaskLastP;
  113. private SunflowAPI api;
  114. private File lastSaveDirectory;
  115. public static void usage(boolean verbose) {
  116. System.out.println("Usage: SunflowGUI [options] scenefile");
  117. if (verbose) {
  118. System.out.println("Sunflow v" + SunflowAPI.VERSION + " textmode");
  119. System.out.println("Renders the specified scene file");
  120. System.out.println("Options:");
  121. System.out.println(" -o filename Saves the output as the specified filename (png, hdr, tga)");
  122. System.out.println(" #'s get expanded to the current frame number");
  123. System.out.println(" -nogui Don't open the frame showing rendering progress");
  124. System.out.println(" -ipr Render using progressive algorithm");
  125. System.out.println(" -sampler type Render using the specified algorithm");
  126. System.out.println(" -threads n Render using n threads");
  127. System.out.println(" -lopri Set thread priority to low (default)");
  128. System.out.println(" -hipri Set thread priority to high");
  129. System.out.println(" -smallmesh Load triangle meshes using triangles optimized for memory use");
  130. System.out.println(" -dumpkd Dump KDTree to an obj file for visualization");
  131. System.out.println(" -buildonly Do not call render method after loading the scene");
  132. System.out.println(" -showaa Display sampling levels per pixel for bucket renderer");
  133. System.out.println(" -nogi Disable any global illumination engines in the scene");
  134. System.out.println(" -nocaustics Disable any caustic engine in the scene");
  135. System.out.println(" -pathgi n Use path tracing with n samples to render global illumination");
  136. System.out.println(" -quick_ambocc d Applies ambient occlusion to the scene with specified maximum distance");
  137. System.out.println(" -quick_uvs Applies a surface uv visualization shader to the scene");
  138. System.out.println(" -quick_normals Applies a surface normal visualization shader to the scene");
  139. System.out.println(" -quick_id Renders using a unique color for each instance");
  140. System.out.println(" -quick_prims Renders using a unique color for each primitive");
  141. System.out.println(" -quick_gray Renders using a plain gray diffuse shader");
  142. System.out.println(" -quick_wire Renders using a wireframe shader");
  143. System.out.println(" -resolution w h Changes the render resolution to the specified width and height (in pixels)");
  144. System.out.println(" -aa min max Overrides the image anti-aliasing depths");
  145. System.out.println(" -samples n Overrides the image sample count (affects bucket and multipass samplers)");
  146. System.out.println(" -bucket n order Changes the default bucket size to n pixels and the default order");
  147. System.out.println(" -bake name Bakes a lightmap for the specified instance");
  148. System.out.println(" -bakedir dir Selects the type of lightmap baking: dir=view or ortho");
  149. System.out.println(" -filter type Selects the image filter to use");
  150. System.out.println(" -bench Run several built-in scenes for benchmark purposes");
  151. System.out.println(" -rtbench Run realtime ray-tracing benchmark");
  152. System.out.println(" -frame n Set frame number to the specified value");
  153. System.out.println(" -anim n1 n2 Render all frames between the two specified values (inclusive)");
  154. System.out.println(" -translate file Translate input scene to the specified filename");
  155. System.out.println(" -v verbosity Set the verbosity level: 0=none,1=errors,2=warnings,3=info,4=detailed");
  156. System.out.println(" -h Prints this message");
  157. }
  158. System.exit(1);
  159. }
  160. public static void main(String[] args) {
  161. if (args.length > 0) {
  162. boolean showFrame = true;
  163. String sampler = null;
  164. boolean noRender = false;
  165. String filename = null;
  166. String input = null;
  167. int i = 0;
  168. int threads = 0;
  169. boolean lowPriority = true;
  170. boolean showAA = false;
  171. boolean noGI = false;
  172. boolean noCaustics = false;
  173. int pathGI = 0;
  174. float maxDist = 0;
  175. String shaderOverride = null;
  176. int resolutionW = 0, resolutionH = 0;
  177. int aaMin = -5, aaMax = -5;
  178. int samples = -1;
  179. int bucketSize = 0;
  180. String bucketOrder = null;
  181. String bakingName = null;
  182. boolean bakeViewdep = false;
  183. String filterType = null;
  184. boolean runBenchmark = false;
  185. boolean runRTBenchmark = false;
  186. String translateFilename = null;
  187. int frameStart = 1, frameStop = 1;
  188. while (i < args.length) {
  189. if (args[i].equals("-o")) {
  190. if (i > args.length - 2)
  191. usage(false);
  192. filename = args[i + 1];
  193. i += 2;
  194. } else if (args[i].equals("-nogui")) {
  195. showFrame = false;
  196. i++;
  197. } else if (args[i].equals("-ipr")) {
  198. sampler = "ipr";
  199. i++;
  200. } else if (args[i].equals("-threads")) {
  201. if (i > args.length - 2)
  202. usage(false);
  203. threads = Integer.parseInt(args[i + 1]);
  204. i += 2;
  205. } else if (args[i].equals("-lopri")) {
  206. lowPriority = true;
  207. i++;
  208. } else if (args[i].equals("-hipri")) {
  209. lowPriority = false;
  210. i++;
  211. } else if (args[i].equals("-sampler")) {
  212. if (i > args.length - 2)
  213. usage(false);
  214. sampler = args[i + 1];
  215. i += 2;
  216. } else if (args[i].equals("-smallmesh")) {
  217. TriangleMesh.setSmallTriangles(true);
  218. i++;
  219. } else if (args[i].equals("-dumpkd")) {
  220. KDTree.setDumpMode(true, "kdtree");
  221. i++;
  222. } else if (args[i].equals("-buildonly")) {
  223. noRender = true;
  224. i++;
  225. } else if (args[i].equals("-showaa")) {
  226. showAA = true;
  227. i++;
  228. } else if (args[i].equals("-nogi")) {
  229. noGI = true;
  230. i++;
  231. } else if (args[i].equals("-nocaustics")) {
  232. noCaustics = true;
  233. i++;
  234. } else if (args[i].equals("-pathgi")) {
  235. if (i > args.length - 2)
  236. usage(false);
  237. pathGI = Integer.parseInt(args[i + 1]);
  238. i += 2;
  239. } else if (args[i].equals("-quick_ambocc")) {
  240. if (i > args.length - 2)
  241. usage(false);
  242. maxDist = Float.parseFloat(args[i + 1]);
  243. shaderOverride = "ambient_occlusion"; // new
  244. // AmbientOcclusionShader(Color.WHITE,
  245. // d);
  246. i += 2;
  247. } else if (args[i].equals("-quick_uvs")) {
  248. if (i > args.length - 1)
  249. usage(false);
  250. shaderOverride = "show_uvs";
  251. i++;
  252. } else if (args[i].equals("-quick_normals")) {
  253. if (i > args.length - 1)
  254. usage(false);
  255. shaderOverride = "show_normals";
  256. i++;
  257. } else if (args[i].equals("-quick_id")) {
  258. if (i > args.length - 1)
  259. usage(false);
  260. shaderOverride = "show_instance_id";
  261. i++;
  262. } else if (args[i].equals("-quick_prims")) {
  263. if (i > args.length - 1)
  264. usage(false);
  265. shaderOverride = "show_primitive_id";
  266. i++;
  267. } else if (args[i].equals("-quick_gray")) {
  268. if (i > args.length - 1)
  269. usage(false);
  270. shaderOverride = "quick_gray";
  271. i++;
  272. } else if (args[i].equals("-quick_wire")) {
  273. if (i > args.length - 1)
  274. usage(false);
  275. shaderOverride = "wireframe";
  276. i++;
  277. } else if (args[i].equals("-resolution")) {
  278. if (i > args.length - 3)
  279. usage(false);
  280. resolutionW = Integer.parseInt(args[i + 1]);
  281. resolutionH = Integer.parseInt(args[i + 2]);
  282. i += 3;
  283. } else if (args[i].equals("-aa")) {
  284. if (i > args.length - 3)
  285. usage(false);
  286. aaMin = Integer.parseInt(args[i + 1]);
  287. aaMax = Integer.parseInt(args[i + 2]);
  288. i += 3;
  289. } else if (args[i].equals("-samples")) {
  290. if (i > args.length - 2)
  291. usage(false);
  292. samples = Integer.parseInt(args[i+1]);
  293. i += 2;
  294. } else if (args[i].equals("-bucket")) {
  295. if (i > args.length - 3)
  296. usage(false);
  297. bucketSize = Integer.parseInt(args[i + 1]);
  298. bucketOrder = args[i + 2];
  299. i += 3;
  300. } else if (args[i].equals("-bake")) {
  301. if (i > args.length - 2)
  302. usage(false);
  303. bakingName = args[i + 1];
  304. i += 2;
  305. } else if (args[i].equals("-bakedir")) {
  306. if (i > args.length - 2)
  307. usage(false);
  308. String baketype = args[i + 1];
  309. if (baketype.equals("view"))
  310. bakeViewdep = true;
  311. else if (baketype.equals("ortho"))
  312. bakeViewdep = false;
  313. else
  314. usage(false);
  315. i += 2;
  316. } else if (args[i].equals("-filter")) {
  317. if (i > args.length - 2)
  318. usage(false);
  319. filterType = args[i + 1];
  320. i += 2;
  321. } else if (args[i].equals("-bench")) {
  322. runBenchmark = true;
  323. i++;
  324. } else if (args[i].equals("-rtbench")) {
  325. runRTBenchmark = true;
  326. i++;
  327. } else if (args[i].equals("-frame")) {
  328. if (i > args.length - 2)
  329. usage(false);
  330. frameStart = frameStop = Integer.parseInt(args[i + 1]);
  331. i += 2;
  332. } else if (args[i].equals("-anim")) {
  333. if (i > args.length - 3)
  334. usage(false);
  335. frameStart = Integer.parseInt(args[i + 1]);
  336. frameStop = Integer.parseInt(args[i + 2]);
  337. i += 3;
  338. } else if (args[i].equals("-v")) {
  339. if (i > args.length - 2)
  340. usage(false);
  341. UI.verbosity(Integer.parseInt(args[i + 1]));
  342. i += 2;
  343. } else if (args[i].equals("-translate")) {
  344. if (i > args.length - 2)
  345. usage(false);
  346. translateFilename = args[i + 1];
  347. i += 2;
  348. } else if (args[i].equals("-h") || args[i].equals("-help")) {
  349. usage(true);
  350. } else {
  351. if (input != null)
  352. usage(false);
  353. input = args[i];
  354. i++;
  355. }
  356. }
  357. if (runBenchmark) {
  358. SunflowAPI.runSystemCheck();
  359. new Benchmark().execute();
  360. return;
  361. }
  362. if (runRTBenchmark) {
  363. SunflowAPI.runSystemCheck();
  364. new RealtimeBenchmark(showFrame, threads);
  365. return;
  366. }
  367. if (input == null)
  368. usage(false);
  369. SunflowAPI.runSystemCheck();
  370. if (translateFilename != null) {
  371. SunflowAPI.translate(input, translateFilename);
  372. return;
  373. }
  374. if (frameStart < frameStop && showFrame) {
  375. UI.printWarning(Module.GUI, "Animations should not be rendered without -nogui - forcing GUI off anyway");
  376. showFrame = false;
  377. }
  378. if (frameStart < frameStop && filename == null) {
  379. filename = "output.#.png";
  380. UI.printWarning(Module.GUI, "Animation output was not specified - defaulting to: \"%s\"", filename);
  381. }
  382. for (int frameNumber = frameStart; frameNumber <= frameStop; frameNumber++) {
  383. SunflowAPI api = SunflowAPI.create(input, frameNumber);
  384. if (api == null)
  385. continue;
  386. if (noRender)
  387. continue;
  388. if (resolutionW > 0 && resolutionH > 0) {
  389. api.parameter("resolutionX", resolutionW);
  390. api.parameter("resolutionY", resolutionH);
  391. }
  392. if (aaMin != -5 || aaMax != -5) {
  393. api.parameter("aa.min", aaMin);
  394. api.parameter("aa.max", aaMax);
  395. }
  396. if (samples >= 0)
  397. api.parameter("aa.samples", samples);
  398. if (bucketSize > 0)
  399. api.parameter("bucket.size", bucketSize);
  400. if (bucketOrder != null)
  401. api.parameter("bucket.order", bucketOrder);
  402. api.parameter("aa.display", showAA);
  403. api.parameter("threads", threads);
  404. api.parameter("threads.lowPriority", lowPriority);
  405. if (bakingName != null) {
  406. api.parameter("baking.instance", bakingName);
  407. api.parameter("baking.viewdep", bakeViewdep);
  408. }
  409. if (filterType != null)
  410. api.parameter("filter", filterType);
  411. if (noGI)
  412. api.parameter("gi.engine", "none");
  413. else if (pathGI > 0) {
  414. api.parameter("gi.engine", "path");
  415. api.parameter("gi.path.samples", pathGI);
  416. }
  417. if (noCaustics)
  418. api.parameter("caustics", "none");
  419. if (sampler != null)
  420. api.parameter("sampler", sampler);
  421. api.options(SunflowAPI.DEFAULT_OPTIONS);
  422. if (shaderOverride != null) {
  423. if (shaderOverride.equals("ambient_occlusion"))
  424. api.parameter("maxdist", maxDist);
  425. api.shader("cmdline_override", shaderOverride);
  426. api.parameter("override.shader", "cmdline_override");
  427. api.parameter("override.photons", true);
  428. api.options(SunflowAPI.DEFAULT_OPTIONS);
  429. }
  430. // create display
  431. Display display;
  432. String currentFilename = (filename != null) ? filename.replace("#", String.format("%04d", frameNumber)) : null;
  433. if (showFrame) {
  434. display = new FrameDisplay(currentFilename);
  435. } else {
  436. if (currentFilename != null && currentFilename.equals("imgpipe")) {
  437. display = new ImgPipeDisplay();
  438. } else
  439. display = new FileDisplay(currentFilename);
  440. }
  441. api.render(SunflowAPI.DEFAULT_OPTIONS, display);
  442. }
  443. } else {
  444. MetalLookAndFeel.setCurrentTheme(new DefaultMetalTheme());
  445. SunflowGUI gui = new SunflowGUI();
  446. gui.setVisible(true);
  447. Dimension screenRes = Toolkit.getDefaultToolkit().getScreenSize();
  448. if (screenRes.getWidth() <= DEFAULT_WIDTH || screenRes.getHeight() <= DEFAULT_HEIGHT)
  449. gui.setExtendedState(MAXIMIZED_BOTH);
  450. gui.tileWindowMenuItem.doClick();
  451. SunflowAPI.runSystemCheck();
  452. }
  453. }
  454. public SunflowGUI() {
  455. super();
  456. currentFile = null;
  457. lastSaveDirectory = null;
  458. api = null;
  459. initGUI();
  460. pack();
  461. setLocationRelativeTo(null);
  462. newFileMenuItemActionPerformed(null);
  463. UI.set(this);
  464. }
  465. private void initGUI() {
  466. setTitle("Sunflow v" + SunflowAPI.VERSION);
  467. setDefaultCloseOperation(EXIT_ON_CLOSE);
  468. {
  469. desktop = new JDesktopPane();
  470. getContentPane().add(desktop, BorderLayout.CENTER);
  471. Dimension screenRes = Toolkit.getDefaultToolkit().getScreenSize();
  472. if (screenRes.getWidth() <= DEFAULT_WIDTH || screenRes.getHeight() <= DEFAULT_HEIGHT)
  473. desktop.setPreferredSize(new java.awt.Dimension(640, 480));
  474. else
  475. desktop.setPreferredSize(new java.awt.Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT));
  476. {
  477. imagePanelFrame = new JInternalFrame();
  478. desktop.add(imagePanelFrame);
  479. {
  480. jPanel1 = new JPanel();
  481. FlowLayout jPanel1Layout = new FlowLayout();
  482. jPanel1Layout.setAlignment(FlowLayout.LEFT);
  483. jPanel1.setLayout(jPanel1Layout);
  484. imagePanelFrame.getContentPane().add(jPanel1, BorderLayout.NORTH);
  485. {
  486. renderButton = new JButton();
  487. jPanel1.add(renderButton);
  488. renderButton.setText("Render");
  489. renderButton.addActionListener(new ActionListener() {
  490. public void actionPerformed(ActionEvent evt) {
  491. renderMenuItemActionPerformed(evt);
  492. }
  493. });
  494. }
  495. {
  496. iprButton = new JButton();
  497. jPanel1.add(iprButton);
  498. iprButton.setText("IPR");
  499. iprButton.addActionListener(new ActionListener() {
  500. public void actionPerformed(ActionEvent evt) {
  501. iprMenuItemActionPerformed(evt);
  502. }
  503. });
  504. }
  505. }
  506. {
  507. imagePanel = new ImagePanel();
  508. imagePanelFrame.getContentPane().add(imagePanel, BorderLayout.CENTER);
  509. }
  510. imagePanelFrame.pack();
  511. imagePanelFrame.setResizable(true);
  512. imagePanelFrame.setMaximizable(true);
  513. imagePanelFrame.setVisible(true);
  514. imagePanelFrame.setTitle("Image");
  515. imagePanelFrame.setIconifiable(true);
  516. }
  517. {
  518. editorFrame = new JInternalFrame();
  519. desktop.add(editorFrame);
  520. editorFrame.setTitle("Script Editor");
  521. editorFrame.setMaximizable(true);
  522. editorFrame.setResizable(true);
  523. editorFrame.setIconifiable(true);
  524. {
  525. jScrollPane1 = new JScrollPane();
  526. editorFrame.getContentPane().add(jScrollPane1, BorderLayout.CENTER);
  527. jScrollPane1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
  528. jScrollPane1.setPreferredSize(new java.awt.Dimension(360, 280));
  529. {
  530. editorTextArea = new JTextArea();
  531. jScrollPane1.setViewportView(editorTextArea);
  532. editorTextArea.setFont(new java.awt.Font("Monospaced", 0, 12));
  533. // drag and drop
  534. editorTextArea.setTransferHandler(new SceneTransferHandler());
  535. }
  536. }
  537. {
  538. jPanel3 = new JPanel();
  539. editorFrame.getContentPane().add(jPanel3, BorderLayout.SOUTH);
  540. FlowLayout jPanel3Layout = new FlowLayout();
  541. jPanel3Layout.setAlignment(FlowLayout.RIGHT);
  542. jPanel3.setLayout(jPanel3Layout);
  543. {
  544. buildButton = new JButton();
  545. jPanel3.add(buildButton);
  546. buildButton.setText("Build Scene");
  547. buildButton.addActionListener(new ActionListener() {
  548. public void actionPerformed(ActionEvent evt) {
  549. buildMenuItemActionPerformed(evt);
  550. }
  551. });
  552. }
  553. }
  554. editorFrame.pack();
  555. editorFrame.setVisible(true);
  556. }
  557. {
  558. consoleFrame = new JInternalFrame();
  559. desktop.add(consoleFrame);
  560. consoleFrame.setIconifiable(true);
  561. consoleFrame.setMaximizable(true);
  562. consoleFrame.setResizable(true);
  563. consoleFrame.setTitle("Console");
  564. {
  565. jScrollPane2 = new JScrollPane();
  566. consoleFrame.getContentPane().add(jScrollPane2, BorderLayout.CENTER);
  567. jScrollPane2.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
  568. jScrollPane2.setPreferredSize(new java.awt.Dimension(360, 100));
  569. {
  570. consoleTextArea = new JTextArea();
  571. jScrollPane2.setViewportView(consoleTextArea);
  572. consoleTextArea.setFont(new java.awt.Font("Monospaced", 0, 12));
  573. consoleTextArea.setEditable(false);
  574. }
  575. }
  576. {
  577. jPanel4 = new JPanel();
  578. consoleFrame.getContentPane().add(jPanel4, BorderLayout.SOUTH);
  579. BorderLayout jPanel4Layout = new BorderLayout();
  580. jPanel4.setLayout(jPanel4Layout);
  581. {
  582. jPanel6 = new JPanel();
  583. BorderLayout jPanel6Layout = new BorderLayout();
  584. jPanel6.setLayout(jPanel6Layout);
  585. jPanel4.add(jPanel6, BorderLayout.CENTER);
  586. jPanel6.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 0));
  587. {
  588. taskProgressBar = new JProgressBar();
  589. jPanel6.add(taskProgressBar);
  590. taskProgressBar.setEnabled(false);
  591. taskProgressBar.setString("");
  592. taskProgressBar.setStringPainted(true);
  593. taskProgressBar.setOpaque(false);
  594. }
  595. }
  596. {
  597. jPanel5 = new JPanel();
  598. FlowLayout jPanel5Layout = new FlowLayout();
  599. jPanel5Layout.setAlignment(FlowLayout.RIGHT);
  600. jPanel5.setLayout(jPanel5Layout);
  601. jPanel4.add(jPanel5, BorderLayout.EAST);
  602. {
  603. taskCancelButton = new JButton();
  604. jPanel5.add(taskCancelButton);
  605. taskCancelButton.setText("Cancel");
  606. taskCancelButton.setEnabled(false);
  607. taskCancelButton.addActionListener(new ActionListener() {
  608. public void actionPerformed(ActionEvent evt) {
  609. UI.taskCancel();
  610. }
  611. });
  612. }
  613. {
  614. clearConsoleButton = new JButton();
  615. jPanel5.add(clearConsoleButton);
  616. clearConsoleButton.setText("Clear");
  617. clearConsoleButton.addActionListener(new ActionListener() {
  618. public void actionPerformed(ActionEvent evt) {
  619. clearConsole();
  620. }
  621. });
  622. }
  623. }
  624. }
  625. consoleFrame.pack();
  626. consoleFrame.setVisible(true);
  627. }
  628. }
  629. {
  630. jMenuBar1 = new JMenuBar();
  631. setJMenuBar(jMenuBar1);
  632. {
  633. fileMenu = new JMenu();
  634. jMenuBar1.add(fileMenu);
  635. fileMenu.setText("File");
  636. {
  637. newFileMenuItem = new JMenuItem();
  638. fileMenu.add(newFileMenuItem);
  639. newFileMenuItem.setText("New");
  640. newFileMenuItem.setAccelerator(KeyStroke.getKeyStroke("ctrl N"));
  641. newFileMenuItem.addActionListener(new ActionListener() {
  642. public void actionPerformed(ActionEvent evt) {
  643. newFileMenuItemActionPerformed(evt);
  644. }
  645. });
  646. }
  647. {
  648. openFileMenuItem = new JMenuItem();
  649. fileMenu.add(openFileMenuItem);
  650. openFileMenuItem.setText("Open ...");
  651. openFileMenuItem.setAccelerator(KeyStroke.getKeyStroke("ctrl O"));
  652. openFileMenuItem.addActionListener(new ActionListener() {
  653. public void actionPerformed(ActionEvent evt) {
  654. openFileMenuItemActionPerformed(evt);
  655. }
  656. });
  657. }
  658. {
  659. saveMenuItem = new JMenuItem();
  660. fileMenu.add(saveMenuItem);
  661. saveMenuItem.setText("Save");
  662. saveMenuItem.setAccelerator(KeyStroke.getKeyStroke("ctrl S"));
  663. saveMenuItem.addActionListener(new ActionListener() {
  664. public void actionPerformed(ActionEvent evt) {
  665. saveCurrentFile(currentFile);
  666. }
  667. });
  668. }
  669. {
  670. saveAsMenuItem = new JMenuItem();
  671. fileMenu.add(saveAsMenuItem);
  672. saveAsMenuItem.setText("Save As ...");
  673. saveAsMenuItem.addActionListener(new ActionListener() {
  674. public void actionPerformed(ActionEvent evt) {
  675. saveAsMenuItemActionPerformed(evt);
  676. }
  677. });
  678. }
  679. {
  680. jSeparator2 = new JSeparator();
  681. fileMenu.add(jSeparator2);
  682. }
  683. {
  684. exitMenuItem = new JMenuItem();
  685. fileMenu.add(exitMenuItem);
  686. exitMenuItem.setText("Exit");
  687. exitMenuItem.addActionListener(new ActionListener() {
  688. public void actionPerformed(ActionEvent evt) {
  689. System.exit(0);
  690. }
  691. });
  692. }
  693. }
  694. {
  695. sceneMenu = new JMenu();
  696. jMenuBar1.add(sceneMenu);
  697. sceneMenu.setText("Scene");
  698. {
  699. buildMenuItem = new JMenuItem();
  700. sceneMenu.add(buildMenuItem);
  701. buildMenuItem.setText("Build");
  702. buildMenuItem.setAccelerator(KeyStroke.getKeyStroke("ctrl B"));
  703. buildMenuItem.addActionListener(new ActionListener() {
  704. public void actionPerformed(ActionEvent evt) {
  705. if (sceneMenu.isEnabled())
  706. buildMenuItemActionPerformed(evt);
  707. }
  708. });
  709. }
  710. {
  711. autoBuildMenuItem = new JCheckBoxMenuItem();
  712. sceneMenu.add(autoBuildMenuItem);
  713. autoBuildMenuItem.setText("Build on open");
  714. autoBuildMenuItem.setSelected(true);
  715. }
  716. {
  717. jSeparator3 = new JSeparator();
  718. sceneMenu.add(jSeparator3);
  719. }
  720. {
  721. renderMenuItem = new JMenuItem();
  722. sceneMenu.add(renderMenuItem);
  723. renderMenuItem.setText("Render");
  724. renderMenuItem.addActionListener(new ActionListener() {
  725. public void actionPerformed(ActionEvent evt) {
  726. renderMenuItemActionPerformed(evt);
  727. }
  728. });
  729. }
  730. {
  731. iprMenuItem = new JMenuItem();
  732. sceneMenu.add(iprMenuItem);
  733. iprMenuItem.setText("IPR");
  734. iprMenuItem.addActionListener(new ActionListener() {
  735. public void actionPerformed(ActionEvent evt) {
  736. iprMenuItemActionPerformed(evt);
  737. }
  738. });
  739. }
  740. {
  741. clearLogMenuItem = new JCheckBoxMenuItem();
  742. sceneMenu.add(clearLogMenuItem);
  743. clearLogMenuItem.setText("Auto Clear Log");
  744. clearLogMenuItem.setToolTipText("Clears the console before building or rendering");
  745. clearLogMenuItem.setSelected(true);
  746. }
  747. {
  748. jSeparator4 = new JSeparator();
  749. sceneMenu.add(jSeparator4);
  750. }
  751. {
  752. textureCacheClearMenuItem = new JMenuItem();
  753. sceneMenu.add(textureCacheClearMenuItem);
  754. textureCacheClearMenuItem.setText("Clear Texture Cache");
  755. textureCacheClearMenuItem.addActionListener(new ActionListener() {
  756. public void actionPerformed(ActionEvent evt) {
  757. textureCacheClearMenuItemActionPerformed(evt);
  758. }
  759. });
  760. }
  761. {
  762. smallTrianglesMenuItem = new JCheckBoxMenuItem();
  763. sceneMenu.add(smallTrianglesMenuItem);
  764. smallTrianglesMenuItem.setText("Low Mem Triangles");
  765. smallTrianglesMenuItem.setToolTipText("Load future meshes using a low memory footprint triangle representation");
  766. smallTrianglesMenuItem.addActionListener(new ActionListener() {
  767. public void actionPerformed(ActionEvent evt) {
  768. smallTrianglesMenuItemActionPerformed(evt);
  769. }
  770. });
  771. }
  772. }
  773. {
  774. imageMenu = new JMenu();
  775. jMenuBar1.add(imageMenu);
  776. imageMenu.setText("Image");
  777. {
  778. resetZoomMenuItem = new JMenuItem();
  779. imageMenu.add(resetZoomMenuItem);
  780. resetZoomMenuItem.setText("Reset Zoom");
  781. resetZoomMenuItem.addActionListener(new ActionListener() {
  782. public void actionPerformed(ActionEvent evt) {
  783. imagePanel.reset();
  784. }
  785. });
  786. }
  787. {
  788. fitWindowMenuItem = new JMenuItem();
  789. imageMenu.add(fitWindowMenuItem);
  790. fitWindowMenuItem.setText("Fit to Window");
  791. fitWindowMenuItem.addActionListener(new ActionListener() {
  792. public void actionPerformed(ActionEvent evt) {
  793. imagePanel.fit();
  794. }
  795. });
  796. }
  797. {
  798. jSeparator1 = new JSeparator();
  799. imageMenu.add(jSeparator1);
  800. }
  801. {
  802. jMenuItem4 = new JMenuItem();
  803. imageMenu.add(jMenuItem4);
  804. jMenuItem4.setText("Save Image ...");
  805. jMenuItem4.addActionListener(new ActionListener() {
  806. public void actionPerformed(ActionEvent evt) {
  807. // imagePanel.image;
  808. JFileChooser fc = new JFileChooser(".");
  809. fc.setFileFilter(new FileFilter() {
  810. @Override
  811. public String getDescription() {
  812. return "Image File";
  813. }
  814. @Override
  815. public boolean accept(File f) {
  816. return (f.isDirectory() || f.getName().endsWith(".png") || f.getName().endsWith(".tga"));
  817. }
  818. });
  819. if (fc.showSaveDialog(SunflowGUI.this) == JFileChooser.APPROVE_OPTION) {
  820. String filename = fc.getSelectedFile().getAbsolutePath();
  821. imagePanel.save(filename);
  822. }
  823. }
  824. });
  825. }
  826. }
  827. {
  828. windowMenu = new JMenu();
  829. jMenuBar1.add(windowMenu);
  830. windowMenu.setText("Window");
  831. }
  832. {
  833. imageWindowMenuItem = new JMenuItem();
  834. windowMenu.add(imageWindowMenuItem);
  835. imageWindowMenuItem.setText("Image");
  836. imageWindowMenuItem.setAccelerator(KeyStroke.getKeyStroke("ctrl 1"));
  837. imageWindowMenuItem.addActionListener(new ActionListener() {
  838. public void actionPerformed(ActionEvent evt) {
  839. selectFrame(imagePanelFrame);
  840. }
  841. });
  842. }
  843. {
  844. editorWindowMenuItem = new JMenuItem();
  845. windowMenu.add(editorWindowMenuItem);
  846. editorWindowMenuItem.setText("Script Editor");
  847. editorWindowMenuItem.setAccelerator(KeyStroke.getKeyStroke("ctrl 2"));
  848. editorWindowMenuItem.addActionListener(new ActionListener() {
  849. public void actionPerformed(ActionEvent evt) {
  850. selectFrame(editorFrame);
  851. }
  852. });
  853. }
  854. {
  855. consoleWindowMenuItem = new JMenuItem();
  856. windowMenu.add(consoleWindowMenuItem);
  857. consoleWindowMenuItem.setText("Console");
  858. consoleWindowMenuItem.setAccelerator(KeyStroke.getKeyStroke("ctrl 3"));
  859. consoleWindowMenuItem.addActionListener(new ActionListener() {
  860. public void actionPerformed(ActionEvent evt) {
  861. selectFrame(consoleFrame);
  862. }
  863. });
  864. }
  865. {
  866. jSeparator5 = new JSeparator();
  867. windowMenu.add(jSeparator5);
  868. }
  869. {
  870. tileWindowMenuItem = new JMenuItem();
  871. windowMenu.add(tileWindowMenuItem);
  872. tileWindowMenuItem.setText("Tile");
  873. tileWindowMenuItem.setAccelerator(KeyStroke.getKeyStroke("ctrl T"));
  874. tileWindowMenuItem.addActionListener(new ActionListener() {
  875. public void actionPerformed(ActionEvent evt) {
  876. tileWindowMenuItemActionPerformed(evt);
  877. }
  878. });
  879. }
  880. }
  881. }
  882. private void newFileMenuItemActionPerformed(ActionEvent evt) {
  883. if (evt != null) {
  884. // check save?
  885. }
  886. // put some template code into the editor
  887. String template = "import org.sunflow.core.*;\nimport org.sunflow.core.accel.*;\nimport org.sunflow.core.camera.*;\nimport org.sunflow.core.primitive.*;\nimport org.sunflow.core.shader.*;\nimport org.sunflow.image.Color;\nimport org.sunflow.math.*;\n\npublic void build() {\n // your code goes here\n\n}\n";
  888. editorTextArea.setText(template);
  889. }
  890. private void openFileMenuItemActionPerformed(ActionEvent evt) {
  891. JFileChooser fc = new JFileChooser(".");
  892. if (lastSaveDirectory != null)
  893. fc.setCurrentDirectory(lastSaveDirectory);
  894. fc.setFileFilter(new FileFilter() {
  895. @Override
  896. public String getDescription() {
  897. return "Scene File";
  898. }
  899. @Override
  900. public boolean accept(File f) {
  901. return (f.isDirectory() || f.getName().endsWith(".sc") || f.getName().endsWith(".java"));
  902. }
  903. });
  904. if (fc.showOpenDialog(SunflowGUI.this) == JFileChooser.APPROVE_OPTION) {
  905. final String f = fc.getSelectedFile().getAbsolutePath();
  906. openFile(f);
  907. lastSaveDirectory = fc.getSelectedFile().getParentFile();
  908. }
  909. }
  910. private void buildMenuItemActionPerformed(ActionEvent evt) {
  911. new Thread() {
  912. @Override
  913. public void run() {
  914. setEnableInterface(false);
  915. if (clearLogMenuItem.isSelected())
  916. clearConsole();
  917. Timer t = new Timer();
  918. t.start();
  919. try {
  920. api = SunflowAPI.compile(editorTextArea.getText());
  921. } catch (NoClassDefFoundError e) {
  922. UI.printError(Module.GUI, "Janino library not found. Please check command line.");
  923. api = null;
  924. }
  925. if (api != null) {
  926. try {
  927. if (currentFile != null) {
  928. String dir = new File(currentFile).getAbsoluteFile().getParent();
  929. api.searchpath("texture", dir);
  930. api.searchpath("include", dir);
  931. }
  932. api.build();
  933. } catch (Exception e) {
  934. UI.printError(Module.GUI, "Build terminated abnormally: %s", e.getMessage());
  935. for (StackTraceElement elt : e.getStackTrace()) {
  936. UI.printInfo(Module.GUI, " at %s", elt.toString());
  937. }
  938. e.printStackTrace();
  939. }
  940. t.end();
  941. UI.printInfo(Module.GUI, "Build time: %s", t.toString());
  942. }
  943. setEnableInterface(true);
  944. }
  945. }.start();
  946. }
  947. private void clearConsole() {
  948. consoleTextArea.setText(null);
  949. }
  950. private void println(final String s) {
  951. SwingUtilities.invokeLater(new Runnable() {
  952. public void run() {
  953. consoleTextArea.append(s + "\n");
  954. }
  955. });
  956. }
  957. private void setEnableInterface(boolean enabled) {
  958. // lock or unlock options which are unsafe during builds or renders
  959. newFileMenuItem.setEnabled(enabled);
  960. openFileMenuItem.setEnabled(enabled);
  961. saveMenuItem.setEnabled(enabled);
  962. saveAsMenuItem.setEnabled(enabled);
  963. sceneMenu.setEnabled(enabled);
  964. buildButton.setEnabled(enabled);
  965. renderButton.setEnabled(enabled);
  966. iprButton.setEnabled(enabled);
  967. }
  968. public void print(Module m, PrintLevel level, String s) {
  969. if (level == PrintLevel.ERROR)
  970. JOptionPane.showMessageDialog(SunflowGUI.this, s, String.format("Error - %s", m.name()), JOptionPane.ERROR_MESSAGE);
  971. println(UI.formatOutput(m, level, s));
  972. }
  973. public void taskStart(String s, int min, int max) {
  974. currentTask = s;
  975. currentTaskLastP = -1;
  976. final int taskMin = min;
  977. final int taskMax = max;
  978. SwingUtilities.invokeLater(new Runnable() {
  979. public void run() {
  980. taskProgressBar.setEnabled(true);
  981. taskCancelButton.setEnabled(true);
  982. taskProgressBar.setMinimum(taskMin);
  983. taskProgressBar.setMaximum(taskMax);
  984. taskProgressBar.setValue(taskMin);
  985. taskProgressBar.setString(currentTask);
  986. }
  987. });
  988. }
  989. public void taskUpdate(int current) {
  990. final int taskCurrent = current;
  991. final String taskString = currentTask;
  992. SwingUtilities.invokeLater(new Runnable() {
  993. public void run() {
  994. taskProgressBar.setValue(taskCurrent);
  995. int p = (int) (100.0 * taskProgressBar.getPercentComplete());
  996. if (p > currentTaskLastP) {
  997. taskProgressBar.setString(taskString + " [" + p + "%]");
  998. currentTaskLastP = p;
  999. }
  1000. }
  1001. });
  1002. }
  1003. public void taskStop() {
  1004. SwingUtilities.invokeLater(new Runnable() {
  1005. public void run() {
  1006. taskProgressBar.setValue(taskProgressBar.getMinimum());
  1007. taskProgressBar.setString("");
  1008. taskProgressBar.setEnabled(false);
  1009. taskCancelButton.setEnabled(false);
  1010. }
  1011. });
  1012. }
  1013. private void renderMenuItemActionPerformed(ActionEvent evt) {
  1014. new Thread() {
  1015. @Override
  1016. public void run() {
  1017. setEnableInterface(false);
  1018. if (clearLogMenuItem.isSelected())
  1019. clearConsole();
  1020. if (api != null) {
  1021. api.parameter("sampler", "bucket");
  1022. api.options(SunflowAPI.DEFAULT_OPTIONS);
  1023. api.render(SunflowAPI.DEFAULT_OPTIONS, imagePanel);
  1024. } else
  1025. UI.printError(Module.GUI, "Nothing to render!");
  1026. setEnableInterface(true);
  1027. }
  1028. }.start();
  1029. }
  1030. private void iprMenuItemActionPerformed(ActionEvent evt) {
  1031. new Thread() {
  1032. @Override
  1033. public void run() {
  1034. setEnableInterface(false);
  1035. if (clearLogMenuItem.isSelected())
  1036. clearConsole();
  1037. if (api != null) {
  1038. api.parameter("sampler", "ipr");
  1039. api.options(SunflowAPI.DEFAULT_OPTIONS);
  1040. api.render(SunflowAPI.DEFAULT_OPTIONS, imagePanel);
  1041. } else
  1042. UI.printError(Module.GUI, "Nothing to IPR!");
  1043. setEnableInterface(true);
  1044. }
  1045. }.start();
  1046. }
  1047. private void textureCacheClearMenuItemActionPerformed(ActionEvent evt) {
  1048. TextureCache.flush();
  1049. }
  1050. private void smallTrianglesMenuItemActionPerformed(ActionEvent evt) {
  1051. TriangleMesh.setSmallTriangles(smallTrianglesMenuItem.isSelected());
  1052. }
  1053. private void saveAsMenuItemActionPerformed(ActionEvent evt) {
  1054. JFileChooser fc = new JFileChooser(".");
  1055. if (lastSaveDirectory != null)
  1056. fc.setCurrentDirectory(lastSaveDirectory);
  1057. fc.setFileFilter(new FileFilter() {
  1058. @Override
  1059. public String getDescription() {
  1060. return "Scene File";
  1061. }
  1062. @Override
  1063. public boolean accept(File f) {
  1064. return (f.isDirectory() || f.getName().endsWith(".java"));
  1065. }
  1066. });
  1067. if (fc.showSaveDialog(SunflowGUI.this) == JFileChooser.APPROVE_OPTION) {
  1068. String f = fc.getSelectedFile().getAbsolutePath();
  1069. if (!f.endsWith(".java"))
  1070. f += ".java";
  1071. File file = new File(f);
  1072. if (!file.exists() || JOptionPane.showConfirmDialog(SunflowGUI.this, "This file already exists.\nOverwrite?", "Warning", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
  1073. // save file
  1074. saveCurrentFile(f);
  1075. lastSaveDirectory = file.getParentFile();
  1076. }
  1077. }
  1078. }
  1079. private void saveCurrentFile(String filename) {
  1080. if (filename == null) {
  1081. // no filename was picked, go to save as dialog
  1082. saveAsMenuItemActionPerformed(null);
  1083. return;
  1084. }
  1085. FileWriter file;
  1086. try {
  1087. file = new FileWriter(filename);
  1088. // get text from editor pane
  1089. file.write(editorTextArea.getText());
  1090. file.close();
  1091. // update current filename
  1092. currentFile

Large files files are truncated, but you can click here to view the full file