Skip to content

Commit dd279c9

Browse files
committed
initial
0 parents  commit dd279c9

File tree

5 files changed

+180
-0
lines changed

5 files changed

+180
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Raytrace in Haskell. Just for fun.

Setup.hs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

raytrace.cabal

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: raytrace
2+
version: 0.1.0.0
3+
-- synopsis:
4+
-- description:
5+
homepage: https://github.com/githubuser/raytrace#readme
6+
license: BSD3
7+
license-file: LICENSE
8+
author: Author name here
9+
maintainer: [email protected]
10+
copyright: 2017 Author name here
11+
category: Web
12+
build-type: Simple
13+
cabal-version: >=1.10
14+
extra-source-files: README.md
15+
16+
executable raytrace
17+
hs-source-dirs: src
18+
main-is: Main.hs
19+
ghc-options: -threaded -rtsopts -with-rtsopts=-N -O2
20+
default-language: Haskell2010
21+
build-depends: base >= 4.7 && < 5
22+
, JuicyPixels >= 3.2 && < 4

src/Main.hs

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
module Main where
2+
3+
import Data.Tuple (swap)
4+
import GHC.Word (Word8)
5+
import Codec.Picture
6+
import Codec.Picture.Types
7+
8+
-- Where is camera pointed ?
9+
maxX = 480
10+
maxY = 240
11+
12+
main :: IO ()
13+
main = do
14+
let objects = [ --Line (Point 0 0 0) (Vector 1 2 1)
15+
--, Line (Point 0 100 0) (Vector 1 (-1) 1)
16+
Plane]
17+
let myPlot = dumbRender maxX maxY objects
18+
let rim = generateImage (\x y -> let (r, g, b) = myPlot !! (x+(maxY-y-1)*maxX) in PixelRGB8 r g b) maxX maxY
19+
-- \let rim = generateFoldImage (\acc -> \x -> \y -> (acc+1, PixelRGB8 (acc `mod` 255) ( 255) (255))) 0 640 480
20+
writePng "test.png" rim
21+
putStrLn "hello world"
22+
23+
enumCoord :: [a] -> [((Int, Int), a)]
24+
enumCoord [] = []
25+
enumCoord xs = let coords = map toCoord (fst <$> zip [0..] xs)
26+
in zip coords xs
27+
where toCoord num = swap $ num `divMod` maxX
28+
29+
type MyPixel = (Word8, Word8, Word8)
30+
class Object a where
31+
draw :: a -> [MyPixel] -> [MyPixel]
32+
33+
34+
data Point = Point Int Int Int deriving Show
35+
data Vector = Vector Int Int Int deriving Show
36+
data Line = Line Point Vector deriving Show
37+
38+
instance Object Line where
39+
draw line plot =
40+
snd . markWhite <$> enumCoord plot
41+
where
42+
markWhite :: ((Int, Int), MyPixel) -> ((Int, Int), MyPixel)
43+
markWhite (screenPoint, pixel) = (screenPoint, newPixel)
44+
where newPixel = if visibleLine screenPoint line then whitePixel else pixel
45+
whitePixel = (200, 200, 200)
46+
visibleLine :: (Int, Int) -> Line -> Bool
47+
visibleLine (sx, sy) (Line (Point x y z) (Vector vx vy vz)) = isTooFar lineY lineZ sy
48+
where deltaK = fromIntegral (sx - x) / fromIntegral vx
49+
lineY = deltaK * fromIntegral vy + fromIntegral y
50+
lineZ = deltaK * fromIntegral vz + fromIntegral z
51+
isTooFar ly lz sy = ((abs . sqrt) $ (fromIntegral sy - ly) ** 2 + lz ** 2) < 30
52+
53+
data Plane = Plane
54+
cameraPos = Point (maxX `div` 2) (maxY * 3 `div` 4) maxX
55+
screenPointToPlanePoint :: (Int, Int) -> Maybe Point
56+
screenPointToPlanePoint (sx, sy) =
57+
let (Point cx cy cz) = cameraPos
58+
-- plane at y=0 allows to simplify equasion
59+
steps = (fromIntegral cy) / (fromIntegral $ cy - sy)
60+
z = (floor $ steps * (fromIntegral cz)) - cz
61+
x = (floor $ steps * (fromIntegral $ cx - sx)) - cx
62+
in
63+
if sy >= cy
64+
then Nothing -- parallel to plane or diverging
65+
else Just $ Point x 0 z
66+
67+
68+
instance Object Plane where
69+
draw plane plot =
70+
snd . markPlane <$> enumCoord plot
71+
where
72+
markPlane :: ((Int, Int), MyPixel) -> ((Int, Int), MyPixel)
73+
markPlane (screenPoint, pixel) = (screenPoint, newPixel)
74+
where newPixel = lineToPixel screenPoint Plane
75+
whitePixel = (200, 200, 200)
76+
blackPixel = (100, 100, 100)
77+
isBlack (Point x _ z) = mx < squareSize && mz < squareSize || mx >= squareSize && mz >= squareSize
78+
where mx = x `mod` (squareSize * 2)
79+
mz = z `mod` (squareSize * 2)
80+
squareSize = 100
81+
lineToPixel :: (Int, Int) -> Plane -> MyPixel
82+
lineToPixel screenPoint _ = case screenPointToPlanePoint screenPoint of Nothing -> pixel
83+
(Just plx) -> if isBlack plx then blackPixel else whitePixel
84+
85+
type Render a = Int -> Int -> [a] -> [MyPixel]
86+
87+
dumbRender :: Object a => Render a
88+
dumbRender x y = foldr draw emptyPlot
89+
where emptyPlot = replicate (x*y) (0, 0, 0)

