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.
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
+ }