LogoopenSUSE Build Service > Projects
Sign Up | Log In

View File sunflow_SweetHome3D.patch of Package sunflow (Project home:adra)

diff -Naur sunflow-0.07.2.svn396/README.TXT sunflow-0.07.2.svn396.SweetHome3D/README.TXT
--- sunflow-0.07.2.svn396/README.TXT	1970-01-01 02:00:00.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/README.TXT	2011-03-13 01:09:50.000000000 +0200
@@ -0,0 +1,12 @@
+SUNFLOW v 0.07.3g
+-----------------
+
+This archive contains the SunFlow files modified for Sweet Home 3D, compared to the revision 396 of SunFlow repository available on SourceForge.net with the following command:
+  svn co -r 396 https://sunflow.svn.sourceforge.net/svnroot/sunflow/trunk sunflow
+
+sunflow-0.07.3g.jar can be built with the following ant command:
+  ant -f buildForSweetHome3D.xml
+
+
+Note: differences in source code are marked with comments starting by 
+  // EP
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/buildForSweetHome3D.xml sunflow-0.07.2.svn396.SweetHome3D/buildForSweetHome3D.xml
--- sunflow-0.07.2.svn396/buildForSweetHome3D.xml	1970-01-01 02:00:00.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/buildForSweetHome3D.xml	2011-03-13 01:10:20.000000000 +0200
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Sunflow" default="jars">
+	<!-- This needs to change with every release -->
+	<property name="sunflow.version" value="0.07.3" />
+	<property name="sunflow.jdk.level" value="5" />
+	<property name="sunflow.zip.comment" value="Sunflow rendering system v${sunflow.version}" />
+	<property name="sunflow.libs" value="janino.jar" />
+	<property name="sunflow.jar.filename" value="sunflow-0.07.3g.jar" />
+
+	<!-- Basic targets -->
+	<target name="init">
+		<property name="src.dir" value="src" />
+		<property name="resources.dir" value="resources" />
+		<available file="${resources.dir}" type="dir" property="resources.present" />
+		<property name="build.dir" value="build" />
+		<property name="release.dir" value="release" />
+		<!-- build folder contains temporary files needed to create release level files -->
+		<property name="build.classes.dir" value="${build.dir}/classes" />
+		<property name="build.manifest" value="${build.dir}/sunflow.mf" />
+		<property name="build.jar" value="${build.dir}/sunflow.jar" />
+		<!-- release folder contains files which may be distributed in some way or another -->
+		<property name="release.javadoc.dir" value="${release.dir}/javadoc" />
+		<property name="release.src.zip" value="${release.dir}/sunflow-src-v${sunflow.version}.zip" />
+		<property name="release.bin.zip" value="${release.dir}/sunflow-bin-v${sunflow.version}.zip" />
+		<property name="release.data.zip" value="${release.dir}/sunflow-data-v${sunflow.version}.zip" />
+	</target>
+
+	<target name="clean" depends="init" description="Remove build files created this scripts">
+		<delete dir="${build.dir}" />
+		<delete dir="${release.dir}" />
+	</target>
+
+
+	<!-- build directory targets -->
+	<target name="compile" depends="init" description="Compile source">
+		<mkdir dir="${build.classes.dir}" />
+		<javac srcdir="${src.dir}" destdir="${build.classes.dir}" source="${sunflow.jdk.level}" target="${sunflow.jdk.level}" classpath="${sunflow.libs}">
+			<compilerarg value="-Xlint:unchecked" />
+		</javac>
+	</target>
+
+	<target name="create_manifest" description="Create the Sunflow jar manifest">
+		<echo file="${build.manifest}" append="false" message="Manifest-Version: 1.0${line.separator}" />
+	</target>
+
+	<target name="jars" depends="clean, compile, create_manifest" if="resources.present" description="Create jar files required for execution">
+		<mkdir dir="${release.dir}" />
+		<jar jarfile="${release.dir}/${sunflow.jar.filename}" manifest="${build.manifest}">
+			<fileset dir="${build.classes.dir}" >
+		        <include name="**"/>
+		        <exclude name="org/sunflow/core/parser/**"/>
+				<exclude name="**/RenderGlobalsPanel*.class"/>
+				<exclude name="**/Benchmark*.class"/>
+				<exclude name="**/ImagePanel*.class"/>
+				<exclude name="**/*FileSunflowAPI*.class"/>
+				<exclude name="SunflowGUI*.class"/>
+		    </fileset>
+		</jar>
+	</target>
+</project>
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/SunflowGUI.java sunflow-0.07.2.svn396.SweetHome3D/src/SunflowGUI.java
--- sunflow-0.07.2.svn396/src/SunflowGUI.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/SunflowGUI.java	2010-09-29 12:12:38.000000000 +0300
@@ -43,7 +43,6 @@
 import org.sunflow.RealtimeBenchmark;
 import org.sunflow.SunflowAPI;
 import org.sunflow.core.Display;
-import org.sunflow.core.TextureCache;
 import org.sunflow.core.accel.KDTree;
 import org.sunflow.core.display.FileDisplay;
 import org.sunflow.core.display.FrameDisplay;
@@ -52,9 +51,9 @@
 import org.sunflow.system.ImagePanel;
 import org.sunflow.system.Timer;
 import org.sunflow.system.UI;
-import org.sunflow.system.UserInterface;
 import org.sunflow.system.UI.Module;
 import org.sunflow.system.UI.PrintLevel;
+import org.sunflow.system.UserInterface;
 
 @SuppressWarnings("serial")
 public class SunflowGUI extends javax.swing.JFrame implements UserInterface {
@@ -1069,7 +1068,8 @@
     }
 
     private void textureCacheClearMenuItemActionPerformed(ActionEvent evt) {
-        TextureCache.flush();
+        // EP : Made texture cache local to SunFlow API
+        api.getTextureCache().flush();
     }
 
     private void smallTrianglesMenuItemActionPerformed(ActionEvent evt) {
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/PluginRegistry.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/PluginRegistry.java
--- sunflow-0.07.2.svn396/src/org/sunflow/PluginRegistry.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/PluginRegistry.java	2010-06-20 22:18:46.000000000 +0300
@@ -51,12 +51,12 @@
 import org.sunflow.core.modifiers.BumpMappingModifier;
 import org.sunflow.core.modifiers.NormalMapModifier;
 import org.sunflow.core.modifiers.PerlinModifier;
-import org.sunflow.core.parser.RA2Parser;
-import org.sunflow.core.parser.RA3Parser;
-import org.sunflow.core.parser.SCAsciiParser;
-import org.sunflow.core.parser.SCBinaryParser;
-import org.sunflow.core.parser.SCParser;
-import org.sunflow.core.parser.ShaveRibParser;
+//import org.sunflow.core.parser.RA2Parser;
+//import org.sunflow.core.parser.RA3Parser;
+//import org.sunflow.core.parser.SCAsciiParser;
+//import org.sunflow.core.parser.SCBinaryParser;
+//import org.sunflow.core.parser.SCParser;
+//import org.sunflow.core.parser.ShaveRibParser;
 import org.sunflow.core.photonmap.CausticPhotonMap;
 import org.sunflow.core.photonmap.GlobalPhotonMap;
 import org.sunflow.core.photonmap.GridPhotonMap;
@@ -291,15 +291,16 @@
         imageSamplerPlugins.registerPlugin("multipass", MultipassRenderer.class);
     }
 
