joonsrenderer 1.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (255) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +53 -0
  3. data/.mvn/extensions.xml +8 -0
  4. data/CHANGELOG.md +2 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE +674 -0
  7. data/README.md +2 -0
  8. data/Rakefile +43 -0
  9. data/docs/.gitignore +6 -0
  10. data/docs/_config.yml +20 -0
  11. data/docs/_includes/footer.html +38 -0
  12. data/docs/_includes/head.html +15 -0
  13. data/docs/_includes/header.html +27 -0
  14. data/docs/_includes/icon-github.html +1 -0
  15. data/docs/_includes/icon-github.svg +1 -0
  16. data/docs/_includes/icon-twitter.html +1 -0
  17. data/docs/_includes/icon-twitter.svg +1 -0
  18. data/docs/_layouts/default.html +20 -0
  19. data/docs/_layouts/page.html +14 -0
  20. data/docs/_layouts/post.html +15 -0
  21. data/docs/_posts/2017-01-08-animated_ray_tracing.md +72 -0
  22. data/docs/_posts/2017-01-08-welcome.md +78 -0
  23. data/docs/_sass/_base.scss +206 -0
  24. data/docs/_sass/_layout.scss +242 -0
  25. data/docs/_sass/_syntax-highlighting.scss +71 -0
  26. data/docs/about.md +12 -0
  27. data/docs/assets/Animation.ogv +0 -0
  28. data/docs/assets/Animation.png +0 -0
  29. data/docs/assets/basic.png +0 -0
  30. data/docs/assets/basic_traced.png +0 -0
  31. data/docs/css/main.scss +38 -0
  32. data/docs/favicon.ico +0 -0
  33. data/docs/feed.xml +30 -0
  34. data/docs/index.html +38 -0
  35. data/joonsrenderer.gemspec +23 -0
  36. data/lib/joonsrenderer.rb +12 -0
  37. data/lib/joonsrenderer/version.rb +3 -0
  38. data/pom.rb +75 -0
  39. data/pom.xml +163 -0
  40. data/src/main/java/SunflowGUI.java +1354 -0
  41. data/src/main/java/joons/JRFiller.java +79 -0
  42. data/src/main/java/joons/JRImagePanel.java +141 -0
  43. data/src/main/java/joons/JRRecorder.java +183 -0
  44. data/src/main/java/joons/JRStatics.java +199 -0
  45. data/src/main/java/joons/JoonsRenderer.java +837 -0
  46. data/src/main/java/org/sunflow/AsciiFileSunflowAPI.java +98 -0
  47. data/src/main/java/org/sunflow/Benchmark.java +313 -0
  48. data/src/main/java/org/sunflow/BinaryFileSunflowAPI.java +228 -0
  49. data/src/main/java/org/sunflow/FileSunflowAPI.java +354 -0
  50. data/src/main/java/org/sunflow/PluginRegistry.java +322 -0
  51. data/src/main/java/org/sunflow/RealtimeBenchmark.java +125 -0
  52. data/src/main/java/org/sunflow/RenderObjectMap.java +344 -0
  53. data/src/main/java/org/sunflow/SunflowAPI.java +762 -0
  54. data/src/main/java/org/sunflow/SunflowAPIInterface.java +277 -0
  55. data/src/main/java/org/sunflow/core/AccelerationStructure.java +20 -0
  56. data/src/main/java/org/sunflow/core/AccelerationStructureFactory.java +36 -0
  57. data/src/main/java/org/sunflow/core/BucketOrder.java +21 -0
  58. data/src/main/java/org/sunflow/core/Camera.java +125 -0
  59. data/src/main/java/org/sunflow/core/CameraLens.java +29 -0
  60. data/src/main/java/org/sunflow/core/CausticPhotonMapInterface.java +15 -0
  61. data/src/main/java/org/sunflow/core/Display.java +78 -0
  62. data/src/main/java/org/sunflow/core/Filter.java +27 -0
  63. data/src/main/java/org/sunflow/core/GIEngine.java +42 -0
  64. data/src/main/java/org/sunflow/core/Geometry.java +157 -0
  65. data/src/main/java/org/sunflow/core/GlobalPhotonMapInterface.java +21 -0
  66. data/src/main/java/org/sunflow/core/ImageSampler.java +26 -0
  67. data/src/main/java/org/sunflow/core/Instance.java +224 -0
  68. data/src/main/java/org/sunflow/core/InstanceList.java +83 -0
  69. data/src/main/java/org/sunflow/core/IntersectionState.java +120 -0
  70. data/src/main/java/org/sunflow/core/LightSample.java +104 -0
  71. data/src/main/java/org/sunflow/core/LightServer.java +382 -0
  72. data/src/main/java/org/sunflow/core/LightSource.java +67 -0
  73. data/src/main/java/org/sunflow/core/Modifier.java +16 -0
  74. data/src/main/java/org/sunflow/core/Options.java +20 -0
  75. data/src/main/java/org/sunflow/core/ParameterList.java +758 -0
  76. data/src/main/java/org/sunflow/core/PhotonStore.java +62 -0
  77. data/src/main/java/org/sunflow/core/PrimitiveList.java +70 -0
  78. data/src/main/java/org/sunflow/core/Ray.java +219 -0
  79. data/src/main/java/org/sunflow/core/RenderObject.java +25 -0
  80. data/src/main/java/org/sunflow/core/Scene.java +377 -0
  81. data/src/main/java/org/sunflow/core/SceneParser.java +58 -0
  82. data/src/main/java/org/sunflow/core/Shader.java +30 -0
  83. data/src/main/java/org/sunflow/core/ShadingCache.java +84 -0
  84. data/src/main/java/org/sunflow/core/ShadingState.java +939 -0
  85. data/src/main/java/org/sunflow/core/Statistics.java +85 -0
  86. data/src/main/java/org/sunflow/core/Tesselatable.java +36 -0
  87. data/src/main/java/org/sunflow/core/Texture.java +128 -0
  88. data/src/main/java/org/sunflow/core/TextureCache.java +48 -0
  89. data/src/main/java/org/sunflow/core/accel/BoundingIntervalHierarchy.java +652 -0
  90. data/src/main/java/org/sunflow/core/accel/KDTree.java +833 -0
  91. data/src/main/java/org/sunflow/core/accel/NullAccelerator.java +30 -0
  92. data/src/main/java/org/sunflow/core/accel/UniformGrid.java +329 -0
  93. data/src/main/java/org/sunflow/core/bucket/BucketOrderFactory.java +26 -0
  94. data/src/main/java/org/sunflow/core/bucket/ColumnBucketOrder.java +21 -0
  95. data/src/main/java/org/sunflow/core/bucket/DiagonalBucketOrder.java +28 -0
  96. data/src/main/java/org/sunflow/core/bucket/HilbertBucketOrder.java +65 -0
  97. data/src/main/java/org/sunflow/core/bucket/InvertedBucketOrder.java +28 -0
  98. data/src/main/java/org/sunflow/core/bucket/RandomBucketOrder.java +49 -0
  99. data/src/main/java/org/sunflow/core/bucket/RowBucketOrder.java +21 -0
  100. data/src/main/java/org/sunflow/core/bucket/SpiralBucketOrder.java +43 -0
  101. data/src/main/java/org/sunflow/core/camera/FisheyeLens.java +25 -0
  102. data/src/main/java/org/sunflow/core/camera/PinholeLens.java +43 -0
  103. data/src/main/java/org/sunflow/core/camera/SphericalLens.java +22 -0
  104. data/src/main/java/org/sunflow/core/camera/ThinLens.java +107 -0
  105. data/src/main/java/org/sunflow/core/display/FastDisplay.java +119 -0
  106. data/src/main/java/org/sunflow/core/display/FileDisplay.java +83 -0
  107. data/src/main/java/org/sunflow/core/display/FrameDisplay.java +97 -0
  108. data/src/main/java/org/sunflow/core/display/ImgPipeDisplay.java +109 -0
  109. data/src/main/java/org/sunflow/core/filter/BlackmanHarrisFilter.java +28 -0
  110. data/src/main/java/org/sunflow/core/filter/BoxFilter.java +16 -0
  111. data/src/main/java/org/sunflow/core/filter/CatmullRomFilter.java +29 -0
  112. data/src/main/java/org/sunflow/core/filter/CubicBSpline.java +32 -0
  113. data/src/main/java/org/sunflow/core/filter/GaussianFilter.java +24 -0
  114. data/src/main/java/org/sunflow/core/filter/LanczosFilter.java +30 -0
  115. data/src/main/java/org/sunflow/core/filter/MitchellFilter.java +28 -0
  116. data/src/main/java/org/sunflow/core/filter/SincFilter.java +25 -0
  117. data/src/main/java/org/sunflow/core/filter/TriangleFilter.java +16 -0
  118. data/src/main/java/org/sunflow/core/gi/AmbientOcclusionGIEngine.java +57 -0
  119. data/src/main/java/org/sunflow/core/gi/FakeGIEngine.java +48 -0
  120. data/src/main/java/org/sunflow/core/gi/InstantGI.java +194 -0
  121. data/src/main/java/org/sunflow/core/gi/IrradianceCacheGIEngine.java +268 -0
  122. data/src/main/java/org/sunflow/core/gi/PathTracingGIEngine.java +65 -0
  123. data/src/main/java/org/sunflow/core/light/DirectionalSpotlight.java +103 -0
  124. data/src/main/java/org/sunflow/core/light/ImageBasedLight.java +303 -0
  125. data/src/main/java/org/sunflow/core/light/PointLight.java +72 -0
  126. data/src/main/java/org/sunflow/core/light/SphereLight.java +166 -0
  127. data/src/main/java/org/sunflow/core/light/SunSkyLight.java +362 -0
  128. data/src/main/java/org/sunflow/core/light/TriangleMeshLight.java +296 -0
  129. data/src/main/java/org/sunflow/core/modifiers/BumpMappingModifier.java +37 -0
  130. data/src/main/java/org/sunflow/core/modifiers/NormalMapModifier.java +34 -0
  131. data/src/main/java/org/sunflow/core/modifiers/PerlinModifier.java +80 -0
  132. data/src/main/java/org/sunflow/core/parser/Keyword.java +39 -0
  133. data/src/main/java/org/sunflow/core/parser/RA2Parser.java +107 -0
  134. data/src/main/java/org/sunflow/core/parser/RA3Parser.java +68 -0
  135. data/src/main/java/org/sunflow/core/parser/SCAbstractParser.java +299 -0
  136. data/src/main/java/org/sunflow/core/parser/SCAsciiParser.java +251 -0
  137. data/src/main/java/org/sunflow/core/parser/SCBinaryParser.java +156 -0
  138. data/src/main/java/org/sunflow/core/parser/SCParser.java +1403 -0
  139. data/src/main/java/org/sunflow/core/parser/ShaveRibParser.java +174 -0
  140. data/src/main/java/org/sunflow/core/parser/TriParser.java +79 -0
  141. data/src/main/java/org/sunflow/core/photonmap/CausticPhotonMap.java +429 -0
  142. data/src/main/java/org/sunflow/core/photonmap/GlobalPhotonMap.java +530 -0
  143. data/src/main/java/org/sunflow/core/photonmap/GridPhotonMap.java +308 -0
  144. data/src/main/java/org/sunflow/core/primitive/Background.java +55 -0
  145. data/src/main/java/org/sunflow/core/primitive/BanchoffSurface.java +100 -0
  146. data/src/main/java/org/sunflow/core/primitive/Box.java +210 -0
  147. data/src/main/java/org/sunflow/core/primitive/CornellBox.java +476 -0
  148. data/src/main/java/org/sunflow/core/primitive/CubeGrid.java +318 -0
  149. data/src/main/java/org/sunflow/core/primitive/Cylinder.java +104 -0
  150. data/src/main/java/org/sunflow/core/primitive/Hair.java +275 -0
  151. data/src/main/java/org/sunflow/core/primitive/JuliaFractal.java +266 -0
  152. data/src/main/java/org/sunflow/core/primitive/ParticleSurface.java +114 -0
  153. data/src/main/java/org/sunflow/core/primitive/Plane.java +163 -0
  154. data/src/main/java/org/sunflow/core/primitive/QuadMesh.java +413 -0
  155. data/src/main/java/org/sunflow/core/primitive/Sphere.java +101 -0
  156. data/src/main/java/org/sunflow/core/primitive/SphereFlake.java +234 -0
  157. data/src/main/java/org/sunflow/core/primitive/Torus.java +145 -0
  158. data/src/main/java/org/sunflow/core/primitive/TriangleMesh.java +849 -0
  159. data/src/main/java/org/sunflow/core/renderer/BucketRenderer.java +491 -0
  160. data/src/main/java/org/sunflow/core/renderer/MultipassRenderer.java +237 -0
  161. data/src/main/java/org/sunflow/core/renderer/ProgressiveRenderer.java +171 -0
  162. data/src/main/java/org/sunflow/core/renderer/SimpleRenderer.java +106 -0
  163. data/src/main/java/org/sunflow/core/shader/AmbientOcclusionShader.java +53 -0
  164. data/src/main/java/org/sunflow/core/shader/AnisotropicWardShader.java +216 -0
  165. data/src/main/java/org/sunflow/core/shader/ConstantShader.java +31 -0
  166. data/src/main/java/org/sunflow/core/shader/DiffuseShader.java +65 -0
  167. data/src/main/java/org/sunflow/core/shader/GlassShader.java +147 -0
  168. data/src/main/java/org/sunflow/core/shader/IDShader.java +27 -0
  169. data/src/main/java/org/sunflow/core/shader/MirrorShader.java +68 -0
  170. data/src/main/java/org/sunflow/core/shader/NormalShader.java +32 -0
  171. data/src/main/java/org/sunflow/core/shader/PhongShader.java +89 -0
  172. data/src/main/java/org/sunflow/core/shader/PrimIDShader.java +30 -0
  173. data/src/main/java/org/sunflow/core/shader/QuickGrayShader.java +63 -0
  174. data/src/main/java/org/sunflow/core/shader/ShinyDiffuseShader.java +98 -0
  175. data/src/main/java/org/sunflow/core/shader/SimpleShader.java +24 -0
  176. data/src/main/java/org/sunflow/core/shader/TexturedAmbientOcclusionShader.java +31 -0
  177. data/src/main/java/org/sunflow/core/shader/TexturedDiffuseShader.java +31 -0
  178. data/src/main/java/org/sunflow/core/shader/TexturedPhongShader.java +31 -0
  179. data/src/main/java/org/sunflow/core/shader/TexturedShinyDiffuseShader.java +31 -0
  180. data/src/main/java/org/sunflow/core/shader/TexturedWardShader.java +31 -0
  181. data/src/main/java/org/sunflow/core/shader/UVShader.java +27 -0
  182. data/src/main/java/org/sunflow/core/shader/UberShader.java +149 -0
  183. data/src/main/java/org/sunflow/core/shader/ViewCausticsShader.java +33 -0
  184. data/src/main/java/org/sunflow/core/shader/ViewGlobalPhotonsShader.java +25 -0
  185. data/src/main/java/org/sunflow/core/shader/ViewIrradianceShader.java +25 -0
  186. data/src/main/java/org/sunflow/core/shader/WireframeShader.java +83 -0
  187. data/src/main/java/org/sunflow/core/tesselatable/BezierMesh.java +254 -0
  188. data/src/main/java/org/sunflow/core/tesselatable/FileMesh.java +251 -0
  189. data/src/main/java/org/sunflow/core/tesselatable/Gumbo.java +1147 -0
  190. data/src/main/java/org/sunflow/core/tesselatable/Teapot.java +237 -0
  191. data/src/main/java/org/sunflow/image/Bitmap.java +15 -0
  192. data/src/main/java/org/sunflow/image/BitmapReader.java +39 -0
  193. data/src/main/java/org/sunflow/image/BitmapWriter.java +79 -0
  194. data/src/main/java/org/sunflow/image/BlackbodySpectrum.java +16 -0
  195. data/src/main/java/org/sunflow/image/ChromaticitySpectrum.java +55 -0
  196. data/src/main/java/org/sunflow/image/Color.java +374 -0
  197. data/src/main/java/org/sunflow/image/ColorEncoder.java +94 -0
  198. data/src/main/java/org/sunflow/image/ColorFactory.java +122 -0
  199. data/src/main/java/org/sunflow/image/ConstantSpectralCurve.java +21 -0
  200. data/src/main/java/org/sunflow/image/IrregularSpectralCurve.java +57 -0
  201. data/src/main/java/org/sunflow/image/RGBSpace.java +207 -0
  202. data/src/main/java/org/sunflow/image/RegularSpectralCurve.java +30 -0
  203. data/src/main/java/org/sunflow/image/SpectralCurve.java +118 -0
  204. data/src/main/java/org/sunflow/image/XYZColor.java +50 -0
  205. data/src/main/java/org/sunflow/image/formats/BitmapBlack.java +27 -0
  206. data/src/main/java/org/sunflow/image/formats/BitmapG8.java +36 -0
  207. data/src/main/java/org/sunflow/image/formats/BitmapGA8.java +30 -0
  208. data/src/main/java/org/sunflow/image/formats/BitmapRGB8.java +40 -0
  209. data/src/main/java/org/sunflow/image/formats/BitmapRGBA8.java +40 -0
  210. data/src/main/java/org/sunflow/image/formats/BitmapRGBE.java +60 -0
  211. data/src/main/java/org/sunflow/image/formats/BitmapXYZ.java +38 -0
  212. data/src/main/java/org/sunflow/image/formats/GenericBitmap.java +73 -0
  213. data/src/main/java/org/sunflow/image/readers/BMPBitmapReader.java +39 -0
  214. data/src/main/java/org/sunflow/image/readers/HDRBitmapReader.java +155 -0
  215. data/src/main/java/org/sunflow/image/readers/IGIBitmapReader.java +104 -0
  216. data/src/main/java/org/sunflow/image/readers/JPGBitmapReader.java +39 -0
  217. data/src/main/java/org/sunflow/image/readers/PNGBitmapReader.java +40 -0
  218. data/src/main/java/org/sunflow/image/readers/TGABitmapReader.java +141 -0
  219. data/src/main/java/org/sunflow/image/writers/EXRBitmapWriter.java +395 -0
  220. data/src/main/java/org/sunflow/image/writers/HDRBitmapWriter.java +54 -0
  221. data/src/main/java/org/sunflow/image/writers/IGIBitmapWriter.java +75 -0
  222. data/src/main/java/org/sunflow/image/writers/PNGBitmapWriter.java +39 -0
  223. data/src/main/java/org/sunflow/image/writers/TGABitmapWriter.java +63 -0
  224. data/src/main/java/org/sunflow/math/BoundingBox.java +340 -0
  225. data/src/main/java/org/sunflow/math/MathUtils.java +159 -0
  226. data/src/main/java/org/sunflow/math/Matrix4.java +573 -0
  227. data/src/main/java/org/sunflow/math/MovingMatrix4.java +119 -0
  228. data/src/main/java/org/sunflow/math/OrthoNormalBasis.java +110 -0
  229. data/src/main/java/org/sunflow/math/PerlinScalar.java +331 -0
  230. data/src/main/java/org/sunflow/math/PerlinVector.java +132 -0
  231. data/src/main/java/org/sunflow/math/Point2.java +36 -0
  232. data/src/main/java/org/sunflow/math/Point3.java +133 -0
  233. data/src/main/java/org/sunflow/math/QMC.java +209 -0
  234. data/src/main/java/org/sunflow/math/Solvers.java +142 -0
  235. data/src/main/java/org/sunflow/math/Vector3.java +197 -0
  236. data/src/main/java/org/sunflow/system/BenchmarkFramework.java +73 -0
  237. data/src/main/java/org/sunflow/system/BenchmarkTest.java +17 -0
  238. data/src/main/java/org/sunflow/system/ByteUtil.java +119 -0
  239. data/src/main/java/org/sunflow/system/FileUtils.java +27 -0
  240. data/src/main/java/org/sunflow/system/ImagePanel.java +282 -0
  241. data/src/main/java/org/sunflow/system/Memory.java +18 -0
  242. data/src/main/java/org/sunflow/system/Parser.java +162 -0
  243. data/src/main/java/org/sunflow/system/Plugins.java +142 -0
  244. data/src/main/java/org/sunflow/system/RenderGlobalsPanel.java +209 -0
  245. data/src/main/java/org/sunflow/system/SearchPath.java +67 -0
  246. data/src/main/java/org/sunflow/system/Timer.java +53 -0
  247. data/src/main/java/org/sunflow/system/UI.java +112 -0
  248. data/src/main/java/org/sunflow/system/UserInterface.java +46 -0
  249. data/src/main/java/org/sunflow/system/ui/ConsoleInterface.java +48 -0
  250. data/src/main/java/org/sunflow/system/ui/SilentInterface.java +28 -0
  251. data/src/main/java/org/sunflow/util/FastHashMap.java +220 -0
  252. data/src/main/java/org/sunflow/util/FloatArray.java +77 -0
  253. data/src/main/java/org/sunflow/util/IntArray.java +77 -0
  254. data/src/test/java/a_maintest.java +129 -0
  255. 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
+ }