joonsrenderer 1.1-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +53 -0
- data/.mvn/extensions.xml +8 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +6 -0
- data/LICENSE +674 -0
- data/README.md +2 -0
- data/Rakefile +43 -0
- data/docs/.gitignore +6 -0
- data/docs/_config.yml +20 -0
- data/docs/_includes/footer.html +38 -0
- data/docs/_includes/head.html +15 -0
- data/docs/_includes/header.html +27 -0
- data/docs/_includes/icon-github.html +1 -0
- data/docs/_includes/icon-github.svg +1 -0
- data/docs/_includes/icon-twitter.html +1 -0
- data/docs/_includes/icon-twitter.svg +1 -0
- data/docs/_layouts/default.html +20 -0
- data/docs/_layouts/page.html +14 -0
- data/docs/_layouts/post.html +15 -0
- data/docs/_posts/2017-01-08-animated_ray_tracing.md +72 -0
- data/docs/_posts/2017-01-08-welcome.md +78 -0
- data/docs/_sass/_base.scss +206 -0
- data/docs/_sass/_layout.scss +242 -0
- data/docs/_sass/_syntax-highlighting.scss +71 -0
- data/docs/about.md +12 -0
- data/docs/assets/Animation.ogv +0 -0
- data/docs/assets/Animation.png +0 -0
- data/docs/assets/basic.png +0 -0
- data/docs/assets/basic_traced.png +0 -0
- data/docs/css/main.scss +38 -0
- data/docs/favicon.ico +0 -0
- data/docs/feed.xml +30 -0
- data/docs/index.html +38 -0
- data/joonsrenderer.gemspec +23 -0
- data/lib/joonsrenderer.rb +12 -0
- data/lib/joonsrenderer/version.rb +3 -0
- data/pom.rb +75 -0
- data/pom.xml +163 -0
- data/src/main/java/SunflowGUI.java +1354 -0
- data/src/main/java/joons/JRFiller.java +79 -0
- data/src/main/java/joons/JRImagePanel.java +141 -0
- data/src/main/java/joons/JRRecorder.java +183 -0
- data/src/main/java/joons/JRStatics.java +199 -0
- data/src/main/java/joons/JoonsRenderer.java +837 -0
- data/src/main/java/org/sunflow/AsciiFileSunflowAPI.java +98 -0
- data/src/main/java/org/sunflow/Benchmark.java +313 -0
- data/src/main/java/org/sunflow/BinaryFileSunflowAPI.java +228 -0
- data/src/main/java/org/sunflow/FileSunflowAPI.java +354 -0
- data/src/main/java/org/sunflow/PluginRegistry.java +322 -0
- data/src/main/java/org/sunflow/RealtimeBenchmark.java +125 -0
- data/src/main/java/org/sunflow/RenderObjectMap.java +344 -0
- data/src/main/java/org/sunflow/SunflowAPI.java +762 -0
- data/src/main/java/org/sunflow/SunflowAPIInterface.java +277 -0
- data/src/main/java/org/sunflow/core/AccelerationStructure.java +20 -0
- data/src/main/java/org/sunflow/core/AccelerationStructureFactory.java +36 -0
- data/src/main/java/org/sunflow/core/BucketOrder.java +21 -0
- data/src/main/java/org/sunflow/core/Camera.java +125 -0
- data/src/main/java/org/sunflow/core/CameraLens.java +29 -0
- data/src/main/java/org/sunflow/core/CausticPhotonMapInterface.java +15 -0
- data/src/main/java/org/sunflow/core/Display.java +78 -0
- data/src/main/java/org/sunflow/core/Filter.java +27 -0
- data/src/main/java/org/sunflow/core/GIEngine.java +42 -0
- data/src/main/java/org/sunflow/core/Geometry.java +157 -0
- data/src/main/java/org/sunflow/core/GlobalPhotonMapInterface.java +21 -0
- data/src/main/java/org/sunflow/core/ImageSampler.java +26 -0
- data/src/main/java/org/sunflow/core/Instance.java +224 -0
- data/src/main/java/org/sunflow/core/InstanceList.java +83 -0
- data/src/main/java/org/sunflow/core/IntersectionState.java +120 -0
- data/src/main/java/org/sunflow/core/LightSample.java +104 -0
- data/src/main/java/org/sunflow/core/LightServer.java +382 -0
- data/src/main/java/org/sunflow/core/LightSource.java +67 -0
- data/src/main/java/org/sunflow/core/Modifier.java +16 -0
- data/src/main/java/org/sunflow/core/Options.java +20 -0
- data/src/main/java/org/sunflow/core/ParameterList.java +758 -0
- data/src/main/java/org/sunflow/core/PhotonStore.java +62 -0
- data/src/main/java/org/sunflow/core/PrimitiveList.java +70 -0
- data/src/main/java/org/sunflow/core/Ray.java +219 -0
- data/src/main/java/org/sunflow/core/RenderObject.java +25 -0
- data/src/main/java/org/sunflow/core/Scene.java +377 -0
- data/src/main/java/org/sunflow/core/SceneParser.java +58 -0
- data/src/main/java/org/sunflow/core/Shader.java +30 -0
- data/src/main/java/org/sunflow/core/ShadingCache.java +84 -0
- data/src/main/java/org/sunflow/core/ShadingState.java +939 -0
- data/src/main/java/org/sunflow/core/Statistics.java +85 -0
- data/src/main/java/org/sunflow/core/Tesselatable.java +36 -0
- data/src/main/java/org/sunflow/core/Texture.java +128 -0
- data/src/main/java/org/sunflow/core/TextureCache.java +48 -0
- data/src/main/java/org/sunflow/core/accel/BoundingIntervalHierarchy.java +652 -0
- data/src/main/java/org/sunflow/core/accel/KDTree.java +833 -0
- data/src/main/java/org/sunflow/core/accel/NullAccelerator.java +30 -0
- data/src/main/java/org/sunflow/core/accel/UniformGrid.java +329 -0
- data/src/main/java/org/sunflow/core/bucket/BucketOrderFactory.java +26 -0
- data/src/main/java/org/sunflow/core/bucket/ColumnBucketOrder.java +21 -0
- data/src/main/java/org/sunflow/core/bucket/DiagonalBucketOrder.java +28 -0
- data/src/main/java/org/sunflow/core/bucket/HilbertBucketOrder.java +65 -0
- data/src/main/java/org/sunflow/core/bucket/InvertedBucketOrder.java +28 -0
- data/src/main/java/org/sunflow/core/bucket/RandomBucketOrder.java +49 -0
- data/src/main/java/org/sunflow/core/bucket/RowBucketOrder.java +21 -0
- data/src/main/java/org/sunflow/core/bucket/SpiralBucketOrder.java +43 -0
- data/src/main/java/org/sunflow/core/camera/FisheyeLens.java +25 -0
- data/src/main/java/org/sunflow/core/camera/PinholeLens.java +43 -0
- data/src/main/java/org/sunflow/core/camera/SphericalLens.java +22 -0
- data/src/main/java/org/sunflow/core/camera/ThinLens.java +107 -0
- data/src/main/java/org/sunflow/core/display/FastDisplay.java +119 -0
- data/src/main/java/org/sunflow/core/display/FileDisplay.java +83 -0
- data/src/main/java/org/sunflow/core/display/FrameDisplay.java +97 -0
- data/src/main/java/org/sunflow/core/display/ImgPipeDisplay.java +109 -0
- data/src/main/java/org/sunflow/core/filter/BlackmanHarrisFilter.java +28 -0
- data/src/main/java/org/sunflow/core/filter/BoxFilter.java +16 -0
- data/src/main/java/org/sunflow/core/filter/CatmullRomFilter.java +29 -0
- data/src/main/java/org/sunflow/core/filter/CubicBSpline.java +32 -0
- data/src/main/java/org/sunflow/core/filter/GaussianFilter.java +24 -0
- data/src/main/java/org/sunflow/core/filter/LanczosFilter.java +30 -0
- data/src/main/java/org/sunflow/core/filter/MitchellFilter.java +28 -0
- data/src/main/java/org/sunflow/core/filter/SincFilter.java +25 -0
- data/src/main/java/org/sunflow/core/filter/TriangleFilter.java +16 -0
- data/src/main/java/org/sunflow/core/gi/AmbientOcclusionGIEngine.java +57 -0
- data/src/main/java/org/sunflow/core/gi/FakeGIEngine.java +48 -0
- data/src/main/java/org/sunflow/core/gi/InstantGI.java +194 -0
- data/src/main/java/org/sunflow/core/gi/IrradianceCacheGIEngine.java +268 -0
- data/src/main/java/org/sunflow/core/gi/PathTracingGIEngine.java +65 -0
- data/src/main/java/org/sunflow/core/light/DirectionalSpotlight.java +103 -0
- data/src/main/java/org/sunflow/core/light/ImageBasedLight.java +303 -0
- data/src/main/java/org/sunflow/core/light/PointLight.java +72 -0
- data/src/main/java/org/sunflow/core/light/SphereLight.java +166 -0
- data/src/main/java/org/sunflow/core/light/SunSkyLight.java +362 -0
- data/src/main/java/org/sunflow/core/light/TriangleMeshLight.java +296 -0
- data/src/main/java/org/sunflow/core/modifiers/BumpMappingModifier.java +37 -0
- data/src/main/java/org/sunflow/core/modifiers/NormalMapModifier.java +34 -0
- data/src/main/java/org/sunflow/core/modifiers/PerlinModifier.java +80 -0
- data/src/main/java/org/sunflow/core/parser/Keyword.java +39 -0
- data/src/main/java/org/sunflow/core/parser/RA2Parser.java +107 -0
- data/src/main/java/org/sunflow/core/parser/RA3Parser.java +68 -0
- data/src/main/java/org/sunflow/core/parser/SCAbstractParser.java +299 -0
- data/src/main/java/org/sunflow/core/parser/SCAsciiParser.java +251 -0
- data/src/main/java/org/sunflow/core/parser/SCBinaryParser.java +156 -0
- data/src/main/java/org/sunflow/core/parser/SCParser.java +1403 -0
- data/src/main/java/org/sunflow/core/parser/ShaveRibParser.java +174 -0
- data/src/main/java/org/sunflow/core/parser/TriParser.java +79 -0
- data/src/main/java/org/sunflow/core/photonmap/CausticPhotonMap.java +429 -0
- data/src/main/java/org/sunflow/core/photonmap/GlobalPhotonMap.java +530 -0
- data/src/main/java/org/sunflow/core/photonmap/GridPhotonMap.java +308 -0
- data/src/main/java/org/sunflow/core/primitive/Background.java +55 -0
- data/src/main/java/org/sunflow/core/primitive/BanchoffSurface.java +100 -0
- data/src/main/java/org/sunflow/core/primitive/Box.java +210 -0
- data/src/main/java/org/sunflow/core/primitive/CornellBox.java +476 -0
- data/src/main/java/org/sunflow/core/primitive/CubeGrid.java +318 -0
- data/src/main/java/org/sunflow/core/primitive/Cylinder.java +104 -0
- data/src/main/java/org/sunflow/core/primitive/Hair.java +275 -0
- data/src/main/java/org/sunflow/core/primitive/JuliaFractal.java +266 -0
- data/src/main/java/org/sunflow/core/primitive/ParticleSurface.java +114 -0
- data/src/main/java/org/sunflow/core/primitive/Plane.java +163 -0
- data/src/main/java/org/sunflow/core/primitive/QuadMesh.java +413 -0
- data/src/main/java/org/sunflow/core/primitive/Sphere.java +101 -0
- data/src/main/java/org/sunflow/core/primitive/SphereFlake.java +234 -0
- data/src/main/java/org/sunflow/core/primitive/Torus.java +145 -0
- data/src/main/java/org/sunflow/core/primitive/TriangleMesh.java +849 -0
- data/src/main/java/org/sunflow/core/renderer/BucketRenderer.java +491 -0
- data/src/main/java/org/sunflow/core/renderer/MultipassRenderer.java +237 -0
- data/src/main/java/org/sunflow/core/renderer/ProgressiveRenderer.java +171 -0
- data/src/main/java/org/sunflow/core/renderer/SimpleRenderer.java +106 -0
- data/src/main/java/org/sunflow/core/shader/AmbientOcclusionShader.java +53 -0
- data/src/main/java/org/sunflow/core/shader/AnisotropicWardShader.java +216 -0
- data/src/main/java/org/sunflow/core/shader/ConstantShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/DiffuseShader.java +65 -0
- data/src/main/java/org/sunflow/core/shader/GlassShader.java +147 -0
- data/src/main/java/org/sunflow/core/shader/IDShader.java +27 -0
- data/src/main/java/org/sunflow/core/shader/MirrorShader.java +68 -0
- data/src/main/java/org/sunflow/core/shader/NormalShader.java +32 -0
- data/src/main/java/org/sunflow/core/shader/PhongShader.java +89 -0
- data/src/main/java/org/sunflow/core/shader/PrimIDShader.java +30 -0
- data/src/main/java/org/sunflow/core/shader/QuickGrayShader.java +63 -0
- data/src/main/java/org/sunflow/core/shader/ShinyDiffuseShader.java +98 -0
- data/src/main/java/org/sunflow/core/shader/SimpleShader.java +24 -0
- data/src/main/java/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/TexturedDiffuseShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/TexturedPhongShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/TexturedShinyDiffuseShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/TexturedWardShader.java +31 -0
- data/src/main/java/org/sunflow/core/shader/UVShader.java +27 -0
- data/src/main/java/org/sunflow/core/shader/UberShader.java +149 -0
- data/src/main/java/org/sunflow/core/shader/ViewCausticsShader.java +33 -0
- data/src/main/java/org/sunflow/core/shader/ViewGlobalPhotonsShader.java +25 -0
- data/src/main/java/org/sunflow/core/shader/ViewIrradianceShader.java +25 -0
- data/src/main/java/org/sunflow/core/shader/WireframeShader.java +83 -0
- data/src/main/java/org/sunflow/core/tesselatable/BezierMesh.java +254 -0
- data/src/main/java/org/sunflow/core/tesselatable/FileMesh.java +251 -0
- data/src/main/java/org/sunflow/core/tesselatable/Gumbo.java +1147 -0
- data/src/main/java/org/sunflow/core/tesselatable/Teapot.java +237 -0
- data/src/main/java/org/sunflow/image/Bitmap.java +15 -0
- data/src/main/java/org/sunflow/image/BitmapReader.java +39 -0
- data/src/main/java/org/sunflow/image/BitmapWriter.java +79 -0
- data/src/main/java/org/sunflow/image/BlackbodySpectrum.java +16 -0
- data/src/main/java/org/sunflow/image/ChromaticitySpectrum.java +55 -0
- data/src/main/java/org/sunflow/image/Color.java +374 -0
- data/src/main/java/org/sunflow/image/ColorEncoder.java +94 -0
- data/src/main/java/org/sunflow/image/ColorFactory.java +122 -0
- data/src/main/java/org/sunflow/image/ConstantSpectralCurve.java +21 -0
- data/src/main/java/org/sunflow/image/IrregularSpectralCurve.java +57 -0
- data/src/main/java/org/sunflow/image/RGBSpace.java +207 -0
- data/src/main/java/org/sunflow/image/RegularSpectralCurve.java +30 -0
- data/src/main/java/org/sunflow/image/SpectralCurve.java +118 -0
- data/src/main/java/org/sunflow/image/XYZColor.java +50 -0
- data/src/main/java/org/sunflow/image/formats/BitmapBlack.java +27 -0
- data/src/main/java/org/sunflow/image/formats/BitmapG8.java +36 -0
- data/src/main/java/org/sunflow/image/formats/BitmapGA8.java +30 -0
- data/src/main/java/org/sunflow/image/formats/BitmapRGB8.java +40 -0
- data/src/main/java/org/sunflow/image/formats/BitmapRGBA8.java +40 -0
- data/src/main/java/org/sunflow/image/formats/BitmapRGBE.java +60 -0
- data/src/main/java/org/sunflow/image/formats/BitmapXYZ.java +38 -0
- data/src/main/java/org/sunflow/image/formats/GenericBitmap.java +73 -0
- data/src/main/java/org/sunflow/image/readers/BMPBitmapReader.java +39 -0
- data/src/main/java/org/sunflow/image/readers/HDRBitmapReader.java +155 -0
- data/src/main/java/org/sunflow/image/readers/IGIBitmapReader.java +104 -0
- data/src/main/java/org/sunflow/image/readers/JPGBitmapReader.java +39 -0
- data/src/main/java/org/sunflow/image/readers/PNGBitmapReader.java +40 -0
- data/src/main/java/org/sunflow/image/readers/TGABitmapReader.java +141 -0
- data/src/main/java/org/sunflow/image/writers/EXRBitmapWriter.java +395 -0
- data/src/main/java/org/sunflow/image/writers/HDRBitmapWriter.java +54 -0
- data/src/main/java/org/sunflow/image/writers/IGIBitmapWriter.java +75 -0
- data/src/main/java/org/sunflow/image/writers/PNGBitmapWriter.java +39 -0
- data/src/main/java/org/sunflow/image/writers/TGABitmapWriter.java +63 -0
- data/src/main/java/org/sunflow/math/BoundingBox.java +340 -0
- data/src/main/java/org/sunflow/math/MathUtils.java +159 -0
- data/src/main/java/org/sunflow/math/Matrix4.java +573 -0
- data/src/main/java/org/sunflow/math/MovingMatrix4.java +119 -0
- data/src/main/java/org/sunflow/math/OrthoNormalBasis.java +110 -0
- data/src/main/java/org/sunflow/math/PerlinScalar.java +331 -0
- data/src/main/java/org/sunflow/math/PerlinVector.java +132 -0
- data/src/main/java/org/sunflow/math/Point2.java +36 -0
- data/src/main/java/org/sunflow/math/Point3.java +133 -0
- data/src/main/java/org/sunflow/math/QMC.java +209 -0
- data/src/main/java/org/sunflow/math/Solvers.java +142 -0
- data/src/main/java/org/sunflow/math/Vector3.java +197 -0
- data/src/main/java/org/sunflow/system/BenchmarkFramework.java +73 -0
- data/src/main/java/org/sunflow/system/BenchmarkTest.java +17 -0
- data/src/main/java/org/sunflow/system/ByteUtil.java +119 -0
- data/src/main/java/org/sunflow/system/FileUtils.java +27 -0
- data/src/main/java/org/sunflow/system/ImagePanel.java +282 -0
- data/src/main/java/org/sunflow/system/Memory.java +18 -0
- data/src/main/java/org/sunflow/system/Parser.java +162 -0
- data/src/main/java/org/sunflow/system/Plugins.java +142 -0
- data/src/main/java/org/sunflow/system/RenderGlobalsPanel.java +209 -0
- data/src/main/java/org/sunflow/system/SearchPath.java +67 -0
- data/src/main/java/org/sunflow/system/Timer.java +53 -0
- data/src/main/java/org/sunflow/system/UI.java +112 -0
- data/src/main/java/org/sunflow/system/UserInterface.java +46 -0
- data/src/main/java/org/sunflow/system/ui/ConsoleInterface.java +48 -0
- data/src/main/java/org/sunflow/system/ui/SilentInterface.java +28 -0
- data/src/main/java/org/sunflow/util/FastHashMap.java +220 -0
- data/src/main/java/org/sunflow/util/FloatArray.java +77 -0
- data/src/main/java/org/sunflow/util/IntArray.java +77 -0
- data/src/test/java/a_maintest.java +129 -0
- metadata +300 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
package org.sunflow.core.parser;
|
|
2
|
+
|
|
3
|
+
import java.io.IOException;
|
|
4
|
+
|
|
5
|
+
import org.sunflow.core.ParameterList.InterpolationType;
|
|
6
|
+
import org.sunflow.image.Color;
|
|
7
|
+
import org.sunflow.math.Matrix4;
|
|
8
|
+
import org.sunflow.system.Parser;
|
|
9
|
+
import org.sunflow.system.UI;
|
|
10
|
+
import org.sunflow.system.Parser.ParserException;
|
|
11
|
+
import org.sunflow.system.UI.Module;
|
|
12
|
+
|
|
13
|
+
public class SCAsciiParser extends SCAbstractParser {
|
|
14
|
+
|
|
15
|
+
private Parser p;
|
|
16
|
+
|
|
17
|
+
protected Color parseColor() throws IOException {
|
|
18
|
+
String space = p.getNextToken();
|
|
19
|
+
Color c = null;
|
|
20
|
+
if (space.equals("sRGB nonlinear")) {
|
|
21
|
+
float r = p.getNextFloat();
|
|
22
|
+
float g = p.getNextFloat();
|
|
23
|
+
float b = p.getNextFloat();
|
|
24
|
+
c = new Color(r, g, b);
|
|
25
|
+
c.toLinear();
|
|
26
|
+
} else if (space.equals("sRGB linear")) {
|
|
27
|
+
float r = p.getNextFloat();
|
|
28
|
+
float g = p.getNextFloat();
|
|
29
|
+
float b = p.getNextFloat();
|
|
30
|
+
c = new Color(r, g, b);
|
|
31
|
+
} else {
|
|
32
|
+
UI.printWarning(Module.API, "Unrecognized color space: %s", space);
|
|
33
|
+
}
|
|
34
|
+
return c;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@Override
|
|
38
|
+
protected Matrix4 parseMatrix() throws IOException {
|
|
39
|
+
if (p.peekNextToken("row")) {
|
|
40
|
+
return new Matrix4(parseFloatArray(16), true);
|
|
41
|
+
} else if (p.peekNextToken("col")) {
|
|
42
|
+
return new Matrix4(parseFloatArray(16), false);
|
|
43
|
+
} else {
|
|
44
|
+
Matrix4 m = Matrix4.IDENTITY;
|
|
45
|
+
try {
|
|
46
|
+
p.checkNextToken("{");
|
|
47
|
+
} catch (ParserException e) {
|
|
48
|
+
throw new IOException(e.getMessage());
|
|
49
|
+
}
|
|
50
|
+
while (!p.peekNextToken("}")) {
|
|
51
|
+
Matrix4 t = null;
|
|
52
|
+
if (p.peekNextToken("translate")) {
|
|
53
|
+
float x = p.getNextFloat();
|
|
54
|
+
float y = p.getNextFloat();
|
|
55
|
+
float z = p.getNextFloat();
|
|
56
|
+
t = Matrix4.translation(x, y, z);
|
|
57
|
+
} else if (p.peekNextToken("scaleu")) {
|
|
58
|
+
float s = p.getNextFloat();
|
|
59
|
+
t = Matrix4.scale(s);
|
|
60
|
+
} else if (p.peekNextToken("scale")) {
|
|
61
|
+
float x = p.getNextFloat();
|
|
62
|
+
float y = p.getNextFloat();
|
|
63
|
+
float z = p.getNextFloat();
|
|
64
|
+
t = Matrix4.scale(x, y, z);
|
|
65
|
+
} else if (p.peekNextToken("rotatex")) {
|
|
66
|
+
float angle = p.getNextFloat();
|
|
67
|
+
t = Matrix4.rotateX((float) Math.toRadians(angle));
|
|
68
|
+
} else if (p.peekNextToken("rotatey")) {
|
|
69
|
+
float angle = p.getNextFloat();
|
|
70
|
+
t = Matrix4.rotateY((float) Math.toRadians(angle));
|
|
71
|
+
} else if (p.peekNextToken("rotatez")) {
|
|
72
|
+
float angle = p.getNextFloat();
|
|
73
|
+
t = Matrix4.rotateZ((float) Math.toRadians(angle));
|
|
74
|
+
} else if (p.peekNextToken("rotate")) {
|
|
75
|
+
float x = p.getNextFloat();
|
|
76
|
+
float y = p.getNextFloat();
|
|
77
|
+
float z = p.getNextFloat();
|
|
78
|
+
float angle = p.getNextFloat();
|
|
79
|
+
t = Matrix4.rotate(x, y, z, (float) Math.toRadians(angle));
|
|
80
|
+
} else {
|
|
81
|
+
UI.printWarning(Module.API, "Unrecognized transformation type: %s", p.getNextToken());
|
|
82
|
+
}
|
|
83
|
+
if (t != null) {
|
|
84
|
+
m = t.multiply(m);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return m;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@Override
|
|
92
|
+
protected void closeParser() throws IOException {
|
|
93
|
+
p.close();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@Override
|
|
97
|
+
protected void openParser(String filename) throws IOException {
|
|
98
|
+
p = new Parser(filename);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@Override
|
|
102
|
+
protected boolean parseBoolean() throws IOException {
|
|
103
|
+
return Boolean.parseBoolean(parseString());
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@Override
|
|
107
|
+
protected float parseFloat() throws IOException {
|
|
108
|
+
return p.getNextFloat();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
@Override
|
|
112
|
+
protected int parseInt() throws IOException {
|
|
113
|
+
return p.getNextInt();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
@Override
|
|
117
|
+
protected String parseString() throws IOException {
|
|
118
|
+
return p.getNextToken();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
@Override
|
|
122
|
+
protected String parseVerbatimString() throws IOException {
|
|
123
|
+
try {
|
|
124
|
+
return p.getNextCodeBlock();
|
|
125
|
+
} catch (ParserException e) {
|
|
126
|
+
throw new IOException(e.getMessage());
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
@Override
|
|
131
|
+
protected InterpolationType parseInterpolationType() throws IOException {
|
|
132
|
+
if (p.peekNextToken("none")) {
|
|
133
|
+
return InterpolationType.NONE;
|
|
134
|
+
} else if (p.peekNextToken("vertex")) {
|
|
135
|
+
return InterpolationType.VERTEX;
|
|
136
|
+
} else if (p.peekNextToken("face")) {
|
|
137
|
+
return InterpolationType.FACE;
|
|
138
|
+
} else if (p.peekNextToken("facevarying")) {
|
|
139
|
+
return InterpolationType.FACEVARYING;
|
|
140
|
+
}
|
|
141
|
+
return InterpolationType.NONE;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@Override
|
|
145
|
+
protected Keyword parseKeyword() throws IOException {
|
|
146
|
+
String keyword = p.getNextToken();
|
|
147
|
+
if (keyword == null) {
|
|
148
|
+
return Keyword.END_OF_FILE;
|
|
149
|
+
}
|
|
150
|
+
if (anyEqual(keyword, "reset")) {
|
|
151
|
+
return Keyword.RESET;
|
|
152
|
+
}
|
|
153
|
+
if (anyEqual(keyword, "parameter", "param", "p")) {
|
|
154
|
+
return Keyword.PARAMETER;
|
|
155
|
+
}
|
|
156
|
+
if (anyEqual(keyword, "geometry", "geom", "g")) {
|
|
157
|
+
return Keyword.GEOMETRY;
|
|
158
|
+
}
|
|
159
|
+
if (anyEqual(keyword, "instance", "inst", "i")) {
|
|
160
|
+
return Keyword.INSTANCE;
|
|
161
|
+
}
|
|
162
|
+
if (anyEqual(keyword, "shader", "shd", "s")) {
|
|
163
|
+
return Keyword.SHADER;
|
|
164
|
+
}
|
|
165
|
+
if (anyEqual(keyword, "modifier", "mod", "m")) {
|
|
166
|
+
return Keyword.MODIFIER;
|
|
167
|
+
}
|
|
168
|
+
if (anyEqual(keyword, "light", "l")) {
|
|
169
|
+
return Keyword.LIGHT;
|
|
170
|
+
}
|
|
171
|
+
if (anyEqual(keyword, "camera", "cam", "c")) {
|
|
172
|
+
return Keyword.CAMERA;
|
|
173
|
+
}
|
|
174
|
+
if (anyEqual(keyword, "options", "opt", "o")) {
|
|
175
|
+
return Keyword.OPTIONS;
|
|
176
|
+
}
|
|
177
|
+
if (anyEqual(keyword, "include", "inc")) {
|
|
178
|
+
return Keyword.INCLUDE;
|
|
179
|
+
}
|
|
180
|
+
if (anyEqual(keyword, "remove")) {
|
|
181
|
+
return Keyword.REMOVE;
|
|
182
|
+
}
|
|
183
|
+
if (anyEqual(keyword, "frame")) {
|
|
184
|
+
return Keyword.FRAME;
|
|
185
|
+
}
|
|
186
|
+
if (anyEqual(keyword, "plugin", "plug")) {
|
|
187
|
+
return Keyword.PLUGIN;
|
|
188
|
+
}
|
|
189
|
+
if (anyEqual(keyword, "searchpath")) {
|
|
190
|
+
return Keyword.SEARCHPATH;
|
|
191
|
+
}
|
|
192
|
+
if (anyEqual(keyword, "string", "str")) {
|
|
193
|
+
return Keyword.STRING;
|
|
194
|
+
}
|
|
195
|
+
if (anyEqual(keyword, "string[]", "str[]")) {
|
|
196
|
+
return Keyword.STRING_ARRAY;
|
|
197
|
+
}
|
|
198
|
+
if (anyEqual(keyword, "boolean", "bool")) {
|
|
199
|
+
return Keyword.BOOL;
|
|
200
|
+
}
|
|
201
|
+
if (anyEqual(keyword, "integer", "int")) {
|
|
202
|
+
return Keyword.INT;
|
|
203
|
+
}
|
|
204
|
+
if (anyEqual(keyword, "integer[]", "int[]")) {
|
|
205
|
+
return Keyword.INT_ARRAY;
|
|
206
|
+
}
|
|
207
|
+
if (anyEqual(keyword, "float", "flt")) {
|
|
208
|
+
return Keyword.FLOAT;
|
|
209
|
+
}
|
|
210
|
+
if (anyEqual(keyword, "float[]", "flt[]")) {
|
|
211
|
+
return Keyword.FLOAT_ARRAY;
|
|
212
|
+
}
|
|
213
|
+
if (anyEqual(keyword, "color", "col")) {
|
|
214
|
+
return Keyword.COLOR;
|
|
215
|
+
}
|
|
216
|
+
if (anyEqual(keyword, "point", "pnt")) {
|
|
217
|
+
return Keyword.POINT;
|
|
218
|
+
}
|
|
219
|
+
if (anyEqual(keyword, "point[]", "pnt[]")) {
|
|
220
|
+
return Keyword.POINT_ARRAY;
|
|
221
|
+
}
|
|
222
|
+
if (anyEqual(keyword, "vector", "vec")) {
|
|
223
|
+
return Keyword.VECTOR;
|
|
224
|
+
}
|
|
225
|
+
if (anyEqual(keyword, "vector[]", "vec[]")) {
|
|
226
|
+
return Keyword.VECTOR_ARRAY;
|
|
227
|
+
}
|
|
228
|
+
if (anyEqual(keyword, "texcoord", "tex")) {
|
|
229
|
+
return Keyword.TEXCOORD;
|
|
230
|
+
}
|
|
231
|
+
if (anyEqual(keyword, "texcoord[]", "tex[]")) {
|
|
232
|
+
return Keyword.TEXCOORD_ARRAY;
|
|
233
|
+
}
|
|
234
|
+
if (anyEqual(keyword, "matrix", "mat")) {
|
|
235
|
+
return Keyword.MATRIX;
|
|
236
|
+
}
|
|
237
|
+
if (anyEqual(keyword, "matrix[]", "mat[]")) {
|
|
238
|
+
return Keyword.MATRIX_ARRAY;
|
|
239
|
+
}
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private boolean anyEqual(String source, String... values) {
|
|
244
|
+
for (String v : values) {
|
|
245
|
+
if (source.equals(v)) {
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
package org.sunflow.core.parser;
|
|
2
|
+
|
|
3
|
+
import java.io.BufferedInputStream;
|
|
4
|
+
import java.io.DataInputStream;
|
|
5
|
+
import java.io.FileInputStream;
|
|
6
|
+
import java.io.IOException;
|
|
7
|
+
|
|
8
|
+
import org.sunflow.core.ParameterList.InterpolationType;
|
|
9
|
+
import org.sunflow.math.Matrix4;
|
|
10
|
+
|
|
11
|
+
public class SCBinaryParser extends SCAbstractParser {
|
|
12
|
+
|
|
13
|
+
private DataInputStream stream;
|
|
14
|
+
|
|
15
|
+
@Override
|
|
16
|
+
protected void closeParser() throws IOException {
|
|
17
|
+
stream.close();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@Override
|
|
21
|
+
protected void openParser(String filename) throws IOException {
|
|
22
|
+
stream = new DataInputStream(new BufferedInputStream(new FileInputStream(filename)));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@Override
|
|
26
|
+
protected boolean parseBoolean() throws IOException {
|
|
27
|
+
return stream.readUnsignedByte() != 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@Override
|
|
31
|
+
protected float parseFloat() throws IOException {
|
|
32
|
+
return Float.intBitsToFloat(parseInt());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@Override
|
|
36
|
+
protected int parseInt() throws IOException {
|
|
37
|
+
// note that we use readUnsignedByte(), not read() to get EOF exceptions
|
|
38
|
+
return stream.readUnsignedByte() | (stream.readUnsignedByte() << 8) | (stream.readUnsignedByte() << 16) | (stream.readUnsignedByte() << 24);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@Override
|
|
42
|
+
protected Matrix4 parseMatrix() throws IOException {
|
|
43
|
+
return new Matrix4(parseFloatArray(16), true);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@Override
|
|
47
|
+
protected String parseString() throws IOException {
|
|
48
|
+
byte[] b = new byte[parseInt()];
|
|
49
|
+
stream.read(b);
|
|
50
|
+
return new String(b, "UTF-8");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@Override
|
|
54
|
+
protected String parseVerbatimString() throws IOException {
|
|
55
|
+
return parseString();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@Override
|
|
59
|
+
protected InterpolationType parseInterpolationType() throws IOException {
|
|
60
|
+
int c;
|
|
61
|
+
switch (c = stream.readUnsignedByte()) {
|
|
62
|
+
case 'n':
|
|
63
|
+
return InterpolationType.NONE;
|
|
64
|
+
case 'v':
|
|
65
|
+
return InterpolationType.VERTEX;
|
|
66
|
+
case 'f':
|
|
67
|
+
return InterpolationType.FACEVARYING;
|
|
68
|
+
case 'p':
|
|
69
|
+
return InterpolationType.FACE;
|
|
70
|
+
default:
|
|
71
|
+
throw new IOException(String.format("Unknown byte found for interpolation type %c", (char) c));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@Override
|
|
76
|
+
protected Keyword parseKeyword() throws IOException {
|
|
77
|
+
int code = stream.read(); // read a single byte - allow for EOF (<0)
|
|
78
|
+
switch (code) {
|
|
79
|
+
case 'p':
|
|
80
|
+
return Keyword.PARAMETER;
|
|
81
|
+
case 'g':
|
|
82
|
+
return Keyword.GEOMETRY;
|
|
83
|
+
case 'i':
|
|
84
|
+
return Keyword.INSTANCE;
|
|
85
|
+
case 's':
|
|
86
|
+
return Keyword.SHADER;
|
|
87
|
+
case 'm':
|
|
88
|
+
return Keyword.MODIFIER;
|
|
89
|
+
case 'l':
|
|
90
|
+
return Keyword.LIGHT;
|
|
91
|
+
case 'c':
|
|
92
|
+
return Keyword.CAMERA;
|
|
93
|
+
case 'o':
|
|
94
|
+
return Keyword.OPTIONS;
|
|
95
|
+
case 'x': {
|
|
96
|
+
// extended keywords (less frequent)
|
|
97
|
+
// note we don't use stream.read() here because we should throw
|
|
98
|
+
// an exception if the end of the file is reached
|
|
99
|
+
switch (code = stream.readUnsignedByte()) {
|
|
100
|
+
case 'R':
|
|
101
|
+
return Keyword.RESET;
|
|
102
|
+
case 'i':
|
|
103
|
+
return Keyword.INCLUDE;
|
|
104
|
+
case 'r':
|
|
105
|
+
return Keyword.REMOVE;
|
|
106
|
+
case 'f':
|
|
107
|
+
return Keyword.FRAME;
|
|
108
|
+
case 'p':
|
|
109
|
+
return Keyword.PLUGIN;
|
|
110
|
+
case 's':
|
|
111
|
+
return Keyword.SEARCHPATH;
|
|
112
|
+
default:
|
|
113
|
+
throw new IOException(String.format("Unknown extended keyword code: %c", (char) code));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
case 't': {
|
|
117
|
+
// data types
|
|
118
|
+
// note we don't use stream.read() here because we should throw
|
|
119
|
+
// an exception if the end of the file is reached
|
|
120
|
+
int type = stream.readUnsignedByte();
|
|
121
|
+
// note that while not all types can be arrays at the moment, we
|
|
122
|
+
// always parse this boolean flag to keep the syntax consistent
|
|
123
|
+
// and allow for future improvements
|
|
124
|
+
boolean isArray = parseBoolean();
|
|
125
|
+
switch (type) {
|
|
126
|
+
case 's':
|
|
127
|
+
return isArray ? Keyword.STRING_ARRAY : Keyword.STRING;
|
|
128
|
+
case 'b':
|
|
129
|
+
return Keyword.BOOL;
|
|
130
|
+
case 'i':
|
|
131
|
+
return isArray ? Keyword.INT_ARRAY : Keyword.INT;
|
|
132
|
+
case 'f':
|
|
133
|
+
return isArray ? Keyword.FLOAT_ARRAY : Keyword.FLOAT;
|
|
134
|
+
case 'c':
|
|
135
|
+
return Keyword.COLOR;
|
|
136
|
+
case 'p':
|
|
137
|
+
return isArray ? Keyword.POINT_ARRAY : Keyword.POINT;
|
|
138
|
+
case 'v':
|
|
139
|
+
return isArray ? Keyword.VECTOR_ARRAY : Keyword.VECTOR;
|
|
140
|
+
case 't':
|
|
141
|
+
return isArray ? Keyword.TEXCOORD_ARRAY : Keyword.TEXCOORD;
|
|
142
|
+
case 'm':
|
|
143
|
+
return isArray ? Keyword.MATRIX_ARRAY : Keyword.MATRIX;
|
|
144
|
+
default:
|
|
145
|
+
throw new IOException(String.format("Unknown datatype keyword code: %c", (char) type));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
default:
|
|
149
|
+
if (code < 0) {
|
|
150
|
+
return Keyword.END_OF_FILE; // normal end of file reached
|
|
151
|
+
} else {
|
|
152
|
+
throw new IOException(String.format("Unknown keyword code: %c", (char) code));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,1403 @@
|
|
|
1
|
+
package org.sunflow.core.parser;
|
|
2
|
+
|
|
3
|
+
import java.io.File;
|
|
4
|
+
import java.io.FileInputStream;
|
|
5
|
+
import java.io.FileNotFoundException;
|
|
6
|
+
import java.io.IOException;
|
|
7
|
+
import java.nio.ByteOrder;
|
|
8
|
+
import java.nio.FloatBuffer;
|
|
9
|
+
import java.nio.MappedByteBuffer;
|
|
10
|
+
import java.nio.channels.FileChannel;
|
|
11
|
+
import java.util.HashMap;
|
|
12
|
+
import java.util.logging.Level;
|
|
13
|
+
import java.util.logging.Logger;
|
|
14
|
+
|
|
15
|
+
import org.sunflow.PluginRegistry;
|
|
16
|
+
import org.sunflow.SunflowAPI;
|
|
17
|
+
import org.sunflow.SunflowAPIInterface;
|
|
18
|
+
import org.sunflow.core.SceneParser;
|
|
19
|
+
import org.sunflow.image.Color;
|
|
20
|
+
import org.sunflow.image.ColorFactory;
|
|
21
|
+
import org.sunflow.image.ColorFactory.ColorSpecificationException;
|
|
22
|
+
import org.sunflow.math.Matrix4;
|
|
23
|
+
import org.sunflow.math.Point3;
|
|
24
|
+
import org.sunflow.math.Vector3;
|
|
25
|
+
import org.sunflow.system.Parser;
|
|
26
|
+
import org.sunflow.system.Timer;
|
|
27
|
+
import org.sunflow.system.UI;
|
|
28
|
+
import org.sunflow.system.Parser.ParserException;
|
|
29
|
+
import org.sunflow.system.UI.Module;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* This class provides a static method for loading files in the Sunflow scene
|
|
33
|
+
* file format.
|
|
34
|
+
*/
|
|
35
|
+
public class SCParser implements SceneParser {
|
|
36
|
+
|
|
37
|
+
private static int instanceCounter = 0;
|
|
38
|
+
private final int instanceNumber;
|
|
39
|
+
private Parser p;
|
|
40
|
+
private int numLightSamples;
|
|
41
|
+
// used to generate unique names inside this parser
|
|
42
|
+
private final HashMap<String, Integer> objectNames;
|
|
43
|
+
|
|
44
|
+
public SCParser() {
|
|
45
|
+
objectNames = new HashMap<>();
|
|
46
|
+
instanceCounter++;
|
|
47
|
+
instanceNumber = instanceCounter;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private String generateUniqueName(String prefix) {
|
|
51
|
+
// generate a unique name for this class:
|
|
52
|
+
int index = 1;
|
|
53
|
+
Integer value = objectNames.get(prefix);
|
|
54
|
+
if (value != null) {
|
|
55
|
+
index = value;
|
|
56
|
+
objectNames.put(prefix, index + 1);
|
|
57
|
+
} else {
|
|
58
|
+
objectNames.put(prefix, index + 1);
|
|
59
|
+
}
|
|
60
|
+
return String.format("@sc_%d::%s_%d", instanceNumber, prefix, index);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@Override
|
|
64
|
+
public boolean parse(String filename, SunflowAPIInterface api) {
|
|
65
|
+
String localDir = new File(filename).getAbsoluteFile().getParentFile().getAbsolutePath();
|
|
66
|
+
numLightSamples = 1;
|
|
67
|
+
Timer timer = new Timer();
|
|
68
|
+
timer.start();
|
|
69
|
+
UI.printInfo(Module.API, "Parsing \"%s\" ...", filename);
|
|
70
|
+
try {
|
|
71
|
+
p = new Parser(filename);
|
|
72
|
+
while (true) {
|
|
73
|
+
String token = p.getNextToken();
|
|
74
|
+
if (token == null) {
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
switch (token) {
|
|
78
|
+
case "image":
|
|
79
|
+
UI.printInfo(Module.API, "Reading image settings ...");
|
|
80
|
+
parseImageBlock(api);
|
|
81
|
+
break;
|
|
82
|
+
case BACKGROUND:
|
|
83
|
+
UI.printInfo(Module.API, "Reading background ...");
|
|
84
|
+
parseBackgroundBlock(api);
|
|
85
|
+
break;
|
|
86
|
+
case "accel":
|
|
87
|
+
UI.printInfo(Module.API, "Reading accelerator type ...");
|
|
88
|
+
p.getNextToken();
|
|
89
|
+
UI.printWarning(Module.API, "Setting accelerator type is not recommended - ignoring");
|
|
90
|
+
break;
|
|
91
|
+
case FILTER:
|
|
92
|
+
UI.printInfo(Module.API, "Reading image filter type ...");
|
|
93
|
+
parseFilter(api);
|
|
94
|
+
break;
|
|
95
|
+
case "bucket":
|
|
96
|
+
UI.printInfo(Module.API, "Reading bucket settings ...");
|
|
97
|
+
api.parameter("bucket.size", p.getNextInt());
|
|
98
|
+
api.parameter("bucket.order", p.getNextToken());
|
|
99
|
+
api.options(SunflowAPI.DEFAULT_OPTIONS);
|
|
100
|
+
break;
|
|
101
|
+
case "photons":
|
|
102
|
+
UI.printInfo(Module.API, "Reading photon settings ...");
|
|
103
|
+
parsePhotonBlock(api);
|
|
104
|
+
break;
|
|
105
|
+
case "gi":
|
|
106
|
+
UI.printInfo(Module.API, "Reading global illumination settings ...");
|
|
107
|
+
parseGIBlock(api);
|
|
108
|
+
break;
|
|
109
|
+
case "lightserver":
|
|
110
|
+
UI.printInfo(Module.API, "Reading light server settings ...");
|
|
111
|
+
parseLightserverBlock(api);
|
|
112
|
+
break;
|
|
113
|
+
case "trace-depths":
|
|
114
|
+
UI.printInfo(Module.API, "Reading trace depths ...");
|
|
115
|
+
parseTraceBlock(api);
|
|
116
|
+
break;
|
|
117
|
+
case "camera":
|
|
118
|
+
parseCamera(api);
|
|
119
|
+
break;
|
|
120
|
+
case SHADER:
|
|
121
|
+
if (!parseShader(api)) {
|
|
122
|
+
return false;
|
|
123
|
+
} break;
|
|
124
|
+
case MODIFIER:
|
|
125
|
+
if (!parseModifier(api)) {
|
|
126
|
+
return false;
|
|
127
|
+
} break;
|
|
128
|
+
case "override":
|
|
129
|
+
api.parameter("override.shader", p.getNextToken());
|
|
130
|
+
api.parameter("override.photons", p.getNextBoolean());
|
|
131
|
+
api.options(SunflowAPI.DEFAULT_OPTIONS);
|
|
132
|
+
break;
|
|
133
|
+
case "object":
|
|
134
|
+
parseObjectBlock(api);
|
|
135
|
+
break;
|
|
136
|
+
case "instance":
|
|
137
|
+
parseInstanceBlock(api);
|
|
138
|
+
break;
|
|
139
|
+
case "light":
|
|
140
|
+
parseLightBlock(api);
|
|
141
|
+
break;
|
|
142
|
+
case "texturepath":
|
|
143
|
+
{
|
|
144
|
+
String path = p.getNextToken();
|
|
145
|
+
if (!new File(path).isAbsolute()) {
|
|
146
|
+
path = localDir + File.separator + path;
|
|
147
|
+
} api.searchpath(TEXTURE, path);
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
case "includepath":
|
|
151
|
+
{
|
|
152
|
+
String path = p.getNextToken();
|
|
153
|
+
if (!new File(path).isAbsolute()) {
|
|
154
|
+
path = localDir + File.separator + path;
|
|
155
|
+
} api.searchpath("include", path);
|
|
156
|
+
break;
|
|
157
|
+
}
|
|
158
|
+
case "include":
|
|
159
|
+
String file = p.getNextToken();
|
|
160
|
+
UI.printInfo(Module.API, "Including: \"%s\" ...", file);
|
|
161
|
+
api.include(file);
|
|
162
|
+
break;
|
|
163
|
+
default:
|
|
164
|
+
UI.printWarning(Module.API, "Unrecognized token %s", token);
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
p.close();
|
|
169
|
+
} catch (ParserException e) {
|
|
170
|
+
UI.printError(Module.API, "%s", e.getMessage());
|
|
171
|
+
Logger.getLogger(SCParser.class.getName()).log(Level.SEVERE, null, e);
|
|
172
|
+
return false;
|
|
173
|
+
} catch (FileNotFoundException e) {
|
|
174
|
+
UI.printError(Module.API, "%s", e.getMessage());
|
|
175
|
+
return false;
|
|
176
|
+
} catch (IOException | ColorSpecificationException e) {
|
|
177
|
+
UI.printError(Module.API, "%s", e.getMessage());
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
timer.end();
|
|
181
|
+
UI.printInfo(Module.API, "Done parsing.");
|
|
182
|
+
UI.printInfo(Module.API, "Parsing time: %s", timer.toString());
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private void parseImageBlock(SunflowAPIInterface api) throws IOException, ParserException {
|
|
187
|
+
p.checkNextToken("{");
|
|
188
|
+
if (p.peekNextToken("resolution")) {
|
|
189
|
+
api.parameter("resolutionX", p.getNextInt());
|
|
190
|
+
api.parameter("resolutionY", p.getNextInt());
|
|
191
|
+
}
|
|
192
|
+
if (p.peekNextToken("sampler")) {
|
|
193
|
+
api.parameter("sampler", p.getNextToken());
|
|
194
|
+
}
|
|
195
|
+
if (p.peekNextToken("aa")) {
|
|
196
|
+
api.parameter("aa.min", p.getNextInt());
|
|
197
|
+
api.parameter("aa.max", p.getNextInt());
|
|
198
|
+
}
|
|
199
|
+
if (p.peekNextToken(SAMPLES)) {
|
|
200
|
+
api.parameter("aa.samples", p.getNextInt());
|
|
201
|
+
}
|
|
202
|
+
if (p.peekNextToken("contrast")) {
|
|
203
|
+
api.parameter("aa.contrast", p.getNextFloat());
|
|
204
|
+
}
|
|
205
|
+
if (p.peekNextToken(FILTER)) {
|
|
206
|
+
api.parameter(FILTER, p.getNextToken());
|
|
207
|
+
}
|
|
208
|
+
if (p.peekNextToken("jitter")) {
|
|
209
|
+
api.parameter("aa.jitter", p.getNextBoolean());
|
|
210
|
+
}
|
|
211
|
+
if (p.peekNextToken("show-aa")) {
|
|
212
|
+
UI.printWarning(Module.API, "Deprecated: show-aa ignored");
|
|
213
|
+
p.getNextBoolean();
|
|
214
|
+
}
|
|
215
|
+
if (p.peekNextToken("cache")) {
|
|
216
|
+
api.parameter("aa.cache", p.getNextBoolean());
|
|
217
|
+
}
|
|
218
|
+
if (p.peekNextToken("output")) {
|
|
219
|
+
UI.printWarning(Module.API, "Deprecated: output statement ignored");
|
|
220
|
+
p.getNextToken();
|
|
221
|
+
}
|
|
222
|
+
api.options(SunflowAPI.DEFAULT_OPTIONS);
|
|
223
|
+
p.checkNextToken("}");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
private void parseBackgroundBlock(SunflowAPIInterface api) throws IOException, ParserException, ColorSpecificationException {
|
|
227
|
+
p.checkNextToken("{");
|
|
228
|
+
p.checkNextToken(COLOR);
|
|
229
|
+
api.parameter(COLOR, null, parseColor().getRGB());
|
|
230
|
+
api.shader("background.shader", "constant");
|
|
231
|
+
api.geometry(BACKGROUND, BACKGROUND);
|
|
232
|
+
api.parameter(SHADERS, "background.shader");
|
|
233
|
+
api.instance("background.instance", BACKGROUND);
|
|
234
|
+
p.checkNextToken("}");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private void parseFilter(SunflowAPIInterface api) throws IOException, ParserException {
|
|
238
|
+
UI.printWarning(Module.API, "Deprecated keyword \"filter\" - set this option in the image block");
|
|
239
|
+
String name = p.getNextToken();
|
|
240
|
+
api.parameter(FILTER, name);
|
|
241
|
+
api.options(SunflowAPI.DEFAULT_OPTIONS);
|
|
242
|
+
boolean hasSizeParams = name.equals("box") || name.equals("gaussian") || name.equals("blackman-harris") || name.equals("sinc") || name.equals("triangle");
|
|
243
|
+
if (hasSizeParams) {
|
|
244
|
+
p.getNextFloat();
|
|
245
|
+
p.getNextFloat();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
private void parsePhotonBlock(SunflowAPIInterface api) throws ParserException, IOException {
|
|
250
|
+
int numEmit = 0;
|
|
251
|
+
boolean globalEmit = false;
|
|
252
|
+
p.checkNextToken("{");
|
|
253
|
+
if (p.peekNextToken(EMIT)) {
|
|
254
|
+
UI.printWarning(Module.API, "Shared photon emit values are deprectated - specify number of photons to emit per map");
|
|
255
|
+
numEmit = p.getNextInt();
|
|
256
|
+
globalEmit = true;
|
|
257
|
+
}
|
|
258
|
+
if (p.peekNextToken("global")) {
|
|
259
|
+
UI.printWarning(Module.API, "Global photon map setting belonds inside the gi block - ignoring");
|
|
260
|
+
if (!globalEmit) {
|
|
261
|
+
p.getNextInt();
|
|
262
|
+
}
|
|
263
|
+
p.getNextToken();
|
|
264
|
+
p.getNextInt();
|
|
265
|
+
p.getNextFloat();
|
|
266
|
+
}
|
|
267
|
+
p.checkNextToken("caustics");
|
|
268
|
+
if (!globalEmit) {
|
|
269
|
+
numEmit = p.getNextInt();
|
|
270
|
+
}
|
|
271
|
+
api.parameter("caustics.emit", numEmit);
|
|
272
|
+
api.parameter("caustics", p.getNextToken());
|
|
273
|
+
api.parameter("caustics.gather", p.getNextInt());
|
|
274
|
+
api.parameter("caustics.radius", p.getNextFloat());
|
|
275
|
+
api.options(SunflowAPI.DEFAULT_OPTIONS);
|
|
276
|
+
p.checkNextToken("}");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
private void parseGIBlock(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException {
|
|
280
|
+
p.checkNextToken("{");
|
|
281
|
+
p.checkNextToken(TYPE);
|
|
282
|
+
if (p.peekNextToken("irr-cache")) {
|
|
283
|
+
api.parameter(GI_ENGINE, "irr-cache");
|
|
284
|
+
p.checkNextToken(SAMPLES);
|
|
285
|
+
api.parameter("gi.irr-cache.samples", p.getNextInt());
|
|
286
|
+
p.checkNextToken("tolerance");
|
|
287
|
+
api.parameter("gi.irr-cache.tolerance", p.getNextFloat());
|
|
288
|
+
p.checkNextToken("spacing");
|
|
289
|
+
api.parameter("gi.irr-cache.min_spacing", p.getNextFloat());
|
|
290
|
+
api.parameter("gi.irr-cache.max_spacing", p.getNextFloat());
|
|
291
|
+
// parse global photon map info
|
|
292
|
+
if (p.peekNextToken("global")) {
|
|
293
|
+
api.parameter("gi.irr-cache.gmap.emit", p.getNextInt());
|
|
294
|
+
api.parameter("gi.irr-cache.gmap", p.getNextToken());
|
|
295
|
+
api.parameter("gi.irr-cache.gmap.gather", p.getNextInt());
|
|
296
|
+
api.parameter("gi.irr-cache.gmap.radius", p.getNextFloat());
|
|
297
|
+
}
|
|
298
|
+
} else if (p.peekNextToken("path")) {
|
|
299
|
+
api.parameter(GI_ENGINE, "path");
|
|
300
|
+
p.checkNextToken(SAMPLES);
|
|
301
|
+
api.parameter("gi.path.samples", p.getNextInt());
|
|
302
|
+
if (p.peekNextToken("bounces")) {
|
|
303
|
+
UI.printWarning(Module.API, "Deprecated setting: bounces - use diffuse trace depth instead");
|
|
304
|
+
p.getNextInt();
|
|
305
|
+
}
|
|
306
|
+
} else if (p.peekNextToken("fake")) {
|
|
307
|
+
api.parameter(GI_ENGINE, "fake");
|
|
308
|
+
p.checkNextToken("up");
|
|
309
|
+
api.parameter("gi.fake.up", parseVector());
|
|
310
|
+
p.checkNextToken("sky");
|
|
311
|
+
api.parameter("gi.fake.sky", null, parseColor().getRGB());
|
|
312
|
+
p.checkNextToken("ground");
|
|
313
|
+
api.parameter("gi.fake.ground", null, parseColor().getRGB());
|
|
314
|
+
} else if (p.peekNextToken("igi")) {
|
|
315
|
+
api.parameter(GI_ENGINE, "igi");
|
|
316
|
+
p.checkNextToken(SAMPLES);
|
|
317
|
+
api.parameter("gi.igi.samples", p.getNextInt());
|
|
318
|
+
p.checkNextToken("sets");
|
|
319
|
+
api.parameter("gi.igi.sets", p.getNextInt());
|
|
320
|
+
if (!p.peekNextToken("b")) {
|
|
321
|
+
p.checkNextToken("c");
|
|
322
|
+
}
|
|
323
|
+
api.parameter("gi.igi.c", p.getNextFloat());
|
|
324
|
+
p.checkNextToken("bias-samples");
|
|
325
|
+
api.parameter("gi.igi.bias_samples", p.getNextInt());
|
|
326
|
+
} else if (p.peekNextToken("ambocc")) {
|
|
327
|
+
api.parameter(GI_ENGINE, "ambocc");
|
|
328
|
+
p.checkNextToken("bright");
|
|
329
|
+
api.parameter("gi.ambocc.bright", null, parseColor().getRGB());
|
|
330
|
+
p.checkNextToken("dark");
|
|
331
|
+
api.parameter("gi.ambocc.dark", null, parseColor().getRGB());
|
|
332
|
+
p.checkNextToken(SAMPLES);
|
|
333
|
+
api.parameter("gi.ambocc.samples", p.getNextInt());
|
|
334
|
+
if (p.peekNextToken("maxdist")) {
|
|
335
|
+
api.parameter("gi.ambocc.maxdist", p.getNextFloat());
|
|
336
|
+
}
|
|
337
|
+
} else if (p.peekNextToken(NONE) || p.peekNextToken("null")) {
|
|
338
|
+
// disable GI
|
|
339
|
+
api.parameter(GI_ENGINE, NONE);
|
|
340
|
+
} else {
|
|
341
|
+
UI.printWarning(Module.API, "Unrecognized gi engine type \"%s\" - ignoring", p.getNextToken());
|
|
342
|
+
}
|
|
343
|
+
api.options(SunflowAPI.DEFAULT_OPTIONS);
|
|
344
|
+
p.checkNextToken("}");
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
private void parseLightserverBlock(SunflowAPIInterface api) throws ParserException, IOException {
|
|
348
|
+
p.checkNextToken("{");
|
|
349
|
+
if (p.peekNextToken("shadows")) {
|
|
350
|
+
UI.printWarning(Module.API, "Deprecated: shadows setting ignored");
|
|
351
|
+
p.getNextBoolean();
|
|
352
|
+
}
|
|
353
|
+
if (p.peekNextToken("direct-samples")) {
|
|
354
|
+
UI.printWarning(Module.API, "Deprecated: use samples keyword in area light definitions");
|
|
355
|
+
numLightSamples = p.getNextInt();
|
|
356
|
+
}
|
|
357
|
+
if (p.peekNextToken("glossy-samples")) {
|
|
358
|
+
UI.printWarning(Module.API, "Deprecated: use samples keyword in glossy shader definitions");
|
|
359
|
+
p.getNextInt();
|
|
360
|
+
}
|
|
361
|
+
if (p.peekNextToken("max-depth")) {
|
|
362
|
+
UI.printWarning(Module.API, "Deprecated: max-depth setting - use trace-depths block instead");
|
|
363
|
+
int d = p.getNextInt();
|
|
364
|
+
api.parameter("depths.diffuse", 1);
|
|
365
|
+
api.parameter("depths.reflection", d - 1);
|
|
366
|
+
api.parameter("depths.refraction", 0);
|
|
367
|
+
api.options(SunflowAPI.DEFAULT_OPTIONS);
|
|
368
|
+
}
|
|
369
|
+
if (p.peekNextToken("global")) {
|
|
370
|
+
UI.printWarning(Module.API, "Deprecated: global settings ignored - use photons block instead");
|
|
371
|
+
p.getNextBoolean();
|
|
372
|
+
p.getNextInt();
|
|
373
|
+
p.getNextInt();
|
|
374
|
+
p.getNextInt();
|
|
375
|
+
p.getNextFloat();
|
|
376
|
+
}
|
|
377
|
+
if (p.peekNextToken("caustics")) {
|
|
378
|
+
UI.printWarning(Module.API, "Deprecated: caustics settings ignored - use photons block instead");
|
|
379
|
+
p.getNextBoolean();
|
|
380
|
+
p.getNextInt();
|
|
381
|
+
p.getNextFloat();
|
|
382
|
+
p.getNextInt();
|
|
383
|
+
p.getNextFloat();
|
|
384
|
+
}
|
|
385
|
+
if (p.peekNextToken("irr-cache")) {
|
|
386
|
+
UI.printWarning(Module.API, "Deprecated: irradiance cache settings ignored - use gi block instead");
|
|
387
|
+
p.getNextInt();
|
|
388
|
+
p.getNextFloat();
|
|
389
|
+
p.getNextFloat();
|
|
390
|
+
p.getNextFloat();
|
|
391
|
+
}
|
|
392
|
+
p.checkNextToken("}");
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private void parseTraceBlock(SunflowAPIInterface api) throws ParserException, IOException {
|
|
396
|
+
p.checkNextToken("{");
|
|
397
|
+
if (p.peekNextToken(DIFF)) {
|
|
398
|
+
api.parameter("depths.diffuse", p.getNextInt());
|
|
399
|
+
}
|
|
400
|
+
if (p.peekNextToken(REFL)) {
|
|
401
|
+
api.parameter("depths.reflection", p.getNextInt());
|
|
402
|
+
}
|
|
403
|
+
if (p.peekNextToken("refr")) {
|
|
404
|
+
api.parameter("depths.refraction", p.getNextInt());
|
|
405
|
+
}
|
|
406
|
+
p.checkNextToken("}");
|
|
407
|
+
api.options(SunflowAPI.DEFAULT_OPTIONS);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
private void parseCamera(SunflowAPIInterface api) throws ParserException, IOException {
|
|
411
|
+
p.checkNextToken("{");
|
|
412
|
+
p.checkNextToken(TYPE);
|
|
413
|
+
String type = p.getNextToken();
|
|
414
|
+
UI.printInfo(Module.API, "Reading %s camera ...", type);
|
|
415
|
+
if (p.peekNextToken("shutter")) {
|
|
416
|
+
api.parameter("shutter.open", p.getNextFloat());
|
|
417
|
+
api.parameter("shutter.close", p.getNextFloat());
|
|
418
|
+
}
|
|
419
|
+
parseCameraTransform(api);
|
|
420
|
+
String name = generateUniqueName("camera");
|
|
421
|
+
switch (type) {
|
|
422
|
+
case "pinhole":
|
|
423
|
+
p.checkNextToken(FOV);
|
|
424
|
+
api.parameter(FOV, p.getNextFloat());
|
|
425
|
+
p.checkNextToken(ASPECT);
|
|
426
|
+
api.parameter(ASPECT, p.getNextFloat());
|
|
427
|
+
if (p.peekNextToken("shift")) {
|
|
428
|
+
api.parameter("shift.x", p.getNextFloat());
|
|
429
|
+
api.parameter("shift.y", p.getNextFloat());
|
|
430
|
+
} api.camera(name, "pinhole");
|
|
431
|
+
break;
|
|
432
|
+
case "thinlens":
|
|
433
|
+
p.checkNextToken(FOV);
|
|
434
|
+
api.parameter(FOV, p.getNextFloat());
|
|
435
|
+
p.checkNextToken(ASPECT);
|
|
436
|
+
api.parameter(ASPECT, p.getNextFloat());
|
|
437
|
+
if (p.peekNextToken("shift")) {
|
|
438
|
+
api.parameter("shift.x", p.getNextFloat());
|
|
439
|
+
api.parameter("shift.y", p.getNextFloat());
|
|
440
|
+
} p.checkNextToken("fdist");
|
|
441
|
+
api.parameter("focus.distance", p.getNextFloat());
|
|
442
|
+
p.checkNextToken("lensr");
|
|
443
|
+
api.parameter("lens.radius", p.getNextFloat());
|
|
444
|
+
if (p.peekNextToken("sides")) {
|
|
445
|
+
api.parameter("lens.sides", p.getNextInt());
|
|
446
|
+
} if (p.peekNextToken("rotation")) {
|
|
447
|
+
api.parameter("lens.rotation", p.getNextFloat());
|
|
448
|
+
} api.camera(name, "thinlens");
|
|
449
|
+
break;
|
|
450
|
+
case "spherical":
|
|
451
|
+
// no extra arguments
|
|
452
|
+
api.camera(name, "spherical");
|
|
453
|
+
break;
|
|
454
|
+
case "fisheye":
|
|
455
|
+
// no extra arguments
|
|
456
|
+
api.camera(name, "fisheye");
|
|
457
|
+
break;
|
|
458
|
+
default:
|
|
459
|
+
UI.printWarning(Module.API, "Unrecognized camera type: %s", p.getNextToken());
|
|
460
|
+
p.checkNextToken("}");
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
p.checkNextToken("}");
|
|
464
|
+
if (name != null) {
|
|
465
|
+
api.parameter("camera", name);
|
|
466
|
+
api.options(SunflowAPI.DEFAULT_OPTIONS);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
private void parseCameraTransform(SunflowAPIInterface api) throws ParserException, IOException {
|
|
471
|
+
if (p.peekNextToken("steps")) {
|
|
472
|
+
// motion blur camera
|
|
473
|
+
int n = p.getNextInt();
|
|
474
|
+
api.parameter("transform.steps", n);
|
|
475
|
+
// parse time extents
|
|
476
|
+
p.checkNextToken("times");
|
|
477
|
+
float t0 = p.getNextFloat();
|
|
478
|
+
float t1 = p.getNextFloat();
|
|
479
|
+
api.parameter("transform.times", "float", NONE, new float[]{t0,
|
|
480
|
+
t1});
|
|
481
|
+
for (int i = 0; i < n; i++) {
|
|
482
|
+
parseCameraMatrix(i, api);
|
|
483
|
+
}
|
|
484
|
+
} else {
|
|
485
|
+
parseCameraMatrix(-1, api);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
private void parseCameraMatrix(int index, SunflowAPIInterface api) throws IOException, ParserException {
|
|
490
|
+
String offset = index < 0 ? "" : String.format("[%d]", index);
|
|
491
|
+
if (p.peekNextToken(TRANSFORM)) {
|
|
492
|
+
// advanced camera
|
|
493
|
+
api.parameter(String.format("transform%s", offset), parseMatrix());
|
|
494
|
+
} else {
|
|
495
|
+
if (index >= 0) {
|
|
496
|
+
p.checkNextToken("{");
|
|
497
|
+
}
|
|
498
|
+
// regular camera specification
|
|
499
|
+
p.checkNextToken("eye");
|
|
500
|
+
Point3 eye = parsePoint();
|
|
501
|
+
p.checkNextToken("target");
|
|
502
|
+
Point3 target = parsePoint();
|
|
503
|
+
p.checkNextToken("up");
|
|
504
|
+
Vector3 up = parseVector();
|
|
505
|
+
api.parameter(String.format("transform%s", offset), Matrix4.lookAt(eye, target, up));
|
|
506
|
+
if (index >= 0) {
|
|
507
|
+
p.checkNextToken("}");
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
private boolean parseShader(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException {
|
|
513
|
+
p.checkNextToken("{");
|
|
514
|
+
p.checkNextToken(NAME);
|
|
515
|
+
String name = p.getNextToken();
|
|
516
|
+
UI.printInfo(Module.API, "Reading shader: %s ...", name);
|
|
517
|
+
p.checkNextToken(TYPE);
|
|
518
|
+
if (p.peekNextToken(DIFFUSE)) {
|
|
519
|
+
if (p.peekNextToken(DIFF)) {
|
|
520
|
+
api.parameter(DIFFUSE, null, parseColor().getRGB());
|
|
521
|
+
api.shader(name, DIFFUSE);
|
|
522
|
+
} else if (p.peekNextToken(TEXTURE)) {
|
|
523
|
+
api.parameter(TEXTURE, p.getNextToken());
|
|
524
|
+
api.shader(name, "textured_diffuse");
|
|
525
|
+
} else {
|
|
526
|
+
UI.printWarning(Module.API, "Unrecognized option in diffuse shader block: %s", p.getNextToken());
|
|
527
|
+
}
|
|
528
|
+
} else if (p.peekNextToken("phong")) {
|
|
529
|
+
String tex = null;
|
|
530
|
+
if (p.peekNextToken(TEXTURE)) {
|
|
531
|
+
api.parameter(TEXTURE, tex = p.getNextToken());
|
|
532
|
+
} else {
|
|
533
|
+
p.checkNextToken(DIFF);
|
|
534
|
+
api.parameter(DIFFUSE, null, parseColor().getRGB());
|
|
535
|
+
}
|
|
536
|
+
p.checkNextToken("spec");
|
|
537
|
+
api.parameter("specular", null, parseColor().getRGB());
|
|
538
|
+
api.parameter(POWER, p.getNextFloat());
|
|
539
|
+
if (p.peekNextToken(SAMPLES)) {
|
|
540
|
+
api.parameter(SAMPLES, p.getNextInt());
|
|
541
|
+
}
|
|
542
|
+
if (tex != null) {
|
|
543
|
+
api.shader(name, "textured_phong");
|
|
544
|
+
} else {
|
|
545
|
+
api.shader(name, "phong");
|
|
546
|
+
}
|
|
547
|
+
} else if (p.peekNextToken("amb-occ") || p.peekNextToken("amb-occ2")) {
|
|
548
|
+
String tex = null;
|
|
549
|
+
if (p.peekNextToken(DIFF) || p.peekNextToken("bright")) {
|
|
550
|
+
api.parameter("bright", null, parseColor().getRGB());
|
|
551
|
+
} else if (p.peekNextToken(TEXTURE)) {
|
|
552
|
+
api.parameter(TEXTURE, tex = p.getNextToken());
|
|
553
|
+
}
|
|
554
|
+
if (p.peekNextToken("dark")) {
|
|
555
|
+
api.parameter("dark", null, parseColor().getRGB());
|
|
556
|
+
p.checkNextToken(SAMPLES);
|
|
557
|
+
api.parameter(SAMPLES, p.getNextInt());
|
|
558
|
+
p.checkNextToken("dist");
|
|
559
|
+
api.parameter("maxdist", p.getNextFloat());
|
|
560
|
+
}
|
|
561
|
+
if (tex == null) {
|
|
562
|
+
api.shader(name, "ambient_occlusion");
|
|
563
|
+
} else {
|
|
564
|
+
api.shader(name, "textured_ambient_occlusion");
|
|
565
|
+
}
|
|
566
|
+
} else if (p.peekNextToken("mirror")) {
|
|
567
|
+
p.checkNextToken(REFL);
|
|
568
|
+
api.parameter(COLOR, null, parseColor().getRGB());
|
|
569
|
+
api.shader(name, "mirror");
|
|
570
|
+
} else if (p.peekNextToken("glass")) {
|
|
571
|
+
p.checkNextToken("eta");
|
|
572
|
+
api.parameter("eta", p.getNextFloat());
|
|
573
|
+
p.checkNextToken(COLOR);
|
|
574
|
+
api.parameter(COLOR, null, parseColor().getRGB());
|
|
575
|
+
if (p.peekNextToken("absorption.distance") || p.peekNextToken("absorbtion.distance")) {
|
|
576
|
+
api.parameter("absorption.distance", p.getNextFloat());
|
|
577
|
+
}
|
|
578
|
+
if (p.peekNextToken("absorption.color") || p.peekNextToken("absorbtion.color")) {
|
|
579
|
+
api.parameter("absorption.color", null, parseColor().getRGB());
|
|
580
|
+
}
|
|
581
|
+
api.shader(name, "glass");
|
|
582
|
+
} else if (p.peekNextToken("shiny")) {
|
|
583
|
+
String tex = null;
|
|
584
|
+
if (p.peekNextToken(TEXTURE)) {
|
|
585
|
+
api.parameter(TEXTURE, tex = p.getNextToken());
|
|
586
|
+
} else {
|
|
587
|
+
p.checkNextToken(DIFF);
|
|
588
|
+
api.parameter(DIFFUSE, null, parseColor().getRGB());
|
|
589
|
+
}
|
|
590
|
+
p.checkNextToken(REFL);
|
|
591
|
+
api.parameter("shiny", p.getNextFloat());
|
|
592
|
+
if (tex == null) {
|
|
593
|
+
api.shader(name, "shiny_diffuse");
|
|
594
|
+
} else {
|
|
595
|
+
api.shader(name, "textured_shiny_diffuse");
|
|
596
|
+
}
|
|
597
|
+
} else if (p.peekNextToken("ward")) {
|
|
598
|
+
String tex = null;
|
|
599
|
+
if (p.peekNextToken(TEXTURE)) {
|
|
600
|
+
api.parameter(TEXTURE, tex = p.getNextToken());
|
|
601
|
+
} else {
|
|
602
|
+
p.checkNextToken(DIFF);
|
|
603
|
+
api.parameter(DIFFUSE, null, parseColor().getRGB());
|
|
604
|
+
}
|
|
605
|
+
p.checkNextToken("spec");
|
|
606
|
+
api.parameter("specular", null, parseColor().getRGB());
|
|
607
|
+
p.checkNextToken("rough");
|
|
608
|
+
api.parameter("roughnessX", p.getNextFloat());
|
|
609
|
+
api.parameter("roughnessY", p.getNextFloat());
|
|
610
|
+
if (p.peekNextToken(SAMPLES)) {
|
|
611
|
+
api.parameter(SAMPLES, p.getNextInt());
|
|
612
|
+
}
|
|
613
|
+
if (tex != null) {
|
|
614
|
+
api.shader(name, "textured_ward");
|
|
615
|
+
} else {
|
|
616
|
+
api.shader(name, "ward");
|
|
617
|
+
}
|
|
618
|
+
} else if (p.peekNextToken("view-caustics")) {
|
|
619
|
+
api.shader(name, "view_caustics");
|
|
620
|
+
} else if (p.peekNextToken("view-irradiance")) {
|
|
621
|
+
api.shader(name, "view_irradiance");
|
|
622
|
+
} else if (p.peekNextToken("view-global")) {
|
|
623
|
+
api.shader(name, "view_global");
|
|
624
|
+
} else if (p.peekNextToken("constant")) {
|
|
625
|
+
// backwards compatibility -- peek only
|
|
626
|
+
p.peekNextToken(COLOR);
|
|
627
|
+
api.parameter(COLOR, null, parseColor().getRGB());
|
|
628
|
+
api.shader(name, "constant");
|
|
629
|
+
} else if (p.peekNextToken("janino")) {
|
|
630
|
+
String typename = p.peekNextToken("typename") ? p.getNextToken() : PluginRegistry.SHADER_PLUGINS.generateUniqueName("janino_shader");
|
|
631
|
+
if (!PluginRegistry.SHADER_PLUGINS.registerPlugin(typename, p.getNextCodeBlock())) {
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
api.shader(name, typename);
|
|
635
|
+
} else if (p.peekNextToken("id")) {
|
|
636
|
+
api.shader(name, "show_instance_id");
|
|
637
|
+
} else if (p.peekNextToken("uber")) {
|
|
638
|
+
if (p.peekNextToken(DIFF)) {
|
|
639
|
+
api.parameter(DIFFUSE, null, parseColor().getRGB());
|
|
640
|
+
}
|
|
641
|
+
if (p.peekNextToken("diff.texture")) {
|
|
642
|
+
api.parameter("diffuse.texture", p.getNextToken());
|
|
643
|
+
}
|
|
644
|
+
if (p.peekNextToken("diff.blend")) {
|
|
645
|
+
api.parameter("diffuse.blend", p.getNextFloat());
|
|
646
|
+
}
|
|
647
|
+
if (p.peekNextToken(REFL) || p.peekNextToken("spec")) {
|
|
648
|
+
api.parameter("specular", null, parseColor().getRGB());
|
|
649
|
+
}
|
|
650
|
+
if (p.peekNextToken(TEXTURE)) {
|
|
651
|
+
// deprecated
|
|
652
|
+
UI.printWarning(Module.API, "Deprecated uber shader parameter \"texture\" - please use \"diffuse.texture\" and \"diffuse.blend\" instead");
|
|
653
|
+
api.parameter("diffuse.texture", p.getNextToken());
|
|
654
|
+
api.parameter("diffuse.blend", p.getNextFloat());
|
|
655
|
+
}
|
|
656
|
+
if (p.peekNextToken("spec.texture")) {
|
|
657
|
+
api.parameter("specular.texture", p.getNextToken());
|
|
658
|
+
}
|
|
659
|
+
if (p.peekNextToken("spec.blend")) {
|
|
660
|
+
api.parameter("specular.blend", p.getNextFloat());
|
|
661
|
+
}
|
|
662
|
+
if (p.peekNextToken("glossy")) {
|
|
663
|
+
api.parameter("glossyness", p.getNextFloat());
|
|
664
|
+
}
|
|
665
|
+
if (p.peekNextToken(SAMPLES)) {
|
|
666
|
+
api.parameter(SAMPLES, p.getNextInt());
|
|
667
|
+
}
|
|
668
|
+
api.shader(name, "uber");
|
|
669
|
+
} else {
|
|
670
|
+
UI.printWarning(Module.API, "Unrecognized shader type: %s", p.getNextToken());
|
|
671
|
+
}
|
|
672
|
+
p.checkNextToken("}");
|
|
673
|
+
return true;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
private boolean parseModifier(SunflowAPIInterface api) throws ParserException, IOException {
|
|
677
|
+
p.checkNextToken("{");
|
|
678
|
+
p.checkNextToken(NAME);
|
|
679
|
+
String name = p.getNextToken();
|
|
680
|
+
UI.printInfo(Module.API, "Reading modifier: %s ...", name);
|
|
681
|
+
p.checkNextToken(TYPE);
|
|
682
|
+
if (p.peekNextToken("bump")) {
|
|
683
|
+
p.checkNextToken(TEXTURE);
|
|
684
|
+
api.parameter(TEXTURE, p.getNextToken());
|
|
685
|
+
p.checkNextToken(SCALE);
|
|
686
|
+
api.parameter(SCALE, p.getNextFloat());
|
|
687
|
+
api.modifier(name, "bump_map");
|
|
688
|
+
} else if (p.peekNextToken("normalmap")) {
|
|
689
|
+
p.checkNextToken(TEXTURE);
|
|
690
|
+
api.parameter(TEXTURE, p.getNextToken());
|
|
691
|
+
api.modifier(name, "normal_map");
|
|
692
|
+
} else if (p.peekNextToken("perlin")) {
|
|
693
|
+
p.checkNextToken("function");
|
|
694
|
+
api.parameter("function", p.getNextInt());
|
|
695
|
+
p.checkNextToken("size");
|
|
696
|
+
api.parameter("size", p.getNextFloat());
|
|
697
|
+
p.checkNextToken(SCALE);
|
|
698
|
+
api.parameter(SCALE, p.getNextFloat());
|
|
699
|
+
api.modifier(name, "perlin");
|
|
700
|
+
} else {
|
|
701
|
+
UI.printWarning(Module.API, "Unrecognized modifier type: %s", p.getNextToken());
|
|
702
|
+
}
|
|
703
|
+
p.checkNextToken("}");
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
private void parseObjectBlock(SunflowAPIInterface api) throws ParserException, IOException {
|
|
708
|
+
p.checkNextToken("{");
|
|
709
|
+
boolean noInstance = false;
|
|
710
|
+
Matrix4[] transform = null;
|
|
711
|
+
float transformTime0 = 0, transformTime1 = 0;
|
|
712
|
+
String name = null;
|
|
713
|
+
String[] shaders = null;
|
|
714
|
+
String[] modifiers = null;
|
|
715
|
+
if (p.peekNextToken("noinstance")) {
|
|
716
|
+
// this indicates that the geometry is to be created, but not
|
|
717
|
+
// instanced into the scene
|
|
718
|
+
noInstance = true;
|
|
719
|
+
} else {
|
|
720
|
+
// these are the parameters to be passed to the instance
|
|
721
|
+
if (p.peekNextToken(SHADERS)) {
|
|
722
|
+
int n = p.getNextInt();
|
|
723
|
+
shaders = new String[n];
|
|
724
|
+
for (int i = 0; i < n; i++) {
|
|
725
|
+
shaders[i] = p.getNextToken();
|
|
726
|
+
}
|
|
727
|
+
} else {
|
|
728
|
+
p.checkNextToken(SHADER);
|
|
729
|
+
shaders = new String[]{p.getNextToken()};
|
|
730
|
+
}
|
|
731
|
+
if (p.peekNextToken(MODIFIERS)) {
|
|
732
|
+
int n = p.getNextInt();
|
|
733
|
+
modifiers = new String[n];
|
|
734
|
+
for (int i = 0; i < n; i++) {
|
|
735
|
+
modifiers[i] = p.getNextToken();
|
|
736
|
+
}
|
|
737
|
+
} else if (p.peekNextToken(MODIFIER)) {
|
|
738
|
+
modifiers = new String[]{p.getNextToken()};
|
|
739
|
+
}
|
|
740
|
+
if (p.peekNextToken(TRANSFORM)) {
|
|
741
|
+
if (p.peekNextToken("steps")) {
|
|
742
|
+
transform = new Matrix4[p.getNextInt()];
|
|
743
|
+
p.checkNextToken("times");
|
|
744
|
+
transformTime0 = p.getNextFloat();
|
|
745
|
+
transformTime1 = p.getNextFloat();
|
|
746
|
+
for (int i = 0; i < transform.length; i++) {
|
|
747
|
+
transform[i] = parseMatrix();
|
|
748
|
+
}
|
|
749
|
+
} else {
|
|
750
|
+
transform = new Matrix4[]{parseMatrix()};
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
if (p.peekNextToken("accel")) {
|
|
755
|
+
api.parameter("accel", p.getNextToken());
|
|
756
|
+
}
|
|
757
|
+
p.checkNextToken(TYPE);
|
|
758
|
+
String type = p.getNextToken();
|
|
759
|
+
if (p.peekNextToken(NAME)) {
|
|
760
|
+
name = p.getNextToken();
|
|
761
|
+
} else {
|
|
762
|
+
name = generateUniqueName(type);
|
|
763
|
+
}
|
|
764
|
+
switch (type) {
|
|
765
|
+
case "mesh":
|
|
766
|
+
{
|
|
767
|
+
UI.printWarning(Module.API, "Deprecated object type: mesh");
|
|
768
|
+
UI.printInfo(Module.API, "Reading mesh: %s ...", name);
|
|
769
|
+
int numVertices = p.getNextInt();
|
|
770
|
+
int numTriangles = p.getNextInt();
|
|
771
|
+
float[] points = new float[numVertices * 3];
|
|
772
|
+
float[] normals = new float[numVertices * 3];
|
|
773
|
+
float[] uvs = new float[numVertices * 2];
|
|
774
|
+
for (int i = 0; i < numVertices; i++) {
|
|
775
|
+
p.checkNextToken("v");
|
|
776
|
+
points[3 * i + 0] = p.getNextFloat();
|
|
777
|
+
points[3 * i + 1] = p.getNextFloat();
|
|
778
|
+
points[3 * i + 2] = p.getNextFloat();
|
|
779
|
+
normals[3 * i + 0] = p.getNextFloat();
|
|
780
|
+
normals[3 * i + 1] = p.getNextFloat();
|
|
781
|
+
normals[3 * i + 2] = p.getNextFloat();
|
|
782
|
+
uvs[2 * i + 0] = p.getNextFloat();
|
|
783
|
+
uvs[2 * i + 1] = p.getNextFloat();
|
|
784
|
+
} int[] triangles = new int[numTriangles * 3];
|
|
785
|
+
for (int i = 0; i < numTriangles; i++) {
|
|
786
|
+
p.checkNextToken("t");
|
|
787
|
+
triangles[i * 3 + 0] = p.getNextInt();
|
|
788
|
+
triangles[i * 3 + 1] = p.getNextInt();
|
|
789
|
+
triangles[i * 3 + 2] = p.getNextInt();
|
|
790
|
+
} // create geometry
|
|
791
|
+
api.parameter(TRIANGLES, triangles);
|
|
792
|
+
api.parameter(POINTS, POINT, VERTEX, points);
|
|
793
|
+
api.parameter(NORMALS, "vector", VERTEX, normals);
|
|
794
|
+
api.parameter(UVS, TEXCOORD, VERTEX, uvs);
|
|
795
|
+
api.geometry(name, TRIANGLE_MESH);
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
case "flat-mesh":
|
|
799
|
+
{
|
|
800
|
+
UI.printWarning(Module.API, "Deprecated object type: flat-mesh");
|
|
801
|
+
UI.printInfo(Module.API, "Reading flat mesh: %s ...", name);
|
|
802
|
+
int numVertices = p.getNextInt();
|
|
803
|
+
int numTriangles = p.getNextInt();
|
|
804
|
+
float[] points = new float[numVertices * 3];
|
|
805
|
+
float[] uvs = new float[numVertices * 2];
|
|
806
|
+
for (int i = 0; i < numVertices; i++) {
|
|
807
|
+
p.checkNextToken("v");
|
|
808
|
+
points[3 * i + 0] = p.getNextFloat();
|
|
809
|
+
points[3 * i + 1] = p.getNextFloat();
|
|
810
|
+
points[3 * i + 2] = p.getNextFloat();
|
|
811
|
+
p.getNextFloat();
|
|
812
|
+
p.getNextFloat();
|
|
813
|
+
p.getNextFloat();
|
|
814
|
+
uvs[2 * i + 0] = p.getNextFloat();
|
|
815
|
+
uvs[2 * i + 1] = p.getNextFloat();
|
|
816
|
+
} int[] triangles = new int[numTriangles * 3];
|
|
817
|
+
for (int i = 0; i < numTriangles; i++) {
|
|
818
|
+
p.checkNextToken("t");
|
|
819
|
+
triangles[i * 3 + 0] = p.getNextInt();
|
|
820
|
+
triangles[i * 3 + 1] = p.getNextInt();
|
|
821
|
+
triangles[i * 3 + 2] = p.getNextInt();
|
|
822
|
+
} // create geometry
|
|
823
|
+
api.parameter(TRIANGLES, triangles);
|
|
824
|
+
api.parameter(POINTS, POINT, VERTEX, points);
|
|
825
|
+
api.parameter(UVS, TEXCOORD, VERTEX, uvs);
|
|
826
|
+
api.geometry(name, TRIANGLE_MESH);
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
case "sphere":
|
|
830
|
+
UI.printInfo(Module.API, "Reading sphere ...");
|
|
831
|
+
api.geometry(name, "sphere");
|
|
832
|
+
if (transform == null && !noInstance) {
|
|
833
|
+
// legacy method of specifying transformation for spheres
|
|
834
|
+
p.checkNextToken("c");
|
|
835
|
+
float x = p.getNextFloat();
|
|
836
|
+
float y = p.getNextFloat();
|
|
837
|
+
float z = p.getNextFloat();
|
|
838
|
+
p.checkNextToken("r");
|
|
839
|
+
float radius = p.getNextFloat();
|
|
840
|
+
api.parameter(TRANSFORM, Matrix4.translation(x, y, z).multiply(Matrix4.scale(radius)));
|
|
841
|
+
api.parameter(SHADERS, shaders);
|
|
842
|
+
if (modifiers != null) {
|
|
843
|
+
api.parameter(MODIFIERS, modifiers);
|
|
844
|
+
}
|
|
845
|
+
api.instance(name + ".instance", name);
|
|
846
|
+
// disable future instancing - instance has already been created
|
|
847
|
+
noInstance = true;
|
|
848
|
+
} break;
|
|
849
|
+
case "cylinder":
|
|
850
|
+
UI.printInfo(Module.API, "Reading cylinder ...");
|
|
851
|
+
api.geometry(name, "cylinder");
|
|
852
|
+
break;
|
|
853
|
+
case "banchoff":
|
|
854
|
+
UI.printInfo(Module.API, "Reading banchoff ...");
|
|
855
|
+
api.geometry(name, "banchoff");
|
|
856
|
+
break;
|
|
857
|
+
case "torus":
|
|
858
|
+
UI.printInfo(Module.API, "Reading torus ...");
|
|
859
|
+
p.checkNextToken("r");
|
|
860
|
+
api.parameter("radiusInner", p.getNextFloat());
|
|
861
|
+
api.parameter("radiusOuter", p.getNextFloat());
|
|
862
|
+
api.geometry(name, "torus");
|
|
863
|
+
break;
|
|
864
|
+
case "sphereflake":
|
|
865
|
+
UI.printInfo(Module.API, "Reading sphereflake ...");
|
|
866
|
+
if (p.peekNextToken("level")) {
|
|
867
|
+
api.parameter("level", p.getNextInt());
|
|
868
|
+
} if (p.peekNextToken("axis")) {
|
|
869
|
+
api.parameter("axis", parseVector());
|
|
870
|
+
} if (p.peekNextToken(RADIUS)) {
|
|
871
|
+
api.parameter(RADIUS, p.getNextFloat());
|
|
872
|
+
} api.geometry(name, "sphereflake");
|
|
873
|
+
break;
|
|
874
|
+
case "plane":
|
|
875
|
+
UI.printInfo(Module.API, "Reading plane ...");
|
|
876
|
+
p.checkNextToken("p");
|
|
877
|
+
api.parameter(CENTER, parsePoint());
|
|
878
|
+
if (p.peekNextToken("n")) {
|
|
879
|
+
api.parameter("normal", parseVector());
|
|
880
|
+
} else {
|
|
881
|
+
p.checkNextToken("p");
|
|
882
|
+
api.parameter("point1", parsePoint());
|
|
883
|
+
p.checkNextToken("p");
|
|
884
|
+
api.parameter("point2", parsePoint());
|
|
885
|
+
} api.geometry(name, "plane");
|
|
886
|
+
break;
|
|
887
|
+
case "generic-mesh":
|
|
888
|
+
UI.printInfo(Module.API, "Reading generic mesh: %s ... ", name);
|
|
889
|
+
// parse vertices
|
|
890
|
+
p.checkNextToken(POINTS);
|
|
891
|
+
int np = p.getNextInt();
|
|
892
|
+
api.parameter(POINTS, POINT, VERTEX, parseFloatArray(np * 3));
|
|
893
|
+
// parse triangle indices
|
|
894
|
+
p.checkNextToken(TRIANGLES);
|
|
895
|
+
int nt = p.getNextInt();
|
|
896
|
+
api.parameter(TRIANGLES, parseIntArray(nt * 3));
|
|
897
|
+
// parse normals
|
|
898
|
+
p.checkNextToken(NORMALS);
|
|
899
|
+
if (p.peekNextToken(VERTEX)) {
|
|
900
|
+
api.parameter(NORMALS, "vector", VERTEX, parseFloatArray(np * 3));
|
|
901
|
+
} else if (p.peekNextToken(FACEVARYING)) {
|
|
902
|
+
api.parameter(NORMALS, "vector", FACEVARYING, parseFloatArray(nt * 9));
|
|
903
|
+
} else {
|
|
904
|
+
p.checkNextToken(NONE);
|
|
905
|
+
} // parse texture coordinates
|
|
906
|
+
p.checkNextToken(UVS);
|
|
907
|
+
if (p.peekNextToken(VERTEX)) {
|
|
908
|
+
api.parameter(UVS, TEXCOORD, VERTEX, parseFloatArray(np * 2));
|
|
909
|
+
} else if (p.peekNextToken(FACEVARYING)) {
|
|
910
|
+
api.parameter(UVS, TEXCOORD, FACEVARYING, parseFloatArray(nt * 6));
|
|
911
|
+
} else {
|
|
912
|
+
p.checkNextToken(NONE);
|
|
913
|
+
} if (p.peekNextToken("face_shaders")) {
|
|
914
|
+
api.parameter("faceshaders", parseIntArray(nt));
|
|
915
|
+
} api.geometry(name, TRIANGLE_MESH);
|
|
916
|
+
break;
|
|
917
|
+
case "hair":
|
|
918
|
+
UI.printInfo(Module.API, "Reading hair curves: %s ... ", name);
|
|
919
|
+
p.checkNextToken("segments");
|
|
920
|
+
api.parameter("segments", p.getNextInt());
|
|
921
|
+
p.checkNextToken("width");
|
|
922
|
+
api.parameter("widths", p.getNextFloat());
|
|
923
|
+
p.checkNextToken(POINTS);
|
|
924
|
+
api.parameter(POINTS, POINT, VERTEX, parseFloatArray(p.getNextInt()));
|
|
925
|
+
api.geometry(name, "hair");
|
|
926
|
+
break;
|
|
927
|
+
case "janino-tesselatable":
|
|
928
|
+
UI.printInfo(Module.API, "Reading procedural primitive: %s ... ", name);
|
|
929
|
+
String typename = p.peekNextToken("typename") ? p.getNextToken() : PluginRegistry.SHADER_PLUGINS.generateUniqueName("janino_shader");
|
|
930
|
+
if (!PluginRegistry.TESSELATABLE_PLUGINS.registerPlugin(typename, p.getNextCodeBlock())) {
|
|
931
|
+
noInstance = true;
|
|
932
|
+
} else {
|
|
933
|
+
api.geometry(name, typename);
|
|
934
|
+
} break;
|
|
935
|
+
case "teapot":
|
|
936
|
+
UI.printInfo(Module.API, "Reading teapot: %s ... ", name);
|
|
937
|
+
if (p.peekNextToken(SUBDIVS)) {
|
|
938
|
+
api.parameter(SUBDIVS, p.getNextInt());
|
|
939
|
+
} if (p.peekNextToken(SMOOTH)) {
|
|
940
|
+
api.parameter(SMOOTH, p.getNextBoolean());
|
|
941
|
+
} api.geometry(name, "teapot");
|
|
942
|
+
break;
|
|
943
|
+
case "gumbo":
|
|
944
|
+
UI.printInfo(Module.API, "Reading gumbo: %s ... ", name);
|
|
945
|
+
if (p.peekNextToken(SUBDIVS)) {
|
|
946
|
+
api.parameter(SUBDIVS, p.getNextInt());
|
|
947
|
+
} if (p.peekNextToken(SMOOTH)) {
|
|
948
|
+
api.parameter(SMOOTH, p.getNextBoolean());
|
|
949
|
+
} api.geometry(name, "gumbo");
|
|
950
|
+
break;
|
|
951
|
+
case "julia":
|
|
952
|
+
UI.printInfo(Module.API, "Reading julia fractal: %s ... ", name);
|
|
953
|
+
if (p.peekNextToken("q")) {
|
|
954
|
+
api.parameter("cw", p.getNextFloat());
|
|
955
|
+
api.parameter("cx", p.getNextFloat());
|
|
956
|
+
api.parameter("cy", p.getNextFloat());
|
|
957
|
+
api.parameter("cz", p.getNextFloat());
|
|
958
|
+
} if (p.peekNextToken("iterations")) {
|
|
959
|
+
api.parameter("iterations", p.getNextInt());
|
|
960
|
+
} if (p.peekNextToken("epsilon")) {
|
|
961
|
+
api.parameter("epsilon", p.getNextFloat());
|
|
962
|
+
} api.geometry(name, "julia");
|
|
963
|
+
break;
|
|
964
|
+
case "particles":
|
|
965
|
+
case "dlasurface":
|
|
966
|
+
if (type.equals("dlasurface")) {
|
|
967
|
+
UI.printWarning(Module.API, "Deprecated object type: \"dlasurface\" - please use \"particles\" instead");
|
|
968
|
+
} float[] data;
|
|
969
|
+
if (p.peekNextToken("filename")) {
|
|
970
|
+
// FIXME: this code should be moved into an on demand loading
|
|
971
|
+
// primitive
|
|
972
|
+
String filename = p.getNextToken();
|
|
973
|
+
boolean littleEndian = false;
|
|
974
|
+
if (p.peekNextToken("little_endian")) {
|
|
975
|
+
littleEndian = true;
|
|
976
|
+
}
|
|
977
|
+
UI.printInfo(Module.USER, "Loading particle file: %s", filename);
|
|
978
|
+
File file = new File(filename);
|
|
979
|
+
try (FileInputStream stream = new FileInputStream(filename)) {
|
|
980
|
+
MappedByteBuffer map = stream.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
|
|
981
|
+
if (littleEndian) {
|
|
982
|
+
map.order(ByteOrder.LITTLE_ENDIAN);
|
|
983
|
+
}
|
|
984
|
+
FloatBuffer buffer = map.asFloatBuffer();
|
|
985
|
+
data = new float[buffer.capacity()];
|
|
986
|
+
for (int i = 0; i < data.length; i++) {
|
|
987
|
+
data[i] = buffer.get(i);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
} else {
|
|
991
|
+
p.checkNextToken(POINTS);
|
|
992
|
+
int n = p.getNextInt();
|
|
993
|
+
data = parseFloatArray(n * 3); // read 3n points
|
|
994
|
+
} api.parameter("particles", POINT, VERTEX, data);
|
|
995
|
+
if (p.peekNextToken("num")) {
|
|
996
|
+
api.parameter("num", p.getNextInt());
|
|
997
|
+
} else {
|
|
998
|
+
api.parameter("num", data.length / 3);
|
|
999
|
+
} p.checkNextToken(RADIUS);
|
|
1000
|
+
api.parameter(RADIUS, p.getNextFloat());
|
|
1001
|
+
api.geometry(name, "particles");
|
|
1002
|
+
break;
|
|
1003
|
+
case "file-mesh":
|
|
1004
|
+
UI.printInfo(Module.API, "Reading file mesh: %s ... ", name);
|
|
1005
|
+
p.checkNextToken("filename");
|
|
1006
|
+
api.parameter("filename", p.getNextToken());
|
|
1007
|
+
if (p.peekNextToken("smooth_normals")) {
|
|
1008
|
+
api.parameter("smooth_normals", p.getNextBoolean());
|
|
1009
|
+
} api.geometry(name, "file_mesh");
|
|
1010
|
+
break;
|
|
1011
|
+
case "bezier-mesh":
|
|
1012
|
+
{
|
|
1013
|
+
UI.printInfo(Module.API, "Reading bezier mesh: %s ... ", name);
|
|
1014
|
+
p.checkNextToken("n");
|
|
1015
|
+
int nu, nv;
|
|
1016
|
+
api.parameter("nu", nu = p.getNextInt());
|
|
1017
|
+
api.parameter("nv", nv = p.getNextInt());
|
|
1018
|
+
if (p.peekNextToken("wrap")) {
|
|
1019
|
+
api.parameter("uwrap", p.getNextBoolean());
|
|
1020
|
+
api.parameter("vwrap", p.getNextBoolean());
|
|
1021
|
+
} p.checkNextToken(POINTS);
|
|
1022
|
+
float[] points = new float[3 * nu * nv];
|
|
1023
|
+
for (int i = 0; i < points.length; i++) {
|
|
1024
|
+
points[i] = p.getNextFloat();
|
|
1025
|
+
} api.parameter(POINTS, POINT, VERTEX, points);
|
|
1026
|
+
if (p.peekNextToken(SUBDIVS)) {
|
|
1027
|
+
api.parameter(SUBDIVS, p.getNextInt());
|
|
1028
|
+
} if (p.peekNextToken(SMOOTH)) {
|
|
1029
|
+
api.parameter(SMOOTH, p.getNextBoolean());
|
|
1030
|
+
} api.geometry(name, "bezier_mesh");
|
|
1031
|
+
break;
|
|
1032
|
+
}
|
|
1033
|
+
default:
|
|
1034
|
+
UI.printWarning(Module.API, "Unrecognized object type: %s", p.getNextToken());
|
|
1035
|
+
noInstance = true;
|
|
1036
|
+
break;
|
|
1037
|
+
}
|
|
1038
|
+
if (!noInstance) {
|
|
1039
|
+
// create instance
|
|
1040
|
+
api.parameter(SHADERS, shaders);
|
|
1041
|
+
if (modifiers != null) {
|
|
1042
|
+
api.parameter(MODIFIERS, modifiers);
|
|
1043
|
+
}
|
|
1044
|
+
if (transform != null && transform.length > 0) {
|
|
1045
|
+
if (transform.length == 1) {
|
|
1046
|
+
api.parameter(TRANSFORM, transform[0]);
|
|
1047
|
+
} else {
|
|
1048
|
+
api.parameter("transform.steps", transform.length);
|
|
1049
|
+
api.parameter("transform.times", "float", NONE, new float[]{
|
|
1050
|
+
transformTime0, transformTime1});
|
|
1051
|
+
for (int i = 0; i < transform.length; i++) {
|
|
1052
|
+
api.parameter(String.format("transform[%d]", i), transform[i]);
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
api.instance(name + ".instance", name);
|
|
1057
|
+
}
|
|
1058
|
+
p.checkNextToken("}");
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
private void parseInstanceBlock(SunflowAPIInterface api) throws ParserException, IOException {
|
|
1062
|
+
p.checkNextToken("{");
|
|
1063
|
+
p.checkNextToken(NAME);
|
|
1064
|
+
String name = p.getNextToken();
|
|
1065
|
+
UI.printInfo(Module.API, "Reading instance: %s ...", name);
|
|
1066
|
+
p.checkNextToken("geometry");
|
|
1067
|
+
String geoname = p.getNextToken();
|
|
1068
|
+
p.checkNextToken(TRANSFORM);
|
|
1069
|
+
if (p.peekNextToken("steps")) {
|
|
1070
|
+
int n = p.getNextInt();
|
|
1071
|
+
api.parameter("transform.steps", n);
|
|
1072
|
+
p.checkNextToken("times");
|
|
1073
|
+
float[] times = new float[2];
|
|
1074
|
+
times[0] = p.getNextFloat();
|
|
1075
|
+
times[1] = p.getNextFloat();
|
|
1076
|
+
api.parameter("transform.times", "float", NONE, times);
|
|
1077
|
+
for (int i = 0; i < n; i++) {
|
|
1078
|
+
api.parameter(String.format("transform[%d]", i), parseMatrix());
|
|
1079
|
+
}
|
|
1080
|
+
} else {
|
|
1081
|
+
api.parameter(TRANSFORM, parseMatrix());
|
|
1082
|
+
}
|
|
1083
|
+
String[] shaders;
|
|
1084
|
+
if (p.peekNextToken(SHADERS)) {
|
|
1085
|
+
int n = p.getNextInt();
|
|
1086
|
+
shaders = new String[n];
|
|
1087
|
+
for (int i = 0; i < n; i++) {
|
|
1088
|
+
shaders[i] = p.getNextToken();
|
|
1089
|
+
}
|
|
1090
|
+
} else {
|
|
1091
|
+
p.checkNextToken(SHADER);
|
|
1092
|
+
shaders = new String[]{p.getNextToken()};
|
|
1093
|
+
}
|
|
1094
|
+
api.parameter(SHADERS, shaders);
|
|
1095
|
+
String[] modifiers = null;
|
|
1096
|
+
if (p.peekNextToken(MODIFIERS)) {
|
|
1097
|
+
int n = p.getNextInt();
|
|
1098
|
+
modifiers = new String[n];
|
|
1099
|
+
for (int i = 0; i < n; i++) {
|
|
1100
|
+
modifiers[i] = p.getNextToken();
|
|
1101
|
+
}
|
|
1102
|
+
} else if (p.peekNextToken(MODIFIER)) {
|
|
1103
|
+
modifiers = new String[]{p.getNextToken()};
|
|
1104
|
+
}
|
|
1105
|
+
if (modifiers != null) {
|
|
1106
|
+
api.parameter(MODIFIERS, modifiers);
|
|
1107
|
+
}
|
|
1108
|
+
api.instance(name, geoname);
|
|
1109
|
+
p.checkNextToken("}");
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
private void parseLightBlock(SunflowAPIInterface api) throws ParserException, IOException, ColorSpecificationException {
|
|
1113
|
+
p.checkNextToken("{");
|
|
1114
|
+
p.checkNextToken(TYPE);
|
|
1115
|
+
if (p.peekNextToken("mesh")) {
|
|
1116
|
+
UI.printWarning(Module.API, "Deprecated light type: mesh");
|
|
1117
|
+
p.checkNextToken(NAME);
|
|
1118
|
+
String name = p.getNextToken();
|
|
1119
|
+
UI.printInfo(Module.API, "Reading light mesh: %s ...", name);
|
|
1120
|
+
p.checkNextToken(EMIT);
|
|
1121
|
+
api.parameter(RADIANCE, null, parseColor().getRGB());
|
|
1122
|
+
int samples = numLightSamples;
|
|
1123
|
+
if (p.peekNextToken(SAMPLES)) {
|
|
1124
|
+
samples = p.getNextInt();
|
|
1125
|
+
} else {
|
|
1126
|
+
UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", samples);
|
|
1127
|
+
}
|
|
1128
|
+
api.parameter(SAMPLES, samples);
|
|
1129
|
+
int numVertices = p.getNextInt();
|
|
1130
|
+
int numTriangles = p.getNextInt();
|
|
1131
|
+
float[] points = new float[3 * numVertices];
|
|
1132
|
+
int[] triangles = new int[3 * numTriangles];
|
|
1133
|
+
for (int i = 0; i < numVertices; i++) {
|
|
1134
|
+
p.checkNextToken("v");
|
|
1135
|
+
points[3 * i + 0] = p.getNextFloat();
|
|
1136
|
+
points[3 * i + 1] = p.getNextFloat();
|
|
1137
|
+
points[3 * i + 2] = p.getNextFloat();
|
|
1138
|
+
// ignored
|
|
1139
|
+
p.getNextFloat();
|
|
1140
|
+
p.getNextFloat();
|
|
1141
|
+
p.getNextFloat();
|
|
1142
|
+
p.getNextFloat();
|
|
1143
|
+
p.getNextFloat();
|
|
1144
|
+
}
|
|
1145
|
+
for (int i = 0; i < numTriangles; i++) {
|
|
1146
|
+
p.checkNextToken("t");
|
|
1147
|
+
triangles[3 * i + 0] = p.getNextInt();
|
|
1148
|
+
triangles[3 * i + 1] = p.getNextInt();
|
|
1149
|
+
triangles[3 * i + 2] = p.getNextInt();
|
|
1150
|
+
}
|
|
1151
|
+
api.parameter(POINTS, POINT, VERTEX, points);
|
|
1152
|
+
api.parameter(TRIANGLES, triangles);
|
|
1153
|
+
api.light(name, TRIANGLE_MESH);
|
|
1154
|
+
} else if (p.peekNextToken(POINT)) {
|
|
1155
|
+
UI.printInfo(Module.API, "Reading point light ...");
|
|
1156
|
+
Color pow;
|
|
1157
|
+
if (p.peekNextToken(COLOR)) {
|
|
1158
|
+
pow = parseColor();
|
|
1159
|
+
p.checkNextToken(POWER);
|
|
1160
|
+
float po = p.getNextFloat();
|
|
1161
|
+
pow.mul(po);
|
|
1162
|
+
} else {
|
|
1163
|
+
UI.printWarning(Module.API, "Deprecated color specification - please use color and power instead");
|
|
1164
|
+
p.checkNextToken(POWER);
|
|
1165
|
+
pow = parseColor();
|
|
1166
|
+
}
|
|
1167
|
+
p.checkNextToken("p");
|
|
1168
|
+
api.parameter(CENTER, parsePoint());
|
|
1169
|
+
api.parameter(POWER, null, pow.getRGB());
|
|
1170
|
+
api.light(generateUniqueName("pointlight"), POINT);
|
|
1171
|
+
} else if (p.peekNextToken("spherical")) {
|
|
1172
|
+
UI.printInfo(Module.API, "Reading spherical light ...");
|
|
1173
|
+
p.checkNextToken(COLOR);
|
|
1174
|
+
Color pow = parseColor();
|
|
1175
|
+
p.checkNextToken(RADIANCE);
|
|
1176
|
+
pow.mul(p.getNextFloat());
|
|
1177
|
+
api.parameter(RADIANCE, null, pow.getRGB());
|
|
1178
|
+
p.checkNextToken(CENTER);
|
|
1179
|
+
api.parameter(CENTER, parsePoint());
|
|
1180
|
+
p.checkNextToken(RADIUS);
|
|
1181
|
+
api.parameter(RADIUS, p.getNextFloat());
|
|
1182
|
+
p.checkNextToken(SAMPLES);
|
|
1183
|
+
api.parameter(SAMPLES, p.getNextInt());
|
|
1184
|
+
api.light(generateUniqueName("spherelight"), "sphere");
|
|
1185
|
+
} else if (p.peekNextToken("directional")) {
|
|
1186
|
+
UI.printInfo(Module.API, "Reading directional light ...");
|
|
1187
|
+
p.checkNextToken("source");
|
|
1188
|
+
Point3 s = parsePoint();
|
|
1189
|
+
api.parameter("source", s);
|
|
1190
|
+
p.checkNextToken("target");
|
|
1191
|
+
Point3 t = parsePoint();
|
|
1192
|
+
api.parameter("dir", Point3.sub(t, s, new Vector3()));
|
|
1193
|
+
p.checkNextToken(RADIUS);
|
|
1194
|
+
api.parameter(RADIUS, p.getNextFloat());
|
|
1195
|
+
p.checkNextToken(EMIT);
|
|
1196
|
+
Color e = parseColor();
|
|
1197
|
+
if (p.peekNextToken("intensity")) {
|
|
1198
|
+
float i = p.getNextFloat();
|
|
1199
|
+
e.mul(i);
|
|
1200
|
+
} else {
|
|
1201
|
+
UI.printWarning(Module.API, "Deprecated color specification - please use emit and intensity instead");
|
|
1202
|
+
}
|
|
1203
|
+
api.parameter(RADIANCE, null, e.getRGB());
|
|
1204
|
+
api.light(generateUniqueName("dirlight"), "directional");
|
|
1205
|
+
} else if (p.peekNextToken("ibl")) {
|
|
1206
|
+
UI.printInfo(Module.API, "Reading image based light ...");
|
|
1207
|
+
p.checkNextToken("image");
|
|
1208
|
+
api.parameter(TEXTURE, p.getNextToken());
|
|
1209
|
+
p.checkNextToken(CENTER);
|
|
1210
|
+
api.parameter(CENTER, parseVector());
|
|
1211
|
+
p.checkNextToken("up");
|
|
1212
|
+
api.parameter("up", parseVector());
|
|
1213
|
+
p.checkNextToken("lock");
|
|
1214
|
+
api.parameter("fixed", p.getNextBoolean());
|
|
1215
|
+
int samples = numLightSamples;
|
|
1216
|
+
if (p.peekNextToken(SAMPLES)) {
|
|
1217
|
+
samples = p.getNextInt();
|
|
1218
|
+
} else {
|
|
1219
|
+
UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", samples);
|
|
1220
|
+
}
|
|
1221
|
+
api.parameter(SAMPLES, samples);
|
|
1222
|
+
if (p.peekNextToken("lowsamples")) {
|
|
1223
|
+
api.parameter("lowsamples", p.getNextInt());
|
|
1224
|
+
} else {
|
|
1225
|
+
api.parameter("lowsamples", samples);
|
|
1226
|
+
}
|
|
1227
|
+
api.light(generateUniqueName("ibl"), "ibl");
|
|
1228
|
+
} else if (p.peekNextToken("meshlight")) {
|
|
1229
|
+
p.checkNextToken(NAME);
|
|
1230
|
+
String name = p.getNextToken();
|
|
1231
|
+
UI.printInfo(Module.API, "Reading meshlight: %s ...", name);
|
|
1232
|
+
p.checkNextToken(EMIT);
|
|
1233
|
+
Color e = parseColor();
|
|
1234
|
+
if (p.peekNextToken(RADIANCE)) {
|
|
1235
|
+
float r = p.getNextFloat();
|
|
1236
|
+
e.mul(r);
|
|
1237
|
+
} else {
|
|
1238
|
+
UI.printWarning(Module.API, "Deprecated color specification - please use emit and radiance instead");
|
|
1239
|
+
}
|
|
1240
|
+
api.parameter(RADIANCE, null, e.getRGB());
|
|
1241
|
+
int samples = numLightSamples;
|
|
1242
|
+
if (p.peekNextToken(SAMPLES)) {
|
|
1243
|
+
samples = p.getNextInt();
|
|
1244
|
+
} else {
|
|
1245
|
+
UI.printWarning(Module.API, "Samples keyword not found - defaulting to %d", samples);
|
|
1246
|
+
}
|
|
1247
|
+
api.parameter(SAMPLES, samples);
|
|
1248
|
+
// parse vertices
|
|
1249
|
+
p.checkNextToken(POINTS);
|
|
1250
|
+
int np = p.getNextInt();
|
|
1251
|
+
api.parameter(POINTS, POINT, VERTEX, parseFloatArray(np * 3));
|
|
1252
|
+
// parse triangle indices
|
|
1253
|
+
p.checkNextToken(TRIANGLES);
|
|
1254
|
+
int nt = p.getNextInt();
|
|
1255
|
+
api.parameter(TRIANGLES, parseIntArray(nt * 3));
|
|
1256
|
+
api.light(name, TRIANGLE_MESH);
|
|
1257
|
+
} else if (p.peekNextToken("sunsky")) {
|
|
1258
|
+
p.checkNextToken("up");
|
|
1259
|
+
api.parameter("up", parseVector());
|
|
1260
|
+
p.checkNextToken("east");
|
|
1261
|
+
api.parameter("east", parseVector());
|
|
1262
|
+
p.checkNextToken("sundir");
|
|
1263
|
+
api.parameter("sundir", parseVector());
|
|
1264
|
+
p.checkNextToken("turbidity");
|
|
1265
|
+
api.parameter("turbidity", p.getNextFloat());
|
|
1266
|
+
if (p.peekNextToken(SAMPLES)) {
|
|
1267
|
+
api.parameter(SAMPLES, p.getNextInt());
|
|
1268
|
+
}
|
|
1269
|
+
if (p.peekNextToken("ground.extendsky")) {
|
|
1270
|
+
api.parameter("ground.extendsky", p.getNextBoolean());
|
|
1271
|
+
} else if (p.peekNextToken("ground.color")) {
|
|
1272
|
+
api.parameter("ground.color", null, parseColor().getRGB());
|
|
1273
|
+
}
|
|
1274
|
+
api.light(generateUniqueName("sunsky"), "sunsky");
|
|
1275
|
+
} else if (p.peekNextToken("cornellbox")) {
|
|
1276
|
+
UI.printInfo(Module.API, "Reading cornell box ...");
|
|
1277
|
+
p.checkNextToken("corner0");
|
|
1278
|
+
api.parameter("corner0", parsePoint());
|
|
1279
|
+
p.checkNextToken("corner1");
|
|
1280
|
+
api.parameter("corner1", parsePoint());
|
|
1281
|
+
p.checkNextToken("left");
|
|
1282
|
+
api.parameter("leftColor", null, parseColor().getRGB());
|
|
1283
|
+
p.checkNextToken("right");
|
|
1284
|
+
api.parameter("rightColor", null, parseColor().getRGB());
|
|
1285
|
+
p.checkNextToken("top");
|
|
1286
|
+
api.parameter("topColor", null, parseColor().getRGB());
|
|
1287
|
+
p.checkNextToken("bottom");
|
|
1288
|
+
api.parameter("bottomColor", null, parseColor().getRGB());
|
|
1289
|
+
p.checkNextToken("back");
|
|
1290
|
+
api.parameter("backColor", null, parseColor().getRGB());
|
|
1291
|
+
p.checkNextToken(EMIT);
|
|
1292
|
+
api.parameter(RADIANCE, null, parseColor().getRGB());
|
|
1293
|
+
if (p.peekNextToken(SAMPLES)) {
|
|
1294
|
+
api.parameter(SAMPLES, p.getNextInt());
|
|
1295
|
+
}
|
|
1296
|
+
api.light(generateUniqueName("cornellbox"), "cornell_box");
|
|
1297
|
+
} else {
|
|
1298
|
+
UI.printWarning(Module.API, "Unrecognized object type: %s", p.getNextToken());
|
|
1299
|
+
}
|
|
1300
|
+
p.checkNextToken("}");
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
private Color parseColor() throws IOException, ParserException, ColorSpecificationException {
|
|
1304
|
+
if (p.peekNextToken("{")) {
|
|
1305
|
+
String space = p.getNextToken();
|
|
1306
|
+
int req = ColorFactory.getRequiredDataValues(space);
|
|
1307
|
+
if (req == -2) {
|
|
1308
|
+
UI.printWarning(Module.API, "Unrecognized color space: %s", space);
|
|
1309
|
+
return null;
|
|
1310
|
+
} else if (req == -1) {
|
|
1311
|
+
// array required, parse how many values are required
|
|
1312
|
+
req = p.getNextInt();
|
|
1313
|
+
}
|
|
1314
|
+
Color c = ColorFactory.createColor(space, parseFloatArray(req));
|
|
1315
|
+
p.checkNextToken("}");
|
|
1316
|
+
return c;
|
|
1317
|
+
} else {
|
|
1318
|
+
float r = p.getNextFloat();
|
|
1319
|
+
float g = p.getNextFloat();
|
|
1320
|
+
float b = p.getNextFloat();
|
|
1321
|
+
return ColorFactory.createColor(null, r, g, b);
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
private Point3 parsePoint() throws IOException {
|
|
1326
|
+
float x = p.getNextFloat();
|
|
1327
|
+
float y = p.getNextFloat();
|
|
1328
|
+
float z = p.getNextFloat();
|
|
1329
|
+
return new Point3(x, y, z);
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
private Vector3 parseVector() throws IOException {
|
|
1333
|
+
float x = p.getNextFloat();
|
|
1334
|
+
float y = p.getNextFloat();
|
|
1335
|
+
float z = p.getNextFloat();
|
|
1336
|
+
return new Vector3(x, y, z);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
private int[] parseIntArray(int size) throws IOException {
|
|
1340
|
+
int[] data = new int[size];
|
|
1341
|
+
for (int i = 0; i < size; i++) {
|
|
1342
|
+
data[i] = p.getNextInt();
|
|
1343
|
+
}
|
|
1344
|
+
return data;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
private float[] parseFloatArray(int size) throws IOException {
|
|
1348
|
+
float[] data = new float[size];
|
|
1349
|
+
for (int i = 0; i < size; i++) {
|
|
1350
|
+
data[i] = p.getNextFloat();
|
|
1351
|
+
}
|
|
1352
|
+
return data;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
private Matrix4 parseMatrix() throws IOException, ParserException {
|
|
1356
|
+
if (p.peekNextToken("row")) {
|
|
1357
|
+
return new Matrix4(parseFloatArray(16), true);
|
|
1358
|
+
} else if (p.peekNextToken("col")) {
|
|
1359
|
+
return new Matrix4(parseFloatArray(16), false);
|
|
1360
|
+
} else {
|
|
1361
|
+
Matrix4 m = Matrix4.IDENTITY;
|
|
1362
|
+
p.checkNextToken("{");
|
|
1363
|
+
while (!p.peekNextToken("}")) {
|
|
1364
|
+
Matrix4 t = null;
|
|
1365
|
+
if (p.peekNextToken("translate")) {
|
|
1366
|
+
float x = p.getNextFloat();
|
|
1367
|
+
float y = p.getNextFloat();
|
|
1368
|
+
float z = p.getNextFloat();
|
|
1369
|
+
t = Matrix4.translation(x, y, z);
|
|
1370
|
+
} else if (p.peekNextToken("scaleu")) {
|
|
1371
|
+
float s = p.getNextFloat();
|
|
1372
|
+
t = Matrix4.scale(s);
|
|
1373
|
+
} else if (p.peekNextToken(SCALE)) {
|
|
1374
|
+
float x = p.getNextFloat();
|
|
1375
|
+
float y = p.getNextFloat();
|
|
1376
|
+
float z = p.getNextFloat();
|
|
1377
|
+
t = Matrix4.scale(x, y, z);
|
|
1378
|
+
} else if (p.peekNextToken("rotatex")) {
|
|
1379
|
+
float angle = p.getNextFloat();
|
|
1380
|
+
t = Matrix4.rotateX((float) Math.toRadians(angle));
|
|
1381
|
+
} else if (p.peekNextToken("rotatey")) {
|
|
1382
|
+
float angle = p.getNextFloat();
|
|
1383
|
+
t = Matrix4.rotateY((float) Math.toRadians(angle));
|
|
1384
|
+
} else if (p.peekNextToken("rotatez")) {
|
|
1385
|
+
float angle = p.getNextFloat();
|
|
1386
|
+
t = Matrix4.rotateZ((float) Math.toRadians(angle));
|
|
1387
|
+
} else if (p.peekNextToken("rotate")) {
|
|
1388
|
+
float x = p.getNextFloat();
|
|
1389
|
+
float y = p.getNextFloat();
|
|
1390
|
+
float z = p.getNextFloat();
|
|
1391
|
+
float angle = p.getNextFloat();
|
|
1392
|
+
t = Matrix4.rotate(x, y, z, (float) Math.toRadians(angle));
|
|
1393
|
+
} else {
|
|
1394
|
+
UI.printWarning(Module.API, "Unrecognized transformation type: %s", p.getNextToken());
|
|
1395
|
+
}
|
|
1396
|
+
if (t != null) {
|
|
1397
|
+
m = t.multiply(m);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return m;
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
}
|