tui_geometry.inc
8l_HeavyThing/tui_geometry.inc
	; ------------------------------------------------------------------------
	; HeavyThing x86_64 assembly language library and showcase programs
	; Copyright Â© 2015, 2016 2 Ton Digital 
	; Homepage: https://2ton.com.au/
	; Author: Jeff Marrison <jeff@2ton.com.au>
	;       
	; This file is part of the HeavyThing library.
	;       
	; HeavyThing is free software: you can redistribute it and/or modify
	; it under the terms of the GNU General Public License, or
	; (at your option) any later version.
	;       
	; HeavyThing is distributed in the hope that it will be useful, 
	; but WITHOUT ANY WARRANTY; without even the implied warranty of
	; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
	; GNU General Public License for more details.
	;       
	; You should have received a copy of the GNU General Public License along
	; with the HeavyThing library. If not, see <http://www.gnu.org/licenses/>.
	; ------------------------------------------------------------------------
	;       
	; tui_geometry.inc: various geometry helpers for our TUI goodies
	; 
	; this is mainly here for reference, though in some cases I do use the
	; functions directly, mostly the math is done directly inline
	;


; the required bytes to hold a point:
point_size = 8

if used point$new | defined include_everything
	; no arguments, returns a heap$alloc'd whopping 8 bytes of space
	; zero-filled (x & y are 0)
falign
point$new:
	prolog	point$new
	mov	edi, 8
	call	heap$alloc
	mov	qword [rax], 0
	epilog
end if

if used point$destroy | defined include_everything
	; reference only, if you want to destroy/delete it just heap$free it
falign
point$destroy:
	prolog	point$destroy
	call	heap$free
	epilog
end if

if used point$new_xy | defined include_everything
	; two arguments: x in edi, y in esi, returns heap$allocated
falign
point$new_xy:
	prolog	point$new_xy
	sub	rsp, 8
	mov	[rsp], edi
	mov	[rsp+4], esi
	mov	edi, 8
	call	heap$alloc
	mov	edi, [rsp]
	mov	[rax], edi
	mov	esi, [rsp+4]
	mov	[rax+4], esi
	add	rsp, 8
	epilog
end if

if used point$new_copy | defined include_everything
	; single argument: point buffer in rdi, returns heap$allocated copy of it
falign
point$new_copy:
	prolog	point$new_copy
	push	rdi
	mov	edi, 8
	call	heap$alloc
	pop	rdi
	mov	rsi, [rdi]
	mov	[rax], rsi
	epilog
end if


if used point$init_xy | defined include_everything
	; three arguments: point buffer in rdi, x in esi, y in edx
	; reference only, you should be doing this yourself, haha
falign
point$init_xy:
	prolog	point$init_xy
	mov	[rdi], esi
	mov	[rdi+4], edx
	epilog
end if


if used point$init_copy | defined include_everything
	; two arguments: point buffer in rdi (destination), point buffer in rsi (source)
	; reference only, you should be doing this yourself, haha
falign
point$init_copy:
	prolog	point$init_copy
	mov	rdx, [rsi]
	mov	[rdi], rdx
	epilog
end if

if used point$add | defined include_everything
	; two arguments: point buffer in rdi (destination), point buffer in rsi (source)
falign
point$add:
	prolog	point$add
	; due to 32bit overflow, have to do them separately
	mov	edx, [rsi]
	mov	ecx, [rsi+4]
	add	dword [rdi], edx
	add	dword [rdi+4], ecx
	epilog
end if


if used point$subtract | defined include_everything
	; two arguments: point buffer in rdi (destination), point buffer in rsi (source)
falign
point$subtract:
	prolog	point$subtract
	mov	edx, [rsi]
	mov	ecx, [rsi+4]
	sub	dword [rdi], edx
	sub	dword [rdi+4], ecx
	epilog
end if


if used point$equals | defined include_everything
	; two arguments: point buffer in rdi, point buffer in rsi
	; returns zero in eax if not, 1 in eax if so
falign
point$equals:
	prolog	point$equals
	mov	rdx, [rsi]
	cmp	[rdi], rdx
	je	.retone
	xor	eax, eax
	epilog
calign
.retone:
	mov	eax, 1
	epilog
end if

	; similar to point insofar as being mostly for reference

rect_size = point_size * 2

if used rect$new | defined include_everything
	; no arguments, returns a heap$alloc'd zeroed rect
falign
rect$new:
	prolog	rect$new
	mov	edi, rect_size
	call	heap$alloc
	mov	qword [rax], 0
	mov	qword [rax+8], 0
	epilog
end if


