diff --git a/README.md b/README.md index ae6088d..2b524f5 100644 --- a/README.md +++ b/README.md @@ -1,163 +1,160 @@ CIS 565 Project3 : CUDA Pathtracer =================== -Fall 2014 - -Due Wed, 10/8 (submit without penalty until Sun, 10/12) ## INTRODUCTION -In this project, you will implement a CUDA based pathtracer capable of -generating pathtraced rendered images extremely quickly. Building a pathtracer can be viewed as a generalization of building a raytracer, so for those of you who have taken 460/560, the basic concept should not be very new to you. For those of you that have not taken -CIS460/560, raytracing is a technique for generating images by tracing rays of -light through pixels in an image plane out into a scene and following the way -the rays of light bounce and interact with objects in the scene. More -information can be found here: -http://en.wikipedia.org/wiki/Ray_tracing_(graphics). Pathtracing is a generalization of this technique by considering more than just the contribution of direct lighting to a surface. - -Since in this class we are concerned with working in generating actual images -and less so with mundane tasks like file I/O, this project includes basecode -for loading a scene description file format, described below, and various other -things that generally make up the render "harness" that takes care of -everything up to the rendering itself. The core renderer is left for you to -implement. Finally, note that while this basecode is meant to serve as a -strong starting point for a CUDA pathtracer, you are not required to use this -basecode if you wish, and you may also change any part of the basecode -specification as you please, so long as the final rendered result is correct. - -## CONTENTS -The Project3 root directory contains the following subdirectories: +This is a CUDA based Monte-Carlo Path tracer that renders images of different objects(sphere, cube, obj file) +in various materials including diffuse, reflection, refraction, and more in the future. The render window will show +real-time rendering progress (like other renderers do:) ), and camera angle can be changed at real-time to allow interesting shots! +To run my code in visual studio, press "ctrl+F5 ", sometimes, the renderer will stuck at 46 frame for certain scene (for instance, myScene.txt) but sometimes it works perfectly if restart the rendering without changing anything. So just keep trying. +I definitely need to fix this in the future. + +## BACIC FEATURES + +* Raycasting from a camera into a scene through a pixel grid + Using jittered coordinates to achieve Anti-Aliasing, and this effect is obvious when using small resolution, and less obvious when using large resolution. -* src/ contains the source code for the project. Both the Windows Visual Studio - solution and the OSX and Linux makefiles reference this folder for all - source; the base source code compiles on Linux, OSX and Windows without - modification. If you are building on OSX, be sure to uncomment lines 4 & 5 of - the CMakeLists.txt in order to make sure CMake builds against clang. -* data/scenes/ contains an example scene description file. -* renders/ contains an example render of the given example scene file. -* windows/ contains a Windows Visual Studio 2010 project and all dependencies - needed for building and running on Windows 7. If you would like to create a - Visual Studio 2012 or 2013 projects, there are static libraries that you can - use for GLFW that are in external/bin/GLFW (Visual Studio 2012 uses msvc110, - and Visual Studio 2013 uses msvc120) -* external/ contains all the header, static libraries and built binaries for - 3rd party libraries (i.e. glm, GLEW, GLFW) that we use for windowing and OpenGL - extensions - -## RUNNING THE CODE -The main function requires a scene description file (that is provided in data/scenes). -The main function reads in the scene file by an argument as such : -'scene=[sceneFileName]' - -If you are using Visual Studio, you can set this in the Debugging > Command Arguments section -in the Project properties. - -## REQUIREMENTS -In this project, you are given code for: - -* Loading, reading, and storing the scene scene description format -* Example functions that can run on both the CPU and GPU for generating random - numbers, spherical intersection testing, and surface point sampling on cubes -* A class for handling image operations and saving images -* Working code for CUDA-GL interop - -You will need to implement the following features: - -* Raycasting from a camera into a scene through a pixel grid -* Diffuse surfaces -* Perfect specular reflective surfaces -* Cube intersection testing -* Sphere surface point sampling -* Stream compaction optimization - -You are also required to implement at least 2 of the following features: - -* Texture mapping -* Bump mapping -* Depth of field -* Refraction, i.e. glass -* OBJ Mesh loading and rendering -* Interactive camera -* Motion blur -* Subsurface scattering - -The 'extra features' list is not comprehensive. If you have a particular feature -you would like to implement (e.g. acceleration structures, etc.) please contact us -first! - -For each 'extra feature' you must provide the following analysis : -* overview write up of the feature -* performance impact of the feature -* if you did something to accelerate the feature, why did you do what you did -* compare your GPU version to a CPU version of this feature (you do NOT need to - implement a CPU version) -* how can this feature be further optimized (again, not necessary to implement it, but - should give a roadmap of how to further optimize and why you believe this is the next - step) - -## BASE CODE TOUR -You will be working in three files: raytraceKernel.cu, intersections.h, and -interactions.h. Within these files, areas that you need to complete are marked -with a TODO comment. Areas that are useful to and serve as hints for optional -features are marked with TODO (Optional). Functions that are useful for -reference are marked with the comment LOOK. - -* raytraceKernel.cu contains the core raytracing CUDA kernel. You will need to - complete: - * cudaRaytraceCore() handles kernel launches and memory management; this - function already contains example code for launching kernels, - transferring geometry and cameras from the host to the device, and transferring - image buffers from the host to the device and back. You will have to complete - this function to support passing materials and lights to CUDA. - * raycastFromCameraKernel() is a function that you need to implement. This - function once correctly implemented should handle camera raycasting. - * raytraceRay() is the core raytracing CUDA kernel; all of your pathtracing - logic should be implemented in this CUDA kernel. raytraceRay() should - take in a camera, image buffer, geometry, materials, and lights, and should - trace a ray through the scene and write the resultant color to a pixel in the - image buffer. - -* intersections.h contains functions for geometry intersection testing and - point generation. You will need to complete: - * boxIntersectionTest(), which takes in a box and a ray and performs an - intersection test. This function should work in the same way as - sphereIntersectionTest(). - * getRandomPointOnSphere(), which takes in a sphere and returns a random - point on the surface of the sphere with an even probability distribution. - This function should work in the same way as getRandomPointOnCube(). You can - (although do not necessarily have to) use this to generate points on a sphere - to use a point lights, or can use this for area lighting. - -* interactions.h contains functions for ray-object interactions that define how - rays behave upon hitting materials and objects. You will need to complete: - * getRandomDirectionInSphere(), which generates a random direction in a - sphere with a uniform probability. This function works in a fashion - similar to that of calculateRandomDirectionInHemisphere(), which generates a - random cosine-weighted direction in a hemisphere. - * calculateBSDF(), which takes in an incoming ray, normal, material, and - other information, and returns an outgoing ray. You can either implement - this function for ray-surface interactions, or you can replace it with your own - function(s). - -You will also want to familiarize yourself with: - -* sceneStructs.h, which contains definitions for how geometry, materials, - lights, cameras, and animation frames are stored in the renderer. -* utilities.h, which serves as a kitchen-sink of useful functions - -## NOTES ON GLM -This project uses GLM, the GL Math library, for linear algebra. You need to -know two important points on how GLM is used in this project: - -* In this project, indices in GLM vectors (such as vec3, vec4), are accessed - via swizzling. So, instead of v[0], v.x is used, and instead of v[1], v.y is - used, and so on and so forth. -* GLM Matrix operations work fine on NVIDIA Fermi cards and later, but - pre-Fermi cards do not play nice with GLM matrices. As such, in this project, - GLM matrices are replaced with a custom matrix struct, called a cudaMat4, found - in cudaMat4.h. A custom function for multiplying glm::vec4s and cudaMat4s is - provided as multiplyMV() in intersections.h. - -## SCENE FORMAT +* Diffuse surfaces +Using Hemi sphere sampling to cast secondary diffuse rays. I used Importance Sampling (cos weighted) to reduce noise and speed up convergence. +shading is done by simplest Lambert BRDF. + +* Perfect specular reflective surfaces +Calculating reflected secondary ray by vector math + +* Cube intersection testing +My cube intersection is based on +http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ + +* Sphere surface point sampling +Monte-Carlo Sampling. + +* Stream compaction optimization +Stream compaction was done by thrust, fast and reliable:) +This can be turned on or off by defining "STREAM_COMPACTION" in "raytracerKernel.h" +The maximum limit of ray depth impacts the rendered speed, and this limit can be set in "MAX_DEPTH" in "raytracerKernel.h" + +The comparison between using and not using stream compaction is shown below +![](windows/Project3-Pathtracer/Project3-Pathtracer/Comparison.png) + + +## ADVANCED FEATURES + +## Refraction, i.e. glass +Refraction was done based on snell's law and fresnel equation. +Using good index of refraction will produce beautiful refractions. +Both clear glass or colored glass can be handled here. Wondering doing some frosted glass(play with transparency)in the future. +The picture below shows three material - diffuse, highly reflective, and refractive glass. +![](windows/Project3-Pathtracer/Project3-Pathtracer/Best6_Materials.bmp) + +##Texture Mapping +Image loading is done through FreeImage. Basic texture mapping for cube and sphere is done. +![](windows/Project3-Pathtracer/Project3-Pathtracer/Best0_Sharp_Texture2.bmp) +![](windows/Project3-Pathtracer/Project3-Pathtracer/Best7_Texture.bmp) + +##Depth of field +Depth of filed was achieved by offsetting initial pinhole ray origin based on camera aperture, and re-calculate the ray direction based on previous focal plane intersecting point. +Thus, the ray casting mimics the lens-based camera and produces depth of field effect where objects out of focus is blurred. + +Turning on/off "DEPTH_OF_FIELD" in "raytracerKernel.h" will switch the effect on/off + +REMEMBER to specify camera "FOCAL" and "APERTURE" in scene txt file no matter using Depth of Field or not, like illustrated below, otherwise my program will have error in reading txt file lines + +CAMERA +RES 800 800 +FOVY 35 +ITERATIONS 5000 +FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 +frame 0 +EYE 0 4.5 8 +VIEW 0 0 -1 +UP 0 1 0 + +Choosing good focal length and aperture is essential to create realistic depth of field. +I have three rendered image as below, first everything is in focus (without depth of field), +second with longer focal length, so further objects are in focus, the third with shorter focal length, hence nearer objects are in focus. +![](windows/Project3-Pathtracer/Project3-Pathtracer/Best0_Sharp.bmp) +![](windows/Project3-Pathtracer/Project3-Pathtracer/Best1_DepthOfField.bmp) +![](windows/Project3-Pathtracer/Project3-Pathtracer/Best2_DepthOfField.bmp) + +##OBJ Mesh loading and rendering +OBJ loading is possible with the help of "TinyObjLoader" by https://github.com/syoyo/tinyobjloader. +The obj data is parsed "mesh" with both "indices" and "positions". This saved me a lot of time in reading the obj file. + +Then I created a structure "triangle" to handle face structure of mesh, and during intersection test, +each of triangle will only be tested if the bounding box is intersecting the ray. This is very important as it will take A LOT OF TIME without bounding box intersection. + +But, my renderer can only handle one obj instead of multiple obj, at current stage. (i.e only one objects in the scene can be specified by obj file, not more. +but with other basic shape like sphere or cube is okay.) As I failed in adding the list of triangle to the member of "geom" and readable by CUDA. +This can be solved by expanding my current global array of triangle to an array of triangle list. I should implement this in the near future. + +In order to load obj, speify the scene file as below. REMEMBER to include FULL PATH for the obj file, so that TinyObjLoader can correctly finds the file. +I have two renders below, 166 and 437 triangle faces respectively, each took 40 minutes, and 80 minutes to render, which is still too slow for a renderer. +In the future, I should implement Kd tree to speed up the rendering for polygonal meshes. + +OBJECT 5 +C:\Users\AppleDu\Documents\GitHub\Project3-Pathtracer\data\scenes\hexGem.obj +material 5 +frame 0 +TRANS 0 1.1 -0.5 +ROTAT 0 0 0 +SCALE 4 4 4 + +![](windows/Project3-Pathtracer/Project3-Pathtracer/Best4_Diamond.bmp) +![](windows/Project3-Pathtracer/Project3-Pathtracer/Best5b_Crystal.bmp) + +##Interactive camera +Interactive Camera is implemented to provide flexible in rendering angles, including pan, tilt, zoom, everything. +Play with camera like a camera man! :) Rendering will start fresh every time camera is changed. This allows interactive adjustment to camera angle, and make interesting shots possible. + +"STEP_SIZE" specifies the step size of camera movements, and can be changed in "main.h". +The keyboard interaction during run-time is as specified below. In the future, I will include real-time modification of camera focal length and aperture as well, so that I can produce a good and realistic depth of field effect. + +* W - move up +* Q - move down +* S - move left +* D - move right +* Q - move forward (zoom in) +* E - move backward (zoom out) +* up - rotate up +* down - rotate down +* left - rotate left +* right - rotate right +* , - rotate CCW +* . - rotate CW +![](windows/Project3-Pathtracer/Project3-Pathtracer/Best3_Depth_and_Camera_moving.bmp) +[![ScreenShot](windows/Project3-Pathtracer/Project3-Pathtracer/YoutubeThumbnail.png)] (http://www.youtube.com/embed/RtjJXwnUBZo) + +##Compare to CPU Ray Tracer +There are tons of advantages this rendered has over the CPU raytracer, such as +* Much faster! +* Real-time Rendering +* Global Illumination ( Color Bleeding, Soft Shadow, & Caustics! ) +* Realistic Rendering ( BRDF ) + +## SCENE FORMAT +In order to use my program, "FOCAL" and "APERTURE" MUST be specified for camera in the scene file, +though depth of field may not be turned on. This is to ensure correctness of reading in scene txt file. +I have some scene files that are interesting to render: +* sampleScene.txt +Original file + +* myScene.txt +There is diffuse item, highly reflective item, glass item, depth of field. +with only one cube for Anti-Aliasing test + +* myScene1.txt +Demonstrating basic materials - diffuse, reflection, and refraction + +* myScene2.txt +Diamond obj with white glass material + +* myScene3.txt +Crystal obj with blue glass material + + +************************************************************ This project uses a custom scene description format. Scene files are flat text files that describe all geometry, materials, lights, cameras, render settings, and animation frames inside of the scene. @@ -216,58 +213,4 @@ Objects are defined in the following fashion: * ROTAT (float rotationx) (float rotationy) (float rotationz) //rotation * SCALE (float scalex) (float scaley) (float scalez) //scale -An example scene file setting up two frames inside of a Cornell Box can be -found in the scenes/ directory. - -For meshes, note that the base code will only read in .obj files. For more -information on the .obj specification see http://en.wikipedia.org/wiki/Wavefront_.obj_file. - -An example of a mesh object is as follows: - -OBJECT 0 -mesh tetra.obj -material 0 -frame 0 -TRANS 0 5 -5 -ROTAT 0 90 0 -SCALE .01 10 10 - -Check the Google group for some sample .obj files of varying complexity. - -## THIRD PARTY CODE POLICY -* Use of any third-party code must be approved by asking on our Google Group. - If it is approved, all students are welcome to use it. Generally, we approve - use of third-party code that is not a core part of the project. For example, - for the ray tracer, we would approve using a third-party library for loading - models, but would not approve copying and pasting a CUDA function for doing - refraction. -* Third-party code must be credited in README.md. -* Using third-party code without its approval, including using another - student's code, is an academic integrity violation, and will result in you - receiving an F for the semester. - -## SELF-GRADING -* On the submission date, email your grade, on a scale of 0 to 100, to Harmony, - harmoli+cis565@seas.upenn.com, with a one paragraph explanation. Be concise and - realistic. Recall that we reserve 30 points as a sanity check to adjust your - grade. Your actual grade will be (0.7 * your grade) + (0.3 * our grade). We - hope to only use this in extreme cases when your grade does not realistically - reflect your work - it is either too high or too low. In most cases, we plan - to give you the exact grade you suggest. -* Projects are not weighted evenly, e.g., Project 0 doesn't count as much as - the path tracer. We will determine the weighting at the end of the semester - based on the size of each project. - -## SUBMISSION -Please change the README to reflect the answers to the questions we have posed -above. Remember: -* this is a renderer, so include images that you've made! -* be sure to back your claims for optimization with numbers and comparisons -* if you reference any other material, please provide a link to it -* you wil not e graded on how fast your path tracer runs, but getting close to - real-time is always nice -* if you have a fast GPU renderer, it is good to show case this with a video to - show interactivity. If you do so, please include a link. - -Be sure to open a pull request and to send Harmony your grade and why you -believe this is the grade you should get. + diff --git a/data/scenes/myScene.txt b/data/scenes/myScene.txt new file mode 100644 index 0000000..db76032 --- /dev/null +++ b/data/scenes/myScene.txt @@ -0,0 +1,280 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 3 //blue glass +RGB .6 .4 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 4 //purple glossy +RGB .6 .2 .8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //blue glossy +RGB .0 .8 .8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //pink light +RGB 1 .42 .71 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 1 +REFRIOR 0 +SCATTER 1.5 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 9 + +MATERIAL 8 //white light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 30 + +MATERIAL 9 //chrome +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 10 //yellow diffuse +RGB .9 .9 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 11 //specular gold +RGB .93 .88 .38 +SPECEX 15 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0.372 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + + +CAMERA +RES 800 800 +FOVY 35 +ITERATIONS 5000 +FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 +frame 0 +EYE 0 4.5 8 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 0 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 2 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 1 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +sphere +material 3 +frame 0 +TRANS 0 1.1 -0.5 +ROTAT 0 45 45 +SCALE 2 2 2 + +OBJECT 6 +sphere +material 9 +frame 0 +TRANS -2.5 1.75 0.1 +ROTAT 0 180 0 +SCALE 2.5 2.5 2.5 + +OBJECT 7 +cube +material 10 +frame 0 +TRANS -2.2 2 -2 +ROTAT 0 45 0 +SCALE 1.5 4 1.5 + + +OBJECT 8 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 + +OBJECT 9 +cube +material 6 +frame 0 +TRANS 0 5 -5 +ROTAT 0 0 0 +SCALE 8 10 0.2 + +OBJECT 10 +sphere +material 4 +frame 0 +TRANS -2.2 5 -2 +ROTAT 0 0 0 +SCALE 2 2 2 + + +OBJECT 11 +sphere +material 7 +frame 0 +TRANS 3.5 7 -3 +ROTAT 0 0 0 +SCALE 1.5 1.5 1.5 + + +OBJECT 12 +cube +material 10 +frame 0 +TRANS 3.5 3.5 -3 +ROTAT 0 35 0 +SCALE 0.2 7 0.2 + + +OBJECT 13 +sphere +material 5 +frame 0 +TRANS 1 2.8 -0.5 +ROTAT 0 0 0 +SCALE 2 2 2 + +OBJECT 14 +sphere +material 5 +frame 0 +TRANS 2 1.1 -0.5 +ROTAT 0 45 45 +SCALE 2 2 2 \ No newline at end of file diff --git a/data/scenes/myScene0.txt b/data/scenes/myScene0.txt new file mode 100644 index 0000000..b1b723c --- /dev/null +++ b/data/scenes/myScene0.txt @@ -0,0 +1,189 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 3 //red glossy +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 4 //white glossy +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //green glossy +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 1 + +MATERIAL 8 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 15 + +MATERIAL 9 //yellow diffuse +RGB .9 .9 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +CAMERA +RES 800 800 +FOVY 35 +ITERATIONS 1000 +FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 +frame 0 +EYE 0 4.5 8 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 0 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 2 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 1 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +cube +material 9 +frame 0 +TRANS 0 4 0 +ROTAT 0 45 45 +SCALE 4 4 4 + + + +OBJECT 6 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 \ No newline at end of file diff --git a/data/scenes/myScene1.txt b/data/scenes/myScene1.txt new file mode 100644 index 0000000..9cdd57a --- /dev/null +++ b/data/scenes/myScene1.txt @@ -0,0 +1,205 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 3 //red glossy +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 4 //white glossy +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //green glossy +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 1 + +MATERIAL 8 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 15 + +MATERIAL 9 //yellow diffuse +RGB .9 .9 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + + +CAMERA +RES 800 800 +FOVY 35 +ITERATIONS 5000 +FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 +frame 0 +EYE 0 4.5 8 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 0 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 2 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 1 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +cube +material 9 +frame 0 +TRANS 0 2 0 +ROTAT 0 45 45 +SCALE 2 2 2 + +OBJECT 6 +sphere +material 6 +frame 0 +TRANS 2 5 2 +ROTAT 0 180 0 +SCALE 2.5 2.5 2.5 + +OBJECT 7 +sphere +material 5 +frame 0 +TRANS -2 5 -2 +ROTAT 0 180 0 +SCALE 3 3 3 + + +OBJECT 8 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 \ No newline at end of file diff --git a/data/scenes/myScene1Texture.txt b/data/scenes/myScene1Texture.txt new file mode 100644 index 0000000..4c9ea7a --- /dev/null +++ b/data/scenes/myScene1Texture.txt @@ -0,0 +1,221 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 3 //blue glossy +RGB .0 .8 .8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 4 //white glossy +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //pink glass +RGB 1 .41 .71 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 7 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 1 + +MATERIAL 8 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 30 + +MATERIAL 9 //yellow diffuse +RGB .9 .9 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + + +CAMERA +RES 800 800 +FOVY 35 +ITERATIONS 3000 +FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 +frame 0 +EYE 0 4.5 8 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material -1 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material -4 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material -4 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material -4 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +cube +material -3 +frame 0 +TRANS -1.3 1.7 0 +ROTAT 0 45 45 +SCALE 1.8 1.8 1.8 + +OBJECT 6 +sphere +material -2 +frame 0 +TRANS -2 4 -2 +ROTAT 0 20 0 +SCALE 3 3 3 + +OBJECT 7 +sphere +material 6 +frame 0 +TRANS 1.5 1.15 -0.5 +ROTAT 0 0 0 +SCALE 2.1 2.1 2.1 + + +OBJECT 8 +sphere +material 5 +frame 0 +TRANS 1.5 2.95 -0.5 +ROTAT 0 0 0 +SCALE 1.4 1.4 1.4 + +OBJECT 9 +cube +material 3 +frame 0 +TRANS 0 5 -5 +ROTAT 0 0 0 +SCALE 8 10 0.2 + +OBJECT 10 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 \ No newline at end of file diff --git a/data/scenes/myScene2.txt b/data/scenes/myScene2.txt new file mode 100644 index 0000000..78f19c9 --- /dev/null +++ b/data/scenes/myScene2.txt @@ -0,0 +1,208 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 3 //blue glass +RGB 0.6 0.4 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 4 //purple glossy +RGB 0.6 0.2 0.8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //blue glossy +RGB .0 .8 .8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //pink light +RGB 1 0.42 0.71 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 1 +REFRIOR 0 +SCATTER 1.5 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 9 + +MATERIAL 8 //white light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 24 + +MATERIAL 9 //chrome +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 10 //yellow diffuse +RGB .9 .9 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + + +CAMERA +RES 800 800 +FOVY 35 +ITERATIONS 5000 +FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 +frame 0 +EYE 0 4.5 8 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 0 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 2 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 1 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +C:\Users\AppleDu\Documents\GitHub\Project3-Pathtracer\data\scenes\hexGem.obj +material 5 +frame 0 +TRANS 0 1.1 -0.5 +ROTAT 0 0 0 +SCALE 4 4 4 + +OBJECT 6 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 4 4 + +OBJECT 7 +cube +material 6 +frame 0 +TRANS 0 5 -5 +ROTAT 0 0 0 +SCALE 8 10 0.2 diff --git a/data/scenes/myScene3.txt b/data/scenes/myScene3.txt new file mode 100644 index 0000000..8dec964 --- /dev/null +++ b/data/scenes/myScene3.txt @@ -0,0 +1,201 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 3 //blue glass +RGB 0.6 0.4 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 4 //green glossy +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //blue glossy +RGB .0 .8 .8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //pink light +RGB 1 0.42 0.71 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 1 +REFRIOR 0 +SCATTER 1.5 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 9 + +MATERIAL 8 //white light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 24 + +MATERIAL 9 //chrome +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 10 //yellow diffuse +RGB .9 .9 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + + +CAMERA +RES 800 800 +FOVY 35 +ITERATIONS 5000 +FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 +frame 0 +EYE 0 5 12 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 0 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 6 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 4 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +C:\Users\AppleDu\Documents\GitHub\Project3-Pathtracer\data\scenes\crystal1.obj +material 3 +frame 0 +TRANS 0 0.5 -0.5 +ROTAT 0 -45 0 +SCALE 9 9 9 + +OBJECT 6 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 4 4 + diff --git a/data/scenes/mySceneTexture.txt b/data/scenes/mySceneTexture.txt new file mode 100644 index 0000000..6b2e540 --- /dev/null +++ b/data/scenes/mySceneTexture.txt @@ -0,0 +1,292 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 3 //blue glass +RGB .6 .4 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 4 //purple glossy +RGB .6 .2 .8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //blue glossy +RGB .0 .8 .8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //pink light +RGB 1 .42 .71 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 1 +REFRIOR 0 +SCATTER 1.5 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 9 + +MATERIAL 8 //white light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 30 + +MATERIAL 9 //chrome +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 10 //yellow diffuse +RGB .9 .9 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 11 //specular gold +RGB .93 .88 .38 +SPECEX 15 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0.372 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 12 //texture +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + + +CAMERA +RES 800 800 +FOVY 35 +ITERATIONS 3000 +FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 +frame 0 +EYE 0 4.5 8 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material -1 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 2 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 1 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +sphere +material 3 +frame 0 +TRANS 0 1.1 -0.5 +ROTAT 0 45 45 +SCALE 2 2 2 + +OBJECT 6 +sphere +material 9 +frame 0 +TRANS -2.5 1.75 0.1 +ROTAT 0 180 0 +SCALE 2.5 2.5 2.5 + +OBJECT 7 +cube +material 10 +frame 0 +TRANS -2.2 2 -2 +ROTAT 0 45 0 +SCALE 1.5 4 1.5 + + +OBJECT 8 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 + +OBJECT 9 +cube +material 6 +frame 0 +TRANS 0 5 -5 +ROTAT 0 0 0 +SCALE 8 10 0.2 + +OBJECT 10 +sphere +material 4 +frame 0 +TRANS -2.2 5 -2 +ROTAT 0 0 0 +SCALE 2 2 2 + + +OBJECT 11 +sphere +material 7 +frame 0 +TRANS 3.5 7 -3 +ROTAT 0 0 0 +SCALE 1.5 1.5 1.5 + + +OBJECT 12 +cube +material 10 +frame 0 +TRANS 3.5 3.5 -3 +ROTAT 0 35 0 +SCALE 0.2 7 0.2 + + +OBJECT 13 +sphere +material 5 +frame 0 +TRANS 1 2.8 -0.5 +ROTAT 0 0 0 +SCALE 2 2 2 + +OBJECT 14 +sphere +material 5 +frame 0 +TRANS 2 1.1 -0.5 +ROTAT 0 45 45 +SCALE 2 2 2 \ No newline at end of file diff --git a/data/scenes/sampleScene.txt b/data/scenes/sampleScene.txt index 6a9f5cc..1687fda 100644 --- a/data/scenes/sampleScene.txt +++ b/data/scenes/sampleScene.txt @@ -111,6 +111,8 @@ RES 800 800 FOVY 25 ITERATIONS 5000 FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 frame 0 EYE 0 4.5 12 VIEW 0 0 -1 diff --git a/data/scenes/test.txt b/data/scenes/test.txt new file mode 100644 index 0000000..db76032 --- /dev/null +++ b/data/scenes/test.txt @@ -0,0 +1,280 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 3 //blue glass +RGB .6 .4 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 4 //purple glossy +RGB .6 .2 .8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //blue glossy +RGB .0 .8 .8 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //pink light +RGB 1 .42 .71 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 1 +REFRIOR 0 +SCATTER 1.5 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 9 + +MATERIAL 8 //white light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 30 + +MATERIAL 9 //chrome +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 0 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 10 //yellow diffuse +RGB .9 .9 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 11 //specular gold +RGB .93 .88 .38 +SPECEX 15 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0.372 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + + +CAMERA +RES 800 800 +FOVY 35 +ITERATIONS 5000 +FILE test.bmp +FOCAL 8.2 +APERTURE 1.3 +frame 0 +EYE 0 4.5 8 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 0 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 2 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 1 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +sphere +material 3 +frame 0 +TRANS 0 1.1 -0.5 +ROTAT 0 45 45 +SCALE 2 2 2 + +OBJECT 6 +sphere +material 9 +frame 0 +TRANS -2.5 1.75 0.1 +ROTAT 0 180 0 +SCALE 2.5 2.5 2.5 + +OBJECT 7 +cube +material 10 +frame 0 +TRANS -2.2 2 -2 +ROTAT 0 45 0 +SCALE 1.5 4 1.5 + + +OBJECT 8 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 + +OBJECT 9 +cube +material 6 +frame 0 +TRANS 0 5 -5 +ROTAT 0 0 0 +SCALE 8 10 0.2 + +OBJECT 10 +sphere +material 4 +frame 0 +TRANS -2.2 5 -2 +ROTAT 0 0 0 +SCALE 2 2 2 + + +OBJECT 11 +sphere +material 7 +frame 0 +TRANS 3.5 7 -3 +ROTAT 0 0 0 +SCALE 1.5 1.5 1.5 + + +OBJECT 12 +cube +material 10 +frame 0 +TRANS 3.5 3.5 -3 +ROTAT 0 35 0 +SCALE 0.2 7 0.2 + + +OBJECT 13 +sphere +material 5 +frame 0 +TRANS 1 2.8 -0.5 +ROTAT 0 0 0 +SCALE 2 2 2 + +OBJECT 14 +sphere +material 5 +frame 0 +TRANS 2 1.1 -0.5 +ROTAT 0 45 45 +SCALE 2 2 2 \ No newline at end of file diff --git a/data/texture/checker.jpg b/data/texture/checker.jpg new file mode 100644 index 0000000..5263c14 Binary files /dev/null and b/data/texture/checker.jpg differ diff --git a/data/texture/cloth.jpg b/data/texture/cloth.jpg new file mode 100644 index 0000000..963a149 Binary files /dev/null and b/data/texture/cloth.jpg differ diff --git a/data/texture/earthmap1024.png b/data/texture/earthmap1024.png new file mode 100644 index 0000000..144a648 Binary files /dev/null and b/data/texture/earthmap1024.png differ diff --git a/data/texture/marble.jpg b/data/texture/marble.jpg new file mode 100644 index 0000000..3b31afd Binary files /dev/null and b/data/texture/marble.jpg differ diff --git a/data/texture/sec05_UsingFreeImage.pdf b/data/texture/sec05_UsingFreeImage.pdf new file mode 100644 index 0000000..5ff3520 Binary files /dev/null and b/data/texture/sec05_UsingFreeImage.pdf differ diff --git a/data/texture/wall.jpg b/data/texture/wall.jpg new file mode 100644 index 0000000..30699c4 Binary files /dev/null and b/data/texture/wall.jpg differ diff --git a/data/texture/wall2.jpg b/data/texture/wall2.jpg new file mode 100644 index 0000000..83ae288 Binary files /dev/null and b/data/texture/wall2.jpg differ diff --git a/data/texture/wood.jpg b/data/texture/wood.jpg new file mode 100644 index 0000000..73abcd0 Binary files /dev/null and b/data/texture/wood.jpg differ diff --git a/data/texture/wood2.jpg b/data/texture/wood2.jpg new file mode 100644 index 0000000..0ead7a3 Binary files /dev/null and b/data/texture/wood2.jpg differ diff --git a/data/texture/wood3.jpg b/data/texture/wood3.jpg new file mode 100644 index 0000000..b4feae5 Binary files /dev/null and b/data/texture/wood3.jpg differ diff --git a/external/FreeImage/FreeImage.dll b/external/FreeImage/FreeImage.dll new file mode 100644 index 0000000..3ce0a70 Binary files /dev/null and b/external/FreeImage/FreeImage.dll differ diff --git a/external/FreeImage/FreeImage.lib b/external/FreeImage/FreeImage.lib new file mode 100644 index 0000000..b29ed71 Binary files /dev/null and b/external/FreeImage/FreeImage.lib differ diff --git a/src/FreeImage.h b/src/FreeImage.h new file mode 100644 index 0000000..2755160 --- /dev/null +++ b/src/FreeImage.h @@ -0,0 +1,1122 @@ +// ========================================================== +// FreeImage 3 +// +// Design and implementation by +// - Floris van den Berg (flvdberg@wxs.nl) +// - Hervé Drolon (drolon@infonie.fr) +// +// Contributors: +// - see changes log named 'Whatsnew.txt', see header of each .h and .cpp file +// +// This file is part of FreeImage 3 +// +// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY +// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES +// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE +// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED +// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT +// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY +// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL +// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER +// THIS DISCLAIMER. +// +// Use at your own risk! +// ========================================================== + +#ifndef FREEIMAGE_H +#define FREEIMAGE_H + +// Version information ------------------------------------------------------ + +#define FREEIMAGE_MAJOR_VERSION 3 +#define FREEIMAGE_MINOR_VERSION 16 +#define FREEIMAGE_RELEASE_SERIAL 0 + +// Compiler options --------------------------------------------------------- + +#include // needed for UNICODE functions + +#if defined(FREEIMAGE_LIB) + #define DLL_API + #define DLL_CALLCONV +#else + #if defined(_WIN32) || defined(__WIN32__) + #define DLL_CALLCONV __stdcall + // The following ifdef block is the standard way of creating macros which make exporting + // from a DLL simpler. All files within this DLL are compiled with the FREEIMAGE_EXPORTS + // symbol defined on the command line. this symbol should not be defined on any project + // that uses this DLL. This way any other project whose source files include this file see + // DLL_API functions as being imported from a DLL, wheras this DLL sees symbols + // defined with this macro as being exported. + #ifdef FREEIMAGE_EXPORTS + #define DLL_API __declspec(dllexport) + #else + #define DLL_API __declspec(dllimport) + #endif // FREEIMAGE_EXPORTS + #else + // try the gcc visibility support (see http://gcc.gnu.org/wiki/Visibility) + #if defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) + #ifndef GCC_HASCLASSVISIBILITY + #define GCC_HASCLASSVISIBILITY + #endif + #endif // __GNUC__ + #define DLL_CALLCONV + #if defined(GCC_HASCLASSVISIBILITY) + #define DLL_API __attribute__ ((visibility("default"))) + #else + #define DLL_API + #endif + #endif // WIN32 / !WIN32 +#endif // FREEIMAGE_LIB + +// Some versions of gcc may have BYTE_ORDER or __BYTE_ORDER defined +// If your big endian system isn't being detected, add an OS specific check +#if (defined(BYTE_ORDER) && BYTE_ORDER==BIG_ENDIAN) || \ + (defined(__BYTE_ORDER) && __BYTE_ORDER==__BIG_ENDIAN) || \ + defined(__BIG_ENDIAN__) +#define FREEIMAGE_BIGENDIAN +#endif // BYTE_ORDER + +// This really only affects 24 and 32 bit formats, the rest are always RGB order. +#define FREEIMAGE_COLORORDER_BGR 0 +#define FREEIMAGE_COLORORDER_RGB 1 +#if defined(FREEIMAGE_BIGENDIAN) +#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_RGB +#else +#define FREEIMAGE_COLORORDER FREEIMAGE_COLORORDER_BGR +#endif + +// Ensure 4-byte enums if we're using Borland C++ compilers +#if defined(__BORLANDC__) +#pragma option push -b +#endif + +// For C compatibility -------------------------------------------------------- + +#ifdef __cplusplus +#define FI_DEFAULT(x) = x +#define FI_ENUM(x) enum x +#define FI_STRUCT(x) struct x +#else +#define FI_DEFAULT(x) +#define FI_ENUM(x) typedef int x; enum x +#define FI_STRUCT(x) typedef struct x x; struct x +#endif + +// Bitmap types ------------------------------------------------------------- + +FI_STRUCT (FIBITMAP) { void *data; }; +FI_STRUCT (FIMULTIBITMAP) { void *data; }; + +// Types used in the library (directly copied from Windows) ----------------- + +#if defined(__MINGW32__) && defined(_WINDOWS_H) +#define _WINDOWS_ // prevent a bug in MinGW32 +#endif // __MINGW32__ + +#ifndef _WINDOWS_ +#define _WINDOWS_ + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef NULL +#define NULL 0 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif + +#ifndef _MSC_VER +// define portable types for 32-bit / 64-bit OS +#include +typedef int32_t BOOL; +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD; +typedef int32_t LONG; +typedef int64_t INT64; +typedef uint64_t UINT64; +#else +// MS is not C99 ISO compliant +typedef long BOOL; +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef long LONG; +typedef signed __int64 INT64; +typedef unsigned __int64 UINT64; +#endif // _MSC_VER + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif // WIN32 + +typedef struct tagRGBQUAD { +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR + BYTE rgbBlue; + BYTE rgbGreen; + BYTE rgbRed; +#else + BYTE rgbRed; + BYTE rgbGreen; + BYTE rgbBlue; +#endif // FREEIMAGE_COLORORDER + BYTE rgbReserved; +} RGBQUAD; + +typedef struct tagRGBTRIPLE { +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR + BYTE rgbtBlue; + BYTE rgbtGreen; + BYTE rgbtRed; +#else + BYTE rgbtRed; + BYTE rgbtGreen; + BYTE rgbtBlue; +#endif // FREEIMAGE_COLORORDER +} RGBTRIPLE; + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(pop) +#else +#pragma pack() +#endif // WIN32 + +typedef struct tagBITMAPINFOHEADER{ + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount; + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} BITMAPINFOHEADER, *PBITMAPINFOHEADER; + +typedef struct tagBITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; +} BITMAPINFO, *PBITMAPINFO; + +#endif // _WINDOWS_ + +// Types used in the library (specific to FreeImage) ------------------------ + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif // WIN32 + +/** 48-bit RGB +*/ +typedef struct tagFIRGB16 { + WORD red; + WORD green; + WORD blue; +} FIRGB16; + +/** 64-bit RGBA +*/ +typedef struct tagFIRGBA16 { + WORD red; + WORD green; + WORD blue; + WORD alpha; +} FIRGBA16; + +/** 96-bit RGB Float +*/ +typedef struct tagFIRGBF { + float red; + float green; + float blue; +} FIRGBF; + +/** 128-bit RGBA Float +*/ +typedef struct tagFIRGBAF { + float red; + float green; + float blue; + float alpha; +} FIRGBAF; + +/** Data structure for COMPLEX type (complex number) +*/ +typedef struct tagFICOMPLEX { + /// real part + double r; + /// imaginary part + double i; +} FICOMPLEX; + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(pop) +#else +#pragma pack() +#endif // WIN32 + +// Indexes for byte arrays, masks and shifts for treating pixels as words --- +// These coincide with the order of RGBQUAD and RGBTRIPLE ------------------- + +#ifndef FREEIMAGE_BIGENDIAN +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR +// Little Endian (x86 / MS Windows, Linux) : BGR(A) order +#define FI_RGBA_RED 2 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 0 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0x00FF0000 +#define FI_RGBA_GREEN_MASK 0x0000FF00 +#define FI_RGBA_BLUE_MASK 0x000000FF +#define FI_RGBA_ALPHA_MASK 0xFF000000 +#define FI_RGBA_RED_SHIFT 16 +#define FI_RGBA_GREEN_SHIFT 8 +#define FI_RGBA_BLUE_SHIFT 0 +#define FI_RGBA_ALPHA_SHIFT 24 +#else +// Little Endian (x86 / MaxOSX) : RGB(A) order +#define FI_RGBA_RED 0 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 2 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0x000000FF +#define FI_RGBA_GREEN_MASK 0x0000FF00 +#define FI_RGBA_BLUE_MASK 0x00FF0000 +#define FI_RGBA_ALPHA_MASK 0xFF000000 +#define FI_RGBA_RED_SHIFT 0 +#define FI_RGBA_GREEN_SHIFT 8 +#define FI_RGBA_BLUE_SHIFT 16 +#define FI_RGBA_ALPHA_SHIFT 24 +#endif // FREEIMAGE_COLORORDER +#else +#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR +// Big Endian (PPC / none) : BGR(A) order +#define FI_RGBA_RED 2 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 0 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0x0000FF00 +#define FI_RGBA_GREEN_MASK 0x00FF0000 +#define FI_RGBA_BLUE_MASK 0xFF000000 +#define FI_RGBA_ALPHA_MASK 0x000000FF +#define FI_RGBA_RED_SHIFT 8 +#define FI_RGBA_GREEN_SHIFT 16 +#define FI_RGBA_BLUE_SHIFT 24 +#define FI_RGBA_ALPHA_SHIFT 0 +#else +// Big Endian (PPC / Linux, MaxOSX) : RGB(A) order +#define FI_RGBA_RED 0 +#define FI_RGBA_GREEN 1 +#define FI_RGBA_BLUE 2 +#define FI_RGBA_ALPHA 3 +#define FI_RGBA_RED_MASK 0xFF000000 +#define FI_RGBA_GREEN_MASK 0x00FF0000 +#define FI_RGBA_BLUE_MASK 0x0000FF00 +#define FI_RGBA_ALPHA_MASK 0x000000FF +#define FI_RGBA_RED_SHIFT 24 +#define FI_RGBA_GREEN_SHIFT 16 +#define FI_RGBA_BLUE_SHIFT 8 +#define FI_RGBA_ALPHA_SHIFT 0 +#endif // FREEIMAGE_COLORORDER +#endif // FREEIMAGE_BIGENDIAN + +#define FI_RGBA_RGB_MASK (FI_RGBA_RED_MASK|FI_RGBA_GREEN_MASK|FI_RGBA_BLUE_MASK) + +// The 16bit macros only include masks and shifts, since each color element is not byte aligned + +#define FI16_555_RED_MASK 0x7C00 +#define FI16_555_GREEN_MASK 0x03E0 +#define FI16_555_BLUE_MASK 0x001F +#define FI16_555_RED_SHIFT 10 +#define FI16_555_GREEN_SHIFT 5 +#define FI16_555_BLUE_SHIFT 0 +#define FI16_565_RED_MASK 0xF800 +#define FI16_565_GREEN_MASK 0x07E0 +#define FI16_565_BLUE_MASK 0x001F +#define FI16_565_RED_SHIFT 11 +#define FI16_565_GREEN_SHIFT 5 +#define FI16_565_BLUE_SHIFT 0 + +// ICC profile support ------------------------------------------------------ + +#define FIICC_DEFAULT 0x00 +#define FIICC_COLOR_IS_CMYK 0x01 + +FI_STRUCT (FIICCPROFILE) { + WORD flags; // info flag + DWORD size; // profile's size measured in bytes + void *data; // points to a block of contiguous memory containing the profile +}; + +// Important enums ---------------------------------------------------------- + +/** I/O image format identifiers. +*/ +FI_ENUM(FREE_IMAGE_FORMAT) { + FIF_UNKNOWN = -1, + FIF_BMP = 0, + FIF_ICO = 1, + FIF_JPEG = 2, + FIF_JNG = 3, + FIF_KOALA = 4, + FIF_LBM = 5, + FIF_IFF = FIF_LBM, + FIF_MNG = 6, + FIF_PBM = 7, + FIF_PBMRAW = 8, + FIF_PCD = 9, + FIF_PCX = 10, + FIF_PGM = 11, + FIF_PGMRAW = 12, + FIF_PNG = 13, + FIF_PPM = 14, + FIF_PPMRAW = 15, + FIF_RAS = 16, + FIF_TARGA = 17, + FIF_TIFF = 18, + FIF_WBMP = 19, + FIF_PSD = 20, + FIF_CUT = 21, + FIF_XBM = 22, + FIF_XPM = 23, + FIF_DDS = 24, + FIF_GIF = 25, + FIF_HDR = 26, + FIF_FAXG3 = 27, + FIF_SGI = 28, + FIF_EXR = 29, + FIF_J2K = 30, + FIF_JP2 = 31, + FIF_PFM = 32, + FIF_PICT = 33, + FIF_RAW = 34, + FIF_WEBP = 35, + FIF_JXR = 36 +}; + +/** Image type used in FreeImage. +*/ +FI_ENUM(FREE_IMAGE_TYPE) { + FIT_UNKNOWN = 0, // unknown type + FIT_BITMAP = 1, // standard image : 1-, 4-, 8-, 16-, 24-, 32-bit + FIT_UINT16 = 2, // array of unsigned short : unsigned 16-bit + FIT_INT16 = 3, // array of short : signed 16-bit + FIT_UINT32 = 4, // array of unsigned long : unsigned 32-bit + FIT_INT32 = 5, // array of long : signed 32-bit + FIT_FLOAT = 6, // array of float : 32-bit IEEE floating point + FIT_DOUBLE = 7, // array of double : 64-bit IEEE floating point + FIT_COMPLEX = 8, // array of FICOMPLEX : 2 x 64-bit IEEE floating point + FIT_RGB16 = 9, // 48-bit RGB image : 3 x 16-bit + FIT_RGBA16 = 10, // 64-bit RGBA image : 4 x 16-bit + FIT_RGBF = 11, // 96-bit RGB float image : 3 x 32-bit IEEE floating point + FIT_RGBAF = 12 // 128-bit RGBA float image : 4 x 32-bit IEEE floating point +}; + +/** Image color type used in FreeImage. +*/ +FI_ENUM(FREE_IMAGE_COLOR_TYPE) { + FIC_MINISWHITE = 0, // min value is white + FIC_MINISBLACK = 1, // min value is black + FIC_RGB = 2, // RGB color model + FIC_PALETTE = 3, // color map indexed + FIC_RGBALPHA = 4, // RGB color model with alpha channel + FIC_CMYK = 5 // CMYK color model +}; + +/** Color quantization algorithms. +Constants used in FreeImage_ColorQuantize. +*/ +FI_ENUM(FREE_IMAGE_QUANTIZE) { + FIQ_WUQUANT = 0, // Xiaolin Wu color quantization algorithm + FIQ_NNQUANT = 1 // NeuQuant neural-net quantization algorithm by Anthony Dekker +}; + +/** Dithering algorithms. +Constants used in FreeImage_Dither. +*/ +FI_ENUM(FREE_IMAGE_DITHER) { + FID_FS = 0, // Floyd & Steinberg error diffusion + FID_BAYER4x4 = 1, // Bayer ordered dispersed dot dithering (order 2 dithering matrix) + FID_BAYER8x8 = 2, // Bayer ordered dispersed dot dithering (order 3 dithering matrix) + FID_CLUSTER6x6 = 3, // Ordered clustered dot dithering (order 3 - 6x6 matrix) + FID_CLUSTER8x8 = 4, // Ordered clustered dot dithering (order 4 - 8x8 matrix) + FID_CLUSTER16x16= 5, // Ordered clustered dot dithering (order 8 - 16x16 matrix) + FID_BAYER16x16 = 6 // Bayer ordered dispersed dot dithering (order 4 dithering matrix) +}; + +/** Lossless JPEG transformations +Constants used in FreeImage_JPEGTransform +*/ +FI_ENUM(FREE_IMAGE_JPEG_OPERATION) { + FIJPEG_OP_NONE = 0, // no transformation + FIJPEG_OP_FLIP_H = 1, // horizontal flip + FIJPEG_OP_FLIP_V = 2, // vertical flip + FIJPEG_OP_TRANSPOSE = 3, // transpose across UL-to-LR axis + FIJPEG_OP_TRANSVERSE = 4, // transpose across UR-to-LL axis + FIJPEG_OP_ROTATE_90 = 5, // 90-degree clockwise rotation + FIJPEG_OP_ROTATE_180 = 6, // 180-degree rotation + FIJPEG_OP_ROTATE_270 = 7 // 270-degree clockwise (or 90 ccw) +}; + +/** Tone mapping operators. +Constants used in FreeImage_ToneMapping. +*/ +FI_ENUM(FREE_IMAGE_TMO) { + FITMO_DRAGO03 = 0, // Adaptive logarithmic mapping (F. Drago, 2003) + FITMO_REINHARD05 = 1, // Dynamic range reduction inspired by photoreceptor physiology (E. Reinhard, 2005) + FITMO_FATTAL02 = 2 // Gradient domain high dynamic range compression (R. Fattal, 2002) +}; + +/** Upsampling / downsampling filters. +Constants used in FreeImage_Rescale. +*/ +FI_ENUM(FREE_IMAGE_FILTER) { + FILTER_BOX = 0, // Box, pulse, Fourier window, 1st order (constant) b-spline + FILTER_BICUBIC = 1, // Mitchell & Netravali's two-param cubic filter + FILTER_BILINEAR = 2, // Bilinear filter + FILTER_BSPLINE = 3, // 4th order (cubic) b-spline + FILTER_CATMULLROM = 4, // Catmull-Rom spline, Overhauser spline + FILTER_LANCZOS3 = 5 // Lanczos3 filter +}; + +/** Color channels. +Constants used in color manipulation routines. +*/ +FI_ENUM(FREE_IMAGE_COLOR_CHANNEL) { + FICC_RGB = 0, // Use red, green and blue channels + FICC_RED = 1, // Use red channel + FICC_GREEN = 2, // Use green channel + FICC_BLUE = 3, // Use blue channel + FICC_ALPHA = 4, // Use alpha channel + FICC_BLACK = 5, // Use black channel + FICC_REAL = 6, // Complex images: use real part + FICC_IMAG = 7, // Complex images: use imaginary part + FICC_MAG = 8, // Complex images: use magnitude + FICC_PHASE = 9 // Complex images: use phase +}; + +// Metadata support --------------------------------------------------------- + +/** + Tag data type information (based on TIFF specifications) + + Note: RATIONALs are the ratio of two 32-bit integer values. +*/ +FI_ENUM(FREE_IMAGE_MDTYPE) { + FIDT_NOTYPE = 0, // placeholder + FIDT_BYTE = 1, // 8-bit unsigned integer + FIDT_ASCII = 2, // 8-bit bytes w/ last byte null + FIDT_SHORT = 3, // 16-bit unsigned integer + FIDT_LONG = 4, // 32-bit unsigned integer + FIDT_RATIONAL = 5, // 64-bit unsigned fraction + FIDT_SBYTE = 6, // 8-bit signed integer + FIDT_UNDEFINED = 7, // 8-bit untyped data + FIDT_SSHORT = 8, // 16-bit signed integer + FIDT_SLONG = 9, // 32-bit signed integer + FIDT_SRATIONAL = 10, // 64-bit signed fraction + FIDT_FLOAT = 11, // 32-bit IEEE floating point + FIDT_DOUBLE = 12, // 64-bit IEEE floating point + FIDT_IFD = 13, // 32-bit unsigned integer (offset) + FIDT_PALETTE = 14, // 32-bit RGBQUAD + FIDT_LONG8 = 16, // 64-bit unsigned integer + FIDT_SLONG8 = 17, // 64-bit signed integer + FIDT_IFD8 = 18 // 64-bit unsigned integer (offset) +}; + +/** + Metadata models supported by FreeImage +*/ +FI_ENUM(FREE_IMAGE_MDMODEL) { + FIMD_NODATA = -1, + FIMD_COMMENTS = 0, // single comment or keywords + FIMD_EXIF_MAIN = 1, // Exif-TIFF metadata + FIMD_EXIF_EXIF = 2, // Exif-specific metadata + FIMD_EXIF_GPS = 3, // Exif GPS metadata + FIMD_EXIF_MAKERNOTE = 4, // Exif maker note metadata + FIMD_EXIF_INTEROP = 5, // Exif interoperability metadata + FIMD_IPTC = 6, // IPTC/NAA metadata + FIMD_XMP = 7, // Abobe XMP metadata + FIMD_GEOTIFF = 8, // GeoTIFF metadata + FIMD_ANIMATION = 9, // Animation metadata + FIMD_CUSTOM = 10, // Used to attach other metadata types to a dib + FIMD_EXIF_RAW = 11 // Exif metadata as a raw buffer +}; + +/** + Handle to a metadata model +*/ +FI_STRUCT (FIMETADATA) { void *data; }; + +/** + Handle to a FreeImage tag +*/ +FI_STRUCT (FITAG) { void *data; }; + +// File IO routines --------------------------------------------------------- + +#ifndef FREEIMAGE_IO +#define FREEIMAGE_IO + +typedef void* fi_handle; +typedef unsigned (DLL_CALLCONV *FI_ReadProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef unsigned (DLL_CALLCONV *FI_WriteProc) (void *buffer, unsigned size, unsigned count, fi_handle handle); +typedef int (DLL_CALLCONV *FI_SeekProc) (fi_handle handle, long offset, int origin); +typedef long (DLL_CALLCONV *FI_TellProc) (fi_handle handle); + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif // WIN32 + +FI_STRUCT(FreeImageIO) { + FI_ReadProc read_proc; // pointer to the function used to read data + FI_WriteProc write_proc; // pointer to the function used to write data + FI_SeekProc seek_proc; // pointer to the function used to seek + FI_TellProc tell_proc; // pointer to the function used to aquire the current position +}; + +#if (defined(_WIN32) || defined(__WIN32__)) +#pragma pack(pop) +#else +#pragma pack() +#endif // WIN32 + +/** +Handle to a memory I/O stream +*/ +FI_STRUCT (FIMEMORY) { void *data; }; + +#endif // FREEIMAGE_IO + +// Plugin routines ---------------------------------------------------------- + +#ifndef PLUGINS +#define PLUGINS + +typedef const char *(DLL_CALLCONV *FI_FormatProc)(void); +typedef const char *(DLL_CALLCONV *FI_DescriptionProc)(void); +typedef const char *(DLL_CALLCONV *FI_ExtensionListProc)(void); +typedef const char *(DLL_CALLCONV *FI_RegExprProc)(void); +typedef void *(DLL_CALLCONV *FI_OpenProc)(FreeImageIO *io, fi_handle handle, BOOL read); +typedef void (DLL_CALLCONV *FI_CloseProc)(FreeImageIO *io, fi_handle handle, void *data); +typedef int (DLL_CALLCONV *FI_PageCountProc)(FreeImageIO *io, fi_handle handle, void *data); +typedef int (DLL_CALLCONV *FI_PageCapabilityProc)(FreeImageIO *io, fi_handle handle, void *data); +typedef FIBITMAP *(DLL_CALLCONV *FI_LoadProc)(FreeImageIO *io, fi_handle handle, int page, int flags, void *data); +typedef BOOL (DLL_CALLCONV *FI_SaveProc)(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data); +typedef BOOL (DLL_CALLCONV *FI_ValidateProc)(FreeImageIO *io, fi_handle handle); +typedef const char *(DLL_CALLCONV *FI_MimeProc)(void); +typedef BOOL (DLL_CALLCONV *FI_SupportsExportBPPProc)(int bpp); +typedef BOOL (DLL_CALLCONV *FI_SupportsExportTypeProc)(FREE_IMAGE_TYPE type); +typedef BOOL (DLL_CALLCONV *FI_SupportsICCProfilesProc)(void); +typedef BOOL (DLL_CALLCONV *FI_SupportsNoPixelsProc)(void); + +FI_STRUCT (Plugin) { + FI_FormatProc format_proc; + FI_DescriptionProc description_proc; + FI_ExtensionListProc extension_proc; + FI_RegExprProc regexpr_proc; + FI_OpenProc open_proc; + FI_CloseProc close_proc; + FI_PageCountProc pagecount_proc; + FI_PageCapabilityProc pagecapability_proc; + FI_LoadProc load_proc; + FI_SaveProc save_proc; + FI_ValidateProc validate_proc; + FI_MimeProc mime_proc; + FI_SupportsExportBPPProc supports_export_bpp_proc; + FI_SupportsExportTypeProc supports_export_type_proc; + FI_SupportsICCProfilesProc supports_icc_profiles_proc; + FI_SupportsNoPixelsProc supports_no_pixels_proc; +}; + +typedef void (DLL_CALLCONV *FI_InitProc)(Plugin *plugin, int format_id); + +#endif // PLUGINS + + +// Load / Save flag constants ----------------------------------------------- + +#define FIF_LOAD_NOPIXELS 0x8000 //! loading: load the image header only (not supported by all plugins, default to full loading) + +#define BMP_DEFAULT 0 +#define BMP_SAVE_RLE 1 +#define CUT_DEFAULT 0 +#define DDS_DEFAULT 0 +#define EXR_DEFAULT 0 //! save data as half with piz-based wavelet compression +#define EXR_FLOAT 0x0001 //! save data as float instead of as half (not recommended) +#define EXR_NONE 0x0002 //! save with no compression +#define EXR_ZIP 0x0004 //! save with zlib compression, in blocks of 16 scan lines +#define EXR_PIZ 0x0008 //! save with piz-based wavelet compression +#define EXR_PXR24 0x0010 //! save with lossy 24-bit float compression +#define EXR_B44 0x0020 //! save with lossy 44% float compression - goes to 22% when combined with EXR_LC +#define EXR_LC 0x0040 //! save images with one luminance and two chroma channels, rather than as RGB (lossy compression) +#define FAXG3_DEFAULT 0 +#define GIF_DEFAULT 0 +#define GIF_LOAD256 1 //! load the image as a 256 color image with ununsed palette entries, if it's 16 or 2 color +#define GIF_PLAYBACK 2 //! 'Play' the GIF to generate each frame (as 32bpp) instead of returning raw frame data when loading +#define HDR_DEFAULT 0 +#define ICO_DEFAULT 0 +#define ICO_MAKEALPHA 1 //! convert to 32bpp and create an alpha channel from the AND-mask when loading +#define IFF_DEFAULT 0 +#define J2K_DEFAULT 0 //! save with a 16:1 rate +#define JP2_DEFAULT 0 //! save with a 16:1 rate +#define JPEG_DEFAULT 0 //! loading (see JPEG_FAST); saving (see JPEG_QUALITYGOOD|JPEG_SUBSAMPLING_420) +#define JPEG_FAST 0x0001 //! load the file as fast as possible, sacrificing some quality +#define JPEG_ACCURATE 0x0002 //! load the file with the best quality, sacrificing some speed +#define JPEG_CMYK 0x0004 //! load separated CMYK "as is" (use | to combine with other load flags) +#define JPEG_EXIFROTATE 0x0008 //! load and rotate according to Exif 'Orientation' tag if available +#define JPEG_GREYSCALE 0x0010 //! load and convert to a 8-bit greyscale image +#define JPEG_QUALITYSUPERB 0x80 //! save with superb quality (100:1) +#define JPEG_QUALITYGOOD 0x0100 //! save with good quality (75:1) +#define JPEG_QUALITYNORMAL 0x0200 //! save with normal quality (50:1) +#define JPEG_QUALITYAVERAGE 0x0400 //! save with average quality (25:1) +#define JPEG_QUALITYBAD 0x0800 //! save with bad quality (10:1) +#define JPEG_PROGRESSIVE 0x2000 //! save as a progressive-JPEG (use | to combine with other save flags) +#define JPEG_SUBSAMPLING_411 0x1000 //! save with high 4x1 chroma subsampling (4:1:1) +#define JPEG_SUBSAMPLING_420 0x4000 //! save with medium 2x2 medium chroma subsampling (4:2:0) - default value +#define JPEG_SUBSAMPLING_422 0x8000 //! save with low 2x1 chroma subsampling (4:2:2) +#define JPEG_SUBSAMPLING_444 0x10000 //! save with no chroma subsampling (4:4:4) +#define JPEG_OPTIMIZE 0x20000 //! on saving, compute optimal Huffman coding tables (can reduce a few percent of file size) +#define JPEG_BASELINE 0x40000 //! save basic JPEG, without metadata or any markers +#define KOALA_DEFAULT 0 +#define LBM_DEFAULT 0 +#define MNG_DEFAULT 0 +#define PCD_DEFAULT 0 +#define PCD_BASE 1 //! load the bitmap sized 768 x 512 +#define PCD_BASEDIV4 2 //! load the bitmap sized 384 x 256 +#define PCD_BASEDIV16 3 //! load the bitmap sized 192 x 128 +#define PCX_DEFAULT 0 +#define PFM_DEFAULT 0 +#define PICT_DEFAULT 0 +#define PNG_DEFAULT 0 +#define PNG_IGNOREGAMMA 1 //! loading: avoid gamma correction +#define PNG_Z_BEST_SPEED 0x0001 //! save using ZLib level 1 compression flag (default value is 6) +#define PNG_Z_DEFAULT_COMPRESSION 0x0006 //! save using ZLib level 6 compression flag (default recommended value) +#define PNG_Z_BEST_COMPRESSION 0x0009 //! save using ZLib level 9 compression flag (default value is 6) +#define PNG_Z_NO_COMPRESSION 0x0100 //! save without ZLib compression +#define PNG_INTERLACED 0x0200 //! save using Adam7 interlacing (use | to combine with other save flags) +#define PNM_DEFAULT 0 +#define PNM_SAVE_RAW 0 //! if set the writer saves in RAW format (i.e. P4, P5 or P6) +#define PNM_SAVE_ASCII 1 //! if set the writer saves in ASCII format (i.e. P1, P2 or P3) +#define PSD_DEFAULT 0 +#define PSD_CMYK 1 //! reads tags for separated CMYK (default is conversion to RGB) +#define PSD_LAB 2 //! reads tags for CIELab (default is conversion to RGB) +#define RAS_DEFAULT 0 +#define RAW_DEFAULT 0 //! load the file as linear RGB 48-bit +#define RAW_PREVIEW 1 //! try to load the embedded JPEG preview with included Exif Data or default to RGB 24-bit +#define RAW_DISPLAY 2 //! load the file as RGB 24-bit +#define RAW_HALFSIZE 4 //! output a half-size color image +#define SGI_DEFAULT 0 +#define TARGA_DEFAULT 0 +#define TARGA_LOAD_RGB888 1 //! if set the loader converts RGB555 and ARGB8888 -> RGB888. +#define TARGA_SAVE_RLE 2 //! if set, the writer saves with RLE compression +#define TIFF_DEFAULT 0 +#define TIFF_CMYK 0x0001 //! reads/stores tags for separated CMYK (use | to combine with compression flags) +#define TIFF_PACKBITS 0x0100 //! save using PACKBITS compression +#define TIFF_DEFLATE 0x0200 //! save using DEFLATE compression (a.k.a. ZLIB compression) +#define TIFF_ADOBE_DEFLATE 0x0400 //! save using ADOBE DEFLATE compression +#define TIFF_NONE 0x0800 //! save without any compression +#define TIFF_CCITTFAX3 0x1000 //! save using CCITT Group 3 fax encoding +#define TIFF_CCITTFAX4 0x2000 //! save using CCITT Group 4 fax encoding +#define TIFF_LZW 0x4000 //! save using LZW compression +#define TIFF_JPEG 0x8000 //! save using JPEG compression +#define TIFF_LOGLUV 0x10000 //! save using LogLuv compression +#define WBMP_DEFAULT 0 +#define XBM_DEFAULT 0 +#define XPM_DEFAULT 0 +#define WEBP_DEFAULT 0 //! save with good quality (75:1) +#define WEBP_LOSSLESS 0x100 //! save in lossless mode +#define JXR_DEFAULT 0 //! save with quality 80 and no chroma subsampling (4:4:4) +#define JXR_LOSSLESS 0x0064 //! save lossless +#define JXR_PROGRESSIVE 0x2000 //! save as a progressive-JXR (use | to combine with other save flags) + +// Background filling options --------------------------------------------------------- +// Constants used in FreeImage_FillBackground and FreeImage_EnlargeCanvas + +#define FI_COLOR_IS_RGB_COLOR 0x00 // RGBQUAD color is a RGB color (contains no valid alpha channel) +#define FI_COLOR_IS_RGBA_COLOR 0x01 // RGBQUAD color is a RGBA color (contains a valid alpha channel) +#define FI_COLOR_FIND_EQUAL_COLOR 0x02 // For palettized images: lookup equal RGB color from palette +#define FI_COLOR_ALPHA_IS_INDEX 0x04 // The color's rgbReserved member (alpha) contains the palette index to be used +#define FI_COLOR_PALETTE_SEARCH_MASK (FI_COLOR_FIND_EQUAL_COLOR | FI_COLOR_ALPHA_IS_INDEX) // No color lookup is performed + + +#ifdef __cplusplus +extern "C" { +#endif + +// Init / Error routines ---------------------------------------------------- + +DLL_API void DLL_CALLCONV FreeImage_Initialise(BOOL load_local_plugins_only FI_DEFAULT(FALSE)); +DLL_API void DLL_CALLCONV FreeImage_DeInitialise(void); + +// Version routines --------------------------------------------------------- + +DLL_API const char *DLL_CALLCONV FreeImage_GetVersion(void); +DLL_API const char *DLL_CALLCONV FreeImage_GetCopyrightMessage(void); + +// Message output functions ------------------------------------------------- + +typedef void (*FreeImage_OutputMessageFunction)(FREE_IMAGE_FORMAT fif, const char *msg); +typedef void (DLL_CALLCONV *FreeImage_OutputMessageFunctionStdCall)(FREE_IMAGE_FORMAT fif, const char *msg); + +DLL_API void DLL_CALLCONV FreeImage_SetOutputMessageStdCall(FreeImage_OutputMessageFunctionStdCall omf); +DLL_API void DLL_CALLCONV FreeImage_SetOutputMessage(FreeImage_OutputMessageFunction omf); +DLL_API void DLL_CALLCONV FreeImage_OutputMessageProc(int fif, const char *fmt, ...); + +// Allocate / Clone / Unload routines --------------------------------------- + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Allocate(int width, int height, int bpp, unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateT(FREE_IMAGE_TYPE type, int width, int height, int bpp FI_DEFAULT(8), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API FIBITMAP * DLL_CALLCONV FreeImage_Clone(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_Unload(FIBITMAP *dib); + +// Header loading routines +DLL_API BOOL DLL_CALLCONV FreeImage_HasPixels(FIBITMAP *dib); + +// Load / Save routines ----------------------------------------------------- + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Load(FREE_IMAGE_FORMAT fif, const char *filename, int flags FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadU(FREE_IMAGE_FORMAT fif, const wchar_t *filename, int flags FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_Save(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const char *filename, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveU(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, const wchar_t *filename, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveToHandle(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); + +// Memory I/O stream routines ----------------------------------------------- + +DLL_API FIMEMORY *DLL_CALLCONV FreeImage_OpenMemory(BYTE *data FI_DEFAULT(0), DWORD size_in_bytes FI_DEFAULT(0)); +DLL_API void DLL_CALLCONV FreeImage_CloseMemory(FIMEMORY *stream); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_LoadFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveToMemory(FREE_IMAGE_FORMAT fif, FIBITMAP *dib, FIMEMORY *stream, int flags FI_DEFAULT(0)); +DLL_API long DLL_CALLCONV FreeImage_TellMemory(FIMEMORY *stream); +DLL_API BOOL DLL_CALLCONV FreeImage_SeekMemory(FIMEMORY *stream, long offset, int origin); +DLL_API BOOL DLL_CALLCONV FreeImage_AcquireMemory(FIMEMORY *stream, BYTE **data, DWORD *size_in_bytes); +DLL_API unsigned DLL_CALLCONV FreeImage_ReadMemory(void *buffer, unsigned size, unsigned count, FIMEMORY *stream); +DLL_API unsigned DLL_CALLCONV FreeImage_WriteMemory(const void *buffer, unsigned size, unsigned count, FIMEMORY *stream); + +DLL_API FIMULTIBITMAP *DLL_CALLCONV FreeImage_LoadMultiBitmapFromMemory(FREE_IMAGE_FORMAT fif, FIMEMORY *stream, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveMultiBitmapToMemory(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, FIMEMORY *stream, int flags); + +// Plugin Interface --------------------------------------------------------- + +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterLocalPlugin(FI_InitProc proc_address, const char *format FI_DEFAULT(0), const char *description FI_DEFAULT(0), const char *extension FI_DEFAULT(0), const char *regexpr FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_RegisterExternalPlugin(const char *path, const char *format FI_DEFAULT(0), const char *description FI_DEFAULT(0), const char *extension FI_DEFAULT(0), const char *regexpr FI_DEFAULT(0)); +DLL_API int DLL_CALLCONV FreeImage_GetFIFCount(void); +DLL_API int DLL_CALLCONV FreeImage_SetPluginEnabled(FREE_IMAGE_FORMAT fif, BOOL enable); +DLL_API int DLL_CALLCONV FreeImage_IsPluginEnabled(FREE_IMAGE_FORMAT fif); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFormat(const char *format); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromMime(const char *mime); +DLL_API const char *DLL_CALLCONV FreeImage_GetFormatFromFIF(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFExtensionList(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFDescription(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFRegExpr(FREE_IMAGE_FORMAT fif); +DLL_API const char *DLL_CALLCONV FreeImage_GetFIFMimeType(FREE_IMAGE_FORMAT fif); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFilename(const char *filename); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFIFFromFilenameU(const wchar_t *filename); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsReading(FREE_IMAGE_FORMAT fif); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsWriting(FREE_IMAGE_FORMAT fif); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsExportBPP(FREE_IMAGE_FORMAT fif, int bpp); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsExportType(FREE_IMAGE_FORMAT fif, FREE_IMAGE_TYPE type); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsICCProfiles(FREE_IMAGE_FORMAT fif); +DLL_API BOOL DLL_CALLCONV FreeImage_FIFSupportsNoPixels(FREE_IMAGE_FORMAT fif); + +// Multipaging interface ---------------------------------------------------- + +DLL_API FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory FI_DEFAULT(FALSE), int flags FI_DEFAULT(0)); +DLL_API FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmapFromHandle(FREE_IMAGE_FORMAT fif, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_SaveMultiBitmapToHandle(FREE_IMAGE_FORMAT fif, FIMULTIBITMAP *bitmap, FreeImageIO *io, fi_handle handle, int flags FI_DEFAULT(0)); +DLL_API BOOL DLL_CALLCONV FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags FI_DEFAULT(0)); +DLL_API int DLL_CALLCONV FreeImage_GetPageCount(FIMULTIBITMAP *bitmap); +DLL_API void DLL_CALLCONV FreeImage_AppendPage(FIMULTIBITMAP *bitmap, FIBITMAP *data); +DLL_API void DLL_CALLCONV FreeImage_InsertPage(FIMULTIBITMAP *bitmap, int page, FIBITMAP *data); +DLL_API void DLL_CALLCONV FreeImage_DeletePage(FIMULTIBITMAP *bitmap, int page); +DLL_API FIBITMAP * DLL_CALLCONV FreeImage_LockPage(FIMULTIBITMAP *bitmap, int page); +DLL_API void DLL_CALLCONV FreeImage_UnlockPage(FIMULTIBITMAP *bitmap, FIBITMAP *data, BOOL changed); +DLL_API BOOL DLL_CALLCONV FreeImage_MovePage(FIMULTIBITMAP *bitmap, int target, int source); +DLL_API BOOL DLL_CALLCONV FreeImage_GetLockedPageNumbers(FIMULTIBITMAP *bitmap, int *pages, int *count); + +// Filetype request routines ------------------------------------------------ + +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileType(const char *filename, int size FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeU(const wchar_t *filename, int size FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromHandle(FreeImageIO *io, fi_handle handle, int size FI_DEFAULT(0)); +DLL_API FREE_IMAGE_FORMAT DLL_CALLCONV FreeImage_GetFileTypeFromMemory(FIMEMORY *stream, int size FI_DEFAULT(0)); + +// Image type request routine ----------------------------------------------- + +DLL_API FREE_IMAGE_TYPE DLL_CALLCONV FreeImage_GetImageType(FIBITMAP *dib); + +// FreeImage helper routines ------------------------------------------------ + +DLL_API BOOL DLL_CALLCONV FreeImage_IsLittleEndian(void); +DLL_API BOOL DLL_CALLCONV FreeImage_LookupX11Color(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nBlue); +DLL_API BOOL DLL_CALLCONV FreeImage_LookupSVGColor(const char *szColor, BYTE *nRed, BYTE *nGreen, BYTE *nBlue); + +// Pixel access routines ---------------------------------------------------- + +DLL_API BYTE *DLL_CALLCONV FreeImage_GetBits(FIBITMAP *dib); +DLL_API BYTE *DLL_CALLCONV FreeImage_GetScanLine(FIBITMAP *dib, int scanline); + +DLL_API BOOL DLL_CALLCONV FreeImage_GetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value); +DLL_API BOOL DLL_CALLCONV FreeImage_GetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value); +DLL_API BOOL DLL_CALLCONV FreeImage_SetPixelIndex(FIBITMAP *dib, unsigned x, unsigned y, BYTE *value); +DLL_API BOOL DLL_CALLCONV FreeImage_SetPixelColor(FIBITMAP *dib, unsigned x, unsigned y, RGBQUAD *value); + +// DIB info routines -------------------------------------------------------- + +DLL_API unsigned DLL_CALLCONV FreeImage_GetColorsUsed(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetBPP(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetWidth(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetHeight(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetLine(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetPitch(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetDIBSize(FIBITMAP *dib); +DLL_API RGBQUAD *DLL_CALLCONV FreeImage_GetPalette(FIBITMAP *dib); + +DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterX(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetDotsPerMeterY(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetDotsPerMeterX(FIBITMAP *dib, unsigned res); +DLL_API void DLL_CALLCONV FreeImage_SetDotsPerMeterY(FIBITMAP *dib, unsigned res); + +DLL_API BITMAPINFOHEADER *DLL_CALLCONV FreeImage_GetInfoHeader(FIBITMAP *dib); +DLL_API BITMAPINFO *DLL_CALLCONV FreeImage_GetInfo(FIBITMAP *dib); +DLL_API FREE_IMAGE_COLOR_TYPE DLL_CALLCONV FreeImage_GetColorType(FIBITMAP *dib); + +DLL_API unsigned DLL_CALLCONV FreeImage_GetRedMask(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetGreenMask(FIBITMAP *dib); +DLL_API unsigned DLL_CALLCONV FreeImage_GetBlueMask(FIBITMAP *dib); + +DLL_API unsigned DLL_CALLCONV FreeImage_GetTransparencyCount(FIBITMAP *dib); +DLL_API BYTE * DLL_CALLCONV FreeImage_GetTransparencyTable(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetTransparent(FIBITMAP *dib, BOOL enabled); +DLL_API void DLL_CALLCONV FreeImage_SetTransparencyTable(FIBITMAP *dib, BYTE *table, int count); +DLL_API BOOL DLL_CALLCONV FreeImage_IsTransparent(FIBITMAP *dib); +DLL_API void DLL_CALLCONV FreeImage_SetTransparentIndex(FIBITMAP *dib, int index); +DLL_API int DLL_CALLCONV FreeImage_GetTransparentIndex(FIBITMAP *dib); + +DLL_API BOOL DLL_CALLCONV FreeImage_HasBackgroundColor(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_GetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor); +DLL_API BOOL DLL_CALLCONV FreeImage_SetBackgroundColor(FIBITMAP *dib, RGBQUAD *bkcolor); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetThumbnail(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_SetThumbnail(FIBITMAP *dib, FIBITMAP *thumbnail); + +// ICC profile routines ----------------------------------------------------- + +DLL_API FIICCPROFILE *DLL_CALLCONV FreeImage_GetICCProfile(FIBITMAP *dib); +DLL_API FIICCPROFILE *DLL_CALLCONV FreeImage_CreateICCProfile(FIBITMAP *dib, void *data, long size); +DLL_API void DLL_CALLCONV FreeImage_DestroyICCProfile(FIBITMAP *dib); + +// Line conversion routines ------------------------------------------------- + +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To4(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To4(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To4_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To4_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To4(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To4(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To8_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To8(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_555(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_565_To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To16_565(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16_555_To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To16_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To24(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To24_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine32To24(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine1To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine4To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine8To32(BYTE *target, BYTE *source, int width_in_pixels, RGBQUAD *palette); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_555(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine16To32_565(BYTE *target, BYTE *source, int width_in_pixels); +DLL_API void DLL_CALLCONV FreeImage_ConvertLine24To32(BYTE *target, BYTE *source, int width_in_pixels); + +// Smart conversion routines ------------------------------------------------ + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo4Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo8Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToGreyscale(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits555(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo16Bits565(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo24Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertTo32Bits(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ColorQuantize(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ColorQuantizeEx(FIBITMAP *dib, FREE_IMAGE_QUANTIZE quantize FI_DEFAULT(FIQ_WUQUANT), int PaletteSize FI_DEFAULT(256), int ReserveSize FI_DEFAULT(0), RGBQUAD *ReservePalette FI_DEFAULT(NULL)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Threshold(FIBITMAP *dib, BYTE T); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Dither(FIBITMAP *dib, FREE_IMAGE_DITHER algorithm); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertFromRawBits(BYTE *bits, int width, int height, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); +DLL_API void DLL_CALLCONV FreeImage_ConvertToRawBits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown FI_DEFAULT(FALSE)); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToFloat(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGBF(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToUINT16(FIBITMAP *dib); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToRGB16(FIBITMAP *dib); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToStandardType(FIBITMAP *src, BOOL scale_linear FI_DEFAULT(TRUE)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ConvertToType(FIBITMAP *src, FREE_IMAGE_TYPE dst_type, BOOL scale_linear FI_DEFAULT(TRUE)); + +// Tone mapping operators --------------------------------------------------- + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_ToneMapping(FIBITMAP *dib, FREE_IMAGE_TMO tmo, double first_param FI_DEFAULT(0), double second_param FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoDrago03(FIBITMAP *src, double gamma FI_DEFAULT(2.2), double exposure FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoReinhard05(FIBITMAP *src, double intensity FI_DEFAULT(0), double contrast FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoReinhard05Ex(FIBITMAP *src, double intensity FI_DEFAULT(0), double contrast FI_DEFAULT(0), double adaptation FI_DEFAULT(1), double color_correction FI_DEFAULT(0)); + +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_TmoFattal02(FIBITMAP *src, double color_saturation FI_DEFAULT(0.5), double attenuation FI_DEFAULT(0.85)); + +// ZLib interface ----------------------------------------------------------- + +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibCompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibUncompress(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibGZip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibGUnzip(BYTE *target, DWORD target_size, BYTE *source, DWORD source_size); +DLL_API DWORD DLL_CALLCONV FreeImage_ZLibCRC32(DWORD crc, BYTE *source, DWORD source_size); + +// -------------------------------------------------------------------------- +// Metadata routines +// -------------------------------------------------------------------------- + +// tag creation / destruction +DLL_API FITAG *DLL_CALLCONV FreeImage_CreateTag(void); +DLL_API void DLL_CALLCONV FreeImage_DeleteTag(FITAG *tag); +DLL_API FITAG *DLL_CALLCONV FreeImage_CloneTag(FITAG *tag); + +// tag getters and setters +DLL_API const char *DLL_CALLCONV FreeImage_GetTagKey(FITAG *tag); +DLL_API const char *DLL_CALLCONV FreeImage_GetTagDescription(FITAG *tag); +DLL_API WORD DLL_CALLCONV FreeImage_GetTagID(FITAG *tag); +DLL_API FREE_IMAGE_MDTYPE DLL_CALLCONV FreeImage_GetTagType(FITAG *tag); +DLL_API DWORD DLL_CALLCONV FreeImage_GetTagCount(FITAG *tag); +DLL_API DWORD DLL_CALLCONV FreeImage_GetTagLength(FITAG *tag); +DLL_API const void *DLL_CALLCONV FreeImage_GetTagValue(FITAG *tag); + +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagKey(FITAG *tag, const char *key); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagDescription(FITAG *tag, const char *description); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagID(FITAG *tag, WORD id); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagType(FITAG *tag, FREE_IMAGE_MDTYPE type); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagCount(FITAG *tag, DWORD count); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagLength(FITAG *tag, DWORD length); +DLL_API BOOL DLL_CALLCONV FreeImage_SetTagValue(FITAG *tag, const void *value); + +// iterator +DLL_API FIMETADATA *DLL_CALLCONV FreeImage_FindFirstMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, FITAG **tag); +DLL_API BOOL DLL_CALLCONV FreeImage_FindNextMetadata(FIMETADATA *mdhandle, FITAG **tag); +DLL_API void DLL_CALLCONV FreeImage_FindCloseMetadata(FIMETADATA *mdhandle); + +// metadata setter and getter +DLL_API BOOL DLL_CALLCONV FreeImage_SetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG *tag); +DLL_API BOOL DLL_CALLCONV FreeImage_GetMetadata(FREE_IMAGE_MDMODEL model, FIBITMAP *dib, const char *key, FITAG **tag); + +// helpers +DLL_API unsigned DLL_CALLCONV FreeImage_GetMetadataCount(FREE_IMAGE_MDMODEL model, FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_CloneMetadata(FIBITMAP *dst, FIBITMAP *src); + +// tag to C string conversion +DLL_API const char* DLL_CALLCONV FreeImage_TagToString(FREE_IMAGE_MDMODEL model, FITAG *tag, char *Make FI_DEFAULT(NULL)); + +// -------------------------------------------------------------------------- +// JPEG lossless transformation routines +// -------------------------------------------------------------------------- + +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransform(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect FI_DEFAULT(TRUE)); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, BOOL perfect FI_DEFAULT(TRUE)); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCrop(const char *src_file, const char *dst_file, int left, int top, int right, int bottom); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGCropU(const wchar_t *src_file, const wchar_t *dst_file, int left, int top, int right, int bottom); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformFromHandle(FreeImageIO* src_io, fi_handle src_handle, FreeImageIO* dst_io, fi_handle dst_handle, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE)); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformCombined(const char *src_file, const char *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE)); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformCombinedU(const wchar_t *src_file, const wchar_t *dst_file, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE)); +DLL_API BOOL DLL_CALLCONV FreeImage_JPEGTransformCombinedFromMemory(FIMEMORY* src_stream, FIMEMORY* dst_stream, FREE_IMAGE_JPEG_OPERATION operation, int* left, int* top, int* right, int* bottom, BOOL perfect FI_DEFAULT(TRUE)); + + +// -------------------------------------------------------------------------- +// Image manipulation toolkit +// -------------------------------------------------------------------------- + +// rotation and flipping +/// @deprecated see FreeImage_Rotate +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_RotateClassic(FIBITMAP *dib, double angle); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Rotate(FIBITMAP *dib, double angle, const void *bkcolor FI_DEFAULT(NULL)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_RotateEx(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, BOOL use_mask); +DLL_API BOOL DLL_CALLCONV FreeImage_FlipHorizontal(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_FlipVertical(FIBITMAP *dib); + +// upsampling / downsampling +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Rescale(FIBITMAP *dib, int dst_width, int dst_height, FREE_IMAGE_FILTER filter FI_DEFAULT(FILTER_CATMULLROM)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_MakeThumbnail(FIBITMAP *dib, int max_pixel_size, BOOL convert FI_DEFAULT(TRUE)); + +// color manipulation routines (point operations) +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustCurve(FIBITMAP *dib, BYTE *LUT, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustGamma(FIBITMAP *dib, double gamma); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustBrightness(FIBITMAP *dib, double percentage); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustContrast(FIBITMAP *dib, double percentage); +DLL_API BOOL DLL_CALLCONV FreeImage_Invert(FIBITMAP *dib); +DLL_API BOOL DLL_CALLCONV FreeImage_GetHistogram(FIBITMAP *dib, DWORD *histo, FREE_IMAGE_COLOR_CHANNEL channel FI_DEFAULT(FICC_BLACK)); +DLL_API int DLL_CALLCONV FreeImage_GetAdjustColorsLookupTable(BYTE *LUT, double brightness, double contrast, double gamma, BOOL invert); +DLL_API BOOL DLL_CALLCONV FreeImage_AdjustColors(FIBITMAP *dib, double brightness, double contrast, double gamma, BOOL invert FI_DEFAULT(FALSE)); +DLL_API unsigned DLL_CALLCONV FreeImage_ApplyColorMapping(FIBITMAP *dib, RGBQUAD *srccolors, RGBQUAD *dstcolors, unsigned count, BOOL ignore_alpha, BOOL swap); +DLL_API unsigned DLL_CALLCONV FreeImage_SwapColors(FIBITMAP *dib, RGBQUAD *color_a, RGBQUAD *color_b, BOOL ignore_alpha); +DLL_API unsigned DLL_CALLCONV FreeImage_ApplyPaletteIndexMapping(FIBITMAP *dib, BYTE *srcindices, BYTE *dstindices, unsigned count, BOOL swap); +DLL_API unsigned DLL_CALLCONV FreeImage_SwapPaletteIndices(FIBITMAP *dib, BYTE *index_a, BYTE *index_b); + +// channel processing routines +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetChannel(FIBITMAP *dib, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API BOOL DLL_CALLCONV FreeImage_SetChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_GetComplexChannel(FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); +DLL_API BOOL DLL_CALLCONV FreeImage_SetComplexChannel(FIBITMAP *dst, FIBITMAP *src, FREE_IMAGE_COLOR_CHANNEL channel); + +// copy / paste / composite routines +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Copy(FIBITMAP *dib, int left, int top, int right, int bottom); +DLL_API BOOL DLL_CALLCONV FreeImage_Paste(FIBITMAP *dst, FIBITMAP *src, int left, int top, int alpha); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_Composite(FIBITMAP *fg, BOOL useFileBkg FI_DEFAULT(FALSE), RGBQUAD *appBkColor FI_DEFAULT(NULL), FIBITMAP *bg FI_DEFAULT(NULL)); +DLL_API BOOL DLL_CALLCONV FreeImage_PreMultiplyWithAlpha(FIBITMAP *dib); + +// background filling routines +DLL_API BOOL DLL_CALLCONV FreeImage_FillBackground(FIBITMAP *dib, const void *color, int options FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_EnlargeCanvas(FIBITMAP *src, int left, int top, int right, int bottom, const void *color, int options FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateEx(int width, int height, int bpp, const RGBQUAD *color, int options FI_DEFAULT(0), const RGBQUAD *palette FI_DEFAULT(NULL), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_AllocateExT(FREE_IMAGE_TYPE type, int width, int height, int bpp, const void *color, int options FI_DEFAULT(0), const RGBQUAD *palette FI_DEFAULT(NULL), unsigned red_mask FI_DEFAULT(0), unsigned green_mask FI_DEFAULT(0), unsigned blue_mask FI_DEFAULT(0)); + +// miscellaneous algorithms +DLL_API FIBITMAP *DLL_CALLCONV FreeImage_MultigridPoissonSolver(FIBITMAP *Laplacian, int ncycle FI_DEFAULT(3)); + +// restore the borland-specific enum size option +#if defined(__BORLANDC__) +#pragma option pop +#endif + +#ifdef __cplusplus +} +#endif + +#endif // FREEIMAGE_H diff --git a/src/interactions.h b/src/interactions.h index 7bf6fab..4d57738 100644 --- a/src/interactions.h +++ b/src/interactions.h @@ -16,6 +16,11 @@ struct Fresnel { struct AbsorptionAndScatteringProperties{ glm::vec3 absorptionCoefficient; float reducedScatteringCoefficient; + //constructor + AbsorptionAndScatteringProperties(glm::vec3 absorbCoeff, float scatterCoeff){ + absorptionCoefficient = absorbCoeff; + reducedScatteringCoefficient = scatterCoeff; + } }; // Forward declaration @@ -38,24 +43,125 @@ __host__ __device__ bool calculateScatterAndAbsorption(ray& r, float& depth, Abs return false; } + + // TODO (OPTIONAL): IMPLEMENT THIS FUNCTION __host__ __device__ glm::vec3 calculateTransmissionDirection(glm::vec3 normal, glm::vec3 incident, float incidentIOR, float transmittedIOR) { - return glm::vec3(0,0,0); + //snell's law: sin(thetaI) / sin(thetaT) = nt/ni + float eta = incidentIOR/transmittedIOR; + float cosI = -glm::dot(incident, normal); + float sin2T = eta * eta * (1.0f - cosI * cosI); + if(sin2T>1) //TIR + return calculateReflectionDirection(incident, normal); + return eta * incident - (eta * cosI + sqrt(1-sin2T)) * normal; + + //return glm::normalize(glm::refract(glm::normalize(incident),glm::normalize(normal), (float)incidentIOR/(float)transmittedIOR)); + + + } // TODO (OPTIONAL): IMPLEMENT THIS FUNCTION __host__ __device__ glm::vec3 calculateReflectionDirection(glm::vec3 normal, glm::vec3 incident) { - //nothing fancy here - return glm::vec3(0,0,0); + + + //Direction - 2*dot(Direction,Normal)*Normal + return incident - 2.0f * glm::dot(incident, normal) * normal; + //return glm::normalize(glm::reflect(incident,normal)); } // TODO (OPTIONAL): IMPLEMENT THIS FUNCTION -__host__ __device__ Fresnel calculateFresnel(glm::vec3 normal, glm::vec3 incident, float incidentIOR, float transmittedIOR, glm::vec3 reflectionDirection, glm::vec3 transmissionDirection) { - Fresnel fresnel; +__host__ __device__ Fresnel calculateFresnel(glm::vec3 normal, glm::vec3 incident, float incidentIOR, float transmittedIOR) { + + Fresnel f; + f.reflectionCoefficient = 1; + f.transmissionCoefficient = 0; + + float eta = incidentIOR/transmittedIOR; + float cosI = -glm::dot(normal,incident); + float sinT2 = eta * eta *(1.0f-cosI*cosI); + if(sinT2>1){ + f.reflectionCoefficient = 1.0f; //TIR + } + else{ + float cosT = sqrt(1.0f - sinT2); + float rOrth = ( incidentIOR * cosI - transmittedIOR * cosT )/( incidentIOR * cosI + transmittedIOR * cosT ); //s-polarization, orthogonal + float rPar = ( incidentIOR * cosT - transmittedIOR * cosI )/( incidentIOR * cosT + transmittedIOR * cosI); //p- polarization, parallel + f.reflectionCoefficient = (rOrth*rOrth + rPar*rPar)/2.0f; + } + f.transmissionCoefficient = 1.0f - f.reflectionCoefficient; + return f; + + /* glm::vec3 inDir = glm::normalize(incident); + + float cosIncidentAngle = glm::dot(inDir, -normal); + float sinIncidentAngle = glm::length(glm::cross(inDir, normal)); + float cosTransmitAngle; + + if(incidentIOR < transmittedIOR) // from air to glass + { + cosTransmitAngle = cos(asin(incidentIOR / transmittedIOR * sinIncidentAngle)); + fresnel.reflectionCoefficient = pow(abs((incidentIOR * cosIncidentAngle - transmittedIOR * cosTransmitAngle) + / (incidentIOR * cosIncidentAngle + transmittedIOR * cosTransmitAngle)), 2); + fresnel.reflectionCoefficient += pow(abs((incidentIOR * cosTransmitAngle - transmittedIOR * cosIncidentAngle) + / (incidentIOR * cosTransmitAngle + transmittedIOR * cosIncidentAngle)), 2); + fresnel.reflectionCoefficient /= 2.0f; + } + else // from glass to air + { + float sinCriticalAngle = transmittedIOR / incidentIOR; + if(sinIncidentAngle > sinCriticalAngle) + { + fresnel.reflectionCoefficient = 1.0f; + } + else + { + cosTransmitAngle = cos(asin(incidentIOR / transmittedIOR * sinIncidentAngle)); + fresnel.reflectionCoefficient = pow(abs((incidentIOR * cosIncidentAngle - transmittedIOR * cosTransmitAngle) + / (incidentIOR * cosIncidentAngle + transmittedIOR * cosTransmitAngle)), 2); + fresnel.reflectionCoefficient += pow(abs((incidentIOR * cosTransmitAngle - transmittedIOR * cosIncidentAngle) + / (incidentIOR * cosTransmitAngle + transmittedIOR * cosIncidentAngle)), 2); + fresnel.reflectionCoefficient /= 2.0f; + } + + } + + fresnel.transmissionCoefficient = 1 - fresnel.reflectionCoefficient; + return fresnel;*/ +} - fresnel.reflectionCoefficient = 1; - fresnel.transmissionCoefficient = 0; - return fresnel; +__host__ __device__ glm::vec3 calculateCosWeightedRandomDirInHemisphere( glm::vec3 n, float Xi1, float Xi2) +{ + + /*const float r = Sqrt(u1); + const float theta = 2 * kPi * u2; + + const float x = r * Cos(theta); + const float y = r * Sin(theta); + + return Vector3(x, y, Sqrt(Max(0.0f, 1 - u1)));*/ + + float theta = acos(sqrt(1.0-Xi1)); + float phi = 2.0f * PI * Xi2; + + float xs = sinf(theta) * cosf(phi); + float ys = cosf(theta); + float zs = sinf(theta) * sinf(phi); + + glm::vec3 y = n; + glm::vec3 h = n; + if (fabs(h.x) <= fabs(h.y) && fabs(h.x) <= fabs(h.z)) + h.x = 1.0; //h.x is smallest + else if (fabs(h.y) <= fabs(h.x) && fabs(h.y) <= fabs(h.z)) + h.y = 1.0; + else + h.z = 1.0; + + glm::vec3 x = glm::normalize( glm::cross( h, y ) ); + glm::vec3 z = glm::normalize( glm::cross( x, y ) ); + + glm::vec3 direction = glm::normalize(xs * x + ys * y + zs * z); + return direction; } // LOOK: This function demonstrates cosine weighted random direction generation in a sphere! @@ -91,16 +197,41 @@ __host__ __device__ glm::vec3 calculateRandomDirectionInHemisphere(glm::vec3 nor // non-cosine (uniform) weighted random direction generation. // This should be much easier than if you had to implement calculateRandomDirectionInHemisphere. __host__ __device__ glm::vec3 getRandomDirectionInSphere(float xi1, float xi2) { - return glm::vec3(0,0,0); + + // Crucial difference between this and calculateRandomDirectionInSphere: THIS IS COSINE WEIGHTED! + + float up = sqrt(xi1); // cos(theta) + float over = sqrt(1 - up * up); // sin(theta) + float around = xi2 * TWO_PI; + + + + return glm::vec3(0,0,0); + + //return glm::vec3(0,0,0); } // TODO (PARTIALLY OPTIONAL): IMPLEMENT THIS FUNCTION // Returns 0 if diffuse scatter, 1 if reflected, 2 if transmitted. -__host__ __device__ int calculateBSDF(ray& r, glm::vec3 intersect, glm::vec3 normal, glm::vec3 emittedColor, - AbsorptionAndScatteringProperties& currentAbsorptionAndScattering, - glm::vec3& color, glm::vec3& unabsorbedColor, material m){ - - return 1; +__host__ __device__ int calculateBSDF(ray& r, glm::vec3 intersect, glm::vec3 normal, glm::vec3& color, + glm::vec3& unabsorbedColor, material m, int seed){ + + AbsorptionAndScatteringProperties ASP( m.absorptionCoefficient, m.reducedScatterCoefficient); + + if(m.hasReflective>0){ //relection + return 1; + } + else if(m.hasRefractive){ //refraction + return 2; + } + else{ //diffuse + thrust::default_random_engine rng(seed); + thrust::uniform_real_distribution u01(0,1); + r.direction = calculateRandomDirectionInHemisphere( normal, (float) u01(rng), (float) u01(rng)); + r.origin = intersect + r.direction * 0.000001f; + color = m.color; + return 0; + } }; #endif diff --git a/src/intersections.h b/src/intersections.h index c9eafb6..3f697f1 100644 --- a/src/intersections.h +++ b/src/intersections.h @@ -8,7 +8,7 @@ #include #include - +#include #include "sceneStructs.h" #include "cudaMat4.h" #include "utilities.h" @@ -21,6 +21,7 @@ __host__ __device__ glm::vec3 getInverseDirectionOfRay(ray r); __host__ __device__ float boxIntersectionTest(staticGeom sphere, ray r, glm::vec3& intersectionPoint, glm::vec3& normal); __host__ __device__ float sphereIntersectionTest(staticGeom sphere, ray r, glm::vec3& intersectionPoint, glm::vec3& normal); __host__ __device__ glm::vec3 getRandomPointOnCube(staticGeom cube, float randomSeed); +__host__ __device__ glm::vec3 getRandomPointOnSphere(staticGeom sphere, float randomSeed); // Handy dandy little hashing function that provides seeds for random number generation __host__ __device__ unsigned int hash(unsigned int a){ @@ -58,6 +59,16 @@ __host__ __device__ glm::vec3 multiplyMV(cudaMat4 m, glm::vec4 v){ return r; } +__host__ __device__ cudaMat4 transposeM(cudaMat4 m){ + cudaMat4 mt; + mt.x.x = m.x.x; mt.y.y = m.y.y; mt.z.z = m.z.z; mt.w.w = m.w.w; //diagonal term remains + mt.x.y = m.y.x; mt.x.z = m.z.x; mt.x.w = m.w.x; + mt.y.z = m.z.y; mt.y.w = m.w.y; + mt.z.w = m.w.z; + + return mt; +} + // Gets 1/direction for a ray __host__ __device__ glm::vec3 getInverseDirectionOfRay(ray r){ return glm::vec3(1.0/r.direction.x, 1.0/r.direction.y, 1.0/r.direction.z); @@ -69,13 +80,204 @@ __host__ __device__ glm::vec3 getSignOfRay(ray r){ return glm::vec3((int)(inv_direction.x < 0), (int)(inv_direction.y < 0), (int)(inv_direction.z < 0)); } + +//find the smallest positive value within an array +__host__ __device__ float find_smallest_t( float* ptr, int length){ + //double* ptr = t_ptr; + float min=-1; + bool flag=true; + for ( int i=0; i=0){ + min = *ptr; + flag = false; //turn off first flag + } + if(*ptr=0 && flag==false) + min = *ptr; + ptr++; + } + return min; +} + + + + // TODO: IMPLEMENT THIS FUNCTION // Cube intersection test, return -1 if no intersection, otherwise, distance to intersection +/*__host__ __device__ float boxIntersectionTest(staticGeom box, ray r, glm::vec3& intersectionPoint, glm::vec3& normal){ + + float min = -0.5, max = 0.5; + float t,D,ans = -1, index = -1; + glm::vec3 N,A,B,Pi,p[8],p1,p2,p3; + + //transform the ray into object space, r_OS = inverseT * r_WS + glm::vec3 P = multiplyMV ( box.inverseTransform, glm::vec4( r.origin, 1.0f )); + glm::vec3 V = glm::normalize( multiplyMV ( box.inverseTransform, glm::vec4( r.direction, 0.0f )) ); + ray rt; rt.origin = P; rt.direction = V; + + //deifning vertex for cube + p[0] = glm::vec3(min,min,min); p[1] = glm::vec3(min,min,max); p[2] = glm::vec3(max,min,max); p[3] = glm::vec3(max,min,min); + p[4] = glm::vec3(min,max,min); p[5] = glm::vec3(min,max,max); p[6] = glm::vec3(max,max,max); p[7] = glm::vec3(max,max,min); + + + for(int i=0; i<6; i++){ + t = -1; + + if(i<4){ //left,front, right, back plane + p1 = p[i]; p2 = p[i+1]; p3 = p[i+4]; + } + else if(i==4){ //bottom plane + p1 = p[0]; p2 = p[1]; p3 = p[2]; + } + else if(i==5){ //top plane + p1 = p[4]; p2 = p[5]; p3 = p[6]; + } + + //defining plane + A = p2 - p1; + B = p3 - p1; + N = glm::cross( A, B ); + Pi = glm::vec3( 0, 0, 0 ); + + //ray is not parallel with plane + if( (glm::dot(N,V) - 0)>EPSILON ){ + D = glm::dot(N,p1); + t = -( glm::dot(N,P) + D ) / glm::dot(N,V); + Pi = P + t * V; + } + + //intersection point is not within the quare boundary + if( t>0 && (Pi.x>max || Pi.y>max || Pi.z>max || Pi.x0) || (ans>0 && t>0 && t-1 ){ //has intersection + // point_WS = T * point_OS + // normal_WS = transpose(inverseT) * normal_OS + glm::vec4 tempNormal; + if(index == 0){ + tempNormal = glm::vec4(-1,0,0,0); + //normal = multiplyMV ( transposeM(box.inverseTransform), glm::vec4(-1,0,0,0) ); //left plane + } + else if(index == 1){ + tempNormal = glm::vec4(0,0,1,0); + //normal = multiplyMV ( transposeM(box.inverseTransform), glm::vec4(0,0,1,0) ); //front plane + } + else if(index == 2){ + tempNormal = glm::vec4(1,0,0,0); + //normal = multiplyMV ( transposeM(box.inverseTransform), glm::vec4(1,0,0,0) ); //right plane + } + else if(index == 3){ + tempNormal = glm::vec4(0,0,-1,0); + //normal = multiplyMV ( transposeM(box.inverseTransform), glm::vec4(0,0,-1,0) ); //back plane + } + else if(index == 4){ + tempNormal = glm::vec4(0,-1,0,0); + //normal = multiplyMV ( transposeM(box.inverseTransform), glm::vec4(0,-1,0,0) ); //bottom plane + } + else if(index == 5){ + //normal = multiplyMV ( transposeM(box.inverseTransform), glm::vec4(0,1,0,0) ); //top plane + } + normal = glm::normalize( multiplyMV ( transposeM(box.inverseTransform),tempNormal ) ); + //t_WS = t_OS/length(r_OS) + //p_WS = r_WS_start + r_WS_direction * t_WS + + //glm::vec3 realIntersectionPoint = multiplyMV(box.transform, glm::vec4(getPointOnRay(rt, ans), 1.0)); + //glm::vec3 realOrigin = multiplyMV(box.transform, glm::vec4(0,0,0,1)); + //intersectionPoint = realIntersectionPoint; + //normal = glm::normalize(realIntersectionPoint - realOrigin); + // printf("normal [%f,%f,%f]\n", normal.x,normal.y,normal.z); + //return glm::length(r.origin - realIntersectionPoint); + intersectionPoint = rt.origin + ans * rt.direction; + return glm::length(intersectionPoint - r.origin); + } + else{ + return -1; + } +}*/ + +//Cube intersection test, return -1 if no intersection, otherwise, distance to intersection __host__ __device__ float boxIntersectionTest(staticGeom box, ray r, glm::vec3& intersectionPoint, glm::vec3& normal){ + ray rt; //transformed r + + glm::vec3 bounds[2]; + if(box.type == MESH){ + bounds[0] = box.bBoxMin; + bounds[1] = box.bBoxMax; + rt.origin = r.origin; + rt.direction = r.direction; //already transformed + } + else{ + //transform the ray into object space, r_OS = inverseT * r_WS + rt.origin = multiplyMV ( box.inverseTransform, glm::vec4( r.origin, 1.0f )); + rt.direction = glm::normalize( multiplyMV ( box.inverseTransform, glm::vec4( r.direction, 0.0f )) ); + bounds[0] = glm::vec3(-0.5f, -0.5f, -0.5f); // unit cube in OS with unit length on each edge + bounds[1] = glm::vec3(0.5f, 0.5f, 0.5f); + } - return -1; + + glm::vec3 invDir = getInverseDirectionOfRay(rt); + int sign[3]; + sign[0] = (invDir.x < 0); + sign[1] = (invDir.y < 0); + sign[2] = (invDir.z < 0); + + double tmin, tmax, tymin, tymax, tzmin, tzmax, t; + tmin = (bounds[sign[0]].x - rt.origin.x) * invDir.x; + tmax = (bounds[1-sign[0]].x - rt.origin.x) * invDir.x; + tymin = (bounds[sign[1]].y - rt.origin.y) * invDir.y; + tymax = (bounds[1-sign[1]].y - rt.origin.y) * invDir.y; + + if ((tmin > tymax) || (tymin > tmax)) + return -1.0f; + if (tymin > tmin) + tmin = tymin; + if (tymax < tmax) + tmax = tymax; + tzmin = (bounds[(int)sign[2]].z - rt.origin.z) * invDir.z; + tzmax = (bounds[1-(int)sign[2]].z - rt.origin.z) * invDir.z; + + if ((tmin > tzmax) || (tzmin > tmax)) + return -1.0f; + if (tzmin > tmin) + tmin = tzmin; + if (tzmax < tmax) + tmax = tzmax; + if (tmax < 0.0) + return -1.0f; + if (tmin < 0.0) + t = tmax; // inside + else + t = tmin; //outside + + glm::vec3 intersect_os = float(t) * rt.direction + rt.origin; + glm::vec3 tempNormal; + if( fabs(intersect_os.x - bounds[0].x) < EPSILON) + tempNormal = glm::vec3(-1.0f, 0.0f, 0.0f); + else if( fabs( intersect_os.x - bounds[1].x) < EPSILON) + tempNormal = glm::vec3(1.0f, 0.0f, 0.0f); + else if( fabs( intersect_os.y - bounds[0].y) < EPSILON) + tempNormal = glm::vec3(0.0f, -1.0f, 0.0f); + else if( fabs( intersect_os.y - bounds[1].y) < EPSILON) + tempNormal = glm::vec3(0.0f, 1.0f, 0.0f); + else if( fabs( intersect_os.z - bounds[0].z) < EPSILON) + tempNormal = glm::vec3(0.0f, 0.0f, -1.0f); + else if( fabs( intersect_os.z - bounds[1].z) < EPSILON) + tempNormal = glm::vec3(0.0f, 0.0f, 1.0f); + + intersectionPoint = multiplyMV(box.transform, glm::vec4(intersect_os, 1.0f)); + + normal = glm::normalize(multiplyMV(box.transform, glm::vec4(tempNormal, 0.0f))); + + return glm::length(r.origin - intersectionPoint); } + // LOOK: Here's an intersection test example from a sphere. Now you just need to figure out cube and, optionally, triangle. // Sphere intersection test, return -1 if no intersection, otherwise, distance to intersection __host__ __device__ float sphereIntersectionTest(staticGeom sphere, ray r, glm::vec3& intersectionPoint, glm::vec3& normal){ @@ -116,6 +318,98 @@ __host__ __device__ float sphereIntersectionTest(staticGeom sphere, ray r, glm:: return glm::length(r.origin - realIntersectionPoint); } +__host__ __device__ float triangleIntersectionTest(triangle& tri, ray rt, glm::vec3& intersectionPoint, glm::vec3& normal){ + + +/* glm::vec3 P = multiplyMV ( tri.inverseTransform, glm::vec4( r.origin, 1.0f )); + glm::vec3 V = glm::normalize( multiplyMV ( tri.inverseTransform, glm::vec4( r.direction, 0.0f )) ); + ray rt; rt.origin = P; rt.direction = V; //transformed r*/ + + // rt is already transformed + glm::vec3 p1 = tri.p1; + glm::vec3 p2 = tri.p2; + glm::vec3 p3 = tri.p3; + glm::vec3 e1 = p2 - p1; + glm::vec3 e2 = p3 - p1; + glm::vec3 n = glm::cross(e1, e2); + + if (glm::length(n) < EPSILON) //degenerate + return -1; + + glm::vec3 w0 = rt.origin - p1; //ray origin test + float a = - glm::dot(n, w0); + float b = glm::dot(n, rt.direction); + if (fabs(b) < EPSILON) // parallel + return -1; + if (fabs(a) < EPSILON) // in plane + return -1; + + float L = a/b; + if (L < 0) + return -1; //no intersect + + glm::vec3 p = rt.origin + L*rt.direction; //intersect + + float e11 = glm::dot(e1, e1); + float e12 = glm::dot(e1, e2); + float e22 = glm::dot(e2, e2); + glm::vec3 w = p - p1; + float we1 = glm::dot(w, e1); + float we2 = glm::dot(w, e2); + + float D = e12 * e12 - e11 * e22; + float s = (e12 * we2 - e22 * we1) / D; + float t = (e12 * we1 - e11 * we2) / D; + + if(s < 0 || s > 1) // outside triangle + return -1; + if (t < 0 || (s + t) > 1) // outside triangle + return -1; + + normal = glm::normalize(n); + intersectionPoint = p; + return L; + +} + + +__host__ __device__ float polygonIntersectionTest(staticGeom polygon, ray r, glm::vec3& intersectionPoint, glm::vec3& normal, triangle * cudatris){ + + //transform the ray into object space, r_OS = inverseT * r_WS + glm::vec3 P = multiplyMV ( polygon.inverseTransform, glm::vec4( r.origin, 1.0f )); + glm::vec3 V = glm::normalize( multiplyMV ( polygon.inverseTransform, glm::vec4( r.direction, 0.0f )) ); + ray rt; rt.origin = P; rt.direction = V; //transformed r + //bounding box test + /*printf("bounding box:\n [%.2f, %.2f, %.2f]\n [%.2f, %.2f, %.2f]\n", polygon.bBoxMin.x, polygon.bBoxMin.y, polygon.bBoxMin.z, + polygon.bBoxMax.x, polygon.bBoxMax.y, polygon.bBoxMax.z);*/ + float t = -1, tMin = -2; + glm::vec3 localIntersect, localNormal; + if(boxIntersectionTest(polygon, rt, intersectionPoint, normal) > 0){ + //printf("intersect bounding box\n"); + glm::vec3 tempIntersect, tempNormal; //they are in local space + + for (int i=0; i -0.5f ) || ( tMin > -1 && t < tMin && t > -0.5f ) ){ + tMin = t; + localIntersect = tempIntersect; + localNormal = tempNormal; + } + } + intersectionPoint = multiplyMV(polygon.transform, glm::vec4(localIntersect, 1.0f)); + glm::vec3 normalP_OS = intersectionPoint + localNormal; + glm::vec3 normalP_WS = multiplyMV(polygon.transform, glm::vec4(normalP_OS, 1.0f)); + normal = glm::normalize(normalP_WS - intersectionPoint); + //printf("distance %.2f\n", tMin); + return tMin; + } + return -1; +} + // Returns x,y,z half-dimensions of tightest bounding box __host__ __device__ glm::vec3 getRadiuses(staticGeom geom){ glm::vec3 origin = multiplyMV(geom.transform, glm::vec4(0,0,0,1)); @@ -130,7 +424,7 @@ __host__ __device__ glm::vec3 getRadiuses(staticGeom geom){ // LOOK: Example for generating a random point on an object using thrust. // Generates a random point on a given cube -__host__ __device__ glm::vec3 getRandomPointOnCube(staticGeom cube, float randomSeed){ +__host__ __device__ glm::vec3 getRandomPointOnCube(staticGeom cube, float randomSeed, glm::vec3& finalNormal, float& finalArea){ thrust::default_random_engine rng(hash(randomSeed)); thrust::uniform_real_distribution u01(0,1); @@ -147,40 +441,78 @@ __host__ __device__ glm::vec3 getRandomPointOnCube(staticGeom cube, float random float russianRoulette = (float)u01(rng); glm::vec3 point = glm::vec3(.5,.5,.5); - + glm::vec3 normal = glm::vec3(0,0,0); if(russianRoulette<(side1/totalarea)){ // x-y face + finalArea = side1; + normal = glm::vec3(0,0,1); point = glm::vec3((float)u02(rng), (float)u02(rng), .5); }else if(russianRoulette<((side1*2)/totalarea)){ // x-y-back face + finalArea = side1; + normal = glm::vec3(0,0,-1); point = glm::vec3((float)u02(rng), (float)u02(rng), -.5); }else if(russianRoulette<(((side1*2)+(side2))/totalarea)){ // y-z face + finalArea = side2; + normal = glm::vec3(1,0,0); point = glm::vec3(.5, (float)u02(rng), (float)u02(rng)); }else if(russianRoulette<(((side1*2)+(side2*2))/totalarea)){ // y-z-back face + finalArea = side2; + normal = glm::vec3(-1,0,0); point = glm::vec3(-.5, (float)u02(rng), (float)u02(rng)); }else if(russianRoulette<(((side1*2)+(side2*2)+(side3))/totalarea)){ // x-z face + finalArea = side3; + normal = glm::vec3(0,1,0); point = glm::vec3((float)u02(rng), .5, (float)u02(rng)); }else{ // x-z-back face + finalArea = side3; + normal = glm::vec3(0,-1,0); point = glm::vec3((float)u02(rng), -.5, (float)u02(rng)); } glm::vec3 randPoint = multiplyMV(cube.transform, glm::vec4(point,1.0f)); + glm::vec3 normalP_OS = point + normal; + glm::vec3 normalP_WS = multiplyMV(cube.transform, glm::vec4(normalP_OS, 1.0f)); + finalNormal = glm::normalize(normalP_WS - randPoint); + return randPoint; } + + + // TODO: IMPLEMENT THIS FUNCTION // Generates a random point on a given sphere -__host__ __device__ glm::vec3 getRandomPointOnSphere(staticGeom sphere, float randomSeed){ +__host__ __device__ glm::vec3 getRandomPointOnSphere(staticGeom sphere, float randomSeed, glm::vec3& finalNormal, float& finalArea){ - return glm::vec3(0,0,0); + thrust::default_random_engine rng(hash(randomSeed)); + thrust::uniform_real_distribution u01(0,1); + float E1 = (float)u01(rng); // E1 = sin^2(theta) + float E2 = (float)u01(rng); //E2 = theta / (2*PI) + float z = 1.0f - 2.0f * E1; + float x = cos(2.0f * PI * E2) * sqrt (1.0f - z*z); + float y = sin(2.0f * PI * E2) * sqrt (1.0f - z*z); + glm::vec3 point_OS(x,y,z); + glm::vec3 point_WS = multiplyMV(sphere.transform, glm::vec4(point_OS,1.0f)); + glm::vec3 normalP_OS = point_OS; + glm::vec3 normalP_WS = multiplyMV(sphere.transform, glm::vec4(normalP_OS, 1.0f)); + finalNormal = glm::normalize(normalP_WS - point_WS); + glm::vec3 radii = getRadiuses(sphere); + float r = max(radii.x, max(radii.y, radii.z)); + finalArea = 4.0f * PI * r * r; + return point_WS; + + + //return glm::vec3(0,0,0); } + #endif diff --git a/src/main.cpp b/src/main.cpp index b002500..bc86962 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,15 @@ #include "main.h" #define GLEW_STATIC +#pragma comment(lib,"FreeImage.lib") + +__host__ __device__ glm::vec3 multiplyMVMain(cudaMat4 m, glm::vec4 v){ + glm::vec3 r(1,1,1); + r.x = (m.x.x*v.x)+(m.x.y*v.y)+(m.x.z*v.z)+(m.x.w*v.w); + r.y = (m.y.x*v.x)+(m.y.y*v.y)+(m.y.z*v.z)+(m.y.w*v.w); + r.z = (m.z.x*v.x)+(m.z.y*v.y)+(m.z.z*v.z)+(m.z.w*v.w); + return r; +} //------------------------------- //-------------MAIN-------------- @@ -14,17 +23,18 @@ int main(int argc, char** argv){ // Set up pathtracer stuff - bool loadedScene = false; + bool loadedScene = true; finishedRender = false; targetFrame = 0; singleFrameMode = false; - + // Load scene file for(int i=1; iresolution[1]; if(targetFrame >= renderCam->frames){ - cout << "Warning: Specified target frame is out of range, defaulting to frame 0." << endl; + cout << "Warning: Specified target frame is out of range , defaulting to frame 0." << endl; targetFrame = 0; } @@ -58,14 +68,29 @@ int main(int argc, char** argv){ return 0; } - +cudaEvent_t start, stop; +float timeDuration; void mainLoop() { while(!glfwWindowShouldClose(window)){ glfwPollEvents(); + + //cuda timer event + cudaEventCreate(&start); + cudaEventCreate(&stop); + cudaEventRecord( start, 0 ); + runCuda(); - string title = "CIS565 Render | " + utilityCore::convertIntToString(iterations) + " Iterations"; - glfwSetWindowTitle(window, title.c_str()); + cudaEventRecord( stop, 0 ); + cudaEventSynchronize( stop ); + cudaEventElapsedTime( &timeDuration, start, stop ); + + string title = "GPU MC Pathtracer | " + utilityCore::convertIntToString(iterations) + " Iterations | " + + utilityCore::convertFloatToString(timeDuration) + "ms"; + glfwSetWindowTitle(window, title.c_str()); + //char title[1000]; + //sprintf(title, "GPU Path Tracer | %d iterations", iterations); + //glfwSetWindowTitle(window, title); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); glBindTexture(GL_TEXTURE_2D, displayImage); @@ -106,7 +131,9 @@ void runCuda(){ } // execute the kernel - cudaRaytraceCore(dptr, renderCam, targetFrame, iterations, materials, renderScene->materials.size(), geoms, renderScene->objects.size() ); + cudaRaytraceCore(dptr, renderCam, targetFrame, iterations, + materials, renderScene->materials.size(), geoms, renderScene->objects.size(), + textureColor, textureMap ); // unmap buffer object cudaGLUnmapBufferObject(pbo); @@ -126,7 +153,8 @@ void runCuda(){ gammaSettings gamma; gamma.applyGamma = true; gamma.gamma = 1.0; - gamma.divisor = 1.0; + //gamma.divisor = 1.0; + gamma.divisor = renderCam->iterations; outputImage.setGammaSettings(gamma); string filename = renderCam->imageName; string s; @@ -170,7 +198,7 @@ bool init(int argc, char* argv[]) { width = 800; height = 800; - window = glfwCreateWindow(width, height, "CIS 565 Pathtracer", NULL, NULL); + window = glfwCreateWindow(width, height, "GPU MC Pathtracer", NULL, NULL); if (!window){ glfwTerminate(); return false; @@ -187,9 +215,15 @@ bool init(int argc, char* argv[]) { // Initialize other stuff initVAO(); initTextures(); +//initMesh(); initCuda(); initPBO(); + //initialize texture + initTextureMap(-1, "C:/Users/AppleDu/Documents/GitHub/Project3-Pathtracer/data/texture/wood2.jpg"); + initTextureMap(-2, "C:/Users/AppleDu/Documents/GitHub/Project3-Pathtracer/data/texture/earthmap1024.png"); + initTextureMap(-3, "C:/Users/AppleDu/Documents/GitHub/Project3-Pathtracer/data/texture/checker.jpg"); + initTextureMap(-4, "C:/Users/AppleDu/Documents/GitHub/Project3-Pathtracer/data/texture/wall.jpg"); GLuint passthroughProgram; passthroughProgram = initShader(); @@ -218,10 +252,17 @@ void initPBO(){ } void initCuda(){ - cudaGLSetGLDevice(0); + // Use device with highest Gflops/s + // cudaGLSetGLDevice( gpuGetMaxGflopsDeviceId() ); + //initMesh(); + //cudaDeviceSynchronize(); //Blocks until the device has completed all preceding requested tasks + //cudaDeviceReset(); //Explicitly destroys and cleans up all resources associated with the current device in the current process + //initMesh(); + cudaGLSetGLDevice(0); //Records the calling thread's current OpenGL context as the OpenGL context to use for OpenGL interoperability with the CUDA device // Clean up on program exit atexit(cleanupCuda); + } void initTextures(){ @@ -282,6 +323,21 @@ GLuint initShader() { return program; } + +void initMesh(){ //intialize cuda memory for the triangle list in MESH objects + + for(int i = 0; i < renderScene->objects.size(); i++){ + if(renderScene->objects[i].type == MESH){ + triangle * cudatris = NULL; + cudaMalloc((void**)&cudatris, renderScene->objects[i].numOfTris *sizeof(triangle)); + cudaMemcpy( cudatris, renderScene->objects[i].tris, renderScene->objects[i].numOfTris *sizeof(triangle), cudaMemcpyHostToDevice); + renderScene->objects[i].tris = cudatris; + } + } + + +} + //------------------------------- //---------CLEANUP STUFF--------- //------------------------------- @@ -289,6 +345,7 @@ GLuint initShader() { void cleanupCuda(){ if(pbo) deletePBO(&pbo); if(displayImage) deleteTexture(&displayImage); + //deleteMesh(); } void deletePBO(GLuint* pbo){ @@ -308,6 +365,14 @@ void deleteTexture(GLuint* tex){ *tex = (GLuint)NULL; } +void deleteMesh(){ + for(int i = 0; i < renderScene->objects.size(); i++){ + if(renderScene->objects[i].type == MESH){ + cudaFree(renderScene->objects[i].tris); + } + } +} + //------------------------------ //-------GLFW CALLBACKS--------- //------------------------------ @@ -316,8 +381,172 @@ void errorCallback(int error, const char* description){ fputs(description, stderr); } + +void cameraReset() +{ + iterations = 0; + //preColors = new glm::vec3[width * height]; + for(int i = 0; i < width * height; i++) + renderCam->image[i] = glm::vec3(0,0,0); +} + void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods){ + renderCam = &renderScene->renderCam; if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS){ glfwSetWindowShouldClose(window, GL_TRUE); } + else if( key ==GLFW_KEY_A ){ //left + glm::vec3 right = glm::cross(renderCam->views[0], renderCam->ups[0]); + renderCam->positions[0] += (float)STEP_SIZE *0.5f * right; + //renderCam->positions[0].x -= (float)STEP_SIZE * 0.5f; + cameraReset(); + } + else if( key ==GLFW_KEY_D ){ //right + glm::vec3 right = glm::cross(renderCam->views[0], renderCam->ups[0]); + renderCam->positions[0] += -(float)STEP_SIZE * 0.5f*right; + //renderCam->positions[0].x += (float)STEP_SIZE * 0.5f; + cameraReset(); + } + else if( key ==GLFW_KEY_W ){ //up + renderCam->positions[0] += (float)STEP_SIZE *0.5f* (renderCam->ups[0]); + //renderCam->positions[0].y += (float)STEP_SIZE * 0.5f; + cameraReset(); + } + else if( key ==GLFW_KEY_S ){ //down + renderCam->positions[0] += - (float)STEP_SIZE *0.5f* (renderCam->ups[0]); + //renderCam->positions[0].y -= (float)STEP_SIZE * 0.5f; + cameraReset(); + } + else if ( key ==GLFW_KEY_Q ){ //forward + renderCam->positions[0] += (float)STEP_SIZE * 0.5f* (renderCam->views[0]); + //renderCam->positions[0].z -= (float)STEP_SIZE * 0.5f; + cameraReset(); + } + else if ( key == GLFW_KEY_E ){ //backward + renderCam->positions[0] += - (float)STEP_SIZE * 0.5f* (renderCam->views[0]); + //renderCam->positions[0].z += (float)STEP_SIZE * 0.5f; + cameraReset(); + } + else{ + glm::vec3 translation = *renderCam->positions; + glm::vec3 scale(1,1,1); + glm::vec3 rotationV(0,0,0); //view rotation + glm::vec3 rotationU(0,0,0); //up rotation + if ( key == GLFW_KEY_UP){ //rotate up + rotationV = glm::vec3((float)STEP_SIZE,0,0); //x-axis rotation + /*glm::vec3 translation = *renderCam->positions; + glm::vec3 rotation((float)STEP_SIZE,0,0); //x-axis rotation + glm::vec3 scale(1,1,1); + glm::mat4 transform = utilityCore::buildTransformationMatrix(translation, rotation, scale); + cudaMat4 transformMy = utilityCore::glmMat4ToCudaMat4(transform); + glm::vec3 right = glm::cross(renderCam->views[0], renderCam->ups[0]); + glm::vec3 newView = multiplyMVMain(transformMy, glm::vec4(*renderCam->views,0.0f)); + glm::vec3 newUp = glm::cross(right, newView); + renderCam->views[0] = newView; + renderCam->ups[0] = newUp; + cameraReset();*/ + } + else if ( key == GLFW_KEY_DOWN ){ //rotate down + rotationV = glm::vec3(-(float)STEP_SIZE,0,0); //x-axis rotation + } + else if(key == GLFW_KEY_LEFT){ //rotate to left + rotationV = glm::vec3(0,-(float)STEP_SIZE,0); //y-axis rotation + } + else if(key == GLFW_KEY_RIGHT){ //rotate to left + rotationV = glm::vec3(0,(float)STEP_SIZE,0); //y-axis rotation + } + else if(key == GLFW_KEY_COMMA){ //rotate CCW + rotationU = glm::vec3(0,0,-(float)STEP_SIZE); //z-axis rotation + } + else if(key == GLFW_KEY_PERIOD){ //rotate CW + rotationU = glm::vec3(0,0,(float)STEP_SIZE); //z-axis rotation + } + glm::mat4 transform; + cudaMat4 transformMy; + glm::vec3 right, newView, newUp; + if(glm::length(rotationV) > 0){ + transform = utilityCore::buildTransformationMatrix(translation, rotationV, scale); + transformMy = utilityCore::glmMat4ToCudaMat4(transform); + right = glm::cross(renderCam->views[0], renderCam->ups[0]); + newView = multiplyMVMain(transformMy, glm::vec4(renderCam->views[0],0.0f)); + newUp = glm::cross(right, newView); + + } + else if(glm::length(rotationU) > 0){ + transform = utilityCore::buildTransformationMatrix(translation, rotationU, scale); + transformMy = utilityCore::glmMat4ToCudaMat4(transform); + right = glm::cross(renderCam->views[0], renderCam->ups[0]); + newUp = multiplyMVMain(transformMy, glm::vec4(renderCam->ups[0],0.0f)); + newView = glm::cross(newUp, right); + } + renderCam->views[0] = newView; + renderCam->ups[0] = newUp; + cameraReset(); + } +} + +//------------------------------ +//-------TEXTURE STUFF--------- +//------------------------------ +//http://www.mingw.org/ +//http://freeimage.sourceforge.net/download.html +//https://www.opengl.org/discussion_boards/showthread.php/163929-image-loading?p=1158293#post1158293 +//http://inst.eecs.berkeley.edu/~cs184/fa09/resources/sec_UsingFreeImage.pdf + +//loading and initializing texture map +void initTextureMap(int id, char* textureFileName){ + int h = 0, w = 0; + int tmp = loadTexture(textureFileName,textureColor,h,w); + if( tmp != -1){ + tex newTex; + newTex.id = id; + newTex.start = tmp; //start index, point to textureColor + newTex.h = h; //height + newTex.w = w; //width + textureMap.push_back(newTex); + } +} + +int loadTexture(char* file, std::vector &c, int &h,int &w){ + FIBITMAP* image = FreeImage_Load( FreeImage_GetFileType(file, 0), file); + if(!image){ + printf("Error: fail to open texture file %s\n", file ); + FreeImage_Unload(image); + return -1; + } + image = FreeImage_ConvertTo32Bits(image); + + w = FreeImage_GetWidth(image); + h = FreeImage_GetHeight(image); + if( w == 0 && h == 0 ) { + printf("Error: texture file is empty\n"); + FreeImage_Unload(image); + return -1; + } + + int start = c.size(); + //int total = w * h; + //if(n.size()>0) //useful when load multiple picture of texture + //total += n[n.size()-1]; + //n.push_back(total); + + //int k = 0; + for(int i = 0; i < w; i++){ + for(int j = 0;j < h; j++){ + RGBQUAD color; + FreeImage_GetPixelColor( image, i, j, &color ); + glm::vec3 nc(color.rgbRed, color.rgbGreen, color.rgbBlue); + c.push_back(nc); + + //printf("color @ %d is %.2f, %.2f, %.2f\n",k, c[k].r, c[k].g, c[k].b); + // k++; + } + } + + FreeImage_Unload(image); + printf("Loaded texture %s with %dx%d pixels\n", file,w,h ); + return start; } + + + diff --git a/src/main.h b/src/main.h index 8bd2aed..82deec4 100644 --- a/src/main.h +++ b/src/main.h @@ -24,11 +24,17 @@ #include "sceneStructs.h" #include "image.h" #include "raytraceKernel.h" +#include "cudaMat4.h" #include "utilities.h" #include "scene.h" +#include "FreeImage.h" //for loading texture from ".jpg", ".png", ".bmp" + +//#include +//#include //gpuGetMaxGflopsDeviceId() -using namespace std; +using namespace std; +#define STEP_SIZE 0.6f //step size of camera movement //------------------------------- //----------PATHTRACER----------- //------------------------------- @@ -86,7 +92,7 @@ void initCuda(); void initTextures(); void initVAO(); GLuint initShader(); - +void initMesh(); //------------------------------- //---------CLEANUP STUFF--------- //------------------------------- @@ -94,7 +100,7 @@ GLuint initShader(); void cleanupCuda(); void deletePBO(GLuint* pbo); void deleteTexture(GLuint* tex); - +void deleteMesh(); //------------------------------ //-------GLFW CALLBACKS--------- //------------------------------ @@ -102,4 +108,14 @@ void mainLoop(); void errorCallback(int error, const char *description); void keyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); + +//------------------------------ +//-------TEXTURE STUFF--------- +//------------------------------ +std::vector textureMap; +std::vector textureColor; +void initTextureMap(int id,char* textureFileName); +int loadTexture(char* file, std::vector &c, int &h,int &w ); + #endif + \ No newline at end of file diff --git a/src/raytraceKernel.cu b/src/raytraceKernel.cu index 9c7bc7d..1d23fd6 100644 --- a/src/raytraceKernel.cu +++ b/src/raytraceKernel.cu @@ -8,7 +8,7 @@ #include #include #include - +#include #include "sceneStructs.h" #include "glm/glm.hpp" #include "utilities.h" @@ -16,6 +16,13 @@ #include "intersections.h" #include "interactions.h" +struct is_dead{ + __host__ __device__ bool operator()(const ray& r) + { + return r.isDead; + } +}; + void checkCUDAError(const char *msg) { cudaError_t err = cudaGetLastError(); if( cudaSuccess != err) { @@ -35,15 +42,51 @@ __host__ __device__ glm::vec3 generateRandomNumberFromThread(glm::vec2 resolutio return glm::vec3((float) u01(rng), (float) u01(rng), (float) u01(rng)); } +__host__ __device__ glm::vec2 generateRandomNumberAntiAliasing(float seed, float x, float y, float d){ + thrust::default_random_engine rng(hash(seed)); + thrust::uniform_real_distribution u01(0,1); + float xOffset = (float)u01(rng) * 2 * d; + float yOffset = (float)u01(rng) * 2 * d; + return glm::vec2(x - d + xOffset, y - d + yOffset); +} + // TODO: IMPLEMENT THIS FUNCTION // Function that does the initial raycast from the camera __host__ __device__ ray raycastFromCameraKernel(glm::vec2 resolution, float time, int x, int y, glm::vec3 eye, glm::vec3 view, glm::vec3 up, glm::vec2 fov){ - ray r; - r.origin = glm::vec3(0,0,0); - r.direction = glm::vec3(0,0,-1); - return r; + + glm::vec3 A = glm::cross(view, up); + glm::vec3 B = glm::cross(A, view); + glm::vec3 M = eye + view; + + glm::vec3 V = (float)tan(fov.y/(float)180.0*PI) * glm::length(view) * glm::normalize(B); + glm::vec3 H = (float)tan(fov.x/(float)180.0*PI) * glm::length(view) * glm::normalize(A); + + //choose point on the image plane based on pixel location + float Sh = float(x)/float(resolution.x-1); + float Sv = 1- float(y)/float(resolution.y-1); //invert y coordinate + + //choose random point on image plane + /*thrust::default_random_engine rng(hash(index*time)); + thrust::uniform_real_distribution u01(0,1); + float Sh = (float) u01(rng); + float Sv = (float) u01(rng);*/ + + //sreen coordinates to world coordinates + glm::vec3 point = M + (float)(2*Sh-1)*H + (float)(2*Sv-1)*V; + + //initial cast of ray + ray r; + r.direction = glm::normalize(point - eye); + r.origin = eye; + r.color = glm::vec3(1,1,1); + r.isDead = false; + return r; } + + + + //Kernel that blacks out a given image buffer __global__ void clearImage(glm::vec2 resolution, glm::vec3* image){ int x = (blockIdx.x * blockDim.x) + threadIdx.x; @@ -55,7 +98,7 @@ __global__ void clearImage(glm::vec2 resolution, glm::vec3* image){ } //Kernel that writes the image to the OpenGL PBO directly. -__global__ void sendImageToPBO(uchar4* PBOpos, glm::vec2 resolution, glm::vec3* image){ +__global__ void sendImageToPBO(uchar4* PBOpos, glm::vec2 resolution, glm::vec3* image, float iterations){ int x = (blockIdx.x * blockDim.x) + threadIdx.x; int y = (blockIdx.y * blockDim.y) + threadIdx.y; @@ -64,9 +107,9 @@ __global__ void sendImageToPBO(uchar4* PBOpos, glm::vec2 resolution, glm::vec3* if(x<=resolution.x && y<=resolution.y){ glm::vec3 color; - color.x = image[index].x*255.0; - color.y = image[index].y*255.0; - color.z = image[index].z*255.0; + color.x = image[index].x*255.0f/iterations; + color.y = image[index].y*255.0f/iterations; + color.z = image[index].z*255.0f/iterations; //weight for each iteration if(color.x>255){ color.x = 255; @@ -88,39 +131,354 @@ __global__ void sendImageToPBO(uchar4* PBOpos, glm::vec2 resolution, glm::vec3* } } + +// loop through all geometry to test ray intersection, returns the geoID that corresponds to intersected geometry + __host__ __device__ int findHitGeo(ray r, glm::vec3& intersect, glm::vec3& normal, staticGeom* geoms, int numberOfGeoms, triangle * cudatris){ + + if(r.isDead) + return -1; + float distMin = -2, dist = -1; + glm::vec3 tempIntersect(0.0f); + glm::vec3 tempNormal(0.0f); + int ID = -1; + //geometry and ray intersect tesing + for (int g=0; g -0.5f ) || ( distMin > -1 && dist < distMin && dist > -0.5f ) ){ + distMin = dist; //update minimum dist + ID = g; //update ID of geometry + intersect = tempIntersect; //update intersct point + normal = tempNormal; //update normal + } + } + return ID; +} + + //return true if there is direct lighting + __host__ __device__ bool ShadowRayTest(ray sr, staticGeom* geoms, int numberOfGeoms, material* materials, triangle * cudatris){ + glm::vec3 intersPoint(0.0f); + glm::vec3 intersNormal(0.0f); + + //printf("shadow ray: [%f,%f,%f], [%f,%f,%f]\n", sr.origin.x,sr.origin.y,sr.origin.z,sr.direction.x,sr.direction.y,sr.direction.z); + int geoID = findHitGeo(sr, intersPoint, intersNormal, geoms, numberOfGeoms, cudatris); + if( geoID>-1 && geoms[geoID].materialid >= 0 &&materials[geoms[geoID].materialid].emittance > 0){ //hit light soource + return true; + } + else{ + return false; + } + +} + + // get shaw ray to a random chosen light, modify the shadowray, return ID of chosen light + __device__ __host__ int getRandomShadowRayDirection(float seed, glm::vec3& theIntersect, int* lights, int numOfLights, + staticGeom* geoms, ray& shadowRay, float& rayLength, glm::vec3 lightNormal, float lightArea){ + + // ****************** choose light first ******************************** // + int chosenLight = lights[0]; //only one light + if( numOfLights > 1){ //more than 1 light + thrust::default_random_engine rng(hash(seed)); + thrust::uniform_real_distribution u01(0,1); + chosenLight = lights[(int)((float)u01(rng) * numOfLights)]; //randomly choose a light to sample + } + + // ****************** find a point on light ******************************** // + glm::vec3 Lnormal(0.0f); //light normal + float Larea; //light area + glm::vec3 Plight; //random point on light + if( geoms[chosenLight].type == CUBE ){ + //Plight = getRandomPointOnCube( geoms[chosenLight], seed); + Plight = getRandomPointOnCube( geoms[chosenLight], seed, Lnormal, Larea); + } + else if( geoms[chosenLight].type == SPHERE ){ + Plight = getRandomPointOnSphere( geoms[chosenLight], seed, Lnormal, Larea); + } + + // ****************** shadow ray test ******************************** // + shadowRay.direction = glm::normalize(Plight - theIntersect); //from intersect to light + shadowRay.origin = theIntersect + (float)EPSILON * shadowRay.direction; + rayLength = glm::length(Plight - theIntersect); + return chosenLight; + } + + + __device__ __host__ glm::vec3 getTextureColor(glm::vec3* cudatexs, tex* cudatexIDs, glm::vec3 &intersect, staticGeom& geom){ + tex theTex = cudatexIDs[abs(geom.materialid)-1]; + // printf("theTex: h=%d, w=%d, start=%d\n", theTex.h, theTex.w, theTex.start); + glm::vec3 p = multiplyMV(geom.inverseTransform, glm::vec4(intersect,1.0f)); + float u,v; + if(geom.type == CUBE){ + // printf("p.x=%f, p.y = %f, p.z=%f, intersect.x=%f, intersect.y=%f, intersect.z=%f\n",p.x, p.y, p.z, intersect.x, intersect.y, intersect.z); + if(std::abs(0.5f - abs(p.x)) < EPSILON){ //left or right face + u = p.z + 0.5f; + v = p.y + 0.5f; + }else if(std::abs(0.5f - abs(p.y)) < EPSILON){ // top or bottom face + u = p.x + 0.5f; + v = p.z + 0.5f; + }else if(std::abs(0.5f - abs(p.z)) < EPSILON){ //front or back face + u = p.x + 0.5f; + v = p.y + 0.5f; v = 1.0f - v; + } + }else if(geom.type == SPHERE){ + glm::vec3 d = glm::vec3(0.0)- glm::vec3(p.x, p.y, p.z); + // printf("p.x=%f, p.y = %f, p.z=%f, intersect.x=%f, intersect.y=%f, intersect.z=%f\n",p.x, p.y, p.z, intersect.x, intersect.y, intersect.z); + u = 0.5f + atan2(d.z, d.x) * 0.5f / PI; + v = 0.5f - asin(d.y) / PI; + } + int i,j,idx = -1; + i = u * (float)theTex.w; + j = v * (float)theTex.h; + idx = i + j * theTex.w + theTex.start; + // printf("x=%f, z=%f, u=%f, v=%f, idx = %d\n",intersect.x * 0.2f,intersect.z * 0.2f, u, v, idx); + if( idx <= theTex.w * theTex.h + theTex.start && idx>=theTex.start ){ + glm::vec3 color(cudatexs[idx].r/255.0, cudatexs[idx].g/255.0, cudatexs[idx].b/255.0); + return color; + } + return intersect; +} + + //calculates the direct lighting for a certain hit point and modify color of that hit +__device__ __host__ void directLighting(float seed, glm::vec3& theColor, glm::vec3& theIntersect, glm::vec3& theNormal, int geoID, + int* lights, int numOfLights, material* cudamats, staticGeom* geoms, int numOfGeoms, triangle * cudatris){ + ray shadowRay; + float rayLen,lightArea; + glm::vec3 lightNormal; + int lightID = getRandomShadowRayDirection(seed, theIntersect, lights, numOfLights, geoms, shadowRay, rayLen, lightNormal, lightArea); + + // ****************** shading if direct illumination ****************** // + if(geoms[geoID].materialid >= 0 ){ + material curMat = cudamats[geoms[geoID].materialid]; //material of the hit goemetry + if(ShadowRayTest(shadowRay, geoms, numOfGeoms, cudamats, cudatris) ){ + float cosTerm = glm::clamp( glm::dot( theNormal, shadowRay.direction ), 0.0f, 1.0f); //proportion of facing light + float cosTerm2 = glm::clamp( glm::dot( lightNormal, -shadowRay.direction ), 0.0f, 1.0f); //proportion of incoming light + float areaSampling = lightArea / (float) pow( rayLen, 2.0f) ; // dA/r^2 + theColor += cudamats[lightID].emittance * curMat.color * cosTerm * cosTerm2 * areaSampling ; + } + } + //don't kill any ray in direct lighting calculation +} + + // TODO: IMPLEMENT THIS FUNCTION // Core raytracer kernel -__global__ void raytraceRay(glm::vec2 resolution, float time, cameraData cam, int rayDepth, glm::vec3* colors, - staticGeom* geoms, int numberOfGeoms){ +__global__ void raytraceRay(ray* rays, float time, int rayDepth, int numOfRays, glm::vec3* colors, + staticGeom* geoms, int numberOfGeoms, material* cudamats, int* lights, int numOfLights, + cameraData cam, triangle* cudatris, glm::vec3* cudatexs, tex* cudatexIDs){ int x = (blockIdx.x * blockDim.x) + threadIdx.x; int y = (blockIdx.y * blockDim.y) + threadIdx.y; - int index = x + (y * resolution.x); + // int index = x * blockDim.y + y; + // int index = x + (y * resolution.x); + int index = x + (int)ceil(sqrt((float)numOfRays))* y; + // printf("blockDim: %d, %d\n", blockDim.x, blockDim.y); - if((x<=resolution.x && y<=resolution.y)){ + if( index < numOfRays ){ + ray r = rays[index]; - colors[index] = generateRandomNumberFromThread(resolution, time, x, y); + glm::vec3 Pintersect(0.0f); + glm::vec3 Pnormal(0.0f); + int hitGeoID = findHitGeo(r, Pintersect, Pnormal, geoms, numberOfGeoms, cudatris); + + if(hitGeoID!=-1){ + material curMat; + if(geoms[hitGeoID].materialid >= 0) + curMat = cudamats[geoms[hitGeoID].materialid]; + if( curMat.emittance > 0 ){ //end when hit light source + if(glm::length(r.color)>0.6f){ + // printf("ray color:[%f, %f, %f]", r.color.r,r.color.g,r.color.b); + } + + colors[r.pixel] += r.color * curMat.color * curMat.emittance; + r.isDead = true; + } + else{ + + //int mode = calculateBSDF(r, Pintersect, Pnormal, color, uncolor, cudamats[matID], hash(index*time)); + float seed = (float)index * (float)time * ( (float)rayDepth + 1.0f ); + if(curMat.hasReflective > 0 || curMat.hasRefractive > 0){ + //------------------------------- calculate Fresnel reflectance and transmittance --------------------------// + Fresnel F; + float reflectance; + glm::vec3 reflectDir, transmitDir; + if(glm::dot(r.direction,Pnormal)<0){ //ray is outside + F = calculateFresnel(Pnormal,r.direction,1.0f, curMat.indexOfRefraction); + reflectDir = calculateReflectionDirection(Pnormal, r.direction); + transmitDir = calculateTransmissionDirection(Pnormal, r.direction,1.0f, curMat.indexOfRefraction); + } + else{ //ray is inside + F = calculateFresnel(-Pnormal,r.direction, curMat.indexOfRefraction,1.0f); + reflectDir = calculateReflectionDirection(-Pnormal, r.direction); + transmitDir = calculateTransmissionDirection(-Pnormal, r.direction, curMat.indexOfRefraction, 1.0f); + } + //--------------------------------------------------------------------------------------------------------// + + //----------------------- choosing between reflection or refraction or both -------------------------------// + if( curMat.hasRefractive > 0 && curMat.hasReflective > 0){ + thrust::default_random_engine rng( hash( seed ) ); + thrust::uniform_real_distribution u01(0,1); + + if((float) u01(rng) < F.reflectionCoefficient ){ //reflected + r.direction = reflectDir; + r.origin = Pintersect + (float)EPSILON * r.direction; + //colors[r.pixel] += glm::abs(r.direction); + if(glm::length(curMat.color)>0) + r.color *= curMat.color ; + //r.color *= curMat.color * F.reflectionCoefficient; + + } + else{ //transmitted + r.direction = transmitDir; + r.origin = Pintersect + (float)EPSILON * r.direction; + //colors[r.pixel] += glm::abs(r.direction); + if(glm::length(curMat.color)>0) + r.color *= curMat.color ; + + } + } + else if(curMat.hasReflective > 0){ //only reflection + r.direction = reflectDir; + r.origin = Pintersect + (float)EPSILON * r.direction; + //colors[r.pixel] += glm::abs(r.direction); + if(glm::length(curMat.color)>0) + r.color *= curMat.color ; + } + else if (curMat.hasRefractive > 0){ //only refraction + r.direction = transmitDir; + r.origin = Pintersect + (float)EPSILON * r.direction; + //colors[r.pixel] += glm::abs(r.direction); + if(glm::length(curMat.color)>0) + r.color *= curMat.color ; + } + } + //--------------------------------------------------------------------------------------------------------// + else if (curMat.hasScatter>0){ + + } + else{ //diffuse rays + thrust::default_random_engine rng( hash( seed ) ); + thrust::uniform_real_distribution u01(0,1); + if((float) u01(rng) < 0.01f ){ //proportion to calculate direct lighting + directLighting(seed,r.color,Pintersect,Pnormal,hitGeoID,lights,numOfLights, cudamats,geoms, numberOfGeoms, cudatris); + } + else{ //proportion to calculate indirect lighting + //cos weighted importance sampling + r.direction = calculateCosWeightedRandomDirInHemisphere(Pnormal, (float) u01(rng), (float) u01(rng)); + r.origin = Pintersect + (float)EPSILON * r.direction ; + float diffuseTerm = glm::clamp( glm::dot( Pnormal,r.direction ), 0.0f, 1.0f); + if(geoms[hitGeoID].materialid < 0){ //texture + r.color *= diffuseTerm * getTextureColor(cudatexs, cudatexIDs, Pintersect, geoms[hitGeoID]); + }else{ + r.color *= diffuseTerm * curMat.color; + } + } + } + + //----------------------------------------- Other Effects ----------------------------------------------// + if(curMat.specularExponent > 0 ){ //specularity & glossiness + thrust::default_random_engine rng( hash( seed ) ); + thrust::uniform_real_distribution u01(0,1); + ray shadowRay; + float rayLen,lightArea; + glm::vec3 lightNormal; + int lightID = getRandomShadowRayDirection(seed, Pintersect, lights, numOfLights, geoms, shadowRay, rayLen, lightNormal, lightArea); + glm::vec3 viewDir = glm::normalize( cam.position - Pintersect ); + glm::vec3 halfVector = glm::normalize(shadowRay.direction + viewDir); //H=(L+V)/length(L+V) + float D = glm::clamp( glm::dot( Pnormal,halfVector), 0.0f, 1.0f); + float specularTerm = pow(D, curMat.specularExponent); //perfect specular means normal vector = half vector + r.color *= specularTerm * curMat.color; + } + + } + + } + else{ //hit nothing + r.isDead = true; + } + rays[index] = r; + + } } + + +// establish parrallel ray pool +__global__ void initialRayPool(ray * rayPool, cameraData cam, float iterations,glm::vec3 *colors, staticGeom* geoms, int numberOfGeoms, + material* cudamats, int * lightIDs, int numberOfLights, triangle * cudatris){ + int x = (blockIdx.x * blockDim.x) + threadIdx.x; + int y = (blockIdx.y * blockDim.y) + threadIdx.y; + int index = x + (y * cam.resolution.x); + ray r = rayPool[index]; + + if( x<= cam.resolution.x && y <= cam.resolution.y ){ + if(ANTI_ALIASING){ + glm::vec2 jitter = generateRandomNumberAntiAliasing((float)index * iterations, x, y, 0.5f); //anti-alizsing + r = raycastFromCameraKernel( cam.resolution, iterations, jitter.x, jitter.y, cam.position, cam.view, cam.up, cam.fov ); + } + else{ + r = raycastFromCameraKernel( cam.resolution, iterations, x, y, cam.position, cam.view, cam.up, cam.fov ); + } + r.pixel = index; //mark ray with pixel indexing, after compaction, (r.pixel) will represent correct pixel location + + if(DEPTH_OF_FIELD){ + glm::vec3 focalPoint = r.origin + r.direction * cam.focalLength / glm::dot(cam.view, r.direction); //L = f/cos(theta) + thrust::default_random_engine rng(hash((float)index*iterations)); + thrust::uniform_real_distribution u01(0,1); + float theta = 2.0f * PI * u01(rng); + float radius = u01(rng) * cam.aperture; + glm::vec3 eyeOffset(cos(theta)*radius, sin(theta)*radius, 0); + glm::vec3 newEyePoint = cam.position + eyeOffset; //offseted cam eye location + r.origin = newEyePoint; + r.direction = glm::normalize(focalPoint - newEyePoint); + } + + glm::vec3 Pintersect(0.0f); + glm::vec3 Pnormal(0.0f); + int geoID = findHitGeo(r, Pintersect, Pnormal, geoms, numberOfGeoms, cudatris); + if( geoID > -1){ + // cast shadow ray towards lights and calculate direct lighting + directLighting((float)index*iterations, colors[index], Pintersect, Pnormal,geoID, lightIDs, + numberOfLights, cudamats, geoms, numberOfGeoms, cudatris); + + } + rayPool[index] = r; + } +} + + // TODO: FINISH THIS FUNCTION // Wrapper for the __global__ call that sets up the kernel calls and does a ton of memory management -void cudaRaytraceCore(uchar4* PBOpos, camera* renderCam, int frame, int iterations, material* materials, int numberOfMaterials, geom* geoms, int numberOfGeoms){ - - int traceDepth = 1; //determines how many bounces the raytracer traces +void cudaRaytraceCore(uchar4* PBOpos, camera* renderCam, int frame, int iterations, + material* materials, int numberOfMaterials, geom* geoms, int numberOfGeoms, + std::vector &textures, std::vector &textureIDs){ + + //frame: current frame number + //iterations: current iteration of rendering < (cam.iterations) + if(iterations == 572 || iterations == 46 || iterations == 7){ + printf("problem"); + } - // set up crucial magic - int tileSize = 8; - dim3 threadsPerBlock(tileSize, tileSize); - dim3 fullBlocksPerGrid((int)ceil(float(renderCam->resolution.x)/float(tileSize)), (int)ceil(float(renderCam->resolution.y)/float(tileSize))); - - // send image to GPU + // send image to GPU glm::vec3* cudaimage = NULL; cudaMalloc((void**)&cudaimage, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3)); cudaMemcpy( cudaimage, renderCam->image, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3), cudaMemcpyHostToDevice); // package geometry and materials and sent to GPU staticGeom* geomList = new staticGeom[numberOfGeoms]; + // triangle* triList; + int meshID = -1; + triangle* cudatris = NULL; for(int i=0; iviews[frame]; cam.up = renderCam->ups[frame]; cam.fov = renderCam->fov; + cam.aperture = renderCam->aperture; + cam.focalLength = renderCam->focalLength; + + // material setup + material* cudamats = NULL; + cudaMalloc((void**)&cudamats, numberOfMaterials*sizeof(material)); + cudaMemcpy( cudamats, materials, numberOfMaterials*sizeof(material), cudaMemcpyHostToDevice); + + //lights setup + int numberOfLights = 0; + for(int i = 0; i < numberOfGeoms; ++i){ + if( geoms[i].materialid >= 0 && materials[geoms[i].materialid].emittance > 0){ + numberOfLights ++ ; + } + } + + int *lightIDs = new int[numberOfLights]; + int k = 0; + for(int i = 0; i < numberOfGeoms; ++i){ + if( geoms[i].materialid >= 0 && materials[geoms[i].materialid].emittance > 0){ + lightIDs[k] = i; + k++; + } + } + int* cudalightIDs = NULL; + cudaMalloc((void**)&cudalightIDs, numberOfLights*sizeof(int)); + cudaMemcpy( cudalightIDs, lightIDs, numberOfLights*sizeof(int), cudaMemcpyHostToDevice); + + //set up textures + int numberOfPixels = textures.size(); + glm::vec3 *texs = new glm::vec3[numberOfPixels]; + for(int i = 0; i < numberOfPixels; ++i){ + texs[i] = textures[i]; + } + glm::vec3 *cudatexs = NULL; + cudaMalloc((void**)&cudatexs,numberOfPixels * sizeof(glm::vec3)); + cudaMemcpy( cudatexs, texs, numberOfPixels * sizeof(glm::vec3), cudaMemcpyHostToDevice); - // kernel launches - raytraceRay<<>>(renderCam->resolution, (float)iterations, cam, traceDepth, cudaimage, cudageoms, numberOfGeoms); + //set up textures id + int numOfTextures = textureIDs.size(); + tex *texIDs = new tex[numOfTextures]; + for(int i = 0; i < numOfTextures; ++i){ + texIDs[i] = textureIDs[i]; + } + tex *cudatexIDs = NULL; + cudaMalloc((void**)&cudatexIDs, numOfTextures * sizeof(tex)); + cudaMemcpy( cudatexIDs, texIDs, numOfTextures* sizeof(tex), cudaMemcpyHostToDevice); - sendImageToPBO<<>>(PBOpos, renderCam->resolution, cudaimage); + //set up ray pool on device + ray* cudarays = NULL; + int numOfRays = cam.resolution.x * cam.resolution.y; + cudaMalloc((void**)&cudarays, numOfRays*sizeof(ray)); + + + // set up crucial magic + int tileSize = 8; + dim3 threadsPerBlock(tileSize, tileSize); + dim3 fullBlocksPerGrid((int)ceil(float(renderCam->resolution.x)/float(tileSize)), (int)ceil(float(renderCam->resolution.y)/float(tileSize))); + + initialRayPool<<>>(cudarays, cam, (float)iterations, cudaimage,cudageoms, numberOfGeoms, cudamats, cudalightIDs, numberOfLights, cudatris); + + for(int k=0; k0; k++){ + if(STREAM_COMPACT){ + thrust::device_ptr Start = thrust::device_pointer_cast(cudarays); //coverts cuda pointer to thrust pointer + thrust::device_ptr End = thrust::remove_if(Start, Start + numOfRays, is_dead()); + numOfRays = thrust::distance(Start, End); + } + //xBlocks * yBlocks = numOfRays / (tileSize*tileSize) + int xBlocks = (int) ceil( sqrt((float)numOfRays)/(float)(tileSize) ); + int yBlocks = (int) ceil( sqrt((float)numOfRays)/(float)(tileSize) ); + dim3 newBlocksPerGrid(xBlocks,yBlocks); + + raytraceRay<<>>(cudarays, (float)iterations, k, (int)numOfRays, cudaimage, cudageoms, numberOfGeoms, cudamats, cudalightIDs, numberOfLights, cam, cudatris, cudatexs, cudatexIDs); + + } + + sendImageToPBO<<>>(PBOpos, renderCam->resolution, cudaimage,(float)iterations); + // retrieve image from GPU cudaMemcpy( renderCam->image, cudaimage, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3), cudaMemcpyDeviceToHost); @@ -156,7 +614,20 @@ void cudaRaytraceCore(uchar4* PBOpos, camera* renderCam, int frame, int iteratio // free up stuff, or else we'll leak memory like a madman cudaFree( cudaimage ); cudaFree( cudageoms ); + cudaFree( cudamats ); + cudaFree( cudarays ); + cudaFree( cudatexs ); + cudaFree( cudatexIDs ); + cudaFree( cudalightIDs ); + if(meshID >-1 ){ + cudaFree( cudatris ); + } + delete geomList; + //delete matList; + delete lightIDs; + delete texs; + delete texIDs; // make certain the kernel has completed cudaThreadSynchronize(); diff --git a/src/raytraceKernel.h b/src/raytraceKernel.h index 984e89f..bf15b16 100755 --- a/src/raytraceKernel.h +++ b/src/raytraceKernel.h @@ -8,12 +8,24 @@ #ifndef RAYTRACEKERNEL_H #define RAYTRACEKERNEL_H + #include #include +#include +#include +#include +#include #include #include #include "sceneStructs.h" -void cudaRaytraceCore(uchar4* pos, camera* renderCam, int frame, int iterations, material* materials, int numberOfMaterials, geom* geoms, int numberOfGeoms); +#define MAX_DEPTH 8 +#define ANTI_ALIASING 0 +#define STREAM_COMPACT 0 +#define DEPTH_OF_FIELD 0 + +void cudaRaytraceCore(uchar4* pos, camera* renderCam, int frame, int iterations, + material* materials, int numberOfMaterials, geom* geoms, int numberOfGeoms, + std::vector &textures, std::vector &textureIDs); #endif diff --git a/src/scene.cpp b/src/scene.cpp index 4cbe216..48e31cb 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -7,6 +7,7 @@ #include #include "scene.h" #include +#include "tiny_obj_loader.h" scene::scene(string filename){ cout << "Reading scene from " << filename << " ..." << endl; @@ -34,6 +35,82 @@ scene::scene(string filename){ } } + +//load obj file, returns the number of triangle faces +int loadMeshFromOBJ(std::vector& shapes, std::vector& materials, const char* filename, + std::vector& tris, std::vector& BB){ //thanks to TinyObjLoader @ https://github.com/syoyo/tinyobjloader + + std::string error = tinyobj::LoadObj(shapes,materials, filename); //tiny obj loader + + if (error.length()>0) { + std::cerr << error << std::endl; + return 0; + } + //there is only one shape in our situation + int length = shapes[0].mesh.indices.size(); + int numofTris = length /3; + std::vector idx = shapes[0].mesh.indices; //indice array + std::vector pos = shapes[0].mesh.positions; //position array + for(int i = 0; i < length; i+=3){ + int i1 = idx[i]; + int i2 = idx[i+1]; + int i3 = idx[i+2]; + + glm::vec3 p1 = glm::vec3(pos[3 * i1 + 0], pos[3 * i1 + 1], pos[3 * i1 + 2]); + glm::vec3 p2 = glm::vec3(pos[3 * i2 + 0], pos[3 * i2 + 1], pos[3 * i2 + 2]); + glm::vec3 p3 = glm::vec3(pos[3 * i3 + 0], pos[3 * i3 + 1], pos[3 * i3 + 2]); + //glm::vec3 edge12 = p2 - p1; + //glm::vec3 edge13 = p3 - p1; + triangle tri; + tri.p1 = p1; + tri.p2 = p2; + tri.p3 = p3; + tris.push_back ( tri ); + } + + //demtermine bounding box for the speed of intersection test + float xMin = FLT_MAX, xMax = FLT_MIN, yMin = FLT_MAX, yMax = FLT_MIN, zMin = FLT_MAX, zMax = FLT_MIN; + for(int k = 0; k < numofTris; k++){ + xMin = min( xMin, tris[k].p1.x ); + xMin = min( xMin, tris[k].p2.x ); + xMin = min( xMin, tris[k].p3.x ); + + xMax = max( xMax, tris[k].p1.x ); + xMax = max( xMax, tris[k].p2.x ); + xMax = max( xMax, tris[k].p3.x ); + + yMin = min( yMin, tris[k].p1.y ); + yMin = min( yMin, tris[k].p2.y ); + yMin = min( yMin, tris[k].p3.y ); + + yMax = max( yMax, tris[k].p1.y ); + yMax = max( yMax, tris[k].p2.y ); + yMax = max( yMax, tris[k].p3.y ); + + zMin = min( zMin, tris[k].p1.z ); + zMin = min( zMin, tris[k].p2.z ); + zMin = min( zMin, tris[k].p3.z ); + + zMax = max( zMax, tris[k].p1.z ); + zMax = max( zMax, tris[k].p2.z ); + zMax = max( zMax, tris[k].p3.z ); + } + BB.push_back( glm::vec3( xMin, yMin, zMin ) ); + BB.push_back( glm::vec3( xMax, yMax, zMax ) ); + + /* printf("BB:\n [%f, %f, %f]\n [%f, %f, %f]\n", + BB[0].x, BB[0].y, BB[0].z, + BB[1].x, BB[1].y, BB[1].z); + + for(int k=0; k shapes; + std::vector materials; + std::vector triangles; + std::vector bb; + int num = loadMeshFromOBJ(shapes, materials, line.c_str(), triangles, bb); + if( num> 0){ + newObject.type = MESH; + newObject.numOfTris = num; + newObject.tris = new triangle[num]; + for(int i=0; i tokens = utilityCore::tokenizeString(line); @@ -152,6 +257,10 @@ int scene::loadCamera(){ newCamera.iterations = atoi(tokens[1].c_str()); }else if(strcmp(tokens[0].c_str(), "FILE")==0){ newCamera.imageName = tokens[1]; + }else if(strcmp(tokens[0].c_str(), "FOCAL")==0){ + newCamera.focalLength = atof(tokens[1].c_str()); + }else if(strcmp(tokens[0].c_str(), "APERTURE")==0){ + newCamera.aperture = atof(tokens[1].c_str()); } } diff --git a/src/sceneStructs.h b/src/sceneStructs.h index 5e0c853..7159e56 100644 --- a/src/sceneStructs.h +++ b/src/sceneStructs.h @@ -6,19 +6,33 @@ #ifndef CUDASTRUCTS_H #define CUDASTRUCTS_H +#include #include "glm/glm.hpp" #include "cudaMat4.h" #include #include + enum GEOMTYPE{ SPHERE, CUBE, MESH }; struct ray { + glm::vec3 attenuate; + bool isDead; + int pixel; + glm::vec3 color; glm::vec3 origin; glm::vec3 direction; }; +struct triangle{ + glm::vec3 p1,p2,p3; +}; + struct geom { + glm::vec3 bBoxMax; + glm::vec3 bBoxMin; + triangle* tris; + int numOfTris; enum GEOMTYPE type; int materialid; int frames; @@ -30,6 +44,10 @@ struct geom { }; struct staticGeom { + glm::vec3 bBoxMin; + glm::vec3 bBoxMax; + triangle* tris; + int numOfTris; enum GEOMTYPE type; int materialid; glm::vec3 translation; @@ -45,6 +63,9 @@ struct cameraData { glm::vec3 view; glm::vec3 up; glm::vec2 fov; + float aperture; + float focalLength; + int time; }; struct camera { @@ -58,6 +79,8 @@ struct camera { glm::vec3* image; ray* rayList; std::string imageName; + float focalLength; + float aperture; //rounded aperture }; struct material{ @@ -73,4 +96,18 @@ struct material{ float emittance; }; + +class tex{ + +public: + tex(){} //default constructor + int id; + int start; + int specularExponent; + int h; + int w; + +}; + + #endif //CUDASTRUCTS_H diff --git a/src/tiny_obj_loader.cc b/src/tiny_obj_loader.cc new file mode 100644 index 0000000..75f0dca --- /dev/null +++ b/src/tiny_obj_loader.cc @@ -0,0 +1,725 @@ +// +// Copyright 2012-2013, Syoyo Fujita. +// +// Licensed under 2-clause BSD liecense. +// + +// +// version 0.9.7: Support multi-materials(per-face material ID) per object/group. +// version 0.9.6: Support Ni(index of refraction) mtl parameter. +// Parse transmittance material parameter correctly. +// version 0.9.5: Parse multiple group name. +// Add support of specifying the base path to load material file. +// version 0.9.4: Initial suupport of group tag(g) +// version 0.9.3: Fix parsing triple 'x/y/z' +// version 0.9.2: Add more .mtl load support +// version 0.9.1: Add initial .mtl load support +// version 0.9.0: Initial +// + + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "tiny_obj_loader.h" + +namespace tinyobj { + +struct vertex_index { + int v_idx, vt_idx, vn_idx; + vertex_index() {}; + vertex_index(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}; + vertex_index(int vidx, int vtidx, int vnidx) : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}; + +}; +// for std::map +static inline bool operator<(const vertex_index& a, const vertex_index& b) +{ + if (a.v_idx != b.v_idx) return (a.v_idx < b.v_idx); + if (a.vn_idx != b.vn_idx) return (a.vn_idx < b.vn_idx); + if (a.vt_idx != b.vt_idx) return (a.vt_idx < b.vt_idx); + + return false; +} + +struct obj_shape { + std::vector v; + std::vector vn; + std::vector vt; +}; + +static inline bool isSpace(const char c) { + return (c == ' ') || (c == '\t'); +} + +static inline bool isNewLine(const char c) { + return (c == '\r') || (c == '\n') || (c == '\0'); +} + +// Make index zero-base, and also support relative index. +static inline int fixIndex(int idx, int n) +{ + int i; + + if (idx > 0) { + i = idx - 1; + } else if (idx == 0) { + i = 0; + } else { // negative value = relative + i = n + idx; + } + return i; +} + +static inline std::string parseString(const char*& token) +{ + std::string s; + int b = strspn(token, " \t"); + int e = strcspn(token, " \t\r"); + s = std::string(&token[b], &token[e]); + + token += (e - b); + return s; +} + +static inline int parseInt(const char*& token) +{ + token += strspn(token, " \t"); + int i = atoi(token); + token += strcspn(token, " \t\r"); + return i; +} + +static inline float parseFloat(const char*& token) +{ + token += strspn(token, " \t"); + float f = (float)atof(token); + token += strcspn(token, " \t\r"); + return f; +} + +static inline void parseFloat2( + float& x, float& y, + const char*& token) +{ + x = parseFloat(token); + y = parseFloat(token); +} + +static inline void parseFloat3( + float& x, float& y, float& z, + const char*& token) +{ + x = parseFloat(token); + y = parseFloat(token); + z = parseFloat(token); +} + + +// Parse triples: i, i/j/k, i//k, i/j +static vertex_index parseTriple( + const char* &token, + int vsize, + int vnsize, + int vtsize) +{ + vertex_index vi(-1); + + vi.v_idx = fixIndex(atoi(token), vsize); + token += strcspn(token, "/ \t\r"); + if (token[0] != '/') { + return vi; + } + token++; + + // i//k + if (token[0] == '/') { + token++; + vi.vn_idx = fixIndex(atoi(token), vnsize); + token += strcspn(token, "/ \t\r"); + return vi; + } + + // i/j/k or i/j + vi.vt_idx = fixIndex(atoi(token), vtsize); + token += strcspn(token, "/ \t\r"); + if (token[0] != '/') { + return vi; + } + + // i/j/k + token++; // skip '/' + vi.vn_idx = fixIndex(atoi(token), vnsize); + token += strcspn(token, "/ \t\r"); + return vi; +} + +static unsigned int +updateVertex( + std::map& vertexCache, + std::vector& positions, + std::vector& normals, + std::vector& texcoords, + const std::vector& in_positions, + const std::vector& in_normals, + const std::vector& in_texcoords, + const vertex_index& i) +{ + const std::map::iterator it = vertexCache.find(i); + + if (it != vertexCache.end()) { + // found cache + return it->second; + } + + assert(in_positions.size() > (unsigned int) (3*i.v_idx+2)); + + positions.push_back(in_positions[3*i.v_idx+0]); + positions.push_back(in_positions[3*i.v_idx+1]); + positions.push_back(in_positions[3*i.v_idx+2]); + + if (i.vn_idx >= 0) { + normals.push_back(in_normals[3*i.vn_idx+0]); + normals.push_back(in_normals[3*i.vn_idx+1]); + normals.push_back(in_normals[3*i.vn_idx+2]); + } + + if (i.vt_idx >= 0) { + texcoords.push_back(in_texcoords[2*i.vt_idx+0]); + texcoords.push_back(in_texcoords[2*i.vt_idx+1]); + } + + unsigned int idx = positions.size() / 3 - 1; + vertexCache[i] = idx; + + return idx; +} + +void InitMaterial(material_t& material) { + material.name = ""; + material.ambient_texname = ""; + material.diffuse_texname = ""; + material.specular_texname = ""; + material.normal_texname = ""; + for (int i = 0; i < 3; i ++) { + material.ambient[i] = 0.f; + material.diffuse[i] = 0.f; + material.specular[i] = 0.f; + material.transmittance[i] = 0.f; + material.emission[i] = 0.f; + } + material.illum = 0; + material.dissolve = 1.f; + material.shininess = 1.f; + material.ior = 1.f; + material.unknown_parameter.clear(); +} + +static bool +exportFaceGroupToShape( + shape_t& shape, + std::map vertexCache, + const std::vector &in_positions, + const std::vector &in_normals, + const std::vector &in_texcoords, + const std::vector >& faceGroup, + const int material_id, + const std::string &name, + bool clearCache) +{ + if (faceGroup.empty()) { + return false; + } + + size_t offset; + + offset = shape.mesh.indices.size(); + + // Flatten vertices and indices + for (size_t i = 0; i < faceGroup.size(); i++) { + const std::vector& face = faceGroup[i]; + + vertex_index i0 = face[0]; + vertex_index i1(-1); + vertex_index i2 = face[1]; + + size_t npolys = face.size(); + + // Polygon -> triangle fan conversion + for (size_t k = 2; k < npolys; k++) { + i1 = i2; + i2 = face[k]; + + unsigned int v0 = updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals, shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i0); + unsigned int v1 = updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals, shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i1); + unsigned int v2 = updateVertex(vertexCache, shape.mesh.positions, shape.mesh.normals, shape.mesh.texcoords, in_positions, in_normals, in_texcoords, i2); + + shape.mesh.indices.push_back(v0); + shape.mesh.indices.push_back(v1); + shape.mesh.indices.push_back(v2); + + shape.mesh.material_ids.push_back(material_id); + } + + } + + shape.name = name; + + if (clearCache) + vertexCache.clear(); + + return true; + +} + +std::string LoadMtl ( + std::map& material_map, + std::vector& materials, + std::istream& inStream) +{ + material_map.clear(); + std::stringstream err; + + material_t material; + + int maxchars = 8192; // Alloc enough size. + std::vector buf(maxchars); // Alloc enough size. + while (inStream.peek() != -1) { + inStream.getline(&buf[0], maxchars); + + std::string linebuf(&buf[0]); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size()-1] == '\r') linebuf.erase(linebuf.size()-1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // new mtl + if ((0 == strncmp(token, "newmtl", 6)) && isSpace((token[6]))) { + // flush previous material. + if (!material.name.empty()) + { + material_map.insert(std::pair(material.name, materials.size())); + materials.push_back(material); + } + + // initial temporary material + InitMaterial(material); + + // set new mtl name + char namebuf[4096]; + token += 7; + sscanf(token, "%s", namebuf); + material.name = namebuf; + continue; + } + + // ambient + if (token[0] == 'K' && token[1] == 'a' && isSpace((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.ambient[0] = r; + material.ambient[1] = g; + material.ambient[2] = b; + continue; + } + + // diffuse + if (token[0] == 'K' && token[1] == 'd' && isSpace((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.diffuse[0] = r; + material.diffuse[1] = g; + material.diffuse[2] = b; + continue; + } + + // specular + if (token[0] == 'K' && token[1] == 's' && isSpace((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.specular[0] = r; + material.specular[1] = g; + material.specular[2] = b; + continue; + } + + // transmittance + if (token[0] == 'K' && token[1] == 't' && isSpace((token[2]))) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.transmittance[0] = r; + material.transmittance[1] = g; + material.transmittance[2] = b; + continue; + } + + // ior(index of refraction) + if (token[0] == 'N' && token[1] == 'i' && isSpace((token[2]))) { + token += 2; + material.ior = parseFloat(token); + continue; + } + + // emission + if(token[0] == 'K' && token[1] == 'e' && isSpace(token[2])) { + token += 2; + float r, g, b; + parseFloat3(r, g, b, token); + material.emission[0] = r; + material.emission[1] = g; + material.emission[2] = b; + continue; + } + + // shininess + if(token[0] == 'N' && token[1] == 's' && isSpace(token[2])) { + token += 2; + material.shininess = parseFloat(token); + continue; + } + + // illum model + if (0 == strncmp(token, "illum", 5) && isSpace(token[5])) { + token += 6; + material.illum = parseInt(token); + continue; + } + + // dissolve + if ((token[0] == 'd' && isSpace(token[1]))) { + token += 1; + material.dissolve = parseFloat(token); + continue; + } + if (token[0] == 'T' && token[1] == 'r' && isSpace(token[2])) { + token += 2; + material.dissolve = parseFloat(token); + continue; + } + + // ambient texture + if ((0 == strncmp(token, "map_Ka", 6)) && isSpace(token[6])) { + token += 7; + material.ambient_texname = token; + continue; + } + + // diffuse texture + if ((0 == strncmp(token, "map_Kd", 6)) && isSpace(token[6])) { + token += 7; + material.diffuse_texname = token; + continue; + } + + // specular texture + if ((0 == strncmp(token, "map_Ks", 6)) && isSpace(token[6])) { + token += 7; + material.specular_texname = token; + continue; + } + + // normal texture + if ((0 == strncmp(token, "map_Ns", 6)) && isSpace(token[6])) { + token += 7; + material.normal_texname = token; + continue; + } + + // unknown parameter + const char* _space = strchr(token, ' '); + if(!_space) { + _space = strchr(token, '\t'); + } + if(_space) { + int len = _space - token; + std::string key(token, len); + std::string value = _space + 1; + material.unknown_parameter.insert(std::pair(key, value)); + } + } + // flush last material. + material_map.insert(std::pair(material.name, materials.size())); + materials.push_back(material); + + return err.str(); +} + +std::string MaterialFileReader::operator() ( + const std::string& matId, + std::vector& materials, + std::map& matMap) +{ + std::string filepath; + + if (!m_mtlBasePath.empty()) { + filepath = std::string(m_mtlBasePath) + matId; + } else { + filepath = matId; + } + + std::ifstream matIStream(filepath.c_str()); + return LoadMtl(matMap, materials, matIStream); +} + +std::string +LoadObj( + std::vector& shapes, + std::vector& materials, // [output] + const char* filename, + const char* mtl_basepath) +{ + + shapes.clear(); + + std::stringstream err; + + std::ifstream ifs(filename); + if (!ifs) { + err << "Cannot open file [" << filename << "]" << std::endl; + return err.str(); + } + + std::string basePath; + if (mtl_basepath) { + basePath = mtl_basepath; + } + MaterialFileReader matFileReader( basePath ); + + return LoadObj(shapes, materials, ifs, matFileReader); +} + +std::string LoadObj( + std::vector& shapes, + std::vector& materials, // [output] + std::istream& inStream, + MaterialReader& readMatFn) +{ + std::stringstream err; + + std::vector v; + std::vector vn; + std::vector vt; + std::vector > faceGroup; + std::string name; + + // material + std::map material_map; + std::map vertexCache; + int material = -1; + + shape_t shape; + + int maxchars = 8192; // Alloc enough size. + std::vector buf(maxchars); // Alloc enough size. + while (inStream.peek() != -1) { + inStream.getline(&buf[0], maxchars); + + std::string linebuf(&buf[0]); + + // Trim newline '\r\n' or '\n' + if (linebuf.size() > 0) { + if (linebuf[linebuf.size()-1] == '\n') linebuf.erase(linebuf.size()-1); + } + if (linebuf.size() > 0) { + if (linebuf[linebuf.size()-1] == '\r') linebuf.erase(linebuf.size()-1); + } + + // Skip if empty line. + if (linebuf.empty()) { + continue; + } + + // Skip leading space. + const char* token = linebuf.c_str(); + token += strspn(token, " \t"); + + assert(token); + if (token[0] == '\0') continue; // empty line + + if (token[0] == '#') continue; // comment line + + // vertex + if (token[0] == 'v' && isSpace((token[1]))) { + token += 2; + float x, y, z; + parseFloat3(x, y, z, token); + v.push_back(x); + v.push_back(y); + v.push_back(z); + continue; + } + + // normal + if (token[0] == 'v' && token[1] == 'n' && isSpace((token[2]))) { + token += 3; + float x, y, z; + parseFloat3(x, y, z, token); + vn.push_back(x); + vn.push_back(y); + vn.push_back(z); + continue; + } + + // texcoord + if (token[0] == 'v' && token[1] == 't' && isSpace((token[2]))) { + token += 3; + float x, y; + parseFloat2(x, y, token); + vt.push_back(x); + vt.push_back(y); + continue; + } + + // face + if (token[0] == 'f' && isSpace((token[1]))) { + token += 2; + token += strspn(token, " \t"); + + std::vector face; + while (!isNewLine(token[0])) { + vertex_index vi = parseTriple(token, v.size() / 3, vn.size() / 3, vt.size() / 2); + face.push_back(vi); + int n = strspn(token, " \t\r"); + token += n; + } + + faceGroup.push_back(face); + + continue; + } + + // use mtl + if ((0 == strncmp(token, "usemtl", 6)) && isSpace((token[6]))) { + + char namebuf[4096]; + token += 7; + sscanf(token, "%s", namebuf); + + bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, false); + faceGroup.clear(); + + if (material_map.find(namebuf) != material_map.end()) { + material = material_map[namebuf]; + } else { + // { error!! material not found } + material = -1; + } + + continue; + + } + + // load mtl + if ((0 == strncmp(token, "mtllib", 6)) && isSpace((token[6]))) { + char namebuf[4096]; + token += 7; + sscanf(token, "%s", namebuf); + + std::string err_mtl = readMatFn(namebuf, materials, material_map); + if (!err_mtl.empty()) { + faceGroup.clear(); // for safety + return err_mtl; + } + + continue; + } + + // group name + if (token[0] == 'g' && isSpace((token[1]))) { + + // flush previous face group. + bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, true); + if (ret) { + shapes.push_back(shape); + } + + shape = shape_t(); + + //material = -1; + faceGroup.clear(); + + std::vector names; + while (!isNewLine(token[0])) { + std::string str = parseString(token); + names.push_back(str); + token += strspn(token, " \t\r"); // skip tag + } + + assert(names.size() > 0); + + // names[0] must be 'g', so skipt 0th element. + if (names.size() > 1) { + name = names[1]; + } else { + name = ""; + } + + continue; + } + + // object name + if (token[0] == 'o' && isSpace((token[1]))) { + + // flush previous face group. + bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, true); + if (ret) { + shapes.push_back(shape); + } + + //material = -1; + faceGroup.clear(); + shape = shape_t(); + + // @todo { multiple object name? } + char namebuf[4096]; + token += 2; + sscanf(token, "%s", namebuf); + name = std::string(namebuf); + + + continue; + } + + // Ignore unknown command. + } + + bool ret = exportFaceGroupToShape(shape, vertexCache, v, vn, vt, faceGroup, material, name, true); + if (ret) { + shapes.push_back(shape); + } + faceGroup.clear(); // for safety + + return err.str(); +} + + +} diff --git a/src/tiny_obj_loader.h b/src/tiny_obj_loader.h new file mode 100644 index 0000000..a58d7be --- /dev/null +++ b/src/tiny_obj_loader.h @@ -0,0 +1,107 @@ +// +// Copyright 2012-2013, Syoyo Fujita. +// +// Licensed under 2-clause BSD liecense. +// +#ifndef _TINY_OBJ_LOADER_H +#define _TINY_OBJ_LOADER_H + +#include +#include +#include + +namespace tinyobj { + +typedef struct +{ + std::string name; + + float ambient[3]; + float diffuse[3]; + float specular[3]; + float transmittance[3]; + float emission[3]; + float shininess; + float ior; // index of refraction + float dissolve; // 1 == opaque; 0 == fully transparent + // illumination model (see http://www.fileformat.info/format/material/) + int illum; + + std::string ambient_texname; + std::string diffuse_texname; + std::string specular_texname; + std::string normal_texname; + std::map unknown_parameter; +} material_t; + +typedef struct +{ + std::vector positions; + std::vector normals; + std::vector texcoords; + std::vector indices; + std::vector material_ids; // per-mesh material ID +} mesh_t; + +typedef struct +{ + std::string name; + mesh_t mesh; +} shape_t; + +class MaterialReader +{ +public: + MaterialReader(){} + virtual ~MaterialReader(){} + + virtual std::string operator() ( + const std::string& matId, + std::vector& materials, + std::map& matMap) = 0; +}; + +class MaterialFileReader: + public MaterialReader +{ + public: + MaterialFileReader(const std::string& mtl_basepath): m_mtlBasePath(mtl_basepath) {} + virtual ~MaterialFileReader() {} + virtual std::string operator() ( + const std::string& matId, + std::vector& materials, + std::map& matMap); + + private: + std::string m_mtlBasePath; +}; + +/// Loads .obj from a file. +/// 'shapes' will be filled with parsed shape data +/// The function returns error string. +/// Returns empty string when loading .obj success. +/// 'mtl_basepath' is optional, and used for base path for .mtl file. +std::string LoadObj( + std::vector& shapes, // [output] + std::vector& materials, // [output] + const char* filename, + const char* mtl_basepath = NULL); + +/// Loads object from a std::istream, uses GetMtlIStreamFn to retrieve +/// std::istream for materials. +/// Returns empty string when loading .obj success. +std::string LoadObj( + std::vector& shapes, // [output] + std::vector& materials, // [output] + std::istream& inStream, + MaterialReader& readMatFn); + +/// Loads materials into std::map +/// Returns an empty string if successful +std::string LoadMtl ( + std::map& material_map, + std::vector& materials, + std::istream& inStream); +} + +#endif // _TINY_OBJ_LOADER_H diff --git a/src/utilities.cpp b/src/utilities.cpp index a8e5d90..0c579f2 100755 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -4,7 +4,7 @@ // File: utilities.cpp // A collection/kitchen sink of generally useful functions -#define GLM_FORCE_RADIANS +//#define GLM_FORCE_RADIANS #include #include @@ -12,6 +12,7 @@ #include "utilities.h" + float utilityCore::clamp(float f, float min, float max){ if(f Level3 Disabled - $(SolutionDir)/../../external/include/;%(AdditionalIncludeDirectories) + $(SolutionDir)/../../external/include/; Q:\CUDA5.5\include;Q:\CUDA5.5\common\inc; %(AdditionalIncludeDirectories) true @@ -50,6 +50,9 @@ cudart.lib;glew32s.lib;glfw3.lib;opengl32.lib;%(AdditionalDependencies) Console + + compute_30,sm_30 + @@ -57,16 +60,20 @@ MaxSpeed true true - $(SolutionDir)/../../external/include/;%(AdditionalIncludeDirectories) + $(SolutionDir)..\..\external\FreeImage;$(SolutionDir)/../../external/include/;%(AdditionalIncludeDirectories) true true true - $(SolutionDir)/../../external/lib/win/GLFW/;$(SolutionDir)/../../external/lib/win/GL/;%(AdditionalLibraryDirectories) - cudart.lib;glew32s.lib;glfw3.lib;opengl32.lib;%(AdditionalDependencies) + $(SolutionDir)..\..\external\FreeImage;$(SolutionDir)/../../external/lib/win/GLFW/;$(SolutionDir)/../../external/lib/win/GL/;%(AdditionalLibraryDirectories) + cudart.lib;glew32s.lib;glfw3.lib;opengl32.lib;FreeImage.lib;%(AdditionalDependencies) Console + + compute_30,sm_30 + $(SolutionDir)/../../external/include/; + @@ -77,6 +84,7 @@ + @@ -86,6 +94,7 @@ + diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj.filters b/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj.filters index 584fd19..4b81361 100644 --- a/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj.filters +++ b/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj.filters @@ -48,6 +48,9 @@ Header Files + + Header Files + @@ -71,6 +74,9 @@ Source Files\stb_image + + Source Files + diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/YoutubeThumbnail.png b/windows/Project3-Pathtracer/Project3-Pathtracer/YoutubeThumbnail.png new file mode 100644 index 0000000..880be1c Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/YoutubeThumbnail.png differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/cube_with_AA.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/cube_with_AA.bmp new file mode 100644 index 0000000..db55021 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/cube_with_AA.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/cube_without_AA.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/cube_without_AA.bmp new file mode 100644 index 0000000..3b02bfe Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/cube_without_AA.bmp differ diff --git a/windows/Project3-Pathtracer/data/scenes/myScene.txt b/windows/Project3-Pathtracer/data/scenes/myScene.txt new file mode 100644 index 0000000..6a9f5cc --- /dev/null +++ b/windows/Project3-Pathtracer/data/scenes/myScene.txt @@ -0,0 +1,190 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 3 //red glossy +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 4 //white glossy +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 1 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //green glossy +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 1 + +MATERIAL 8 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 15 + +CAMERA +RES 800 800 +FOVY 25 +ITERATIONS 5000 +FILE test.bmp +frame 0 +EYE 0 4.5 12 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 0 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 1 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 2 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +sphere +material 4 +frame 0 +TRANS 0 2 0 +ROTAT 0 180 0 +SCALE 3 3 3 + +OBJECT 6 +sphere +material 3 +frame 0 +TRANS 2 5 2 +ROTAT 0 180 0 +SCALE 2.5 2.5 2.5 + +OBJECT 7 +sphere +material 6 +frame 0 +TRANS -2 5 -2 +ROTAT 0 180 0 +SCALE 3 3 3 + + +OBJECT 8 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 \ No newline at end of file diff --git a/windows/Project3-Pathtracer/data/scenes/sampleScene.txt b/windows/Project3-Pathtracer/data/scenes/sampleScene.txt new file mode 100644 index 0000000..6a9f5cc --- /dev/null +++ b/windows/Project3-Pathtracer/data/scenes/sampleScene.txt @@ -0,0 +1,190 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 3 //red glossy +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 4 //white glossy +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 1 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //green glossy +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 1 + +MATERIAL 8 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 15 + +CAMERA +RES 800 800 +FOVY 25 +ITERATIONS 5000 +FILE test.bmp +frame 0 +EYE 0 4.5 12 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 0 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 1 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 2 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +sphere +material 4 +frame 0 +TRANS 0 2 0 +ROTAT 0 180 0 +SCALE 3 3 3 + +OBJECT 6 +sphere +material 3 +frame 0 +TRANS 2 5 2 +ROTAT 0 180 0 +SCALE 2.5 2.5 2.5 + +OBJECT 7 +sphere +material 6 +frame 0 +TRANS -2 5 -2 +ROTAT 0 180 0 +SCALE 3 3 3 + + +OBJECT 8 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 \ No newline at end of file