summaryrefslogtreecommitdiff
path: root/hello_obj2.lc
blob: 00ba27cfd1f9cbb4ce53ed6491e64df57ee1f4f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188

coordmap (cam::Mat 4 4 Float) (p::Vec 4 Float)
    = cam *. p

blendplane = -- NoBlending -- BlendLogicOp Xor
    Blend (FuncAdd,FuncAdd)
          ((OneBF,SrcAlpha),(DstAlpha,DstAlpha))
          (V4 0 0 0 0)

point :: Vec 3 Float -> Vec 4 Float
point p = V4 p%x p%y p%z 1

homoproj :: Vec 4 Float -> Vec 3 Float
homoproj v = v%xyz *! (1 / v%w)

type Position = Vec 4 Float
type TextureCoord = Vec 3 Float
type Normal = Vec 3 Float
type Overlay = ( (FragmentOperation Depth, FragmentOperation (Color (VecScalar 4 Float)))
               , FragmentStream 1 ((Vec 4 Float)) )

-- This lighting model ignores the normal vector and simply applies
-- ambient lighting and a texture map.
--
-- "Color on and Ambient off"
-- inputs: Kd, map_Kd
--
-- illum 0 -- color = Kd
ambientOnly :: Mat 4 4 Float -> Vec 4 Float -> Texture -> PrimitiveStream Triangle (Position,TextureCoord,Normal)
                                                       -> Overlay
ambientOnly cam color texture prims = prims
    & mapPrimitives (\(p,n,uvw) -> ( coordmap cam p, V2 uvw%x (1 - uvw%y) ))
    & rasterizePrimitives (TriangleCtx CullBack PolygonFill NoOffset LastVertex) ((Smooth))
    & mapFragments (\((uv)) -> ((color * texture2D (Sampler PointFilter MirroredRepeat texture) uv )))
    & accumulateWith (DepthOp Less True, ColorOp NoBlending (V4 True True True True))

-- ½ ambient + ½ lambertian reflectance
-- lambertian reflectance = (light ∙ normal) * diffuse * intensity
-- I_d = (L ∙ N) C_d I_L
--
-- "Color on and Ambient on"
-- Chrome example indicates: Ka, Kd, Ks, refl
--
-- illum 1 -- color = KaIa + Kd { SUM j=1..ls, (N ∙ Lj)Ij }
--
-- The illum 0 can be implemented using illum 1 code by setting
--   KaIa = Kd
--   Ij = 0 forall j
--
-- The spec seems to require settings for Ia and Ij (j = light number).
-- Ka should probably be calculated similar to Kd: using a Ka_map texture.
lambertianReflectance cam lightpos color texture prims = prims
    & mapPrimitives (\(p,n,uvw) ->
        let light_vector = normalize $ -- light direction from surface
                            if lightpos%w == 0
                                then lightpos%xyz
                                else homoproj lightpos - homoproj p
            lambertian = dot light_vector (normalize n)
          in ( coordmap cam p, V2 uvw%x (1 - uvw%y), lambertian ))
    & rasterizePrimitives (TriangleCtx CullBack PolygonFill NoOffset LastVertex) (Smooth,Smooth)
    & mapFragments (\(uv,lambertian) -> ((color * texture2D (Sampler PointFilter MirroredRepeat texture) uv *! (0.5 + 0.5*lambertian) )))
    & accumulateWith (DepthOp Less True, ColorOp NoBlending (V4 True True True True))


-- Blinn-Phong
--
-- illum 0 -- color = Kd
-- illum 1 -- color = KaIa + Kd { SUM j=1..ls, (N ∙ Lj)Ij }
-- illum 2 -- color = KaIa + Kd { SUM j=1..ls, (N ∙ Lj)Ij } + Ks { SUM j=1..ls, ((H∙Hj)^Ns)Ij }
--
-- The illum 1 can be implemented using illum2 code by setting
--   Ks = 0 (specular reflectance)
--
-- TODO: Add (H∙Hj)^Ns term
--
-- Okay, I don't understand why the spec says H∙Hj.  I think it means N∙Hj.
-- So i'm implementing that.
blinnPhong cam lightpos color texture specular prims = prims
    & mapPrimitives (\(p,n,uvw) ->
        let light_vector = normalize $ -- light direction from surface
                            if lightpos%w == 0
                                then lightpos%xyz
                                else homoproj lightpos - homoproj p
            lambertian = dot light_vector (normalize n)
          in ( coordmap cam p, V2 uvw%x (1 - uvw%y), lambertian, n, p ))
    & rasterizePrimitives (TriangleCtx CullBack PolygonFill NoOffset LastVertex) (Smooth,Smooth,Smooth,Smooth)
    & mapFragments (\(uv,lambertian, n, p) ->
        let ct = texture2D (Sampler PointFilter MirroredRepeat texture) uv
            ns = specular%w
            ks = point $ specular%xyz
            campos = cam *. V4 0 0 0 1
            view_vector = normalize $ homoproj campos - homoproj p
            h = normalize $ light_vector + view_vector
            refl = dot h (normalize n)
            light_vector = normalize $ -- light direction from surface
                            if lightpos%w == 0
                                then lightpos%xyz
                                else homoproj lightpos - homoproj p
        in (( color * ct *! (0.5 + 0.5*lambertian) + if refl>0 then ks *! pow refl ns else zero )) )
    & accumulateWith (DepthOp Less True, ColorOp NoBlending (V4 True True True True))


