-
Notifications
You must be signed in to change notification settings - Fork 0
/
Projects.hs
257 lines (245 loc) · 15.4 KB
/
Projects.hs
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
module Projects
( handlers
) where
import PageTypes
import PageStructure
projectPreview name link image description = do
tag "div" [("class", "preview")] $ do
tag "div" [("class", "image")] $ do
screenshot image "preview image"
tag "div" [("class", "content")] $ do
tag "h2" [] $ do
text name
tag "hr" [] noHtml
tag "div" [("class", "description")] $ do
description
button ("/Projects" ++ link) "Go to project page"
projectLayout head body =
mainLayout (customHead >> head) (body >> popup) [("section", "projects")]
where
customHead = do
script "/scripts/jquery-2.2.0.min.js"
script "/scripts/screenshots.js"
stylesheet "/styles/project.css"
popup = do
tag "div" [("class", "overlay")] noHtml
tag "div" [("class", "popup_container")] $ do
tag "div" [("class", "popup_content")] $ do
tag "div" [("class", "screenshot_popup")] $ do
tag "a" [("href", "javascript:void(0)"), ("class", "close")] $ text "x"
image "" ""
projectsPage urlOptions request =
projectLayout head content
where
head = do
title "Projects"
stylesheet "/styles/project_previews.css"
content = do
projectPreview "Geometry Wars Clone" "/GeoWarsClone" "/images/geometry_wars_clone_v2_small.jpg" $ do
tag "p" [] $ text "A clone of the Xbox Live Arcade game Geometry Wars. A 2D top down shooter on a deformable grid. The grid and particle effects are computed on the GPU using an old-school style of GPGPU using OpenGL textures and shaders."
tag "hr" [("class", "preview_separator")] noHtml
projectPreview "ATA Hackathon Game" "/ATAHackathonGame" "/images/ata_hackathon_game_merged_small.jpg" $ do
tag "p" [] $ text "A 2D arena shooter platformer made during a 48-hour hackathon while working at A Thinking Ape. It features wall-jumping, powerups, and the ability to temporarily remove walls in a circle around you for getting the drop on an enemy, or to shoot through walls."
tag "hr" [("class", "preview_separator")] noHtml
projectPreview "Deferred Renderer" "/DeferredRenderer" "/images/deferred_renderer_small.jpg" $ do
tag "p" [] $ text "A 3D rendering engine that implements real-time bump mapping, deferred rendering, and ambient occlusion. Using the depth information generated during the deferred rendering process, occlusion information for each pixel is calculated in screen-space using a randomly oriented sampling of nearby points."
tag "hr" [("class", "preview_separator")] noHtml
projectPreview "Geometry Wars Clone (old)" "/GeoWarsCloneOld" "/images/GWClone_dragon.jpg" $ do
tag "p" [] $ text "An old attempt at making a Geometry Wars clone. Particles and grid effects are implemented on the CPU and are rendered with OpenGL 1.0's glBegin and glEnd. The outdated technologies used is what motivated creating a new version."
tag "hr" [("class", "preview_separator")] noHtml
projectPreview "2D Lighting Demo" "/LightingDemo" "/images/LightingDemo1_web.jpg" $ do
tag "p" [] $ text "A lighting demo to test the creation of 2D shadows. Shadows are generated by calculating the geometry of the shadows and then using it to create a mask for each light."
tag "hr" [("class", "preview_separator")] noHtml
projectPreview "Paradox Tower" "/ParadoxTower" "/images/paradox_tower.jpg" $ do
tag "p" [] $ text "A top-down 2D adventure game created during the Global Game Jam, a 48-hour game jam."
tag "hr" [("class", "preview_separator")] noHtml
projectPreview "Spring Physics Demo" "/SpringPhysics" "/images/spring_physics.jpg" $ do
tag "p" [] $ text "An attempt to create a game about a living ball of slime that can change the surface tension of its skin in order to jump. This uses a collection of springs to simulate the ball of slime. Unfortunately Euler integration was used, which lead to some instability in the slime ball."
geometryWarsPage urlOptions request =
projectLayout head content
where
head =
title "Geometry Wars Clone"
content = do
tag "div" [("class", "right_info")] $ do
tag "div" [] $ text "Sept. 2014 - Dec. 2014"
tag "div" [] $ text "Scala and LWJGL"
tag "h1" [] $ text "Geometry Wars Clone"
tag "hr" [] noHtml
youtube_video "Xv-3VLCFOQM" 560 315
projectSection "Description" $ do
tag "p" [] $ do
text "A clone of the game "
link "http://en.wikipedia.org/wiki/Geometry_Wars" "Geometry Wars"
text " including a bloom effect, a huge number of particles, and a deformable grid (also implemented as particles). "
text "Uses framebuffers to store particle position and velocity, allowing all particle simulation to be done on the GPU using shaders."
tag "h3" [] $ text "Particle Simulation"
tag "p" [] $ text "Sparks and the deformable grid are simulated using an old-school style GPGPU technique to simluate them as particles. Particles' positions and velocities are stored as textures on the GPU where the index of each pixel represents each particle, and the red and green values represent the x and y components of each vector. The sparks don't have any acceleration after being created, so all that's needed is the elapsed time to calculate the next position and velocity for each particle. Sparks are then rendered by passing in geometry data with each index to access to draw the particle."
screenshot "/images/particles_overview.jpg" "Particle System Overview"
tag "p" [] $ text "Because the grid experiences variable acceleration, the process is more complex. Each intersection point is simulated as a particle as before, but there's two sources of acceleration it can experience: push forces from objects in the game, and pull forces from the elasticity of the grid."
tag "p" [] $ text "In order to have multiple push effects on the grid, an acceleration texture is generated in screen space, where each pixel represents the acceleration that a particle at that position would experience from objects in the game."
screenshot "/images/particles_grid_acceleration.jpg" "Grid Accelerations"
tag "p" [] $ text "This is combined with the pull force from the elasticity of the grid that pulls the grid particle back towards its initial position with strength proportional to its distance from that initial position. Initial positions are stored in another texture thats used when updating the grid particles."
tag "h3" [] $ text "Improvements"
tag "p" [] $ text "There's a couple improvements I could make to the particle simulation, both of which weren't done initially because I was just learning how to use shaders to do more complex tasks, and wanted to keep things simple. First of all, positions and velocities could live in the same texture with the red and green components being the position and blue and alpha components being the velocity. Also instead of keeping a separate texture for the grid particles' initial positions, they could be generated on the fly in the shader using the indices passed in. Besides reducing the required video memory by more than half (going from 5 textures to 2 textures), this would also likely reduce cache misses while updating particles."
projectSection "Screenshots" $ do
screenshot "/images/geometry_wars_clone_v2_small.jpg" "Particles everywhere!"
projectSection "Downloads" $ do
button "https://github.com/TerranceN/Geometry-Wars-Clone-V2" "Source"
geometryWarsOldPage urlOptions request =
projectLayout head content
where
head =
title "Geometry Wars Clone (old)"
content = do
tag "div" [("class", "right_info")] $ do
tag "div" [] $ text "Feb. 2011 - June. 2011"
tag "div" [] $ text "Java and LWJGL"
tag "h1" [] $ text "Geometry Wars Clone (old)"
tag "hr" [] noHtml
youtube_video "2-HFsanORGw" 560 315
projectSection "Description" $ do
tag "p" [("class", "noindent")] $ do
text "See the new, updated version "
link "/Projects/GeoWarsClone/" "here"
tag "p" [("class", "noindent")] $ do
text "A clone of the Xbox Live Arcade game "
link "http://en.wikipedia.org/wiki/Geometry_Wars" "Geometry Wars."
projectSection "Screenshots" $ do
screenshot "/images/GWClone_grid.jpg" "Grid Effects"
screenshot "/images/GWClone_dragon.jpg" "Dragons!"
projectSection "Downloads" $ do
tag "p" [] $ text "Doesn't currently work on Macs, sorry!"
button "/files/Geometry_Wars_Clone.zip" "JAR"
button "https://github.com/TerranceN/GeometryWarsClone" "Source"
ataHackathonPage urlOptions request =
projectLayout head content
where
head =
title "ATA Hackathon Game"
content = do
tag "div" [("class", "right_info")] $ do
tag "div" [] $ text "Apr. 8-10 2014"
tag "div" [] $ text "Java and LibGDX"
tag "h1" [] $ text "ATA Hackathon Game"
tag "hr" [] noHtml
youtube_video "y7BLvpp1HlY" 560 315
projectSection "Description" $ do
tag "p" [] $ do
text "A 2D multiplayer platformer deathmatch game with wall-jumping, dashing, and the ability to surround yourself with a 'null sphere' that lets you temporarily phase through walls. Created for a 48-hour hackathon while working for my previous employer "
link "http://www.athinkingape.com/" "A Thinking Ape"
text " with a team of 2 other engineers on co-op there ("
link "http://www.almostmatt.com/matthew-hyndman/" "Matt Hyndman"
text ", and "
link "https://twitter.com/ggollmer" "Geoff Gollmer"
text "), as well as two full-time artists ("
link "http://www.joelfurtado.com/" "Joel Furtado"
text ", and "
link "http://mechanical-bunnies.com/" "Jennifer Duong"
text ")."
tag "h3" [] $ text "My Contributions"
tag "p" [] $ do
text "My main responsibilities on the team was collision, including wall jumping, level wrapping, and the null spheres, and some visual effects like the desaturation effect for the null spheres, and (after the hackathon) adding a heat distortion effect on players bullets."
tag "p" [("class", "noindent")] $ do
text "You can see the full list of my contributions on GitHub "
link "https://github.com/TerranceN/ATAHackathonW14/commits/master?author=TerranceN" "here"
text "."
projectSection "Screenshots" $ do
screenshot "/images/ata_hackathon_game_merged_small.jpg" "Game"
projectSection "Downloads" $ do
button "https://github.com/TerranceN/ATAHackathonW14" "Source"
deferredRendererPage urlOptions request =
projectLayout head content
where
head =
title "Deferred Renderer"
content = do
tag "div" [("class", "right_info")] $ do
tag "div" [] $ text "Sept. 2013 - Oct. 2013"
tag "div" [] $ text "Scala and LWJGL"
tag "h1" [] $ text "Deferred Renderer"
tag "hr" [] noHtml
youtube_video "eJY72rMtFx4" 560 315
projectSection "Description" $ do
tag "p" [] $ do
text "3D Renderer that stores all albedo, depth, normal, and specular information into a series of textures,"
text " then combines those textures and lighting information to make the final image."
text " This allows lighting calculations to be done once per pixel, instead of once per fragnent."
tag "p" [] $ do
text "The renderer also computes ambient occlusion information using the scene information in the G-Buffer."
text " Ambient occlusion is computed in a style similar to Crysis, but uses normal-oriented hemispheres instead of full spheres."
text " This allows the normal map to be used, allowing for fine details in the computed occlusion map."
projectSection "Screenshots" $ do
screenshot "/images/deferred_renderer_small.jpg" "Game"
projectSection "Downloads" $ do
button "https://github.com/TerranceN/Deferred-Renderer" "Source"
springPhysicsPage urlOptions request =
projectLayout head content
where
head =
title "Spring Physics Demo"
content = do
tag "div" [("class", "right_info")] $ do
tag "div" [] $ text "Feb. 2012 - March. 2012"
tag "div" [] $ text "C++ and SFML"
tag "h1" [] $ text "Spring Physics Demo"
tag "hr" [] noHtml
youtube_video "OS00DNj0GgI" 560 315
projectSection "Description" $ do
tag "p" [] $ do
text "A physics simulation of a blob of springs that can control its own springiness."
projectSection "Downloads" $ do
button "/files/SpringPhysicsW32.zip" "Windows"
button "/files/SpringPhysicsLinux.zip" "Linux"
button "https://github.com/TerranceN/SpringPhysicsDemo" "Source"
lightingDemoPage urlOptions request =
projectLayout head content
where
head =
title "2D Lighting Demo"
content = do
tag "div" [("class", "right_info")] $ do
tag "div" [] $ text "Oct. 2011 - Jan. 2012"
tag "div" [] $ text "Java and LWJGL"
tag "h1" [] $ text "2D Lighting Demo"
tag "hr" [] noHtml
projectSection "Description" $ do
tag "p" [] $ do
text "This demo creates and displays shadow geometry based on arbitrary shapes in the scene. Coded in Java with "
link "http://www.lwjgl.org/" "LWJGL"
text ", and was worked on from Oct. 2011 to Jan. 2012."
projectSection "Screenshots" $ do
screenshot "/images/LightingDemo1_web.jpg" ""
screenshot "/images/LightingDemo2_web.jpg" ""
projectSection "Downloads" $ do
tag "p" [] $ text "Doesn't currently work on Macs, sorry!"
button "/files/2DShadows.zip" "JAR"
button "https://github.com/TerranceN/2DLightingDemo" "Source"
paradoxTowerPage urlOptions request =
projectLayout head content
where
head =
title "Paradox Tower"
content = do
tag "div" [("class", "right_info")] $ do
tag "div" [] $ text "Global Game Jam 2012"
tag "div" [] $ text "Java"
tag "h1" [] $ text "Paradox Tower"
tag "hr" [] noHtml
tag "p" [] $ do
text "This project is hosted on the Global Jam Jam site "
link "http://archive.globalgamejam.org/2012/paradox-tower" "here"
text "."
handlers :: [Handler]
handlers =
[(exactly "/", projectsPage)
,(exactly "/geowarsclone/", geometryWarsPage)
,(exactly "/geowarscloneold/", geometryWarsOldPage)
,(exactly "/atahackathongame/", ataHackathonPage)
,(exactly "/deferredrenderer/", deferredRendererPage)
-- Also catch this typo since I used it in old versions of my resume
,(exactly "/deferedrenderer/", deferredRendererPage)
,(exactly "/springphysics/", springPhysicsPage)
,(exactly "/lightingdemo/", lightingDemoPage)
,(exactly "/paradoxtower/", paradoxTowerPage)
]