Sample

Schnappinger/aoi/artofillusion.Scene

Human rating uses the original dataset scale.

Human2.57
Lines1687

Scores

MethodScoreScaleDataset rank
(0–100)
Posnett00–1; higher is more readable
4.5Δ 10.3
Scalabrino0.8250–1; higher is more readable
69.2Δ 54.3
Dorn00–1; higher is more readable
2.0Δ 12.9
Mi0.3340–1; higher is more readable
20.8Δ 5.9
LLOC852Logical lines; fewer is more readable
0.7Δ 14.2
DeepSeek V4 Pro13.330–20; mean of three runs
24.1Δ 9.2
GPT-6.1 Sol130–20; mean of three runs
9.4Δ 5.4
BTTF0.2470–1; higher is more readable
15.8Δ 1.0
Human2.571–4; original rating
14.9

Views

Source code

/* Copyright (C) 1999-2013 by Peter Eastman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ package artofillusion; import artofillusion.animation.*; import artofillusion.image.*; import artofillusion.material.*; import artofillusion.math.*; import artofillusion.object.*; import artofillusion.texture.*; import artofillusion.ui.*; import artofillusion.util.*; import java.awt.*; import java.io.*; import java.lang.reflect.*; import java.util.*; import java.util.List; import java.util.zip.*; import java.beans.*; /** The Scene class describes a collection of objects, arranged relative to each other to form a scene, as well as the available textures and materials, environment options, etc. */ public class Scene { private Vector<ObjectInfo> objects; private Vector<Material> materials; private Vector<Texture> textures; private Vector<ImageMap> images; private Vector<Integer> selection; private Vector<ListChangeListener> textureListeners, materialListeners; private HashMap<String, Object> metadataMap; private HashMap<ObjectInfo, Integer> objectIndexMap; private RGBColor ambientColor, environColor, fogColor; private Texture environTexture; private TextureMapping environMapping; private int gridSubdivisions, environMode, framesPerSecond, nextID; private double fogDist, gridSpacing, time; private boolean fog, showGrid, snapToGrid, errorsLoading; private String name, directory; private TexturesAndMaterialsDialog texDlg; private ParameterValue environParamValue[]; private StringBuffer loadingErrors; public static final int HANDLE_SIZE = 4; public static final int ENVIRON_SOLID = 0; public static final int ENVIRON_DIFFUSE = 1; public static final int ENVIRON_EMISSIVE = 2; private static final byte FILE_PREFIX[] = {'A', 'o', 'I', 'S', 'c', 'e', 'n', 'e'}; public Scene() { UniformTexture defTex = new UniformTexture(); objects = new Vector<ObjectInfo>(); materials = new Vector<Material>(); textures = new Vector<Texture>(); images = new Vector<ImageMap>(); selection = new Vector<Integer>(); metadataMap = new HashMap<String, Object>(); textureListeners = new Vector<ListChangeListener>(); materialListeners = new Vector<ListChangeListener>(); defTex.setName("Default Texture"); textures.addElement(defTex); ambientColor = new RGBColor(0.3f, 0.3f, 0.3f); environColor = new RGBColor(0.0f, 0.0f, 0.0f); environTexture = defTex; environMapping = defTex.getDefaultMapping(new Sphere(1.0, 1.0, 1.0)); environParamValue = new ParameterValue [0]; environMode = ENVIRON_SOLID; fogColor = new RGBColor(0.3f, 0.3f, 0.3f); fogDist = 20.0; fog = false; framesPerSecond = 30; nextID = 1; // Grids are off by default. showGrid = snapToGrid = false; gridSpacing = 1.0; gridSubdivisions = 10; } /** Get the name of this scene. */ public String getName() { return name; } /** Set the name of this scene. */ public void setName(String newName) { name = newName; } /** Get the directory on disk in which this scene is saved. */ public String getDirectory() { return directory; } /** Set the directory on disk in which this scene is saved. */ public void setDirectory(String newDir) { directory = newDir; } /** Get the current time. */ public double getTime() { return time; } /** Set the current time. */ public void setTime(double t) { time = t; boolean processed[] = new boolean [objects.size()]; for (int i = 0; i < objects.size(); i++) { ObjectInfo info = objects.elementAt(i); applyTracksToObject(info, processed, null, i); } for (ObjectInfo obj : objects) obj.getObject().sceneChanged(obj, this); } /** Modify an object (and any objects that depend on it) based on its tracks at the current time. */ public void applyTracksToObject(ObjectInfo info) { applyTracksToObject(info, new boolean[objects.size()], null, 0); for (ObjectInfo obj : objects) obj.getObject().sceneChanged(obj, this); } /** This should be called after one or more objects have been modified by the user. It applies the animation tracks of all other objects which depend on the modified ones. It also applies a subset of the animation tracks on the modified objects themselves to reflect their dependencies on other parts of the scene. */ public void applyTracksAfterModification(Collection<ObjectInfo> changedObjects) { boolean changed[] = new boolean[objects.size()]; boolean processed[] = new boolean[objects.size()]; // First apply a subset of the tracks of the modified objects. for (ObjectInfo info : changedObjects) { int index = indexOf(info); changed[index] = processed[index] = true; // Find Constraint and IK tracks at the top of the list and apply them. int i; for (i = 0; i < info.getTracks().length && (info.getTracks()[i] instanceof ConstraintTrack || info.getTracks()[i] instanceof IKTrack || info.getTracks()[i].isNullTrack()); i++); for (int j = i-1; j >= 0; j--) if (info.getTracks()[j].isEnabled()) info.getTracks()[j].apply(time); if (info.getPose() != null) info.getObject().applyPoseKeyframe(info.getPose()); } // Now apply tracks to all dependent objects. for (ObjectInfo info : objects) applyTracksToObject(info, processed, changed, indexOf(info)); for (ObjectInfo info : objects) info.getObject().sceneChanged(info, this); } private void applyTracksToObject(ObjectInfo info, boolean processed[], boolean changed[], int index) { if (processed[index]) { // This object has already been updated. info.getObject().sceneChanged(info, this); return; } processed[index] = true; // Determine whether this object possesses a Position or Rotation track, and update any // tracks it is dependent on. boolean hasPos = false, hasRot = false, hasPose = false; for (Track track : info.getTracks()) { if (track.isNullTrack() || !track.isEnabled()) continue; ObjectInfo depends[] = track.getDependencies(); for (int i = 0; i < depends.length; i++) { int k = indexOf(depends[i]); if (k > -1 && !processed[k]) applyTracksToObject(depends[i], processed, changed, k); if (k > -1 && changed != null && changed[k]) changed[index] = true; } if (track instanceof PositionTrack || track instanceof ProceduralPositionTrack) hasPos = true; else if (track instanceof RotationTrack || track instanceof ProceduralRotationTrack) hasRot = true; else if (track instanceof PoseTrack || track instanceof IKTrack) hasPose = true; } if (changed != null && !changed[index]) return; if (hasPos) { Vec3 orig = info.getCoords().getOrigin(); orig.set(0.0, 0.0, 0.0); info.getCoords().setOrigin(orig); } if (hasRot) info.getCoords().setOrientation(0.0, 0.0, 0.0); if (hasPose) info.clearCachedMeshes(); info.setPose(null); // Apply the tracks. info.clearDistortion(); for (int j = info.getTracks().length-1; j >= 0; j--) if (info.getTracks()[j].isEnabled()) info.getTracks()[j].apply(time); if (info.getPose() != null) info.getObject().applyPoseKeyframe(info.getPose()); } /** Get the number of frames per second. */ public int getFramesPerSecond() { return framesPerSecond; } /** Set the number of frames per second. */ public void setFramesPerSecond(int n) { framesPerSecond = n; } /** Get the scene's ambient light color. */ public RGBColor getAmbientColor() { return ambientColor; } /** Set the scene's ambient light color. */ public void setAmbientColor(RGBColor color) { ambientColor = color; } /** Get the Scene's environment mapping mode. This will be either ENVIRON_SOLID, ENVIRON_DIFFUSE, or ENVIRON_EMISSIVE. */ public int getEnvironmentMode() { return environMode; } /** Set the Scene's environment mapping mode. This should be either ENVIRON_SOLID, ENVIRON_DIFFUSE, or ENVIRON_EMISSIVE. */ public void setEnvironmentMode(int mode) { environMode = mode; } /** Get the texture being used as an environment mapping. */ public Texture getEnvironmentTexture() { return environTexture; } /** Set the texture being used as an environment mapping. */ public void setEnvironmentTexture(Texture tex) { environTexture = tex; } /** Get the TextureMapping being used to map the environment map texture to the environment sphere. */ public TextureMapping getEnvironmentMapping() { return environMapping; } /** Set the TextureMapping to use for mapping the environment map texture to the environment sphere. */ public void setEnvironmentMapping(TextureMapping map) { environMapping = map; } /** Get the parameter values used for the environment map. */ public ParameterValue [] getEnvironmentParameterValues() { return environParamValue; } /** Set the parameter values used for the environment map. */ public void setEnvironmentParameterValues(ParameterValue value[]) { environParamValue = value; } /** Get the environment color. */ public RGBColor getEnvironmentColor() { return environColor; } /** Set the environment color. */ public void setEnvironmentColor(RGBColor color) { environColor = color; } /** Get the fog color. */ public RGBColor getFogColor() { return fogColor; } /** Set the fog color. */ public void setFogColor(RGBColor color) { fogColor = color; } /** Determine whether fog is enabled. */ public boolean getFogState() { return fog; } /** Get the length constant for exponential fog. */ public double getFogDistance() { return fogDist; } /** Set the state of fog in the scene. @param state sets whether fog is enabled @param dist the length constant for exponential fog. */ public void setFog(boolean state, double dist) { fog = state; fogDist = dist; } /** Get whether the grid is displayed. */ public boolean getShowGrid() { return showGrid; } /** Set whether the grid is displayed. */ public void setShowGrid(boolean show) { showGrid = show; } /** Get whether snap-to-grid is enabled. */ public boolean getSnapToGrid() { return snapToGrid; } /** Set whether snap-to-grid is enabled. */ public void setSnapToGrid(boolean snap) { snapToGrid = snap; } /** Get the grid spacing. */ public double getGridSpacing() { return gridSpacing; } /** Set the grid spacing. */ public void setGridSpacing(double spacing) { gridSpacing = spacing; } /** Get the number of grid snap-to subdivisions. */ public int getGridSubdivisions() { return gridSubdivisions; } /** Set the number of grid snap-to subdivisions. */ public void setGridSubdivisions(int subdivisions) { gridSubdivisions = subdivisions; } /** Add a new object to the scene. If undo is not null, appropriate commands will be added to it to undo this operation. */ public void addObject(Object3D obj, CoordinateSystem coords, String name, UndoRecord undo) { addObject(new ObjectInfo(obj, coords, name), undo); updateSelectionInfo(); } /** Add a new object to the scene. If undo is not null, appropriate commands will be added to it to undo this operation. */ public void addObject(ObjectInfo info, UndoRecord undo) { addObject(info, objects.size(), undo); updateSelectionInfo(); } /** Add a new object to the scene in the specified position. If undo is not null, appropriate commands will be added to it to undo this operation. */ public void addObject(ObjectInfo info, int index, UndoRecord undo) { info.setId(nextID++); if (info.getTracks() == null) { info.addTrack(new PositionTrack(info), 0); info.addTrack(new RotationTrack(info), 1); } if (info.getObject().canSetTexture() && info.getObject().getTextureMapping() == null) info.setTexture(getDefaultTexture(), getDefaultTexture().getDefaultMapping(info.getObject())); info.getObject().sceneChanged(info, this); objects.insertElementAt(info, index); objectIndexMap = null; if (undo != null) undo.addCommandAtBeginning(UndoRecord.DELETE_OBJECT, new Object [] {index}); updateSelectionInfo(); } /** Delete an object from the scene. If undo is not null, appropriate commands will be added to it to undo this operation. */ public void removeObject(int which, UndoRecord undo) { ObjectInfo info = objects.elementAt(which); objects.removeElementAt(which); objectIndexMap = null; if (undo != null) undo.addCommandAtBeginning(UndoRecord.ADD_OBJECT, new Object [] {info, which}); if (info.getParent() != null) { int j; for (j = 0; info.getParent().getChildren()[j] != info; j++); if (undo != null) undo.addCommandAtBeginning(UndoRecord.ADD_TO_GROUP, new Object [] {info.getParent(), info, j}); info.getParent().removeChild(j); } for (int i = 0; i < objects.size(); i++) { ObjectInfo obj = objects.elementAt(i); for (int j = 0; j < obj.getTracks().length; j++) { Track tr = obj.getTracks()[j]; ObjectInfo depends[] = tr.getDependencies(); for (int k = 0; k < depends.length; k++) if (depends[k] == info) { if (undo != null) undo.addCommandAtBeginning(UndoRecord.COPY_TRACK, new Object [] {tr, tr.duplicate(tr.getParent())}); obj.getTracks()[j].deleteDependencies(info); } } } clearSelection(); } /** Add a new Material to the scene. */ public void addMaterial(Material mat) { addMaterial(mat, materials.size()); } /** * Add a new Material to the scene. * * @param mat the Material to add * @param index the position in the list to add it at */ public void addMaterial(Material mat, int index) { materials.add(index, mat); for (int i = 0; i < materialListeners.size(); i++) materialListeners.elementAt(i).itemAdded(materials.size()-1, mat); } /** Remove a Material from the scene. */ public void removeMaterial(int which) { Material mat = materials.elementAt(which); materials.removeElementAt(which); for (int i = 0; i < materialListeners.size(); i++) materialListeners.elementAt(i).itemRemoved(which, mat); for (int i = 0; i < objects.size(); i++) { ObjectInfo obj = objects.elementAt(i); if (obj.getObject().getMaterial() == mat) obj.setMaterial(null, null); } } /** * Reorder the list of Materials by moving a Material to a new position in the list. * * @param oldIndex the index of the Material to move * @param newIndex the new position to move it to */ public void reorderMaterial(int oldIndex, int newIndex) { if (newIndex < 0 || newIndex >= materials.size()) throw new IllegalArgumentException("Illegal value for newIndex: "+newIndex); Material mat = materials.remove(oldIndex); materials.add(newIndex, mat); } /** Add a new Texture to the scene. */ public void addTexture(Texture tex) { addTexture(tex, textures.size()); } /** * Add a new Texture to the scene. * * @param tex the Texture to add * @param index the position in the list to add it at */ public void addTexture(Texture tex, int index) { textures.add(index, tex); for (int i = 0; i < textureListeners.size(); i++) textureListeners.elementAt(i).itemAdded(textures.size()-1, tex); } /** Remove a Texture from the scene. */ public void removeTexture(int which) { Texture tex = textures.elementAt(which); textures.removeElementAt(which); for (int i = 0; i < textureListeners.size(); i++) textureListeners.elementAt(i).itemRemoved(which, tex); if (textures.size() == 0) { UniformTexture defTex = new UniformTexture(); defTex.setName("Default Texture"); textures.addElement(defTex); for (int i = 0; i < textureListeners.size(); i++) textureListeners.elementAt(i).itemAdded(0, defTex); } Texture def = textures.elementAt(0); for (int i = 0; i < objects.size(); i++) { ObjectInfo obj = objects.elementAt(i); if (obj.getObject().getTexture() == tex) obj.setTexture(def, def.getDefaultMapping(obj.getObject())); if (obj.getObject().getTextureMapping() instanceof LayeredMapping) { LayeredMapping map = (LayeredMapping) obj.getObject().getTextureMapping(); for (int j = map.getNumLayers()-1; j >= 0; j--) if (map.getLayer(j) == tex) map.deleteLayer(j); obj.setTexture(obj.getObject().getTexture(), map); } } if (environTexture == tex) { environTexture = def; environMapping = def.getDefaultMapping(new Sphere(1.0, 1.0, 1.0)); } if (environMapping instanceof LayeredMapping) { Sphere tempObject = new Sphere(1, 1, 1); tempObject.setTexture(environTexture, environMapping); tempObject.setParameterValues(environParamValue); LayeredMapping map = (LayeredMapping) environMapping; for (int j = map.getNumLayers()-1; j >= 0; j--) if (map.getLayer(j) == tex) map.deleteLayer(j); tempObject.setTexture(environTexture, environMapping); environParamValue = tempObject.getParameterValues(); } } /** * Reorder the list of Textures by moving a Texture to a new position in the list. * * @param oldIndex the index of the Texture to move * @param newIndex the new position to move it to */ public void reorderTexture(int oldIndex, int newIndex) { if (newIndex < 0 || newIndex >= textures.size()) throw new IllegalArgumentException("Illegal value for newIndex: "+newIndex); Texture tex = textures.remove(oldIndex); textures.add(newIndex, tex); } /** This method should be called after a Material has been edited. It notifies any objects using the Material that it has changed. */ public void changeMaterial(int which) { Material mat = materials.elementAt(which); Object3D obj; for (int i = 0; i < objects.size(); i++) { obj = objects.elementAt(i).getObject(); if (obj.getMaterial() == mat) obj.setMaterial(mat, obj.getMaterialMapping()); } for (int i = 0; i < materialListeners.size(); i++) materialListeners.elementAt(i).itemChanged(which, mat); } /** This method should be called after a Texture has been edited. It notifies any objects using the Texture that it has changed. */ public void changeTexture(int which) { Texture tex = textures.elementAt(which); for (int i = 0; i < objects.size(); i++) { ObjectInfo obj = objects.elementAt(i); if (obj.getObject().getTexture() == tex) obj.setTexture(tex, obj.getObject().getTextureMapping()); else if (obj.getObject().getTexture() instanceof LayeredTexture) for (Texture layer : ((LayeredMapping) obj.getObject().getTextureMapping()).getLayers()) if (layer == tex) { obj.setTexture(tex, obj.getObject().getTextureMapping()); break; } } for (int i = 0; i < textureListeners.size(); i++) textureListeners.elementAt(i).itemChanged(which, tex); } /** Add an object which wants to be notified when the list of Materials in the Scene changes. */ public void addMaterialListener(ListChangeListener ls) { materialListeners.addElement(ls); } /** Remove an object from the set to be notified when the list of Materials changes. */ public void removeMaterialListener(ListChangeListener ls) { materialListeners.removeElement(ls); } /** Add an object which wants to be notified when the list of Textures in the Scene changes. */ public void addTextureListener(ListChangeListener ls) { textureListeners.addElement(ls); } /** Remove an object from the set to be notified when the list of Textures changes. */ public void removeTextureListener(ListChangeListener ls) { textureListeners.removeElement(ls); } /** * Get a piece of metadata stored in this scene. * * @param name the name of the piece of metadata to get * @return the value associated with that name, or null if there is none */ public Object getMetadata(String name) { return metadataMap.get(name); } /** * Store a piece of metadata in this scene. This may be an arbitrary object which * you want to store as part of the scene. When the scene is saved to disk, metadata * objects are stored using the java.beans.XMLEncoder class. This means that if the * object is not a bean, you must register a PersistenceDelegate for it before calling * this method. Otherwise, it will fail to be saved. * * @param name the name of the piece of metadata to set * @param value the value to store */ public void setMetadata(String name, Object value) { metadataMap.put(name, value); } /** * Get the names of all metadata objects stored in this scene. */ public Set<String> getAllMetadataNames() { return metadataMap.keySet(); } /** Show the dialog for editing textures and materials. */ public void showTexturesDialog(EditingWindow parent) { if (texDlg == null) texDlg = new TexturesAndMaterialsDialog(parent, this); else { Rectangle r = texDlg.getBounds(); texDlg.dispose(); texDlg = new TexturesAndMaterialsDialog(parent, this); texDlg.setBounds(r); } texDlg.setVisible(true); } /** Add an image map to the scene. */ public void addImage(ImageMap im) { images.addElement(im); } /** Remove an image map from the scene. */ public boolean removeImage(int which) { ImageMap image = images.elementAt(which); for (int i = 0; i < textures.size(); i++) if (textures.elementAt(i).usesImage(image)) return false; for (int i = 0; i < materials.size(); i++) if (materials.elementAt(i).usesImage(image)) return false; images.removeElementAt(which); return true; } /** Replace every instance of one object in the scene with another one. If undo is not null, commands will be added to it to undo this operation. */ public void replaceObject(Object3D original, Object3D replaceWith, UndoRecord undo) { for (int i = 0; i < objects.size(); i++) { ObjectInfo info = objects.elementAt(i); if (info.getObject() != original) continue; if (undo != null) undo.addCommand(UndoRecord.SET_OBJECT, new Object [] {info, original}); info.setObject(replaceWith); info.clearCachedMeshes(); } } /** This should be called whenever an object changes. It clears any cached meshes for any instances of the object. */ public void objectModified(Object3D obj) { for (int i = 0; i < objects.size(); i++) { ObjectInfo info = objects.elementAt(i); if (info.getObject() == obj) { info.clearCachedMeshes(); info.setPose(null); } } } /** * Set one object to be selected, deselecting all other objects. * @deprecated Call setSelection() on the LayoutWindow instead. */ public void setSelection(int which) { clearSelection(); addToSelection(which); updateSelectionInfo(); } /** * Set a list of objects to be selected, deselecting all other objects. * @deprecated Call setSelection() on the LayoutWindow instead. */ public void setSelection(int which[]) { clearSelection(); for (int i = 0; i < which.length; i++) addToSelection(which[i]); updateSelectionInfo(); } /** * Add an object to the list of selected objects. * @deprecated Call addToSelection() on the LayoutWindow instead. */ public void addToSelection(int which) { ObjectInfo info = objects.elementAt(which); if (!info.selected) selection.addElement(which); info.selected = true; updateSelectionInfo(); } /** * Deselect all objects. * @deprecated Call clearSelection() on the LayoutWindow instead. */ public void clearSelection() { selection.removeAllElements(); for (int i = 0; i < objects.size(); i++) objects.elementAt(i).selected = false; updateSelectionInfo(); } /** * Deselect a particular object. * @deprecated Call removeFromSelection() on the LayoutWindow instead. */ public void removeFromSelection(int which) { ObjectInfo info = objects.elementAt(which); selection.removeElement(which); info.selected = false; updateSelectionInfo(); } /** Calculate the list of which objects are children of selected objects. */ private void updateSelectionInfo() { for (int i = objects.size()-1; i >= 0; i--) objects.elementAt(i).parentSelected = false; for (int i = objects.size()-1; i >= 0; i--) { ObjectInfo info = objects.elementAt(i); ObjectInfo parent = info.getParent(); while (parent != null) { if (parent.selected || parent.parentSelected) { info.parentSelected = true; break; } parent = parent.getParent(); } } } /** Get the number of objects in this scene. */ public int getNumObjects() { return objects.size(); } /** Get the i'th object. */ public ObjectInfo getObject(int i) { return objects.elementAt(i); } /** Get the object with the specified name, or null if there is none. If more than one object has the same name, this will return the first one. */ public ObjectInfo getObject(String name) { for (int i = 0; i < objects.size(); i++) { ObjectInfo info = objects.elementAt(i); if (info.getName().equals(name)) return info; } return null; } /** Get the object with the specified ID, or null if there is none. */ public ObjectInfo getObjectById(int id) { for (int i = 0; i < objects.size(); i++) { ObjectInfo info = objects.elementAt(i); if (info.getId() == id) return info; } return null; } /** Get all objects in the Scene in the form of a List. */ public List<ObjectInfo> getAllObjects() { return Collections.unmodifiableList(objects); } /** Get the index of the specified object. */ public int indexOf(ObjectInfo info) { if (objectIndexMap == null) { // Build an index for fast lookup. objectIndexMap = new HashMap<ObjectInfo, Integer>(); for (int i = 0; i < objects.size(); i++) objectIndexMap.put(objects.get(i), i); } Integer index = objectIndexMap.get(info); return (index == null ? -1 : index); } /** Get the number of textures in this scene. */ public int getNumTextures() { return textures.size(); } /** Get the index of the specified texture. */ public int indexOf(Texture tex) { return textures.indexOf(tex); } /** Get the i'th texture. */ public Texture getTexture(int i) { return textures.elementAt(i); } /** Get the texture with the specified name, or null if there is none. If more than one texture has the same name, this will return the first one. */ public Texture getTexture(String name) { for (int i = 0; i < textures.size(); i++) { Texture tex = textures.elementAt(i); if (tex.getName().equals(name)) return tex; } return null; } /** Get the number of materials in this scene. */ public int getNumMaterials() { return materials.size(); } /** Get the i'th material. */ public Material getMaterial(int i) { return materials.elementAt(i); } /** Get the material with the specified name, or null if there is none. If more than one material has the same name, this will return the first one. */ public Material getMaterial(String name) { for (int i = 0; i < materials.size(); i++) { Material mat = materials.elementAt(i); if (mat.getName().equals(name)) return mat; } return null; } /** Get the index of the specified material. */ public int indexOf(Material mat) { return materials.indexOf(mat); } /** Get the number of image maps in this scene. */ public int getNumImages() { return images.size(); } /** Get the i'th image map. */ public ImageMap getImage(int i) { return images.elementAt(i); } /** Get the index of the specified image map. */ public int indexOf(ImageMap im) { return images.indexOf(im); } /** Get the default Texture for newly created objects. */ public Texture getDefaultTexture() { return textures.elementAt(0); } /** * Get a list of the indices of all selected objects. * @deprecated Call getSelectedIndices() or getSelectedObjects() on the LayoutWindow instead. */ public int [] getSelection() { int sel[] = new int [selection.size()]; for (int i = 0; i < sel.length; i++) sel[i] = selection.elementAt(i); return sel; } /** * Get the indices of all objects which are either selected, or are children of * selected objects. * @deprecated Call getSelectionWithChildren() on the LayoutWindow instead. */ public int [] getSelectionWithChildren() { int count = 0; for (int i = objects.size()-1; i >= 0; i--) { ObjectInfo info = objects.elementAt(i); if (info.selected || info.parentSelected) count++; } int sel[] = new int [count]; count = 0; for (int i = objects.size()-1; i >= 0; i--) { ObjectInfo info = objects.elementAt(i); if (info.selected || info.parentSelected) sel[count++] = i; } return sel; } /** Return true if any errors occurred while loading the scene. The scene is still valid and usable, but some objects in it were not loaded correctly. */ public boolean errorsOccurredInLoading() { return errorsLoading; } /** Get a description of any errors which occurred while loading the scene. */ public String getLoadingErrors() { return (loadingErrors == null ? "" : loadingErrors.toString()); } /** The following constructor is used for reading files. If fullScene is false, only the Textures and Materials are read. */ public Scene(File f, boolean fullScene) throws IOException, InvalidObjectException { setName(f.getName()); setDirectory(f.getParent()); BufferedInputStream buf = new BufferedInputStream(new FileInputStream(f)); buf.mark(FILE_PREFIX.length); // See if the file begins with the expected prefix. boolean hasPrefix = true; for (int i = 0; hasPrefix && i < FILE_PREFIX.length; i++) hasPrefix &= (buf.read() == FILE_PREFIX[i]); if (!hasPrefix) buf.reset(); // This is an old file that doesn't start with the prefix. // We expect the data to be gzipped, but if it's somehow gotten decompressed we should accept that to. DataInputStream in; try { in = new DataInputStream(new GZIPInputStream(buf)); } catch (IOException ex) { buf.close(); buf = new BufferedInputStream(new FileInputStream(f)); in = new DataInputStream(buf); } initFromStream(in, fullScene); in.close(); } /** The following constructor is used for reading from arbitrary input streams. If fullScene is false, only the Textures and Materials are read. */ public Scene(DataInputStream in, boolean fullScene) throws IOException, InvalidObjectException { initFromStream(in, fullScene); } /** Initialize the scene based on information read from an input stream. */ private void initFromStream(DataInputStream in, boolean fullScene) throws IOException, InvalidObjectException { int count; short version = in.readShort(); Hashtable<Integer, Object3D> table; Class cls; Constructor con; if (version < 0 || version > 4) throw new InvalidObjectException(""); loadingErrors = new StringBuffer(); ambientColor = new RGBColor(in); fogColor = new RGBColor(in); fog = in.readBoolean(); fogDist = in.readDouble(); showGrid = in.readBoolean(); snapToGrid = in.readBoolean(); gridSpacing = in.readDouble(); gridSubdivisions = in.readInt(); framesPerSecond = in.readInt(); nextID = 1; // Read the image maps. count = in.readInt(); images = new Vector<ImageMap>(count); for (int i = 0; i < count; i++) { if (version == 0) { images.addElement(new MIPMappedImage(in, (short) 0)); continue; } String classname = in.readUTF(); try { cls = ArtOfIllusion.getClass(classname); if (cls == null) throw new IOException("Unknown class: "+classname); con = cls.getConstructor(DataInputStream.class); images.addElement((ImageMap) con.newInstance(in)); } catch (Exception ex) { throw new IOException("Error loading image: "+ex.getMessage()); } } // Read the materials. count = in.readInt(); materials = new Vector<Material>(count); for (int i = 0; i < count; i++) { try { String classname = in.readUTF(); int len = in.readInt(); byte bytes[] = new byte [len]; in.readFully(bytes); cls = ArtOfIllusion.getClass(classname); try { if (cls == null) throw new IOException("Unknown class: "+classname); con = cls.getConstructor(DataInputStream.class, Scene.class); materials.addElement((Material) con.newInstance(new DataInputStream(new ByteArrayInputStream(bytes)), this)); } catch (Exception ex) { ex.printStackTrace(); if (ex instanceof ClassNotFoundException) loadingErrors.append(Translate.text("errorFindingClass", classname)).append('\n'); else loadingErrors.append(Translate.text("errorInstantiatingClass", classname)).append('\n'); UniformMaterial m = new UniformMaterial(); m.setName("<unreadable>"); materials.addElement(m); errorsLoading = true; } } catch (Exception ex) { ex.printStackTrace(); throw new IOException(); } } // Read the textures. count = in.readInt(); textures = new Vector<Texture>(count); for (int i = 0; i < count; i++) { try { String classname = in.readUTF(); int len = in.readInt(); byte bytes[] = new byte [len]; in.readFully(bytes); cls = ArtOfIllusion.getClass(classname); try { if (cls == null) throw new IOException("Unknown class: "+classname); con = cls.getConstructor(DataInputStream.class, Scene.class); textures.addElement((Texture) con.newInstance(new DataInputStream(new ByteArrayInputStream(bytes)), this)); } catch (Exception ex) { ex.printStackTrace(); if (ex instanceof ClassNotFoundException) loadingErrors.append(Translate.text("errorFindingClass", classname)).append('\n'); else loadingErrors.append(Translate.text("errorInstantiatingClass", classname)).append('\n'); UniformTexture t = new UniformTexture(); t.setName("<unreadable>"); textures.addElement(t); errorsLoading = true; } } catch (Exception ex) { ex.printStackTrace(); throw new IOException(); } } // Read the objects. count = in.readInt(); objects = new Vector<ObjectInfo>(count); table = new Hashtable<Integer, Object3D>(count); for (int i = 0; i < count; i++) objects.addElement(readObjectFromFile(in, table, version)); objectIndexMap = null; selection = new Vector<Integer>(); // Read the list of children for each object. for (int i = 0; i < objects.size(); i++) { ObjectInfo info = objects.elementAt(i); int num = in.readInt(); for (int j = 0; j < num; j++) { ObjectInfo child = objects.elementAt(in.readInt()); info.addChild(child, j); } } // Read in the environment mapping information. environMode = (int) in.readShort(); if (environMode == ENVIRON_SOLID) { environColor = new RGBColor(in); environTexture = textures.elementAt(0); environMapping = environTexture.getDefaultMapping(new Sphere(1.0, 1.0, 1.0)); environParamValue = new ParameterValue [0]; } else { int texIndex = in.readInt(); if (texIndex == -1) { // This is a layered texture. Object3D sphere = new Sphere(1.0, 1.0, 1.0); environTexture = new LayeredTexture(sphere); String mapClassName = in.readUTF(); if (!LayeredMapping.class.getName().equals(mapClassName)) throw new InvalidObjectException(""); environMapping = environTexture.getDefaultMapping(sphere); ((LayeredMapping) environMapping).readFromFile(in, this); } else { environTexture = textures.elementAt(texIndex); try { Class mapClass = ArtOfIllusion.getClass(in.readUTF()); con = mapClass.getConstructor(DataInputStream.class, Object3D.class, Texture.class); environMapping = (TextureMapping) con.newInstance(in, new Sphere(1.0, 1.0, 1.0), environTexture); } catch (Exception ex) { throw new IOException(); } } environColor = new RGBColor(0.0f, 0.0f, 0.0f); environParamValue = new ParameterValue [environMapping.getParameters().length]; if (version > 2) for (int i = 0; i < environParamValue.length; i++) environParamValue[i] = Object3D.readParameterValue(in); } // Read the metadata. metadataMap = new HashMap<String, Object>(); if (version > 3) { count = in.readInt(); SearchlistClassLoader loader = new SearchlistClassLoader(getClass().getClassLoader()); for (ClassLoader cl : PluginRegistry.getPluginClassLoaders()) loader.add(cl); for (int i = 0; i < count; i++) { try { String name = in.readUTF(); byte data[] = new byte[in.readInt()]; in.readFully(data); XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(data), null, null, loader); metadataMap.put(name, decoder.readObject()); } catch (Exception ex) { ex.printStackTrace(); // Nothing more we can do about it. } } } textureListeners = new Vector<ListChangeListener>(); materialListeners = new Vector<ListChangeListener>(); setTime(0.0); } private ObjectInfo readObjectFromFile(DataInputStream in, Hashtable<Integer, Object3D> table, int version) throws IOException, InvalidObjectException { ObjectInfo info = new ObjectInfo(null, new CoordinateSystem(in), in.readUTF()); Class cls; Constructor con; Object3D obj; info.setId(in.readInt()); if (info.getId() >= nextID) nextID = info.getId() +1; info.setVisible(in.readBoolean()); Integer key = in.readInt(); obj = table.get(key); if (obj == null) { try { String classname = in.readUTF(); int len = in.readInt(); byte bytes[] = new byte [len]; in.readFully(bytes); try { cls = ArtOfIllusion.getClass(classname); con = cls.getConstructor(DataInputStream.class, Scene.class); obj = (Object3D) con.newInstance(new DataInputStream(new ByteArrayInputStream(bytes)), this); } catch (Exception ex) { if (ex instanceof InvocationTargetException) ((InvocationTargetException) ex).getTargetException().printStackTrace(); else ex.printStackTrace(); if (ex instanceof ClassNotFoundException) loadingErrors.append(info.getName()).append(": ").append(Translate.text("errorFindingClass", classname)).append('\n'); else loadingErrors.append(info.getName()).append(": ").append(Translate.text("errorInstantiatingClass", classname)).append('\n'); obj = new NullObject(); info.setName("<unreadable> "+ info.getName()); errorsLoading = true; } table.put(key, obj); } catch (Exception ex) { ex.printStackTrace(); throw new IOException(); } } info.setObject(obj); if (version < 2 && obj.getTexture() != null) { // Initialize the texture parameters. TextureParameter texParam[] = obj.getTextureMapping().getParameters(); ParameterValue paramValue[] = obj.getParameterValues(); double val[] = new double [paramValue.length]; boolean perVertex[] = new boolean [paramValue.length]; for (int i = 0; i < val.length; i++) val[i] = in.readDouble(); for (int i = 0; i < perVertex.length; i++) perVertex[i] = in.readBoolean(); for (int i = 0; i < paramValue.length; i++) if (paramValue[i] == null) { if (perVertex[i]) paramValue[i] = new VertexParameterValue((Mesh) obj, texParam[i]); else paramValue[i] = new ConstantParameterValue(val[i]); } obj.setParameterValues(paramValue); } // Read the tracks for this object. int tracks = in.readInt(); try { for (int i = 0; i < tracks; i++) { cls = ArtOfIllusion.getClass(in.readUTF()); con = cls.getConstructor(ObjectInfo.class); Track tr = (Track) con.newInstance(info); tr.initFromStream(in, this); info.addTrack(tr, i); } if (info.getTracks() == null) info.tracks = new Track [0]; } catch (Exception ex) { ex.printStackTrace(); throw new IOException(); } return info; } /** Save the Scene to a file. */ public void writeToFile(File f) throws IOException { int mode = (ArtOfIllusion.getPreferences().getKeepBackupFiles() ? SafeFileOutputStream.OVERWRITE+SafeFileOutputStream.KEEP_BACKUP : SafeFileOutputStream.OVERWRITE); SafeFileOutputStream safeOut = new SafeFileOutputStream(f, mode); BufferedOutputStream bout = new BufferedOutputStream(safeOut); bout.write(FILE_PREFIX); DataOutputStream out = new DataOutputStream(new GZIPOutputStream(bout)); writeToStream(out); out.close(); } /** Write the Scene's representation to an output stream. */ public void writeToStream(DataOutputStream out) throws IOException { Material mat; Texture tex; int i, j, index = 0; Hashtable<Object3D, Integer> table = new Hashtable<Object3D, Integer>(objects.size()); out.writeShort(4); ambientColor.writeToFile(out); fogColor.writeToFile(out); out.writeBoolean(fog); out.writeDouble(fogDist); out.writeBoolean(showGrid); out.writeBoolean(snapToGrid); out.writeDouble(gridSpacing); out.writeInt(gridSubdivisions); out.writeInt(framesPerSecond); // Save the image maps. out.writeInt(images.size()); for (i = 0; i < images.size(); i++) { ImageMap img = images.elementAt(i); out.writeUTF(img.getClass().getName()); img.writeToStream(out); } // Save the materials. out.writeInt(materials.size()); for (i = 0; i < materials.size(); i++) { mat = materials.elementAt(i); out.writeUTF(mat.getClass().getName()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); mat.writeToFile(new DataOutputStream(bos), this); byte bytes[] = bos.toByteArray(); out.writeInt(bytes.length); out.write(bytes, 0, bytes.length); } // Save the textures. out.writeInt(textures.size()); for (i = 0; i < textures.size(); i++) { tex = textures.elementAt(i); out.writeUTF(tex.getClass().getName()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); tex.writeToFile(new DataOutputStream(bos), this); byte bytes[] = bos.toByteArray(); out.writeInt(bytes.length); out.write(bytes, 0, bytes.length); } // Save the objects. out.writeInt(objects.size()); for (i = 0; i < objects.size(); i++) index = writeObjectToFile(out, objects.elementAt(i), table, index); // Record the children of each object. The format of this will be changed in the // next version. for (i = 0; i < objects.size(); i++) { ObjectInfo info = objects.elementAt(i); out.writeInt(info.getChildren().length); for (j = 0; j < info.getChildren().length; j++) out.writeInt(indexOf(info.getChildren()[j])); } // Save the environment mapping information. out.writeShort((short) environMode); if (environMode == ENVIRON_SOLID) environColor.writeToFile(out); else { out.writeInt(textures.lastIndexOf(environTexture)); out.writeUTF(environMapping.getClass().getName()); if (environMapping instanceof LayeredMapping) ((LayeredMapping) environMapping).writeToFile(out, this); else environMapping.writeToFile(out); for (i = 0; i < environParamValue.length; i++) { out.writeUTF(environParamValue[i].getClass().getName()); environParamValue[i].writeToStream(out); } } // Save metadata. out.writeInt(metadataMap.size()); ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); SearchlistClassLoader loader = new SearchlistClassLoader(getClass().getClassLoader()); for (ClassLoader cl : PluginRegistry.getPluginClassLoaders()) loader.add(cl); Thread.currentThread().setContextClassLoader(loader); // So that plugin classes can be saved correctly. ExceptionListener exceptionListener = new ExceptionListener() { public void exceptionThrown(Exception e) { e.printStackTrace(); } }; for (Map.Entry<String, Object> entry : metadataMap.entrySet()) { ByteArrayOutputStream value = new ByteArrayOutputStream(); XMLEncoder encoder = new XMLEncoder(value); encoder.setExceptionListener(exceptionListener); encoder.writeObject(entry.getValue()); encoder.close(); out.writeUTF(entry.getKey()); out.writeInt(value.size()); out.write(value.toByteArray()); } Thread.currentThread().setContextClassLoader(contextClassLoader); } /** Write the information about a single object to a file. */ private int writeObjectToFile(DataOutputStream out, ObjectInfo info, Hashtable<Object3D, Integer> table, int index) throws IOException { Integer key; info.getCoords().writeToFile(out); out.writeUTF(info.getName()); out.writeInt(info.getId()); out.writeBoolean(info.isVisible()); key = table.get(info.getObject()); if (key == null) { out.writeInt(index); out.writeUTF(info.getObject().getClass().getName()); ByteArrayOutputStream bos = new ByteArrayOutputStream(); info.getObject().writeToFile(new DataOutputStream(bos), this); byte bytes[] = bos.toByteArray(); out.writeInt(bytes.length); out.write(bytes, 0, bytes.length); key = index++; table.put(info.getObject(), key); } else out.writeInt(key.intValue()); // Write the tracks for this object. out.writeInt(info.getTracks().length); for (int i = 0; i < info.getTracks().length; i++) { out.writeUTF(info.getTracks()[i].getClass().getName()); info.getTracks()[i].writeToStream(out, this); } return index; } }

Loading feature diagnosis…

Source regions

Feature contributions

Feature contributions

FeatureValueContribution
(log-odds)
Halstead volumeHow much symbolic information the code contains. It combines the total number of operators and values with the number of distinct ones.74322.9−2452.656
Source linesThe number of non-empty source lines.1687+674.8
Byte entropyHow varied the bytes in the source text are. Repeated bytes give a lower value; a more even mixture gives a higher value.4.704−7.056

Intercept 8.87 + feature contributions = -1776.041 (log-odds).
Score = sigmoid(-1776.041) = 0.

Score0.825

Feature contributions

FeatureValueContribution
(log-odds)
Comment layout frequencyHow frequently the layout switches between lines containing only comments or whitespace and lines containing code.1687−58.695
Indentation frequencyHow rapidly indentation changes from line to line.1565+53.394
Number layout frequencyHow rapidly the number of numeric values per line changes through the code.1565−35.491
Identifier layout (vertical)How rapidly the visual pattern of identifier characters changes from top to bottom.1685.905+23.156
Identifier layout (horizontal)How rapidly the visual pattern of identifier characters changes from left to right. It measures spatial frequency, not the meaning of the names.167.98−3.45
Comment layout (horizontal)How rapidly the visual pattern of comment characters changes from left to right.167.991+1.906
Operator visual areaThe share of the code’s visual area occupied by operators such as +, =, and *.0.098−0.007

Intercept 0.07 + feature contributions = -19.116 (log-odds).
Score = sigmoid(-19.116) = 0.

Score0.334
Score852
Run 1

The code is organized into logical methods with clear JavaDoc comments, but suffers from several readability issues. The class is extremely long, violating single-responsibility by mixing scene state, serialization, UI dialogs, and listener management. Many methods use legacy Vector with elementAt() loops instead of for-each, adding verbosity. Deep nesting occurs in serialization/deserialization methods (e.g., removeTexture, initFromStream) with multiple try-catch blocks and conditional branches. Some methods mix multiple actions per line (e.g., chained method calls in removeTexture). Naming is generally clear, and getters/setters are concise, but large methods like initFromStream and writeToStream are dense and hard to follow. The reading flow is disrupted by frequent interleaving of comments and complex error-handling logic.

Run 2

The code is generally well-structured, with a clear class purpose and many small, focused methods that follow a consistent JavaBean style. Javadoc comments are extensive and helpful. Most methods perform a single logical action with limited nesting. However, several methods (e.g., removeTexture, initFromStream, applyTracksToObject) are quite long and contain deeply nested loops and conditionals, which hinders readability. The heavy use of older Vector and manual index-based loops, alongside newer generics and for-each loops, creates a slightly inconsistent style. Some sections, like file I/O with error handling, become tangled. Overall, the intent is usually clear due to good naming and comments, but code length and occasional nesting reduce the score.

Run 3

The code is logically organized into clear sections with many methods having explanatory comments, which aids basic understanding. However, readability is significantly impacted by several issues: multiple actions and conditionals are packed into single lines (e.g., in applyTracksAfterModification and removeObject), creating dense blocks. Nesting is deep in loops processing objects, textures, and tracks (reaching 3-4 levels), making the flow hard to follow. Methods like removeTexture and initFromStream are very long and combine many different operations—serialization, error handling, and listener updates—reducing clarity of intent. While the sequential arrangement of getters/setters and serialization methods is natural, the frequent use of legacy Vector and verbose loops instead of modern idioms makes the code unnecessarily lengthy. The overall structure is reasonable, but dense methods and mixed responsibilities lower readability.

Run 1

1. Code Structure: Methods are mostly logically grouped, but the large Scene class combines animation, resource management, selection, UI, and persistence responsibilities. 2. Nesting: Accessors and basic operations are flat; object removal and deserialization contain deep loops, conditionals, and nested exception handling. 3. Clarity of intent: Descriptive method names, Javadocs, and section comments explain most behavior, though abbreviated variables, reflection, and empty-body search loops require careful interpretation. 4. Code length: Many methods are concise, but repetitive accessors and duplicated serialization logic make the class lengthy; loading and saving methods would benefit from decomposition. 5. Action granularity: Most statements perform one action per line, with occasional chained assignments and side-effecting increments reducing explicitness. 6. Reading flow: Clear spacing and sequential serialization sections support navigation, but inconsistent indentation, omitted braces, long expressions, and repeated getter chains interrupt the flow. Overall, understandable and documented, but complex sections and excessive scope limit readability.

Run 2

1. Code Structure: Methods are generally organized by related operations, but Scene combines state management, animation, selection, UI, and serialization in one oversized class. 2. Nesting: Accessors and many operations are flat; dependency removal and deserialization contain deeply nested loops, conditionals, and try/catch blocks. 3. Clarity of intent: Descriptive method names, Javadocs, and section comments explain most behavior, while abbreviations, reflection, empty-body loops, and complex conditions require extra effort. 4. Code length: Numerous simple accessors are understandable, but repetitive serialization logic and very long methods increase navigation and comprehension costs. 5. Action granularity: Most statements perform one action per line, with occasional chained assignments and increment side effects reducing explicitness. 6. Reading flow: Related methods and sequential read/write sections provide a natural flow, but inconsistent indentation, omitted braces, long expressions, and repeated getter chains disrupt it.

Run 3

1. Code Structure: Methods are generally organized by related operations, but the large Scene class combines scene state, animation, selection, UI, and persistence responsibilities. 2. Nesting: Accessors and basic operations are flat; dependency removal and reflective deserialization contain deep loops and nested try/catch blocks. 3. Clarity of intent: Descriptive method names, documentation, and section comments explain most purposes, although abbreviated variables, empty-body loops, and reflection complicate interpretation. 4. Code length: Many methods are concise, but extensive accessor boilerplate, repeated serialization patterns, and long loading/saving methods make the class cumbersome to navigate. 5. Action granularity: Most statements perform one action per line; chained assignments, increments inside expressions, and lengthy constructor calls occasionally obscure individual steps. 6. Reading flow: Related methods and serialization phases mostly follow a natural sequence, but inconsistent indentation, optional braces, repeated getter chains, and scattered responsibilities interrupt the flow. Overall, understandable locally but harder to comprehend and maintain as a whole.