-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.s
440 lines (398 loc) · 11.1 KB
/
main.s
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
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
.data
half: .double 0.5
tiny: .double 0.00000001
.text
.globl main
main:
# Stack usage: 52 bytes
# 0($sp) camera ray (48 bytes)
# - 0($sp) location vector (0,8,16)
# - 24($sp) direction vector (24,32,40)
# 48($sp) return address (4 bytes)
addi $sp, $sp, -52
sw $ra, 48($sp)
# Open the output file
la $a0, filename
li $a1, 0x8101 # _O_WRONLY | _O_CREAT | _O_BINARY
li $a2, 0x0180 # _S_IREAD | _S_IWRITE
li $v0, 13 # open
syscall
move $s4, $v0 # save the file descriptor into $s4
# Write the bitmap header
move $a0, $s4
la $t0, width
lw $a1, 0($t0) # width
la $t0, height
lw $a2, 0($t0) # height
move $s0, $a1 # save the width
move $s1, $a2 # and height
jal bmp.write_header
jal scene.init # Initialize the Scene
# The camera ray's position never changes, so load it here.
la $t0, camera
l.d $f0, 0($t0)
s.d $f0, 0($sp)
l.d $f0, 8($t0)
s.d $f0, 8($sp)
l.d $f0, 16($t0)
s.d $f0, 16($sp)
# For each pixel in the image
li $s3, 0 # y coord of current pixel
main.loop1:
li $s2, 0 # x coord of current pixel
main.loop2:
# Compute the camera ray
# Move Right to $f0-$f4
la $t0, camera
l.d $f0, 48($t0)
l.d $f2, 56($t0)
l.d $f4, 64($t0)
jal unit.v # Compute Magnitude/Unit Vector
la $t1, half
l.d $f12, 0($t1) # Move constant .5 to $f12
mtc1 $s2, $f14 # Move x to $f14 and make it a double
cvt.d.w $f14, $f14
add.d $f14, $f14, $f12 # Add .5 to x
mul.d $f30, $f30, $f14 # Multiply |right|*(x+.5)
mtc1 $s0, $f14 # Move number of pixels to $f14, make it a double
cvt.d.w $f14, $f14
div.d $f30, $f30, $f14 # Divide $f30 by number of pixels
# Multiply Unit Vector by Scalar
mul.d $f6, $f24, $f30
mul.d $f8, $f26, $f30
mul.d $f10, $f28, $f30
# Load Up
l.d $f0, 72($t0)
l.d $f2, 80($t0)
l.d $f4, 88($t0)
jal unit.v # Compute Unit Vector/Magnitude
mtc1 $s3, $f14 # Move y to $f14
cvt.d.w $f14, $f14 # Make y a double
add.d $f14, $f14, $f12 # Add .5 to y
mul.d $f30, $f30, $f14 # Multiply |up|*(y+.5)
mtc1 $s1, $f14 # Move number of pixels to $f14
cvt.d.w $f14, $f14 # Make it a double
div.d $f30, $f30, $f14 # Divide by number of pixels
# Multiply Unit Vector by Scalar
mul.d $f0, $f24, $f30
mul.d $f2, $f26, $f30
mul.d $f4, $f28, $f30
jal add.v # Add the Two Vectors
# Load Corner
l.d $f0, 24($t0)
l.d $f2, 32($t0)
l.d $f4, 40($t0)
# Add Corner to Frame Vector
add.d $f0, $f0, $f24
add.d $f2, $f2, $f26
add.d $f4, $f4, $f28
# Load Camera Postion
l.d $f6, 0($t0)
l.d $f8, 8($t0)
l.d $f10, 16($t0)
jal sub.v # Subtract Camera from Frame Vector
# Move Result to $f0-$f4
mov.d $f0, $f24
mov.d $f2, $f26
mov.d $f4, $f28
jal unit.v # Get Direction to Pixel
# Store Ray Direction to Stack
s.d $f24, 24($sp)
s.d $f26, 32($sp)
s.d $f28, 40($sp)
# Trace that ray to get a color
add $a0, $sp, $zero # Set argument to point to ray on stack
la $t0, recurseLevels
lw $a1, 0($t0) # Number of Recursive Levels
jal raytrace # Call raytrace on ray in stack
jal clip # Normalize Output of raytrace
li $t0, 0xff
mtc1 $t0, $f28 # Move 256 To $f28
cvt.d.w $f28, $f28 # Convert 256 To Double
mul.d $f0, $f0, $f28 # Convert $f0 To Color
mul.d $f2, $f2, $f28 # Convert $f2 To Color
mul.d $f4, $f4, $f28 # Convert $f4 To Color
# Make Colors Integers
cvt.w.d $f0, $f0
cvt.w.d $f2, $f2
cvt.w.d $f4, $f4
# Output that pixel to the output file
move $a0, $s4 # file descriptor
#li $a1, 0xff # R
mfc1 $a1, $f0 # Move R from $f0
#li $a2, 0xff # G
mfc1 $a2, $f2 # Move G from $f2
#li $a3, 0xff # B
mfc1 $a3, $f4 # Move B from $f4
jal bmp.write_pixel
addi $s2, $s2, 1 # move to the next column
bne $s2, $s0 main.loop2
addi $s3, $s3, 1 # move to the next row
bne $s3, $s1 main.loop1
# End for
# Close the file and exit
move $a0, $s4
li $v0, 16 # close
syscall
lw $ra, 48($sp)
addi $sp, $sp, 52
jr $ra
# The Ray Tracing Algorithm
# Inputs:
# $a0 pointer to a ray
# $a1 recursion levels left
# Output:
# <f0, f2, f4> 3-vector for the color
raytrace:
bgt $a1, $zero, cont1
mtc1 $zero, $f0
cvt.d.w $f0, $f0
mov.d $f2, $f0
mov.d $f4, $f0
jr $ra # Return if recursion levels left is <= 0
cont1:
# Allocate Space on the Stack
# Need 21 Additional Words on Stack (12 for reflected ray, 6 for color, 1 for $ra, 2 for $s0-1)
# $fp := previous $fp, $sp := previous $sp (2 extra words on stack)
sw $fp, -4($sp)
addi $fp, $sp, -4
sw $sp, -88($fp)
addi $sp, $fp, -88
sw $ra, -4($fp) # Put $ra on stack
sw $s0, -8($fp) # Put $s0 on stack
sw $s1, -12($fp) # Put $s1 on stack
# Use $s0 to store $a1 accross calls
add $s0, $a1, $zero # Store $a1
# Use $s1 to store pointer to nearest object
add $s1, $zero, $zero # Initialize Nearest object to "NULL"
jal nearestHit # Get the closest hit object
bne $v0, $zero, aHit # Has there been a hit?
# No hit, set color to black (or background color)
la $t0, background
l.d $f0, 0($t0)
l.d $f2, 8($t0)
l.d $f4, 16($t0)
j endTrace
aHit:
add $s1, $v1, $zero # Store nearest object's address
add $a1, $v1, $zero # Set nearest object as argument for shadow
jal shadow # Calculate intensity
# Load Object Color
l.d $f6, 8($s1)
l.d $f8, 16($s1)
l.d $f10, 24($s1)
# Multiply intensity times color
mul.d $f0, $f0, $f6
mul.d $f2, $f2, $f8
mul.d $f4, $f4, $f10
# Store point color to stack
s.d $f0, -20($fp)
s.d $f2, -28($fp)
s.d $f4, -36($fp)
# Generate a reflected ray, and call recursively on this ray
add $a1, $s1, $zero # Set argument for reflect
addi $a2, $sp, 4 # Set argument for reflect
jal reflect
add $a0, $sp, 4 # Make reflected ray an argument
addi $a1, $s0, -1 # Decrement $a1
jal raytrace # Call recursively on relfected ray
# NO! addi $gp, $gp, -48 # Delete Reflected Ray From Memory
# Given returned color, add to contribution from shadow/light appropriately
l.d $f28, 32($s1) # Get reflectivity of surface
# Multiply reflectivity times returned value
mul.d $f0, $f0, $f28
mul.d $f2, $f2, $f28
mul.d $f4, $f4, $f28
# Get point color
l.d $f6, -20($fp)
l.d $f8, -28($fp)
l.d $f10, -36($fp)
jal add.v # Add point color and reflected color
# Move Result to f0-f4
mov.d $f0, $f24
mov.d $f2, $f26
mov.d $f4, $f28
endTrace:
lw $ra, -4($fp) # Restore $ra
lw $s0, -8($fp) # Restore $s0
lw $s1, -12($fp) # Restore $s1
lw $fp, 0($fp) # Restore $fp
lw $sp, 0($sp) # Restore $sp
jr $ra
# Calculates the light intensity at a point
# Given:
# $a0 pointer to ray
# $a1 pointer to object
# Returns intensity in <$f0, $f2, $f4>
shadow:
sw $ra, -4($sp) # Put $ra on stack
sw $s0, -8($sp) # Put $s0 on stack
sw $a0, -12($sp) # put $a0 on stack
# There's a spot on the stack for a shadow ray (12 words) 80,88,96,104,112,120
# There's a spot on the stack for a normal vector (6 words) 56,64,72
# There's a spot on the stack for the point of intersection (6 words) 32,40,48
# There's a spot on the stack for the distance to the light (2 words) 24
# There's a spot on the stack for the intensity (6 words) 0,8,16
# 22 Words total on stack
addi $sp, $sp, -140 # Adjust $sp
jal normal # Calculate normal to intersection
# Put normal on stack
s.d $f0, 56($sp)
s.d $f2, 64($sp)
s.d $f4, 72($sp)
jal intersect # Get intersection
mov.d $f30, $f0 # Move $f0 to $f30
# Load Ray Direction
l.d $f0, 24($a0)
l.d $f2, 32($a0)
l.d $f4, 40($a0)
# Multiply distance time direction vector
mul.d $f0, $f0, $f30
mul.d $f2, $f2, $f30
mul.d $f4, $f4, $f30
# Load Ray Source
l.d $f6, 0($a0)
l.d $f8, 8($a0)
l.d $f10, 16($a0)
jal add.v # Add to find intersection point
# Store intersection point to stack
s.d $f24, 32($sp)
s.d $f26, 40($sp)
s.d $f28, 48($sp)
la $t0, lights
lw $s0, 0($t0) # Set $s0 to point to first light source
# Initialize Intensity, put on stack
mtc1 $zero, $f0
cvt.d.w $f0, $f0
s.d $f0, 0($sp)
s.d $f0, 8($sp)
s.d $f0, 16($sp)
nextLight: # Loop through lights
beq $s0, $zero, endLight # Break loop when light pointer is NULL
# Calculate Distance to Light Source (Put on Stack)
# Load Light Source Position
l.d $f0, 8($s0)
l.d $f2, 16($s0)
l.d $f4, 24($s0)
# Load Intersection Point
l.d $f6, 32($sp)
l.d $f8, 40($sp)
l.d $f10, 48($sp)
jal sub.v # Get vector from intersection to light
# Move Result to f0-f4
mov.d $f0, $f24
mov.d $f2, $f26
mov.d $f4, $f28
jal unit.v # Get unit vector pointing to light, and magnitude in f30
s.d $f30, 24($sp) # Put Distance on Stack
# Put a shadow ray in memory
addi $a0, $sp, 80 # Set pointer to appropraite word in stack
# Make the start of the shadow ray start away from the shape
# (So it doesn't find an intersection with an object at distance 0)
la $t0, tiny
l.d $f12, 0($t0)
mul.d $f14, $f12, $f24
add.d $f6, $f6, $f14
mul.d $f14, $f12, $f26
add.d $f8, $f8, $f14
mul.d $f14, $f12, $f28
add.d $f10, $f10, $f14
# Put Intersection point in memory
s.d $f6, 80($sp)
s.d $f8, 88($sp)
s.d $f10, 96($sp)
# Put unit vector in memory
s.d $f24, 104($sp)
s.d $f26, 112($sp)
s.d $f28, 120($sp)
# NO! addi $gp, $gp, 52 # Adjust $gp
jal nearestHit # Call Nearest Hit with shadow ray as argument
beq $v0, $zero, isLight # If No Hit goto isLight
l.d $f2, 24($sp) # Load distance to light
c.lt.d $f2, $f0 # If light is closer than hit, goto isLight
bc1t isLight
j isShadow
isLight:
# Calculate Dot of Normal and Shadow Ray Direction
# Load Intersection Normal
l.d $f0, 56($sp)
l.d $f2, 64($sp)
l.d $f4, 72($sp)
# Load Shadow Ray Direction
l.d $f6, 104($sp)
l.d $f8, 112($sp)
l.d $f10, 120($sp)
jal dot.v # Dot the normals
# If less than zero, goto isShadow
mtc1 $zero, $f28
cvt.d.w $f28, $f28
c.lt.d $f30, $f28
bc1t isShadow
# Optional: Raise Dot product to appropriate power?
# Multiply value times light color
l.d $f0, 32($s0)
l.d $f2, 40($s0)
l.d $f4, 48($s0)
# Multiply Vector times value in $f30
mul.d $f0, $f0, $f30
mul.d $f2, $f2, $f30
mul.d $f4, $f4, $f30
# Add to current intensity Value on Stack
l.d $f6, 0($sp)
l.d $f8, 8($sp)
l.d $f10, 16($sp)
jal add.v # Add intensities
# Store intensity back to Stack
s.d $f24, 0($sp)
s.d $f26, 8($sp)
s.d $f28, 16($sp)
isShadow:
# NO! addi $gp, $gp, -52 # Delete Shadow Ray from Memory
lw $s0, 0($s0) # Set $s0 to Next Light
j nextLight # Loop through lights
endLight:
# Load Diffuse Intensity
l.d $f0, 0($sp)
l.d $f2, 8($sp)
l.d $f4, 16($sp)
la $s0, diffuse # Memory Address of Diffuse Constants
# Load Diffuse Constants
l.d $f6, 0($s0)
l.d $f8, 8($s0)
l.d $f10, 16($s0)
# Calculate Diffuse Intensity
mul.d $f0, $f0, $f6
mul.d $f2, $f2, $f8
mul.d $f4, $f4, $f10
la $s0, ambient # Memory Address of Ambient Constants
# Load Ambient Constants
l.d $f6, 0($s0)
l.d $f8, 8($s0)
l.d $f10, 16($s0)
# Add ambient and diffuse contributions
add.d $f0, $f0, $f6
add.d $f2, $f2, $f8
add.d $f4, $f4, $f10
addi $sp, $sp, 140 # Restore $sp
lw $a0, -12($sp) # Restore $a0
lw $s0, -8($sp) # Restore $s0
lw $ra, -4($sp) # Restore $ra
jr $ra # Return
# Clips the values of a color between zero and 1
# Given:
# Color in <$f0, $f2, $f4>
# Returns value in <$f0, $f2, $f4>
# Uses $f28
clip:
# Move "1" to $f28
li $t0, 1
mtc1 $t0, $f28
cvt.d.w $f28, $f28
# For each component, if it is not less than 1, move 1 to it
c.lt.d 0, $f0, $f28
movf.d $f0, $f28, 0
c.lt.d 0, $f2, $f28
movf.d $f2, $f28, 0
c.lt.d 0, $f4, $f28
movf.d $f4, $f28, 0
jr $ra # Return