summaryrefslogtreecommitdiff
path: root/ball-sim.asm
blob: 769def21376ce5757f2049fee00266f64b4a136f (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
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