├── .gitattributes ├── .gitignore ├── README.md ├── Reyes.sln └── Reyes ├── FrameBuffer.cpp ├── FrameBuffer.h ├── Matrix4.cpp ├── Matrix4.h ├── Mesh.cpp ├── Mesh.h ├── Noise.h ├── Primitive.h ├── Reyes.vcxproj ├── Reyes.vcxproj.filters ├── Ri.cpp ├── Ri.h ├── SampleScene.cpp ├── Shader.cpp ├── Shader.h ├── Triangle.h ├── Vector3.cpp ├── Vector3.h ├── Vector4.cpp ├── Vector4.h ├── earth.jpg ├── main.cpp ├── stb_image.h └── stb_image_write.h /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | 65 | *.h linguist-language=C++ 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # reyes-renderer 2 | A REYES-style micropolygon renderer written in C++ which implements a subset of the RenderMan specification. Features include Monte Carlo motion blur, displacement and surface shaders using Perlin noise, transparency, and anti-aliasing. 3 | For high resolution renders, the program must be compiled in 64-bit mode. 4 | 5 | ## Example Renders 6 | donuts 7 | donuts_still 8 | trevorshadertest 9 | trevorshadertest_blur 10 | earth 11 | rocket 12 | shadertest 13 | 14 | ## Scenes 15 | The scenes are all contained within SampleScene.cpp. The main() function, also defined in this file, can be used to determine which scenes to render. 16 | 17 | ## RenderMan Spec 18 | The following RenderMan functions defined in Ri.h are implemented: 19 | * RiBegin 20 | * RiEnd 21 | * RiFormat 22 | * RiProjection 23 | * RiFrameAspectRatio 24 | * RiPixelSamples 25 | * RiDisplay 26 | * RiFrameBegin 27 | * RiFrameEnd 28 | * RiWorldBegin 29 | * RiWorldEnd 30 | * RiTransformBegin 31 | * RiTransformEnd 32 | * RiIdentity 33 | * RiTransform 34 | * RiPerspective 35 | * RiTranslate 36 | * RiRotate 37 | * RiScale 38 | * RiConcactTransform 39 | * RiSphere 40 | * RiCone 41 | * RiCylinder 42 | * RiTorus 43 | * RiColor 44 | * RiOpacity 45 | * RiBackgroundColor - new 46 | * RiMakeTexture - new 47 | * RiSurface 48 | * RiDisplacement 49 | * RiShutter 50 | * RiMotionBlur - new 51 | 52 | ## Shaders 53 | Shaders are defined in Shader.h and implemented in Shader.cpp. 54 | 55 | ### Surface Shaders 56 | * texture 57 | * LIGHTING 58 | * CHECKERBOARD 59 | * MARBLE 60 | * WOOD 61 | * DONUT_SURFACE 62 | 63 | ### Displacement Shaders 64 | * BUMPY 65 | * DONUT_DISPLACEMENT 66 | 67 | ## Motion Blur 68 | My implementation of motion blur allows for a single translation movement per frame only. 69 | To use motion blur, I created RiMotionBlur(dx, dy, dz) which allows you to specify the movement of subsequent primitives. RiShutter specifies the capture start and stop time (usually 0 and 1). 70 | To turn motion blur off, RiMotionBlur(0, 0, 0) should be sufficient. 71 | I did not optimize the motion blur much, so for large displacements the bounding box of each micropolygon can be quite big, causing significant render times. 72 | An example of motion blur can be seen in the 'Donuts' scene. 73 | -------------------------------------------------------------------------------- /Reyes.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Reyes", "Reyes\Reyes.vcxproj", "{350C43BF-B073-418C-B4EC-69D1AA3B8218}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {350C43BF-B073-418C-B4EC-69D1AA3B8218}.Debug|x64.ActiveCfg = Debug|x64 17 | {350C43BF-B073-418C-B4EC-69D1AA3B8218}.Debug|x64.Build.0 = Debug|x64 18 | {350C43BF-B073-418C-B4EC-69D1AA3B8218}.Debug|x86.ActiveCfg = Debug|Win32 19 | {350C43BF-B073-418C-B4EC-69D1AA3B8218}.Debug|x86.Build.0 = Debug|Win32 20 | {350C43BF-B073-418C-B4EC-69D1AA3B8218}.Release|x64.ActiveCfg = Release|x64 21 | {350C43BF-B073-418C-B4EC-69D1AA3B8218}.Release|x64.Build.0 = Release|x64 22 | {350C43BF-B073-418C-B4EC-69D1AA3B8218}.Release|x86.ActiveCfg = Release|Win32 23 | {350C43BF-B073-418C-B4EC-69D1AA3B8218}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /Reyes/FrameBuffer.cpp: -------------------------------------------------------------------------------- 1 | #include "FrameBuffer.h" 2 | //#include "CImg.h" 3 | #define STB_IMAGE_WRITE_IMPLEMENTATION 4 | #include "stb_image_write.h" 5 | 6 | FrameBuffer::FrameBuffer(int width, int height, int mSamples, int nSamples, float timeStart, float timeStop) { 7 | this->width = width; 8 | this->height = height; 9 | this->mSamples = mSamples; 10 | this->nSamples = nSamples; 11 | //motion blur 12 | this->numIntervals = mSamples * nSamples; 13 | this->timeStart = timeStart; 14 | this->timeStop = timeStop; 15 | 16 | //allocate zbuffer 17 | zbuffer = new SampleNode*[width * mSamples * height * nSamples]; 18 | 19 | //create sample kernel 20 | sampleKernel = new float[width * mSamples * height * nSamples * 3]; 21 | //m x n jittering 22 | for (int x = 0; x < width; x++) { 23 | for (int y = 0; y < height; y++) { 24 | //which time interval to place sample in (there are mxn total intervals) 25 | std::vector intervals; 26 | for (int i = 0; i < numIntervals; i++) 27 | intervals.push_back(i); 28 | std::random_shuffle(intervals.begin(), intervals.end()); 29 | int index = 0; 30 | for (int m = 0; m < mSamples; m++) { 31 | for (int n = 0; n < nSamples; n++) { 32 | float mMin = (float)m / mSamples; 33 | float nMin = (float)n / nSamples; 34 | float mMax = (float)(m + 1) / mSamples; 35 | float nMax = (float)(n + 1) / nSamples; 36 | 37 | //pick random position values between min and max 38 | getKernelPtr(x, y, m, n)[0] = x + ((float)rand() / RAND_MAX) * (mMax - mMin) + mMin; 39 | getKernelPtr(x, y, m, n)[1] = y + ((float)rand() / RAND_MAX) * (nMax - nMin) + nMin; 40 | 41 | //pick time sample within this interval 42 | float tMin = ((float)intervals[index] / numIntervals) * (timeStop - timeStart) + timeStart; 43 | float tMax = ((float)(intervals[index] + 1) / numIntervals) * (timeStop - timeStart) + timeStart; 44 | getKernelPtr(x, y, m, n)[2] = ((float)rand() / RAND_MAX) * (tMax - tMin) + tMin; 45 | index++; 46 | 47 | //also initalize zbuffer to NULL at every pixel and sample point 48 | *getHeadPtr(x, y, m, n) = NULL; 49 | } 50 | } 51 | } 52 | } 53 | } 54 | 55 | void FrameBuffer::FilterAndSaveToFile(std::string path) { 56 | //cimg_library::cimg::imagemagick_path("ImageMagick-7.0.5-Q16/convert.exe"); 57 | //cimg_library::CImg outputBuffer(width, height, 1, 3); 58 | //filter 59 | unsigned char* outputBuffer = new unsigned char[width * height * 3]; 60 | for (int x = 0; x < width; x++) { 61 | for (int y = 0; y < height; y++) { 62 | //average all samples in this pixel (box filter) 63 | float pixelColor[3] = { 0 }; 64 | for (int m = 0; m < mSamples; m++) { 65 | for (int n = 0; n < nSamples; n++) { 66 | //collapse all opacities at each sample point 67 | float sampleColor[3] = { 0 }; 68 | collapseSamples(*getHeadPtr(x, y, m, n), sampleColor); 69 | 70 | pixelColor[0] += sampleColor[0]; 71 | pixelColor[1] += sampleColor[1]; 72 | pixelColor[2] += sampleColor[2]; 73 | } 74 | } 75 | //average 76 | pixelColor[0] /= (mSamples * nSamples); 77 | pixelColor[1] /= (mSamples * nSamples); 78 | pixelColor[2] /= (mSamples * nSamples); 79 | //clamp and quantize 80 | outputBuffer[3 * (y * width + x) + 0] = max(0, min(255, (int)(pixelColor[0] * 255.0f))); 81 | outputBuffer[3 * (y * width + x) + 1] = max(0, min(255, (int)(pixelColor[1] * 255.0f))); 82 | outputBuffer[3 * (y * width + x) + 2] = max(0, min(255, (int)(pixelColor[2] * 255.0f))); 83 | //outputBuffer(x, y, 0, 0) = max(0, min(255, (int)(pixelColor[0] * 255.0f))); 84 | //outputBuffer(x, y, 0, 1) = max(0, min(255, (int)(pixelColor[1] * 255.0f))); 85 | //outputBuffer(x, y, 0, 2) = max(0, min(255, (int)(pixelColor[2] * 255.0f))); 86 | } 87 | } 88 | 89 | //save to file 90 | if (path.substr(path.find_last_of(".") + 1) == "png") 91 | stbi_write_png(path.c_str(), width, height, 3, outputBuffer, width*3); 92 | else if (path.substr(path.find_last_of(".") + 1) == "tga") 93 | stbi_write_tga(path.c_str(), width, height, 3, outputBuffer); 94 | else 95 | stbi_write_bmp(path.c_str(), width, height, 3, outputBuffer); 96 | 97 | delete[] outputBuffer; 98 | //outputBuffer.save(path.c_str()); 99 | } 100 | 101 | void FrameBuffer::DrawMesh(Mesh* mesh, Vector4& movementVector, Matrix4& projection) { 102 | //perform perspective divide and transform to pixel space 103 | //mesh->Project(width, height); 104 | 105 | //break into micropolygons 106 | for (int u = 0; u < mesh->width - 1; u++) { 107 | for (int v = 0; v < mesh->height - 1; v++) { 108 | //get points of micropolygon 109 | MeshPoint* points[4]; 110 | points[0] = mesh->getGridPtr(u, v); 111 | points[1] = mesh->getGridPtr(u, v + 1); 112 | points[2] = mesh->getGridPtr(u + 1, v + 1); 113 | points[3] = mesh->getGridPtr(u + 1, v); 114 | 115 | //if any points have been invalidated, skip 116 | //if (!points[0]->valid || !points[1]->valid || !points[2]->valid || !points[3]->valid) 117 | //continue; 118 | 119 | //get bounding box (over time) 120 | Vector4 startPoints[4]; 121 | Vector4 endPoints[4]; 122 | int min_x = width; 123 | int max_x = 0; 124 | int min_y = height; 125 | int max_y = 0; 126 | bool valid = true; 127 | for (int j = 0; j < 4; j++) { 128 | startPoints[j] = points[j]->position + movementVector * timeStart; 129 | endPoints[j] = points[j]->position + movementVector * timeStop; 130 | 131 | //check against near and far planes 132 | if (startPoints[j].z < 0 || endPoints[j].z < 0) 133 | valid = false; 134 | //project 135 | startPoints[j] = projection * startPoints[j]; 136 | endPoints[j] = projection * endPoints[j]; 137 | //perspective divide 138 | startPoints[j] = startPoints[j].homogenize(); 139 | endPoints[j] = endPoints[j].homogenize(); 140 | 141 | //convert to pixel space 142 | startPoints[j].x = (startPoints[j].x + 1.0f) * 0.5f * width; 143 | startPoints[j].y = (-startPoints[j].y + 1.0f) * 0.5f * height; //y axis is inverted in pixel space 144 | endPoints[j].x = (endPoints[j].x + 1.0f) * 0.5f * width; 145 | endPoints[j].y = (-endPoints[j].y + 1.0f) * 0.5f * height; 146 | 147 | min_x = min(min_x, (int)floor(startPoints[j].x)); 148 | min_x = min(min_x, (int)floor(endPoints[j].x)); 149 | min_y = min(min_y, (int)floor(startPoints[j].y)); 150 | min_y = min(min_y, (int)floor(endPoints[j].y)); 151 | max_x = max(max_x, (int)ceil(startPoints[j].x)); 152 | max_x = max(max_x, (int)ceil(endPoints[j].x)); 153 | max_y = max(max_y, (int)ceil(startPoints[j].y)); 154 | max_y = max(max_y, (int)ceil(endPoints[j].y)); 155 | } 156 | if (!valid) 157 | continue; 158 | /*int min_x = floor(min(min(triangles[i].v[0].x, triangles[i].v[1].x), triangles[i].v[2].x)); 159 | int max_x = ceil(max(max(triangles[i].v[0].x, triangles[i].v[1].x), triangles[i].v[2].x)); 160 | int min_y = floor(min(min(triangles[i].v[0].y, triangles[i].v[1].y), triangles[i].v[2].y)); 161 | int max_y = ceil(max(max(triangles[i].v[0].y, triangles[i].v[1].y), triangles[i].v[2].y));*/ 162 | 163 | //clamp bounds to window 164 | min_x = max(0, min_x); 165 | max_x = min(width, max_x); 166 | min_y = max(0, min_y); 167 | max_y = min(height, max_y); 168 | 169 | //sample all points within bounding box 170 | for (int x = min_x; x < max_x; x++) { 171 | for (int y = min_y; y < max_y; y++) { 172 | for (int m = 0; m < mSamples; m++) { 173 | for (int n = 0; n < nSamples; n++) { 174 | //get sample pos 175 | float sampleX = getKernelPtr(x, y, m, n)[0]; 176 | float sampleY = getKernelPtr(x, y, m, n)[1]; 177 | float sampleTime = getKernelPtr(x, y, m, n)[2]; 178 | 179 | //sample each triangle 180 | Triangle triangles[2]; 181 | triangles[0] = Triangle(points[0]->position, points[1]->position, points[2]->position); 182 | triangles[1] = Triangle(points[0]->position, points[2]->position, points[3]->position); 183 | 184 | for (int i = 0; i < 2; i++) { 185 | //calc position based on time 186 | for (int j = 0; j < 3; j++) { 187 | triangles[i].v[j] = triangles[i].v[j] + movementVector * sampleTime; 188 | //project 189 | triangles[i].v[j] = projection * triangles[i].v[j]; 190 | //perspective divide 191 | triangles[i].v[j] = triangles[i].v[j].homogenize(); 192 | 193 | //convert to pixel space 194 | triangles[i].v[j].x = (triangles[i].v[j].x + 1.0f) * 0.5f * width; 195 | triangles[i].v[j].y = (-triangles[i].v[j].y + 1.0f) * 0.5f * height; //y axis is inverted in pixel space 196 | } 197 | 198 | //set up interpolation 199 | float area = abs(triangles[i].normal().length()) / 2; 200 | Vector4 edge0 = triangles[i].v[2] - triangles[i].v[1]; 201 | Vector4 edge1 = triangles[i].v[0] - triangles[i].v[2]; 202 | 203 | //if sample point is inside triangle 204 | if (triangles[i].insideTriangle(sampleX, sampleY)) { 205 | //create node 206 | SampleNode* node = new SampleNode(); 207 | 208 | //interpolate attributes 209 | Vector4 p = Vector4(sampleX, sampleY, 1); 210 | Vector4 vp1 = p - triangles[i].v[1]; 211 | Vector4 vp2 = p - triangles[i].v[2]; 212 | float b0 = (edge0.cross(vp1).length() / 2) / area; 213 | float b1 = (edge1.cross(vp2).length() / 2) / area; 214 | //interpolate depth 215 | node->depth = b0 * triangles[i].v[0].z + b1 * triangles[i].v[1].z + (1 - b0 - b1) * triangles[i].v[2].z; 216 | //interpolate color and opacity 217 | for (int c = 0; c < 3; c++) { 218 | if (i == 0) { 219 | //triangle 0 has points 0,1,2 220 | node->color[c] = b0 * points[0]->color[c] + b1 * points[1]->color[c] + (1 - b0 - b1) * points[2]->color[c]; 221 | node->opacity[c] = b0 * points[0]->opacity[c] + b1 * points[1]->opacity[c] + (1 - b0 - b1) * points[2]->opacity[c]; 222 | } 223 | else { 224 | //triangle 1 has points 0,2,3 225 | node->color[c] = b0 * points[0]->color[c] + b1 * points[2]->color[c] + (1 - b0 - b1) * points[3]->color[c]; 226 | node->opacity[c] = b0 * points[0]->opacity[c] + b1 * points[2]->opacity[c] + (1 - b0 - b1) * points[3]->opacity[c]; 227 | } 228 | 229 | //clamp color and opacity between 0 and 1 230 | node->color[c] = min(max(0.0f, node->color[c]), 1.0f); 231 | node->opacity[c] = min(max(0.0f, node->opacity[c]), 1.0f); 232 | } 233 | 234 | //insert into buffer (sorted by depth - this will effectively perform depth test) 235 | insertSample(x, y, m, n, node); 236 | } 237 | } 238 | } 239 | } 240 | } 241 | } 242 | //} 243 | } 244 | } 245 | } 246 | 247 | void FrameBuffer::insertSample(int x, int y, int m, int n, SampleNode* node) { 248 | //discard samples below minimum threshold 249 | if (node->opacity[0] < ALPHA_TRANSPARENT_THRESHOLD && node->opacity[1] < ALPHA_TRANSPARENT_THRESHOLD && node->opacity[2] < ALPHA_TRANSPARENT_THRESHOLD) 250 | return; 251 | 252 | SampleNode** headPtr = getHeadPtr(x, y, m, n); 253 | 254 | //empty or first item 255 | if (*headPtr == NULL || node->depth < (*headPtr)->depth) { 256 | node->next = *headPtr; 257 | *headPtr = node; 258 | } 259 | else { 260 | SampleNode* curr = *headPtr; 261 | while (curr->next != NULL && curr->next->depth < node->depth) { 262 | curr = curr->next; 263 | } 264 | node->next = curr->next; 265 | curr->next = node; 266 | //if newly inserted item is fully opaque, delete everything after it 267 | if (node->opacity[0] > ALPHA_OPAQUE_THRESHOLD && node->opacity[1] > ALPHA_OPAQUE_THRESHOLD && node->opacity[2] > ALPHA_OPAQUE_THRESHOLD) { 268 | deleteList(node->next); 269 | node->next = NULL; 270 | } 271 | } 272 | } 273 | 274 | void FrameBuffer::collapseSamples(SampleNode* node, float* color) { 275 | //no entries or end of list - color is background 276 | if (node == NULL) { 277 | color[0] = Ri_backgroundColor[0]; 278 | color[1] = Ri_backgroundColor[1]; 279 | color[2] = Ri_backgroundColor[2]; 280 | return; 281 | } 282 | //look at next sample 283 | collapseSamples(node->next, color); 284 | 285 | //apply this nodes color 286 | color[0] = node->color[0] * node->opacity[0] + color[0] * (1 - node->opacity[0]); 287 | color[1] = node->color[1] * node->opacity[1] + color[1] * (1 - node->opacity[1]); 288 | color[2] = node->color[2] * node->opacity[2] + color[2] * (1 - node->opacity[2]); 289 | } 290 | 291 | void FrameBuffer::deleteList(SampleNode* node) { 292 | while (node != NULL) { 293 | SampleNode* temp = node; 294 | node = node->next; 295 | delete temp; 296 | } 297 | } -------------------------------------------------------------------------------- /Reyes/FrameBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Mesh.h" 3 | #include "Triangle.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | using std::max; 9 | using std::min; 10 | 11 | #define NEAR_PLANE 0.01f 12 | #define FAR_PLANE 100.0f 13 | 14 | // Furthest distance 15 | #define MAX_DEPTH 1.0f 16 | 17 | // All alphas below this value will be considered fully transparent and discarded 18 | #define ALPHA_TRANSPARENT_THRESHOLD 0.04f 19 | // All alphas above this value will be considered fully opaque and will block 20 | #define ALPHA_OPAQUE_THRESHOLD 0.96f 21 | 22 | // Motion blur reference 23 | // http://graphics.stanford.edu/papers/mprast/rast_hpg09.pdf 24 | 25 | extern RtColor Ri_backgroundColor; 26 | 27 | // The values of a sampled point as a linked-list node 28 | struct SampleNode { 29 | //data 30 | float color[3]; 31 | float opacity[3]; 32 | float depth; 33 | 34 | //next 35 | SampleNode* next; 36 | 37 | SampleNode() { 38 | next = NULL; 39 | } 40 | }; 41 | 42 | // Holds state of current frame 43 | class FrameBuffer { 44 | private: 45 | // Dimensions 46 | int width, height; 47 | int mSamples, nSamples; 48 | int numIntervals; 49 | 50 | float timeStart, timeStop; 51 | 52 | // Sample kernel (x, y, t) 53 | // x and y are in pixel space 54 | // t is from timeStart to timeStop 55 | float* sampleKernel; 56 | 57 | // Z-buffer and color buffer 58 | SampleNode** zbuffer; 59 | 60 | // Linked-list manipulation 61 | // Insert a sample 62 | void insertSample(int x, int y, int m, int n, SampleNode* node); 63 | // Collapse list of samples and apply opacity 64 | void collapseSamples(SampleNode* head, float* color); 65 | // Deletes list from node until the end 66 | void deleteList(SampleNode* node); 67 | 68 | public: 69 | FrameBuffer() { 70 | width = height = mSamples = nSamples = 0; 71 | zbuffer = NULL; 72 | sampleKernel = NULL; 73 | } 74 | 75 | // Initalize and allocate a framebuffer with the given dimensions 76 | FrameBuffer(int width, int height, int mSamples, int nSamples, float timeStart, float timeStop); 77 | 78 | ~FrameBuffer() { 79 | delete[] sampleKernel; 80 | Clear(); 81 | delete[] zbuffer; 82 | } 83 | 84 | // Apply a mesh to depth/color buffer 85 | void DrawMesh(Mesh* mesh, Vector4& movementVector, Matrix4& projection); 86 | 87 | // Filter and output to bitmap file 88 | void FilterAndSaveToFile(std::string path); 89 | 90 | // Completely clear buffer 91 | void Clear() { 92 | for (int x = 0; x < width; x++) { 93 | for (int y = 0; y < height; y++) { 94 | for (int m = 0; m < mSamples; m++) { 95 | for (int n = 0; n < nSamples; n++) { 96 | SampleNode** head = getHeadPtr(x, y, m, n); 97 | deleteList(*head); 98 | *head = NULL; 99 | } 100 | } 101 | } 102 | } 103 | } 104 | 105 | // Get the head of the linkedlist at the given pixel and sample point 106 | SampleNode** getHeadPtr(int x, int y, int m, int n) { 107 | return (zbuffer + (y * mSamples * nSamples * width + x * mSamples * nSamples + n * mSamples + m)); 108 | } 109 | 110 | // Get the sample position as an array of 3 floats 111 | float* getKernelPtr(int x, int y, int m, int n) { 112 | return (sampleKernel + (y * mSamples * nSamples * width + x * mSamples * nSamples + n * mSamples + m) * 3); 113 | } 114 | 115 | int GetWidth() { 116 | return width; 117 | } 118 | 119 | int GetHeight() { 120 | return height; 121 | } 122 | 123 | int GetSampleWidth() { 124 | return mSamples; 125 | } 126 | 127 | int GetSampleHeight() { 128 | return nSamples; 129 | } 130 | }; -------------------------------------------------------------------------------- /Reyes/Matrix4.cpp: -------------------------------------------------------------------------------- 1 | #include "Matrix4.h" 2 | 3 | 4 | 5 | Matrix4::Matrix4() { 6 | //zeros 7 | for (int i = 0; i < MATRIX_NUM_ELEM; i++) { 8 | m[i] = 0.0f; 9 | } 10 | } 11 | 12 | Matrix4::~Matrix4() { 13 | } 14 | 15 | Matrix4::Matrix4(float values[4][4]) { 16 | for (int i = 0; i < MATRIX_SIZE; i++) { 17 | for (int j = 0; j < MATRIX_SIZE; j++) { 18 | m[j*MATRIX_SIZE + i] = values[i][j]; 19 | } 20 | } 21 | } 22 | 23 | Matrix4 Matrix4::Identity() { 24 | Matrix4 result; 25 | result.m[0] = 1.0f; 26 | result.m[5] = 1.0f; 27 | result.m[10] = 1.0f; 28 | result.m[15] = 1.0f; 29 | return result; 30 | } 31 | 32 | Matrix4 Matrix4::Translate(float x, float y, float z) { 33 | //start with identity 34 | Matrix4 result = Matrix4::Identity(); 35 | result.m[12] = x; 36 | result.m[13] = y; 37 | result.m[14] = z; 38 | return result; 39 | } 40 | 41 | Matrix4 Matrix4::Scale(float x, float y, float z) { 42 | Matrix4 result; 43 | result.m[0] = x; 44 | result.m[5] = y; 45 | result.m[10] = z; 46 | result.m[15] = 1.0f; 47 | return result; 48 | } 49 | 50 | Matrix4 Matrix4::RotateX(float angle) { 51 | Matrix4 result; 52 | result.m[0] = 1.0f; 53 | result.m[5] = cos(angle); 54 | result.m[9] = -sin(angle); 55 | result.m[6] = sin(angle); 56 | result.m[10] = cos(angle); 57 | result.m[15] = 1.0f; 58 | return result; 59 | } 60 | 61 | Matrix4 Matrix4::RotateY(float angle) { 62 | Matrix4 result; 63 | result.m[0] = cos(angle); 64 | result.m[8] = sin(angle); 65 | result.m[5] = 1.0f; 66 | result.m[2] = -sin(angle); 67 | result.m[10] = cos(angle); 68 | result.m[15] = 1.0f; 69 | return result; 70 | } 71 | 72 | Matrix4 Matrix4::RotateZ(float angle) { 73 | Matrix4 result; 74 | result.m[0] = cos(angle); 75 | result.m[4] = -sin(angle); 76 | result.m[1] = sin(angle); 77 | result.m[5] = cos(angle); 78 | result.m[10] = 1.0f; 79 | result.m[15] = 1.0f; 80 | return result; 81 | } 82 | 83 | Matrix4 Matrix4::Rotate(float angle, float x, float y, float z) { 84 | Vector4 axis(x, y, z); 85 | axis = axis.normalize(); 86 | x = axis.x; 87 | y = axis.y; 88 | z = axis.z; 89 | Matrix4 result; 90 | result.m[0] = x * x * (1 - cos(angle)) + cos(angle); 91 | result.m[1] = x * y * (1 - cos(angle)) + z * sin(angle); 92 | result.m[2] = x * z * (1 - cos(angle)) - y * sin(angle); 93 | result.m[4] = y * x * (1 - cos(angle)) - z * sin(angle); 94 | result.m[5] = y * y * (1 - cos(angle)) + cos(angle); 95 | result.m[6] = y * z * (1 - cos(angle)) + x * sin(angle); 96 | result.m[8] = z * x * (1 - cos(angle)) + y * sin(angle); 97 | result.m[9] = z * y * (1 - cos(angle)) - x * sin(angle); 98 | result.m[10] = z * z * (1 - cos(angle)) + cos(angle); 99 | result.m[15] = 1.0f; 100 | return result; 101 | } 102 | 103 | Matrix4 Matrix4::Orthographic(float left, float right, float top, float bottom, float near, float far) { 104 | Matrix4 result; 105 | result.m[0] = 2.0f / (right - left); 106 | result.m[5] = 2.0f / (top - bottom); 107 | result.m[10] = 1.0f / (far - near); 108 | result.m[15] = 1.0f; 109 | result.m[3] = -(right + left) / (right - left); 110 | result.m[7] = -(top + bottom) / (top - bottom); 111 | result.m[11] = 1 -(far + near) / (far - near); 112 | return result; 113 | } 114 | 115 | Matrix4 Matrix4::Perspective(float fov, float aspect, float near, float far) { 116 | float f = 1.0f / tan(fov / 2.0f); 117 | Matrix4 result; 118 | result.m[0] = f / aspect; //f 119 | result.m[5] = f;//1.0f / tan(fov / (aspect *2.0f)); // 120 | result.m[10] = far / (far - near); //(far + near) / (near - far); 121 | result.m[14] = -far * near / (far - near); //-2 * far*near / (near - far); 122 | result.m[11] = 1.0f; 123 | return result; 124 | } 125 | 126 | Matrix4 Matrix4::operator*(const Matrix4& other) { 127 | Matrix4 result; 128 | //result.m[0] = m[0] * other.m[0] + m[4] * other.m[1] + m[8] * other.m[2] + m[12] * other.m[3]; 129 | for (int c = 0; c < MATRIX_SIZE; c++) { 130 | for (int r = 0; r < MATRIX_SIZE; r++) { 131 | result.m[r + c * 4] = 0.0f; 132 | for (int i = 0; i < MATRIX_SIZE; i++) { 133 | result.m[r + c * 4] += m[r + i * 4] * other.m[i + c * 4]; 134 | } 135 | } 136 | } 137 | return result; 138 | } 139 | 140 | Vector4 Matrix4::operator*(const Vector4& other) { 141 | Vector4 result; 142 | result.x = other.x * m[0] + other.y * m[4] + other.z * m[8] + other.w * m[12]; 143 | result.y = other.x * m[1] + other.y * m[5] + other.z * m[9] + other.w * m[13]; 144 | result.z = other.x * m[2] + other.y * m[6] + other.z * m[10] + other.w * m[14]; 145 | result.w = other.x * m[3] + other.y * m[7] + other.z * m[11] + other.w * m[15]; 146 | /*for (int i = 0; i < MATRIX_SIZE; i++) { 147 | result.v[i] = 0.0f; 148 | for (int j = 0; j < VECTOR4_SIZE; j++) { 149 | result.v[i] += other.v[j] * m[i + j * 4]; 150 | } 151 | }*/ 152 | return result; 153 | } 154 | 155 | Matrix4 Matrix4::operator*(float scalar) { 156 | Matrix4 result; 157 | for (int i = 0; i < MATRIX_NUM_ELEM; i++) { 158 | result.m[i] = m[i] * scalar; 159 | } 160 | return result; 161 | } 162 | 163 | Matrix4 Matrix4::transpose() { 164 | Matrix4 result; 165 | result.m[0] = m[0]; 166 | result.m[1] = m[4]; 167 | result.m[2] = m[8]; 168 | result.m[3] = m[12]; 169 | result.m[4] = m[1]; 170 | result.m[5] = m[5]; 171 | result.m[6] = m[9]; 172 | result.m[7] = m[13]; 173 | result.m[8] = m[2]; 174 | result.m[9] = m[6]; 175 | result.m[10] = m[10]; 176 | result.m[11] = m[14]; 177 | result.m[12] = m[3]; 178 | result.m[13] = m[7]; 179 | result.m[14] = m[11]; 180 | result.m[15] = m[15]; 181 | return result; 182 | } 183 | 184 | Matrix4 Matrix4::inverse() { 185 | // 186 | // Inversion by Cramer's rule. Code taken from an Intel publication 187 | // Source: https://graphics.stanford.edu/~mdfisher/Code/Engine/Matrix4.cpp.html 188 | // Original Source: http://download.intel.com/design/PentiumIII/sml/24504301.pdf 189 | // 190 | double Result[4][4]; 191 | double tmp[12]; /* temp array for pairs */ 192 | double src[16]; /* array of transpose source matrix */ 193 | double det; /* determinant */ 194 | /* transpose matrix */ 195 | for (int i = 0; i < 4; i++) 196 | { 197 | src[i + 0] = m[i*4 + 0]; 198 | src[i + 4] = m[i*4 + 1]; 199 | src[i + 8] = m[i*4 + 2]; 200 | src[i + 12] = m[i*4 + 3]; 201 | } 202 | /* calculate pairs for first 8 elements (cofactors) */ 203 | tmp[0] = src[10] * src[15]; 204 | tmp[1] = src[11] * src[14]; 205 | tmp[2] = src[9] * src[15]; 206 | tmp[3] = src[11] * src[13]; 207 | tmp[4] = src[9] * src[14]; 208 | tmp[5] = src[10] * src[13]; 209 | tmp[6] = src[8] * src[15]; 210 | tmp[7] = src[11] * src[12]; 211 | tmp[8] = src[8] * src[14]; 212 | tmp[9] = src[10] * src[12]; 213 | tmp[10] = src[8] * src[13]; 214 | tmp[11] = src[9] * src[12]; 215 | /* calculate first 8 elements (cofactors) */ 216 | Result[0][0] = tmp[0] * src[5] + tmp[3] * src[6] + tmp[4] * src[7]; 217 | Result[0][0] -= tmp[1] * src[5] + tmp[2] * src[6] + tmp[5] * src[7]; 218 | Result[0][1] = tmp[1] * src[4] + tmp[6] * src[6] + tmp[9] * src[7]; 219 | Result[0][1] -= tmp[0] * src[4] + tmp[7] * src[6] + tmp[8] * src[7]; 220 | Result[0][2] = tmp[2] * src[4] + tmp[7] * src[5] + tmp[10] * src[7]; 221 | Result[0][2] -= tmp[3] * src[4] + tmp[6] * src[5] + tmp[11] * src[7]; 222 | Result[0][3] = tmp[5] * src[4] + tmp[8] * src[5] + tmp[11] * src[6]; 223 | Result[0][3] -= tmp[4] * src[4] + tmp[9] * src[5] + tmp[10] * src[6]; 224 | Result[1][0] = tmp[1] * src[1] + tmp[2] * src[2] + tmp[5] * src[3]; 225 | Result[1][0] -= tmp[0] * src[1] + tmp[3] * src[2] + tmp[4] * src[3]; 226 | Result[1][1] = tmp[0] * src[0] + tmp[7] * src[2] + tmp[8] * src[3]; 227 | Result[1][1] -= tmp[1] * src[0] + tmp[6] * src[2] + tmp[9] * src[3]; 228 | Result[1][2] = tmp[3] * src[0] + tmp[6] * src[1] + tmp[11] * src[3]; 229 | Result[1][2] -= tmp[2] * src[0] + tmp[7] * src[1] + tmp[10] * src[3]; 230 | Result[1][3] = tmp[4] * src[0] + tmp[9] * src[1] + tmp[10] * src[2]; 231 | Result[1][3] -= tmp[5] * src[0] + tmp[8] * src[1] + tmp[11] * src[2]; 232 | /* calculate pairs for second 8 elements (cofactors) */ 233 | tmp[0] = src[2] * src[7]; 234 | tmp[1] = src[3] * src[6]; 235 | tmp[2] = src[1] * src[7]; 236 | tmp[3] = src[3] * src[5]; 237 | tmp[4] = src[1] * src[6]; 238 | tmp[5] = src[2] * src[5]; 239 | 240 | tmp[6] = src[0] * src[7]; 241 | tmp[7] = src[3] * src[4]; 242 | tmp[8] = src[0] * src[6]; 243 | tmp[9] = src[2] * src[4]; 244 | tmp[10] = src[0] * src[5]; 245 | tmp[11] = src[1] * src[4]; 246 | /* calculate second 8 elements (cofactors) */ 247 | Result[2][0] = tmp[0] * src[13] + tmp[3] * src[14] + tmp[4] * src[15]; 248 | Result[2][0] -= tmp[1] * src[13] + tmp[2] * src[14] + tmp[5] * src[15]; 249 | Result[2][1] = tmp[1] * src[12] + tmp[6] * src[14] + tmp[9] * src[15]; 250 | Result[2][1] -= tmp[0] * src[12] + tmp[7] * src[14] + tmp[8] * src[15]; 251 | Result[2][2] = tmp[2] * src[12] + tmp[7] * src[13] + tmp[10] * src[15]; 252 | Result[2][2] -= tmp[3] * src[12] + tmp[6] * src[13] + tmp[11] * src[15]; 253 | Result[2][3] = tmp[5] * src[12] + tmp[8] * src[13] + tmp[11] * src[14]; 254 | Result[2][3] -= tmp[4] * src[12] + tmp[9] * src[13] + tmp[10] * src[14]; 255 | Result[3][0] = tmp[2] * src[10] + tmp[5] * src[11] + tmp[1] * src[9]; 256 | Result[3][0] -= tmp[4] * src[11] + tmp[0] * src[9] + tmp[3] * src[10]; 257 | Result[3][1] = tmp[8] * src[11] + tmp[0] * src[8] + tmp[7] * src[10]; 258 | Result[3][1] -= tmp[6] * src[10] + tmp[9] * src[11] + tmp[1] * src[8]; 259 | Result[3][2] = tmp[6] * src[9] + tmp[11] * src[11] + tmp[3] * src[8]; 260 | Result[3][2] -= tmp[10] * src[11] + tmp[2] * src[8] + tmp[7] * src[9]; 261 | Result[3][3] = tmp[10] * src[10] + tmp[4] * src[8] + tmp[9] * src[9]; 262 | Result[3][3] -= tmp[8] * src[9] + tmp[11] * src[10] + tmp[5] * src[8]; 263 | /* calculate determinant */ 264 | det = src[0] * Result[0][0] + src[1] * Result[0][1] + src[2] * Result[0][2] + src[3] * Result[0][3]; 265 | /* calculate matrix inverse */ 266 | det = 1.0f / det; 267 | //End code 268 | 269 | Matrix4 result; 270 | for (int i = 0; i < 4; i++) 271 | { 272 | for (int j = 0; j < 4; j++) 273 | { 274 | result.m[i*4 + j] = float(Result[i][j] * det); 275 | } 276 | } 277 | return result; 278 | } -------------------------------------------------------------------------------- /Reyes/Matrix4.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Vector4.h" 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | #define MATRIX_SIZE 4 7 | #define MATRIX_NUM_ELEM 16 8 | 9 | // 4x4 Matrix 10 | class Matrix4 { 11 | public: 12 | //Data arranged in column-major order: 13 | // 0 4 8 12 14 | // 1 5 9 13 15 | // 2 6 10 14 16 | // 3 7 11 15 17 | float m[MATRIX_NUM_ELEM]; 18 | 19 | //Create a zero matrix 20 | Matrix4(); 21 | ~Matrix4(); 22 | 23 | //Create a matrix from a 4x4 array 24 | Matrix4(float values[4][4]); 25 | 26 | //Create an identity matrix 27 | static Matrix4 Identity(); 28 | 29 | //Create a 3D translation matrix 30 | static Matrix4 Translate(float x, float y, float z); 31 | 32 | //Create a scaling matrix 33 | static Matrix4 Scale(float x, float y, float z); 34 | 35 | //Create a rotation matrix around x axis 36 | static Matrix4 RotateX(float angle); 37 | //Create a rotation matrix around y axis 38 | static Matrix4 RotateY(float angle); 39 | //Create a rotation matrix around z axis 40 | static Matrix4 RotateZ(float angle); 41 | //Create a rotation matrix around arbitrary axis x, y, z 42 | static Matrix4 Rotate(float angle, float x, float y, float z); 43 | 44 | //Create an orthographic projection matrix 45 | static Matrix4 Orthographic(float left, float right, float top, float bottom, float near, float far); 46 | //Create a perspective projection matrix where near z is mapped to 0 and far z is mapped to 1 47 | static Matrix4 Perspective(float fov, float aspect, float near, float far); 48 | 49 | //Addition 50 | //Matrix4 operator+(const Matrix4& other); 51 | 52 | //Subtraction 53 | //Matrix4 operator-(const Matrix4& other); 54 | 55 | //Multiplication 56 | Matrix4 operator*(const Matrix4& other); 57 | Vector4 operator*(const Vector4& other); 58 | Matrix4 operator*(float scalar); 59 | 60 | //Transpose 61 | Matrix4 transpose(); 62 | 63 | //Inverse 64 | Matrix4 inverse(); 65 | 66 | //Accessors 67 | //float get(int row, int column); 68 | }; 69 | 70 | -------------------------------------------------------------------------------- /Reyes/Mesh.cpp: -------------------------------------------------------------------------------- 1 | #include "Mesh.h" 2 | -------------------------------------------------------------------------------- /Reyes/Mesh.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ri.h" 3 | #include "Shader.h" 4 | #include "Matrix4.h" 5 | #include "Vector4.h" 6 | #define _USE_MATH_DEFINES 7 | #include 8 | #include 9 | using std::min; 10 | using std::max; 11 | 12 | // Shader function pointers 13 | extern void(*Ri_shaderSurfaceFunction)(); 14 | extern void(*Ri_shaderDisplacementFunction)(); 15 | 16 | // A point in the grid at (u,v) 17 | struct MeshPoint { 18 | bool valid; 19 | Vector4 position; 20 | Vector4 normal; 21 | float color[3]; 22 | float opacity[3]; 23 | }; 24 | 25 | // A grid of points (u, v) with their corresponding positions and attributes 26 | class Mesh { 27 | public: 28 | int width, height; 29 | MeshPoint* grid; 30 | 31 | Mesh() { 32 | width = height = 0; 33 | grid = NULL; 34 | } 35 | 36 | Mesh(int width, int height) { 37 | this->width = width; 38 | this->height = height; 39 | grid = new MeshPoint[width * height]; 40 | } 41 | 42 | ~Mesh() { 43 | if (grid != NULL) { 44 | delete[] grid; 45 | } 46 | } 47 | 48 | MeshPoint *getGridPtr(int u, int v) { 49 | return (grid + (v * width + u)); 50 | } 51 | 52 | // Apply MVP matrix to all points in grid 53 | void ApplyMatrix(Matrix4& matrix) { 54 | //calculate transposed inverse matrix for normals 55 | Matrix4 normalMatrix = matrix.inverse().transpose(); 56 | //truncate into 3x3 to ignore translation component 57 | normalMatrix.m[3] = 0.0f; 58 | normalMatrix.m[7] = 0.0f; 59 | normalMatrix.m[11] = 0.0f; 60 | normalMatrix.m[12] = 0.0f; 61 | normalMatrix.m[13] = 0.0f; 62 | normalMatrix.m[14] = 0.0f; 63 | normalMatrix.m[15] = 0.0f; 64 | for (int u = 0; u < width; u++) { 65 | for (int v = 0; v < height; v++) { 66 | getGridPtr(u, v)->position = matrix * getGridPtr(u, v)->position; 67 | getGridPtr(u, v)->normal = (normalMatrix * getGridPtr(u, v)->normal).normalize(); 68 | } 69 | } 70 | } 71 | 72 | // "Clip", perform perspective divide, and transform to pixel space for all points in the grid 73 | // Currently only used for initial bounding, as projection is now done during drawing phase(FrameBuffer::DrawMesh) so we can apply motion blur 74 | void Project(int frameWidth, int frameHeight) { 75 | //convert points to screen space 76 | for (int u = 0; u < width; u++) { 77 | for (int v = 0; v < height; v++) { 78 | //Clip against near and far 79 | if (getGridPtr(u, v)->position.z < 0 || getGridPtr(u, v)->position.z > getGridPtr(u, v)->position.w) { 80 | getGridPtr(u, v)->valid = false; 81 | //printf("invalid: "); 82 | //getGridPtr(u, v)->position.print(); 83 | continue; 84 | } 85 | //TODO: clip against other planes 86 | getGridPtr(u, v)->valid = true; 87 | 88 | //perspective divide 89 | Vector4 pos = getGridPtr(u, v)->position.homogenize(); 90 | 91 | //convert to pixel space 92 | getGridPtr(u, v)->position.x = (pos.x + 1.0f) * 0.5f * frameWidth; 93 | getGridPtr(u, v)->position.y = (-pos.y + 1.0f) * 0.5f * frameHeight; //y axis is inverted in pixel space 94 | getGridPtr(u, v)->position.z = pos.z; 95 | getGridPtr(u, v)->position.w = 1.0f; 96 | } 97 | } 98 | } 99 | 100 | // Apply displacement shader if one is being used 101 | void ShadeDisplacement() { 102 | if (Ri_shaderDisplacementFunction == NULL) 103 | return; 104 | 105 | //set input variables that don't change 106 | __my_shader_du = 1.0f / (width - 1); 107 | __my_shader_dv = 1.0f / (height - 1); 108 | 109 | for (int u = 0; u < width; u++) { 110 | for (int v = 0; v < height; v++) { 111 | //set input variables 112 | setShaderArguments(u, v, false); 113 | 114 | //run shader 115 | Ri_shaderDisplacementFunction(); 116 | 117 | //save modified values 118 | //position 119 | getGridPtr(u, v)->position.x = __my_shader_P[0]; 120 | getGridPtr(u, v)->position.y = __my_shader_P[1]; 121 | getGridPtr(u, v)->position.z = __my_shader_P[2]; 122 | 123 | //normals 124 | //normals will be recalculated 125 | /* 126 | getGridPtr(u, v)->normal.x = __my_shader_N[0]; 127 | getGridPtr(u, v)->normal.y = __my_shader_N[1]; 128 | getGridPtr(u, v)->normal.z = __my_shader_N[2];*/ 129 | } 130 | } 131 | 132 | //recalculate normals 133 | for (int u = 0; u < width; u++) { 134 | for (int v = 0; v < height; v++) { 135 | int currU = (u == 0) ? u : u - 1; 136 | int currV = (v == 0) ? v : v - 1; 137 | int nextU = (u == width - 1) ? u : u + 1; 138 | int nextV = (v == height - 1) ? v : v + 1; 139 | Vector4 dPdu = (getGridPtr(nextU, v)->position - getGridPtr(currU, v)->position).normalize(); 140 | Vector4 dPdv = (getGridPtr(u, nextV)->position - getGridPtr(u, currV)->position).normalize(); 141 | getGridPtr(u, v)->normal = (dPdv.cross(dPdu)).normalize(); 142 | } 143 | } 144 | } 145 | 146 | // Apply surface shader if one is being used or just do lighting 147 | void ShadeSurface() { 148 | //if (Ri_shaderSurfaceFunction == NULL) 149 | // return; 150 | 151 | //set input variables that don't change 152 | __my_shader_du = 1.0f / (width - 1); 153 | __my_shader_dv = 1.0f / (height - 1); 154 | 155 | for (int u = 0; u < width; u++) { 156 | for (int v = 0; v < height; v++) { 157 | //set input variables 158 | setShaderArguments(u, v, true); 159 | 160 | //run shader 161 | if (Ri_shaderSurfaceFunction != NULL) 162 | Ri_shaderSurfaceFunction(); 163 | 164 | //always do lighting 165 | LIGHTING(); 166 | 167 | //save modified values 168 | //color 169 | getGridPtr(u, v)->color[0] = __my_shader_Ci[0]; 170 | getGridPtr(u, v)->color[1] = __my_shader_Ci[1]; 171 | getGridPtr(u, v)->color[2] = __my_shader_Ci[2]; 172 | //opacity 173 | getGridPtr(u, v)->opacity[0] = __my_shader_Oi[0]; 174 | getGridPtr(u, v)->opacity[1] = __my_shader_Oi[1]; 175 | getGridPtr(u, v)->opacity[2] = __my_shader_Oi[2]; 176 | } 177 | } 178 | } 179 | 180 | void setShaderArguments(int u, int v, bool surface) { 181 | //position 182 | __my_shader_P[0] = getGridPtr(u, v)->position.x; 183 | __my_shader_P[1] = getGridPtr(u, v)->position.y; 184 | __my_shader_P[2] = getGridPtr(u, v)->position.z; 185 | //normal 186 | __my_shader_N[0] = getGridPtr(u, v)->normal.x; 187 | __my_shader_N[1] = getGridPtr(u, v)->normal.y; 188 | __my_shader_N[2] = getGridPtr(u, v)->normal.z; 189 | //color 190 | __my_shader_Ci[0] = getGridPtr(u, v)->color[0]; 191 | __my_shader_Ci[1] = getGridPtr(u, v)->color[1]; 192 | __my_shader_Ci[2] = getGridPtr(u, v)->color[2]; 193 | //opacity 194 | __my_shader_Oi[0] = getGridPtr(u, v)->opacity[0]; 195 | __my_shader_Oi[1] = getGridPtr(u, v)->opacity[1]; 196 | __my_shader_Oi[2] = getGridPtr(u, v)->opacity[2]; 197 | //u,v 198 | __my_shader_u = (float)u / (width - 1); 199 | __my_shader_v = (float)v / (height - 1); 200 | //derivatives 201 | //use prev and next point, except on edges of mesh 202 | int currU = (u == 0) ? u : u - 1; 203 | int currV = (v == 0) ? v : v - 1; 204 | int nextU = (u == width - 1) ? u : u + 1; 205 | int nextV = (v == height - 1) ? v : v + 1; 206 | Vector4 dPdu = (getGridPtr(nextU, v)->position - getGridPtr(currU, v)->position) * (1.0f/__my_shader_du); 207 | __my_shader_dPdu[0] = dPdu.x; 208 | __my_shader_dPdu[1] = dPdu.y; 209 | __my_shader_dPdu[2] = dPdu.z; 210 | Vector4 dPdv = (getGridPtr(u, nextV)->position - getGridPtr(u, currV)->position) * (1.0f / __my_shader_dv); 211 | __my_shader_dPdv[0] = dPdv.x; 212 | __my_shader_dPdv[1] = dPdv.y; 213 | __my_shader_dPdv[2] = dPdv.z; 214 | } 215 | }; -------------------------------------------------------------------------------- /Reyes/Noise.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #define _USE_MATH_DEFINES 4 | #include 5 | #include 6 | #include 7 | 8 | #define GRID_SIZE 256 9 | 10 | // 3-D Perlin Noise 11 | class Noise { 12 | private: 13 | // 3D cube of gradients (3-D vectors) 14 | float gradients[GRID_SIZE+1][GRID_SIZE+1][GRID_SIZE+1][3]; 15 | 16 | float lerp(float a, float b, float t) { 17 | return a + t * (b - a); 18 | } 19 | 20 | // fifth degree interpolator 6t^5 - 15t^4 + 10t^3 21 | // as used in Perlin's improved algorithm 22 | // http://http.developer.nvidia.com/GPUGems/gpugems_ch05.html 23 | float smooth(float t) { 24 | return t * t * t * (t * (t * 6 - 15) + 10); 25 | } 26 | 27 | // dot product between distance vector of u,v,w and gradient at grid position x,y,z 28 | float gridGradient(int x, int y, int z, float u, float v, float w) { 29 | float du = u - x; 30 | float dv = v - y; 31 | float dw = w - z; 32 | return du * gradients[x][y][z][0] + dv * gradients[x][y][z][1] + dw * gradients[x][y][z][2]; 33 | } 34 | 35 | public: 36 | Noise() { 37 | //create grid 38 | for (int x = 0; x < GRID_SIZE; x++) { 39 | for (int y = 0; y < GRID_SIZE; y++) { 40 | for (int z = 0; z < GRID_SIZE; z++) { 41 | //pick a point on the unit sphere 42 | //using formulas 6, 7, 8 on http://mathworld.wolfram.com/SpherePointPicking.html 43 | float theta = ((float)rand() / RAND_MAX) * 2.0f * M_PI; 44 | float u = ((float)rand() / RAND_MAX) * 2.0f - 1.0f; 45 | 46 | gradients[x][y][z][0] = sqrt(1 - u*u) * cos(theta); 47 | gradients[x][y][z][1] = sqrt(1 - u*u) * sin(theta); 48 | gradients[x][y][z][2] = u; 49 | } 50 | } 51 | } 52 | //duplicate first layer as last layer 53 | for (int i = 0; i < 3; i++) { 54 | gradients[GRID_SIZE - 1][GRID_SIZE-1][GRID_SIZE][i] = gradients[GRID_SIZE - 1][GRID_SIZE-1][0][i]; 55 | gradients[GRID_SIZE - 1][GRID_SIZE][GRID_SIZE-1][i] = gradients[GRID_SIZE - 1][0][GRID_SIZE - 1][i]; 56 | gradients[GRID_SIZE-1][GRID_SIZE][GRID_SIZE][i] = gradients[GRID_SIZE-1][0][0][i]; 57 | gradients[GRID_SIZE][GRID_SIZE - 1][GRID_SIZE - 1][i] = gradients[0][GRID_SIZE - 1][GRID_SIZE - 1][i]; 58 | gradients[GRID_SIZE][GRID_SIZE - 1][GRID_SIZE][i] = gradients[0][GRID_SIZE - 1][0][i]; 59 | gradients[GRID_SIZE][GRID_SIZE][GRID_SIZE - 1][i] = gradients[0][0][GRID_SIZE - 1][i]; 60 | gradients[GRID_SIZE][GRID_SIZE][GRID_SIZE][i] = gradients[0][0][0][i]; 61 | } 62 | } 63 | 64 | float noise(float x, float y, float z) { 65 | //which cube to use (tile for points after GRID_SIZE or before 0) 66 | //min corner 67 | int x0 = (int)floor(x) % GRID_SIZE; 68 | int y0 = (int)floor(y) % GRID_SIZE; 69 | int z0 = (int)floor(z) % GRID_SIZE; 70 | //max corner 71 | int x1 = x0 + 1; 72 | int y1 = y0 + 1; 73 | int z1 = z0 + 1; 74 | 75 | //wrap around for point within cube 76 | x = x - floor(x) + x0; 77 | y = y - floor(y) + y0; 78 | z = z - floor(z) + z0; 79 | 80 | //get point within cube from 0 to 1 and smooth it 81 | //used as interpolant weights 82 | float dx = smooth(x - floor(x)); 83 | float dy = smooth(y - floor(y)); 84 | float dz = smooth(z - floor(z)); 85 | 86 | //interpolate between corners of grid 87 | //x dimension 88 | float c00 = lerp(gridGradient(x0, y0, z0, x, y, z), gridGradient(x1, y0, z0, x, y, z), dx); 89 | float c01 = lerp(gridGradient(x0, y0, z1, x, y, z), gridGradient(x1, y0, z1, x, y, z), dx); 90 | float c10 = lerp(gridGradient(x0, y1, z0, x, y, z), gridGradient(x1, y1, z0, x, y, z), dx); 91 | float c11 = lerp(gridGradient(x0, y1, z1, x, y, z), gridGradient(x1, y1, z1, x, y, z), dx); 92 | //y dimension 93 | float c0 = lerp(c00, c10, dy); 94 | float c1 = lerp(c01, c11, dy); 95 | //z dimension 96 | return lerp(c0, c1, dz); 97 | } 98 | 99 | float octaveNoise(float x, float y, float z, int start, int stop) { 100 | float n = 0; 101 | float total = 0; 102 | for (int i = start; i <= stop; i++) { 103 | float amplitude = 1.0f / pow(2, i); 104 | total += amplitude; 105 | n += amplitude * noise(x * pow(2, i), y * pow(2, i), z); 106 | //amplitude *= 0.5f; 107 | } 108 | return n / total; 109 | } 110 | }; -------------------------------------------------------------------------------- /Reyes/Primitive.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Matrix4.h" 3 | #include "Mesh.h" 4 | 5 | #define MICROPOLYGONS_PER_PIXEL 2 6 | 7 | //which solid color new primitives are set to 8 | extern RtColor Ri_drawColor; 9 | //which opacity new primtives are set to 10 | extern RtColor Ri_drawOpacity; 11 | 12 | // A primitive that can be diced into a Mesh 13 | class Primitive { 14 | protected: 15 | virtual void getPositionAndNormal(float u, float v, Vector4& position, Vector4& normal) = 0; 16 | virtual void getBounds(Vector4& bbMin, Vector4& bbMax) = 0; 17 | public: 18 | bool Bound(Matrix4& mvp, int frameWidth, int frameHeight, int& diceFactor) { 19 | //get a feel for how big the primitive will be 20 | //TODO: account for possible displacement 21 | //diceFactor = 100; 22 | //return true; 23 | Mesh* coarseMesh = Dice(8, 8); 24 | coarseMesh->ApplyMatrix(mvp); 25 | coarseMesh->Project(frameWidth, frameHeight); 26 | //get bounds from mesh 27 | float x_min = FLT_MAX; 28 | float x_max = FLT_MIN; 29 | float y_min = FLT_MAX; 30 | float y_max = FLT_MIN; 31 | bool valid = false; 32 | for (int u = 0; u < coarseMesh->width; u++) { 33 | for (int v = 0; v < coarseMesh->width; v++) { 34 | MeshPoint* point = coarseMesh->getGridPtr(u, v); 35 | //only look at valid points 36 | if (!point->valid) 37 | continue; 38 | //must have one valid point 39 | valid = true; 40 | if (point->position.x < x_min) 41 | x_min = point->position.x; 42 | if (point->position.x > x_max) 43 | x_max = point->position.x; 44 | if (point->position.y < y_min) 45 | y_min = point->position.y; 46 | if (point->position.y > y_max) 47 | y_max = point->position.y; 48 | } 49 | } 50 | delete coarseMesh; 51 | if (!valid) 52 | return false; 53 | 54 | //bind to screen dimensions 55 | //y_max = min((int)y_max, frameHeight); 56 | //y_min = max((int)y_min, 0); 57 | //x_max = min((int)x_max, frameWidth); 58 | //x_min = max((int)x_min, 0); 59 | 60 | //if it will be on the screen, how many pixels will it take up? 61 | int xFactor = (x_max - x_min) * MICROPOLYGONS_PER_PIXEL; 62 | int yFactor = (y_max - y_min) * MICROPOLYGONS_PER_PIXEL; 63 | 64 | //choose the largest dimension 65 | diceFactor = max(xFactor, yFactor); 66 | //can't be higher than screen resolution*MICROPOLYGONS_PER_PIXEL 67 | diceFactor = min(diceFactor, max(frameWidth, frameHeight) * MICROPOLYGONS_PER_PIXEL * 2); 68 | 69 | return true; 70 | } 71 | 72 | Mesh* Dice(int xFactor, int yFactor) { 73 | Mesh* mesh = new Mesh(xFactor, yFactor); 74 | for (int u = 0; u < mesh->width; u++) { 75 | for (int v = 0; v < mesh->height; v++) { 76 | //normalized u, v which runs from 0 to 1 77 | float u_n = (float)u / (mesh->width - 1); 78 | float v_n = (float)v / (mesh->height - 1); 79 | 80 | //get position and normal through overridden methods per each type of primitive 81 | getPositionAndNormal(u_n, v_n, mesh->getGridPtr(u, v)->position, mesh->getGridPtr(u, v)->normal); 82 | 83 | //set to draw color(set by RiColor) to begin 84 | mesh->getGridPtr(u, v)->color[0] = Ri_drawColor[0]; 85 | mesh->getGridPtr(u, v)->color[1] = Ri_drawColor[1]; 86 | mesh->getGridPtr(u, v)->color[2] = Ri_drawColor[2]; 87 | //set opacity 88 | mesh->getGridPtr(u, v)->opacity[0] = Ri_drawOpacity[0]; 89 | mesh->getGridPtr(u, v)->opacity[1] = Ri_drawOpacity[1]; 90 | mesh->getGridPtr(u, v)->opacity[2] = Ri_drawOpacity[2]; 91 | } 92 | } 93 | return mesh; 94 | } 95 | }; 96 | 97 | class Sphere : public Primitive { 98 | protected: 99 | //intial parameters 100 | float radius; 101 | //calculated parameters for dicing 102 | float phiMin, phiMax, thetaMax; 103 | 104 | virtual void getPositionAndNormal(float u, float v, Vector4& position, Vector4& normal) { 105 | float phi = phiMin + v * (phiMax - phiMin); 106 | float theta = u * thetaMax; 107 | 108 | position.x = radius * cos(theta) * cos(phi); 109 | position.y = radius * sin(theta) * cos(phi); 110 | position.z = radius * sin(phi); 111 | position.w = 1.0f; 112 | 113 | normal = position.normalize(); 114 | } 115 | 116 | virtual void getBounds(Vector4& bbMin, Vector4& bbMax) { 117 | bbMin = Vector4(-radius, -radius, -radius); 118 | bbMax = Vector4(radius, radius, radius); 119 | } 120 | 121 | public: 122 | Sphere(float radius, float zmin, float zmax, float tmax) { 123 | this->radius = radius; 124 | 125 | //calculate necessary parameters (in radians) 126 | this->phiMin = (zmin > -radius) ? asin(zmin / radius) : -M_PI_2; 127 | this->phiMax = (zmax < radius) ? asin(zmax / radius) : M_PI_2; 128 | this->thetaMax = tmax * M_PI / 180.0f; 129 | } 130 | }; 131 | 132 | class Cone : public Primitive { 133 | protected: 134 | //intial parameters 135 | float height, radius; 136 | //calculated parameters for dicing 137 | float thetaMax; 138 | 139 | virtual void getPositionAndNormal(float u, float v, Vector4& position, Vector4& normal) { 140 | float theta = u * thetaMax; 141 | 142 | position.x = radius * (1 - v) * cos(theta); 143 | position.y = radius * (1 - v) * sin(theta); 144 | position.z = v * height; 145 | position.w = 1.0f; 146 | 147 | //vector from center to position 148 | Vector4 V = Vector4(position.x, position.y, 0).normalize(); 149 | normal.x = V.x * height / radius; 150 | normal.y = V.y * height / radius; 151 | normal.z = radius / height; 152 | normal.w = 1.0f; 153 | normal = normal.normalize(); 154 | } 155 | 156 | virtual void getBounds(Vector4& bbMin, Vector4& bbMax) { 157 | bbMin = Vector4(-radius, -radius, 0); 158 | bbMax = Vector4(radius, radius, height); 159 | } 160 | 161 | public: 162 | Cone(float height, float radius, float tmax) { 163 | this->radius = radius; 164 | this->height = height; 165 | 166 | //calculate necessary parameters (in radians) 167 | this->thetaMax = tmax * M_PI / 180.0f; 168 | } 169 | }; 170 | 171 | class Cylinder : public Primitive { 172 | protected: 173 | //intial parameters 174 | float radius, zmin, zmax; 175 | //calculated parameters for dicing 176 | float thetaMax; 177 | 178 | virtual void getPositionAndNormal(float u, float v, Vector4& position, Vector4& normal) { 179 | float theta = u * thetaMax; 180 | 181 | position.x = radius * cos(theta); 182 | position.y = radius * sin(theta); 183 | position.z = zmin + v * (zmax - zmin); 184 | position.w = 1.0f; 185 | 186 | normal = Vector4(position.x, position.y, 0).normalize(); 187 | } 188 | 189 | virtual void getBounds(Vector4& bbMin, Vector4& bbMax) { 190 | bbMin = Vector4(-radius, -radius, zmin); 191 | bbMax = Vector4(radius, radius, zmax); 192 | } 193 | 194 | public: 195 | Cylinder(float radius, float zmin, float zmax, float tmax) { 196 | this->radius = radius; 197 | this->zmax = zmax; 198 | this->zmin = zmin; 199 | 200 | //calculate necessary parameters (in radians) 201 | this->thetaMax = tmax * M_PI / 180.0f; 202 | } 203 | }; 204 | 205 | class Torus : public Primitive { 206 | protected: 207 | //intial parameters 208 | float majorradius, minorradius; 209 | //calculated parameters for dicing 210 | float phiMin, phiMax, thetaMax; 211 | 212 | virtual void getPositionAndNormal(float u, float v, Vector4& position, Vector4& normal) { 213 | float phi = phiMin + v * (phiMax - phiMin); 214 | float theta = u * thetaMax; 215 | float r = minorradius * cos(phi); 216 | 217 | position.x = (majorradius + r) * cos(theta); 218 | position.y = (majorradius + r) * sin(theta); 219 | position.z = minorradius * sin(phi); 220 | position.w = 1.0f; 221 | 222 | normal = (position - Vector4(majorradius*cos(theta), majorradius*sin(theta), 0)).normalize(); 223 | } 224 | 225 | virtual void getBounds(Vector4& bbMin, Vector4& bbMax) { 226 | bbMin = Vector4(-(majorradius+minorradius), -(majorradius + minorradius), -minorradius); 227 | bbMax = Vector4((majorradius + minorradius), (majorradius + minorradius), minorradius); 228 | } 229 | 230 | public: 231 | Torus(float majorradius, float minorradius, float pmin, float pmax, float tmax) { 232 | this->majorradius = majorradius; 233 | this->minorradius = minorradius; 234 | 235 | //calculate necessary parameters (in radians) 236 | this->phiMin = pmin * M_PI / 180.0f; 237 | this->phiMax = pmax * M_PI / 180.0f; 238 | this->thetaMax = tmax * M_PI / 180.0f; 239 | } 240 | }; -------------------------------------------------------------------------------- /Reyes/Reyes.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {350C43BF-B073-418C-B4EC-69D1AA3B8218} 23 | Reyes 24 | 8.1 25 | 26 | 27 | 28 | Application 29 | true 30 | v140 31 | MultiByte 32 | 33 | 34 | Application 35 | false 36 | v140 37 | true 38 | MultiByte 39 | 40 | 41 | Application 42 | true 43 | v140 44 | MultiByte 45 | 46 | 47 | Application 48 | false 49 | v140 50 | true 51 | MultiByte 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | Level3 75 | Disabled 76 | true 77 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 78 | 79 | 80 | 81 | 82 | Level3 83 | Disabled 84 | true 85 | 86 | 87 | 88 | 89 | Level3 90 | MaxSpeed 91 | true 92 | true 93 | true 94 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 95 | 96 | 97 | true 98 | true 99 | 100 | 101 | 102 | 103 | Level3 104 | MaxSpeed 105 | true 106 | true 107 | true 108 | _CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) 109 | 110 | 111 | true 112 | true 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /Reyes/Reyes.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | 38 | 39 | Header Files 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | Header Files 58 | 59 | 60 | Header Files 61 | 62 | 63 | Header Files 64 | 65 | 66 | Header Files 67 | 68 | 69 | Header Files 70 | 71 | 72 | -------------------------------------------------------------------------------- /Reyes/Ri.cpp: -------------------------------------------------------------------------------- 1 | #include "Ri.h" 2 | #include "Primitive.h" 3 | #include "FrameBuffer.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #define STB_IMAGE_IMPLEMENTATION 9 | #include "stb_image.h" 10 | 11 | RtToken RI_PERSPECTIVE = "perspective"; 12 | RtToken RI_ORTHOGRAPHIC = "orthgraphic"; 13 | 14 | // Global state 15 | //Frame 16 | int frameWidth = 0; 17 | int frameHeight = 0; 18 | int samplesWidth = 0; 19 | int samplesHeight = 0; 20 | float aspectRatio = 0; 21 | std::string outputFilename; 22 | FrameBuffer* frameBuffer = NULL; 23 | 24 | //Transformations 25 | Matrix4 modelView; 26 | Matrix4 projection; 27 | std::stack transformationStack; 28 | 29 | //Motion blur 30 | float Ri_timeStart = 0.0f; 31 | float Ri_timeStop = 1.0f; 32 | Vector4 movementVector; 33 | 34 | //Primitive creation 35 | RtColor Ri_drawColor; 36 | RtColor Ri_drawOpacity; 37 | //Background 38 | RtColor Ri_backgroundColor; 39 | 40 | //Shaders 41 | void(*Ri_shaderSurfaceFunction)(); 42 | void(*Ri_shaderDisplacementFunction)(); 43 | 44 | //Shader "arguments" 45 | RtPoint __my_shader_P; 46 | RtPoint __my_shader_N; 47 | RtFloat __my_shader_u; 48 | RtFloat __my_shader_v; 49 | RtFloat __my_shader_du; 50 | RtFloat __my_shader_dv; 51 | RtColor __my_shader_Ci; 52 | RtColor __my_shader_Oi; 53 | RtVector __my_shader_dPdu; 54 | RtVector __my_shader_dPdv; 55 | 56 | //Textures 57 | struct RtTexture { 58 | int width, height; 59 | unsigned char* data; 60 | }; 61 | //hashmap of textures 62 | std::unordered_map textures; 63 | 64 | // Functions to set up graphics state 65 | RtVoid RiBegin(RtToken name) { 66 | //set everything to default values 67 | frameWidth = 640; 68 | frameHeight = 480; 69 | samplesWidth = 2; 70 | samplesHeight = 2; 71 | aspectRatio = 1.0f; 72 | outputFilename = "output.bmp"; 73 | frameBuffer = NULL; 74 | 75 | modelView = Matrix4::Identity(); 76 | projection = Matrix4::Identity(); 77 | while (!transformationStack.empty()) 78 | transformationStack.pop(); 79 | 80 | Ri_timeStart = 0.0f; 81 | Ri_timeStop = 1.0f; 82 | movementVector = Vector4(0, 0, 0, 0); 83 | 84 | Ri_drawColor[0] = 1.0f; 85 | Ri_drawColor[1] = 1.0f; 86 | Ri_drawColor[2] = 1.0f; 87 | Ri_drawOpacity[0] = 1.0f; 88 | Ri_drawOpacity[1] = 1.0f; 89 | Ri_drawOpacity[2] = 1.0f; 90 | Ri_backgroundColor[0] = 0.0f; 91 | Ri_backgroundColor[1] = 0.0f; 92 | Ri_backgroundColor[2] = 0.0f; 93 | 94 | Ri_shaderSurfaceFunction = NULL; 95 | Ri_shaderDisplacementFunction = NULL; 96 | 97 | textures.clear(); 98 | } 99 | 100 | RtVoid RiEnd() { 101 | //delete framebuffer 102 | if (frameBuffer != NULL) { 103 | delete frameBuffer; 104 | frameBuffer = NULL; 105 | } 106 | //free textures 107 | for (auto it = textures.begin(); it != textures.end(); ++it) { 108 | free((*it).second.data); 109 | } 110 | } 111 | 112 | RtVoid RiFormat(RtInt xres, RtInt yres, RtFloat aspect) { 113 | frameWidth = xres; 114 | frameHeight = yres; 115 | aspectRatio = aspect; 116 | } 117 | 118 | RtVoid RiProjection(RtToken name) { 119 | if (name == RI_PERSPECTIVE) { 120 | float aspect = aspectRatio * (float)frameWidth / frameHeight; 121 | projection = Matrix4::Perspective(45.0f * M_PI / 180.0f, aspect, NEAR_PLANE, FAR_PLANE); 122 | } 123 | else if (name == RI_ORTHOGRAPHIC) { 124 | projection = Matrix4::Orthographic(-5, 5, 5, -5, NEAR_PLANE, FAR_PLANE); 125 | } 126 | } 127 | 128 | RtVoid RiProjection(RtToken name, char* arg, float* fov, ...) { 129 | if (name == RI_PERSPECTIVE) { 130 | float aspect = aspectRatio * (float)frameWidth / frameHeight; 131 | projection = Matrix4::Perspective(*fov * M_PI / 180.0f, aspect, NEAR_PLANE, FAR_PLANE); 132 | } 133 | } 134 | 135 | 136 | RtVoid RiFrameAspectRatio(RtFloat aspect) { 137 | aspectRatio = aspect; 138 | } 139 | 140 | RtVoid RiPixelSamples(RtFloat xsamples, RtFloat ysamples) { 141 | samplesWidth = xsamples; 142 | samplesHeight = ysamples; 143 | } 144 | 145 | RtVoid RiDisplay(char * name, RtToken type, RtToken mode, ...) { 146 | outputFilename = std::string(name); 147 | } 148 | 149 | RtVoid RiFrameBegin(RtInt frame) { 150 | //if no framebuffer exists 151 | if (frameBuffer == NULL) 152 | frameBuffer = new FrameBuffer(frameWidth, frameHeight, samplesWidth, samplesHeight, Ri_timeStart, Ri_timeStop); 153 | //if a dimension has changed, remake 154 | else if (frameBuffer->GetWidth() != frameWidth || frameBuffer->GetHeight() != frameHeight || frameBuffer->GetSampleWidth() != samplesWidth || frameBuffer->GetSampleHeight() != samplesHeight) { 155 | delete frameBuffer; 156 | frameBuffer = new FrameBuffer(frameWidth, frameHeight, samplesWidth, samplesHeight, Ri_timeStart, Ri_timeStop); 157 | } 158 | //no change, just need to clear 159 | else 160 | frameBuffer->Clear(); 161 | 162 | //reset transformation stack 163 | modelView = Matrix4::Identity(); 164 | while (!transformationStack.empty()) 165 | transformationStack.pop(); 166 | 167 | movementVector = Vector4(0, 0, 0, 0); 168 | } 169 | 170 | RtVoid RiFrameEnd(void) { 171 | //save current frame 172 | printf("filtering\n"); 173 | frameBuffer->FilterAndSaveToFile(outputFilename); 174 | printf("created %s\n\n", outputFilename.c_str()); 175 | } 176 | 177 | RtVoid RiWorldBegin() { 178 | 179 | } 180 | 181 | RtVoid RiWorldEnd() { 182 | 183 | } 184 | 185 | // Transformations 186 | RtVoid RiTransformBegin() { 187 | //save current transformation on stack 188 | transformationStack.push(modelView); 189 | } 190 | 191 | RtVoid RiTransformEnd(void) { 192 | //get transformation from top of stack and overwrite current 193 | modelView = transformationStack.top(); 194 | transformationStack.pop(); 195 | } 196 | 197 | RtVoid RiIdentity() { 198 | modelView = Matrix4::Identity(); 199 | } 200 | 201 | RtVoid RiTransform(RtMatrix transform) { 202 | modelView = modelView * Matrix4(transform); 203 | } 204 | 205 | RtVoid RiPerspective(RtFloat fov) { 206 | modelView = modelView * Matrix4::Perspective(fov * M_PI / 180.0f, aspectRatio, NEAR_PLANE, FAR_PLANE); 207 | } 208 | 209 | RtVoid RiTranslate(RtFloat dx, RtFloat dy, RtFloat dz) { 210 | modelView = modelView * Matrix4::Translate(dx, dy, dz); 211 | } 212 | 213 | RtVoid RiRotate(RtFloat angle, RtFloat dx, RtFloat dy, RtFloat dz) { 214 | //which axis? 215 | /*if (dx >= 0.99f) 216 | modelView = modelView * Matrix4::RotateX(angle * M_PI / 180.0f); 217 | if (dy >= 0.99f) 218 | modelView = modelView * Matrix4::RotateY(angle * M_PI / 180.0f); 219 | if (dz >= 0.99f) 220 | modelView = modelView * Matrix4::RotateZ(angle * M_PI / 180.0f);*/ 221 | modelView = modelView * Matrix4::Rotate(angle * M_PI / 180.0f, dx, dy, dz); 222 | } 223 | 224 | RtVoid RiScale(RtFloat sx, RtFloat sy, RtFloat sz) { 225 | modelView = modelView * Matrix4::Scale(sx, sy, sz); 226 | } 227 | 228 | RtVoid RiConcatTransform(RtMatrix transform) { 229 | modelView = Matrix4(transform) * modelView; 230 | } 231 | 232 | void drawPrimitive(Primitive* primitive) { 233 | //check if in bounds and get dicing factors 234 | int diceFactor; 235 | Matrix4 mvp = projection * modelView; 236 | if (primitive->Bound(mvp, frameWidth, frameHeight, diceFactor)) { 237 | printf("mesh %d x %d\n", diceFactor, diceFactor); 238 | //dice to create mesh 239 | Mesh* mesh = primitive->Dice(diceFactor, diceFactor); 240 | //perform displacement in model space 241 | mesh->ShadeDisplacement(); 242 | //transform points/normals to eye space 243 | mesh->ApplyMatrix(modelView); 244 | //shade surfaces in eye space 245 | mesh->ShadeSurface(); 246 | //transform to "clip space" 247 | //mesh->ApplyMatrix(projection); 248 | //project and sample 249 | frameBuffer->DrawMesh(mesh, movementVector, projection); 250 | delete mesh; 251 | } 252 | } 253 | 254 | // Primitives 255 | RtVoid RiSphere(RtFloat radius, RtFloat zmin, RtFloat zmax, RtFloat tmax, ...) { 256 | Sphere primitive(radius, zmin, zmax, tmax); 257 | printf("sphere: "); 258 | drawPrimitive(&primitive); 259 | } 260 | 261 | RtVoid RiCone(RtFloat height, RtFloat radius, RtFloat tmax, ...) { 262 | Cone primitive(height, radius, tmax); 263 | printf("cone: "); 264 | drawPrimitive(&primitive); 265 | } 266 | 267 | RtVoid RiCylinder(RtFloat radius, RtFloat zmin, RtFloat zmax, RtFloat tmax, ...) { 268 | Cylinder primitive(radius, zmin, zmax, tmax); 269 | printf("cylinder: "); 270 | drawPrimitive(&primitive); 271 | } 272 | 273 | RtVoid RiTorus(RtFloat majrad, RtFloat minrad, RtFloat phimin, RtFloat phimax, RtFloat tmax, ...) { 274 | Torus primitive(majrad, minrad, phimin, phimax, tmax); 275 | printf("torus: "); 276 | drawPrimitive(&primitive); 277 | } 278 | 279 | // Shading 280 | RtVoid RiColor(RtColor color) { 281 | Ri_drawColor[0] = color[0]; 282 | Ri_drawColor[1] = color[1]; 283 | Ri_drawColor[2] = color[2]; 284 | } 285 | 286 | RtVoid RiOpacity(RtColor color) { 287 | Ri_drawOpacity[0] = color[0]; 288 | Ri_drawOpacity[1] = color[1]; 289 | Ri_drawOpacity[2] = color[2]; 290 | } 291 | 292 | RtVoid RiBackgroundColor(RtColor color) { 293 | Ri_backgroundColor[0] = color[0]; 294 | Ri_backgroundColor[1] = color[1]; 295 | Ri_backgroundColor[2] = color[2]; 296 | } 297 | 298 | RtVoid RiMakeTexture(const char* file, int unit) { 299 | RtTexture tex; 300 | int n; 301 | tex.data = stbi_load(file, &tex.width, &tex.height, &n, 3); 302 | if (tex.data == NULL) { 303 | printf("error loading \"%s\"\n", file); 304 | return; 305 | } 306 | 307 | //insert into hashmap 308 | textures[unit] = tex; 309 | } 310 | 311 | RtVoid RiSurface(void(*shaderFunc)(void)) { 312 | Ri_shaderSurfaceFunction = shaderFunc; 313 | } 314 | 315 | RtVoid RiDisplacement(void(*shaderFunc)(void)) { 316 | Ri_shaderDisplacementFunction = shaderFunc; 317 | } 318 | 319 | RtVoid RiShutter(RtFloat min, RtFloat max) { 320 | Ri_timeStart = min; 321 | Ri_timeStop = max; 322 | } 323 | 324 | RtVoid RiMotionBlur(float dx, float dy, float dz) { 325 | movementVector.x = dx; 326 | movementVector.y = dy; 327 | movementVector.z = dz; 328 | movementVector.w = 0; 329 | } 330 | 331 | float TEXTURE_TILE_X = 1.0f; 332 | float TEXTURE_TILE_Y = 1.0f; 333 | void texture(int unit) { 334 | //texture doesn't exist? 335 | if (textures.find(unit) == textures.end()) 336 | return; 337 | RtTexture tex = textures[unit]; 338 | 339 | //look up pixel 340 | int pixelX = (int)(__my_shader_u * TEXTURE_TILE_X * (tex.width - 1)); 341 | int pixelY = (int)(__my_shader_v * TEXTURE_TILE_Y * (tex.height - 1)); 342 | 343 | //tile 344 | pixelX = pixelX % tex.width; 345 | pixelY = pixelY % tex.height; 346 | 347 | __my_shader_Ci[0] = tex.data[(pixelY * tex.width + pixelX) * 3 + 0] / 255.0f; 348 | __my_shader_Ci[1] = tex.data[(pixelY * tex.width + pixelX) * 3 + 1] / 255.0f; 349 | __my_shader_Ci[2] = tex.data[(pixelY * tex.width + pixelX) * 3 + 2] / 255.0f; 350 | } -------------------------------------------------------------------------------- /Reyes/Ri.h: -------------------------------------------------------------------------------- 1 | #ifndef RI_H 2 | #define RI_H 3 | /* 4 | * RenderMan Interface Standard Include File 5 | * (for ANSI Standard C) 6 | */ 7 | /* Definitions of Abstract Types used in RI */ 8 | 9 | typedef short RtBoolean; 10 | typedef int RtInt; 11 | typedef float RtFloat; 12 | typedef char *RtToken; 13 | typedef RtFloat RtColor[3]; 14 | typedef RtFloat RtPoint[3]; 15 | typedef RtFloat RtVector[3]; 16 | typedef RtFloat RtNormal[3]; 17 | typedef RtFloat RtHpoint[4]; 18 | typedef RtFloat RtMatrix[4][4]; 19 | typedef RtFloat RtBasis[4][4]; 20 | typedef RtFloat RtBound[6]; 21 | typedef char *RtString; 22 | typedef void *RtPointer; 23 | #define RtVoid void 24 | typedef RtFloat(*RtFilterFunc)(RtFloat, RtFloat, RtFloat, RtFloat); 25 | typedef RtVoid(*RtErrorHandler)(RtInt, RtInt, char *); 26 | typedef RtVoid(*RtProcSubdivFunc)(RtPointer, RtFloat); 27 | typedef RtVoid(*RtProcFreeFunc)(RtPointer); 28 | typedef RtVoid(*RtArchiveCallback)(RtToken, char *, ...); 29 | typedef RtPointer RtObjectHandle; 30 | typedef RtPointer RtLightHandle; 31 | typedef RtPointer RtContextHandle; 32 | /* Extern Declarations for Predefined RI Data Structures */ 33 | #define RI_FALSE 0 34 | #define RI_TRUE (! RI_FALSE) 35 | #define RI_INFINITY 1.0e38 36 | #define RI_EPSILON 1.0e-10 37 | #define RI_NULL ((RtToken)0) 38 | extern RtToken RI_FRAMEBUFFER, RI_FILE; 39 | extern RtToken RI_RGB, RI_RGBA, RI_RGBZ, RI_RGBAZ, RI_A, RI_Z, RI_AZ; 40 | extern RtToken RI_PERSPECTIVE, RI_ORTHOGRAPHIC; 41 | extern RtToken RI_HIDDEN, RI_PAINT; 42 | extern RtToken RI_CONSTANT, RI_SMOOTH; 43 | extern RtToken RI_FLATNESS, RI_FOV; 44 | extern RtToken RI_AMBIENTLIGHT, RI_POINTLIGHT, RI_DISTANTLIGHT, 45 | RI_SPOTLIGHT; 46 | extern RtToken RI_INTENSITY, RI_LIGHTCOLOR, RI_FROM, RI_TO, RI_CONEANGLE, 47 | RI_CONEDELTAANGLE, RI_BEAMDISTRIBUTION; 48 | extern RtToken RI_MATTE, RI_METAL, RI_SHINYMETAL, 49 | RI_PLASTIC, RI_PAINTEDPLASTIC; 50 | extern RtToken RI_KA, RI_KD, RI_KS, RI_ROUGHNESS, RI_KR, 51 | RI_TEXTURENAME, RI_SPECULARCOLOR; 52 | extern RtToken RI_DEPTHCUE, RI_FOG, RI_BUMPY; 53 | extern RtToken RI_MINDISTANCE, RI_MAXDISTANCE, RI_BACKGROUND, 54 | RI_DISTANCE, RI_AMPLITUDE; 55 | extern RtToken RI_RASTER, RI_SCREEN, RI_CAMERA, RI_WORLD, RI_OBJECT; 56 | extern RtToken RI_INSIDE, RI_OUTSIDE, RI_LH, RI_RH; 57 | extern RtToken RI_P, RI_PZ, RI_PW, RI_N, RI_NP, 58 | RI_CS, RI_OS, RI_S, RI_T, RI_ST; 59 | extern RtToken RI_BILINEAR, RI_BICUBIC; 60 | extern RtToken RI_LINEAR, RI_CUBIC; 61 | extern RtToken RI_PRIMITIVE, RI_INTERSECTION, RI_UNION, RI_DIFFERENCE; 62 | extern RtToken RI_PERIODIC, RI_NONPERIODIC, RI_CLAMP, RI_BLACK; 63 | extern RtToken RI_IGNORE, RI_PRINT, RI_ABORT, RI_HANDLER; 64 | extern RtToken RI_COMMENT, RI_STRUCTURE, RI_VERBATIM; 65 | extern RtToken RI_IDENTIFIER, RI_NAME, RI_SHADINGGROUP; 66 | extern RtToken RI_WIDTH, RI_CONSTANTWIDTH; 67 | extern RtBasis RiBezierBasis, RiBSplineBasis, RiCatmullRomBasis, 68 | RiHermiteBasis, RiPowerBasis; 69 | #define RI_BEZIERSTEP ((RtInt)3) 70 | #define RI_BSPLINESTEP ((RtInt)1) 71 | #define RI_CATMULLROMSTEP ((RtInt)1) 72 | #define RI_HERMITESTEP ((RtInt)2) 73 | #define RI_POWERSTEP ((RtInt)4) 74 | extern RtInt RiLastError; 75 | /* Declarations of All the RenderMan Interface Subroutines */ 76 | extern RtFloat RiGaussianFilter(RtFloat x, RtFloat y, 77 | RtFloat xwidth, RtFloat ywidth); 78 | extern RtFloat RiBoxFilter(RtFloat x, RtFloat y, 79 | RtFloat xwidth, RtFloat ywidth); 80 | extern RtFloat RiTriangleFilter(RtFloat x, RtFloat y, 81 | RtFloat xwidth, RtFloat ywidth); 82 | extern RtFloat RiCatmullRomFilter(RtFloat x, RtFloat y, 83 | RtFloat xwidth, RtFloat ywidth); 84 | extern RtFloat RiSincFilter(RtFloat x, RtFloat y, 85 | RtFloat xwidth, RtFloat ywidth); 86 | extern RtVoid RiErrorIgnore(RtInt code, RtInt severity, char *msg); 87 | extern RtVoid RiErrorPrint(RtInt code, RtInt severity, char *msg); 88 | extern RtVoid RiErrorAbort(RtInt code, RtInt severity, char *msg); 89 | extern RtVoid RiProcDelayedReadArchive(RtPointer data, RtFloat detail); 90 | extern RtVoid RiProcRunProgram(RtPointer data, RtFloat detail); 91 | extern RtVoid RiProcDynamicLoad(RtPointer data, RtFloat detail); 92 | extern RtContextHandle RiGetContext(void); 93 | extern RtVoid RiContext(RtContextHandle); 94 | extern RtToken 95 | RiDeclare(char *name, char *declaration); 96 | extern RtVoid 97 | RiBegin(RtToken name), 98 | RiEnd(void), 99 | RiFrameBegin(RtInt frame), 100 | RiFrameEnd(void), 101 | RiWorldBegin(void), 102 | RiWorldEnd(void); 103 | extern RtVoid 104 | RiFormat(RtInt xres, RtInt yres, RtFloat aspect), 105 | RiFrameAspectRatio(RtFloat aspect), 106 | RiScreenWindow(RtFloat left, RtFloat right, RtFloat bot, RtFloat top), 107 | RiCropWindow(RtFloat xmin, RtFloat xmax, RtFloat ymin, RtFloat ymax), 108 | RiProjection(RtToken name), //MODIFIED 109 | RiProjection(RtToken name, char* arg, float* fov, ...), //ADDED 110 | RiProjectionV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]), 111 | RiClipping(RtFloat hither, RtFloat yon), 112 | RiClippingPlane(RtFloat x, RtFloat y, RtFloat z, 113 | RtFloat nx, RtFloat ny, RtFloat nz), 114 | RiShutter(RtFloat min, RtFloat max); 115 | extern RtVoid 116 | RiPixelVariance(RtFloat variation), 117 | RiPixelSamples(RtFloat xsamples, RtFloat ysamples), 118 | RiPixelFilter(RtFilterFunc filterfunc, RtFloat xwidth, RtFloat ywidth), 119 | RiExposure(RtFloat gain, RtFloat gamma), 120 | RiImager(RtToken name, ...), 121 | RiImagerV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]), 122 | RiQuantize(RtToken type, RtInt one, RtInt min, RtInt max, RtFloat ampl), 123 | RiDisplay(char *name, RtToken type, RtToken mode, ...), 124 | RiDisplayV(char *name, RtToken type, RtToken mode, 125 | RtInt n, RtToken tokens[], RtPointer parms[]); 126 | extern RtVoid 127 | RiHider(RtToken type, ...), 128 | RiHiderV(RtToken type, RtInt n, RtToken tokens[], RtPointer parms[]), 129 | RiColorSamples(RtInt n, RtFloat nRGB[], RtFloat RGBn[]), 130 | RiRelativeDetail(RtFloat relativedetail), 131 | RiOption(RtToken name, ...), 132 | RiOptionV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]); 133 | extern RtVoid 134 | RiAttributeBegin(void), 135 | RiAttributeEnd(void), 136 | RiColor(RtColor color), 137 | RiOpacity(RtColor color), 138 | RiTextureCoordinates(RtFloat s1, RtFloat t1, RtFloat s2, RtFloat t2, 139 | RtFloat s3, RtFloat t3, RtFloat s4, RtFloat t4); 140 | extern RtLightHandle 141 | RiLightSource(RtToken name, ...), 142 | RiLightSourceV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]), 143 | RiAreaLightSource(RtToken name, ...), 144 | RiAreaLightSourceV(RtToken name, 145 | RtInt n, RtToken tokens[], RtPointer parms[]); 146 | extern RtVoid 147 | RiIlluminate(RtLightHandle light, RtBoolean onoff), 148 | //RiSurface(RtToken name, ...), 149 | RiBackgroundColor(RtColor color), //ADDED 150 | RiSurface(void (*shaderFunc)(void)), //MODIFIED 151 | RiSurfaceV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]), 152 | RiAtmosphere(RtToken name, ...), 153 | RiAtmosphereV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]), 154 | RiInterior(RtToken name, ...), 155 | RiInteriorV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]), 156 | RiExterior(RtToken name, ...), 157 | RiExteriorV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]), 158 | RiShadingRate(RtFloat size), 159 | RiShadingInterpolation(RtToken type), 160 | RiMatte(RtBoolean onoff); 161 | extern RtVoid 162 | RiBound(RtBound bound), 163 | RiDetail(RtBound bound), 164 | RiDetailRange(RtFloat minvis, RtFloat lowtran, RtFloat uptran, RtFloat maxvis), 165 | RiGeometricApproximation(RtToken type, RtFloat value), 166 | RiOrientation(RtToken orientation), 167 | RiReverseOrientation(void), 168 | RiSides(RtInt sides); 169 | extern RtVoid 170 | RiIdentity(void), 171 | RiTransform(RtMatrix transform), 172 | RiConcatTransform(RtMatrix transform), 173 | RiPerspective(RtFloat fov), 174 | RiTranslate(RtFloat dx, RtFloat dy, RtFloat dz), 175 | RiRotate(RtFloat angle, RtFloat dx, RtFloat dy, RtFloat dz), 176 | RiScale(RtFloat sx, RtFloat sy, RtFloat sz), 177 | RiSkew(RtFloat angle, RtFloat dx1, RtFloat dy1, RtFloat dz1, RtFloat dx2, RtFloat dy2, RtFloat dz2), 178 | RiDeformation(RtToken name, ...), 179 | RiDeformationV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]), 180 | //RiDisplacement(RtToken name, ...), 181 | RiDisplacement(void(*shaderFunc)(void)), //MODIFIED 182 | RiDisplacementV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]), 183 | RiCoordinateSystem(RtToken space), 184 | RiCoordSysTransform(RtToken space); 185 | extern RtPoint * 186 | RiTransformPoints(RtToken fromspace, RtToken tospace, RtInt n, RtPoint points[]); 187 | extern RtVoid 188 | RiTransformBegin(void), 189 | RiTransformEnd(void); 190 | extern RtVoid 191 | RiAttribute(RtToken name, ...), 192 | RiAttributeV(RtToken name, RtInt n, RtToken tokens[], RtPointer parms[]); 193 | extern RtVoid 194 | RiPolygon(RtInt nverts, ...), 195 | RiPolygonV(RtInt nverts, RtInt n, RtToken tokens[], RtPointer parms[]), 196 | RiGeneralPolygon(RtInt nloops, RtInt nverts[], ...), 197 | RiGeneralPolygonV(RtInt nloops, RtInt nverts[], 198 | RtInt n, RtToken tokens[], RtPointer parms[]), 199 | RiPointsPolygons(RtInt npolys, RtInt nverts[], RtInt verts[], ...), 200 | RiPointsPolygonsV(RtInt npolys, RtInt nverts[], RtInt verts[], 201 | RtInt n, RtToken tokens[], RtPointer parms[]), 202 | RiPointsGeneralPolygons(RtInt npolys, RtInt nloops[], RtInt nverts[], 203 | RtInt verts[], ...), 204 | RiPointsGeneralPolygonsV(RtInt npolys, RtInt nloops[], RtInt nverts[], 205 | RtInt verts[], RtInt n, RtToken tokens[], RtPointer parms[]), 206 | RiBasis(RtBasis ubasis, RtInt ustep, RtBasis vbasis, RtInt vstep), 207 | RiPatch(RtToken type, ...), 208 | RiPatchV(RtToken type, RtInt n, RtToken tokens[], RtPointer parms[]), 209 | RiPatchMesh(RtToken type, RtInt nu, RtToken uwrap, 210 | RtInt nv, RtToken vwrap, ...), 211 | RiPatchMeshV(RtToken type, RtInt nu, RtToken uwrap, 212 | RtInt nv, RtToken vwrap, RtInt n, RtToken tokens[], RtPointer parms[]), 213 | RiNuPatch(RtInt nu, RtInt uorder, RtFloat uknot[], RtFloat umin, 214 | RtFloat umax, RtInt nv, RtInt vorder, RtFloat vknot[], 215 | RtFloat vmin, RtFloat vmax, ...), 216 | RiNuPatchV(RtInt nu, RtInt uorder, RtFloat uknot[], RtFloat umin, 217 | RtFloat umax, RtInt nv, RtInt vorder, RtFloat vknot[], 218 | RtFloat vmin, RtFloat vmax, RtInt n, RtToken tokens[], RtPointer parms[]), 219 | RiTrimCurve(RtInt nloops, RtInt ncurves[], RtInt order[], 220 | RtFloat knot[], RtFloat min[], RtFloat max[], RtInt n[], 221 | RtFloat u[], RtFloat v[], RtFloat w[]); 222 | extern RtVoid 223 | RiSphere(RtFloat radius, RtFloat zmin, RtFloat zmax, RtFloat tmax, ...), 224 | RiSphereV(RtFloat radius, RtFloat zmin, RtFloat zmax, RtFloat tmax, 225 | RtInt n, RtToken tokens[], RtPointer parms[]), 226 | RiCone(RtFloat height, RtFloat radius, RtFloat tmax, ...), 227 | RiConeV(RtFloat height, RtFloat radius, RtFloat tmax, 228 | RtInt n, RtToken tokens[], RtPointer parms[]), 229 | RiCylinder(RtFloat radius, RtFloat zmin, RtFloat zmax, RtFloat tmax, ...), 230 | RiCylinderV(RtFloat radius, RtFloat zmin, RtFloat zmax, RtFloat tmax, 231 | RtInt n, RtToken tokens[], RtPointer parms[]), 232 | RiHyperboloid(RtPoint point1, RtPoint point2, RtFloat tmax, ...), 233 | RiHyperboloidV(RtPoint point1, RtPoint point2, RtFloat tmax, 234 | RtInt n, RtToken tokens[], RtPointer parms[]), 235 | RiParaboloid(RtFloat rmax, RtFloat zmin, RtFloat zmax, RtFloat tmax, ...), 236 | RiParaboloidV(RtFloat rmax, RtFloat zmin, RtFloat zmax, RtFloat tmax, 237 | RtInt n, RtToken tokens[], RtPointer parms[]), 238 | RiDisk(RtFloat height, RtFloat radius, RtFloat tmax, ...), 239 | RiDiskV(RtFloat height, RtFloat radius, RtFloat tmax, 240 | RtInt n, RtToken tokens[], RtPointer parms[]), 241 | RiTorus(RtFloat majrad, RtFloat minrad, RtFloat phimin, 242 | RtFloat phimax, RtFloat tmax, ...), 243 | RiTorusV(RtFloat majrad, RtFloat minrad, 244 | RtFloat phimin, RtFloat phimax, RtFloat tmax, 245 | RtInt n, RtToken tokens[], RtPointer parms[]); 246 | extern RtVoid RiBlobby(RtInt nleaf, RtInt ncode, RtInt code[], 247 | RtInt nflt, RtFloat flt[], 248 | RtInt nstr, RtToken str[], ...); 249 | extern RtVoid RiBlobbyV(RtInt nleaf, RtInt ncode, RtInt code[], 250 | RtInt nflt, RtFloat flt[], 251 | RtInt nstr, RtToken str[], 252 | RtInt n, RtToken tokens[], RtPointer parms[]); 253 | extern RtVoid 254 | RiCurves(RtToken type, RtInt ncurves, 255 | RtInt nvertices[], RtToken wrap, ...), 256 | RiCurvesV(RtToken type, RtInt ncurves, RtInt nvertices[], RtToken wrap, 257 | RtInt n, RtToken tokens[], RtPointer parms[]), 258 | RiPoints(RtInt nverts, ...), 259 | RiPointsV(RtInt nverts, RtInt n, RtToken tokens[], RtPointer parms[]), 260 | RiSubdivisionMesh(RtToken mask, RtInt nf, RtInt nverts[], 261 | RtInt verts[], 262 | RtInt ntags, RtToken tags[], RtInt numargs[], 263 | RtInt intargs[], RtFloat floatargs[], ...), 264 | RiSubdivisionMeshV(RtToken mask, RtInt nf, RtInt nverts[], 265 | RtInt verts[], RtInt ntags, RtToken tags[], 266 | RtInt nargs[], RtInt intargs[], 267 | RtFloat floatargs[], RtInt n, 268 | RtToken tokens[], RtPointer *parms); 269 | extern RtVoid 270 | RiProcedural(RtPointer data, RtBound bound, 271 | RtVoid(*subdivfunc)(RtPointer, RtFloat), 272 | RtVoid(*freefunc)(RtPointer)), 273 | RiGeometry(RtToken type, ...), 274 | RiGeometryV(RtToken type, RtInt n, RtToken tokens[], RtPointer parms[]); 275 | extern RtVoid 276 | RiSolidBegin(RtToken operation), 277 | RiSolidEnd(void); 278 | extern RtObjectHandle 279 | RiObjectBegin(void); 280 | extern RtVoid 281 | RiObjectEnd(void), 282 | RiObjectInstance(RtObjectHandle handle), 283 | RiMotionBegin(RtInt n, ...), 284 | RiMotionBeginV(RtInt n, RtFloat times[]), 285 | RiMotionEnd(void); 286 | RtVoid RiMotionBlur(float dx, float dy, float dz); // ADDED 287 | extern RtVoid 288 | RiMakeTexture(const char* file, int unit), //ADDED 289 | //RiMakeTexture(char *pic, char *tex, RtToken swrap, RtToken twrap, //MODIFIED 290 | //RtFilterFunc filterfunc, RtFloat swidth, RtFloat twidth, ...), 291 | /*RiMakeTextureV(char *pic, char *tex, RtToken swrap, RtToken twrap, //MODIFIED 292 | RtFilterFunc filterfunc, RtFloat swidth, RtFloat twidth, 293 | RtInt n, RtToken tokens[], RtPointer parms[]),*/ 294 | RiMakeBump(char *pic, char *tex, RtToken swrap, RtToken twrap, 295 | RtFilterFunc filterfunc, RtFloat swidth, RtFloat twidth, ...), 296 | RiMakeBumpV(char *pic, char *tex, RtToken swrap, RtToken twrap, 297 | RtFilterFunc filterfunc, RtFloat swidth, RtFloat twidth, 298 | RtInt n, RtToken tokens[], RtPointer parms[]), 299 | RiMakeLatLongEnvironment(char *pic, char *tex, 300 | RtFilterFunc filterfunc, 301 | RtFloat swidth, RtFloat twidth, ...), 302 | RiMakeLatLongEnvironmentV(char *pic, char *tex, 303 | RtFilterFunc filterfunc, 304 | RtFloat swidth, RtFloat twidth, 305 | RtInt n, RtToken tokens[], RtPointer parms[]), 306 | RiMakeCubeFaceEnvironment(char *px, char *nx, char *py, char *ny, 307 | char *pz, char *nz, char *tex, RtFloat fov, 308 | RtFilterFunc filterfunc, RtFloat swidth, RtFloat ywidth, ...), 309 | RiMakeCubeFaceEnvironmentV(char *px, char *nx, char *py, char *ny, 310 | char *pz, char *nz, char *tex, RtFloat fov, 311 | RtFilterFunc filterfunc, RtFloat swidth, RtFloat ywidth, 312 | RtInt n, RtToken tokens[], RtPointer parms[]), 313 | RiMakeShadow(char *pic, char *tex, ...), 314 | RiMakeShadowV(char *pic, char *tex, 315 | RtInt n, RtToken tokens[], RtPointer parms[]); 316 | extern RtVoid 317 | RiArchiveRecord(RtToken type, char *format, ...), 318 | RiReadArchive(RtToken name, RtArchiveCallback callback, ...), 319 | RiReadArchiveV(RtToken name, RtArchiveCallback callback, 320 | RtInt n, RtToken tokens[], RtPointer parms[]); 321 | extern RtVoid 322 | RiErrorHandler(RtErrorHandler handler); 323 | /* 324 | Error Codes 325 | 1 - 10 System and File Errors 326 | 11 - 20 Program Limitations 327 | 21 - 40 State Errors 328 | 41 - 60 Parameter and Protocol Errors 329 | 61 - 80 Execution Errors 330 | */ 331 | #define RIE_NOERROR ((RtInt)0) 332 | #define RIE_NOMEM ((RtInt)1) /* Out of memory */ 333 | #define RIE_SYSTEM ((RtInt)2) /* Miscellaneous system error */ 334 | #define RIE_NOFILE ((RtInt)3) /* File nonexistent */ 335 | #define RIE_BADFILE ((RtInt)4) /* Bad file format */ 336 | #define RIE_VERSION ((RtInt)5) /* File version mismatch */ 337 | #define RIE_DISKFULL ((RtInt)6) /* Target disk is full */ 338 | #define RIE_INCAPABLE ((RtInt)11) /* Optional RI feature */ 339 | #define RIE_UNIMPLEMENT ((RtInt)12) /* Unimplemented feature */ 340 | #define RIE_LIMIT ((RtInt)13) /* Arbitrary program limit */ 341 | #define RIE_BUG ((RtInt)14) /* Probably a bug in renderer */ 342 | #define RIE_NOTSTARTED ((RtInt)23) /* RiBegin not called */ 343 | #define RIE_NESTING ((RtInt)24) /* Bad begin-end nesting */ 344 | #define RIE_NOTOPTIONS ((RtInt)25) /* Invalid state for options */ 345 | #define RIE_NOTATTRIBS ((RtInt)26) /* Invalid state for attribs */ 346 | #define RIE_NOTPRIMS ((RtInt)27) /* Invalid state for primitives */ 347 | #define RIE_ILLSTATE ((RtInt)28) /* Other invalid state */ 348 | #define RIE_BADMOTION ((RtInt)29) /* Badly formed motion block */ 349 | #define RIE_BADSOLID ((RtInt)30) /* Badly formed solid block */ 350 | #define RIE_BADTOKEN ((RtInt)41) /* Invalid token for request */ 351 | #define RIE_RANGE ((RtInt)42) /* Parameter out of range */ 352 | #define RIE_CONSISTENCY ((RtInt)43) /* Parameters inconsistent */ 353 | #define RIE_BADHANDLE ((RtInt)44) /* Bad object/light handle */ 354 | #define RIE_NOSHADER ((RtInt)45) /* Can't load requested shader */ 355 | #define RIE_MISSINGDATA ((RtInt)46) /* Required parameters not provided */ 356 | #define RIE_SYNTAX ((RtInt)47) /* Declare type syntax error */ 357 | #define RIE_MATH ((RtInt)61) /* Zerodivide, noninvert matrix, etc. */ 358 | /* Error severity levels */ 359 | #define RIE_INFO ((RtInt)0) /* Rendering stats and other info */ 360 | #define RIE_WARNING ((RtInt)1) /* Something seems wrong, maybe okay */ 361 | #define RIE_ERROR ((RtInt)2) /* Problem. Results may be wrong */ 362 | #define RIE_SEVERE ((RtInt)3) /* So bad you should probably abort */ 363 | #endif -------------------------------------------------------------------------------- /Reyes/SampleScene.cpp: -------------------------------------------------------------------------------- 1 | // Scenes cpp file 2 | 3 | #include "Shader.h" 4 | #include 5 | #include 6 | 7 | /********************************************/ 8 | /********************************************/ 9 | // Texture lookup 10 | void TextureMap0() 11 | { 12 | texture(0); 13 | } 14 | 15 | /********************************************/ 16 | /********************************************/ 17 | void TransparencyTest() 18 | { 19 | RiBegin(RI_NULL); 20 | //RiFormat(960, 720, 1.0); 21 | RiFormat(400, 300, 1.0); 22 | //RiFormat(200, 150, 1.0); 23 | RiDisplay("TransparencyTest.png", "", ""); 24 | RiPixelSamples(2, 2); 25 | 26 | RiFrameBegin(0); 27 | /* set the perspective transformation */ 28 | float fov = 45.0; 29 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 30 | //RiProjection(RI_ORTHOGRAPHIC); 31 | 32 | RiWorldBegin(); 33 | RiTransformBegin(); 34 | RtColor color = { 1,0,0 }; 35 | RtColor opacity = { .4,.4,.4 }; 36 | RiOpacity(opacity); 37 | RiColor(color); 38 | RiTranslate(0, 0.5, 7.0); 39 | RiRotate(60, 1, 0, 0); 40 | RiTorus(1, .25, 0, 250, 270); 41 | RiTransformEnd(); 42 | RiTransformBegin(); 43 | color[0] = 0; color[1] = 1; 44 | opacity[0] = 0.4; opacity[1] = 0.4; opacity[2] = 0.4; 45 | RiOpacity(opacity); 46 | RiColor(color); 47 | RiTranslate(0, 0, 8.0); 48 | RiRotate(60, 1, 0, 0); 49 | RiRotate(30, 0, 1, 0); 50 | RiCylinder(1, -1, 1, 300); 51 | RiTransformEnd(); 52 | RiTransformBegin(); 53 | color[1] = 0; color[2] = 1; 54 | opacity[0] = .7; opacity[1] = .7; opacity[2] = .7; 55 | RiOpacity(opacity); 56 | RiColor(color); 57 | RiTranslate(0, 1, 9.0); 58 | RiRotate(60, 1, 0, 0); 59 | RiSphere(1.8, -1.0, 1.0, 250); 60 | RiTransformEnd(); 61 | RiTransformBegin(); 62 | color[0] = 1; color[1] = .6; color[2] = .6; 63 | RiColor(color); 64 | opacity[0] = .6; opacity[1] = .6; opacity[2] = .6; 65 | RiOpacity(opacity); 66 | RiTranslate(0, -1, 8.5); 67 | RiRotate(-160, 1, 0, 0); 68 | RiRotate(30, 0, 1, 0); 69 | RiRotate(140, 0, 0, 1); 70 | RiCone(2.5, 1, 270); 71 | RiTransformEnd(); 72 | RiWorldEnd(); 73 | 74 | RiFrameEnd(); 75 | 76 | RiEnd(); 77 | } 78 | 79 | /********************************************/ 80 | /********************************************/ 81 | void ShaderTest() 82 | { 83 | RiBegin(RI_NULL); 84 | //RiFormat(960, 720, 1.0); 85 | RiFormat(400, 300, 1.0); 86 | //RiFormat(200, 150, 1.0); 87 | RiDisplay("ShaderTest.png", "", ""); 88 | RiPixelSamples(4, 4); 89 | 90 | RiFrameBegin(0); 91 | /* set the perspective transformation */ 92 | float fov = 45.0; 93 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 94 | //RiProjection(RI_ORTHOGRAPHIC); 95 | 96 | RiWorldBegin(); 97 | RiTransformBegin(); 98 | RtColor color = { 1,0,0 }; 99 | RtColor opacity = { .4,.4,.4 }; 100 | RiOpacity(opacity); 101 | RiColor(color); 102 | CHECK_SIZE_X = 20; 103 | CHECK_SIZE_Y = 10; 104 | RiSurface(CHECKERBOARD); 105 | RiTranslate(0, 0.5, 11); 106 | RiRotate(70, 0, 1, 0); 107 | RiTorus(2.5, .5, 0, 360, 360); 108 | RiTransformEnd(); 109 | RiTransformBegin(); 110 | color[0] = 0; color[1] = 1; color[2] = 0; 111 | opacity[0] = 1; opacity[1] = 1; opacity[2] = 1; 112 | RiOpacity(opacity); 113 | RiSurface(NULL); 114 | RiColor(color); 115 | RiTranslate(3, -1.5, 11); 116 | RiRotate(90, 1, 0, 0); 117 | RiCylinder(1, -1, 1, 360); 118 | RiTransformEnd(); 119 | RiTransformBegin(); 120 | opacity[0] = 1; opacity[1] = 1; opacity[2] = 1; 121 | RiOpacity(opacity); 122 | RiMakeTexture("earth.jpg", 0); 123 | void(*earthShader)(void) = TextureMap0; 124 | RiSurface(earthShader); 125 | BUMP_AMPLITUDE = 1; 126 | BUMP_MIN_FREQ_EXP = 2; 127 | BUMP_MAX_FREQ_EXP = 6; 128 | RiDisplacement(BUMPY); 129 | RiTranslate(3, 1, 11.0); 130 | RiRotate(-40, 0, 0, 1); 131 | RiRotate(-100, 0, 1, 0); 132 | RiRotate(110, 1, 0, 0); 133 | RiSphere(1, -1.5, 1.5, 360); 134 | RiTransformEnd(); 135 | RiTransformBegin(); 136 | opacity[0] = .8; opacity[1] = .8; opacity[2] = .8; 137 | RiOpacity(opacity); 138 | RiSurface(earthShader); 139 | RiDisplacement(NULL); 140 | RiTranslate(-2.5, 1, 11.0); 141 | RiRotate(-175, 0, 1, 0); 142 | RiRotate(110, 1, 0, 0); 143 | RiSphere(1.5, -1.5, 1.5, 360); 144 | RiTransformEnd(); 145 | RiTransformBegin(); 146 | color[0] = 0.4; color[1] = 0.2; color[2] = 0; 147 | RiColor(color); 148 | opacity[0] = 1; opacity[1] = 1; opacity[2] = 1; 149 | RiOpacity(opacity); 150 | RiSurface(NULL); 151 | BUMP_AMPLITUDE = .5; 152 | BUMP_MAX_FREQ_EXP = 8; 153 | RiDisplacement(BUMPY); 154 | RiTranslate(-2.5, -2.5, 11); 155 | RiRotate(-90, 1, 0, 0); 156 | RiRotate(90, 0, 0, 1); 157 | RiCone(2.5, 1, 360); 158 | RiTransformEnd(); 159 | RiWorldEnd(); 160 | 161 | RiFrameEnd(); 162 | 163 | RiEnd(); 164 | } 165 | 166 | /********************************************/ 167 | /********************************************/ 168 | void Rocket() 169 | { 170 | RiBegin(RI_NULL); 171 | //RiFormat(960, 720, 1.0); 172 | RiFormat(400, 300, 1.0); 173 | //RiFormat(200, 150, 1.0); 174 | RiDisplay("Rocket.png", "", ""); 175 | RiPixelSamples(2, 2); 176 | 177 | RiFrameBegin(0); 178 | /* set the perspective transformation */ 179 | float fov = 45.0; 180 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 181 | //RiProjection(RI_ORTHOGRAPHIC); 182 | 183 | RiWorldBegin(); 184 | RiTransformBegin(); 185 | // water 186 | RtColor color = { 0,0,1 }; 187 | RtColor opacity = { .6,.6,.6 }; 188 | RiOpacity(opacity); 189 | RiColor(color); 190 | BUMP_AMPLITUDE = .05; 191 | BUMP_MIN_FREQ_EXP = 2; 192 | BUMP_MAX_FREQ_EXP = 6; 193 | RiDisplacement(BUMPY); 194 | RiScale(7, 1.15, 1); 195 | RiTranslate(0, -0.75, 4); 196 | RiRotate(180, 0, 1, 0); 197 | RiRotate(110, 1, 0, 0); 198 | RiTranslate(0, 0, 1); 199 | RiRotate(180, 1, 0, 0); 200 | RiSphere(1, .9, 1, 360); 201 | // mountain 202 | color[0] = 0.6; color[1] = 0.3; color[2] = 0; 203 | opacity[0] = 1; opacity[1] = 1; opacity[2] = 1; 204 | RiColor(color); 205 | RiOpacity(opacity); 206 | RiDisplacement(NULL); 207 | BUMP_AMPLITUDE = 2; 208 | BUMP_MIN_FREQ_EXP = 3; 209 | BUMP_MAX_FREQ_EXP = 9; 210 | RiDisplacement(BUMPY); 211 | RiTranslate(0, 4, -6); 212 | RiRotate(15, 1, 0, 0); 213 | RiSphere(7, 6.8, 7, 360); 214 | RiTransformEnd(); 215 | 216 | RiTransformBegin(); 217 | // rocket 218 | RiDisplacement(NULL); 219 | color[0] = .8; color[1] = 0.8; color[2] = .8; 220 | RiColor(color); 221 | RiTranslate(-.25, .25, 2); 222 | RiRotate(40, 0, 0, 1); 223 | RiScale(1, 2, 1); 224 | RiRotate(150, 0, 1, 0); 225 | RiRotate(-90, 1, 0, 0); 226 | RiSphere(.1, -.1, .1, 360); 227 | 228 | RiTranslate(0, 0, .07); 229 | RiCone(.075, .075, 360); 230 | 231 | RiSurface(NULL); 232 | BUMP_AMPLITUDE = .1; 233 | BUMP_MIN_FREQ_EXP = 5; 234 | BUMP_MAX_FREQ_EXP = 7; 235 | RiDisplacement(BUMPY); 236 | color[0] = 1; color[1] = 0.27; color[2] = 0; 237 | opacity[0] = .4; opacity[1] = .4; opacity[2] = .4; 238 | RiOpacity(opacity); 239 | RiColor(color); 240 | RiTranslate(0, 0, -.45); 241 | RiCone(.3, .1, 360); 242 | 243 | color[1] = .1; 244 | RiColor(color); 245 | opacity[0] = 1; opacity[1] = 1; opacity[2] = 1; 246 | RiOpacity(opacity); 247 | RiDisplacement(NULL); 248 | RiScale(20, .5, 1); 249 | RiTranslate(0, 0, .375); 250 | RiSphere(.025, -.025, .025, 360); 251 | 252 | RiScale(1 / 40, 16, 1); 253 | RiTranslate(0, -0.015, -.075); 254 | RiSphere(.025, -.025, .025, 360); 255 | RiTransformEnd(); 256 | RiWorldEnd(); 257 | 258 | RiFrameEnd(); 259 | 260 | RiEnd(); 261 | } 262 | 263 | /********************************************/ 264 | /********************************************/ 265 | void Tunnel() 266 | { 267 | RiBegin(RI_NULL); 268 | //RiFormat(960, 720, 1.0); 269 | RiFormat(400, 300, 1.0); 270 | RiDisplay("Tunnel.png", "", ""); 271 | RiPixelSamples(2, 2); 272 | 273 | RiFrameBegin(0); 274 | /* set the perspective transformation */ 275 | float fov = 45.0; 276 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 277 | //RiProjection(RI_ORTHOGRAPHIC); 278 | 279 | RiWorldBegin(); 280 | RiTransformBegin(); 281 | RtColor color = { 1,0,0 }; 282 | RiColor(color); 283 | RiTranslate(0, 0.5, 7.0); 284 | RiRotate(60, 1, 0, 0); 285 | RiTorus(1, .25, 0, 360, 360); 286 | RiTransformEnd(); 287 | RiTransformBegin(); 288 | color[0] = 0; color[1] = 1; 289 | RiColor(color); 290 | RiTranslate(0, 0, 8.0); 291 | RiRotate(60, 1, 0, 0); 292 | RiRotate(30, 0, 1, 0); 293 | RiCylinder(1, -1, 1, 360); 294 | RiTransformEnd(); 295 | RiTransformBegin(); 296 | color[1] = 0; color[2] = 1; 297 | RiColor(color); 298 | RiTranslate(0, 1, 9.0); 299 | RiRotate(60, 1, 0, 0); 300 | RiSphere(1.0, -1.0, 1.0, 360); 301 | RiTransformEnd(); 302 | RiTransformBegin(); 303 | color[0] = 1; color[1] = .4; color[2] = .4; 304 | RiColor(color); 305 | CHECK_SIZE_X = 40; 306 | CHECK_SIZE_Y = 40; 307 | RiSurface(CHECKERBOARD); 308 | RiTranslate(0, -1, 8.5); 309 | RiRotate(-160, 1, 0, 0); 310 | RiRotate(30, 0, 1, 0); 311 | RiCone(2, 1, 360); 312 | RiTransformEnd(); 313 | RiTransformBegin(); 314 | CHECK_SIZE_X = 40; 315 | CHECK_SIZE_Y = 40; 316 | RiTranslate(0, 0, 7.0); 317 | RiCylinder(3, 0, 10, 360); 318 | RiTransformEnd(); 319 | RiWorldEnd(); 320 | 321 | RiFrameEnd(); 322 | 323 | RiEnd(); 324 | } 325 | 326 | /********************************************/ 327 | /********************************************/ 328 | void Earth() 329 | { 330 | RiBegin(RI_NULL); 331 | //RiFormat(960, 720, 1.0); 332 | RiFormat(400, 300, 1.0); 333 | //RiFormat(200, 150, 1.0); 334 | RiDisplay("Earth.png", "", ""); 335 | RiPixelSamples(2, 2); 336 | 337 | RiFrameBegin(0); 338 | /* set the perspective transformation */ 339 | float fov = 45.0; 340 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 341 | //RiProjection(RI_ORTHOGRAPHIC); 342 | 343 | RiWorldBegin(); 344 | RiTransformBegin(); 345 | RiMakeTexture("earth.jpg", 0); 346 | void(*earthShader)(void) = TextureMap0; 347 | RiSurface(earthShader); 348 | RtColor blue = { 0, 0, 1 }; 349 | RtColor opacity = { .9, .9, .9 }; 350 | RiColor(blue); 351 | RiOpacity(opacity); 352 | BUMP_AMPLITUDE = .02; 353 | BUMP_MIN_FREQ_EXP = 14; 354 | BUMP_MAX_FREQ_EXP = 16; 355 | RiDisplacement(BUMPY); 356 | RiTranslate(0, 0, 5.0); 357 | RiRotate(-175, 0, 1, 0); 358 | RiRotate(110, 1, 0, 0); 359 | RiSphere(1, -1, 1, 360); 360 | RiTransformEnd(); 361 | RiWorldEnd(); 362 | 363 | RiFrameEnd(); 364 | 365 | RiEnd(); 366 | } 367 | 368 | /********************************************/ 369 | /********************************************/ 370 | void Tornado() 371 | { 372 | RiBegin(RI_NULL); 373 | //RiFormat(960, 720, 1.0); 374 | RiFormat(400, 300, 1.0); 375 | //RiFormat(200, 150, 1.0); 376 | RiDisplay("Tornado.png", "", ""); 377 | RiPixelSamples(2, 2); 378 | 379 | RiFrameBegin(0); 380 | /* set the perspective transformation */ 381 | float fov = 45.0; 382 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 383 | //RiProjection(RI_ORTHOGRAPHIC); 384 | 385 | RiWorldBegin(); 386 | RiTransformBegin(); 387 | RtColor gray = { .4, .4, .4 }; 388 | RtColor opacity = { 0.5, 0.5, 0.5 }; 389 | RiColor(gray); 390 | RiOpacity(opacity); 391 | BUMP_AMPLITUDE = 1; 392 | BUMP_MIN_FREQ_EXP = 3; 393 | BUMP_MAX_FREQ_EXP = 10; 394 | RiDisplacement(BUMPY); 395 | RiTranslate(0, 0, 5.0); 396 | RiRotate(90, 0, 1, 0); 397 | RiRotate(80, 1, 0, 0); 398 | RiTranslate(0, 0, -1.5); 399 | RiCone(3, 1, 360); 400 | RiTransformEnd(); 401 | RiWorldEnd(); 402 | 403 | RiFrameEnd(); 404 | 405 | RiEnd(); 406 | } 407 | 408 | /********************************************/ 409 | /********************************************/ 410 | void SampleScene1(void) { 411 | int i; 412 | int nf; 413 | float slopex, slopey, slopez; 414 | char name[50]; 415 | 416 | RtColor red = { 1,0,0 }; 417 | RtColor green = { 0,1,0 }; 418 | RtColor blue = { 0,0,1 }; 419 | RtColor white = { 1,1,1 }; 420 | 421 | 422 | RtPoint p1 = { 30,0,10 }; /* ball's initial position */ 423 | RtPoint p2 = { 0,20,10 }; /* ball's final position */ 424 | 425 | 426 | RtFloat fov = 45; 427 | RtFloat intensity1 = 0.1; 428 | RtFloat intensity2 = 1.5; 429 | RtInt init = 0, end = 1; 430 | 431 | 432 | nf = 100; /* number of frames to output */ 433 | slopex = (p2[0] - p1[0]) / nf; 434 | slopey = (p2[1] - p1[1]) / nf; 435 | slopez = (p2[2] - p1[2]) / nf; 436 | 437 | RiBegin(RI_NULL); 438 | RiFormat(320, 240, 1); 439 | RiPixelSamples(2, 2); 440 | RiShutter(0, 1); 441 | 442 | /* loop through all the frames */ 443 | for (i = 1; i <= nf; i++) { 444 | RiFrameBegin(i); 445 | sprintf_s(name, "samplescene/image_%02d.bmp", i - 1); 446 | RiDisplay(name, "file", "rgb", RI_NULL); 447 | 448 | RiProjection("perspective", "fov", &fov, RI_NULL); 449 | RiTranslate(0, -5, 60); 450 | RiRotate(-120, 1, 0, 0); 451 | RiRotate(25, 0, 0, 1); 452 | 453 | RiWorldBegin(); 454 | RiColor(blue); 455 | RiTransformBegin(); 456 | RiCylinder(1, 0, 20, 360, RI_NULL); 457 | RiTranslate(0, 0, 20); 458 | RiCone(2, 2, 360, RI_NULL); 459 | RiTransformEnd(); 460 | 461 | RiColor(green); 462 | RiTransformBegin(); 463 | RiRotate(-90, 1, 0, 0); 464 | RiCylinder(1, 0, 20, 360, RI_NULL); 465 | RiTranslate(0, 0, 20); 466 | RiCone(2, 2, 360, RI_NULL); 467 | RiTransformEnd(); 468 | 469 | RiColor(red); 470 | RiTransformBegin(); 471 | RiRotate(90, 0, 1, 0); 472 | RiCylinder(1, 0, 20, 360, RI_NULL); 473 | RiTranslate(0, 0, 20); 474 | RiCone(2, 2, 360, RI_NULL); 475 | RiTransformEnd(); 476 | 477 | 478 | RiColor(white); 479 | RiTransformBegin(); 480 | RiTranslate(p1[0] + slopex * (i - 1), p1[1] + slopey * (i - 1), p1[2] + slopez * (i - 1)); 481 | RiSphere(5, -5, 5, 360, RI_NULL); 482 | RiTransformEnd(); 483 | RiWorldEnd(); 484 | 485 | /* when you hit this command you should output the final image for this frame */ 486 | RiFrameEnd(); 487 | } 488 | RiEnd(); 489 | } 490 | 491 | /********************************************/ 492 | /********************************************/ 493 | // MY SCENES 494 | 495 | 496 | void Donuts() { 497 | RiBegin(RI_NULL); 498 | RiFormat(320, 240, 1.0); 499 | RiPixelSamples(8, 8); 500 | //RiPixelSamples(4, 4); 501 | RiFrameAspectRatio(1.0f); 502 | RiDisplay("Donuts.bmp", "", ""); 503 | RiFrameBegin(0); 504 | /* set the perspective transformation */ 505 | float fov = 45.0; 506 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 507 | 508 | RiWorldBegin(); 509 | 510 | srand(19); 511 | for (int i = 0; i < 12; i++) { 512 | float xpos = (i % 4) * 1.4 - (1.4*1.5); 513 | float ypos = (i % 3)* 1.3 - 0.5f; 514 | float zpos = 7 + ((float)rand() / RAND_MAX) * 7 - 2.5; 515 | float xrot = ((float)rand() / RAND_MAX) * 180; //70; 516 | float yrot = ((float)rand() / RAND_MAX) * 180; //70; 517 | float zrot = ((float)rand() / RAND_MAX) * 360; //35; 518 | RiTransformBegin(); 519 | RiMotionBlur(((float)rand() / RAND_MAX) * 0.4 - 0.2f, ((float)rand() / RAND_MAX) * 0.3f + 0.7f, 0); 520 | RiDisplacement(DONUT_DISPLACEMENT); 521 | RiSurface(DONUT_SURFACE); 522 | RiTranslate(xpos, ypos, zpos); 523 | RiRotate(zrot, 0, 0, 1); 524 | RiRotate(yrot, 0, 1, 0); 525 | RiRotate(xrot, 1, 0, 0); 526 | RiTorus(0.5f, 0.3f, 0, 360, 360); 527 | RiTransformEnd(); 528 | } 529 | RiMotionBlur(0, 0, 0); 530 | RiTransformBegin(); 531 | BUMP_AMPLITUDE = 0.05; 532 | BUMP_MIN_FREQ_EXP = 3; 533 | BUMP_MAX_FREQ_EXP = 8; 534 | LIGHTING_REFLECTIVITY = 2.0f; 535 | LIGHTING_SPEC_ATTEN = 0.3f; 536 | RiDisplacement(BUMPY); 537 | RiSurface(WOOD); 538 | RiTranslate(0, 0, 12); 539 | RiRotate(90, 1, 0, 0); 540 | RiRotate(180, 0, 1, 0); 541 | RiCylinder(8, -3, 8.5, 180); 542 | RiTransformEnd(); 543 | 544 | RiTransformBegin(); 545 | //RiDisplacement(NULL); 546 | LIGHTING_REFLECTIVITY = 64.0f; 547 | LIGHTING_SPEC_ATTEN = 1.0f; 548 | RiSurface(MARBLE); 549 | RiTranslate(0, -12, 13); 550 | RiRotate(-90, 1, 0, 0); 551 | RiScale(1, 1, 0.5f); 552 | RiSphere(20, 17, 20, 360); 553 | RiTransformEnd(); 554 | RiWorldEnd(); 555 | RiFrameEnd(); 556 | RiEnd(); 557 | } 558 | 559 | // Create and render a scene that has the four main primitives (sphere, cylinder, cone, torus), 560 | // but set the zmin, zmax, and thetamax for these to different values so that the shapes are 561 | // incomplete and are missing their top and bottom and are open on one side 562 | void MyTestScene() { 563 | RtColor red = { 0.9, 0.1, 0.1 }; 564 | RtColor green = { 0.2, 0.9, 0.3 }; 565 | RtColor blue = { 0.1, 0.2, 0.9 }; 566 | RtColor purple = { 0.9, 0.1, 0.8 }; 567 | RtColor transparent = { 0.5, 0.5, 0.5 }; 568 | RiBegin(RI_NULL); 569 | RiFormat(400, 300, 1.0); 570 | RiPixelSamples(2, 2); 571 | RiFrameAspectRatio(1.0f); 572 | RiDisplay("TrevorTestScene.bmp", "", ""); 573 | RiFrameBegin(0); 574 | /* set the perspective transformation */ 575 | float fov = 45.0; 576 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 577 | RiWorldBegin(); 578 | RiTransformBegin(); 579 | RiOpacity(transparent); 580 | RiColor(red); 581 | RiTranslate(-1, 0, 8); 582 | RiRotate(110, 1, 0, 0); 583 | RiSphere(2, -1.5, 1.5, 250.0f); 584 | RiTransformEnd(); 585 | RiTransformBegin(); 586 | RiColor(green); 587 | RiTranslate(1, 0, 8); 588 | RiRotate(180, 0, 1, 0); 589 | RiRotate(110, 1, 0, 0); 590 | RiRotate(45, 0, 0, 1); 591 | RiCylinder(2, -1, 1, 250.0f); 592 | RiTransformEnd(); 593 | RiTransformBegin(); 594 | RiColor(purple); 595 | RiTranslate(0, 1, 8); 596 | RiRotate(-45, 1, 0, 0); 597 | RiTorus(2, 0.4, 60, 180, 250); 598 | RiTransformEnd(); 599 | RiTransformBegin(); 600 | RiColor(blue); 601 | RiTranslate(-1, -1, 8); 602 | RiRotate(-120, 1, 0, 0); 603 | RiRotate(180, 0, 0, 1); 604 | RiCone(2.5, 1, 250.0f); 605 | RiTransformEnd(); 606 | RiWorldEnd(); 607 | RiFrameEnd(); 608 | RiEnd(); 609 | } 610 | 611 | // Create and render a test scene that shows off your different shaders (standard lighting, checkerboard, bumpy) 612 | void MyShaderTest() { 613 | RtColor grass = { 0, 123.0f / 255, 12.0f / 255 }; 614 | RtColor post = { 0.7,0.6, 0 }; 615 | RtColor transparent = { 0.4, 0.4, 0.4 }; 616 | RtColor opaque = { 1, 1, 1 }; 617 | RtColor sky = { 135.0f / 255, 206.0f / 255, 235.0f / 255 }; 618 | RiBegin(RI_NULL); 619 | RiFormat(400, 300, 1.0); 620 | RiPixelSamples(4, 4); 621 | RiFrameAspectRatio(1.0f); 622 | RiDisplay("TrevorShaderTest.bmp", "", ""); 623 | //RiBackgroundColor(sky); 624 | RiFrameBegin(0); 625 | /* set the perspective transformation */ 626 | float fov = 45.0; 627 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 628 | RiWorldBegin(); 629 | // ball 630 | //RiMotionBlur(0.2, 0.8, 0.3); 631 | RiTransformBegin(); 632 | CHECK_SIZE_X = 10; 633 | CHECK_SIZE_Y = 5; 634 | RiSurface(CHECKERBOARD); 635 | RiTranslate(-1.5, -0.7, 8.8); 636 | RiRotate(110, 1, 0, 0); 637 | RiRotate(45, 0, 1, 0); 638 | RiSphere(0.8, -0.8, 0.8, 360.0f); 639 | RiTransformEnd(); 640 | //RiMotionBlur(0, 0, 0); 641 | // goal 642 | RiTransformBegin(); 643 | CHECK_SIZE_X = 60; 644 | CHECK_SIZE_Y = 60; 645 | RiSurface(CHECKERBOARD); 646 | RiOpacity(transparent); 647 | RiTranslate(0, 0.5, 13); 648 | RiScale(1, 1, 0.3f); 649 | RiRotate(90, 1, 0, 0); 650 | RiRotate(90, 0, 1, 0); 651 | RiCylinder(2, -2, 2, 100); 652 | RiTransformEnd(); 653 | //goal posts 654 | RiTransformBegin(); 655 | RiSurface(NULL); 656 | RiOpacity(opaque); 657 | RiColor(post); 658 | RiTranslate(2, 0.5, 13); 659 | RiRotate(-90, 1, 0, 0); 660 | RiCone(2, 0.3, 360); 661 | RiTransformEnd(); 662 | RiTransformBegin(); 663 | RiTranslate(-2, 0.5, 13); 664 | RiRotate(-90, 1, 0, 0); 665 | RiCone(2, 0.3, 360); 666 | RiTransformEnd(); 667 | // grass 668 | RiTransformBegin(); 669 | RiOpacity(opaque); 670 | RiColor(grass); 671 | RiSurface(NULL); 672 | BUMP_AMPLITUDE = 0.8; 673 | BUMP_MIN_FREQ_EXP = 10; 674 | BUMP_MAX_FREQ_EXP = 19; 675 | RiDisplacement(BUMPY); 676 | RiTranslate(0, -9, 15); 677 | RiRotate(-95, 1, 0, 0); 678 | RiSphere(10, 5, 10, 360.0f); 679 | RiTransformEnd(); 680 | RiWorldEnd(); 681 | RiFrameEnd(); 682 | RiEnd(); 683 | } 684 | 685 | void main() { 686 | //SampleScene1(); 687 | //TransparencyTest(); 688 | //ShaderTest(); 689 | //Rocket(); 690 | //Tunnel(); 691 | //Earth(); 692 | //Tornado(); 693 | 694 | //my scenes 695 | //MyTestScene(); 696 | MyShaderTest(); 697 | //Donuts(); 698 | } -------------------------------------------------------------------------------- /Reyes/Shader.cpp: -------------------------------------------------------------------------------- 1 | #include "Shader.h" 2 | #include "Vector4.h" 3 | #include "Noise.h" 4 | #include 5 | #include 6 | using std::max; 7 | using std::min; 8 | 9 | // Useful globals 10 | Noise noise; 11 | 12 | // Useful functions 13 | float mix(float a, float b, float t) { 14 | return a + t * (b - a); 15 | } 16 | 17 | void mix(RtColor a, RtColor b, float t, RtColor out) { 18 | for (int i = 0; i < 3; i++) 19 | out[i] = a[i] + t * (b[i] - a[i]); 20 | } 21 | 22 | 23 | float MARBLE_PERIOD_X = 1; 24 | float MARBLE_PERIOD_Y = 3; 25 | float MARBLE_TURBULENCE = 40; 26 | void MARBLE() { 27 | //create a tubulent sine wave 28 | float turbulence = MARBLE_TURBULENCE * noise.octaveNoise(__my_shader_u, __my_shader_v, 0, 2, 9); 29 | float sine = abs(sin(__my_shader_u * MARBLE_PERIOD_X + __my_shader_v * MARBLE_PERIOD_Y + turbulence)); 30 | 31 | //blue veins 32 | float turbulence2 = MARBLE_TURBULENCE * 2 * noise.octaveNoise(__my_shader_u, __my_shader_v, 3, 1, 10); 33 | float sine2 = abs(sin(__my_shader_u * MARBLE_PERIOD_Y * 0.5 + __my_shader_v * MARBLE_PERIOD_X * 0.9 + turbulence)); 34 | 35 | //attenuate and combine colors 36 | __my_shader_Ci[0] = 0.7 * sine + 0.2 * sine2; 37 | __my_shader_Ci[1] = 0.7 * sine + 0.2 * sine2; 38 | __my_shader_Ci[2] = 0.7 * sine + 0.3 * sine2; 39 | 40 | __my_shader_N[0] = 0; 41 | __my_shader_N[1] = 1; 42 | __my_shader_N[2] = 0; 43 | 44 | } 45 | 46 | float WOOD_PERIOD = 10; 47 | float WOOD_TURBULENCE = 6; 48 | void WOOD() { 49 | //define a center 50 | float centerx = 0.2; 51 | float centery = 0.8; 52 | //distance to center 53 | float distx = __my_shader_u - centerx; 54 | float disty = __my_shader_v - centery; 55 | float dist = sqrt(distx*distx + disty*disty); 56 | //put into sin along with turbulence 57 | float turbulence = WOOD_TURBULENCE * noise.octaveNoise(__my_shader_u, __my_shader_v, 0, 1, 3); 58 | //sqrt to decrease width of dark rings 59 | float sine = sqrt(abs(sin(dist * WOOD_PERIOD * M_PI + turbulence))); 60 | //sine = (sine > 0.8) ? 1 : sine; 61 | 62 | //add some overall grain 63 | sine += 0.5 * noise.octaveNoise(__my_shader_u, __my_shader_v, 5, 4, 9); 64 | 65 | //attenuate and combine colors 66 | RtColor dark = { 0.45, 0.32, 0.22 }; 67 | RtColor light = { 1, 0.83, 0.61 }; 68 | 69 | __my_shader_Ci[0] = dark[0] + sine * (light[0] - dark[0]); 70 | __my_shader_Ci[1] = dark[1] + sine * (light[1] - dark[1]); 71 | __my_shader_Ci[2] = dark[2] + sine * (light[2] - dark[2]); 72 | } 73 | 74 | //Phong lighting 75 | float LIGHTING_REFLECTIVITY = 32; 76 | float LIGHTING_SPEC_ATTEN = 1.0f; 77 | void LIGHTING() { 78 | //All positions are in eye space 79 | Vector4 lightPos(-2, 10, 0); 80 | Vector4 fragPos(__my_shader_P[0], __my_shader_P[1], __my_shader_P[2]); 81 | Vector4 normal = Vector4(__my_shader_N[0], __my_shader_N[1], __my_shader_N[2]).normalize(); 82 | Vector4 eyeDir = -fragPos.normalize(); 83 | 84 | //make normal frontfacing 85 | if (eyeDir.dot3(normal) < 0) 86 | normal = -normal; 87 | Vector4 lightDir = (lightPos - fragPos).normalize(); 88 | 89 | //diffuse lighting factor 90 | float diffuse = max(lightDir.dot3(normal), 0.0f); 91 | 92 | //specular lighting factor 93 | Vector4 reflectDir = (-lightDir).reflect(normal); 94 | float specular = pow(max(eyeDir.dot3(reflectDir), 0.0f), LIGHTING_REFLECTIVITY) * LIGHTING_SPEC_ATTEN; 95 | 96 | __my_shader_Ci[0] = min((diffuse + 0.2f)*__my_shader_Ci[0] + specular*1.0f, 1.0f); 97 | __my_shader_Ci[1] = min((diffuse + 0.2f)*__my_shader_Ci[1] + specular*1.0f, 1.0f); 98 | __my_shader_Ci[2] = min((diffuse + 0.2f)*__my_shader_Ci[2] + specular*1.0f, 1.0f); 99 | } 100 | 101 | // Checkerboard 102 | float CHECK_SIZE_X = 10.0f; 103 | float CHECK_SIZE_Y = 10.0f; 104 | void CHECKERBOARD() { 105 | if ((int)(floor(__my_shader_u*CHECK_SIZE_X) + floor(__my_shader_v*CHECK_SIZE_Y)) % 2 == 0) { 106 | __my_shader_Ci[0] = 1; 107 | __my_shader_Ci[1] = 1; 108 | __my_shader_Ci[2] = 1; 109 | } 110 | else { 111 | __my_shader_Ci[0] = 0; 112 | __my_shader_Ci[1] = 0; 113 | __my_shader_Ci[2] = 0; 114 | } 115 | 116 | } 117 | 118 | // Bumpy surface 119 | float BUMP_AMPLITUDE = 1; 120 | float BUMP_MIN_FREQ_EXP = 1; 121 | float BUMP_MAX_FREQ_EXP = 2; 122 | void BUMPY() { 123 | Vector4 normal(__my_shader_N[0], __my_shader_N[1], __my_shader_N[2]); 124 | Vector4 position(__my_shader_P[0], __my_shader_P[1], __my_shader_P[2]); 125 | 126 | //octaving 127 | float displacement = BUMP_AMPLITUDE * noise.octaveNoise(__my_shader_u, __my_shader_v, 0, BUMP_MIN_FREQ_EXP, BUMP_MAX_FREQ_EXP); 128 | 129 | //displace along normal 130 | position = position + normal.normalize() * displacement; 131 | 132 | __my_shader_P[0] = position.x; 133 | __my_shader_P[1] = position.y; 134 | __my_shader_P[2] = position.z; 135 | } 136 | 137 | void DONUT_DISPLACEMENT() { 138 | float donutSine = sin((__my_shader_v + 0.5f) * M_PI * 2); 139 | //barrier between dough and glaze 140 | float barrier = donutSine - (noise.octaveNoise(__my_shader_u, __my_shader_v, 1, 3, 6) + 0.5f); 141 | if (barrier > 0) { 142 | //make glaze stick out slightly 143 | Vector4 normal(__my_shader_N[0], __my_shader_N[1], __my_shader_N[2]); 144 | Vector4 position(__my_shader_P[0], __my_shader_P[1], __my_shader_P[2]); 145 | 146 | float displacement = min(0.05f, barrier * 0.05f); 147 | 148 | //displace along normal 149 | position = position + normal.normalize() * displacement; 150 | 151 | __my_shader_P[0] = position.x; 152 | __my_shader_P[1] = position.y; 153 | __my_shader_P[2] = position.z; 154 | } 155 | 156 | //make bumpy overall 157 | BUMP_AMPLITUDE = 0.05; 158 | BUMP_MIN_FREQ_EXP = 2; 159 | BUMP_MAX_FREQ_EXP = 9; 160 | BUMPY(); 161 | } 162 | 163 | void DONUT_SURFACE() { 164 | //create the dough color which has a lighter band around the middle 165 | RtColor top = { 207.0f / 255, 115.0f / 255, 64.0f / 255 }; 166 | RtColor middle = { 206.0f / 255, 185.0f / 255, 157.0f / 255 }; 167 | float donutSine = sin((__my_shader_v + 0.5f) * M_PI * 2); 168 | float doughScale = pow(abs(sin(donutSine)), 0.6); 169 | 170 | mix(middle, top, doughScale, __my_shader_Ci); 171 | 172 | //create glaze on top 173 | RtColor glaze = { 93.0f/255, 52.0f/255, 34.0f/255 }; 174 | //barrier between dough and glaze 175 | if (donutSine > noise.octaveNoise(__my_shader_u, __my_shader_v, 1, 3, 6) + 0.5f) { 176 | mix(__my_shader_Ci, glaze, 1.0f, __my_shader_Ci); 177 | } 178 | } -------------------------------------------------------------------------------- /Reyes/Shader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Ri.h" 3 | // This file provides forward declarations of shaders and their "parameters" 4 | // These shaders should be implemented in Shader.cpp 5 | // To use a shader, call RiSurface(shaderFunction) or RiDisplacement(shaderFunction) before issuing a primitive 6 | 7 | // Shader input/outputs 8 | extern RtPoint __my_shader_P; 9 | extern RtPoint __my_shader_N; 10 | extern RtColor __my_shader_Ci; 11 | extern RtColor __my_shader_Oi; 12 | extern RtFloat __my_shader_u; 13 | extern RtFloat __my_shader_v; 14 | extern RtFloat __my_shader_du; 15 | extern RtFloat __my_shader_dv; 16 | extern RtVector __my_shader_dPdu; 17 | extern RtVector __my_shader_dPdv; 18 | 19 | //------------------------------------------------ 20 | // Textures 21 | //------------------------------------------------ 22 | 23 | //Loads color into Ci from texture unit at u,v coords 24 | extern float TEXTURE_TILE_X; 25 | extern float TEXTURE_TILE_Y; 26 | void texture(int unit); 27 | 28 | //------------------------------------------------ 29 | // Surface shaders 30 | //------------------------------------------------ 31 | 32 | // Phong lighting - used automatically on everything after surface shader is run 33 | extern float LIGHTING_REFLECTIVITY; 34 | extern float LIGHTING_SPEC_ATTEN; 35 | void LIGHTING(); 36 | 37 | // Checkerboard pattern 38 | extern float CHECK_SIZE_X; 39 | extern float CHECK_SIZE_Y; 40 | void CHECKERBOARD(); 41 | 42 | void MARBLE(); 43 | 44 | void WOOD(); 45 | 46 | void DONUT_SURFACE(); 47 | 48 | //------------------------------------------------ 49 | // Displacement shaders 50 | //------------------------------------------------ 51 | 52 | // Bumpy surface 53 | extern float BUMP_AMPLITUDE; 54 | extern float BUMP_MIN_FREQ_EXP; 55 | extern float BUMP_MAX_FREQ_EXP; 56 | void BUMPY(); 57 | 58 | void DONUT_DISPLACEMENT(); -------------------------------------------------------------------------------- /Reyes/Triangle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Vector4.h" 3 | 4 | // A triangle. Used only for sampling micropolygons 5 | class Triangle { 6 | public: 7 | Vector4 v[3]; 8 | 9 | Triangle() { 10 | 11 | } 12 | 13 | Triangle(Vector4& v0, Vector4& v1, Vector4& v2) { 14 | v[0] = v0; 15 | v[1] = v1; 16 | v[2] = v2; 17 | } 18 | 19 | Vector4 normal() { 20 | Vector4 v0v1 = v[1] - v[0]; 21 | Vector4 v0v2 = v[2] - v[0]; 22 | return v0v1.cross(v0v2); 23 | } 24 | 25 | bool shadowTest(Vector4& line) { 26 | return (line.x == 0) ? (line.y > 0) : (line.y > 0); 27 | } 28 | 29 | bool insideLine(float e, Vector4& line) { 30 | return (e == 0) ? shadowTest(line) : (e > 0); 31 | } 32 | 33 | bool insideTriangle(float x, float y) { 34 | Vector4 line0 = v[1].cross2(v[0]); 35 | Vector4 line1 = v[2].cross2(v[1]); 36 | Vector4 line2 = v[0].cross2(v[2]); 37 | 38 | //invert lines if vertices are not in CCW order 39 | Vector4 v0v1 = v[1] - v[0]; 40 | Vector4 v0v2 = v[2] - v[0]; 41 | Vector4 normal = v0v1.cross(v0v2); 42 | bool ccw = (normal.z < 0); 43 | if (!ccw) { 44 | line0 = -line0; 45 | line1 = -line1; 46 | line2 = -line2; 47 | } 48 | //TODO add shadow test 49 | Vector4 point(x, y, 1); 50 | if (insideLine(point.dot3(line0), line0) && insideLine(point.dot3(line1), line1) && insideLine(point.dot3(line2), line2)) 51 | return true; 52 | return false; 53 | } 54 | }; -------------------------------------------------------------------------------- /Reyes/Vector3.cpp: -------------------------------------------------------------------------------- 1 | #include "Vector3.h" 2 | 3 | 4 | 5 | Vector3::Vector3() { 6 | for (int i = 0; i < VECTOR3_SIZE; i++) 7 | v[i] = 0.0f; 8 | } 9 | 10 | Vector3::Vector3(float x, float y, float z) { 11 | v[0] = x; 12 | v[1] = y; 13 | v[2] = z; 14 | } 15 | 16 | Vector3::Vector3(float x, float y) { 17 | v[0] = x; 18 | v[1] = y; 19 | v[2] = 1.0f; 20 | } 21 | 22 | Vector3 Vector3::operator-() { 23 | return Vector3(-v[0], -v[1], -v[2]); 24 | } 25 | 26 | Vector3 Vector3::operator+(const Vector3& other) { 27 | return Vector3(v[0] + other.v[0], v[1] + other.v[1], v[2] + other.v[2]); 28 | } 29 | 30 | Vector3 Vector3::operator-(const Vector3& other) { 31 | return Vector3(v[0] - other.v[0], v[1] - other.v[1], v[2] - other.v[2]); 32 | } 33 | 34 | Vector3 Vector3::operator*(float scalar) { 35 | return Vector3(v[0] * scalar, v[1] * scalar, v[2] * scalar); 36 | } 37 | 38 | float Vector3::dot(const Vector3& other) { 39 | return v[0] * other.v[0] + v[1] * other.v[1] + v[2] * other.v[2]; 40 | } 41 | 42 | Vector3 Vector3::cross(const Vector3& other) { 43 | // x y z 44 | //v[0] v[1] v[2] 45 | //o[0] o[1] o[2] 46 | Vector3 result; 47 | result.v[0] = v[1] * other.v[2] - v[2] * other.v[1]; 48 | result.v[1] = -v[0] * other.v[2] + v[2] * other.v[0]; 49 | result.v[2] = v[0] * other.v[1] - v[1] * other.v[0]; 50 | return result; 51 | } 52 | 53 | float Vector3::x() { 54 | return v[0]; 55 | } 56 | 57 | float Vector3::y() { 58 | return v[1]; 59 | } 60 | 61 | float Vector3::z() { 62 | return v[2]; 63 | } -------------------------------------------------------------------------------- /Reyes/Vector3.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define VECTOR3_SIZE 3 3 | 4 | class Vector3 { 5 | public: 6 | //data 7 | float v[VECTOR3_SIZE]; 8 | 9 | //Initialize to (0,0,0) 10 | Vector3(); 11 | //Initialize to (x,y,1) 12 | Vector3(float x, float y); 13 | //Initialize to (x,y,z) 14 | Vector3(float x, float y, float z); 15 | 16 | //Inverse 17 | Vector3 operator-(); 18 | 19 | //Addition 20 | Vector3 operator+(const Vector3& other); 21 | 22 | //Subtraction 23 | Vector3 operator-(const Vector3& other); 24 | 25 | //Multiplication 26 | Vector3 operator*(float scalar); 27 | float dot(const Vector3& other); 28 | Vector3 cross(const Vector3& other); 29 | 30 | //Accessors 31 | float x(); 32 | float y(); 33 | float z(); 34 | }; 35 | 36 | -------------------------------------------------------------------------------- /Reyes/Vector4.cpp: -------------------------------------------------------------------------------- 1 | #include "Vector4.h" 2 | 3 | 4 | 5 | Vector4::Vector4() { 6 | x = y = z = w = 0.0f; 7 | } 8 | 9 | Vector4::Vector4(float x, float y, float z, float w) { 10 | this->x = x; 11 | this->y = y; 12 | this->z = z; 13 | this->w = w; 14 | } 15 | 16 | Vector4::Vector4(float x, float y, float z) { 17 | this->x = x; 18 | this->y = y; 19 | this->z = z; 20 | this->w = 1; 21 | } 22 | 23 | Vector4 Vector4::operator+(const Vector4& other) { 24 | return Vector4(x + other.x, y + other.y, z + other.z, w + other.w); 25 | } 26 | 27 | Vector4 Vector4::operator-(const Vector4& other) { 28 | return Vector4(x - other.x, y - other.y, z - other.z, w - other.w); 29 | } 30 | 31 | Vector4 Vector4::operator*(float scalar) { 32 | return Vector4(x * scalar, y * scalar, z * scalar, w * scalar); 33 | } 34 | 35 | Vector4 Vector4::cross2(const Vector4& other) { 36 | // x y z 37 | //v[x] v[y] v[z] 38 | //o[x] o[y] o[z] 39 | Vector4 result; 40 | result.x = y * 1 - 1 * other.y; 41 | result.y = -x * 1 + 1 * other.x; 42 | result.z = x * other.y - y * other.x; 43 | return result; 44 | } 45 | 46 | Vector4 Vector4::cross(const Vector4& other) { 47 | // x y z 48 | //v[x] v[y] v[z] 49 | //o[x] o[y] o[z] 50 | Vector4 result; 51 | result.x = y * other.z - z * other.y; 52 | result.y = -x * other.z + z * other.x; 53 | result.z = x * other.y - y * other.x; 54 | return result; 55 | } -------------------------------------------------------------------------------- /Reyes/Vector4.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define _USE_MATH_DEFINES 3 | #include 4 | #include 5 | #define VECTOR4_SIZE 4 6 | 7 | //4-D Vector 8 | class Vector4 { 9 | public: 10 | //data 11 | float x, y, z, w; 12 | 13 | //Initialize to (0,0,0,0) 14 | Vector4(); 15 | //Initialize to (x,y,z,w) 16 | Vector4(float x, float y, float z, float w); 17 | //Initialize to (x,y,z,1) 18 | Vector4(float x, float y, float z); 19 | 20 | //Addition 21 | Vector4 operator+(const Vector4& other); 22 | 23 | //Subtraction 24 | Vector4 operator-(const Vector4& other); 25 | 26 | //Multiplication 27 | Vector4 operator*(float scalar); 28 | 29 | //2D Cross Product (Mainly for rasterization) 30 | Vector4 cross2(const Vector4& other); 31 | 32 | //3D Cross Product 33 | Vector4 cross(const Vector4& other); 34 | 35 | Vector4 homogenize() { 36 | Vector4 result; 37 | result.x = this->x / this->w; 38 | result.y = this->y / this->w; 39 | result.z = this->z / this->w; 40 | result.w = 1.0f; 41 | return result; 42 | } 43 | 44 | float dot3(Vector4& other) { 45 | return x * other.x + y * other.y + z * other.z; 46 | } 47 | 48 | Vector4 reflect(Vector4& normal) { 49 | return *this - normal * 2 * this->dot3(normal); 50 | } 51 | 52 | Vector4 operator -() { 53 | return Vector4(-x, -y, -z, -w); 54 | } 55 | 56 | float length() { 57 | return sqrt(x*x + y*y + z*z); 58 | } 59 | 60 | Vector4 normalize() { 61 | float magnitude = length(); 62 | return Vector4(x / magnitude, y / magnitude, z / magnitude); 63 | } 64 | 65 | void print() { 66 | printf("[%f %f %f %f]\n", x, y, z, w); 67 | } 68 | }; 69 | 70 | -------------------------------------------------------------------------------- /Reyes/earth.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trevor-m/reyes-renderer/490a771c4a064c350404fa6233dae4211fbbee73/Reyes/earth.jpg -------------------------------------------------------------------------------- /Reyes/main.cpp: -------------------------------------------------------------------------------- 1 | #include "Ri.h" 2 | #include "Shader.h" 3 | #include 4 | 5 | // Texture lookup 6 | void TextureMap0() 7 | { 8 | texture(0); 9 | } 10 | 11 | /********************************************/ 12 | /********************************************/ 13 | void TransparencyTest() 14 | { 15 | RiBegin(RI_NULL); 16 | //RiFormat(960, 720, 1.0); 17 | RiFormat(400, 300, 1.0); 18 | //RiFormat(200, 150, 1.0); 19 | RiDisplay("TransparencyTest.png", "", ""); 20 | RiPixelSamples(2, 2); 21 | 22 | RiFrameBegin(0); 23 | /* set the perspective transformation */ 24 | float fov = 45.0; 25 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 26 | //RiProjection(RI_ORTHOGRAPHIC); 27 | RiWorldBegin(); 28 | RiTransformBegin(); 29 | RtColor color = { 1,0,0 }; 30 | RtColor opacity = { .4,.4,.4 }; 31 | RiOpacity(opacity); 32 | RiColor(color); 33 | RiTranslate(0, 0.5, 7.0); 34 | RiRotate(60, 1, 0, 0); 35 | RiTorus(1, .25, 0, 250, 270); 36 | RiTransformEnd(); 37 | RiTransformBegin(); 38 | color[0] = 0; color[1] = 1; 39 | opacity[0] = 0.4; opacity[1] = 0.4; opacity[2] = 0.4; 40 | RiOpacity(opacity); 41 | RiColor(color); 42 | RiTranslate(0, 0, 8.0); 43 | RiRotate(60, 1, 0, 0); 44 | RiRotate(30, 0, 1, 0); 45 | RiCylinder(1, -1, 1, 300); 46 | RiTransformEnd(); 47 | RiTransformBegin(); 48 | color[1] = 0; color[2] = 1; 49 | opacity[0] = .7; opacity[1] = .7; opacity[2] = .7; 50 | RiOpacity(opacity); 51 | RiColor(color); 52 | RiTranslate(0, 1, 9.0); 53 | RiRotate(60, 1, 0, 0); 54 | RiSphere(1.8, -1.0, 1.0, 250); 55 | RiTransformEnd(); 56 | RiTransformBegin(); 57 | color[0] = 1; color[1] = .6; color[2] = .6; 58 | RiColor(color); 59 | opacity[0] = .6; opacity[1] = .6; opacity[2] = .6; 60 | RiOpacity(opacity); 61 | RiTranslate(0, -1, 8.5); 62 | RiRotate(-160, 1, 0, 0); 63 | RiRotate(30, 0, 1, 0); 64 | RiRotate(140, 0, 0, 1); 65 | RiCone(2.5, 1, 270); 66 | RiTransformEnd(); 67 | RiWorldEnd(); 68 | 69 | RiFrameEnd(); 70 | 71 | RiEnd(); 72 | } 73 | 74 | /********************************************/ 75 | /********************************************/ 76 | void Earth() 77 | { 78 | RiBegin(RI_NULL); 79 | //RiFormat(960, 720, 1.0); 80 | RiFormat(400, 300, 1.0); 81 | //RiFormat(200, 150, 1.0); 82 | RiDisplay("Earth.png", "", ""); 83 | RiPixelSamples(2, 2); 84 | 85 | RiFrameBegin(0); 86 | /* set the perspective transformation */ 87 | float fov = 45.0; 88 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 89 | //RiProjection(RI_ORTHOGRAPHIC); 90 | 91 | RiWorldBegin(); 92 | RiTransformBegin(); 93 | RiMakeTexture("earth.jpg", 0); 94 | void(*earthShader)(void) = TextureMap0; 95 | RiSurface(earthShader); 96 | RtColor blue = { 0, 0, 1 }; 97 | RtColor opacity = { .9, .9, .9 }; 98 | RiColor(blue); 99 | RiOpacity(opacity); 100 | BUMP_AMPLITUDE = .02; 101 | BUMP_MIN_FREQ_EXP = 14; 102 | BUMP_MAX_FREQ_EXP = 16; 103 | RiDisplacement(BUMPY); 104 | RiTranslate(0, 0, 5.0); 105 | RiRotate(-175, 0, 1, 0); 106 | RiRotate(110, 1, 0, 0); 107 | RiSphere(1, -1, 1, 360); 108 | RiTransformEnd(); 109 | RiWorldEnd(); 110 | 111 | RiFrameEnd(); 112 | 113 | RiEnd(); 114 | } 115 | 116 | void myScene(void) { 117 | RtColor gemColor = { 0.25, 0.5, 1 }; 118 | RtColor ringColor = { 1, 1, 0 }; 119 | RtColor transparent = { 0.5, 0.5, 0.5 }; 120 | RtColor opaque = { 1.0, 1.0, 1.0 }; 121 | RiMakeTexture("earth.jpg", 0); 122 | 123 | RiBegin(RI_NULL); 124 | RiFormat(300, 300, 1.0); 125 | RiPixelSamples(4, 4); 126 | RiFrameAspectRatio(4.0/3.0); 127 | RiDisplay("scene.bmp", "", ""); 128 | RiFrameBegin(0); 129 | /* set the perspective transformation */ 130 | float fov = 45.0; 131 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 132 | 133 | RiWorldBegin(); 134 | BUMP_AMPLITUDE = 1; 135 | BUMP_MIN_FREQ_EXP = 6; 136 | BUMP_MAX_FREQ_EXP = 9; 137 | RiDisplacement(BUMPY); 138 | RiTransformBegin(); 139 | RiTranslate(-1.6, 0, 10); 140 | RiColor(gemColor); 141 | RiSphere(1.0, -1.0, 1.0, 360); 142 | RiTransformEnd(); 143 | 144 | RiOpacity(transparent); 145 | RiTransformBegin(); 146 | 147 | RiTranslate(1, 0, 10); 148 | RiRotate(45, 1, 0, 0); 149 | RiColor(ringColor); 150 | RiTorus(2, 0.5, 0, 360, 360); 151 | RiTransformEnd(); 152 | RiDisplacement(NULL); 153 | //CHECK_SIZE_X = 40.0f; 154 | //CHECK_SIZE_Y = 40.0f; 155 | RiSurface(NOISY); 156 | RiOpacity(opaque); 157 | RiTransformBegin(); 158 | 159 | RiTranslate(0, 5, 13); 160 | RiRotate(120, 1, 0, 0); 161 | RiCylinder(5, -5, 5, 150); 162 | RiTransformEnd(); 163 | RiWorldEnd(); 164 | RiFrameEnd(); 165 | RiEnd(); 166 | } 167 | 168 | void Rocket() 169 | { 170 | RiBegin(RI_NULL); 171 | //RiFormat(960, 720, 1.0); 172 | RiFormat(400, 300, 1.0); 173 | //RiFormat(200, 150, 1.0); 174 | RiDisplay("Rocket.png", "", ""); 175 | RiPixelSamples(2, 2); 176 | 177 | RiFrameBegin(0); 178 | /* set the perspective transformation */ 179 | float fov = 45.0; 180 | RiProjection(RI_PERSPECTIVE, "fov", &fov); 181 | //RiProjection(RI_ORTHOGRAPHIC); 182 | 183 | RiWorldBegin(); 184 | RiTransformBegin(); 185 | // water 186 | RtColor color = { 0,0,1 }; 187 | RtColor opacity = { .6,.6,.6 }; 188 | RiOpacity(opacity); 189 | RiColor(color); 190 | BUMP_AMPLITUDE = .05; 191 | BUMP_MIN_FREQ_EXP = 2; 192 | BUMP_MAX_FREQ_EXP = 6; 193 | RiDisplacement(BUMPY); 194 | RiScale(7, 1.15, 1); 195 | RiTranslate(0, -0.75, 4); 196 | RiRotate(180, 0, 1, 0); 197 | RiRotate(110, 1, 0, 0); 198 | RiTranslate(0, 0, 1); 199 | RiRotate(180, 1, 0, 0); 200 | RiSphere(1, .9, 1, 360); 201 | // mountain 202 | color[0] = 0.6; color[1] = 0.3; color[2] = 0; 203 | opacity[0] = 1; opacity[1] = 1; opacity[2] = 1; 204 | RiColor(color); 205 | RiOpacity(opacity); 206 | RiDisplacement(NULL); 207 | BUMP_AMPLITUDE = 2; 208 | BUMP_MIN_FREQ_EXP = 3; 209 | BUMP_MAX_FREQ_EXP = 9; 210 | RiDisplacement(BUMPY); 211 | RiTranslate(0, 4, -6); 212 | RiRotate(15, 1, 0, 0); 213 | RiSphere(7, 6.8, 7, 360); 214 | RiTransformEnd(); 215 | 216 | RiTransformBegin(); 217 | // rocket 218 | RiDisplacement(NULL); 219 | color[0] = .8; color[1] = 0.8; color[2] = .8; 220 | RiColor(color); 221 | RiTranslate(-.25, .25, 2); 222 | RiRotate(40, 0, 0, 1); 223 | RiScale(1, 2, 1); 224 | RiRotate(150, 0, 1, 0); 225 | RiRotate(-90, 1, 0, 0); 226 | RiSphere(.1, -.1, .1, 360); 227 | 228 | RiTranslate(0, 0, .07); 229 | RiCone(.075, .075, 360); 230 | 231 | RiSurface(NULL); 232 | BUMP_AMPLITUDE = 0.1f; 233 | BUMP_MIN_FREQ_EXP = 5; 234 | BUMP_MAX_FREQ_EXP = 7; 235 | RiDisplacement(BUMPY); 236 | color[0] = 1; color[1] = 0.27; color[2] = 0; 237 | opacity[0] = .4; opacity[1] = .4; opacity[2] = .4; 238 | RiOpacity(opacity); 239 | RiColor(color); 240 | RiTranslate(0, 0, -.45); 241 | RiCone(.3, .1, 360); 242 | 243 | color[1] = .1; 244 | RiColor(color); 245 | opacity[0] = 1; opacity[1] = 1; opacity[2] = 1; 246 | RiOpacity(opacity); 247 | RiDisplacement(NULL); 248 | RiScale(20, .5, 1); 249 | RiTranslate(0, 0, .375); 250 | RiSphere(.025, -.025, .025, 360); 251 | 252 | RiScale(1 / 40, 16, 1); 253 | RiTranslate(0, -0.015, -.075); 254 | RiSphere(.025, -.025, .025, 360); 255 | RiTransformEnd(); 256 | RiWorldEnd(); 257 | 258 | RiFrameEnd(); 259 | 260 | RiEnd(); 261 | } 262 | 263 | //int main() { 264 | //Earth(); 265 | //TransparencyTest(); 266 | //myScene(); 267 | //Rocket(); 268 | //SampleScene1(); 269 | 270 | //return 0; 271 | //} -------------------------------------------------------------------------------- /Reyes/stb_image_write.h: -------------------------------------------------------------------------------- 1 | /* stb_image_write - v1.05 - public domain - http://nothings.org/stb/stb_image_write.h 2 | writes out PNG/BMP/TGA images to C stdio - Sean Barrett 2010-2015 3 | no warranty implied; use at your own risk 4 | 5 | Before #including, 6 | 7 | #define STB_IMAGE_WRITE_IMPLEMENTATION 8 | 9 | in the file that you want to have the implementation. 10 | 11 | Will probably not work correctly with strict-aliasing optimizations. 12 | 13 | ABOUT: 14 | 15 | This header file is a library for writing images to C stdio. It could be 16 | adapted to write to memory or a general streaming interface; let me know. 17 | 18 | The PNG output is not optimal; it is 20-50% larger than the file 19 | written by a decent optimizing implementation. This library is designed 20 | for source code compactness and simplicity, not optimal image file size 21 | or run-time performance. 22 | 23 | BUILDING: 24 | 25 | You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h. 26 | You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace 27 | malloc,realloc,free. 28 | You can define STBIW_MEMMOVE() to replace memmove() 29 | 30 | USAGE: 31 | 32 | There are four functions, one for each image file format: 33 | 34 | int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 35 | int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 36 | int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 37 | int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); 38 | 39 | There are also four equivalent functions that use an arbitrary write function. You are 40 | expected to open/close your file-equivalent before and after calling these: 41 | 42 | int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); 43 | int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 44 | int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 45 | int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); 46 | 47 | where the callback is: 48 | void stbi_write_func(void *context, void *data, int size); 49 | 50 | You can define STBI_WRITE_NO_STDIO to disable the file variant of these 51 | functions, so the library will not use stdio.h at all. However, this will 52 | also disable HDR writing, because it requires stdio for formatted output. 53 | 54 | Each function returns 0 on failure and non-0 on success. 55 | 56 | The functions create an image file defined by the parameters. The image 57 | is a rectangle of pixels stored from left-to-right, top-to-bottom. 58 | Each pixel contains 'comp' channels of data stored interleaved with 8-bits 59 | per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is 60 | monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall. 61 | The *data pointer points to the first byte of the top-left-most pixel. 62 | For PNG, "stride_in_bytes" is the distance in bytes from the first byte of 63 | a row of pixels to the first byte of the next row of pixels. 64 | 65 | PNG creates output files with the same number of components as the input. 66 | The BMP format expands Y to RGB in the file format and does not 67 | output alpha. 68 | 69 | PNG supports writing rectangles of data even when the bytes storing rows of 70 | data are not consecutive in memory (e.g. sub-rectangles of a larger image), 71 | by supplying the stride between the beginning of adjacent rows. The other 72 | formats do not. (Thus you cannot write a native-format BMP through the BMP 73 | writer, both because it is in BGR order and because it may have padding 74 | at the end of the line.) 75 | 76 | HDR expects linear float data. Since the format is always 32-bit rgb(e) 77 | data, alpha (if provided) is discarded, and for monochrome data it is 78 | replicated across all three channels. 79 | 80 | TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed 81 | data, set the global variable 'stbi_write_tga_with_rle' to 0. 82 | 83 | CREDITS: 84 | 85 | PNG/BMP/TGA 86 | Sean Barrett 87 | HDR 88 | Baldur Karlsson 89 | TGA monochrome: 90 | Jean-Sebastien Guay 91 | misc enhancements: 92 | Tim Kelsey 93 | TGA RLE 94 | Alan Hickman 95 | initial file IO callback implementation 96 | Emmanuel Julien 97 | bugfixes: 98 | github:Chribba 99 | Guillaume Chereau 100 | github:jry2 101 | github:romigrou 102 | Sergio Gonzalez 103 | Jonas Karlsson 104 | Filip Wasil 105 | Thatcher Ulrich 106 | github:poppolopoppo 107 | Patrick Boettcher 108 | 109 | LICENSE 110 | 111 | See end of file for license information. 112 | 113 | */ 114 | 115 | #ifndef INCLUDE_STB_IMAGE_WRITE_H 116 | #define INCLUDE_STB_IMAGE_WRITE_H 117 | 118 | #ifdef __cplusplus 119 | extern "C" { 120 | #endif 121 | 122 | #ifdef STB_IMAGE_WRITE_STATIC 123 | #define STBIWDEF static 124 | #else 125 | #define STBIWDEF extern 126 | extern int stbi_write_tga_with_rle; 127 | #endif 128 | 129 | #ifndef STBI_WRITE_NO_STDIO 130 | STBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes); 131 | STBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data); 132 | STBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data); 133 | STBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data); 134 | #endif 135 | 136 | typedef void stbi_write_func(void *context, void *data, int size); 137 | 138 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data, int stride_in_bytes); 139 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 140 | STBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void *data); 141 | STBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data); 142 | 143 | #ifdef __cplusplus 144 | } 145 | #endif 146 | 147 | #endif//INCLUDE_STB_IMAGE_WRITE_H 148 | 149 | #ifdef STB_IMAGE_WRITE_IMPLEMENTATION 150 | 151 | #ifdef _WIN32 152 | #ifndef _CRT_SECURE_NO_WARNINGS 153 | #define _CRT_SECURE_NO_WARNINGS 154 | #endif 155 | #ifndef _CRT_NONSTDC_NO_DEPRECATE 156 | #define _CRT_NONSTDC_NO_DEPRECATE 157 | #endif 158 | #endif 159 | 160 | #ifndef STBI_WRITE_NO_STDIO 161 | #include 162 | #endif // STBI_WRITE_NO_STDIO 163 | 164 | #include 165 | #include 166 | #include 167 | #include 168 | 169 | #if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED)) 170 | // ok 171 | #elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED) 172 | // ok 173 | #else 174 | #error "Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED)." 175 | #endif 176 | 177 | #ifndef STBIW_MALLOC 178 | #define STBIW_MALLOC(sz) malloc(sz) 179 | #define STBIW_REALLOC(p,newsz) realloc(p,newsz) 180 | #define STBIW_FREE(p) free(p) 181 | #endif 182 | 183 | #ifndef STBIW_REALLOC_SIZED 184 | #define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz) 185 | #endif 186 | 187 | 188 | #ifndef STBIW_MEMMOVE 189 | #define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz) 190 | #endif 191 | 192 | 193 | #ifndef STBIW_ASSERT 194 | #include 195 | #define STBIW_ASSERT(x) assert(x) 196 | #endif 197 | 198 | #define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff) 199 | 200 | typedef struct 201 | { 202 | stbi_write_func *func; 203 | void *context; 204 | } stbi__write_context; 205 | 206 | // initialize a callback-based context 207 | static void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context) 208 | { 209 | s->func = c; 210 | s->context = context; 211 | } 212 | 213 | #ifndef STBI_WRITE_NO_STDIO 214 | 215 | static void stbi__stdio_write(void *context, void *data, int size) 216 | { 217 | fwrite(data, 1, size, (FILE*)context); 218 | } 219 | 220 | static int stbi__start_write_file(stbi__write_context *s, const char *filename) 221 | { 222 | FILE *f = fopen(filename, "wb"); 223 | stbi__start_write_callbacks(s, stbi__stdio_write, (void *)f); 224 | return f != NULL; 225 | } 226 | 227 | static void stbi__end_write_file(stbi__write_context *s) 228 | { 229 | fclose((FILE *)s->context); 230 | } 231 | 232 | #endif // !STBI_WRITE_NO_STDIO 233 | 234 | typedef unsigned int stbiw_uint32; 235 | typedef int stb_image_write_test[sizeof(stbiw_uint32) == 4 ? 1 : -1]; 236 | 237 | #ifdef STB_IMAGE_WRITE_STATIC 238 | static int stbi_write_tga_with_rle = 1; 239 | #else 240 | int stbi_write_tga_with_rle = 1; 241 | #endif 242 | 243 | static void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v) 244 | { 245 | while (*fmt) { 246 | switch (*fmt++) { 247 | case ' ': break; 248 | case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int)); 249 | s->func(s->context, &x, 1); 250 | break; } 251 | case '2': { int x = va_arg(v, int); 252 | unsigned char b[2]; 253 | b[0] = STBIW_UCHAR(x); 254 | b[1] = STBIW_UCHAR(x >> 8); 255 | s->func(s->context, b, 2); 256 | break; } 257 | case '4': { stbiw_uint32 x = va_arg(v, int); 258 | unsigned char b[4]; 259 | b[0] = STBIW_UCHAR(x); 260 | b[1] = STBIW_UCHAR(x >> 8); 261 | b[2] = STBIW_UCHAR(x >> 16); 262 | b[3] = STBIW_UCHAR(x >> 24); 263 | s->func(s->context, b, 4); 264 | break; } 265 | default: 266 | STBIW_ASSERT(0); 267 | return; 268 | } 269 | } 270 | } 271 | 272 | static void stbiw__writef(stbi__write_context *s, const char *fmt, ...) 273 | { 274 | va_list v; 275 | va_start(v, fmt); 276 | stbiw__writefv(s, fmt, v); 277 | va_end(v); 278 | } 279 | 280 | static void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c) 281 | { 282 | unsigned char arr[3]; 283 | arr[0] = a, arr[1] = b, arr[2] = c; 284 | s->func(s->context, arr, 3); 285 | } 286 | 287 | static void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d) 288 | { 289 | unsigned char bg[3] = { 255, 0, 255 }, px[3]; 290 | int k; 291 | 292 | if (write_alpha < 0) 293 | s->func(s->context, &d[comp - 1], 1); 294 | 295 | switch (comp) { 296 | case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case 297 | case 1: 298 | if (expand_mono) 299 | stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp 300 | else 301 | s->func(s->context, d, 1); // monochrome TGA 302 | break; 303 | case 4: 304 | if (!write_alpha) { 305 | // composite against pink background 306 | for (k = 0; k < 3; ++k) 307 | px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255; 308 | stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]); 309 | break; 310 | } 311 | /* FALLTHROUGH */ 312 | case 3: 313 | stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]); 314 | break; 315 | } 316 | if (write_alpha > 0) 317 | s->func(s->context, &d[comp - 1], 1); 318 | } 319 | 320 | static void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono) 321 | { 322 | stbiw_uint32 zero = 0; 323 | int i, j, j_end; 324 | 325 | if (y <= 0) 326 | return; 327 | 328 | if (vdir < 0) 329 | j_end = -1, j = y - 1; 330 | else 331 | j_end = y, j = 0; 332 | 333 | for (; j != j_end; j += vdir) { 334 | for (i = 0; i < x; ++i) { 335 | unsigned char *d = (unsigned char *)data + (j*x + i)*comp; 336 | stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d); 337 | } 338 | s->func(s->context, &zero, scanline_pad); 339 | } 340 | } 341 | 342 | static int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...) 343 | { 344 | if (y < 0 || x < 0) { 345 | return 0; 346 | } 347 | else { 348 | va_list v; 349 | va_start(v, fmt); 350 | stbiw__writefv(s, fmt, v); 351 | va_end(v); 352 | stbiw__write_pixels(s, rgb_dir, vdir, x, y, comp, data, alpha, pad, expand_mono); 353 | return 1; 354 | } 355 | } 356 | 357 | static int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data) 358 | { 359 | int pad = (-x * 3) & 3; 360 | return stbiw__outfile(s, -1, -1, x, y, comp, 1, (void *)data, 0, pad, 361 | "11 4 22 4" "4 44 22 444444", 362 | 'B', 'M', 14 + 40 + (x * 3 + pad)*y, 0, 0, 14 + 40, // file header 363 | 40, x, y, 1, 24, 0, 0, 0, 0, 0, 0); // bitmap header 364 | } 365 | 366 | STBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) 367 | { 368 | stbi__write_context s; 369 | stbi__start_write_callbacks(&s, func, context); 370 | return stbi_write_bmp_core(&s, x, y, comp, data); 371 | } 372 | 373 | #ifndef STBI_WRITE_NO_STDIO 374 | STBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data) 375 | { 376 | stbi__write_context s; 377 | if (stbi__start_write_file(&s, filename)) { 378 | int r = stbi_write_bmp_core(&s, x, y, comp, data); 379 | stbi__end_write_file(&s); 380 | return r; 381 | } 382 | else 383 | return 0; 384 | } 385 | #endif //!STBI_WRITE_NO_STDIO 386 | 387 | static int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data) 388 | { 389 | int has_alpha = (comp == 2 || comp == 4); 390 | int colorbytes = has_alpha ? comp - 1 : comp; 391 | int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3 392 | 393 | if (y < 0 || x < 0) 394 | return 0; 395 | 396 | if (!stbi_write_tga_with_rle) { 397 | return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *)data, has_alpha, 0, 398 | "111 221 2222 11", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); 399 | } 400 | else { 401 | int i, j, k; 402 | 403 | stbiw__writef(s, "111 221 2222 11", 0, 0, format + 8, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8); 404 | 405 | for (j = y - 1; j >= 0; --j) { 406 | unsigned char *row = (unsigned char *)data + j * x * comp; 407 | int len; 408 | 409 | for (i = 0; i < x; i += len) { 410 | unsigned char *begin = row + i * comp; 411 | int diff = 1; 412 | len = 1; 413 | 414 | if (i < x - 1) { 415 | ++len; 416 | diff = memcmp(begin, row + (i + 1) * comp, comp); 417 | if (diff) { 418 | const unsigned char *prev = begin; 419 | for (k = i + 2; k < x && len < 128; ++k) { 420 | if (memcmp(prev, row + k * comp, comp)) { 421 | prev += comp; 422 | ++len; 423 | } 424 | else { 425 | --len; 426 | break; 427 | } 428 | } 429 | } 430 | else { 431 | for (k = i + 2; k < x && len < 128; ++k) { 432 | if (!memcmp(begin, row + k * comp, comp)) { 433 | ++len; 434 | } 435 | else { 436 | break; 437 | } 438 | } 439 | } 440 | } 441 | 442 | if (diff) { 443 | unsigned char header = STBIW_UCHAR(len - 1); 444 | s->func(s->context, &header, 1); 445 | for (k = 0; k < len; ++k) { 446 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp); 447 | } 448 | } 449 | else { 450 | unsigned char header = STBIW_UCHAR(len - 129); 451 | s->func(s->context, &header, 1); 452 | stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin); 453 | } 454 | } 455 | } 456 | } 457 | return 1; 458 | } 459 | 460 | int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data) 461 | { 462 | stbi__write_context s; 463 | stbi__start_write_callbacks(&s, func, context); 464 | return stbi_write_tga_core(&s, x, y, comp, (void *)data); 465 | } 466 | 467 | #ifndef STBI_WRITE_NO_STDIO 468 | int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data) 469 | { 470 | stbi__write_context s; 471 | if (stbi__start_write_file(&s, filename)) { 472 | int r = stbi_write_tga_core(&s, x, y, comp, (void *)data); 473 | stbi__end_write_file(&s); 474 | return r; 475 | } 476 | else 477 | return 0; 478 | } 479 | #endif 480 | 481 | // ************************************************************************************************* 482 | // Radiance RGBE HDR writer 483 | // by Baldur Karlsson 484 | 485 | #define stbiw__max(a, b) ((a) > (b) ? (a) : (b)) 486 | 487 | void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear) 488 | { 489 | int exponent; 490 | float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2])); 491 | 492 | if (maxcomp < 1e-32f) { 493 | rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0; 494 | } 495 | else { 496 | float normalize = (float)frexp(maxcomp, &exponent) * 256.0f / maxcomp; 497 | 498 | rgbe[0] = (unsigned char)(linear[0] * normalize); 499 | rgbe[1] = (unsigned char)(linear[1] * normalize); 500 | rgbe[2] = (unsigned char)(linear[2] * normalize); 501 | rgbe[3] = (unsigned char)(exponent + 128); 502 | } 503 | } 504 | 505 | void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte) 506 | { 507 | unsigned char lengthbyte = STBIW_UCHAR(length + 128); 508 | STBIW_ASSERT(length + 128 <= 255); 509 | s->func(s->context, &lengthbyte, 1); 510 | s->func(s->context, &databyte, 1); 511 | } 512 | 513 | void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data) 514 | { 515 | unsigned char lengthbyte = STBIW_UCHAR(length); 516 | STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code 517 | s->func(s->context, &lengthbyte, 1); 518 | s->func(s->context, data, length); 519 | } 520 | 521 | void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline) 522 | { 523 | unsigned char scanlineheader[4] = { 2, 2, 0, 0 }; 524 | unsigned char rgbe[4]; 525 | float linear[3]; 526 | int x; 527 | 528 | scanlineheader[2] = (width & 0xff00) >> 8; 529 | scanlineheader[3] = (width & 0x00ff); 530 | 531 | /* skip RLE for images too small or large */ 532 | if (width < 8 || width >= 32768) { 533 | for (x = 0; x < width; x++) { 534 | switch (ncomp) { 535 | case 4: /* fallthrough */ 536 | case 3: linear[2] = scanline[x*ncomp + 2]; 537 | linear[1] = scanline[x*ncomp + 1]; 538 | linear[0] = scanline[x*ncomp + 0]; 539 | break; 540 | default: 541 | linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; 542 | break; 543 | } 544 | stbiw__linear_to_rgbe(rgbe, linear); 545 | s->func(s->context, rgbe, 4); 546 | } 547 | } 548 | else { 549 | int c, r; 550 | /* encode into scratch buffer */ 551 | for (x = 0; x < width; x++) { 552 | switch (ncomp) { 553 | case 4: /* fallthrough */ 554 | case 3: linear[2] = scanline[x*ncomp + 2]; 555 | linear[1] = scanline[x*ncomp + 1]; 556 | linear[0] = scanline[x*ncomp + 0]; 557 | break; 558 | default: 559 | linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0]; 560 | break; 561 | } 562 | stbiw__linear_to_rgbe(rgbe, linear); 563 | scratch[x + width * 0] = rgbe[0]; 564 | scratch[x + width * 1] = rgbe[1]; 565 | scratch[x + width * 2] = rgbe[2]; 566 | scratch[x + width * 3] = rgbe[3]; 567 | } 568 | 569 | s->func(s->context, scanlineheader, 4); 570 | 571 | /* RLE each component separately */ 572 | for (c = 0; c < 4; c++) { 573 | unsigned char *comp = &scratch[width*c]; 574 | 575 | x = 0; 576 | while (x < width) { 577 | // find first run 578 | r = x; 579 | while (r + 2 < width) { 580 | if (comp[r] == comp[r + 1] && comp[r] == comp[r + 2]) 581 | break; 582 | ++r; 583 | } 584 | if (r + 2 >= width) 585 | r = width; 586 | // dump up to first run 587 | while (x < r) { 588 | int len = r - x; 589 | if (len > 128) len = 128; 590 | stbiw__write_dump_data(s, len, &comp[x]); 591 | x += len; 592 | } 593 | // if there's a run, output it 594 | if (r + 2 < width) { // same test as what we break out of in search loop, so only true if we break'd 595 | // find next byte after run 596 | while (r < width && comp[r] == comp[x]) 597 | ++r; 598 | // output run up to r 599 | while (x < r) { 600 | int len = r - x; 601 | if (len > 127) len = 127; 602 | stbiw__write_run_data(s, len, comp[x]); 603 | x += len; 604 | } 605 | } 606 | } 607 | } 608 | } 609 | } 610 | 611 | static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data) 612 | { 613 | if (y <= 0 || x <= 0 || data == NULL) 614 | return 0; 615 | else { 616 | // Each component is stored separately. Allocate scratch space for full output scanline. 617 | unsigned char *scratch = (unsigned char *)STBIW_MALLOC(x * 4); 618 | int i, len; 619 | char buffer[128]; 620 | char header[] = "#?RADIANCE\n# Written by stb_image_write.h\nFORMAT=32-bit_rle_rgbe\n"; 621 | s->func(s->context, header, sizeof(header) - 1); 622 | 623 | len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); 624 | s->func(s->context, buffer, len); 625 | 626 | for (i = 0; i < y; i++) 627 | stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*i*x); 628 | STBIW_FREE(scratch); 629 | return 1; 630 | } 631 | } 632 | 633 | int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data) 634 | { 635 | stbi__write_context s; 636 | stbi__start_write_callbacks(&s, func, context); 637 | return stbi_write_hdr_core(&s, x, y, comp, (float *)data); 638 | } 639 | 640 | #ifndef STBI_WRITE_NO_STDIO 641 | int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data) 642 | { 643 | stbi__write_context s; 644 | if (stbi__start_write_file(&s, filename)) { 645 | int r = stbi_write_hdr_core(&s, x, y, comp, (float *)data); 646 | stbi__end_write_file(&s); 647 | return r; 648 | } 649 | else 650 | return 0; 651 | } 652 | #endif // STBI_WRITE_NO_STDIO 653 | 654 | 655 | ////////////////////////////////////////////////////////////////////////////// 656 | // 657 | // PNG writer 658 | // 659 | 660 | // stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size() 661 | #define stbiw__sbraw(a) ((int *) (a) - 2) 662 | #define stbiw__sbm(a) stbiw__sbraw(a)[0] 663 | #define stbiw__sbn(a) stbiw__sbraw(a)[1] 664 | 665 | #define stbiw__sbneedgrow(a,n) ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a)) 666 | #define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0) 667 | #define stbiw__sbgrow(a,n) stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a))) 668 | 669 | #define stbiw__sbpush(a, v) (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v)) 670 | #define stbiw__sbcount(a) ((a) ? stbiw__sbn(a) : 0) 671 | #define stbiw__sbfree(a) ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0) 672 | 673 | static void *stbiw__sbgrowf(void **arr, int increment, int itemsize) 674 | { 675 | int m = *arr ? 2 * stbiw__sbm(*arr) + increment : increment + 1; 676 | void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int) * 2) : 0, itemsize * m + sizeof(int) * 2); 677 | STBIW_ASSERT(p); 678 | if (p) { 679 | if (!*arr) ((int *)p)[1] = 0; 680 | *arr = (void *)((int *)p + 2); 681 | stbiw__sbm(*arr) = m; 682 | } 683 | return *arr; 684 | } 685 | 686 | static unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount) 687 | { 688 | while (*bitcount >= 8) { 689 | stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer)); 690 | *bitbuffer >>= 8; 691 | *bitcount -= 8; 692 | } 693 | return data; 694 | } 695 | 696 | static int stbiw__zlib_bitrev(int code, int codebits) 697 | { 698 | int res = 0; 699 | while (codebits--) { 700 | res = (res << 1) | (code & 1); 701 | code >>= 1; 702 | } 703 | return res; 704 | } 705 | 706 | static unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit) 707 | { 708 | int i; 709 | for (i = 0; i < limit && i < 258; ++i) 710 | if (a[i] != b[i]) break; 711 | return i; 712 | } 713 | 714 | static unsigned int stbiw__zhash(unsigned char *data) 715 | { 716 | stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16); 717 | hash ^= hash << 3; 718 | hash += hash >> 5; 719 | hash ^= hash << 4; 720 | hash += hash >> 17; 721 | hash ^= hash << 25; 722 | hash += hash >> 6; 723 | return hash; 724 | } 725 | 726 | #define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount)) 727 | #define stbiw__zlib_add(code,codebits) \ 728 | (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush()) 729 | #define stbiw__zlib_huffa(b,c) stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c) 730 | // default huffman tables 731 | #define stbiw__zlib_huff1(n) stbiw__zlib_huffa(0x30 + (n), 8) 732 | #define stbiw__zlib_huff2(n) stbiw__zlib_huffa(0x190 + (n)-144, 9) 733 | #define stbiw__zlib_huff3(n) stbiw__zlib_huffa(0 + (n)-256,7) 734 | #define stbiw__zlib_huff4(n) stbiw__zlib_huffa(0xc0 + (n)-280,8) 735 | #define stbiw__zlib_huff(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n)) 736 | #define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n)) 737 | 738 | #define stbiw__ZHASH 16384 739 | 740 | unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality) 741 | { 742 | static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 }; 743 | static unsigned char lengtheb[] = { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; 744 | static unsigned short distc[] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 }; 745 | static unsigned char disteb[] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 }; 746 | unsigned int bitbuf = 0; 747 | int i, j, bitcount = 0; 748 | unsigned char *out = NULL; 749 | unsigned char ***hash_table = (unsigned char***)STBIW_MALLOC(stbiw__ZHASH * sizeof(char**)); 750 | if (quality < 5) quality = 5; 751 | 752 | stbiw__sbpush(out, 0x78); // DEFLATE 32K window 753 | stbiw__sbpush(out, 0x5e); // FLEVEL = 1 754 | stbiw__zlib_add(1, 1); // BFINAL = 1 755 | stbiw__zlib_add(1, 2); // BTYPE = 1 -- fixed huffman 756 | 757 | for (i = 0; i < stbiw__ZHASH; ++i) 758 | hash_table[i] = NULL; 759 | 760 | i = 0; 761 | while (i < data_len - 3) { 762 | // hash next 3 bytes of data to be compressed 763 | int h = stbiw__zhash(data + i)&(stbiw__ZHASH - 1), best = 3; 764 | unsigned char *bestloc = 0; 765 | unsigned char **hlist = hash_table[h]; 766 | int n = stbiw__sbcount(hlist); 767 | for (j = 0; j < n; ++j) { 768 | if (hlist[j] - data > i - 32768) { // if entry lies within window 769 | int d = stbiw__zlib_countm(hlist[j], data + i, data_len - i); 770 | if (d >= best) best = d, bestloc = hlist[j]; 771 | } 772 | } 773 | // when hash table entry is too long, delete half the entries 774 | if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2 * quality) { 775 | STBIW_MEMMOVE(hash_table[h], hash_table[h] + quality, sizeof(hash_table[h][0])*quality); 776 | stbiw__sbn(hash_table[h]) = quality; 777 | } 778 | stbiw__sbpush(hash_table[h], data + i); 779 | 780 | if (bestloc) { 781 | // "lazy matching" - check match at *next* byte, and if it's better, do cur byte as literal 782 | h = stbiw__zhash(data + i + 1)&(stbiw__ZHASH - 1); 783 | hlist = hash_table[h]; 784 | n = stbiw__sbcount(hlist); 785 | for (j = 0; j < n; ++j) { 786 | if (hlist[j] - data > i - 32767) { 787 | int e = stbiw__zlib_countm(hlist[j], data + i + 1, data_len - i - 1); 788 | if (e > best) { // if next match is better, bail on current match 789 | bestloc = NULL; 790 | break; 791 | } 792 | } 793 | } 794 | } 795 | 796 | if (bestloc) { 797 | int d = (int)(data + i - bestloc); // distance back 798 | STBIW_ASSERT(d <= 32767 && best <= 258); 799 | for (j = 0; best > lengthc[j + 1] - 1; ++j); 800 | stbiw__zlib_huff(j + 257); 801 | if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]); 802 | for (j = 0; d > distc[j + 1] - 1; ++j); 803 | stbiw__zlib_add(stbiw__zlib_bitrev(j, 5), 5); 804 | if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]); 805 | i += best; 806 | } 807 | else { 808 | stbiw__zlib_huffb(data[i]); 809 | ++i; 810 | } 811 | } 812 | // write out final bytes 813 | for (; i < data_len; ++i) 814 | stbiw__zlib_huffb(data[i]); 815 | stbiw__zlib_huff(256); // end of block 816 | // pad with 0 bits to byte boundary 817 | while (bitcount) 818 | stbiw__zlib_add(0, 1); 819 | 820 | for (i = 0; i < stbiw__ZHASH; ++i) 821 | (void) stbiw__sbfree(hash_table[i]); 822 | STBIW_FREE(hash_table); 823 | 824 | { 825 | // compute adler32 on input 826 | unsigned int s1 = 1, s2 = 0; 827 | int blocklen = (int)(data_len % 5552); 828 | j = 0; 829 | while (j < data_len) { 830 | for (i = 0; i < blocklen; ++i) s1 += data[j + i], s2 += s1; 831 | s1 %= 65521, s2 %= 65521; 832 | j += blocklen; 833 | blocklen = 5552; 834 | } 835 | stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8)); 836 | stbiw__sbpush(out, STBIW_UCHAR(s2)); 837 | stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8)); 838 | stbiw__sbpush(out, STBIW_UCHAR(s1)); 839 | } 840 | *out_len = stbiw__sbn(out); 841 | // make returned pointer freeable 842 | STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len); 843 | return (unsigned char *)stbiw__sbraw(out); 844 | } 845 | 846 | static unsigned int stbiw__crc32(unsigned char *buffer, int len) 847 | { 848 | static unsigned int crc_table[256] = 849 | { 850 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 851 | 0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 852 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 853 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 854 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 855 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 856 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 857 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 858 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 859 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 860 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 861 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 862 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 863 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 864 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 865 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 866 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 867 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 868 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 869 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 870 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 871 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 872 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 873 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 874 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 875 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 876 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 877 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 878 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 879 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 880 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 881 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 882 | }; 883 | 884 | unsigned int crc = ~0u; 885 | int i; 886 | for (i = 0; i < len; ++i) 887 | crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)]; 888 | return ~crc; 889 | } 890 | 891 | #define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4) 892 | #define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v)); 893 | #define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3]) 894 | 895 | static void stbiw__wpcrc(unsigned char **data, int len) 896 | { 897 | unsigned int crc = stbiw__crc32(*data - len - 4, len + 4); 898 | stbiw__wp32(*data, crc); 899 | } 900 | 901 | static unsigned char stbiw__paeth(int a, int b, int c) 902 | { 903 | int p = a + b - c, pa = abs(p - a), pb = abs(p - b), pc = abs(p - c); 904 | if (pa <= pb && pa <= pc) return STBIW_UCHAR(a); 905 | if (pb <= pc) return STBIW_UCHAR(b); 906 | return STBIW_UCHAR(c); 907 | } 908 | 909 | // @OPTIMIZE: provide an option that always forces left-predict or paeth predict 910 | unsigned char *stbi_write_png_to_mem(unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len) 911 | { 912 | int ctype[5] = { -1, 0, 4, 2, 6 }; 913 | unsigned char sig[8] = { 137,80,78,71,13,10,26,10 }; 914 | unsigned char *out, *o, *filt, *zlib; 915 | signed char *line_buffer; 916 | int i, j, k, p, zlen; 917 | 918 | if (stride_bytes == 0) 919 | stride_bytes = x * n; 920 | 921 | filt = (unsigned char *)STBIW_MALLOC((x*n + 1) * y); if (!filt) return 0; 922 | line_buffer = (signed char *)STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; } 923 | for (j = 0; j < y; ++j) { 924 | static int mapping[] = { 0,1,2,3,4 }; 925 | static int firstmap[] = { 0,1,0,5,6 }; 926 | int *mymap = (j != 0) ? mapping : firstmap; 927 | int best = 0, bestval = 0x7fffffff; 928 | for (p = 0; p < 2; ++p) { 929 | for (k = p ? best : 0; k < 5; ++k) { // @TODO: clarity: rewrite this to go 0..5, and 'continue' the unwanted ones during 2nd pass 930 | int type = mymap[k], est = 0; 931 | unsigned char *z = pixels + stride_bytes*j; 932 | for (i = 0; i < n; ++i) 933 | switch (type) { 934 | case 0: line_buffer[i] = z[i]; break; 935 | case 1: line_buffer[i] = z[i]; break; 936 | case 2: line_buffer[i] = z[i] - z[i - stride_bytes]; break; 937 | case 3: line_buffer[i] = z[i] - (z[i - stride_bytes] >> 1); break; 938 | case 4: line_buffer[i] = (signed char)(z[i] - stbiw__paeth(0, z[i - stride_bytes], 0)); break; 939 | case 5: line_buffer[i] = z[i]; break; 940 | case 6: line_buffer[i] = z[i]; break; 941 | } 942 | for (i = n; i < x*n; ++i) { 943 | switch (type) { 944 | case 0: line_buffer[i] = z[i]; break; 945 | case 1: line_buffer[i] = z[i] - z[i - n]; break; 946 | case 2: line_buffer[i] = z[i] - z[i - stride_bytes]; break; 947 | case 3: line_buffer[i] = z[i] - ((z[i - n] + z[i - stride_bytes]) >> 1); break; 948 | case 4: line_buffer[i] = z[i] - stbiw__paeth(z[i - n], z[i - stride_bytes], z[i - stride_bytes - n]); break; 949 | case 5: line_buffer[i] = z[i] - (z[i - n] >> 1); break; 950 | case 6: line_buffer[i] = z[i] - stbiw__paeth(z[i - n], 0, 0); break; 951 | } 952 | } 953 | if (p) break; 954 | for (i = 0; i < x*n; ++i) 955 | est += abs((signed char)line_buffer[i]); 956 | if (est < bestval) { bestval = est; best = k; } 957 | } 958 | } 959 | // when we get here, best contains the filter type, and line_buffer contains the data 960 | filt[j*(x*n + 1)] = (unsigned char)best; 961 | STBIW_MEMMOVE(filt + j*(x*n + 1) + 1, line_buffer, x*n); 962 | } 963 | STBIW_FREE(line_buffer); 964 | zlib = stbi_zlib_compress(filt, y*(x*n + 1), &zlen, 8); // increase 8 to get smaller but use more memory 965 | STBIW_FREE(filt); 966 | if (!zlib) return 0; 967 | 968 | // each tag requires 12 bytes of overhead 969 | out = (unsigned char *)STBIW_MALLOC(8 + 12 + 13 + 12 + zlen + 12); 970 | if (!out) return 0; 971 | *out_len = 8 + 12 + 13 + 12 + zlen + 12; 972 | 973 | o = out; 974 | STBIW_MEMMOVE(o, sig, 8); o += 8; 975 | stbiw__wp32(o, 13); // header length 976 | stbiw__wptag(o, "IHDR"); 977 | stbiw__wp32(o, x); 978 | stbiw__wp32(o, y); 979 | *o++ = 8; 980 | *o++ = STBIW_UCHAR(ctype[n]); 981 | *o++ = 0; 982 | *o++ = 0; 983 | *o++ = 0; 984 | stbiw__wpcrc(&o, 13); 985 | 986 | stbiw__wp32(o, zlen); 987 | stbiw__wptag(o, "IDAT"); 988 | STBIW_MEMMOVE(o, zlib, zlen); 989 | o += zlen; 990 | STBIW_FREE(zlib); 991 | stbiw__wpcrc(&o, zlen); 992 | 993 | stbiw__wp32(o, 0); 994 | stbiw__wptag(o, "IEND"); 995 | stbiw__wpcrc(&o, 0); 996 | 997 | STBIW_ASSERT(o == out + *out_len); 998 | 999 | return out; 1000 | } 1001 | 1002 | #ifndef STBI_WRITE_NO_STDIO 1003 | STBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes) 1004 | { 1005 | FILE *f; 1006 | int len; 1007 | unsigned char *png = stbi_write_png_to_mem((unsigned char *)data, stride_bytes, x, y, comp, &len); 1008 | if (png == NULL) return 0; 1009 | f = fopen(filename, "wb"); 1010 | if (!f) { STBIW_FREE(png); return 0; } 1011 | fwrite(png, 1, len, f); 1012 | fclose(f); 1013 | STBIW_FREE(png); 1014 | return 1; 1015 | } 1016 | #endif 1017 | 1018 | STBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes) 1019 | { 1020 | int len; 1021 | unsigned char *png = stbi_write_png_to_mem((unsigned char *)data, stride_bytes, x, y, comp, &len); 1022 | if (png == NULL) return 0; 1023 | func(context, png, len); 1024 | STBIW_FREE(png); 1025 | return 1; 1026 | } 1027 | 1028 | #endif // STB_IMAGE_WRITE_IMPLEMENTATION 1029 | 1030 | /* Revision history 1031 | 1.04 (2017-03-03) 1032 | monochrome BMP expansion 1033 | 1.03 ??? 1034 | 1.02 (2016-04-02) 1035 | avoid allocating large structures on the stack 1036 | 1.01 (2016-01-16) 1037 | STBIW_REALLOC_SIZED: support allocators with no realloc support 1038 | avoid race-condition in crc initialization 1039 | minor compile issues 1040 | 1.00 (2015-09-14) 1041 | installable file IO function 1042 | 0.99 (2015-09-13) 1043 | warning fixes; TGA rle support 1044 | 0.98 (2015-04-08) 1045 | added STBIW_MALLOC, STBIW_ASSERT etc 1046 | 0.97 (2015-01-18) 1047 | fixed HDR asserts, rewrote HDR rle logic 1048 | 0.96 (2015-01-17) 1049 | add HDR output 1050 | fix monochrome BMP 1051 | 0.95 (2014-08-17) 1052 | add monochrome TGA output 1053 | 0.94 (2014-05-31) 1054 | rename private functions to avoid conflicts with stb_image.h 1055 | 0.93 (2014-05-27) 1056 | warning fixes 1057 | 0.92 (2010-08-01) 1058 | casts to unsigned char to fix warnings 1059 | 0.91 (2010-07-17) 1060 | first public release 1061 | 0.90 first internal release 1062 | */ 1063 | 1064 | /* 1065 | ------------------------------------------------------------------------------ 1066 | This software is available under 2 licenses -- choose whichever you prefer. 1067 | ------------------------------------------------------------------------------ 1068 | ALTERNATIVE A - MIT License 1069 | Copyright (c) 2017 Sean Barrett 1070 | Permission is hereby granted, free of charge, to any person obtaining a copy of 1071 | this software and associated documentation files (the "Software"), to deal in 1072 | the Software without restriction, including without limitation the rights to 1073 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 1074 | of the Software, and to permit persons to whom the Software is furnished to do 1075 | so, subject to the following conditions: 1076 | The above copyright notice and this permission notice shall be included in all 1077 | copies or substantial portions of the Software. 1078 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1079 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1080 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1081 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1082 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 1083 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 1084 | SOFTWARE. 1085 | ------------------------------------------------------------------------------ 1086 | ALTERNATIVE B - Public Domain (www.unlicense.org) 1087 | This is free and unencumbered software released into the public domain. 1088 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this 1089 | software, either in source code form or as a compiled binary, for any purpose, 1090 | commercial or non-commercial, and by any means. 1091 | In jurisdictions that recognize copyright laws, the author or authors of this 1092 | software dedicate any and all copyright interest in the software to the public 1093 | domain. We make this dedication for the benefit of the public at large and to 1094 | the detriment of our heirs and successors. We intend this dedication to be an 1095 | overt act of relinquishment in perpetuity of all present and future rights to 1096 | this software under copyright law. 1097 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1098 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1099 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 1100 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 1101 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 1102 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 1103 | ------------------------------------------------------------------------------ 1104 | */ --------------------------------------------------------------------------------