206 lines
5.7 KiB
Plaintext
206 lines
5.7 KiB
Plaintext
#import "math.kl"
|
|
|
|
Epsilon :: 0.00001
|
|
Screen : *U32
|
|
X : S64
|
|
Y : S64
|
|
TotalTime: F64
|
|
LightPos := Vec3{2,4,2}
|
|
|
|
SphereSDF :: (pos: Vec3): F32
|
|
result := Vec3_Length(pos) - 1.0
|
|
return result
|
|
|
|
Raymarcher_Update :: ()
|
|
up := Vec3{0, 1, 0}
|
|
forward := Vec3{0, 0, -1}
|
|
side := Vec3_Normalize(Vec3_Cross(forward, up))
|
|
|
|
LightPos.x = cosf(TotalTime->F32)*4
|
|
LightPos.y = sinf(TotalTime->F32)*4
|
|
|
|
ambient_color := Vec3{0.2,0.2,0.2}
|
|
diffuse_color := Vec3{0.7,0.2,0.2}
|
|
specular_color := Vec3{1,1,1}
|
|
eye := Vec3{0, 0, 2}
|
|
light_intensity :: 1.2
|
|
|
|
Xf := 1 / X->F32
|
|
Yf := 1 / Y->F32
|
|
ratio := X->F32 / Y->F32
|
|
for y := 0, y < Y, y+=1
|
|
for x := 0, x < X, x+=1
|
|
uv := Vec3{x->F32 * Xf * 2 - 1, y->F32 * Yf * 2 - 1, 1.0}
|
|
uv.x *= ratio
|
|
dir := Vec3_Normalize(Vec3{Vec3_Dot(side, uv), Vec3_Dot(up, uv), Vec3_Dot(forward, uv)})
|
|
|
|
t: F32
|
|
end: F32 = 100.0
|
|
hit := true
|
|
p: Vec3
|
|
for i := 0, i < 255, i+=1
|
|
p = Vec3_Add(eye, Vec3_MulF32(dir, t))
|
|
|
|
distance := SphereSDF(p)
|
|
if distance < Epsilon
|
|
break
|
|
|
|
t += distance
|
|
if distance >= end
|
|
hit = false
|
|
break
|
|
|
|
if hit
|
|
normal := Vec3_Normalize(Vec3{
|
|
SphereSDF({p.x + Epsilon, p.y, p.z}) - SphereSDF({p.x - Epsilon, p.y, p.z}),
|
|
SphereSDF({p.x, p.y + Epsilon, p.z}) - SphereSDF({p.x, p.y - Epsilon, p.z}),
|
|
SphereSDF({p.x, p.y, p.z + Epsilon}) - SphereSDF({p.x, p.y, p.z - Epsilon}),
|
|
})
|
|
|
|
light_to_point := Vec3_Normalize(Vec3_Sub(LightPos, p))
|
|
eye_to_point := Vec3_Normalize(Vec3_Sub(eye, p))
|
|
reflected_light := Vec3_Normalize(Vec3_Reflect(Vec3_Negate(light_to_point), normal))
|
|
|
|
ambient :: 0.2
|
|
diffuse := Vec3_Dot(normal, light_to_point)
|
|
|
|
color := Vec3_MulF32(ambient_color, ambient)
|
|
if diffuse > Epsilon
|
|
color = Vec3_Add(color, Vec3_MulF32(diffuse_color, diffuse))
|
|
|
|
specular := Vec3_Dot(reflected_light, eye_to_point)
|
|
if specular > Epsilon
|
|
specular = specular*specular*specular*specular
|
|
color = Vec3_Add(color, Vec3_MulF32(specular_color, specular*0.2))
|
|
color = Vec3_MulF32(color, light_intensity)
|
|
|
|
// Gamma correction
|
|
color.x = sqrtf(color.x)
|
|
color.y = sqrtf(color.y)
|
|
color.z = sqrtf(color.z)
|
|
Screen[x + y*X] = Vec3_ConvertToARGB(color)
|
|
|
|
else;; Screen[x + y*X] = 0
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////
|
|
//
|
|
// Windows specific code
|
|
//
|
|
|
|
#import "base.kl"
|
|
#import "arena.kl"
|
|
#import "os_windows.kl"
|
|
#import "kernel32.kl"
|
|
#import "gdi32.kl"
|
|
#import "user32.kl"
|
|
#import "winmm.kl"
|
|
|
|
Windows_Bitmap :: struct
|
|
size: Vec2I
|
|
data: *U32
|
|
hdc: HDC
|
|
dib: HBITMAP
|
|
|
|
CreateBitmap :: (size: Vec2I, bottom_up: Bool = true): Windows_Bitmap
|
|
result: Windows_Bitmap = {size = size}
|
|
if bottom_up == false
|
|
result.size.y = -result.size.y
|
|
|
|
header_size: U32 = SizeOf(BITMAPINFOHEADER)
|
|
Assert(header_size == 40)
|
|
bminfo := BITMAPINFO{
|
|
BITMAPINFOHEADER{
|
|
biSize = header_size,
|
|
biWidth = size.x->LONG,
|
|
biHeight = size.y->LONG,
|
|
biPlanes = 1,
|
|
biBitCount = 32,
|
|
biCompression = BI_RGB,
|
|
biXPelsPerMeter = 1,
|
|
biYPelsPerMeter = 1,
|
|
}
|
|
}
|
|
|
|
hdc := GetDC(0)
|
|
result.dib = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS, (&result.data)->**void, 0, 0)
|
|
result.hdc = CreateCompatibleDC(hdc)
|
|
return result
|
|
|
|
|
|
AppIsRunning := true
|
|
WindowProc :: (hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM): LRESULT
|
|
if msg == WM_DESTROY
|
|
PostQuitMessage(0)
|
|
AppIsRunning = false
|
|
return 0
|
|
else;; return DefWindowProcW(hwnd, msg, wparam, lparam)
|
|
|
|
WinMain :: (hInstance: HINSTANCE, hPrevInstance: HINSTANCE, lpCmdLine: LPSTR, nShowCmd: int): int
|
|
if good_scheduling := false, timeBeginPeriod(1) == TIMERR_NOERROR
|
|
good_scheduling = true
|
|
|
|
dpi_aware_set := SetProcessDPIAware()
|
|
Assert(dpi_aware_set != 0)
|
|
|
|
arena: Arena
|
|
|
|
window_name := StringToString16(&arena, "Have a wonderful day! 你好世界 ")
|
|
w := WNDCLASSW{
|
|
lpfnWndProc = WindowProc,
|
|
hInstance = hInstance,
|
|
lpszClassName = window_name.str,
|
|
}
|
|
Assert(RegisterClassW(&w) != 0)
|
|
|
|
screen_size: Vec2I = {1280, 720}
|
|
window := CreateWindowExW(
|
|
dwExStyle = 0, hWndParent = 0, hMenu = 0, lpParam = 0,
|
|
X = CW_USEDEFAULT, Y = CW_USEDEFAULT, nWidth = screen_size.x->int, nHeight = screen_size.y->int,
|
|
lpClassName = window_name.str,
|
|
lpWindowName = window_name.str,
|
|
dwStyle = WS_OVERLAPPEDWINDOW,
|
|
hInstance = hInstance
|
|
)
|
|
Assert(window != 0)
|
|
ShowWindow(window, nShowCmd)
|
|
|
|
window_dc := GetDC(window)
|
|
bitmap := CreateBitmap(screen_size)
|
|
|
|
requested_time_per_frame := 1.0 / 60.0
|
|
frame_start_time := Time()
|
|
frame_number: S64
|
|
for AppIsRunning
|
|
msg: MSG
|
|
for PeekMessageW(&msg, window, 0, 0, PM_REMOVE) > 0
|
|
TranslateMessage(&msg)
|
|
DispatchMessageW(&msg)
|
|
|
|
Screen = bitmap.data; X = bitmap.size.x; Y = bitmap.size.y
|
|
Raymarcher_Update()
|
|
|
|
|
|
SelectObject(bitmap.hdc, bitmap.dib)
|
|
BitBlt(window_dc, 0, 0, (bitmap.size.x)->int, (bitmap.size.y)->int, bitmap.hdc, 0, 0, SRCCOPY)
|
|
|
|
|
|
frame_time := Time() - frame_start_time
|
|
frame_number += 1
|
|
TotalTime += frame_time
|
|
if frame_time < requested_time_per_frame
|
|
if good_scheduling
|
|
time_to_sleep := (requested_time_per_frame - frame_time) * 1000
|
|
if time_to_sleep > 0
|
|
time_to_sleep_dword := time_to_sleep->DWORD
|
|
// @check if time_to_sleep_dword truncates down
|
|
Sleep(time_to_sleep_dword)
|
|
|
|
new_frame_time := Time()
|
|
for new_frame_time < requested_time_per_frame
|
|
new_frame_time = Time() - frame_start_time
|
|
|
|
frame_time = new_frame_time
|