Part 8: Tile System
这个提交包含在:
		
							父节点
							
								
									02a911ef9f
								
							
						
					
					
						当前提交
						1096c7eac2
					
				|  | @ -19,3 +19,5 @@ if (ret != ESP_OK) { | |||
| 	* `IDF_TOOLS_PATH` is the path to the toolchain | ||||
| * `source export.sh` | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
|  |  | |||
										
											二进制文件未显示。
										
									
								
							| 之后 宽度: | 高度: | 大小: 1.3 KiB | 
										
											二进制文件未显示。
										
									
								
							| 之后 宽度: | 高度: | 大小: 1.3 KiB | 
										
											二进制文件未显示。
										
									
								
							| 之后 宽度: | 高度: | 大小: 1.3 KiB | 
										
											二进制文件未显示。
										
									
								
							| 之后 宽度: | 高度: | 大小: 1.3 KiB | 
|  | @ -0,0 +1,7 @@ | |||
| JASC-PAL | ||||
| 0100 | ||||
| 4 | ||||
| 255 255 255 | ||||
| 171 171 171 | ||||
| 84 84 84 | ||||
| 0 0 0 | ||||
										
											二进制文件未显示。
										
									
								
							
										
											二进制文件未显示。
										
									
								
							
										
											二进制文件未显示。
										
									
								
							
										
											二进制文件未显示。
										
									
								
							
							
								
								
									
										276
									
								
								game/src/main.c
								
								
								
								
							
							
						
						
									
										276
									
								
								game/src/main.c
								
								
								
								
							|  | @ -15,6 +15,139 @@ static const char* LOG_TAG = "Main"; | |||
| static uint16_t gFramebuffer[LCD_WIDTH * LCD_HEIGHT]; | ||||
| 
 | ||||
| 
 | ||||
| static const uint16_t palette[4] = | ||||
| { | ||||
| 	0xFFFF, | ||||
| 	0x55AD, | ||||
| 	0xAA52, | ||||
| 	0x0000, | ||||
| }; | ||||
| 
 | ||||
| static const uint8_t tiles[][16*16] = | ||||
| { | ||||
| 	// White
 | ||||
| 	{ | ||||
| 	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,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, | ||||
| 	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,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, | ||||
| 	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,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, | ||||
| 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||||
| 	}, | ||||
| 
 | ||||
| 	// Light Grey
 | ||||
| 	{ | ||||
| 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||||
| 	0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0, | ||||
| 	0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0, | ||||
| 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||||
| 	}, | ||||
| 
 | ||||
| 	// Dark Grey
 | ||||
| 	{ | ||||
| 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||||
| 	0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0, | ||||
| 	0,0,2,2,2,2,2,2,2,2,2,2,2,2,0,0, | ||||
| 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||||
| 	}, | ||||
| 
 | ||||
| 	// Black
 | ||||
| 	{ | ||||
| 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||||
| 	0,0,3,3,3,3,3,3,3,3,3,3,3,3,0,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0, | ||||
| 	0,0,3,3,3,3,3,3,3,3,3,3,3,3,0,0, | ||||
| 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static int tileBuffer[15][40] = | ||||
| { | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| 	{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}, | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| void DrawTile(int index, int x, int y) | ||||
| { | ||||
| 	int startX = x * 16; | ||||
| 	int startY = y * 16; | ||||
| 
 | ||||
| 	for (int row = 0; row < 16; ++row) | ||||
| 	{ | ||||
| 		for (int col = 0; col < 16; ++col) | ||||
| 		{ | ||||
| 			uint8_t paletteIndex = tiles[index][row * 16 + col]; | ||||
| 
 | ||||
| 			int screenY = startY + row; | ||||
| 			int screenX = startX + col; | ||||
| 
 | ||||
| 			uint16_t color = palette[paletteIndex]; | ||||
| 
 | ||||
| 			gFramebuffer[screenY * LCD_WIDTH + screenX] = color; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void app_main(void) | ||||
| { | ||||
| 	Odroid_InitializeInput(); | ||||
|  | @ -23,113 +156,63 @@ void app_main(void) | |||
| 	Odroid_InitializeBatteryReader(); | ||||
| 	Odroid_InitializeAudio(); | ||||
| 
 | ||||
| 	// Load sprite
 | ||||
| 	uint16_t* sprite = (uint16_t*)malloc(64 * 64 * sizeof(uint16_t)); | ||||
| 	{ | ||||
| 		FILE* spriteFile = fopen("/sdcard/key", "r"); | ||||
| 		assert(spriteFile); | ||||
| 
 | ||||
| 		for (int i = 0; i < 64; ++i) | ||||
| 		{ | ||||
| 			for (int j = 0; j < 64; ++j) | ||||
| 			{ | ||||
| 				fread(sprite, sizeof(uint16_t), 64 * 64, spriteFile); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		fclose(spriteFile); | ||||
| 	} | ||||
| 
 | ||||
| 	// Load sound effect
 | ||||
| 	uint16_t* soundBuffer; | ||||
| 	int soundEffectLength = 1441; | ||||
| 	{ | ||||
| 		FILE* soundFile = fopen("/sdcard/jump", "r"); | ||||
| 		assert(soundFile); | ||||
| 
 | ||||
| 		uint8_t* soundEffect = malloc(soundEffectLength); | ||||
| 		assert(soundEffect); | ||||
| 
 | ||||
| 		soundBuffer = malloc(soundEffectLength*2); | ||||
| 		assert(soundBuffer); | ||||
| 
 | ||||
| 		fread(soundEffect, soundEffectLength, 1, soundFile); | ||||
| 
 | ||||
| 		for (int i = 0; i < soundEffectLength; ++i) | ||||
| 		{ | ||||
| 			// 16 bits required but only MSB is actually sent to the DAC
 | ||||
| 			soundBuffer[i] = (soundEffect[i] << 8u); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	ESP_LOGI(LOG_TAG, "Odroid initialization complete - entering main loop"); | ||||
| 
 | ||||
| 	int x = 0; | ||||
| 	int y = 0; | ||||
| 
 | ||||
| 	uint16_t color = 0xffff; | ||||
| 
 | ||||
| 	int lastState = 0; | ||||
| 	uint8_t frameIndex = 0; | ||||
| 	char snapFilename[20]; | ||||
| 	int xLeft = 0; | ||||
| 
 | ||||
| 	for (;;) | ||||
| 	{ | ||||
| 		memset(gFramebuffer, 0, 320 * 240 * 2); | ||||
| 		memset(gFramebuffer, 0xff, 320*240*2); | ||||
| 
 | ||||
| 		Odroid_Input input = Odroid_PollInput(); | ||||
| 
 | ||||
| 		if (input.left) { x -= 20; } | ||||
| 		else if (input.right) { x += 20; } | ||||
| 
 | ||||
| 		if (input.up) { y -= 20; } | ||||
| 		else if (input.down) { y += 20; } | ||||
| 
 | ||||
| 		if (input.a) { color = SWAP_ENDIAN_16(RGB565(0xff, 0, 0)); } | ||||
| 		else if (input.b) { color = SWAP_ENDIAN_16(RGB565(0, 0xff, 0)); } | ||||
| 		else if (input.start) { color = SWAP_ENDIAN_16(RGB565(0, 0, 0xff)); } | ||||
| 		else if (input.select) { color = SWAP_ENDIAN_16(RGB565(0xff, 0xff, 0xff)); } | ||||
| 
 | ||||
| 
 | ||||
| 		int thisState = input.volume; | ||||
| 
 | ||||
| 		if ((thisState == 1) && (thisState != lastState)) | ||||
| 		if (input.left) | ||||
| 		{ | ||||
| 			Odroid_PlayAudio(soundBuffer, soundEffectLength*2); | ||||
| 		} | ||||
| 			xLeft -= 1; | ||||
| 
 | ||||
| 		lastState = thisState; | ||||
| 
 | ||||
| 
 | ||||
| 		DrawText(gFramebuffer, "The Quick Brown Fox", 19, 0, 5, SWAP_ENDIAN_16(RGB565(0xFF, 0, 0))); | ||||
| 		DrawText(gFramebuffer, "Jumped Over The:", 16, 0, 6, SWAP_ENDIAN_16(RGB565(0, 0xFF, 0))); | ||||
| 		DrawText(gFramebuffer, "Lazy Dog?!", 10, 0, 7, SWAP_ENDIAN_16(RGB565(0, 0, 0xFF))); | ||||
| 
 | ||||
| 
 | ||||
| 		int spriteRow = 0; | ||||
| 		int spriteCol = 0; | ||||
| 
 | ||||
| 		for (int row = y; row < y + 64; ++row) | ||||
| 		{ | ||||
| 			spriteCol = 0; | ||||
| 
 | ||||
| 			for (int col = x; col < x + 64; ++col) | ||||
| 			if (xLeft < 0) | ||||
| 			{ | ||||
| 				uint16_t pixelColor = sprite[64 * spriteRow + spriteCol]; | ||||
| 
 | ||||
| 				if (pixelColor != 0) | ||||
| 				{ | ||||
| 					gFramebuffer[row * LCD_WIDTH + col] = color; | ||||
| 				} | ||||
| 
 | ||||
| 				++spriteCol; | ||||
| 				xLeft = 39; | ||||
| 			} | ||||
| 
 | ||||
| 			++spriteRow; | ||||
| 		} | ||||
| 
 | ||||
| 		else if (input.right) | ||||
| 		{ | ||||
| 			xLeft += 1; | ||||
| 
 | ||||
| 			if (xLeft > 39) | ||||
| 			{ | ||||
| 				xLeft = 0; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		for (int tileY = 0; tileY < 15; ++tileY) | ||||
| 		{ | ||||
| 			for (int tileX = xLeft; tileX < xLeft + 20; ++tileX) | ||||
| 			{ | ||||
| 				int tile = tileX % 40; | ||||
| 
 | ||||
| 				int tileIndex = tileBuffer[tileY][tile]; | ||||
| 
 | ||||
| 				DrawTile(tileIndex, tileX - xLeft, tileY); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		char string[5]; | ||||
| 		snprintf(string, 5, "%02d", xLeft); | ||||
| 		DrawText(gFramebuffer, string, 2, 0, 0, palette[3]); | ||||
| 
 | ||||
| 		int tileRight = (xLeft + 20) % 40; | ||||
| 		snprintf(string, 5, "%02d", tileRight); | ||||
| 		DrawText(gFramebuffer, string, 2, 18, 0, palette[3]); | ||||
| 
 | ||||
| 		if (input.menu) | ||||
| 		{ | ||||
| 			const char* snapFilename = "/sdcard/framebuf"; | ||||
| 			snprintf(snapFilename, 20, "/sdcard/frame%02d", frameIndex); | ||||
| 
 | ||||
| 			ESP_LOGI(LOG_TAG, "Writing snapshot to %s", snapFilename); | ||||
| 
 | ||||
|  | @ -139,19 +222,8 @@ void app_main(void) | |||
| 			fwrite(gFramebuffer, 1, LCD_WIDTH * LCD_HEIGHT * sizeof(gFramebuffer[0]), snapFile); | ||||
| 
 | ||||
| 			fclose(snapFile); | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| 		uint32_t batteryLevel = Odroid_ReadBatteryLevel(); | ||||
| 		ESP_LOGI(LOG_TAG, "Battery level: %u\n", batteryLevel); | ||||
| 
 | ||||
| 		if (batteryLevel < 3600) | ||||
| 		{ | ||||
| 			Odroid_EnableBatteryLight(); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			Odroid_DisableBatteryLight(); | ||||
| 			++frameIndex; | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,8 +8,8 @@ static const int MAX_GLYPHS_PER_COL = LCD_HEIGHT / GLYPH_HEIGHT; | |||
| 
 | ||||
| void DrawText(uint16_t* framebuffer, char* string, int length, int x, int y, uint16_t color) | ||||
| { | ||||
| 	assert(x + length < MAX_GLYPHS_PER_ROW); | ||||
| 	assert(y < MAX_GLYPHS_PER_COL); | ||||
| 	assert(x + length <= MAX_GLYPHS_PER_ROW); | ||||
| 	assert(y <= MAX_GLYPHS_PER_COL); | ||||
| 
 | ||||
| 	for (int charIndex = 0; charIndex < length; ++charIndex) | ||||
| 	{ | ||||
|  |  | |||
|  | @ -4,5 +4,7 @@ project(tools) | |||
| 
 | ||||
| set(CMAKE_C_FLAGS "-Wall -Werror") | ||||
| 
 | ||||
| add_executable(font_generator src/font_generator.c) | ||||
| add_executable(font_processor src/font_processor.c) | ||||
| add_executable(palette_processor src/palette_processor.c) | ||||
| add_executable(tile_processor src/tile_processor.c) | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,105 @@ | |||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	if (argc != 3) | ||||
| 	{ | ||||
| 		fprintf(stderr, "Usage: %s <input palette> <output header>\n", argv[0]); | ||||
| 
 | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	const char* inFilename = argv[1]; | ||||
| 	const char* outFilename = argv[2]; | ||||
| 
 | ||||
| 	// Read the file
 | ||||
| 	uint16_t* palette; | ||||
| 	int paletteSize; | ||||
| 	{ | ||||
| 		FILE* inFile = fopen(inFilename, "r"); | ||||
| 		assert(inFile); | ||||
| 
 | ||||
| 		char* line; | ||||
| 		size_t len = 0; | ||||
| 
 | ||||
| 		getline(&line, &len, inFile); | ||||
| 		assert(strncmp(line, "JASC-PAL", 8) == 0); | ||||
| 
 | ||||
| 		getline(&line, &len, inFile); | ||||
| 		assert(strncmp(line, "0100", 4) == 0); | ||||
| 
 | ||||
| 		getline(&line, &len, inFile); | ||||
| 		paletteSize = atoi(line); | ||||
| 
 | ||||
| 		palette = malloc(sizeof(*palette) * paletteSize); | ||||
| 		assert(palette); | ||||
| 
 | ||||
| 		// Each line is of form R G B
 | ||||
| 		for (int i = 0; i < paletteSize; ++i) | ||||
| 		{ | ||||
| 			getline(&line, &len, inFile); | ||||
| 
 | ||||
| 			char* tok = strtok(line, " "); | ||||
| 			int red = atoi(tok); | ||||
| 
 | ||||
| 			tok = strtok(NULL, " "); | ||||
| 			int green = atoi(tok); | ||||
| 
 | ||||
| 			tok = strtok(NULL, " "); | ||||
| 			int blue = atoi(tok); | ||||
| 
 | ||||
| 			uint16_t rgb565 = | ||||
| 				  ((red >> 3u) << 11u) | ||||
| 				| ((green >> 2u) << 5u) | ||||
| 				| (blue >> 3u); | ||||
| 
 | ||||
| 			uint16_t endianSwap = ((rgb565 & 0xFFu) << 8u) | (rgb565 >> 8u); | ||||
| 
 | ||||
| 			palette[i] = endianSwap; | ||||
| 		} | ||||
| 
 | ||||
| 		fclose(inFile); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	printf("Input: %s\n", inFilename); | ||||
| 	printf("Output: %s\n", outFilename); | ||||
| 	printf("Palette Size: %d\n", paletteSize); | ||||
| 
 | ||||
| 
 | ||||
| 	// Output to the file
 | ||||
| 	{ | ||||
| 		FILE* outFile = fopen(outFilename, "w"); | ||||
| 		assert(outFile); | ||||
| 
 | ||||
| 		fprintf(outFile, "// AUTOMATICALLY GENERATED. DO NOT EDIT.\n"); | ||||
| 		fprintf(outFile, "\n"); | ||||
| 		fprintf(outFile, "#pragma once\n"); | ||||
| 		fprintf(outFile, "\n"); | ||||
| 		fprintf(outFile, "\n"); | ||||
| 
 | ||||
| 		fprintf(outFile, "uint16_t palette[%d] =\n", paletteSize); | ||||
| 		fprintf(outFile, "{\n"); | ||||
| 
 | ||||
| 		for (int i = 0; i < paletteSize; ++i) | ||||
| 		{ | ||||
| 			fprintf(outFile, "	0x%04X,\n", palette[i]); | ||||
| 		} | ||||
| 
 | ||||
| 		fprintf(outFile, "};\n"); | ||||
| 		fprintf(outFile, "\n"); | ||||
| 
 | ||||
| 		fclose(outFile); | ||||
| 	} | ||||
| 
 | ||||
| 	printf("\n"); | ||||
| 	printf("DONE\n"); | ||||
| 
 | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,132 @@ | |||
| #include <assert.h> | ||||
| #include <ctype.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| 
 | ||||
| 
 | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
| 	if (argc != 3) | ||||
| 	{ | ||||
| 		fprintf(stderr, "Usage: %s <input image> <output header>\n", argv[0]); | ||||
| 
 | ||||
| 		return 1; | ||||
| 	} | ||||
| 
 | ||||
| 	const char* inFilename = argv[1]; | ||||
| 	const char* outFilename = argv[2]; | ||||
| 
 | ||||
| 
 | ||||
| 	int tileWidth; | ||||
| 	int tileHeight; | ||||
| 	uint8_t* tileBuffer; | ||||
| 	{ | ||||
| 		FILE* inFile = fopen(inFilename, "rb"); | ||||
| 		assert(inFile); | ||||
| 
 | ||||
| 		#pragma pack(push,1) | ||||
| 		struct BmpHeader | ||||
| 		{ | ||||
| 			char magic[2]; | ||||
| 			uint32_t totalSize; | ||||
| 			uint32_t reserved; | ||||
| 			uint32_t offset; | ||||
| 			uint32_t headerSize; | ||||
| 			int32_t width; | ||||
| 			int32_t height; | ||||
| 			uint16_t planes; | ||||
| 			uint16_t depth; | ||||
| 			uint32_t compression; | ||||
| 			uint32_t imageSize; | ||||
| 			int32_t horizontalResolution; | ||||
| 			int32_t verticalResolution; | ||||
| 			uint32_t paletteColorCount; | ||||
| 			uint32_t importantColorcount; | ||||
| 		} bmpHeader; | ||||
| 		#pragma pack(pop) | ||||
| 
 | ||||
| 		// Read the BMP header so we know where the image data is located
 | ||||
| 		fread(&bmpHeader, 1, sizeof(bmpHeader), inFile); | ||||
| 		assert(bmpHeader.magic[0] == 'B' && bmpHeader.magic[1] == 'M'); | ||||
| 		assert(bmpHeader.depth == 8); | ||||
| 		assert(bmpHeader.headerSize == 40); | ||||
| 
 | ||||
| 		// Go to location in file of image data
 | ||||
| 		fseek(inFile, bmpHeader.offset, SEEK_SET); | ||||
| 
 | ||||
| 		// Read in the image data
 | ||||
| 		tileBuffer = malloc(bmpHeader.imageSize); | ||||
| 		assert(tileBuffer); | ||||
| 		fread(tileBuffer, 1, bmpHeader.imageSize, inFile); | ||||
| 
 | ||||
| 		tileWidth = bmpHeader.width; | ||||
| 		tileHeight = bmpHeader.height; | ||||
| 
 | ||||
| 		fclose(inFile); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	printf("Input: %s\n", inFilename); | ||||
| 	printf("Output: %s\n", outFilename); | ||||
| 	printf("Width: %d\n", tileWidth); | ||||
| 	printf("Height: %d\n", tileHeight); | ||||
| 
 | ||||
| 	FILE* outFile = fopen(outFilename, "w"); | ||||
| 	assert(outFile); | ||||
| 
 | ||||
| 
 | ||||
| 	// Generate the preamble
 | ||||
| 	{ | ||||
| 		fprintf(outFile, "// AUTOMATICALLY GENERATED. DO NOT EDIT.\n"); | ||||
| 		fprintf(outFile, "\n"); | ||||
| 		fprintf(outFile, "#pragma once\n"); | ||||
| 		fprintf(outFile, "\n"); | ||||
| 		fprintf(outFile, "#include <stdint.h>\n"); | ||||
| 		fprintf(outFile, "\n"); | ||||
| 		fprintf(outFile, "\n"); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	// Generate the font map with the calculated glyph bytes
 | ||||
| 	{ | ||||
| 		fprintf(outFile, "static const uint8_t tile[%d][%d] =\n", tileHeight, tileWidth); | ||||
| 		fprintf(outFile, "{\n"); | ||||
| 		fprintf(outFile, "	"); | ||||
| 
 | ||||
| 		int count = 0; | ||||
| 
 | ||||
| 		for (int row = 0; row < tileHeight; ++row) | ||||
| 		{ | ||||
| 			for (int col = 0; col < tileWidth; ++col) | ||||
| 			{ | ||||
| 				// BMP is laid out bottom-to-top, but we want top-to-bottom (0-indexed)
 | ||||
| 				int y =  tileHeight - row - 1; | ||||
| 
 | ||||
| 				uint8_t paletteIndex = tileBuffer[y * tileWidth + col]; | ||||
| 
 | ||||
| 				fprintf(outFile, "%d,", paletteIndex); | ||||
| 				++count; | ||||
| 
 | ||||
| 				// Put a newline after sixteen values to keep it orderly
 | ||||
| 				if ((count % 16) == 0) | ||||
| 				{ | ||||
| 					fprintf(outFile, "\n"); | ||||
| 					fprintf(outFile, "	"); | ||||
| 
 | ||||
| 					count = 0; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		fprintf(outFile, "};\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	fclose(outFile); | ||||
| 
 | ||||
| 	printf("\n"); | ||||
| 	printf("DONE\n"); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
		正在加载...
	
		在新工单中引用