stack.yaml

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# This file was automatically generated by 'stack init'
2+
#
3+
# Some commonly used options have been documented as comments in this file.
4+
# For advanced use and comprehensive documentation of the format, please see:
5+
# http://docs.haskellstack.org/en/stable/yaml_configuration/
6+
7+
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
8+
# A snapshot resolver dictates the compiler version and the set of packages
9+
# to be used for project dependencies. For example:
10+
#
11+
# resolver: lts-3.5
12+
# resolver: nightly-2015-09-21
13+
# resolver: ghc-7.10.2
14+
# resolver: ghcjs-0.1.0_ghc-7.10.2
15+
# resolver:
16+
# name: custom-snapshot
17+
# location: "./custom-snapshot.yaml"
18+
resolver: lts-9.2
19+
20+
# User packages to be built.
21+
# Various formats can be used as shown in the example below.
22+
#
23+
# packages:
24+
# - some-directory
25+
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
26+
# - location:
27+
# git: https://github.com/commercialhaskell/stack.git
28+
# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
29+
# - location: https://github.com/commercialhaskell/stack/commit/e7b331f14bcffb8367cd58fbfc8b40ec7642100a
30+
# extra-dep: true
31+
# subdirs:
32+
# - auto-update
33+
# - wai
34+
#
35+
# A package marked 'extra-dep: true' will only be built if demanded by a
36+
# non-dependency (i.e. a user package), and its test suites and benchmarks
37+
# will not be run. This is useful for tweaking upstream packages.
38+
packages:
39+
- '.'
40+
# Dependency packages to be pulled from upstream that are not in the resolver
41+
# (e.g., acme-missiles-0.3)
42+
extra-deps: []
43+
44+
# Override default flag values for local packages and extra-deps
45+
flags: {}
46+
47+
# Extra package databases containing global packages
48+
extra-package-dbs: []
49+
50+
# Control whether we use the GHC we find on the path
51+
# system-ghc: true
52+
#
53+
# Require a specific version of stack, using version ranges
54+
# require-stack-version: -any # Default
55+
# require-stack-version: ">=1.4"
56+
#
57+
# Override the architecture used by stack, especially useful on Windows
58+
# arch: i386
59+
# arch: x86_64
60+
#
61+
# Extra directories used by stack for building
62+
# extra-include-dirs: [/path/to/dir]
63+
# extra-lib-dirs: [/path/to/dir]
64+
#
65+
# Allow a newer minor version of GHC than the snapshot specifies
66+
# compiler-check: newer-minor

0 commit comments

Comments
 (0)