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
|
format ELF64
initial_width = 800
initial_height = 450
FLAG_MSAA_4X_HINT = 32
struc splat x {
dd x, x, x, x
}
struc Vec2 x,y {
dd x, y, 0.0, 0.0
}
struc Ball x, y, r {
.pos Vec2 x, y
.vel splat 0.0
.rad splat r
}
public _start
extrn SetConfigFlags
extrn InitWindow
extrn SetTargetFPS
extrn WindowShouldClose
extrn GetMouseWheelMove
extrn IsMouseButtonDown
extrn GetMousePosition
extrn GetScreenWidth
extrn GetScreenHeight
extrn BeginDrawing
extrn EndDrawing
extrn ClearBackground
extrn DrawCircleV
extrn _exit
section '.text' executable
_start:
; enable anti-aliasing
mov edi, FLAG_MSAA_4X_HINT
call SetConfigFlags
; initialise window
mov edi, initial_width
mov esi, initial_height
mov rdx, title
call InitWindow
; 60 fps
mov edi, 60
call SetTargetFPS
jmp loop_entr
main_loop:
; change ball size
call GetMouseWheelMove
shufps xmm0, xmm0, 0x0
addps xmm0, [ball.rad]
maxps xmm0, [minimum_radius]
movlps [ball.rad], xmm0
; check if lmb is pressed
xor edi, edi
call IsMouseButtonDown
test eax, eax
jz no_click
; accelerate ball towards mouse
call GetMousePosition
subps xmm0, [ball.pos]
mulps xmm0, [mouse_seek_speed]
jmp move_and_draw
no_click:
; get width/height
call GetScreenWidth
mov ebx, eax
call GetScreenHeight
; convert width/height to packed single precision floats
cvtsi2ss xmm0, ebx
cvtsi2ss xmm1, eax
movlhps xmm0, xmm1
shufps xmm0, xmm0, 0x8
; load ball position and radius
movlps xmm1, [ball.pos]
movlps xmm2, [ball.rad]
; calculate upper boundaries
subps xmm0, xmm2
; stash boundaries for later
movaps xmm3, xmm2
movaps xmm4, xmm0
; dirty, rotten, low-down, no-good hack
cmpnleps xmm2, xmm1 ; out of left/top bounds mask
cmpltps xmm0, xmm1 ; out of right/bottom bounds mask
orps xmm0, xmm2 ; or the masks
andps xmm0, [restitution_minus_one] ; mask & restitution coefficient minus one
addps xmm0, [ones] ; add ones to create bounce vector (0.0 -> 1.0, restitution - 1.0 -> restitution)
maxps xmm1, xmm3
minps xmm1, xmm4 ; keep position in bounds
; scale velocity by bounce vector
mulps xmm0, [ball.vel]
; apply air resistance and gravity
mulps xmm0, [air_resistance_coef]
addps xmm0, [grav_accel]
; store position
movlps [ball.pos], xmm1
move_and_draw:
; store velocity
movlps [ball.vel], xmm0
; move ball
addps xmm0, [ball.pos]
movlps [ball.pos], xmm0
; draw frame
call BeginDrawing
; black background
xor edi, edi
call ClearBackground
; sphere
movlps xmm0, [ball.pos]
movss xmm1, [ball.rad]
mov rdi, 0xFF2C7500 ; green
call DrawCircleV
call EndDrawing
loop_entr:
call WindowShouldClose
test eax, eax
jz main_loop
xor edi, edi
call _exit
section '.data' writable align 16
mouse_seek_speed splat 0.5
minimum_radius splat 2.5
air_resistance_coef splat 0.99
restitution_minus_one splat -1.8
ones splat 1.0
grav_accel Vec2 0.0, 0.69
ball Ball 400.0, 250.0, 25.0
title db 'ball simulator',0
|