#ifdef INTELLISENSE_DIRECTIVES
#	pragma once
#	include "duffle/dsl.h"
#	include "duffle/math.h"
#	include "duffle/gp.h"
#endif

enum {
	PrimitiveBuff_Len = 4096,
	OrderingTbl_Len   = 2048
};

typedef Struct_(DrawEnv_Packed) { U4 tag; U4 code[15]; };
typedef Struct_(DrawEnv) {
	Rect_S2 clip_area;
	A2_S2   drawing_offset;
	Rect_S2 texture_window;
	S2      texture_page;
	B1      flag_dither;	
	B1      flag_draw_on_display;
	B1      enable_auto_clear;
	RGB8    initial_bg_color;
	DrawEnv_Packed dr_env; // reserved
};
typedef Struct_(DisplayEnv) {
	Rect_S2 display_area;
	Rect_S2 screen;
	B1      vinterlace;
	B1      color24;
	B1      pad0;
	B1      pad1;
};
typedef Array_(DrawEnv,    2);
typedef Array_(DisplayEnv, 2);
typedef Struct_(DoubleBuffer) {
	A2_DrawEnv    draw;
	A2_DisplayEnv display;
};

#define ScreenRes_X 320
#define ScreenRes_Y 240
#define ScreenZ     320
#define ScreenRes_CenterX (ScreenRes_X >> 1)
#define ScreenRes_CenterY (ScreenRes_Y >> 1)

DisplayEnv* displayenv_init(DisplayEnv* env, S4 x, S4 y, S4 w, S4 h) __asm__("SetDefDispEnv");
DrawEnv*    drawenv_init   (DrawEnv*    env, S4 x, S4 y, S4 w, S4 h) __asm__("SetDefDrawEnv");

DisplayEnv* displayenv_put(DisplayEnv* env) __asm__("PutDispEnv");
DrawEnv*    drawenv_put   (DrawEnv*    env) __asm__("PutDrawEnv");

U4   geom_init(void)             __asm__("InitGeom");
void geom_set_offset(U4 x, U4 y) __asm__("SetGeomOffset");
void geom_set_screen(U4 h)       __asm__("SetGeomScreen");

U4* orderingtbl_clear_reverse(U4* ot, U4 len) __asm__("ClearOTagR");

U4 reset_graph(U4 mode)           __asm__("ResetGraph");
void set_display_enabled(U4 mask) __asm__("SetDispMask");

U4 draw_sync(U4 mode) __asm__("DrawSync");
U4 vsync(U4 mode)     __asm__("VSync");

void draw_orderingtbl(U4* buf) __asm__("DrawOTag");

typedef Struct_(Tile) {
	U4      tag;
	RGB8    color;
	B1      code;
	Rect_S2 rect;
};

/*
	Linear Algebra
*/

M3_S2* m3s2_rotation   (V3_S2* vec, M3_S2* mat) __asm__("RotMatrix");
M3_S2* m3s2_translation(M3_S2* mat, V3_S4* vec) __asm__("TransMatrix");
M3_S2* m3s2_scale      (M3_S2* mat, V3_S4* vec) __asm__("ScaleMatrix");

// Rotation, Translation, Perspective

S4 rtp_v3s2_raw(V3_S2* vec, S4* xy, S4* pp, S4* flag) __asm__("RotTransPers");
FI_ S4 rtp_v3s2(V3_S2* vec, V2_S2* xy, A2_S2* pp, S4* flag) { return rtp_v3s2_raw(vec, C_(S4*R_, & xy->x), C_(S4*R_, pp), r_(flag)); }

S4 rtp_avg_nclip_a3_v3s2_raw(V3_S2* v0, V3_S2* v1, V3_S2* v2, S4* xy1, S4* xy2, S4* xy3, S4* pp, S4* otz, S4* flag) __asm__("RotAverageNclip3");
FI_  S4 rtp_avg_nclip_a3_v3s2(
	V3_S2* v0,  V3_S2* v1,  V3_S2* v2, 
	V2_S2* xy0, V2_S2* xy1, V2_S2* xy2, 
	A2_S2* pp, S4* otz, S4* flag
){
	return rtp_avg_nclip_a3_v3s2_raw(
		v0, v1, v2, 
		C_(S4*R_, xy0), C_(S4*R_, xy1), C_(S4*R_, xy2),
		C_(S4*R_, pp),  C_(S4*R_, otz), C_(S4*R_, flag)
	);
}

S4 rtp_avg_nclip_a4_v3s2_raw(V3_S2* v0, V3_S2* v1, V3_S2* v2, V3_S2* v3, S4* xy1, S4* xy2, S4* xy3, S4* xy4, S4* pp, S4* otz, S4* flag) __asm__("RotAverageNclip4");
FI_ S4 rtp_avg_nclip_a4_v3s2(
	V3_S2* v0,  V3_S2* v1,  V3_S2* v2,  V3_S2* v3,
	V2_S2* xy0, V2_S2* xy1, V2_S2* xy2, V2_S2* xy3,
	A2_S2* pp,  S4* otz,    S4* flag
){
	return rtp_avg_nclip_a4_v3s2_raw(
		v0, v1, v2, v3,
		C_(S4*R_, xy0), C_(S4*R_, xy1), C_(S4*R_, xy2), C_(S4*R_, xy3),
		C_(S4*R_, pp),  C_(S4*R_, otz), C_(S4*R_, flag)
	);
}

void gte_matrix_set_rotation   (M3_S2* mat) __asm__("SetRotMatrix");
void gte_matrix_set_translation(M3_S2* mat) __asm__("SetTransMatrix");

enum {
	fp_one = (1 << 12),
};

#define v3s4_fp_one() v3s4(fp_one, fp_one, fp_one)
