From 93d587b314389ece27b7321b764587b027d8ff33 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Sun, 8 Apr 2012 00:29:54 +0200 Subject: [PATCH] Raytracer :-) --- CMakeLists.txt | 3 +- Raytracer/CMakeLists.txt | 22 ++++ Raytracer/raytracer.cc | 254 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 Raytracer/CMakeLists.txt create mode 100644 Raytracer/raytracer.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index feb0d96724..1824985378 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project(Retro) if(CMAKE_SYSTEM_NAME MATCHES Retro68) add_subdirectory(libretro) add_subdirectory(App2) +add_subdirectory(Raytracer) else() add_subdirectory(MakeAPPL) -endif() \ No newline at end of file +endif() diff --git a/Raytracer/CMakeLists.txt b/Raytracer/CMakeLists.txt new file mode 100644 index 0000000000..6abc3a39f1 --- /dev/null +++ b/Raytracer/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 2.8) + +if(NOT APPLE) +set(CMAKE_CXX_FLAGS "-std=c++11") +endif() + +include_directories(../App2) +add_executable(Raytracer MACOSX_BUNDLE + raytracer.cc + ) + +if(APPLE) +target_link_libraries(Raytracer "-framework Carbon") +else() +target_link_libraries(Raytracer retrocrt) +add_custom_command( + OUTPUT Raytracer.bin + COMMAND ${MAKE_APPL} -c Raytracer -o Raytracer + DEPENDS Raytracer) +add_custom_target(RaytracerAPPL ALL DEPENDS Raytracer.bin) +endif() + diff --git a/Raytracer/raytracer.cc b/Raytracer/raytracer.cc new file mode 100644 index 0000000000..34b6e5bc01 --- /dev/null +++ b/Raytracer/raytracer.cc @@ -0,0 +1,254 @@ +#ifdef __APPLE__ +#include +#include +#define PSTR(x) ("\p" x) + +#else + +#include +#include +#include +#include +#include +#include + +#include "MacUtils.h" + +QDGlobals qd; + +#endif + + +#include +#include +#include +#include +#include + +bool hitSphere(float x0, float y0, float z0, float dx, float dy, float dz, float& t) +{ + const float xc = 0.0f, yc = 0.0f, zc = -6.0f, r = 1.0f; + float x0c = x0 - xc; + float y0c = y0 - yc; + float z0c = z0 - zc; + + /* + (x-xc)^2 + (y-yc)^2 + (z-zc)^2 = r^2; + (x0c + dx * t)^2 + (y0c + dy * t)^2 + (z0c + dz * t)^2 = r^2; + x0c^2 + 2*x0c*dx*t + dx^2*t^2 + y0c^2 + 2*y0c*dy*t + dy^2*t^2 + z0c^2 + 2 * z0c*dz*t + dz^2*t^2 = r^2 + + (dx^2 + dy^2 + dz^2)*t^2 + (2*x0c*dx + 2*y0c&dy + 2*z0c*dz) * t + x0c^2+y0c^2+z0c^2-r^2 + */ + float a = dx*dx + dy*dy + dz*dz; + float b = 2*(x0c*dx + y0c*dy + z0c*dz); + float c = x0c*x0c + y0c*y0c + z0c*z0c -r*r; + + float D = b*b - 4 * a * c; + + if(D >= 0) + { + float t = (-b - std::sqrt(D)) / (2*a); + return t >= 0; + } + return false; +} +const float lx = -2, ly = 4, lz = 3; +const float lenl = 1.0f / std::sqrt(lx*lx + ly*ly + lz*lz); +const float lxn = lx*lenl, lyn = ly*lenl, lzn = lz*lenl; + +float ray(int n, float x0, float y0, float z0, float dx, float dy, float dz) +{ + { + const float xc = 0.0f, yc = 0.0f, zc = -6.0f, r = 1.0f; + float x0c = x0 - xc; + float y0c = y0 - yc; + float z0c = z0 - zc; + + /* + (x-xc)^2 + (y-yc)^2 + (z-zc)^2 = r^2; + (x0c + dx * t)^2 + (y0c + dy * t)^2 + (z0c + dz * t)^2 = r^2; + x0c^2 + 2*x0c*dx*t + dx^2*t^2 + y0c^2 + 2*y0c*dy*t + dy^2*t^2 + z0c^2 + 2 * z0c*dz*t + dz^2*t^2 = r^2 + + (dx^2 + dy^2 + dz^2)*t^2 + (2*x0c*dx + 2*y0c&dy + 2*z0c*dz) * t + x0c^2+y0c^2+z0c^2-r^2 + */ + float a = dx*dx + dy*dy + dz*dz; + float b = 2*(x0c*dx + y0c*dy + z0c*dz); + float c = x0c*x0c + y0c*y0c + z0c*z0c -r*r; + + float D = b*b - 4 * a * c; + + if(D >= 0) + { + float t = (-b - std::sqrt(D)) / (2*a); + if(t > 0) + { + float x = x0 + dx * t; + float y = y0 + dy * t; + float z = z0 + dz * t; + + float dx2 = x - xc; + float dy2 = y - yc; + float dz2 = z - zc; + + + float l = dx2 * dx + dy2 * dy + dz2 * dz; + l *= 2; + + float reflected; + if(n) + reflected = ray(n-1, x,y,z, dx - l*dx2, dy - l*dy2, dz - l*dz2); + else + reflected = 0.0f; + + + float lambert = dx2 * lxn + dy2 * lyn + dz2 * lzn; + + return 0.2f + 0.4f * std::max(0.0f,lambert) + 0.4f * reflected; + } + } + } + + if(dy < 0) + { + float t = (-1.5f - y0) / dy; + float x = x0 + dx * t; + float z = z0 + dz * t; + + float color; + if( (static_cast( std::floor(x) ) + + static_cast( std::floor(z) )) % 2 ) + color = 0.8f; + else + color = 0.1f; + + float ts; + if(hitSphere(x,-1.5f,z, lxn, lyn, lzn, ts)) + color *= 0.2f; + + return std::min(1.0f, color + 0.5f * ray(n-1, x,-2.0f,z,dx,-dy,dz)); + } + + return std::max(0.0f, dy * 0.3f); +} + +int main() +{ + WindowPtr win; + +#if !TARGET_API_MAC_CARBON + InitGraf(&qd.thePort); + InitFonts(); + InitWindows(); + InitMenus(); + + Rect r = qd.screenBits.bounds; +#else + BitMap bm; + GetQDGlobalsScreenBits(&bm); + Rect r = bm.bounds; +#endif + SetRect(&r, r.left + 5, r.top + 45, r.right - 5, r.bottom -5); + win = NewWindow(NULL, &r, PSTR("Raytracer"), true, 0, (WindowPtr)-1, false, 0); + +#if !TARGET_API_MAC_CARBON + SetPort(win); + r = win->portRect; +#else + SetPortWindowPort(win); + GetPortBounds(GetWindowPort(win), &r); +#endif + EraseRect(&r); + float accum = 0.0f; + short cx = r.right /2; + short cy = r.bottom / 2; + + long startTime = TickCount(); + std::vector accumV(r.right); + for(int y = 0; y < r.bottom; y++) + { + for(int x = 0; x < r.right; x++) + { + float pixel; + + // cam = (0,0,0) + // ray = t * (x-r.right/2, - (y-r.bottom/2), -1) + // plane: y = -2 + + float dx = x - cx; + float dy = - (y - cy); + float dz = -cx; + float n1 = 1.0f / std::sqrt(dx*dx + dy*dy + dz*dz); + + pixel = ray(1,0,0,0,n1*dx,n1*dy,n1*dz); + +#if 0 + accum += pixel; + if(accum >= 0.5f) + accum -= 1.0f; + else + { + MoveTo(x,y); + Line(0,0); + } +#elif 1 + accum += pixel; + accum += accumV[x]; + if(accum >= 0.5f) + accum -= 1.0f; + else + { + MoveTo(x,y); + Line(0,0); + } + accumV[x] = accum = accum / 2; +#elif 0 + //if(pixel < Random() / 32767.0) + if(pixel < (float)std::rand() / (32767.0f * 65536.0f)) + { + MoveTo(x,y); + Line(0,0); + } +#else + float thresh = (float)std::rand() / (32767.0f * 65536.0f); + thresh = 0.5f + 0.4f * (thresh - 0.5f); + accum += pixel; + accum += accumV[x]; + if(accum >= thresh) + accum -= 1.0f; + else + { + MoveTo(x,y); + Line(0,0); + } + accumV[x] = accum = accum / 2; +#endif + } + if(Button()) + return 0; +#if TARGET_API_MAC_CARBON +// QDFlushPortBuffer(GetWindowPort(win),NULL); +#endif + } + long endTime = TickCount(); + + char buf[256]; + unsigned char* pstr = (unsigned char*)buf; + sprintf(buf+1, "pps = %g", (double)r.right * r.bottom / (endTime - startTime) * 60.0); + buf[0] = std::strlen(buf+1); + + SetRect(&r, 10, 10, 10 + StringWidth(pstr) + 10, 30); + PaintRect(&r); + PenMode(patXor); + FrameRect(&r); + MoveTo(15,25); + TextMode(srcBic); + DrawString(pstr); +#if TARGET_API_MAC_CARBON + QDFlushPortBuffer(GetWindowPort(win),NULL); +#endif + + while(!Button()) + ; + FlushEvents(everyEvent, -1); + return 0; +}