if used rect$new_coords | defined include_everything
	; edi, esi, edx, ecx == ax, ay, bx, by
	; returns heap$alloc'd new rect
falign
rect$new_coords:
	prolog	rect$new_coords
	sub	rsp, rect_size
	mov	[rsp], edi
	mov	edi, rect_size
	mov	[rsp+4], esi
	mov	[rsp+8], edx
	mov	[rsp+12], ecx
	call	heap$alloc
	mov	rdi, [rsp]
	mov	rsi, [rsp+8]
	mov	[rax], rdi
	mov	[rax+8], rsi
	add	rsp, rect_size
	epilog
end if


if used rect$new_rect | defined include_everything
	; single argument in rdi: rect (source)
	; returns heap$alloc'd new rect
falign
rect$new_rect:
	prolog	rect$new_rect
	push	rdi
	mov	edi, rect_size
	call	heap$alloc
	pop	rdi
	mov	rsi, [rdi]
	mov	rdx, [rdi+8]
	mov	[rax], rsi
	mov	[rax+8], rdx
	epilog
end if

if used rect$new_points | defined include_everything
	; two arguments: point in rdi, point in rsi
	; returns new heap$alloc'd rect
falign
rect$new_points:
	prolog	rect$new_points
	mov	rdx, [rdi]
	mov	rcx, [rsi]
	sub	rsp, rect_size
	mov	[rsp], rdx
	mov	[rsp+8], rcx
	mov	edi, rect_size
	call	heap$alloc
	mov	rdi, [rsp]
	mov	rsi, [rsp+8]
	mov	[rax], rdi
	mov	[rax+8], rsi
	add	rsp, rect_size
	epilog
end if


if used rect$init | defined include_everything
	; single argument: rect in rdi
	; just zeroes it
falign
rect$init:
	prolog	rect$init
	mov	qword [rdi], 0
	mov	qword [rdi+8], 0
	epilog
end if


if used rect$init_coords | defined include_everything
	; five arguments: rect buffer in rdi, then esi, edx, ecx, r8d == ax, ay, bx, by
falign
rect$init_coords:
	prolog	rect$init_coords
	mov	[rdi], esi
	mov	[rdi+4], edx
	mov	[rdi+8], ecx
	mov	[rdi+12], r8d
	epilog
end if


if used rect$init_rect | defined include_everything
	; two arguments: rect buffer in rdi (destination), rect buffer in rsi (source)
falign
rect$init_rect:
	prolog	rect$init_rect
	mov	rdx, [rsi]
	mov	rcx, [rsi+8]
	mov	[rdi], rdx
	mov	[rdi+8], rcx
	epilog
end if


if used rect$init_points | defined include_everything
	; three arguments: rect buffer in rdi, point in rsi, point in rdx
falign
rect$init_points:
	prolog	rect$init_points
	mov	rcx, [rsi]
	mov	r8, [rdx]
	mov	[rdi], rcx
	mov	[rdi+8], r8
	epilog
end if

if used rect$width | defined include_everything
	; single argument: rect in rdi
	; returns width in eax
falign
rect$width:
	prolog	rect$width
	mov	eax, [rdi+8]
	sub	eax, dword [rdi]
	epilog
end if


if used rect$height | defined include_everything
	; single argument: rect in rdi
	; returns height in eax
falign
rect$height:
	prolog	rect$height
	mov	eax, [rdi+12]
	sub	eax, dword [rdi+4]
	epilog
end if

if used rect$dims_into | defined include_everything
	; two arguments: rect buffer in rdi, point (destination) buffer in rdi
falign
rect$dims_into:
	prolog	rect$dims_into
	mov	eax, [rdi+8]
	sub	eax, dword [rdi]	; width
	mov	ecx, [rdi+12]
	sub	ecx, dword [rdi+4]	; height
	mov	[rdi], eax
	mov	[rdi+4], ecx
	epilog
end if

if used rect$move | defined include_everything
	; three arguments: rect buffer in rdi, delta x in esi, delta y in edx
falign
rect$move:
	prolog	rect$move
	add	dword [rdi], esi
	add	dword [rdi+4], edx
	add	dword [rdi+8], esi
	add	dword [rdi+12], edx
	epilog
end if

if used rect$grow | defined include_everything
	; three arguments: rect buffer in rdi, delta x in esi, delta y in edx
falign
rect$grow:
	prolog	rect$grow
	sub	dword [rdi], esi
	sub	dword [rdi+4], edx
	add	dword [rdi+8], esi
	add	dword [rdi+12], edx
	epilog
end if

if used rect$intersect | defined include_everything
	; two arguments: rect buffer in rdi (dest), rect buffer in rsi
