Explorar el Código

Part 8: Tile System

Austin Morlan hace 5 meses
padre
commit
1096c7eac2
Firmado por: Austin Morlan <mail@austinmorlan.com> GPG Key ID: FD6B27654AF5E348

+ 2
- 0
README.md Ver fichero

@@ -19,3 +19,5 @@ if (ret != ESP_OK) {
19 19
 	* `IDF_TOOLS_PATH` is the path to the toolchain
20 20
 * `source export.sh`
21 21
 
22
+![Current Status](https://austinmorlan.com/posts/embedded_game_programming_8/media/demo.gif)
23
+

BIN
assets/export/tiles/black.bmp Ver fichero


BIN
assets/export/tiles/dark_grey.bmp Ver fichero


BIN
assets/export/tiles/light_grey.bmp Ver fichero


BIN
assets/export/tiles/white.bmp Ver fichero


+ 7
- 0
assets/source/palettes/grey.pal Ver fichero

@@ -0,0 +1,7 @@
1
+JASC-PAL
2
+0100
3
+4
4
+255 255 255
5
+171 171 171
6
+84 84 84
7
+0 0 0

BIN
assets/source/tiles/black.aseprite Ver fichero


BIN
assets/source/tiles/dark_grey.aseprite Ver fichero


BIN
assets/source/tiles/light_grey.aseprite Ver fichero


BIN
assets/source/tiles/white.aseprite Ver fichero


+ 164
- 92
game/src/main.c Ver fichero

@@ -15,121 +15,204 @@ static const char* LOG_TAG = "Main";
15 15
 static uint16_t gFramebuffer[LCD_WIDTH * LCD_HEIGHT];
16 16
 
17 17
 
18
-void app_main(void)
18
+static const uint16_t palette[4] =
19 19
 {
20
-	Odroid_InitializeInput();
21
-	Odroid_InitializeDisplay();
22
-	Odroid_InitializeSdcard();
23
-	Odroid_InitializeBatteryReader();
24
-	Odroid_InitializeAudio();
20
+	0xFFFF,
21
+	0x55AD,
22
+	0xAA52,
23
+	0x0000,
24
+};
25 25
 
26
-	// Load sprite
27
-	uint16_t* sprite = (uint16_t*)malloc(64 * 64 * sizeof(uint16_t));
26
+static const uint8_t tiles[][16*16] =
27
+{
28
+	// White
28 29
 	{
29
-		FILE* spriteFile = fopen("/sdcard/key", "r");
30
-		assert(spriteFile);
31
-
32
-		for (int i = 0; i < 64; ++i)
33
-		{
34
-			for (int j = 0; j < 64; ++j)
35
-			{
36
-				fread(sprite, sizeof(uint16_t), 64 * 64, spriteFile);
37
-			}
38
-		}
39
-
40
-		fclose(spriteFile);
41
-	}
42
-
43
-	// Load sound effect
44
-	uint16_t* soundBuffer;
45
-	int soundEffectLength = 1441;
30
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
31
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
32
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
33
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
34
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
35
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
36
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
37
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
38
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
39
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
41
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
42
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
43
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
44
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
45
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
46
+	},
47
+
48
+	// Light Grey
46 49
 	{
47
-		FILE* soundFile = fopen("/sdcard/jump", "r");
48
-		assert(soundFile);
50
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
51
+	0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
52
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
53
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
54
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
55
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
56
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
57
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
58
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
59
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
60
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
61
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
62
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
63
+	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
64
+	0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
65
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
66
+	},
67
+
68
+	// Dark Grey
69
+	{
70
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
71
+	0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,
72
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
73
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
74
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
75
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
76
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
77
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
78
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
79
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
80
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
81
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
82
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
83
+	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
84
+	0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0,
85
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
86
+	},
87
+
88
+	// Black
89
+	{
90
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
91
+	0,0,3,3,3,3,3,3,3,3,3,3,3,3,0,0,
92
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
93
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
94
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
95
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
96
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
97
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
98
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
99
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
100
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
101
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
102
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
103
+	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
104
+	0,0,3,3,3,3,3,3,3,3,3,3,3,3,0,0,
105
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
106
+	},
107
+};
108
+
109
+static int tileBuffer[15][40] =
110
+{
111
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
112
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
113
+	{0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
114
+	{0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0},
115
+	{0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0},
116
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0},
117
+	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0},
118
+	{0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0},
119
+	{0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0},
120
+	{0, 0, 3, 0, 0, 0, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0},
121
+	{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
122
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
123
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
124
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
125
+	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
126
+};
127
+
128
+
129
+void DrawTile(int index, int x, int y)
130
+{
131
+	int startX = x * 16;
132
+	int startY = y * 16;
49 133
 
50
-		uint8_t* soundEffect = malloc(soundEffectLength);
51
-		assert(soundEffect);
134
+	for (int row = 0; row < 16; ++row)
135
+	{
136
+		for (int col = 0; col < 16; ++col)
137
+		{
138
+			uint8_t paletteIndex = tiles[index][row * 16 + col];
52 139
 
53
-		soundBuffer = malloc(soundEffectLength*2);
54
-		assert(soundBuffer);
140
+			int screenY = startY + row;
141
+			int screenX = startX + col;
55 142
 
56
-		fread(soundEffect, soundEffectLength, 1, soundFile);
143
+			uint16_t color = palette[paletteIndex];
57 144
 
58
-		for (int i = 0; i < soundEffectLength; ++i)
59
-		{
60
-			// 16 bits required but only MSB is actually sent to the DAC
61
-			soundBuffer[i] = (soundEffect[i] << 8u);
145
+			gFramebuffer[screenY * LCD_WIDTH + screenX] = color;
62 146
 		}
63 147
 	}
148
+}
64 149
 
65 150
 
66
-	ESP_LOGI(LOG_TAG, "Odroid initialization complete - entering main loop");
151
+void app_main(void)
152
+{
153
+	Odroid_InitializeInput();
154
+	Odroid_InitializeDisplay();
155
+	Odroid_InitializeSdcard();
156
+	Odroid_InitializeBatteryReader();
157
+	Odroid_InitializeAudio();
67 158
 
68
-	int x = 0;
69
-	int y = 0;
159
+	ESP_LOGI(LOG_TAG, "Odroid initialization complete - entering main loop");
70 160
 
71
-	uint16_t color = 0xffff;
72 161
 
73
-	int lastState = 0;
162
+	uint8_t frameIndex = 0;
163
+	char snapFilename[20];
164
+	int xLeft = 0;
74 165
 
75 166
 	for (;;)
76 167
 	{
77
-		memset(gFramebuffer, 0, 320 * 240 * 2);
168
+		memset(gFramebuffer, 0xff, 320*240*2);
78 169
 
79 170
 		Odroid_Input input = Odroid_PollInput();
80 171
 
81
-		if (input.left) { x -= 20; }
82
-		else if (input.right) { x += 20; }
83
-
84
-		if (input.up) { y -= 20; }
85
-		else if (input.down) { y += 20; }
86
-
87
-		if (input.a) { color = SWAP_ENDIAN_16(RGB565(0xff, 0, 0)); }
88
-		else if (input.b) { color = SWAP_ENDIAN_16(RGB565(0, 0xff, 0)); }
89
-		else if (input.start) { color = SWAP_ENDIAN_16(RGB565(0, 0, 0xff)); }
90
-		else if (input.select) { color = SWAP_ENDIAN_16(RGB565(0xff, 0xff, 0xff)); }
91
-
92
-
93
-		int thisState = input.volume;
94
-
95
-		if ((thisState == 1) && (thisState != lastState))
172
+		if (input.left)
96 173
 		{
97
-			Odroid_PlayAudio(soundBuffer, soundEffectLength*2);
98
-		}
99
-
100
-		lastState = thisState;
174
+			xLeft -= 1;
101 175
 
176
+			if (xLeft < 0)
177
+			{
178
+				xLeft = 39;
179
+			}
180
+		}
102 181
 
103
-		DrawText(gFramebuffer, "The Quick Brown Fox", 19, 0, 5, SWAP_ENDIAN_16(RGB565(0xFF, 0, 0)));
104
-		DrawText(gFramebuffer, "Jumped Over The:", 16, 0, 6, SWAP_ENDIAN_16(RGB565(0, 0xFF, 0)));
105
-		DrawText(gFramebuffer, "Lazy Dog?!", 10, 0, 7, SWAP_ENDIAN_16(RGB565(0, 0, 0xFF)));
106
-
182
+		else if (input.right)
183
+		{
184
+			xLeft += 1;
107 185
 
108
-		int spriteRow = 0;
109
-		int spriteCol = 0;
186
+			if (xLeft > 39)
187
+			{
188
+				xLeft = 0;
189
+			}
190
+		}
110 191
 
111
-		for (int row = y; row < y + 64; ++row)
192
+		for (int tileY = 0; tileY < 15; ++tileY)
112 193
 		{
113
-			spriteCol = 0;
114
-
115
-			for (int col = x; col < x + 64; ++col)
194
+			for (int tileX = xLeft; tileX < xLeft + 20; ++tileX)
116 195
 			{
117
-				uint16_t pixelColor = sprite[64 * spriteRow + spriteCol];
196
+				int tile = tileX % 40;
118 197
 
119
-				if (pixelColor != 0)
120
-				{
121
-					gFramebuffer[row * LCD_WIDTH + col] = color;
122
-				}
198
+				int tileIndex = tileBuffer[tileY][tile];
123 199
 
124
-				++spriteCol;
200
+				DrawTile(tileIndex, tileX - xLeft, tileY);
125 201
 			}
126
-
127
-			++spriteRow;
128 202
 		}
129 203
 
204
+
205
+		char string[5];
206
+		snprintf(string, 5, "%02d", xLeft);
207
+		DrawText(gFramebuffer, string, 2, 0, 0, palette[3]);
208
+
209
+		int tileRight = (xLeft + 20) % 40;
210
+		snprintf(string, 5, "%02d", tileRight);
211
+		DrawText(gFramebuffer, string, 2, 18, 0, palette[3]);
212
+
130 213
 		if (input.menu)
131 214
 		{
132
-			const char* snapFilename = "/sdcard/framebuf";
215
+			snprintf(snapFilename, 20, "/sdcard/frame%02d", frameIndex);
133 216
 
134 217
 			ESP_LOGI(LOG_TAG, "Writing snapshot to %s", snapFilename);
135 218
 
@@ -139,19 +222,8 @@ void app_main(void)
139 222
 			fwrite(gFramebuffer, 1, LCD_WIDTH * LCD_HEIGHT * sizeof(gFramebuffer[0]), snapFile);
140 223
 
141 224
 			fclose(snapFile);
142
-		}
143
-
144
-
145
-		uint32_t batteryLevel = Odroid_ReadBatteryLevel();
146
-		ESP_LOGI(LOG_TAG, "Battery level: %u\n", batteryLevel);
147 225
 
148
-		if (batteryLevel < 3600)
149
-		{
150
-			Odroid_EnableBatteryLight();
151
-		}
152
-		else
153
-		{
154
-			Odroid_DisableBatteryLight();
226
+			++frameIndex;
155 227
 		}
156 228
 
157 229
 

+ 2
- 2
game/src/text.c Ver fichero

@@ -8,8 +8,8 @@ static const int MAX_GLYPHS_PER_COL = LCD_HEIGHT / GLYPH_HEIGHT;
8 8
 
9 9
 void DrawText(uint16_t* framebuffer, char* string, int length, int x, int y, uint16_t color)
10 10
 {
11
-	assert(x + length < MAX_GLYPHS_PER_ROW);
12
-	assert(y < MAX_GLYPHS_PER_COL);
11
+	assert(x + length <= MAX_GLYPHS_PER_ROW);
12
+	assert(y <= MAX_GLYPHS_PER_COL);
13 13
 
14 14
 	for (int charIndex = 0; charIndex < length; ++charIndex)
15 15
 	{

+ 3
- 1
tools/CMakeLists.txt Ver fichero

@@ -4,5 +4,7 @@ project(tools)
4 4
 
5 5
 set(CMAKE_C_FLAGS "-Wall -Werror")
6 6
 
7
-add_executable(font_generator src/font_generator.c)
7
+add_executable(font_processor src/font_processor.c)
8
+add_executable(palette_processor src/palette_processor.c)
9
+add_executable(tile_processor src/tile_processor.c)
8 10
 

tools/src/font_generator.c → tools/src/font_processor.c Ver fichero


+ 105
- 0
tools/src/palette_processor.c Ver fichero

@@ -0,0 +1,105 @@
1
+#include <assert.h>
2
+#include <stdlib.h>
3
+#include <stdint.h>
4
+#include <stdio.h>
5
+#include <string.h>
6
+
7
+int main(int argc, char** argv)
8
+{
9
+	if (argc != 3)
10
+	{
11
+		fprintf(stderr, "Usage: %s <input palette> <output header>\n", argv[0]);
12
+
13
+		return 1;
14
+	}
15
+
16
+	const char* inFilename = argv[1];
17
+	const char* outFilename = argv[2];
18
+
19
+	// Read the file
20
+	uint16_t* palette;
21
+	int paletteSize;
22
+	{
23
+		FILE* inFile = fopen(inFilename, "r");
24
+		assert(inFile);
25
+
26
+		char* line;
27
+		size_t len = 0;
28
+
29
+		getline(&line, &len, inFile);
30
+		assert(strncmp(line, "JASC-PAL", 8) == 0);
31
+
32
+		getline(&line, &len, inFile);
33
+		assert(strncmp(line, "0100", 4) == 0);
34
+
35
+		getline(&line, &len, inFile);
36
+		paletteSize = atoi(line);
37
+
38
+		palette = malloc(sizeof(*palette) * paletteSize);
39
+		assert(palette);
40
+
41
+		// Each line is of form R G B
42
+		for (int i = 0; i < paletteSize; ++i)
43
+		{
44
+			getline(&line, &len, inFile);
45
+
46
+			char* tok = strtok(line, " ");
47
+			int red = atoi(tok);
48
+
49
+			tok = strtok(NULL, " ");
50
+			int green = atoi(tok);
51
+
52
+			tok = strtok(NULL, " ");
53
+			int blue = atoi(tok);
54
+
55
+			uint16_t rgb565 =
56
+				  ((red >> 3u) << 11u)
57
+				| ((green >> 2u) << 5u)
58
+				| (blue >> 3u);
59
+
60
+			uint16_t endianSwap = ((rgb565 & 0xFFu) << 8u) | (rgb565 >> 8u);
61
+
62
+			palette[i] = endianSwap;
63
+		}
64
+
65
+		fclose(inFile);
66
+	}
67
+
68
+
69
+	printf("Input: %s\n", inFilename);
70
+	printf("Output: %s\n", outFilename);
71
+	printf("Palette Size: %d\n", paletteSize);
72
+
73
+
74
+	// Output to the file
75
+	{
76
+		FILE* outFile = fopen(outFilename, "w");
77
+		assert(outFile);
78
+
79
+		fprintf(outFile, "// AUTOMATICALLY GENERATED. DO NOT EDIT.\n");
80
+		fprintf(outFile, "\n");
81
+		fprintf(outFile, "#pragma once\n");
82
+		fprintf(outFile, "\n");
83
+		fprintf(outFile, "\n");
84
+
85
+		fprintf(outFile, "uint16_t palette[%d] =\n", paletteSize);
86
+		fprintf(outFile, "{\n");
87
+
88
+		for (int i = 0; i < paletteSize; ++i)
89
+		{
90
+			fprintf(outFile, "	0x%04X,\n", palette[i]);
91
+		}
92
+
93
+		fprintf(outFile, "};\n");
94
+		fprintf(outFile, "\n");
95
+
96
+		fclose(outFile);
97
+	}
98
+
99
+	printf("\n");
100
+	printf("DONE\n");
101
+
102
+
103
+	return 0;
104
+}
105
+

+ 132
- 0
tools/src/tile_processor.c Ver fichero

@@ -0,0 +1,132 @@
1
+#include <assert.h>
2
+#include <ctype.h>
3
+#include <stdint.h>
4
+#include <stdio.h>
5
+#include <stdlib.h>
6
+#include <string.h>
7
+
8
+
9
+int main(int argc, char** argv)
10
+{
11
+	if (argc != 3)
12
+	{
13
+		fprintf(stderr, "Usage: %s <input image> <output header>\n", argv[0]);
14
+
15
+		return 1;
16
+	}
17
+
18
+	const char* inFilename = argv[1];
19
+	const char* outFilename = argv[2];
20
+
21
+
22
+	int tileWidth;
23
+	int tileHeight;
24
+	uint8_t* tileBuffer;
25
+	{
26
+		FILE* inFile = fopen(inFilename, "rb");
27
+		assert(inFile);
28
+
29
+		#pragma pack(push,1)
30
+		struct BmpHeader
31
+		{
32
+			char magic[2];
33
+			uint32_t totalSize;
34
+			uint32_t reserved;
35
+			uint32_t offset;
36
+			uint32_t headerSize;
37
+			int32_t width;
38
+			int32_t height;
39
+			uint16_t planes;
40
+			uint16_t depth;
41
+			uint32_t compression;
42
+			uint32_t imageSize;
43
+			int32_t horizontalResolution;
44
+			int32_t verticalResolution;
45
+			uint32_t paletteColorCount;
46
+			uint32_t importantColorcount;
47
+		} bmpHeader;
48
+		#pragma pack(pop)
49
+
50
+		// Read the BMP header so we know where the image data is located
51
+		fread(&bmpHeader, 1, sizeof(bmpHeader), inFile);
52
+		assert(bmpHeader.magic[0] == 'B' && bmpHeader.magic[1] == 'M');
53
+		assert(bmpHeader.depth == 8);
54
+		assert(bmpHeader.headerSize == 40);
55
+
56
+		// Go to location in file of image data
57
+		fseek(inFile, bmpHeader.offset, SEEK_SET);
58
+
59
+		// Read in the image data
60
+		tileBuffer = malloc(bmpHeader.imageSize);
61
+		assert(tileBuffer);
62
+		fread(tileBuffer, 1, bmpHeader.imageSize, inFile);
63
+
64
+		tileWidth = bmpHeader.width;
65
+		tileHeight = bmpHeader.height;
66
+
67
+		fclose(inFile);
68
+	}
69
+
70
+
71
+	printf("Input: %s\n", inFilename);
72
+	printf("Output: %s\n", outFilename);
73
+	printf("Width: %d\n", tileWidth);
74
+	printf("Height: %d\n", tileHeight);
75
+
76
+	FILE* outFile = fopen(outFilename, "w");
77
+	assert(outFile);
78
+
79
+
80
+	// Generate the preamble
81
+	{
82
+		fprintf(outFile, "// AUTOMATICALLY GENERATED. DO NOT EDIT.\n");
83
+		fprintf(outFile, "\n");
84
+		fprintf(outFile, "#pragma once\n");
85
+		fprintf(outFile, "\n");
86
+		fprintf(outFile, "#include <stdint.h>\n");
87
+		fprintf(outFile, "\n");
88
+		fprintf(outFile, "\n");
89
+	}
90
+
91
+
92
+	// Generate the font map with the calculated glyph bytes
93
+	{
94
+		fprintf(outFile, "static const uint8_t tile[%d][%d] =\n", tileHeight, tileWidth);
95
+		fprintf(outFile, "{\n");
96
+		fprintf(outFile, "	");
97
+
98
+		int count = 0;
99
+
100
+		for (int row = 0; row < tileHeight; ++row)
101
+		{
102
+			for (int col = 0; col < tileWidth; ++col)
103
+			{
104
+				// BMP is laid out bottom-to-top, but we want top-to-bottom (0-indexed)
105
+				int y =  tileHeight - row - 1;
106
+
107
+				uint8_t paletteIndex = tileBuffer[y * tileWidth + col];
108
+
109
+				fprintf(outFile, "%d,", paletteIndex);
110
+				++count;
111
+
112
+				// Put a newline after sixteen values to keep it orderly
113
+				if ((count % 16) == 0)
114
+				{
115
+					fprintf(outFile, "\n");
116
+					fprintf(outFile, "	");
117
+
118
+					count = 0;
119
+				}
120
+			}
121
+		}
122
+
123
+		fprintf(outFile, "};\n");
124
+	}
125
+
126
+	fclose(outFile);
127
+
128
+	printf("\n");
129
+	printf("DONE\n");
130
+
131
+	return 0;
132
+}

Loading…
Cancelar
Guardar