-    static {
-        // parsers
-        parserPlugins.registerPlugin("sc", SCParser.class);
-        parserPlugins.registerPlugin("sca", SCAsciiParser.class);
-        parserPlugins.registerPlugin("scb", SCBinaryParser.class);
-        parserPlugins.registerPlugin("rib", ShaveRibParser.class);
-        parserPlugins.registerPlugin("ra2", RA2Parser.class);
-        parserPlugins.registerPlugin("ra3", RA3Parser.class);
-    }
+// EP : Don't need parsers
+//    static {
+//        // parsers
+//        parserPlugins.registerPlugin("sc", SCParser.class);
+//        parserPlugins.registerPlugin("sca", SCAsciiParser.class);
+//        parserPlugins.registerPlugin("scb", SCBinaryParser.class);
+//        parserPlugins.registerPlugin("rib", ShaveRibParser.class);
+//        parserPlugins.registerPlugin("ra2", RA2Parser.class);
+//        parserPlugins.registerPlugin("ra3", RA3Parser.class);
+//    }
 
     static {
         // bitmap readers
@@ -309,6 +310,8 @@
         bitmapReaderPlugins.registerPlugin("jpg", JPGBitmapReader.class);
         bitmapReaderPlugins.registerPlugin("bmp", BMPBitmapReader.class);
         bitmapReaderPlugins.registerPlugin("igi", IGIBitmapReader.class);
+        // EP : Added extension jpeg
+        bitmapReaderPlugins.registerPlugin("jpeg", JPGBitmapReader.class);
     }
 
     static {
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/SunflowAPI.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/SunflowAPI.java
--- sunflow-0.07.2.svn396/src/org/sunflow/SunflowAPI.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/SunflowAPI.java	2010-06-20 22:18:46.000000000 +0300
@@ -1,16 +1,8 @@
 package org.sunflow;
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.StringReader;
 import java.util.Locale;
 
-import org.codehaus.janino.ClassBodyEvaluator;
-import org.codehaus.janino.CompileException;
-import org.codehaus.janino.Scanner;
-import org.codehaus.janino.Parser.ParseException;
-import org.codehaus.janino.Scanner.ScanException;
 import org.sunflow.core.Camera;
 import org.sunflow.core.CameraLens;
 import org.sunflow.core.Display;
@@ -26,6 +18,7 @@
 import org.sunflow.core.SceneParser;
 import org.sunflow.core.Shader;
 import org.sunflow.core.Tesselatable;
+import org.sunflow.core.TextureCache;
 import org.sunflow.core.ParameterList.InterpolationType;
 import org.sunflow.image.ColorFactory;
 import org.sunflow.image.ColorFactory.ColorSpecificationException;
@@ -36,7 +29,6 @@
 import org.sunflow.math.Vector3;
 import org.sunflow.system.FileUtils;
 import org.sunflow.system.SearchPath;
-import org.sunflow.system.Timer;
 import org.sunflow.system.UI;
 import org.sunflow.system.UI.Module;
 
@@ -565,51 +557,53 @@
      * @return a valid SunflowAPI object or <code>null</code> on failure
      */
     public static SunflowAPI create(String filename, int frameNumber) {
-        if (filename == null)
-            return new SunflowAPI();
-        SunflowAPI api = null;
-        if (filename.endsWith(".java")) {
-            Timer t = new Timer();
-            UI.printInfo(Module.API, "Compiling \"" + filename + "\" ...");
-            t.start();
-            try {
-                FileInputStream stream = new FileInputStream(filename);
-                api = (SunflowAPI) ClassBodyEvaluator.createFastClassBodyEvaluator(new Scanner(filename, stream), SunflowAPI.class, ClassLoader.getSystemClassLoader());
-                stream.close();
-            } catch (CompileException e) {
-                UI.printError(Module.API, "Could not compile: \"%s\"", filename);
-                UI.printError(Module.API, "%s", e.getMessage());
-                return null;
-            } catch (ParseException e) {
-                UI.printError(Module.API, "Could not compile: \"%s\"", filename);
-                UI.printError(Module.API, "%s", e.getMessage());
-                return null;
-            } catch (ScanException e) {
-                UI.printError(Module.API, "Could not compile: \"%s\"", filename);
-                UI.printError(Module.API, "%s", e.getMessage());
-                return null;
-            } catch (IOException e) {
-                UI.printError(Module.API, "Could not compile: \"%s\"", filename);
-                UI.printError(Module.API, "%s", e.getMessage());
-                return null;
-            }
-            t.end();
-            UI.printInfo(Module.API, "Compile time: " + t.toString());
-            // allow relative paths
-            String currentFolder = new File(filename).getAbsoluteFile().getParentFile().getAbsolutePath();
-            api.includeSearchPath.addSearchPath(currentFolder);
-            api.textureSearchPath.addSearchPath(currentFolder);
-            UI.printInfo(Module.API, "Build script running ...");
-            t.start();
-            api.currentFrame(frameNumber);
-            api.build();
-            t.end();
-            UI.printInfo(Module.API, "Build script time: %s", t.toString());
-        } else {
-            api = new SunflowAPI();
-            api = api.include(filename) ? api : null;
-        }
-        return api;
+// EP : Don't need parser        
+//        if (filename == null)
+//            return new SunflowAPI();
+//        SunflowAPI api = null;
+//        if (filename.endsWith(".java")) {
+//            Timer t = new Timer();
+//            UI.printInfo(Module.API, "Compiling \"" + filename + "\" ...");
+//            t.start();
+//            try {
+//                FileInputStream stream = new FileInputStream(filename);
+//                api = (SunflowAPI) ClassBodyEvaluator.createFastClassBodyEvaluator(new Scanner(filename, stream), SunflowAPI.class, ClassLoader.getSystemClassLoader());
+//                stream.close();
+//            } catch (CompileException e) {
+//                UI.printError(Module.API, "Could not compile: \"%s\"", filename);
+//                UI.printError(Module.API, "%s", e.getMessage());
+//                return null;
+//            } catch (ParseException e) {
+//                UI.printError(Module.API, "Could not compile: \"%s\"", filename);
+//                UI.printError(Module.API, "%s", e.getMessage());
+//                return null;
+//            } catch (ScanException e) {
+//                UI.printError(Module.API, "Could not compile: \"%s\"", filename);
+//                UI.printError(Module.API, "%s", e.getMessage());
+//                return null;
+//            } catch (IOException e) {
+//                UI.printError(Module.API, "Could not compile: \"%s\"", filename);
+//                UI.printError(Module.API, "%s", e.getMessage());
+//                return null;
+//            }
+//            t.end();
+//            UI.printInfo(Module.API, "Compile time: " + t.toString());
+//            // allow relative paths
+//            String currentFolder = new File(filename).getAbsoluteFile().getParentFile().getAbsolutePath();
+//            api.includeSearchPath.addSearchPath(currentFolder);
+//            api.textureSearchPath.addSearchPath(currentFolder);
+//            UI.printInfo(Module.API, "Build script running ...");
+//            t.start();
+//            api.currentFrame(frameNumber);
+//            api.build();
+//            t.end();
+//            UI.printInfo(Module.API, "Build script time: %s", t.toString());
+//        } else {
+//            api = new SunflowAPI();
+//            api = api.include(filename) ? api : null;
+//        }
+//        return api;
+        throw new UnsupportedOperationException("Removed parser support  from SunFlow");
     }
 
     /**
@@ -620,35 +614,37 @@
      * @return <code>true</code> upon success, <code>false</code> otherwise
      */
     public static boolean translate(String filename, String outputFilename) {
-        FileSunflowAPI api = null;
-        try {
-            if (outputFilename.endsWith(".sca"))
-                api = new AsciiFileSunflowAPI(outputFilename);
-            else if (outputFilename.endsWith(".scb"))
-                api = new BinaryFileSunflowAPI(outputFilename);
-            else {
-                UI.printError(Module.API, "Unable to determine output filetype: \"%s\"", outputFilename);
-                return false;
-            }
-        } catch (IOException e) {
-            UI.printError(Module.API, "Unable to create output file - %s", e.getMessage());
-            return false;
-        }
-        String extension = filename.substring(filename.lastIndexOf('.') + 1);
-        SceneParser parser = PluginRegistry.parserPlugins.createObject(extension);
-        if (parser == null) {
-            UI.printError(Module.API, "Unable to find a suitable parser for: \"%s\"", filename);
-            return false;
-        }
-        try {
-            return parser.parse(filename, api);
-        } catch (RuntimeException e) {
-            e.printStackTrace();
-            UI.printError(Module.API, "Error occured during translation: %s", e.getMessage());
-            return false;
-        } finally {
-            api.close();
-        }
+// EP : Don't need parser        
+//        FileSunflowAPI api = null;
+//        try {
+//            if (outputFilename.endsWith(".sca"))
+//                api = new AsciiFileSunflowAPI(outputFilename);
+//            else if (outputFilename.endsWith(".scb"))
+//                api = new BinaryFileSunflowAPI(outputFilename);
+//            else {
+//                UI.printError(Module.API, "Unable to determine output filetype: \"%s\"", outputFilename);
+//                return false;
+//            }
+//        } catch (IOException e) {
+//            UI.printError(Module.API, "Unable to create output file - %s", e.getMessage());
+//            return false;
+//        }
+//        String extension = filename.substring(filename.lastIndexOf('.') + 1);
+//        SceneParser parser = PluginRegistry.parserPlugins.createObject(extension);
+//        if (parser == null) {
+//            UI.printError(Module.API, "Unable to find a suitable parser for: \"%s\"", filename);
+//            return false;
+//        }
+//        try {
+//            return parser.parse(filename, api);
+//        } catch (RuntimeException e) {
+//            e.printStackTrace();
+//            UI.printError(Module.API, "Error occured during translation: %s", e.getMessage());
+//            return false;
+//        } finally {
+//            api.close();
+//        }
+        throw new UnsupportedOperationException("Removed parser support from SunFlow");
     }
 
     /**
@@ -661,26 +657,28 @@
      *         otherwise.
      */
     public static SunflowAPI compile(String code) {
-        try {
-            Timer t = new Timer();
-            t.start();
-            SunflowAPI api = (SunflowAPI) ClassBodyEvaluator.createFastClassBodyEvaluator(new Scanner(null, new StringReader(code)), SunflowAPI.class, (ClassLoader) null);
-            t.end();
-            UI.printInfo(Module.API, "Compile time: %s", t.toString());
-            return api;
-        } catch (CompileException e) {
-            UI.printError(Module.API, "%s", e.getMessage());
-            return null;
-        } catch (ParseException e) {
-            UI.printError(Module.API, "%s", e.getMessage());
-            return null;
-        } catch (ScanException e) {
-            UI.printError(Module.API, "%s", e.getMessage());
-            return null;
-        } catch (IOException e) {
-            UI.printError(Module.API, "%s", e.getMessage());
-            return null;
-        }
+// EP : Don't need parser        
+//        try {
+//            Timer t = new Timer();
+//            t.start();
+//            SunflowAPI api = (SunflowAPI) ClassBodyEvaluator.createFastClassBodyEvaluator(new Scanner(null, new StringReader(code)), SunflowAPI.class, (ClassLoader) null);
+//            t.end();
+//            UI.printInfo(Module.API, "Compile time: %s", t.toString());
+//            return api;
+//        } catch (CompileException e) {
+//            UI.printError(Module.API, "%s", e.getMessage());
+//            return null;
+//        } catch (ParseException e) {
+//            UI.printError(Module.API, "%s", e.getMessage());
+//            return null;
+//        } catch (ScanException e) {
+//            UI.printError(Module.API, "%s", e.getMessage());
+//            return null;
+//        } catch (IOException e) {
+//            UI.printError(Module.API, "%s", e.getMessage());
+//            return null;
+//        }
+        throw new UnsupportedOperationException("Removed parser support from SunFlow");
     }
 
     /**
@@ -697,4 +695,12 @@
     public void currentFrame(int currentFrame) {
         this.currentFrame = currentFrame;
     }
+
+    // EP : Made texture cache local to a SunFlow API instance
+    private TextureCache textureCache = new TextureCache();
+    
+    public TextureCache getTextureCache() {
+        return this.textureCache;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/LightServer.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/LightServer.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/LightServer.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/LightServer.java	2010-12-04 18:53:08.000000000 +0200
@@ -24,12 +24,15 @@
     private int maxDiffuseDepth;
     private int maxReflectionDepth;
     private int maxRefractionDepth;
+    // EP : Added transparency management  
+    private int maxTransparencyDepth;
 
     // indirect illumination
     private CausticPhotonMapInterface causticPhotonMap;
     private GIEngine giEngine;
     private int photonCounter;
 
+
     LightServer(Scene scene) {
         this.scene = scene;
         lights = new LightSource[0];
@@ -41,6 +44,8 @@
         maxDiffuseDepth = 1;
         maxReflectionDepth = 4;
         maxRefractionDepth = 4;
+        // EP : Added transparency management
+        maxTransparencyDepth = 4;
 
         causticPhotonMap = null;
         giEngine = null;
@@ -64,6 +69,8 @@
         maxDiffuseDepth = options.getInt("depths.diffuse", maxDiffuseDepth);
         maxReflectionDepth = options.getInt("depths.reflection", maxReflectionDepth);
         maxRefractionDepth = options.getInt("depths.refraction", maxRefractionDepth);
+        // EP : Added transparency management
+        maxTransparencyDepth = options.getInt("depths.transparency", maxTransparencyDepth);
         String giEngineType = options.getString("gi.engine", null);
         giEngine = PluginRegistry.giEnginePlugins.createObject(giEngineType);
         String caustics = options.getString("caustics", null);
@@ -143,7 +150,8 @@
                         synchronized (LightServer.this) {
                             UI.taskUpdate(photonCounter);
                             photonCounter++;
-                            if (UI.taskCanceled())
+                            // EP : Manage renderer stop with interruptions
+                            if (Thread.currentThread().isInterrupted())
                                 return;
                         }
 
@@ -176,18 +184,19 @@
             photonThreads[i].setPriority(scene.getThreadPriority());
             photonThreads[i].start();
         }
-        for (int i = 0; i < photonThreads.length; i++) {
-            try {
+        // EP : Moved InterruptedException out of loop to be able to stop all rendering threads
+        try {
+            for (int i = 0; i < photonThreads.length; i++) {
                 photonThreads[i].join();
-            } catch (InterruptedException e) {
-                UI.printError(Module.LIGHT, "Photon thread %d of %d was interrupted", i + 1, photonThreads.length);
-                return false;
             }
-        }
-        if (UI.taskCanceled()) {
-            UI.taskStop(); // shut down task cleanly
+        } catch (InterruptedException e) {
+            for (int i = 0; i < photonThreads.length; i++) {
+                photonThreads[i].interrupt();
+            }
+            UI.printError(Module.BCKT, "Photon thread was interrupted");
             return false;
         }
+        // EP : End of modification
         photonTimer.end();
         UI.taskStop();
         UI.printInfo(Module.LIGHT, "Tracing time for %s photons: %s", type, photonTimer.toString());
@@ -294,7 +303,7 @@
     Color shadeHit(ShadingState state) {
         state.getInstance().prepareShadingState(state);
         Shader shader = getShader(state);
-        return (shader != null) ? shader.getRadiance(state) : Color.BLACK;
+         return (shader != null) ? shader.getRadiance(state) : Color.BLACK;
     }
 
     Color traceGlossy(ShadingState previous, Ray r, int i) {
@@ -357,4 +366,28 @@
         if (causticPhotonMap != null)
             causticPhotonMap.getSamples(state);
     }
+    
+    // EP : Added transparency management  
+    Color traceShadow(Ray r, ShadingState previous) {
+        float maxDist = r.getMax();
+        scene.traceShadow(r, previous.getIntersectionState());
+        if (previous.getIntersectionState().hit()) {
+            Shader previousShader = previous.getIntersectionState().instance.getShader(0);
+            if (previousShader == null || previousShader.isOpaque() || previous.getShadowDepth() >= maxTransparencyDepth) {
+                return Color.WHITE; // fully opaque hit
+            }
+            ShadingState sstate = ShadingState.createShadowState(previous, r);
+            sstate.getInstance().prepareShadingState(sstate);
+            Shader shader = getShader(sstate);
+            if (shader == null || shader.isOpaque())
+                return Color.WHITE;
+            Color opac = shader.getOpacity(sstate);
+            if (opac.isWhite())
+                return opac;
+            else
+                return opac.copy().madd(Color.sub(Color.WHITE, opac), sstate.traceTransparentShadow(maxDist));
+        } else
+            return Color.BLACK;
+    }
+    // EP : End of modification  
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/Ray.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/Ray.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/Ray.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/Ray.java	2010-06-20 22:18:46.000000000 +0300
@@ -214,4 +214,11 @@
     public final void setMax(float t) {
         tMax = t;
     }
+
+    // EP : Added transparency management  
+    public void setMinMax(float min, float max) {
+        tMin = min;
+        tMax = max;
+    }
+    // EP : end of modification  
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/Shader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/Shader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/Shader.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/Shader.java	2010-06-20 22:18:46.000000000 +0300
@@ -26,4 +26,18 @@
      * @param power power of the incoming photon.
      */
     public void scatterPhoton(ShadingState state, Color power);
+
+    // EP : Added transparency management  
+    /**
+     * Returns <code>true</code> if this shader is fully opaque. 
+     * This gives a quick way to find out if a shader needs further processing 
+     * when hit by a shadow ray. 
+     */
+    public boolean isOpaque(); 
+    
+    /**
+     * Returns how much light is blocked by this shader.  
+     */
+    public Color getOpacity(ShadingState state);    
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/ShadingState.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/ShadingState.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/ShadingState.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/ShadingState.java	2010-11-21 00:14:30.000000000 +0200
@@ -46,9 +46,12 @@
     private boolean includeSpecular;
     private LightSample lightSample;
     private PhotonStore map;
+    // EP : Added transparency management  
+    private int shadowDepth;
 
     static ShadingState createPhotonState(Ray r, IntersectionState istate, int i, PhotonStore map, LightServer server) {
-        ShadingState s = new ShadingState(null, istate, r, i, 4);
+        // EP : Added ignoreHalton parameter 
+        ShadingState s = new ShadingState(null, istate, r, i, 4, false);
         s.server = server;
         s.map = map;
         return s;
@@ -56,7 +59,8 @@
     }
 
     static ShadingState createState(IntersectionState istate, float rx, float ry, float time, Ray r, int i, int d, LightServer server) {
-        ShadingState s = new ShadingState(null, istate, r, i, d);
+        // EP : Added ignoreHalton parameter 
+        ShadingState s = new ShadingState(null, istate, r, i, d, false);
         s.server = server;
         s.rx = rx;
         s.ry = ry;
@@ -65,40 +69,48 @@
     }
 
     static ShadingState createDiffuseBounceState(ShadingState previous, Ray r, int i) {
-        ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
+        // EP : Added ignoreHalton parameter 
+        ShadingState s = new ShadingState(previous, previous.istate, r, i, 2, false);
         s.diffuseDepth++;
         return s;
     }
 
     static ShadingState createGlossyBounceState(ShadingState previous, Ray r, int i) {
-        ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
+        // EP : Added ignoreHalton parameter 
+        ShadingState s = new ShadingState(previous, previous.istate, r, i, 2, false);
         s.includeLights = false;
-        s.includeSpecular = false;
-        s.reflectionDepth++;
+        // EP : Set includeSpecular to true to get the reflects
+        s.includeSpecular = true;
+        // EP : Very dirty hack to let mirror shader manage more bounces than uber shader 
+        s.reflectionDepth += 4;
         return s;
     }
 
     static ShadingState createReflectionBounceState(ShadingState previous, Ray r, int i) {
-        ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
+        // EP : Added ignoreHalton parameter 
+        ShadingState s = new ShadingState(previous, previous.istate, r, i, 2, false);
         s.reflectionDepth++;
         return s;
     }
 
     static ShadingState createRefractionBounceState(ShadingState previous, Ray r, int i) {
-        ShadingState s = new ShadingState(previous, previous.istate, r, i, 2);
+        // EP : Added ignoreHalton parameter 
+        ShadingState s = new ShadingState(previous, previous.istate, r, i, 2, false);
         s.refractionDepth++;
         return s;
     }
 
     static ShadingState createFinalGatherState(ShadingState state, Ray r, int i) {
-        ShadingState finalGatherState = new ShadingState(state, state.istate, r, i, 2);
+        // EP : Added ignoreHalton parameter 
+        ShadingState finalGatherState = new ShadingState(state, state.istate, r, i, 2, false);
         finalGatherState.diffuseDepth++;
         finalGatherState.includeLights = false;
         finalGatherState.includeSpecular = false;
         return finalGatherState;
     }
 
-    private ShadingState(ShadingState previous, IntersectionState istate, Ray r, int i, int d) {
+    // EP : Added ignoreHalton parameter 
+    private ShadingState(ShadingState previous, IntersectionState istate, Ray r, int i, int d, boolean ignoreHalton) {
         this.r = r;
         this.istate = istate;
         this.i = i;
@@ -121,6 +133,8 @@
             diffuseDepth = previous.diffuseDepth;
             reflectionDepth = previous.reflectionDepth;
             refractionDepth = previous.refractionDepth;
+            // EP : copy shadow depth
+            shadowDepth = previous.shadowDepth;
             server = previous.server;
             map = previous.map;
             rx = previous.rx;
@@ -131,8 +145,12 @@
         behind = false;
         cosND = Float.NaN;
         includeLights = includeSpecular = true;
-        qmcD0I = QMC.halton(this.d, this.i);
-        qmcD1I = QMC.halton(this.d + 1, this.i);
+        // EP : Ignore Halton values for transparency computing
+        if (!ignoreHalton) {
+            qmcD0I = QMC.halton(this.d, this.i);
+            qmcD1I = QMC.halton(this.d + 1, this.i);
+        }
+        // EP : End of modification 
         result = null;
         bias = 0.001f;
     }
@@ -691,7 +709,8 @@
      * @return opacity along the shadow ray
      */
     public final Color traceShadow(Ray r) {
-        return server.getScene().traceShadow(r, istate);
+        // EP : Added  transparency management
+        return server.traceShadow(r, this);
     }
 
     /**
@@ -926,4 +945,22 @@
             throw new UnsupportedOperationException();
         }
     }
+
+    // EP : Added transparency management  
+    static ShadingState createShadowState(ShadingState previous, Ray r) {
+        ShadingState s = new ShadingState(previous, previous.istate, r, previous.i, previous.d, true);
+        s.shadowDepth++;
+        return s;
+    }
+    
+    public final int getShadowDepth() {
+        return shadowDepth;
+    }
+
+    public Color traceTransparentShadow(float oldMaxT) {
+        Ray tr = new Ray(r.ox, r.oy, r.oz, r.dx, r.dy, r.dz);
+        tr.setMinMax(r.getMax(), oldMaxT);
+        return traceShadow(tr);
+    }
+    // EP : end of modification  
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/Texture.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/Texture.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/Texture.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/Texture.java	2010-09-28 18:38:56.000000000 +0300
@@ -1,6 +1,8 @@
 package org.sunflow.core;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
 
 import org.sunflow.PluginRegistry;
 import org.sunflow.image.Bitmap;
@@ -23,6 +25,8 @@
     private boolean isLinear;
     private Bitmap bitmap;
     private int loaded;
+    // EP : Added bitmap transparency support
+    private boolean isTransparent;
 
     /**
      * Creates a new texture from the specfied file.
@@ -43,11 +47,38 @@
         try {
             UI.printInfo(Module.TEX, "Reading texture bitmap from: \"%s\" ...", filename);
             BitmapReader reader = PluginRegistry.bitmapReaderPlugins.createObject(extension);
+            // EP : Tolerate no extension in URLs
+            if (reader == null) {
+                try {
+                    // Choose a reader depending on the magic number of the file
+                    URL url = new URL(filename);
+                    InputStream in = url.openStream();
+                    int firstByte = in.read();
+                    int secondByte = in.read();
+                    in.close();                    
+                    reader = firstByte == 0xFF && secondByte == 0xD8
+                        ? PluginRegistry.bitmapReaderPlugins.createObject("jpg")
+                        : PluginRegistry.bitmapReaderPlugins.createObject("png");
+                } catch (IOException ex) {  
+                    // Don't try to search an other reader
+                }
+            }
+            // EP : End of modification
             if (reader != null) {
                 bitmap = reader.load(filename, isLinear);
                 if (bitmap.getWidth() == 0 || bitmap.getHeight() == 0)
                     bitmap = null;
             }
+            // EP : Check transparency
+            for (int x = 0; x < bitmap.getWidth(); x++) {
+                for (int y = 0; y < bitmap.getHeight(); y++) {
+                    if (bitmap.readAlpha(x, y) < 1) {
+                        this.isTransparent = true;
+                        break;
+                    }
+                }
+            }
+            // EP : End of modification
             if (bitmap == null) {
                 UI.printError(Module.TEX, "Bitmap reading failed");
                 bitmap = new BitmapBlack();
@@ -105,7 +136,51 @@
         c.madd(k11, c11);
         return c;
     }
-
+    
+    // EP : Added bitmap transparency support
+    public Color getOpacity(float x, float y) {
+        Bitmap bitmap = getBitmap();
+        x = MathUtils.frac(x);
+        y = MathUtils.frac(y);
+        float dx = x * (bitmap.getWidth() - 1);
+        float dy = y * (bitmap.getHeight() - 1);
+        int ix0 = (int) dx;
+        int iy0 = (int) dy;
+        int ix1 = (ix0 + 1) % bitmap.getWidth();
+        int iy1 = (iy0 + 1) % bitmap.getHeight();
+        float u = dx - ix0;
+        float v = dy - iy0;
+        u = u * u * (3.0f - (2.0f * u));
+        v = v * v * (3.0f - (2.0f * v));
+        float k00 = (1.0f - u) * (1.0f - v);
+        float a00 = bitmap.readAlpha(ix0, iy0);
+        float k01 = (1.0f - u) * v;
+        float a01 = bitmap.readAlpha(ix0, iy1);
+        float k10 = u * (1.0f - v);
+        float a10 = bitmap.readAlpha(ix1, iy0);
+        float k11 = u * v;
+        float a11 = bitmap.readAlpha(ix1, iy1);
+        float transparency = k00 * a00 +  k01 * a01 + k10 * a10 + k11 * a11;
+        if (transparency <= 0.9999) {
+            Color c00 = bitmap.readColor(ix0, iy0);
+            Color c01 = bitmap.readColor(ix0, iy1);
+            Color c10 = bitmap.readColor(ix1, iy0);
+            Color c11 = bitmap.readColor(ix1, iy1);
+            Color c = Color.mul(k00, c00);
+            c.madd(k01, c01);
+            c.madd(k10, c10);
+            c.madd(k11, c11);
+            return c.opposite().mul(transparency);
+        } else {
+            return Color.WHITE; 
+        }
+    }
+    
+    public boolean isTransparent() {
+        return this.isTransparent;
+    }
+    // EP : End of modification
+    
     public Vector3 getNormal(float x, float y, OrthoNormalBasis basis) {
         float[] rgb = getPixel(x, y).getRGB();
         return basis.transform(new Vector3(2 * rgb[0] - 1, 2 * rgb[1] - 1, 2 * rgb[2] - 1)).normalize();
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/TextureCache.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/TextureCache.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/TextureCache.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/TextureCache.java	2010-06-20 22:18:46.000000000 +0300
@@ -10,9 +10,11 @@
  * texture might be used more than once in your scene.
  */
 public final class TextureCache {
-    private static HashMap<String, Texture> textures = new HashMap<String, Texture>();
+    // EP : Removed static to enable GC to free Texture memory
+    private HashMap<String, Texture> textures = new HashMap<String, Texture>();
 
-    private TextureCache() {
+    // EP : Made texture cache local to SunFlow API
+    public TextureCache() {
     }
 
     /**
@@ -25,7 +27,8 @@
      * @return texture object
      * @see Texture
      */
-    public synchronized static Texture getTexture(String filename, boolean isLinear) {
+    // EP : Removed static to enable GC to free Texture memory
+    public synchronized Texture getTexture(String filename, boolean isLinear) {
         if (textures.containsKey(filename)) {
             UI.printInfo(Module.TEX, "Using cached copy for file \"%s\" ...", filename);
             return textures.get(filename);
@@ -40,7 +43,8 @@
      * Flush all textures from the cache, this will cause them to be reloaded
      * anew the next time they are accessed.
      */
-    public synchronized static void flush() {
+    // EP : Removed static to enable GC to free Texture memory
+    public synchronized void flush() {
         UI.printInfo(Module.TEX, "Flushing texture cache");
         textures.clear();
     }
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/accel/BoundingIntervalHierarchy.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/accel/BoundingIntervalHierarchy.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/accel/BoundingIntervalHierarchy.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/accel/BoundingIntervalHierarchy.java	2011-02-13 00:12:06.000000000 +0200
@@ -177,7 +177,13 @@
         float clipL = Float.NaN, clipR = Float.NaN, prevClip = Float.NaN;
         float split = Float.NaN, prevSplit;
         boolean wasLeft = true;
-        while (true) {
+        // EP : Added a loop counter to avoid endless loop
+        float[] gridBoxCopy = gridBox.clone();
+        float[] nodeBoxCopy = nodeBox.clone();
+        int loopCount = 0;
+        // EP : End of modification
+        do {
+        // while (true) {
             prevAxis = axis;
             prevSplit = split;
             // perform quick consistency checks
@@ -256,7 +262,8 @@
             // ensure we are making progress in the subdivision
             if (right == rightOrig) {
                 // all left
-                if (clipL <= split) {
+                // EP : Added additional test to avoid endless loop
+                if (clipL < split || (clipL == split && !(prevAxis == axis && prevSplit == split))) {
                     // keep looping on left half
                     gridBox[2 * axis + 1] = split;
                     prevClip = clipL;
@@ -274,7 +281,8 @@
             } else if (left > right) {
                 // all right
                 right = rightOrig;
-                if (clipR >= split) {
+                // EP : Added additional test to avoid endless loop
+                if (clipR > split || (clipR == split && !(prevAxis == axis && prevSplit == split))) {
                     // keep looping on right half
                     gridBox[2 * axis + 0] = split;
                     prevClip = clipR;
@@ -322,7 +330,15 @@
                 }
                 break;
             }
+        // EP : Added test to avoid endless loop
+        } while (loopCount++ < 100);
+        if (loopCount > 100) {
+            System.arraycopy(gridBoxCopy, 0, gridBox, 0, gridBox.length);
+            System.arraycopy(nodeBoxCopy, 0, nodeBox, 0, nodeBox.length);
+            return;
         }
+        // EP : End of modification
+        
         // compute index of child nodes
         int nextIndex = tempTree.getSize();
         // allocate left node
@@ -482,8 +498,13 @@
                             intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                             continue;
                         }
+                        // EP : Give up if stack is full
+                        if (stackPos == stack.length) {
+                            break pushloop;
+                        }
+                        // EP : End of modification
                         // ray passes through both nodes
-                        // push back node
+                        // push back node                        
                         stack[stackPos].node = back;
                         stack[stackPos].near = (tb >= intervalMin) ? tb : intervalMin;
                         stack[stackPos].far = intervalMax;
@@ -511,6 +532,11 @@
                             intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                             continue;
                         }
+                        // EP : Give up if stack is full
+                        if (stackPos == stack.length) {
+                            break pushloop;
+                        }
+                        // EP : End of modification
                         // ray passes through both nodes
                         // push back node
                         stack[stackPos].node = back;
@@ -541,6 +567,11 @@
                             intervalMax = (tf <= intervalMax) ? tf : intervalMax;
                             continue;
                         }
+                        // EP : Give up if stack is full
+                        if (stackPos == stack.length) {
+                            break pushloop;
+                        }
+                        // EP : End of modification
                         // ray passes through both nodes
                         // push back node
                         stack[stackPos].node = back;
@@ -597,7 +628,12 @@
             } // traversal loop
             do {
                 // stack is empty?
-                if (stackPos == 0)
+                if (stackPos == 0 
+                    // EP : Check ray values aren't NaN
+                    || Float.isNaN(r.dx) 
+                    || Float.isNaN(r.dy) 
+                    || Float.isNaN(r.dz))
+                    // EP : End of modification
                     return;
                 // move back up the stack
                 stackPos--;
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/light/ImageBasedLight.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/light/ImageBasedLight.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/light/ImageBasedLight.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/light/ImageBasedLight.java	2010-06-20 22:18:44.000000000 +0300
@@ -11,7 +11,6 @@
 import org.sunflow.core.Shader;
 import org.sunflow.core.ShadingState;
 import org.sunflow.core.Texture;
-import org.sunflow.core.TextureCache;
 import org.sunflow.image.Bitmap;
 import org.sunflow.image.Color;
 import org.sunflow.math.BoundingBox;
@@ -55,7 +54,8 @@
         numLowSamples = pl.getInt("lowsamples", numLowSamples);
         String filename = pl.getString("texture", null);
         if (filename != null)
-            texture = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
+            // EP : Made texture cache local to a SunFlow API instance
+            texture = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
 
         // no texture provided
         if (texture == null)
@@ -272,4 +272,14 @@
     public Instance createInstance() {
         return Instance.createTemporary(this, null, this);
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/light/SphereLight.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/light/SphereLight.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/light/SphereLight.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/light/SphereLight.java	2010-06-20 22:18:44.000000000 +0300
@@ -150,4 +150,14 @@
     public Instance createInstance() {
         return Instance.createTemporary(new Sphere(), Matrix4.translation(center.x, center.y, center.z).multiply(Matrix4.scale(radius)), this);
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/light/SunSkyLight.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/light/SunSkyLight.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/light/SunSkyLight.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/light/SunSkyLight.java	2010-10-08 19:38:16.000000000 +0300
@@ -315,6 +315,12 @@
         return getSkyRGB(basis.untransform(state.getRay().getDirection())).constrainRGB();
     }
 
+    // EP : Reused sun sky color
+    public Color getSunColor() {
+        return getSkyRGB(basis.untransform(sunDirWorld)).constrainRGB();
+    }
+    // EP : End of modification
+    
     public void scatterPhoton(ShadingState state, Color power) {
         // let photon escape
     }
@@ -334,4 +340,14 @@
     public Instance createInstance() {
         return Instance.createTemporary(this, null, this);
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/light/TriangleMeshLight.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/light/TriangleMeshLight.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/light/TriangleMeshLight.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/light/TriangleMeshLight.java	2010-06-20 22:18:44.000000000 +0300
@@ -269,4 +269,14 @@
             }
         }
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/modifiers/BumpMappingModifier.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/modifiers/BumpMappingModifier.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/modifiers/BumpMappingModifier.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/modifiers/BumpMappingModifier.java	2010-06-20 22:18:46.000000000 +0300
@@ -5,7 +5,6 @@
 import org.sunflow.core.ParameterList;
 import org.sunflow.core.ShadingState;
 import org.sunflow.core.Texture;
-import org.sunflow.core.TextureCache;
 import org.sunflow.math.OrthoNormalBasis;
 
 public class BumpMappingModifier implements Modifier {
@@ -20,7 +19,8 @@
     public boolean update(ParameterList pl, SunflowAPI api) {
         String filename = pl.getString("texture", null);
         if (filename != null)
-            bumpTexture = TextureCache.getTexture(api.resolveTextureFilename(filename), true);
+            // EP : Made texture cache local to a SunFlow API instance
+            bumpTexture = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), true);
         scale = pl.getFloat("scale", scale);
         return bumpTexture != null;
     }
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/modifiers/NormalMapModifier.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/modifiers/NormalMapModifier.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/modifiers/NormalMapModifier.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/modifiers/NormalMapModifier.java	2010-06-20 22:18:46.000000000 +0300
@@ -5,7 +5,6 @@
 import org.sunflow.core.ParameterList;
 import org.sunflow.core.ShadingState;
 import org.sunflow.core.Texture;
-import org.sunflow.core.TextureCache;
 import org.sunflow.math.OrthoNormalBasis;
 
 public class NormalMapModifier implements Modifier {
@@ -18,7 +17,8 @@
     public boolean update(ParameterList pl, SunflowAPI api) {
         String filename = pl.getString("texture", null);
         if (filename != null)
-            normalMap = TextureCache.getTexture(api.resolveTextureFilename(filename), true);
+            // EP : Made texture cache local to a SunFlow API instance
+            normalMap = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), true);
         return normalMap != null;
     }
 
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/photonmap/GlobalPhotonMap.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/photonmap/GlobalPhotonMap.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/photonmap/GlobalPhotonMap.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/photonmap/GlobalPhotonMap.java	2010-06-20 22:18:46.000000000 +0300
@@ -260,7 +260,8 @@
         t.start();
         balance();
         t.end();
-        UI.taskStop();
+        // EP : Replaced task management with interruptions
+        // UI.taskStop();
         UI.printInfo(Module.LIGHT, "Global photon map:");
         UI.printInfo(Module.LIGHT, "  * Photons stored:   %d", storedPhotons);
         UI.printInfo(Module.LIGHT, "  * Photons/estimate: %d", numGather);
@@ -328,7 +329,8 @@
             curr.data = irr.toRGBE();
             temp[i] = curr;
         }
-        UI.taskStop();
+        // EP : Replaced task management with interruptions
+        // UI.taskStop();
 
         // resize photon map to only include irradiance photons
         numGather /= 4;
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/primitive/CornellBox.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/primitive/CornellBox.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/primitive/CornellBox.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/primitive/CornellBox.java	2010-06-20 22:18:46.000000000 +0300
@@ -443,4 +443,14 @@
     public Instance createInstance() {
         return Instance.createTemporary(this, null, this);
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/primitive/Hair.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/primitive/Hair.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/primitive/Hair.java	2011-12-29 21:09:19.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/primitive/Hair.java	2010-06-20 22:18:46.000000000 +0300
@@ -258,4 +258,14 @@
     public PrimitiveList getBakingPrimitives() {
         return null;
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/renderer/BucketRenderer.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/renderer/BucketRenderer.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/renderer/BucketRenderer.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/renderer/BucketRenderer.java	2010-09-26 12:34:16.000000000 +0300
@@ -157,15 +157,22 @@
             renderThreads[i].setPriority(scene.getThreadPriority());
             renderThreads[i].start();
         }
-        for (int i = 0; i < renderThreads.length; i++) {
-            try {
-                renderThreads[i].join();
-            } catch (InterruptedException e) {
-                UI.printError(Module.BCKT, "Bucket processing thread %d of %d was interrupted", i + 1, renderThreads.length);
-            } finally {
-                renderThreads[i].updateStats();
+        // EP : Moved InterruptedException out of loop to be able to stop all rendering threads
+        try {
+            for (int i = 0; i < renderThreads.length; i++) {
+                try {
+                    renderThreads[i].join();
+                } finally {
+                    renderThreads[i].updateStats();
+                }
+            }
+        } catch (InterruptedException e) {
+            for (int i = 0; i < renderThreads.length; i++) {
+                renderThreads[i].interrupt();
             }
+            UI.printError(Module.BCKT, "Bucket processing was interrupted");
         }
+        // EP : End of modification
         UI.taskStop();
         timer.end();
         UI.printInfo(Module.BCKT, "Render time: %s", timer.toString());
@@ -183,7 +190,8 @@
 
         @Override
         public void run() {
-            while (true) {
+            // EP : Check rendering isn't interrupted 
+            while (!isInterrupted()) {
                 int bx, by;
                 synchronized (BucketRenderer.this) {
                     if (bucketCounter >= bucketCoords.length)
@@ -194,8 +202,6 @@
                     bucketCounter += 2;
                 }
                 renderBucket(display, bx, by, threadID, istate);
-                if (UI.taskCanceled())
-                    return;
             }
         }
 
@@ -251,8 +257,13 @@
             }
         }
         for (int x = 0; x < sbw - 1; x += maxStepSize)
-            for (int y = 0; y < sbh - 1; y += maxStepSize)
+            for (int y = 0; y < sbh - 1; y += maxStepSize) {
+                // EP : Check rendering isn't interrupted
+                if (Thread.currentThread().isInterrupted()) {
+                    return;
+                }
                 refineSamples(samples, sbw, x, y, maxStepSize, thresh, istate);
+            }
         if (dumpBuckets) {
             UI.printInfo(Module.BCKT, "Dumping bucket [%d, %d] to file ...", bx, by);
             GenericBitmap bitmap = new GenericBitmap(sbw, sbh);
@@ -297,7 +308,9 @@
                             if (Math.abs(dy) > fhs)
                                 continue;
                             float f = filter.get(dx, dy);
-                            c.madd(f, samples[s].c);
+                            // EP : Test if color isn't null
+                            if (samples[s].c != null)
+                                c.madd(f, samples[s].c);
                             a += f * samples[s].alpha;
                             weight += f;
 
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/renderer/MultipassRenderer.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/renderer/MultipassRenderer.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/renderer/MultipassRenderer.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/renderer/MultipassRenderer.java	2010-06-20 22:18:46.000000000 +0300
@@ -86,15 +86,22 @@
             renderThreads[i].setPriority(scene.getThreadPriority());
             renderThreads[i].start();
         }
-        for (int i = 0; i < renderThreads.length; i++) {
-            try {
-                renderThreads[i].join();
-            } catch (InterruptedException e) {
-                UI.printError(Module.BCKT, "Bucket processing thread %d of %d was interrupted", i + 1, renderThreads.length);
-            } finally {
-                renderThreads[i].updateStats();
+        // EP : Moved InterruptedException out of loop to be able to stop all rendering threads
+        try {
+            for (int i = 0; i < renderThreads.length; i++) {
+                try {
+                    renderThreads[i].join();
+                } finally {
+                    renderThreads[i].updateStats();
+                }
             }
+        } catch (InterruptedException e) {
+            for (int i = 0; i < renderThreads.length; i++) {
+                renderThreads[i].interrupt();
+            }
+            UI.printError(Module.BCKT, "Bucket processing was interrupted");
         }
+        // EP : End of modification
         UI.taskStop();
         timer.end();
         UI.printInfo(Module.BCKT, "Render time: %s", timer.toString());
@@ -114,7 +121,8 @@
 
         @Override
         public void run() {
-            while (true) {
+            // EP : Check rendering isn't interrupted or canceled
+            while (!isInterrupted()) {
                 int bx, by;
                 synchronized (MultipassRenderer.this) {
                     if (bucketCounter >= bucketCoords.length)
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/renderer/ProgressiveRenderer.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/renderer/ProgressiveRenderer.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/renderer/ProgressiveRenderer.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/renderer/ProgressiveRenderer.java	2010-06-20 22:18:46.000000000 +0300
@@ -58,15 +58,22 @@
             renderThreads[i] = new SmallBucketThread();
             renderThreads[i].start();
         }
-        for (int i = 0; i < renderThreads.length; i++) {
-            try {
-                renderThreads[i].join();
-            } catch (InterruptedException e) {
-                UI.printError(Module.IPR, "Thread %d of %d was interrupted", i + 1, renderThreads.length);
-            } finally {
-                renderThreads[i].updateStats();
+        // EP : Moved InterruptedException out of loop to be able to stop all rendering threads
+        try {
+            for (int i = 0; i < renderThreads.length; i++) {
+                try {
+                    renderThreads[i].join();
+                } finally {
+                    renderThreads[i].updateStats();
+                }
+            }
+        } catch (InterruptedException e) {
+            for (int i = 0; i < renderThreads.length; i++) {
+                renderThreads[i].interrupt();
             }
+            UI.printError(Module.IPR, "Thread was interrupted");
         }
+        // EP : End of modification
         UI.taskStop();
         t.end();
         UI.printInfo(Module.IPR, "Rendering time: %s", t.toString());
@@ -78,7 +85,8 @@
 
         @Override
         public void run() {
-            while (true) {
+            // EP : Check rendering isn't interrupted
+            while (!isInterrupted()) {
                 int n = progressiveRenderNext(istate);
                 synchronized (ProgressiveRenderer.this) {
                     if (counter >= counterMax)
@@ -86,8 +94,6 @@
                     counter += n;
                     UI.taskUpdate(counter);
                 }
-                if (UI.taskCanceled())
-                    return;
             }
         }
 
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/renderer/SimpleRenderer.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/renderer/SimpleRenderer.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/renderer/SimpleRenderer.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/renderer/SimpleRenderer.java	2010-06-20 22:18:46.000000000 +0300
@@ -41,15 +41,23 @@
             renderThreads[i] = new BucketThread();
             renderThreads[i].start();
         }
-        for (int i = 0; i < renderThreads.length; i++) {
-            try {
-                renderThreads[i].join();
-            } catch (InterruptedException e) {
-                UI.printError(Module.BCKT, "Bucket processing thread %d of %d was interrupted", i + 1, renderThreads.length);
-            } finally {
-                renderThreads[i].updateStats();
+        // EP : Moved InterruptedException out of loop to be able to stop all rendering threads
+        try {
+            for (int i = 0; i < renderThreads.length; i++) {
+                try {
+                    renderThreads[i].join();
+                } finally {
+                    renderThreads[i].updateStats();
+                }
+            }
+        } catch (InterruptedException e) {
+            for (int i = 0; i < renderThreads.length; i++) {
+                renderThreads[i].interrupt();
             }
+            UI.printError(Module.BCKT, "Bucket processing was interrupted");
         }
+        UI.taskStop();
+        // EP : End of modification
         timer.end();
         UI.printInfo(Module.BCKT, "Render time: %s", timer.toString());
         display.imageEnd();
@@ -60,7 +68,8 @@
 
         @Override
         public void run() {
-            while (true) {
+            // EP : Check rendering isn't interrupted 
+            while (!isInterrupted()) {
                 int bx, by;
                 synchronized (SimpleRenderer.this) {
                     if (bucketCounter >= numBuckets)
@@ -90,6 +99,9 @@
 
         for (int y = 0, i = 0; y < bh; y++) {
             for (int x = 0; x < bw; x++, i++) {
+                // EP : Check rendering isn't interrupted
+                if (Thread.currentThread().isInterrupted())
+                    return;
                 ShadingState state = scene.getRadiance(istate, x0 + x, imageHeight - 1 - (y0 + y), 0.0, 0.0, 0.0, 0, 0, null);
                 bucketRGB[i] = (state != null) ? state.getResult() : Color.BLACK;
                 bucketAlpha[i] = (state != null) ? 1 : 0;
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/AmbientOcclusionShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/AmbientOcclusionShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/AmbientOcclusionShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/AmbientOcclusionShader.java	2010-09-28 11:28:50.000000000 +0300
@@ -45,4 +45,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+    
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/AnisotropicWardShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/AnisotropicWardShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/AnisotropicWardShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/AnisotropicWardShader.java	2010-09-28 11:29:26.000000000 +0300
@@ -208,4 +208,14 @@
             state.traceReflectionPhoton(r, power);
         }
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ConstantShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ConstantShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ConstantShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ConstantShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -24,4 +24,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/DiffuseShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/DiffuseShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/DiffuseShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/DiffuseShader.java	2010-09-28 11:29:50.000000000 +0300
@@ -58,4 +58,14 @@
             state.traceDiffusePhoton(new Ray(state.getPoint(), w), power);
         }
     }
+    
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/GlassShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/GlassShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/GlassShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/GlassShader.java	2011-03-13 00:31:10.000000000 +0200
@@ -136,4 +136,14 @@
             }
         }
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return absorptionColor.isWhite();
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return absorptionColor;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/IDShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/IDShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/IDShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/IDShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -20,4 +20,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/MirrorShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/MirrorShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/MirrorShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/MirrorShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -59,4 +59,14 @@
         dir.z = (dn * state.getNormal().z) + state.getRay().getDirection().z;
         state.traceReflectionPhoton(new Ray(state.getPoint(), dir), power);
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/NormalShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/NormalShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/NormalShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/NormalShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -24,4 +24,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/PhongShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/PhongShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/PhongShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/PhongShader.java	2010-09-28 11:34:54.000000000 +0300
@@ -82,4 +82,14 @@
             state.traceReflectionPhoton(new Ray(state.getPoint(), w), power);
         }
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/PrimIDShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/PrimIDShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/PrimIDShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/PrimIDShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -23,4 +23,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/QuickGrayShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/QuickGrayShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/QuickGrayShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/QuickGrayShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -56,4 +56,14 @@
             state.traceDiffusePhoton(new Ray(state.getPoint(), w), power);
         }
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ShinyDiffuseShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ShinyDiffuseShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ShinyDiffuseShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ShinyDiffuseShader.java	2010-09-29 12:19:42.000000000 +0300
@@ -24,6 +24,12 @@
         return true;
     }
 
+    // EP : Added getter to read shininess from subclasses
+    protected float getShininess() {
+        return this.refl;
+    }
+    // EP : End of modification
+    
     public Color getDiffuse(ShadingState state) {
         return diff;
     }
@@ -90,4 +96,14 @@
             state.traceReflectionPhoton(new Ray(state.getPoint(), dir), power);
         }
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/SimpleShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/SimpleShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/SimpleShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/SimpleShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -17,4 +17,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -4,7 +4,6 @@
 import org.sunflow.core.ParameterList;
 import org.sunflow.core.ShadingState;
 import org.sunflow.core.Texture;
-import org.sunflow.core.TextureCache;
 import org.sunflow.image.Color;
 
 public class TexturedAmbientOcclusionShader extends AmbientOcclusionShader {
@@ -18,7 +17,8 @@
     public boolean update(ParameterList pl, SunflowAPI api) {
         String filename = pl.getString("texture", null);
         if (filename != null)
-            tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
+            // EP : Made texture cache local to a SunFlow API instance
+            tex = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
         return tex != null && super.update(pl, api);
     }
 
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedDiffuseShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedDiffuseShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedDiffuseShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedDiffuseShader.java	2010-10-11 12:27:38.000000000 +0300
@@ -2,10 +2,11 @@
 
 import org.sunflow.SunflowAPI;
 import org.sunflow.core.ParameterList;
+import org.sunflow.core.Ray;
 import org.sunflow.core.ShadingState;
 import org.sunflow.core.Texture;
-import org.sunflow.core.TextureCache;
 import org.sunflow.image.Color;
+import org.sunflow.math.Vector3;
 
 public class TexturedDiffuseShader extends DiffuseShader {
     private Texture tex;
@@ -18,7 +19,8 @@
     public boolean update(ParameterList pl, SunflowAPI api) {
         String filename = pl.getString("texture", null);
         if (filename != null)
-            tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
+            // EP : Made texture cache local to a SunFlow API instance
+            tex = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
         return tex != null && super.update(pl, api);
     }
 
@@ -26,4 +28,32 @@
     public Color getDiffuse(ShadingState state) {
         return tex.getPixel(state.getUV().x, state.getUV().y);
     }
+
+    // EP : Added transparency management  
+    @Override
+    public Color getRadiance(ShadingState state) {
+        Color opacity;
+        if (isOpaque() || (opacity = getOpacity(state)).isWhite()) {
+            // Pixel is fully opaque
+            return super.getRadiance(state);
+        } else {
+            state.faceforward();
+            state.initLightSamples();
+            state.initCausticSamples();
+            Vector3 refrDir = state.getRay().getDirection();
+            Color refraction = state.traceRefraction(new Ray(state.getPoint(), refrDir), 0);
+            return Color.sub(Color.WHITE, opacity).mul(refraction);
+        }
+    }
+
+    @Override
+    public boolean isOpaque() {
+        return !(tex.isTransparent());
+    }
+    
+    @Override
+    public Color getOpacity(ShadingState state) {
+        return tex.getOpacity(state.getUV().x, state.getUV().y);
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedPhongShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedPhongShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedPhongShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedPhongShader.java	2010-10-11 13:02:34.000000000 +0300
@@ -2,10 +2,11 @@
 
 import org.sunflow.SunflowAPI;
 import org.sunflow.core.ParameterList;
+import org.sunflow.core.Ray;
 import org.sunflow.core.ShadingState;
 import org.sunflow.core.Texture;
-import org.sunflow.core.TextureCache;
 import org.sunflow.image.Color;
+import org.sunflow.math.Vector3;
 
 public class TexturedPhongShader extends PhongShader {
     private Texture tex;
@@ -18,7 +19,8 @@
     public boolean update(ParameterList pl, SunflowAPI api) {
         String filename = pl.getString("texture", null);
         if (filename != null)
-            tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
+            // EP : Made texture cache local to a SunFlow API instance
+            tex = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
         return tex != null && super.update(pl, api);
     }
 
@@ -26,4 +28,31 @@
     public Color getDiffuse(ShadingState state) {
         return tex.getPixel(state.getUV().x, state.getUV().y);
     }
+
+    // EP : Added transparency management  
+    @Override
+    public Color getRadiance(ShadingState state) {
+        Color opacity;
+        if (isOpaque() || (opacity = getOpacity(state)).isWhite()) {
+            return super.getRadiance(state);
+        } else {
+            state.faceforward();
+            state.initLightSamples();
+            state.initCausticSamples();
+            Vector3 refrDir = state.getRay().getDirection();
+            Color refraction = state.traceRefraction(new Ray(state.getPoint(), refrDir), 0);
+            return Color.sub(Color.WHITE, opacity).mul(refraction);
+        }
+    }
+    
+    @Override
+    public boolean isOpaque() {
+        return !(tex.isTransparent());
+    }
+    
+    @Override
+    public Color getOpacity(ShadingState state) {
+        return tex.getOpacity(state.getUV().x, state.getUV().y);
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedShinyDiffuseShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedShinyDiffuseShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedShinyDiffuseShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedShinyDiffuseShader.java	2010-10-11 12:51:26.000000000 +0300
@@ -2,10 +2,11 @@
 
 import org.sunflow.SunflowAPI;
 import org.sunflow.core.ParameterList;
+import org.sunflow.core.Ray;
 import org.sunflow.core.ShadingState;
 import org.sunflow.core.Texture;
-import org.sunflow.core.TextureCache;
 import org.sunflow.image.Color;
+import org.sunflow.math.Vector3;
 
 public class TexturedShinyDiffuseShader extends ShinyDiffuseShader {
     private Texture tex;
@@ -18,7 +19,8 @@
     public boolean update(ParameterList pl, SunflowAPI api) {
         String filename = pl.getString("texture", null);
         if (filename != null)
-            tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
+            // EP : Made texture cache local to a SunFlow API instance
+            tex = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
         return tex != null && super.update(pl, api);
     }
 
@@ -26,4 +28,56 @@
     public Color getDiffuse(ShadingState state) {
         return tex.getPixel(state.getUV().x, state.getUV().y);
     }
+
+    // EP : Added transparency management  
+    @Override
+    public Color getRadiance(ShadingState state) {
+        Color opacity;
+        if (isOpaque() || (opacity = getOpacity(state)).isWhite()) {
+            // Pixel is fully opaque
+            return super.getRadiance(state);
+        } else {
+            state.faceforward();
+            // direct lighting
+            state.initLightSamples();
+            state.initCausticSamples();
+            Color d = Color.sub(Color.WHITE, opacity);
+            Vector3 refrDir = state.getRay().getDirection();
+            Color refraction = state.traceRefraction(new Ray(state.getPoint(), refrDir), 0);
+            d.mul(refraction);
+            if (!state.includeSpecular()
+                || opacity.isBlack()) { // No reflection when fully transparent
+                return d;
+            }
+            float cos = state.getCosND();
+            float dn = 2 * cos;
+            Vector3 refDir = new Vector3();
+            refDir.x = (dn * state.getNormal().x) + state.getRay().getDirection().x;
+            refDir.y = (dn * state.getNormal().y) + state.getRay().getDirection().y;
+            refDir.z = (dn * state.getNormal().z) + state.getRay().getDirection().z;
+            Ray refRay = new Ray(state.getPoint(), refDir);
+            // compute Fresnel term
+            cos = 1 - cos;
+            float cos2 = cos * cos;
+            float cos5 = cos2 * cos2 * cos;
+
+            Color ret = Color.white();
+            Color r = Color.sub(Color.WHITE, opacity).mul(getShininess());
+            ret.sub(r);
+            ret.mul(cos5);
+            ret.add(r);
+            return d.add(ret.mul(state.traceReflection(refRay, 0)));
+        }
+    }
+    
+    @Override
+    public boolean isOpaque() {
+        return !(tex.isTransparent());
+    }
+    
+    @Override
+    public Color getOpacity(ShadingState state) {
+        return tex.getOpacity(state.getUV().x, state.getUV().y);
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedWardShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedWardShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/TexturedWardShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/TexturedWardShader.java	2010-09-29 12:21:22.000000000 +0300
@@ -4,7 +4,6 @@
 import org.sunflow.core.ParameterList;
 import org.sunflow.core.ShadingState;
 import org.sunflow.core.Texture;
-import org.sunflow.core.TextureCache;
 import org.sunflow.image.Color;
 
 public class TexturedWardShader extends AnisotropicWardShader {
@@ -18,7 +17,8 @@
     public boolean update(ParameterList pl, SunflowAPI api) {
         String filename = pl.getString("texture", null);
         if (filename != null)
-            tex = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
+            // EP : Made texture cache local to a SunFlow API instance
+            tex = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
         return tex != null && super.update(pl, api);
     }
 
@@ -26,4 +26,16 @@
     public Color getDiffuse(ShadingState state) {
         return tex.getPixel(state.getUV().x, state.getUV().y);
     }
+
+    // EP : Added transparency management  
+    @Override
+    public boolean isOpaque() {
+        return !(tex.isTransparent());
+    }
+    
+    @Override
+    public Color getOpacity(ShadingState state) {
+        return tex.getOpacity(state.getUV().x, state.getUV().y);
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/UVShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/UVShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/UVShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/UVShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -19,4 +19,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/UberShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/UberShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/UberShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/UberShader.java	2010-10-11 13:02:22.000000000 +0300
@@ -6,7 +6,6 @@
 import org.sunflow.core.Shader;
 import org.sunflow.core.ShadingState;
 import org.sunflow.core.Texture;
-import org.sunflow.core.TextureCache;
 import org.sunflow.image.Color;
 import org.sunflow.math.MathUtils;
 import org.sunflow.math.OrthoNormalBasis;
@@ -36,10 +35,12 @@
         String filename;
         filename = pl.getString("diffuse.texture", null);
         if (filename != null)
-            diffmap = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
+            // EP : Made texture cache local to a SunFlow API instance
+            diffmap = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
         filename = pl.getString("specular.texture", null);
         if (filename != null)
-            specmap = TextureCache.getTexture(api.resolveTextureFilename(filename), false);
+            // EP : Made texture cache local to a SunFlow API instance
+            specmap = api.getTextureCache().getTexture(api.resolveTextureFilename(filename), false);
         diffBlend = MathUtils.clamp(pl.getFloat("diffuse.blend", diffBlend), 0, 1);
         specBlend = MathUtils.clamp(pl.getFloat("specular.blend", diffBlend), 0, 1);
         glossyness = MathUtils.clamp(pl.getFloat("glossyness", glossyness), 0, 1);
@@ -61,30 +62,41 @@
         // direct lighting
         state.initLightSamples();
         state.initCausticSamples();
-        Color d = getDiffuse(state);
-        Color lr = state.diffuse(d);
-        if (!state.includeSpecular())
-            return lr;
-        if (glossyness == 0) {
-            float cos = state.getCosND();
-            float dn = 2 * cos;
-            Vector3 refDir = new Vector3();
-            refDir.x = (dn * state.getNormal().x) + state.getRay().getDirection().x;
-            refDir.y = (dn * state.getNormal().y) + state.getRay().getDirection().y;
-            refDir.z = (dn * state.getNormal().z) + state.getRay().getDirection().z;
-            Ray refRay = new Ray(state.getPoint(), refDir);
-            // compute Fresnel term
-            cos = 1 - cos;
-            float cos2 = cos * cos;
-            float cos5 = cos2 * cos2 * cos;
-            Color spec = getSpecular(state);
-            Color ret = Color.white();
-            ret.sub(spec);
-            ret.mul(cos5);
-            ret.add(spec);
-            return lr.add(ret.mul(state.traceReflection(refRay, 0)));
-        } else
-            return lr.add(state.specularPhong(getSpecular(state), 2 / glossyness, numSamples));
+        // EP : Added transparency management  
+        Color opacity;
+        if (!isOpaque() && !(opacity = getOpacity(state)).isWhite()) {
+            Vector3 refrDir = state.getRay().getDirection();
+            Color refraction = state.traceRefraction(new Ray(state.getPoint(), refrDir), 0);
+            return Color.sub(Color.WHITE, opacity).mul(refraction);
+        } else {
+        // EP : End of modification
+            Color d = getDiffuse(state);
+            Color lr = state.diffuse(d);
+            if (!state.includeSpecular())
+                return lr;
+            if (glossyness == 0) {
+                float cos = state.getCosND();
+                float dn = 2 * cos;
+                Vector3 refDir = new Vector3();
+                refDir.x = (dn * state.getNormal().x) + state.getRay().getDirection().x;
+                refDir.y = (dn * state.getNormal().y) + state.getRay().getDirection().y;
+                refDir.z = (dn * state.getNormal().z) + state.getRay().getDirection().z;
+                Ray refRay = new Ray(state.getPoint(), refDir);
+                // compute Fresnel term
+                cos = 1 - cos;
+                float cos2 = cos * cos;
+                float cos5 = cos2 * cos2 * cos;
+                Color spec = getSpecular(state);
+                Color ret = Color.white();
+                ret.sub(spec);
+                ret.mul(cos5);
+                ret.add(spec);
+                return lr.add(ret.mul(state.traceReflection(refRay, 0)));
+            } else
+                return lr.add(state.specularPhong(getSpecular(state), 2 / glossyness, numSamples));
+        // EP : Added transparency management  
+        }
+        // EP : End of modification
     }
 
     public void scatterPhoton(ShadingState state, Color power) {
@@ -138,4 +150,14 @@
             }
         }
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return diffmap == null || !(diffmap.isTransparent());
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return diffmap != null ? diffmap.getOpacity(state.getUV().x, state.getUV().y) : Color.WHITE;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ViewCausticsShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ViewCausticsShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ViewCausticsShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ViewCausticsShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -25,4 +25,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ViewGlobalPhotonsShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ViewGlobalPhotonsShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ViewGlobalPhotonsShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ViewGlobalPhotonsShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -18,4 +18,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ViewIrradianceShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ViewIrradianceShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/ViewIrradianceShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/ViewIrradianceShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -18,4 +18,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/core/shader/WireframeShader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/WireframeShader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/core/shader/WireframeShader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/core/shader/WireframeShader.java	2010-06-20 22:18:46.000000000 +0300
@@ -73,4 +73,14 @@
 
     public void scatterPhoton(ShadingState state, Color power) {
     }
+
+    // EP : Added transparency management  
+    public boolean isOpaque() {
+        return true;
+    }
+    
+    public Color getOpacity(ShadingState state) {
+        return null;
+    }
+    // EP : End of modification
 }
\ No newline at end of file
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/image/Color.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/Color.java
--- sunflow-0.07.2.svn396/src/org/sunflow/image/Color.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/Color.java	2010-09-29 10:28:50.000000000 +0300
@@ -116,6 +116,12 @@
         return r <= 0 && g <= 0 && b <= 0;
     }
 
+    // EP : Added to manage white colors
+    public boolean isWhite() {
+        return r >= 1 && g >= 1 && b >= 1;
+    }
+    // EP : End of modification
+
     public final float getLuminance() {
         return (0.2989f * r) + (0.5866f * g) + (0.1145f * b);
     }
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/image/readers/BMPBitmapReader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/BMPBitmapReader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/image/readers/BMPBitmapReader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/BMPBitmapReader.java	2010-06-20 22:18:46.000000000 +0300
@@ -1,8 +1,11 @@
 package org.sunflow.image.readers;
 
 import java.awt.image.BufferedImage;
-import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 
 import javax.imageio.ImageIO;
 
@@ -13,8 +16,25 @@
 
 public class BMPBitmapReader implements BitmapReader {
     public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
-        // regular image, load using Java api - ignore alpha channel
-        BufferedImage bi = ImageIO.read(new File(filename));
+        // EP : Try to read filename as an URL or as a file
+        InputStream f;
+        try {
+            // Let's try first to read filename as an URL
+            f = new URL(filename).openStream();
+        } catch (MalformedURLException ex) {
+            // Let's try to read filename as a file
+            f = new FileInputStream(filename);
+        }
+
+        BufferedImage bi;
+        try {
+            // regular image, load using Java api - ignore alpha channel
+            bi = ImageIO.read(f);
+        } finally {
+            f.close();
+        }
+        // EP : End of modification
+
         int width = bi.getWidth();
         int height = bi.getHeight();
         byte[] pixels = new byte[3 * width * height];
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/image/readers/HDRBitmapReader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/HDRBitmapReader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/image/readers/HDRBitmapReader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/HDRBitmapReader.java	2010-06-20 22:18:46.000000000 +0300
@@ -4,6 +4,8 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 
 import org.sunflow.image.Bitmap;
 import org.sunflow.image.BitmapReader;
@@ -11,8 +13,19 @@
 
 public class HDRBitmapReader implements BitmapReader {
     public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
-        // load radiance rgbe file
-        InputStream f = new BufferedInputStream(new FileInputStream(filename));
+        // EP : Try to read filename as an URL or as a file
+        InputStream f;
+        try {
+          // Let's try first to read filename as an URL
+          f = new URL(filename).openStream();
+        } catch (MalformedURLException ex) {
+          // Let's try to read filename as a file
+          f = new FileInputStream(filename);
+        }
+
+        f = new BufferedInputStream(f);
+        // End of modification
+
         // parse header
         boolean parseWidth = false, parseHeight = false;
         int width = 0, height = 0;
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/image/readers/IGIBitmapReader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/IGIBitmapReader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/image/readers/IGIBitmapReader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/IGIBitmapReader.java	2010-06-20 22:18:46.000000000 +0300
@@ -4,6 +4,8 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 
 import org.sunflow.image.Bitmap;
 import org.sunflow.image.BitmapReader;
@@ -15,7 +17,19 @@
  */
 public class IGIBitmapReader implements BitmapReader {
     public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
-        InputStream stream = new BufferedInputStream(new FileInputStream(filename));
+        // EP : Try to read filename as an URL or as a file
+        InputStream stream;
+        try {
+          // Let's try first to read filename as an URL
+          stream = new URL(filename).openStream();
+        } catch (MalformedURLException ex) {
+          // Let's try to read filename as a file
+          stream = new FileInputStream(filename);
+        }
+
+        stream = new BufferedInputStream(stream);
+        // End of modification
+
         // read header
         int magic = read32i(stream);
         int version = read32i(stream);
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/image/readers/JPGBitmapReader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/JPGBitmapReader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/image/readers/JPGBitmapReader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/JPGBitmapReader.java	2010-10-18 23:51:52.000000000 +0300
@@ -1,8 +1,13 @@
 package org.sunflow.image.readers;
 
+import java.awt.Graphics2D;
+import java.awt.Transparency;
 import java.awt.image.BufferedImage;
-import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 
 import javax.imageio.ImageIO;
 
@@ -13,14 +18,47 @@
 
 public class JPGBitmapReader implements BitmapReader {
     public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
-        // regular image, load using Java api - ignore alpha channel
-        BufferedImage bi = ImageIO.read(new File(filename));
+        // EP : Try to read filename as an URL or as a file
+        InputStream f;
+        try {
+            // Let's try first to read filename as an URL
+            f = new URL(filename).openStream();
+        } catch (MalformedURLException ex) {
+            // Let's try to read filename as a file
+            f = new FileInputStream(filename);
+        }
+
+        BufferedImage bi;
+        try {
+            // regular image, load using Java api - ignore alpha channel
+            bi = ImageIO.read(f);
+        } finally {
+            f.close();
+        }
+        
+        if (bi.getType() != BufferedImage.TYPE_INT_RGB
+            && bi.getType() != BufferedImage.TYPE_INT_ARGB) {
+          // Transform as TYPE_INT_ARGB or TYPE_INT_RGB (much faster than calling image.getRGB())
+          BufferedImage tmp = new BufferedImage(bi.getWidth(), bi.getHeight(), 
+                  bi.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB);
+          Graphics2D g = (Graphics2D)tmp.getGraphics();
+          g.drawImage(bi, null, 0, 0);
+          g.dispose();
+          bi = tmp;
+        }
+        // Retrieve image bits
+        int [] imageBits = (int [])bi.getRaster().getDataElements(0, 0, bi.getWidth(), bi.getHeight(), null);
+        // EP : End of modification
+
         int width = bi.getWidth();
         int height = bi.getHeight();
         byte[] pixels = new byte[3 * width * height];
         for (int y = 0, index = 0; y < height; y++) {
             for (int x = 0; x < width; x++, index += 3) {
-                int argb = bi.getRGB(x, height - 1 - y);
+                // EP : Retrieved image data with raster data 
+                // int argb = bi.getRGB(x, height - 1 - y);
+                int argb = imageBits [x + (height - 1 - y) * width];                
+                // EP : End of modification
                 pixels[index + 0] = (byte) (argb >> 16);
                 pixels[index + 1] = (byte) (argb >> 8);
                 pixels[index + 2] = (byte) argb;
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/image/readers/PNGBitmapReader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/PNGBitmapReader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/image/readers/PNGBitmapReader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/PNGBitmapReader.java	2011-01-16 21:27:56.000000000 +0200
@@ -1,8 +1,13 @@
 package org.sunflow.image.readers;
 
+import java.awt.Graphics2D;
+import java.awt.Transparency;
 import java.awt.image.BufferedImage;
-import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 
 import javax.imageio.ImageIO;
 
@@ -13,18 +18,54 @@
 
 public class PNGBitmapReader implements BitmapReader {
     public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
-        // regular image, load using Java api
-        BufferedImage bi = ImageIO.read(new File(filename));
+        // EP : Try to read filename as an URL or as a file
+        InputStream f;
+        try {
+            // Let's try first to read filename as an URL
+            f = new URL(filename).openStream();
+        } catch (MalformedURLException ex) {
+            // Let's try to read filename as a file
+            f = new FileInputStream(filename);
+        }
+
+        BufferedImage bi;
+        try {
+            // regular image, load using Java api 
+            bi = ImageIO.read(f);
+        } finally {
+            f.close();
+        }
+        
+        boolean opaque = bi.getTransparency() == Transparency.OPAQUE;
+        if (bi.getType() != BufferedImage.TYPE_INT_RGB
+            && bi.getType() != BufferedImage.TYPE_INT_ARGB) {
+            // Transform as TYPE_INT_ARGB or TYPE_INT_RGB (much faster than calling image.getRGB())
+            BufferedImage tmp = new BufferedImage(bi.getWidth(), bi.getHeight(), 
+                    opaque ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB);
+            Graphics2D g = (Graphics2D)tmp.getGraphics();
+            g.drawImage(bi, null, 0, 0);
+            g.dispose();
+            bi = tmp;
+        }
+        // Retrieve image bits
+        int [] imageBits = (int [])bi.getRaster().getDataElements(0, 0, bi.getWidth(), bi.getHeight(), null);
+        // EP : End of modification
+        
         int width = bi.getWidth();
         int height = bi.getHeight();
         byte[] pixels = new byte[4 * width * height];
         for (int y = 0, index = 0; y < height; y++) {
             for (int x = 0; x < width; x++, index += 4) {
-                int argb = bi.getRGB(x, height - 1 - y);
+                // EP : Retrieved image data with raster data 
+                // int argb = bi.getRGB(x, height - 1 - y);
+                int argb = imageBits [x + (height - 1 - y) * width];                
+                // EP : End of modification
                 pixels[index + 0] = (byte) (argb >> 16);
                 pixels[index + 1] = (byte) (argb >> 8);
                 pixels[index + 2] = (byte) argb;
-                pixels[index + 3] = (byte) (argb >> 24);
+                // EP : Added opaque transparency  
+                pixels[index + 3] = opaque ? (byte)0xFF : (byte) (argb >> 24);
+                // EP : End of modification 
             }
         }
         if (!isLinear) {
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/image/readers/TGABitmapReader.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/TGABitmapReader.java
--- sunflow-0.07.2.svn396/src/org/sunflow/image/readers/TGABitmapReader.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/image/readers/TGABitmapReader.java	2010-06-20 22:18:46.000000000 +0300
@@ -4,6 +4,8 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
 
 import org.sunflow.image.Bitmap;
 import org.sunflow.image.BitmapReader;
@@ -16,7 +18,19 @@
     private static final int[] CHANNEL_INDEX = { 2, 1, 0, 3 };
 
     public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
-        InputStream f = new BufferedInputStream(new FileInputStream(filename));
+        // EP : Try to read filename as an URL or as a file
+        InputStream f;
+        try {
+          // Let's try first to read filename as an URL
+          f = new URL(filename).openStream();
+        } catch (MalformedURLException ex) {
+          // Let's try to read filename as a file
+          f = new FileInputStream(filename);
+        }
+
+        f = new BufferedInputStream(f);
+        // End of modification
+        
         byte[] read = new byte[4];
 
         // read header
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/system/ImagePanel.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/system/ImagePanel.java
--- sunflow-0.07.2.svn396/src/org/sunflow/system/ImagePanel.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/system/ImagePanel.java	2010-06-20 22:18:48.000000000 +0300
@@ -4,7 +4,6 @@
 import java.awt.Graphics;
 import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
-import java.awt.event.MouseWheelEvent;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
@@ -78,10 +77,11 @@
             mouseDragged(e);
         }
 
-        @Override
-        public void mouseWheelMoved(MouseWheelEvent e) {
-            zoom(-20 * e.getWheelRotation(), 0);
-        }
+// EP : Support Java 1.5 
+//        @Override
+//        public void mouseWheelMoved(MouseWheelEvent e) {
+//            zoom(-20 * e.getWheelRotation(), 0);
+//        }
     }
 
     public ImagePanel() {
@@ -92,7 +92,8 @@
         ScrollZoomListener listener = new ScrollZoomListener();
         addMouseListener(listener);
         addMouseMotionListener(listener);
-        addMouseWheelListener(listener);
+// EP : Support Java 1.5 
+//        addMouseWheelListener(listener);
     }
 
     public void save(String filename) {
diff -Naur sunflow-0.07.2.svn396/src/org/sunflow/system/Plugins.java sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/system/Plugins.java
--- sunflow-0.07.2.svn396/src/org/sunflow/system/Plugins.java	2011-12-29 21:09:18.000000000 +0200
+++ sunflow-0.07.2.svn396.SweetHome3D/src/org/sunflow/system/Plugins.java	2010-06-20 22:18:48.000000000 +0300
@@ -1,9 +1,5 @@
 package org.sunflow.system;
 
-import org.codehaus.janino.ClassBodyEvaluator;
-import org.codehaus.janino.CompileException;
-import org.codehaus.janino.Parser.ParseException;
-import org.codehaus.janino.Scanner.ScanException;
 import org.sunflow.system.UI.Module;
 import org.sunflow.util.FastHashMap;
 
@@ -98,25 +94,27 @@
      */
     @SuppressWarnings("unchecked")
     public boolean registerPlugin(String name, String sourceCode) {
-        try {
-            ClassBodyEvaluator cbe = new ClassBodyEvaluator();
-            cbe.setClassName(name);
-            if (baseClass.isInterface())
-                cbe.setImplementedTypes(new Class[] { baseClass });
-            else
-                cbe.setExtendedType(baseClass);
-            cbe.cook(sourceCode);
-            return registerPlugin(name, cbe.getClazz());
-        } catch (CompileException e) {
-            UI.printError(Module.API, "Plugin \"%s\" could not be declared - %s", name, e.getLocalizedMessage());
-            return false;
-        } catch (ParseException e) {
-            UI.printError(Module.API, "Plugin \"%s\" could not be declared - %s", name, e.getLocalizedMessage());
-            return false;
-        } catch (ScanException e) {
-            UI.printError(Module.API, "Plugin \"%s\" could not be declared - %s", name, e.getLocalizedMessage());
-            return false;
-        }
+// EP : Don't need parser        
+//        try {
+//            ClassBodyEvaluator cbe = new ClassBodyEvaluator();
+//            cbe.setClassName(name);
+//            if (baseClass.isInterface())
+//                cbe.setImplementedTypes(new Class[] { baseClass });
+//            else
+//                cbe.setExtendedType(baseClass);
+//            cbe.cook(sourceCode);
+//            return registerPlugin(name, cbe.getClazz());
+//        } catch (CompileException e) {
+//            UI.printError(Module.API, "Plugin \"%s\" could not be declared - %s", name, e.getLocalizedMessage());
+//            return false;
+//        } catch (ParseException e) {
+//            UI.printError(Module.API, "Plugin \"%s\" could not be declared - %s", name, e.getLocalizedMessage());
+//            return false;
+//        } catch (ScanException e) {
+//            UI.printError(Module.API, "Plugin \"%s\" could not be declared - %s", name, e.getLocalizedMessage());
+//            return false;
+//        }
+        return false;
     }
 
     /**