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,141 @@
1
+ package org.sunflow.image.readers;
2
+
3
+ import java.io.BufferedInputStream;
4
+ import java.io.FileInputStream;
5
+ import java.io.IOException;
6
+ import java.io.InputStream;
7
+
8
+ import org.sunflow.image.Bitmap;
9
+ import org.sunflow.image.BitmapReader;
10
+ import org.sunflow.image.Color;
11
+ import org.sunflow.image.formats.BitmapG8;
12
+ import org.sunflow.image.formats.BitmapRGB8;
13
+ import org.sunflow.image.formats.BitmapRGBA8;
14
+
15
+ public class TGABitmapReader implements BitmapReader {
16
+
17
+ private static final int[] CHANNEL_INDEX = {2, 1, 0, 3};
18
+
19
+ public Bitmap load(String filename, boolean isLinear) throws IOException, BitmapFormatException {
20
+ InputStream f = new BufferedInputStream(new FileInputStream(filename));
21
+ byte[] read = new byte[4];
22
+
23
+ // read header
24
+ int idsize = f.read();
25
+ int cmaptype = f.read(); // cmap byte (unsupported)
26
+ if (cmaptype != 0) {
27
+ throw new BitmapFormatException(String.format("Colormapping (type: %d) is unsupported", cmaptype));
28
+ }
29
+ int datatype = f.read();
30
+
31
+ // colormap info (5 bytes ignored)
32
+ f.read();
33
+ f.read();
34
+ f.read();
35
+ f.read();
36
+ f.read();
37
+
38
+ f.read(); // xstart, 16 bits (ignored)
39
+ f.read();
40
+ f.read(); // ystart, 16 bits (ignored)
41
+ f.read();
42
+
43
+ // read resolution
44
+ int width = f.read();
45
+ width |= f.read() << 8;
46
+ int height = f.read();
47
+ height |= f.read() << 8;
48
+
49
+ int bits = f.read();
50
+ int bpp = bits / 8;
51
+
52
+ int imgdscr = f.read();
53
+
54
+ // skip image ID if present
55
+ if (idsize != 0) {
56
+ f.skip(idsize);
57
+ }
58
+
59
+ // allocate byte buffer to hold the image
60
+ byte[] pixels = new byte[width * height * bpp];
61
+ if (datatype == 2 || datatype == 3) {
62
+ if (bpp != 1 && bpp != 3 && bpp != 4) {
63
+ throw new BitmapFormatException(String.format("Invalid bit depth in uncompressed TGA: %d", bits));
64
+ }
65
+ // uncompressed image
66
+ for (int ptr = 0; ptr < pixels.length; ptr += bpp) {
67
+ // read bytes
68
+ f.read(read, 0, bpp);
69
+ for (int i = 0; i < bpp; i++) {
70
+ pixels[ptr + CHANNEL_INDEX[i]] = read[i];
71
+ }
72
+ }
73
+ } else if (datatype == 10) {
74
+ if (bpp != 3 && bpp != 4) {
75
+ throw new BitmapFormatException(String.format("Invalid bit depth in run-length encoded TGA: %d", bits));
76
+ }
77
+ // RLE encoded image
78
+ for (int ptr = 0; ptr < pixels.length;) {
79
+ int rle = f.read();
80
+ int num = 1 + (rle & 0x7F);
81
+ if ((rle & 0x80) != 0) {
82
+ // rle packet - decode length and copy pixel
83
+ f.read(read, 0, bpp);
84
+ for (int j = 0; j < num; j++) {
85
+ for (int i = 0; i < bpp; i++) {
86
+ pixels[ptr + CHANNEL_INDEX[i]] = read[i];
87
+ }
88
+ ptr += bpp;
89
+ }
90
+ } else {
91
+ // raw packet - decode length and read pixels
92
+ for (int j = 0; j < num; j++) {
93
+ f.read(read, 0, bpp);
94
+ for (int i = 0; i < bpp; i++) {
95
+ pixels[ptr + CHANNEL_INDEX[i]] = read[i];
96
+ }
97
+ ptr += bpp;
98
+ }
99
+ }
100
+ }
101
+ } else {
102
+ throw new BitmapFormatException(String.format("Unsupported TGA image type: %d", datatype));
103
+ }
104
+
105
+ if (!isLinear) {
106
+ // apply reverse correction
107
+ for (int ptr = 0; ptr < pixels.length; ptr += bpp) {
108
+ for (int i = 0; i < 3 && i < bpp; i++) {
109
+ pixels[ptr + i] = Color.NATIVE_SPACE.rgbToLinear(pixels[ptr + i]);
110
+ }
111
+ }
112
+ }
113
+
114
+ // should image be flipped in Y?
115
+ if ((imgdscr & 32) == 32) {
116
+ for (int y = 0, pix_ptr = 0; y < (height / 2); y++) {
117
+ int bot_ptr = bpp * (height - y - 1) * width;
118
+ for (int x = 0; x < width; x++) {
119
+ for (int i = 0; i < bpp; i++) {
120
+ byte t = pixels[pix_ptr + i];
121
+ pixels[pix_ptr + i] = pixels[bot_ptr + i];
122
+ pixels[bot_ptr + i] = t;
123
+ }
124
+ pix_ptr += bpp;
125
+ bot_ptr += bpp;
126
+ }
127
+ }
128
+
129
+ }
130
+ f.close();
131
+ switch (bpp) {
132
+ case 1:
133
+ return new BitmapG8(width, height, pixels);
134
+ case 3:
135
+ return new BitmapRGB8(width, height, pixels);
136
+ case 4:
137
+ return new BitmapRGBA8(width, height, pixels);
138
+ }
139
+ throw new BitmapFormatException("Inconsistent code in TGA reader");
140
+ }
141
+ }
@@ -0,0 +1,395 @@
1
+ package org.sunflow.image.writers;
2
+
3
+ import java.io.IOException;
4
+ import java.io.RandomAccessFile;
5
+ import java.util.Arrays;
6
+ import java.util.zip.Deflater;
7
+
8
+ import org.sunflow.image.BitmapWriter;
9
+ import org.sunflow.image.Color;
10
+ import org.sunflow.system.ByteUtil;
11
+ import org.sunflow.system.UI;
12
+ import org.sunflow.system.UI.Module;
13
+
14
+ public class EXRBitmapWriter implements BitmapWriter {
15
+
16
+ private static final byte HALF = 1;
17
+ private static final byte FLOAT = 2;
18
+ private static final int HALF_SIZE = 2;
19
+ private static final int FLOAT_SIZE = 4;
20
+ private final static int OE_MAGIC = 20000630;
21
+ private final static int OE_EXR_VERSION = 2;
22
+ private final static int OE_TILED_FLAG = 0x00000200;
23
+ private static final int NO_COMPRESSION = 0;
24
+ private static final int RLE_COMPRESSION = 1;
25
+ private static final int ZIP_COMPRESSION = 3;
26
+ private static final int RLE_MIN_RUN = 3;
27
+ private static final int RLE_MAX_RUN = 127;
28
+ private String filename;
29
+ private RandomAccessFile file;
30
+ private long[][] tileOffsets;
31
+ private long tileOffsetsPosition;
32
+ private int tilesX;
33
+ private int tilesY;
34
+ private int tileSize;
35
+ private int compression;
36
+ private byte channelType;
37
+ private int channelSize;
38
+ private byte[] tmpbuf;
39
+ private byte[] comprbuf;
40
+ final String COMPRESSION = "compression";
41
+
42
+ public EXRBitmapWriter() {
43
+ // default settings
44
+ configure(COMPRESSION, "zip");
45
+ configure("channeltype", "half");
46
+ }
47
+
48
+ @Override
49
+ public final void configure(final String option, String value) {
50
+ if (option.equals(COMPRESSION)) {
51
+ if (value.equals("none")) {
52
+ compression = NO_COMPRESSION;
53
+ } else if (value.equals("rle")) {
54
+ compression = RLE_COMPRESSION;
55
+ } else if (value.equals("zip")) {
56
+ compression = ZIP_COMPRESSION;
57
+ } else {
58
+ UI.printWarning(Module.IMG, "EXR - Compression type was not recognized - defaulting to zip");
59
+ compression = ZIP_COMPRESSION;
60
+ }
61
+ } else if (option.equals("channeltype")) {
62
+ if (value.equals("float")) {
63
+ channelType = FLOAT;
64
+ channelSize = FLOAT_SIZE;
65
+ } else if (value.equals("half")) {
66
+ channelType = HALF;
67
+ channelSize = HALF_SIZE;
68
+ } else {
69
+ UI.printWarning(Module.DISP, "EXR - Channel type was not recognized - defaulting to float");
70
+ channelType = FLOAT;
71
+ channelSize = FLOAT_SIZE;
72
+ }
73
+ }
74
+ }
75
+
76
+ @Override
77
+ public void openFile(String filename) throws IOException {
78
+ this.filename = filename == null ? "output.exr" : filename;
79
+ }
80
+
81
+ @Override
82
+ public void writeHeader(int width, int height, int tileSize) throws IOException, UnsupportedOperationException {
83
+ file = new RandomAccessFile(filename, "rw");
84
+ file.setLength(0);
85
+ if (tileSize <= 0) {
86
+ throw new UnsupportedOperationException("Can't use OpenEXR bitmap writer without buckets.");
87
+ }
88
+ writeRGBAHeader(width, height, tileSize);
89
+ }
90
+
91
+ @Override
92
+ public void writeTile(int x, int y, int w, int h, Color[] color, float[] alpha) throws IOException {
93
+ int tx = x / tileSize;
94
+ int ty = y / tileSize;
95
+ writeEXRTile(tx, ty, w, h, color, alpha);
96
+ }
97
+
98
+ @Override
99
+ public void closeFile() throws IOException {
100
+ writeTileOffsets();
101
+ file.close();
102
+ }
103
+
104
+ private void writeRGBAHeader(int w, int h, int tileSize) throws IOException {
105
+ byte[] chanOut = {0, channelType, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1,
106
+ 0, 0, 0};
107
+
108
+ file.write(ByteUtil.get4Bytes(OE_MAGIC));
109
+
110
+ file.write(ByteUtil.get4Bytes(OE_EXR_VERSION | OE_TILED_FLAG));
111
+
112
+ file.write("channels".getBytes());
113
+ file.write(0);
114
+ file.write("chlist".getBytes());
115
+ file.write(0);
116
+ file.write(ByteUtil.get4Bytes(73));
117
+ file.write("R".getBytes());
118
+ file.write(chanOut);
119
+ file.write("G".getBytes());
120
+ file.write(chanOut);
121
+ file.write("B".getBytes());
122
+ file.write(chanOut);
123
+ file.write("A".getBytes());
124
+ file.write(chanOut);
125
+ file.write(0);
126
+
127
+ // compression
128
+ file.write(COMPRESSION.getBytes());
129
+ file.write(0);
130
+ file.write(COMPRESSION.getBytes());
131
+ file.write(0);
132
+ file.write(1);
133
+ file.write(ByteUtil.get4BytesInv(compression));
134
+
135
+ // datawindow =~ image size
136
+ file.write("dataWindow".getBytes());
137
+ file.write(0);
138
+ file.write("box2i".getBytes());
139
+ file.write(0);
140
+ file.write(ByteUtil.get4Bytes(0x10));
141
+ file.write(ByteUtil.get4Bytes(0));
142
+ file.write(ByteUtil.get4Bytes(0));
143
+ file.write(ByteUtil.get4Bytes(w - 1));
144
+ file.write(ByteUtil.get4Bytes(h - 1));
145
+
146
+ // dispwindow -> look at openexr.com for more info
147
+ file.write("displayWindow".getBytes());
148
+ file.write(0);
149
+ file.write("box2i".getBytes());
150
+ file.write(0);
151
+ file.write(ByteUtil.get4Bytes(0x10));
152
+ file.write(ByteUtil.get4Bytes(0));
153
+ file.write(ByteUtil.get4Bytes(0));
154
+ file.write(ByteUtil.get4Bytes(w - 1));
155
+ file.write(ByteUtil.get4Bytes(h - 1));
156
+
157
+ /*
158
+ * lines in increasing y order = 0 decreasing would be 1
159
+ */
160
+ file.write("lineOrder".getBytes());
161
+ file.write(0);
162
+ file.write("lineOrder".getBytes());
163
+ file.write(0);
164
+ file.write(1);
165
+ file.write(ByteUtil.get4BytesInv(2));
166
+
167
+ file.write("pixelAspectRatio".getBytes());
168
+ file.write(0);
169
+ file.write("float".getBytes());
170
+ file.write(0);
171
+ file.write(ByteUtil.get4Bytes(4));
172
+ file.write(ByteUtil.get4Bytes(Float.floatToIntBits(1)));
173
+
174
+ // meaningless to a flat (2D) image
175
+ file.write("screenWindowCenter".getBytes());
176
+ file.write(0);
177
+ file.write("v2f".getBytes());
178
+ file.write(0);
179
+ file.write(ByteUtil.get4Bytes(8));
180
+ file.write(ByteUtil.get4Bytes(Float.floatToIntBits(0)));
181
+ file.write(ByteUtil.get4Bytes(Float.floatToIntBits(0)));
182
+
183
+ // meaningless to a flat (2D) image
184
+ file.write("screenWindowWidth".getBytes());
185
+ file.write(0);
186
+ file.write("float".getBytes());
187
+ file.write(0);
188
+ file.write(ByteUtil.get4Bytes(4));
189
+ file.write(ByteUtil.get4Bytes(Float.floatToIntBits(1)));
190
+
191
+ this.tileSize = tileSize;
192
+
193
+ tilesX = ((w + tileSize - 1) / tileSize);
194
+ tilesY = ((h + tileSize - 1) / tileSize);
195
+
196
+ /*
197
+ * twice the space for the compressing buffer, as for ex. the compressor
198
+ * can actually increase the size of the data :) If that happens though,
199
+ * it is not saved into the file, but discarded
200
+ */
201
+ tmpbuf = new byte[tileSize * tileSize * channelSize * 4];
202
+ comprbuf = new byte[tileSize * tileSize * channelSize * 4 * 2];
203
+
204
+ tileOffsets = new long[tilesX][tilesY];
205
+
206
+ file.write("tiles".getBytes());
207
+ file.write(0);
208
+ file.write("tiledesc".getBytes());
209
+ file.write(0);
210
+ file.write(ByteUtil.get4Bytes(9));
211
+
212
+ file.write(ByteUtil.get4Bytes(tileSize));
213
+ file.write(ByteUtil.get4Bytes(tileSize));
214
+
215
+ // ONE_LEVEL tiles, ROUNDING_MODE = not important
216
+ file.write(0);
217
+
218
+ // an attribute with a name of 0 to end the list
219
+ file.write(0);
220
+
221
+ // save a pointer to where the tileOffsets are stored and write dummy
222
+ // fillers for now
223
+ tileOffsetsPosition = file.getFilePointer();
224
+ writeTileOffsets();
225
+ }
226
+
227
+ private void writeTileOffsets() throws IOException {
228
+ file.seek(tileOffsetsPosition);
229
+ for (int ty = 0; ty < tilesY; ty++) {
230
+ for (int tx = 0; tx < tilesX; tx++) {
231
+ file.write(ByteUtil.get8Bytes(tileOffsets[tx][ty]));
232
+ }
233
+ }
234
+ }
235
+
236
+ private synchronized void writeEXRTile(int tileX, int tileY, int w, int h, Color[] tile, float[] alpha) throws IOException {
237
+ byte[] rgb;
238
+
239
+ // setting comprSize to max integer so without compression things
240
+ // don't go awry
241
+ int pixptr = 0, writeSize = 0, comprSize = Integer.MAX_VALUE;
242
+ int tileRangeX = (tileSize < w) ? tileSize : w;
243
+ int tileRangeY = (tileSize < h) ? tileSize : h;
244
+ int channelBase = tileRangeX * channelSize;
245
+
246
+ // lets see if the alignment matches, you can comment this out if
247
+ // need be
248
+ if ((tileSize != tileRangeX) && (tileX == 0)) {
249
+ System.out.print(" bad X alignment ");
250
+ }
251
+ if ((tileSize != tileRangeY) && (tileY == 0)) {
252
+ System.out.print(" bad Y alignment ");
253
+ }
254
+
255
+ tileOffsets[tileX][tileY] = file.getFilePointer();
256
+
257
+ // the tile header: tile's x&y coordinate, levels x&y coordinate and
258
+ // tilesize
259
+ file.write(ByteUtil.get4Bytes(tileX));
260
+ file.write(ByteUtil.get4Bytes(tileY));
261
+ file.write(ByteUtil.get4Bytes(0));
262
+ file.write(ByteUtil.get4Bytes(0));
263
+
264
+ // just in case
265
+ Arrays.fill(tmpbuf, (byte) 0);
266
+
267
+ for (int ty = 0; ty < tileRangeY; ty++) {
268
+ for (int tx = 0; tx < tileRangeX; tx++) {
269
+ float[] rgbf = tile[tx + ty * tileRangeX].getRGB();
270
+ if (channelType == FLOAT) {
271
+ rgb = ByteUtil.get4Bytes(Float.floatToRawIntBits(alpha[tx + ty * tileRangeX]));
272
+ tmpbuf[pixptr + 0] = rgb[0];
273
+ tmpbuf[pixptr + 1] = rgb[1];
274
+ tmpbuf[pixptr + 2] = rgb[2];
275
+ tmpbuf[pixptr + 3] = rgb[3];
276
+ } else if (channelType == HALF) {
277
+ rgb = ByteUtil.get2Bytes(ByteUtil.floatToHalf(alpha[tx + ty * tileRangeX]));
278
+ tmpbuf[pixptr + 0] = rgb[0];
279
+ tmpbuf[pixptr + 1] = rgb[1];
280
+ }
281
+ for (int component = 1; component <= 3; component++) {
282
+ if (channelType == FLOAT) {
283
+ rgb = ByteUtil.get4Bytes(Float.floatToRawIntBits(rgbf[3 - component]));
284
+ tmpbuf[(channelBase * component) + pixptr + 0] = rgb[0];
285
+ tmpbuf[(channelBase * component) + pixptr + 1] = rgb[1];
286
+ tmpbuf[(channelBase * component) + pixptr + 2] = rgb[2];
287
+ tmpbuf[(channelBase * component) + pixptr + 3] = rgb[3];
288
+ } else if (channelType == HALF) {
289
+ rgb = ByteUtil.get2Bytes(ByteUtil.floatToHalf(rgbf[3 - component]));
290
+ tmpbuf[(channelBase * component) + pixptr + 0] = rgb[0];
291
+ tmpbuf[(channelBase * component) + pixptr + 1] = rgb[1];
292
+ }
293
+ }
294
+ pixptr += channelSize;
295
+ }
296
+ pixptr += (tileRangeX * channelSize * 3);
297
+ }
298
+
299
+ writeSize = tileRangeX * tileRangeY * channelSize * 4;
300
+
301
+ if (compression != NO_COMPRESSION) {
302
+ comprSize = compress(compression, tmpbuf, writeSize, comprbuf);
303
+ }
304
+
305
+ // lastly, write the size of the tile and the tile itself
306
+ // (compressed or not)
307
+ if (comprSize < writeSize) {
308
+ file.write(ByteUtil.get4Bytes(comprSize));
309
+ file.write(comprbuf, 0, comprSize);
310
+ } else {
311
+ file.write(ByteUtil.get4Bytes(writeSize));
312
+ file.write(tmpbuf, 0, writeSize);
313
+ }
314
+ }
315
+
316
+ private static int compress(int tp, byte[] in, int inSize, byte[] out) {
317
+ if (inSize == 0) {
318
+ return 0;
319
+ }
320
+
321
+ int t1 = 0, t2 = (inSize + 1) / 2;
322
+ int inPtr = 0, ret;
323
+ byte[] tmp = new byte[inSize];
324
+
325
+ // zip and rle treat the data first, in the same way so I'm not
326
+ // repeating the code
327
+ if ((tp == ZIP_COMPRESSION) || (tp == RLE_COMPRESSION)) {
328
+ // reorder the pixel data ~ straight from ImfZipCompressor.cpp :)
329
+ while (true) {
330
+ if (inPtr < inSize) {
331
+ tmp[t1++] = in[inPtr++];
332
+ } else {
333
+ break;
334
+ }
335
+
336
+ if (inPtr < inSize) {
337
+ tmp[t2++] = in[inPtr++];
338
+ } else {
339
+ break;
340
+ }
341
+ }
342
+
343
+ // Predictor ~ straight from ImfZipCompressor.cpp :)
344
+ t1 = 1;
345
+ int p = tmp[t1 - 1];
346
+ while (t1 < inSize) {
347
+ int d = tmp[t1] - p + (128 + 256);
348
+ p = tmp[t1];
349
+ tmp[t1] = (byte) d;
350
+ t1++;
351
+ }
352
+ }
353
+
354
+ // We'll just jump from here to the wanted compress/decompress stuff if
355
+ // need be
356
+ switch (tp) {
357
+ case ZIP_COMPRESSION:
358
+ Deflater def = new Deflater(Deflater.DEFAULT_COMPRESSION, false);
359
+ def.setInput(tmp, 0, inSize);
360
+ def.finish();
361
+ ret = def.deflate(out);
362
+ return ret;
363
+ case RLE_COMPRESSION:
364
+ return rleCompress(tmp, inSize, out);
365
+ default:
366
+ return -1;
367
+ }
368
+ }
369
+
370
+ private static int rleCompress(byte[] in, int inLen, byte[] out) {
371
+ int runStart = 0, runEnd = 1, outWrite = 0;
372
+ while (runStart < inLen) {
373
+ while (runEnd < inLen && in[runStart] == in[runEnd] && (runEnd - runStart - 1) < RLE_MAX_RUN) {
374
+ runEnd++;
375
+ }
376
+ if (runEnd - runStart >= RLE_MIN_RUN) {
377
+ // Compressable run
378
+ out[outWrite++] = (byte) ((runEnd - runStart) - 1);
379
+ out[outWrite++] = in[runStart];
380
+ runStart = runEnd;
381
+ } else {
382
+ // Uncompressable run
383
+ while (runEnd < inLen && (((runEnd + 1) >= inLen || in[runEnd] != in[runEnd + 1]) || ((runEnd + 2) >= inLen || in[runEnd + 1] != in[runEnd + 2])) && (runEnd - runStart) < RLE_MAX_RUN) {
384
+ runEnd++;
385
+ }
386
+ out[outWrite++] = (byte) (runStart - runEnd);
387
+ while (runStart < runEnd) {
388
+ out[outWrite++] = in[runStart++];
389
+ }
390
+ }
391
+ runEnd++;
392
+ }
393
+ return outWrite;
394
+ }
395
+ }