summary refs log tree commit diff
path: root/src/IsometricDrawer.c
diff options
context:
space:
mode:
authorWlodekM <[email protected]>2024-06-16 10:35:45 +0300
committerWlodekM <[email protected]>2024-06-16 10:35:45 +0300
commitabef6da56913f1c55528103e60a50451a39628b1 (patch)
treeb3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/IsometricDrawer.c
initial commit
Diffstat (limited to 'src/IsometricDrawer.c')
-rw-r--r--src/IsometricDrawer.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/IsometricDrawer.c b/src/IsometricDrawer.c
new file mode 100644
index 0000000..6e500c5
--- /dev/null
+++ b/src/IsometricDrawer.c
@@ -0,0 +1,170 @@
+#include "IsometricDrawer.h"
+#include "Drawer.h"
+#include "Graphics.h"
+#include "PackedCol.h"
+#include "ExtMath.h"
+#include "Block.h"
+#include "TexturePack.h"
+#include "Block.h"
+#include "Game.h"
+
+static struct VertexTextured* iso_vertices;
+static struct VertexTextured* iso_vertices_base;
+static int* iso_state;
+
+static cc_bool iso_cacheInited;
+static PackedCol iso_colorXSide, iso_colorZSide, iso_colorYBottom;
+static float iso_posX, iso_posY;
+
+#define iso_cosX  (0.86602540378443864f) /* cos(30  * MATH_DEG2RAD) */
+#define iso_sinX  (0.50000000000000000f) /* sin(30  * MATH_DEG2RAD) */
+#define iso_cosY  (0.70710678118654752f) /* cos(-45 * MATH_DEG2RAD) */
+#define iso_sinY (-0.70710678118654752f) /* sin(-45 * MATH_DEG2RAD) */
+
+static void IsometricDrawer_InitCache(void) {
+	if (iso_cacheInited) return;
+
+	iso_cacheInited = true;
+	PackedCol_GetShaded(PACKEDCOL_WHITE,
+		&iso_colorXSide, &iso_colorZSide, &iso_colorYBottom);
+}
+
+static TextureLoc IsometricDrawer_GetTexLoc(BlockID block, Face face) {
+	TextureLoc loc = Block_Tex(block, face);
+	*iso_state++   = Atlas1D_Index(loc);
+	return loc;
+}
+
+static void IsometricDrawer_Flat(BlockID block, float size) {
+	int texIndex;
+	TextureLoc loc = Block_Tex(block, FACE_ZMAX);
+	TextureRec rec = Atlas1D_TexRec(loc, 1, &texIndex);
+
+	struct VertexTextured v;
+	float minX, maxX, minY, maxY;
+	float scale;
+
+	*iso_state++ = texIndex;
+	v.Col = PACKEDCOL_WHITE;
+	Block_Tint(v.Col, block);
+
+	/* Rescale by 0.70 in Classic mode to match vanilla size */
+	/* Rescale by 0.88 in Enhanced mode to be slightly nicer */
+	/*  Default selected size:  54px -> 48px */
+	/*  Default inventory size: 36px -> 32px */
+	/*  Default hotbar size:    28px -> 24px */
+	scale = Game_ClassicMode ? 0.70f : 0.88f;
+	size  = Math_Ceil(size * scale);
+	minX  = iso_posX - size; maxX = iso_posX + size;
+	minY  = iso_posY - size; maxY = iso_posY + size;
+
+	v.z = 0.0f;
+	v.x = minX; v.y = minY; v.U = rec.u1; v.V = rec.v1; *iso_vertices++ = v;
+	            v.y = maxY;               v.V = rec.v2; *iso_vertices++ = v;
+	v.x = maxX;             v.U = rec.u2;               *iso_vertices++ = v;
+	            v.y = minY;               v.V = rec.v1; *iso_vertices++ = v;
+}
+
+static void IsometricDrawer_Angled(BlockID block, float size) {
+	cc_bool bright;
+	Vec3 min, max;
+	struct VertexTextured* beg = iso_vertices;
+	struct VertexTextured* v;
+	float x, y, scale;
+
+	/* isometric coords size: cosY * -scale - sinY * scale */
+	/* we need to divide by (2 * cosY), as the calling function expects size to be in pixels. */
+	scale = size / (2.0f * iso_cosY);
+
+	Drawer.MinBB = Blocks.MinBB[block]; Drawer.MinBB.y = 1.0f - Drawer.MinBB.y;
+	Drawer.MaxBB = Blocks.MaxBB[block]; Drawer.MaxBB.y = 1.0f - Drawer.MaxBB.y;
+	min = Blocks.MinBB[block]; max = Blocks.MaxBB[block];
+
+	Drawer.X1 = scale * (1.0f - min.x * 2.0f);
+	Drawer.X2 = scale * (1.0f - max.x * 2.0f);
+	Drawer.Y1 = scale * (1.0f - min.y * 2.0f);
+	Drawer.Y2 = scale * (1.0f - max.y * 2.0f);
+	Drawer.Z1 = scale * (1.0f - min.z * 2.0f);
+	Drawer.Z2 = scale * (1.0f - max.z * 2.0f);
+
+	bright = Blocks.Brightness[block];
+	Drawer.Tinted  = Blocks.Tinted[block];
+	Drawer.TintCol = Blocks.FogCol[block];
+
+	Drawer_XMax(1, bright ? PACKEDCOL_WHITE : iso_colorXSide,
+		IsometricDrawer_GetTexLoc(block, FACE_XMAX), &iso_vertices);
+	Drawer_ZMin(1, bright ? PACKEDCOL_WHITE : iso_colorZSide,
+		IsometricDrawer_GetTexLoc(block, FACE_ZMIN), &iso_vertices);
+	Drawer_YMax(1, PACKEDCOL_WHITE,
+		IsometricDrawer_GetTexLoc(block, FACE_YMAX), &iso_vertices);
+
+	for (v = beg; v < iso_vertices; v++)
+	{
+		/* Cut down form of: */
+		/*   Matrix_RotateY(&rotY,  45.0f * MATH_DEG2RAD); */
+		/*   Matrix_RotateX(&rotX, -30.0f * MATH_DEG2RAD); */
+		/*   Matrix_Mul(&iso_transform, &rotY, &rotX); */
+		/*   ...                                       */
+		/*   Vec3 vec = { v.x, v.y, v.z }; */
+		/*   Vec3_Transform(&vec, &vec, &iso_transform); */
+		/* With all unnecessary operations either simplified or removed */
+		x = v->x * iso_cosY                              + v->z * -iso_sinY;
+		y = v->x * iso_sinX * iso_sinY + v->y * iso_cosX + v->z * iso_sinX * iso_cosY;
+
+		v->x = x + iso_posX;
+		v->y = y + iso_posY;
+	}
+}
+
+void IsometricDrawer_BeginBatch(struct VertexTextured* vertices, int* state) {
+	IsometricDrawer_InitCache();
+	iso_vertices      = vertices;
+	iso_vertices_base = vertices;
+	iso_state         = state; /* TODO just store TextureLoc ??? */
+}
+
+void IsometricDrawer_AddBatch(BlockID block, float size, float x, float y) {
+	if (Blocks.Draw[block] == DRAW_GAS) return;
+	
+	iso_posX = x; iso_posY = y;
+	/* See comment in Gfx_Make2DQuad() for why 0.5 is subtracted in D3D9 */
+	/* TODO pass as arguments? test diff */
+#if CC_GFX_BACKEND == CC_GFX_BACKEND_D3D9
+	iso_posX -= 0.5f; iso_posY -= 0.5f;
+#endif
+
+	if (Blocks.Draw[block] == DRAW_SPRITE) {
+		IsometricDrawer_Flat(block, size);
+	} else {
+		IsometricDrawer_Angled(block, size);
+	}
+}
+
+int IsometricDrawer_EndBatch(void) {
+	return (int)(iso_vertices - iso_vertices_base);
+}
+
+void IsometricDrawer_Render(int count, int offset, int* state) {
+	int i, curIdx, batchBeg, batchLen;
+
+	curIdx   = state[0];
+	batchLen = 0;
+	batchBeg = offset;
+
+	for (i = 0; i < count / 4; i++, batchLen += 4) 
+	{
+		if (state[i] == curIdx) continue;
+
+		/* Flush previous batch */
+		Gfx_BindTexture(Atlas1D.TexIds[curIdx]);
+		Gfx_DrawVb_IndexedTris_Range(batchLen, batchBeg);
+
+		/* Reset for next batch */
+		curIdx   = state[i];
+		batchBeg += batchLen;
+		batchLen = 0;
+	}
+
+	Gfx_BindTexture(Atlas1D.TexIds[curIdx]);
+	Gfx_DrawVb_IndexedTris_Range(batchLen, batchBeg);
+}