falign
rect$intersect:
	prolog	rect$intersect
	mov	edx, [rdi]		; a.x
	mov	ecx, [rdi+8]		; b.x
	mov	r8d, [rsi]		; r.a.x
	mov	r9d, [rsi+8]		; r.b.x
	cmp	edx, r8d
	cmovl	edx, r8d		; a.x = max(a.x, r.a.x)
	cmp	ecx, r9d
	cmovg	ecx, r9d		; b.x = min(b.x, r.b.x)
	mov	[rdi], edx
	mov	[rdi+8], ecx

	mov	edx, [rdi+4]		; a.y
	mov	ecx, [rdi+12]		; b.y
	mov	r8d, [rsi+4]		; r.a.y
	mov	r9d, [rsi+12]		; r.b.y
	cmp	edx, r8d
	cmovl	edx, r8d		; a.y = max(a.y, r.a.y)
	cmp	ecx, r9d
	cmovg	ecx, r9d		; b.y = min(b.y, r.b.y)
	mov	[rdi+4], edx
	mov	[rdi+12], ecx
	epilog
end if

if used rect$union | defined include_everything
	; two arguments: rect buffer in rdi (dest), rect buffer in rsi
falign
rect$union:
	prolog	rect$union
	mov	edx, [rdi]		; a.x
	mov	ecx, [rdi+8]		; b.x
	mov	r8d, [rsi]		; r.a.x
	mov	r9d, [rsi+8]		; r.b.x
	cmp	edx, r8d
	cmovg	edx, r8d		; a.x = min(a.x, r.a.x)
	cmp	ecx, r9d
	cmovl	ecx, r9d		; b.x = max(b.x, r.b.x)
	mov	[rdi], edx
	mov	[rdi+8], ecx

	mov	edx, [rdi+4]		; a.y
	mov	ecx, [rdi+12]		; b.y
	mov	r8d, [rsi+4]		; r.a.y
	mov	r9d, [rsi+12]		; r.b.y
	cmp	edx, r8d
	cmovg	edx, r8d		; a.y = min(a.y, r.a.y)
	cmp	ecx, r9d
	cmovl	ecx, r9d		; b.y = max(b.y, r.b.y)
	mov	[rdi+4], edx
	mov	[rdi+12], ecx
	epilog
end if

if used rect$contains | defined include_everything
	; two arguments: rect buffer in rdi, point buffer in rsi
	; returns zero in eax if not, 1 in eax if so
falign
rect$contains:
	prolog	rect$contains
	mov	edx, [rsi]		; point.x
	mov	ecx, [rsi+4]		; point.y
	cmp	edx, dword [rdi]
	jl	.nope
	cmp	edx, dword [rdi+8]
	jge	.nope
	cmp	ecx, dword [rdi+4]
	jl	.nope
	cmp	ecx, dword [rdi+12]
	jge	.nope
	mov	eax, 1
	epilog
calign
.nope:
	xor	eax, eax
	epilog
end if

if used rect$contains_xy | defined include_everything
	; three arguments: rect buffer in rdi, x in esi, y in edx
	; returns zero in eax if not, 1 in eax if so
falign
rect$contains_xy:
	prolog	rect$contains_xy
	cmp	esi, dword [rdi]
	jl	.nope
	cmp	esi, dword [rdi+8]
	jge	.nope
	cmp	edx, dword [rdi+4]
	jl	.nope
	cmp	edx, dword [rdi+12]
	jge	.nope
	mov	eax, 1
	epilog
calign
.nope:
	xor	eax, eax
	epilog
end if

if used rect$equals | defined include_everything
	; two arguments: rect buffer in rdi, rect buffer in rsi
	; returns zero in eax if not, 1 in eax if so
falign
rect$equals:
	prolog	rect$equals
	mov	rdx, [rsi]
	mov	rcx, [rsi+8]
	cmp	rdx, qword [rdi]
	jne	.nope
	cmp	rcx, qword [rdi+8]
	jne	.nope
	mov	eax, 1
	epilog
calign
.nope:
	xor	eax, eax
	epilog
end if

if used rect$empty | defined include_everything
	; single argument: rect buffer in rdi
	; returns zero in eax if not, 1 in eax if so
falign
rect$empty:
	prolog	rect$empty
	mov	esi, dword [rdi]
	mov	edx, dword [rdi+4]
	cmp	esi, dword [rdi+8]
	jl	.nope
	cmp	edx, dword [rdi+12]
	jl	.nope
	mov	eax, 1
	epilog
calign
.nope:
	xor	eax, eax
	epilog
end if