makeFrame (cubemap :: TextureCube)
          (skybox :: PrimitiveStream Triangle ((Vec 3 Float)))
          (cameraPosition :: Vec 3 Float)
          (cam ::  Mat 4 4 Float)
          (color :: Vec 4 Float)
          (texture :: Texture)
          (specular :: Vec 4 Float)
          (prims0 :: PrimitiveStream Triangle (Vec 4 Float, Vec 3 Float, Vec 3 Float))
          (prims1 :: PrimitiveStream Triangle (Vec 4 Float, Vec 3 Float, Vec 3 Float))
          (prims2 :: PrimitiveStream Triangle (Vec 4 Float, Vec 3 Float, Vec 3 Float))
          (plane :: PrimitiveStream Triangle ((Vec 4 Float)))
          (lines :: PrimitiveStream Line (Vec 3 Float, Vec 3 Float))
          (points :: PrimitiveStream Point (Vec 3 Float, Vec 3 Float))
          (plane_mat :: Mat 4 4 Float)

    = imageFrame (emptyDepthImage 1, emptyColorImage (V4 0 0 0.4 1))
  `overlay`
      skybox
    & mapPrimitives (\((p)) -> let texcoord = V3 p%x (p%y) (p%z)
                                   p' = cam *. point (p + cameraPosition)
                                in (p', texcoord))
    & rasterizePrimitives (TriangleCtx CullNone PolygonFill NoOffset LastVertex) ((Smooth))
    & mapFragments (\((d)) -> (( textureCube cubemap d )))
    & accumulateWith (DepthOp Always False, ColorOp NoBlending (V4 True True True True))
  `overlay` ambientOnly           cam color texture prims0
  `overlay` lambertianReflectance cam (V4 0 20 10 1) color texture prims1
  `overlay` blinnPhong            cam (V4 0 20 10 1) color texture specular prims2
  `overlay`
      plane
    & mapPrimitives (\((p)) -> let p' = coordmap cam $ plane_mat *. p in (p', p%xz))
    & rasterizePrimitives (TriangleCtx CullNone PolygonFill NoOffset LastVertex) ((Smooth))
    & mapFragments (\((uv)) -> let c = mixB zero one (fract uv >= (one *! (0.95::Float)))
                                   r = V4 1 1 1 0 *! (max c%x c%y)
                                in ((r + V4 0 0 0 (0.8))))
    & accumulateWith (DepthOp Less True, ColorOp blendplane (V4 True True True True))
  `overlay`
      lines
    & mapPrimitives (\(p,c) -> let p' = coordmap cam $ point p
                                   w = p'%w
                                   yellowish = normalize c `dot` V3 1 1 0
                                   p2 = if yellowish >= 0.9*sqrt 2
                                            then V4 p'%x p'%y 0.1 w
                                            else V4 p'%x p'%y 0.11 w
                                in (p2, point c))

    & renderPoints cam (LineCtx 1.0 LastVertex)
  `overlay`
      points
    & mapPrimitives (\(p,c) -> let p' = coordmap cam $ point p
                                   w = p'%w
                                   yellowish = normalize c `dot` V3 1 1 0
                                   p2 = if yellowish >= 0.9*sqrt 2
                                            then V4 p'%x p'%y 0.1 w
                                            else V4 p'%x p'%y 0.11 w
                                in (p2, point c))

    & renderPoints cam (PointCtx (PointSize 5.0) 1.0 LowerLeft)

renderPoints ::
   Mat 4 4 Float
   -> RasterContext (Vec 4 Float, Vec 4 Float) pr
   -> PrimitiveStream pr (Vec 4 Float, Vec 4 Float)
   -> ( (FragmentOperation Depth, FragmentOperation (Color (VecScalar 4 Float)))
      , FragmentStream 1 ((Vec 4 Float)) )
renderPoints cam ctx points =
      points
    & rasterizePrimitives ctx ((Flat))
    & mapFragments (\((c)) -> ((c)))
    & accumulateWith (DepthOp Less True, ColorOp NoBlending (V4 True True True True))

main :: Output
main = renderFrame $
   makeFrame (TextureCubeSlot "CubeMap")
             (fetch "SkyCube" ((Attribute "position")))
             (Uniform "CameraPosition")
             (Uniform "ViewProjection")
             (Uniform "diffuseColor")
             (Texture2DSlot "diffuseTexture")
             (Uniform "specularReflectivity")
             (fetch "objects0" (Attribute "position", Attribute "normal", Attribute "uvw"))
             (fetch "objects1" (Attribute "position", Attribute "normal", Attribute "uvw"))
             (fetch "objects2" (Attribute "position", Attribute "normal", Attribute "uvw"))
             (fetch "plane"   ((Attribute "position")))
             (fetch "Curve" (Attribute "position", Attribute "color"))
             (fetch "Points" (Attribute "position", Attribute "color"))
             (Uniform "PlaneModel")