Merge branch 'new_blit'
This commit is contained in:
		@@ -22,6 +22,12 @@
 | 
				
			|||||||
    <ClCompile Include="..\..\..\examples\sdl-renderer.c" />
 | 
					    <ClCompile Include="..\..\..\examples\sdl-renderer.c" />
 | 
				
			||||||
  </ItemGroup>
 | 
					  </ItemGroup>
 | 
				
			||||||
  <ItemGroup>
 | 
					  <ItemGroup>
 | 
				
			||||||
 | 
					    <ProjectReference Include="..\..\..\..\3rd-party\SDL2-2.0.5\VisualC\SDLmain\SDLmain.vcxproj">
 | 
				
			||||||
 | 
					      <Project>{da956fd3-e142-46f2-9dd5-c78bebb56b7a}</Project>
 | 
				
			||||||
 | 
					    </ProjectReference>
 | 
				
			||||||
 | 
					    <ProjectReference Include="..\..\..\..\3rd-party\SDL2-2.0.5\VisualC\SDL\SDL.vcxproj">
 | 
				
			||||||
 | 
					      <Project>{81ce8daf-ebb2-4761-8e45-b71abcca8c68}</Project>
 | 
				
			||||||
 | 
					    </ProjectReference>
 | 
				
			||||||
    <ProjectReference Include="..\tic80\tic80.vcxproj">
 | 
					    <ProjectReference Include="..\tic80\tic80.vcxproj">
 | 
				
			||||||
      <Project>{c4d8bc10-ebf6-42bb-9b5d-6712fb428a50}</Project>
 | 
					      <Project>{c4d8bc10-ebf6-42bb-9b5d-6712fb428a50}</Project>
 | 
				
			||||||
    </ProjectReference>
 | 
					    </ProjectReference>
 | 
				
			||||||
@@ -100,7 +106,7 @@
 | 
				
			|||||||
    <Link>
 | 
					    <Link>
 | 
				
			||||||
      <SubSystem>Windows</SubSystem>
 | 
					      <SubSystem>Windows</SubSystem>
 | 
				
			||||||
      <GenerateDebugInformation>true</GenerateDebugInformation>
 | 
					      <GenerateDebugInformation>true</GenerateDebugInformation>
 | 
				
			||||||
      <AdditionalDependencies>SDL2main.lib;SDL2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
					      <AdditionalDependencies>;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
				
			||||||
      <AdditionalLibraryDirectories>..\..\..\lib\windows</AdditionalLibraryDirectories>
 | 
					      <AdditionalLibraryDirectories>..\..\..\lib\windows</AdditionalLibraryDirectories>
 | 
				
			||||||
    </Link>
 | 
					    </Link>
 | 
				
			||||||
  </ItemDefinitionGroup>
 | 
					  </ItemDefinitionGroup>
 | 
				
			||||||
@@ -115,7 +121,7 @@
 | 
				
			|||||||
    <Link>
 | 
					    <Link>
 | 
				
			||||||
      <SubSystem>Windows</SubSystem>
 | 
					      <SubSystem>Windows</SubSystem>
 | 
				
			||||||
      <GenerateDebugInformation>true</GenerateDebugInformation>
 | 
					      <GenerateDebugInformation>true</GenerateDebugInformation>
 | 
				
			||||||
      <AdditionalDependencies>SDL2main.lib;SDL2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
					      <AdditionalDependencies>;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
				
			||||||
      <AdditionalLibraryDirectories>..\..\..\lib\windows</AdditionalLibraryDirectories>
 | 
					      <AdditionalLibraryDirectories>..\..\..\lib\windows</AdditionalLibraryDirectories>
 | 
				
			||||||
    </Link>
 | 
					    </Link>
 | 
				
			||||||
  </ItemDefinitionGroup>
 | 
					  </ItemDefinitionGroup>
 | 
				
			||||||
@@ -134,7 +140,7 @@
 | 
				
			|||||||
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
 | 
					      <EnableCOMDATFolding>true</EnableCOMDATFolding>
 | 
				
			||||||
      <OptimizeReferences>true</OptimizeReferences>
 | 
					      <OptimizeReferences>true</OptimizeReferences>
 | 
				
			||||||
      <GenerateDebugInformation>true</GenerateDebugInformation>
 | 
					      <GenerateDebugInformation>true</GenerateDebugInformation>
 | 
				
			||||||
      <AdditionalDependencies>SDL2main.lib;SDL2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
					      <AdditionalDependencies>;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
				
			||||||
      <AdditionalLibraryDirectories>..\..\..\lib\windows</AdditionalLibraryDirectories>
 | 
					      <AdditionalLibraryDirectories>..\..\..\lib\windows</AdditionalLibraryDirectories>
 | 
				
			||||||
    </Link>
 | 
					    </Link>
 | 
				
			||||||
  </ItemDefinitionGroup>
 | 
					  </ItemDefinitionGroup>
 | 
				
			||||||
@@ -153,7 +159,7 @@
 | 
				
			|||||||
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
 | 
					      <EnableCOMDATFolding>true</EnableCOMDATFolding>
 | 
				
			||||||
      <OptimizeReferences>true</OptimizeReferences>
 | 
					      <OptimizeReferences>true</OptimizeReferences>
 | 
				
			||||||
      <GenerateDebugInformation>true</GenerateDebugInformation>
 | 
					      <GenerateDebugInformation>true</GenerateDebugInformation>
 | 
				
			||||||
      <AdditionalDependencies>SDL2main.lib;SDL2.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
					      <AdditionalDependencies>;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
 | 
				
			||||||
      <AdditionalLibraryDirectories>..\..\..\lib\windows</AdditionalLibraryDirectories>
 | 
					      <AdditionalLibraryDirectories>..\..\..\lib\windows</AdditionalLibraryDirectories>
 | 
				
			||||||
    </Link>
 | 
					    </Link>
 | 
				
			||||||
  </ItemDefinitionGroup>
 | 
					  </ItemDefinitionGroup>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,9 +56,9 @@ int main(int argc, char **argv)
 | 
				
			|||||||
			SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
 | 
								SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				SDL_Window* window = SDL_CreateWindow("TIC-80 SDL demo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, TIC80_WIDTH, TIC80_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
 | 
									SDL_Window* window = SDL_CreateWindow("TIC-80 SDL demo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, TIC80_FULLWIDTH, TIC80_FULLHEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
 | 
				
			||||||
				SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
 | 
									SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
 | 
				
			||||||
				SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, TIC80_WIDTH, TIC80_HEIGHT);
 | 
									SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, TIC80_FULLWIDTH, TIC80_FULLHEIGHT);
 | 
				
			||||||
				
 | 
									
 | 
				
			||||||
				SDL_AudioDeviceID audioDevice = 0;
 | 
									SDL_AudioDeviceID audioDevice = 0;
 | 
				
			||||||
				SDL_AudioSpec audioSpec;
 | 
									SDL_AudioSpec audioSpec;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,8 @@ extern "C" {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define TIC80_WIDTH 240
 | 
					#define TIC80_WIDTH 240
 | 
				
			||||||
#define TIC80_HEIGHT 136
 | 
					#define TIC80_HEIGHT 136
 | 
				
			||||||
 | 
					#define TIC80_FULLWIDTH 256
 | 
				
			||||||
 | 
					#define TIC80_FULLHEIGHT (TIC80_FULLWIDTH*9/16)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct 
 | 
					typedef struct 
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -47,15 +49,8 @@ typedef struct
 | 
				
			|||||||
		s32 count;
 | 
							s32 count;
 | 
				
			||||||
	} sound;
 | 
						} sound;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u32 screen[TIC80_WIDTH * TIC80_HEIGHT];
 | 
						u32 screen[TIC80_FULLWIDTH * TIC80_FULLHEIGHT];
 | 
				
			||||||
	u32 border[TIC80_HEIGHT];
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		s8 x;
 | 
					 | 
				
			||||||
		s8 y;
 | 
					 | 
				
			||||||
		s8 rows[TIC80_HEIGHT];
 | 
					 | 
				
			||||||
	} offset;
 | 
					 | 
				
			||||||
} tic80;
 | 
					} tic80;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef union
 | 
					typedef union
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1782,7 +1782,7 @@ static void onConsoleRamCommand(Console* console, const char* param)
 | 
				
			|||||||
		ADDR_RECORD(console->tic->ram.vram.screen, 					"SCREEN"),
 | 
							ADDR_RECORD(console->tic->ram.vram.screen, 					"SCREEN"),
 | 
				
			||||||
		ADDR_RECORD(console->tic->ram.vram.palette, 				"PALETTE"),
 | 
							ADDR_RECORD(console->tic->ram.vram.palette, 				"PALETTE"),
 | 
				
			||||||
		ADDR_RECORD(console->tic->ram.vram.mapping, 				"PALETTE MAP"),
 | 
							ADDR_RECORD(console->tic->ram.vram.mapping, 				"PALETTE MAP"),
 | 
				
			||||||
		ADDR_RECORD(console->tic->ram.vram.vars.border, 			"BORDER COLOR"),
 | 
							ADDR_RECORD(console->tic->ram.vram.vars.colors, 			"BORDER/BG COLOR"),
 | 
				
			||||||
		ADDR_RECORD(console->tic->ram.vram.vars.offset, 			"SCREEN OFFSET"),
 | 
							ADDR_RECORD(console->tic->ram.vram.vars.offset, 			"SCREEN OFFSET"),
 | 
				
			||||||
		ADDR_RECORD(console->tic->ram.vram.vars.mask, 				"GAMEPAD MASK"),
 | 
							ADDR_RECORD(console->tic->ram.vram.vars.mask, 				"GAMEPAD MASK"),
 | 
				
			||||||
		ADDR_RECORD(console->tic->ram.vram.input.gamepad, 			"GAMEPAD"),
 | 
							ADDR_RECORD(console->tic->ram.vram.input.gamepad, 			"GAMEPAD"),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										214
									
								
								src/studio.c
									
									
									
									
									
								
							
							
						
						
									
										214
									
								
								src/studio.c
									
									
									
									
									
								
							@@ -47,14 +47,15 @@
 | 
				
			|||||||
#include "ext/md5.h"
 | 
					#include "ext/md5.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STUDIO_UI_SCALE 3
 | 
					#define STUDIO_UI_SCALE 3
 | 
				
			||||||
#define STUDIO_UI_BORDER 16
 | 
					#define TEXTURE_SIZE (TIC80_FULLWIDTH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_CONTROLLERS 4
 | 
					#define MAX_CONTROLLERS 4
 | 
				
			||||||
#define STUDIO_PIXEL_FORMAT SDL_PIXELFORMAT_ARGB8888
 | 
					#define STUDIO_PIXEL_FORMAT SDL_PIXELFORMAT_ARGB8888
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_OFFSET 128
 | 
					#define FRAME_SIZE (TIC80_FULLWIDTH * TIC80_FULLHEIGHT * sizeof(u32))
 | 
				
			||||||
#define FULL_WIDTH (TIC80_WIDTH + MAX_OFFSET*2)
 | 
					
 | 
				
			||||||
#define FRAME_SIZE (TIC80_WIDTH * TIC80_HEIGHT * sizeof(u32))
 | 
					#define OFFSET_LEFT ((TIC80_FULLWIDTH-TIC80_WIDTH)/2)
 | 
				
			||||||
 | 
					#define OFFSET_TOP ((TIC80_FULLHEIGHT-TIC80_HEIGHT)/2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct
 | 
					typedef struct
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -80,8 +81,8 @@ static struct
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	SDL_Window* window;
 | 
						SDL_Window* window;
 | 
				
			||||||
	SDL_Renderer* renderer;
 | 
						SDL_Renderer* renderer;
 | 
				
			||||||
 | 
						SDL_Renderer* softwareRenderer;
 | 
				
			||||||
	SDL_Texture* texture;
 | 
						SDL_Texture* texture;
 | 
				
			||||||
	SDL_Texture* borderTexture;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SDL_AudioSpec audioSpec;
 | 
						SDL_AudioSpec audioSpec;
 | 
				
			||||||
	SDL_AudioDeviceID audioDevice;
 | 
						SDL_AudioDeviceID audioDevice;
 | 
				
			||||||
@@ -195,8 +196,8 @@ static struct
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	.window = NULL,
 | 
						.window = NULL,
 | 
				
			||||||
	.renderer = NULL,
 | 
						.renderer = NULL,
 | 
				
			||||||
 | 
						.softwareRenderer = NULL,
 | 
				
			||||||
	.texture = NULL,
 | 
						.texture = NULL,
 | 
				
			||||||
	.borderTexture = NULL,
 | 
					 | 
				
			||||||
	.audioDevice = 0,
 | 
						.audioDevice = 0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.joysticks = {NULL, NULL, NULL, NULL},
 | 
						.joysticks = {NULL, NULL, NULL, NULL},
 | 
				
			||||||
@@ -962,7 +963,9 @@ static void calcTextureRect(SDL_Rect* rect)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		rect->x = (rect->w - discreteWidth) / 2;
 | 
							rect->x = (rect->w - discreteWidth) / 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rect->y = rect->w > rect->h ? (rect->h - discreteHeight) / 2 : 0;
 | 
							rect->y = rect->w > rect->h 
 | 
				
			||||||
 | 
								? (rect->h - discreteHeight) / 2 
 | 
				
			||||||
 | 
								: OFFSET_LEFT*discreteWidth/TIC80_WIDTH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rect->w = discreteWidth;
 | 
							rect->w = discreteWidth;
 | 
				
			||||||
		rect->h = discreteHeight;
 | 
							rect->h = discreteHeight;
 | 
				
			||||||
@@ -1406,78 +1409,38 @@ static u32* paletteBlit()
 | 
				
			|||||||
	return srcPaletteBlit(studio.tic->ram.vram.palette.data);
 | 
						return srcPaletteBlit(studio.tic->ram.vram.palette.data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void blit(u32* out, u32* bgOut, s32 pitch, s32 bgPitch)
 | 
					static void screen2buffer(u32* buffer, const u32* pixels, SDL_Rect rect)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const s32 pitchWidth = pitch/sizeof *out;
 | 
						pixels += rect.y * TIC80_FULLWIDTH;
 | 
				
			||||||
	const s32 bgPitchWidth = bgPitch/sizeof *bgOut;
 | 
					 | 
				
			||||||
	u32* row = out;
 | 
					 | 
				
			||||||
	const u32* pal = paletteBlit();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void(*scanline)(tic_mem* memory, s32 row) = NULL;
 | 
						for(s32 i = 0; i < rect.h; i++)
 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch(studio.mode)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	case TIC_RUN_MODE:
 | 
							SDL_memcpy(buffer, pixels + rect.x, rect.w * sizeof(pixels[0]));
 | 
				
			||||||
		scanline = studio.tic->api.scanline;
 | 
							pixels += TIC80_FULLWIDTH;
 | 
				
			||||||
		break;
 | 
							buffer += rect.w;
 | 
				
			||||||
	case TIC_SPRITE_MODE:
 | 
					 | 
				
			||||||
		scanline = studio.sprite.scanline;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case TIC_MAP_MODE:
 | 
					 | 
				
			||||||
		scanline = studio.map.scanline;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for(s32 r = 0, pos = 0; r < TIC80_HEIGHT; r++, row += pitchWidth)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if(scanline)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			scanline(studio.tic, r);
 | 
					 | 
				
			||||||
			pal = paletteBlit();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if(bgOut)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			u8 border = tic_tool_peek4(studio.tic->ram.vram.mapping, studio.tic->ram.vram.vars.border & 0xf);
 | 
					 | 
				
			||||||
			SDL_memset4(bgOut, pal[border], TIC80_WIDTH);
 | 
					 | 
				
			||||||
			bgOut += bgPitchWidth;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		SDL_memset4(row, 0, pitchWidth);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for(u32* ptr = row + MAX_OFFSET + studio.tic->ram.vram.vars.offset.x, c = 0; c < TIC80_WIDTH; c++, ptr++)
 | 
					 | 
				
			||||||
			*ptr = pal[tic_tool_peek4(studio.tic->ram.vram.screen.data, pos++)];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void screen2buffer(u32* buffer, const u8* pixels, s32 pitch)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	for(s32 i = 0; i < TIC80_HEIGHT; i++)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		SDL_memcpy(buffer, pixels+MAX_OFFSET * sizeof(u32), TIC80_WIDTH * sizeof(u32));
 | 
					 | 
				
			||||||
		pixels += pitch;
 | 
					 | 
				
			||||||
		buffer += TIC80_WIDTH;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void setCoverImage()
 | 
					static void setCoverImage()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						tic_mem* tic = studio.tic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(studio.mode == TIC_RUN_MODE)
 | 
						if(studio.mode == TIC_RUN_MODE)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		enum {Pitch = FULL_WIDTH*sizeof(u32)};
 | 
							enum {Pitch = TIC80_FULLWIDTH*sizeof(u32)};
 | 
				
			||||||
		u32* pixels = SDL_malloc(Pitch * TIC80_HEIGHT);
 | 
							u32* pixels = SDL_malloc(Pitch * TIC80_FULLHEIGHT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if(pixels)
 | 
							if(pixels)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			blit(pixels, NULL, Pitch, 0);
 | 
								tic->api.blit(tic, pixels, tic->api.scanline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			u32* buffer = SDL_malloc(TIC80_WIDTH * TIC80_HEIGHT * sizeof(u32));
 | 
								u32* buffer = SDL_malloc(TIC80_WIDTH * TIC80_HEIGHT * sizeof(u32));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(buffer)
 | 
								if(buffer)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				screen2buffer(buffer, (const u8*)pixels, Pitch);
 | 
									SDL_Rect rect = {OFFSET_LEFT, OFFSET_TOP, TIC80_WIDTH, TIC80_HEIGHT};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									screen2buffer(buffer, pixels, rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				gif_write_animation(studio.tic->cart.cover.data, &studio.tic->cart.cover.size,
 | 
									gif_write_animation(studio.tic->cart.cover.data, &studio.tic->cart.cover.size,
 | 
				
			||||||
					TIC80_WIDTH, TIC80_HEIGHT, (const u8*)buffer, 1, TIC_FRAMERATE, 1);
 | 
										TIC80_WIDTH, TIC80_HEIGHT, (const u8*)buffer, 1, TIC_FRAMERATE, 1);
 | 
				
			||||||
@@ -1508,7 +1471,7 @@ static void stopVideoRecord()
 | 
				
			|||||||
			s32 size = 0;
 | 
								s32 size = 0;
 | 
				
			||||||
			u8* data = SDL_malloc(FRAME_SIZE * studio.video.frame);
 | 
								u8* data = SDL_malloc(FRAME_SIZE * studio.video.frame);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			gif_write_animation(data, &size, TIC80_WIDTH, TIC80_HEIGHT, (const u8*)studio.video.buffer, studio.video.frame, TIC_FRAMERATE, getConfig()->gifScale);
 | 
								gif_write_animation(data, &size, TIC80_FULLWIDTH, TIC80_FULLHEIGHT, (const u8*)studio.video.buffer, studio.video.frame, TIC_FRAMERATE, getConfig()->gifScale);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			fsGetFileData(onVideoExported, "screen.gif", data, size, DEFAULT_CHMOD, NULL);
 | 
								fsGetFileData(onVideoExported, "screen.gif", data, size, DEFAULT_CHMOD, NULL);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -1835,6 +1798,7 @@ static void blitSound()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	s32 samples = studio.audioSpec.freq / TIC_FRAMERATE;
 | 
						s32 samples = studio.audioSpec.freq / TIC_FRAMERATE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: use SDL_ConvertAudio to covert format
 | 
				
			||||||
	if(studio.audioSpec.format == AUDIO_F32)
 | 
						if(studio.audioSpec.format == AUDIO_F32)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if(!studio.floatSamples)
 | 
							if(!studio.floatSamples)
 | 
				
			||||||
@@ -1852,7 +1816,7 @@ static void blitSound()
 | 
				
			|||||||
		SDL_QueueAudio(studio.audioDevice, studio.tic->samples.buffer, studio.tic->samples.size);
 | 
							SDL_QueueAudio(studio.audioDevice, studio.tic->samples.buffer, studio.tic->samples.size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void drawRecordLabel(u8* frame, s32 pitch, s32 sx, s32 sy, const u32* color)
 | 
					static void drawRecordLabel(u32* frame, s32 pitch, s32 sx, s32 sy, const u32* color)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static const u16 RecLabel[] =
 | 
						static const u16 RecLabel[] =
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
@@ -1868,23 +1832,24 @@ static void drawRecordLabel(u8* frame, s32 pitch, s32 sx, s32 sy, const u32* col
 | 
				
			|||||||
		for(s32 x = 0; x < sizeof RecLabel[0]*BITS_IN_BYTE; x++)
 | 
							for(s32 x = 0; x < sizeof RecLabel[0]*BITS_IN_BYTE; x++)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if(RecLabel[y] & (1 << x))
 | 
								if(RecLabel[y] & (1 << x))
 | 
				
			||||||
				memcpy(&frame[((MAX_OFFSET + sx) + 15 - x + (y+sy)*(pitch/4))*4], color, sizeof *color);
 | 
									memcpy(&frame[sx + 15 - x + (y+sy)*TIC80_FULLWIDTH], color, sizeof *color);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void recordFrame(u8* pixels, s32 pitch)
 | 
					static void recordFrame(u32* pixels)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if(studio.video.record)
 | 
						if(studio.video.record)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if(studio.video.frame < studio.video.frames)
 | 
							if(studio.video.frame < studio.video.frames)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			screen2buffer(studio.video.buffer + (TIC80_WIDTH*TIC80_HEIGHT) * studio.video.frame, pixels, pitch);
 | 
								SDL_Rect rect = {0, 0, TIC80_FULLWIDTH, TIC80_FULLHEIGHT};
 | 
				
			||||||
 | 
								screen2buffer(studio.video.buffer + (TIC80_FULLWIDTH*TIC80_FULLHEIGHT) * studio.video.frame, pixels, rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if(studio.video.frame % TIC_FRAMERATE < TIC_FRAMERATE / 2)
 | 
								if(studio.video.frame % TIC_FRAMERATE < TIC_FRAMERATE / 2)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				const u32* pal = srcPaletteBlit(studio.tic->config.palette.data);
 | 
									const u32* pal = srcPaletteBlit(studio.tic->config.palette.data);
 | 
				
			||||||
				drawRecordLabel(pixels, pitch, TIC80_WIDTH-24, 8, &pal[tic_color_red]);
 | 
									drawRecordLabel(pixels, TIC80_FULLWIDTH, TIC80_WIDTH-24, 8, &pal[tic_color_red]);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			studio.video.frame++;
 | 
								studio.video.frame++;
 | 
				
			||||||
@@ -1899,42 +1864,73 @@ static void recordFrame(u8* pixels, s32 pitch)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void blitTexture()
 | 
					static void blitTexture()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						tic_mem* tic = studio.tic;
 | 
				
			||||||
	SDL_Rect rect = {0, 0, 0, 0};
 | 
						SDL_Rect rect = {0, 0, 0, 0};
 | 
				
			||||||
	calcTextureRect(&rect);
 | 
						calcTextureRect(&rect);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const s32 Pixel = rect.w / TIC80_WIDTH;
 | 
					 | 
				
			||||||
	rect.x -= MAX_OFFSET * Pixel;
 | 
					 | 
				
			||||||
	rect.w = rect.w * FULL_WIDTH / TIC80_WIDTH;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void* pixels = NULL;
 | 
						void* pixels = NULL;
 | 
				
			||||||
	s32 pitch = 0;
 | 
						s32 pitch = 0;
 | 
				
			||||||
	SDL_LockTexture(studio.texture, NULL, &pixels, &pitch);
 | 
						SDL_LockTexture(studio.texture, NULL, &pixels, &pitch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(studio.mode == TIC_RUN_MODE)
 | 
						tic_scanline scanline = NULL;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		rect.y += studio.tic->ram.vram.vars.offset.y * Pixel;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch(studio.mode)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
			void* bgPixels = NULL;
 | 
						case TIC_RUN_MODE:
 | 
				
			||||||
			s32 bgPitch = 0;
 | 
							scanline = tic->api.scanline;
 | 
				
			||||||
			SDL_LockTexture(studio.borderTexture, NULL, &bgPixels, &bgPitch);
 | 
							break;
 | 
				
			||||||
			blit(pixels, bgPixels, pitch, bgPitch);
 | 
						case TIC_SPRITE_MODE:
 | 
				
			||||||
			SDL_UnlockTexture(studio.borderTexture);
 | 
							scanline = studio.sprite.scanline;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case TIC_MAP_MODE:
 | 
				
			||||||
 | 
							scanline = studio.map.scanline;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			{
 | 
						tic->api.blit(tic, pixels, scanline);
 | 
				
			||||||
				SDL_Rect srcRect = {0, 0, TIC80_WIDTH, TIC80_HEIGHT};
 | 
					 | 
				
			||||||
				SDL_RenderCopy(studio.renderer, studio.borderTexture, &srcRect, NULL);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else blit(pixels, NULL, pitch, 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	recordFrame(pixels, pitch);
 | 
						recordFrame(pixels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SDL_UnlockTexture(studio.texture);
 | 
						SDL_UnlockTexture(studio.texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		SDL_Rect srcRect = {0, 0, FULL_WIDTH, TIC80_HEIGHT};
 | 
							enum {Header = OFFSET_TOP};
 | 
				
			||||||
 | 
							SDL_Rect srcRect = {0, 0, TIC80_FULLWIDTH, Header};
 | 
				
			||||||
 | 
							SDL_Rect dstRect = {0};
 | 
				
			||||||
 | 
							SDL_GetWindowSize(studio.window, &dstRect.w, &dstRect.h);
 | 
				
			||||||
 | 
							dstRect.h = rect.y;
 | 
				
			||||||
 | 
							SDL_RenderCopy(studio.renderer, studio.texture, &srcRect, &dstRect);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							enum {Header = OFFSET_TOP};
 | 
				
			||||||
 | 
							SDL_Rect srcRect = {0, TIC80_FULLHEIGHT - Header, TIC80_FULLWIDTH, Header};
 | 
				
			||||||
 | 
							SDL_Rect dstRect = {0};
 | 
				
			||||||
 | 
							SDL_GetWindowSize(studio.window, &dstRect.w, &dstRect.h);
 | 
				
			||||||
 | 
							dstRect.y = rect.y + rect.h;
 | 
				
			||||||
 | 
							dstRect.h = rect.y;
 | 
				
			||||||
 | 
							SDL_RenderCopy(studio.renderer, studio.texture, &srcRect, &dstRect);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							enum {Header = OFFSET_TOP};
 | 
				
			||||||
 | 
							enum {Left = OFFSET_LEFT};
 | 
				
			||||||
 | 
							SDL_Rect srcRect = {0, Header, Left, TIC80_HEIGHT};
 | 
				
			||||||
 | 
							SDL_Rect dstRect = {0};
 | 
				
			||||||
 | 
							SDL_GetWindowSize(studio.window, &dstRect.w, &dstRect.h);
 | 
				
			||||||
 | 
							dstRect.y = rect.y;
 | 
				
			||||||
 | 
							dstRect.h = rect.h;
 | 
				
			||||||
 | 
							SDL_RenderCopy(studio.renderer, studio.texture, &srcRect, &dstRect);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							enum {Top = OFFSET_TOP};
 | 
				
			||||||
 | 
							enum {Left = OFFSET_LEFT};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							SDL_Rect srcRect = {Left, Top, TIC80_WIDTH, TIC80_HEIGHT};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        SDL_RenderCopy(studio.renderer, studio.texture, &srcRect, &rect);
 | 
					        SDL_RenderCopy(studio.renderer, studio.texture, &srcRect, &rect);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -2180,11 +2176,6 @@ static void tick()
 | 
				
			|||||||
	SDL_SystemCursor cursor = studio.mouse.system;
 | 
						SDL_SystemCursor cursor = studio.mouse.system;
 | 
				
			||||||
	studio.mouse.system = SDL_SYSTEM_CURSOR_ARROW;
 | 
						studio.mouse.system = SDL_SYSTEM_CURSOR_ARROW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		const u8* pal = (u8*)(paletteBlit() + tic_tool_peek4(studio.tic->ram.vram.mapping, studio.tic->ram.vram.vars.border & 0xf));
 | 
					 | 
				
			||||||
		SDL_SetRenderDrawColor(studio.renderer, pal[2], pal[1], pal[0], SDL_ALPHA_OPAQUE);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	SDL_RenderClear(studio.renderer);
 | 
						SDL_RenderClear(studio.renderer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	renderStudio();
 | 
						renderStudio();
 | 
				
			||||||
@@ -2217,14 +2208,6 @@ static void initSound()
 | 
				
			|||||||
		SDL_PauseAudioDevice(studio.audioDevice, 0);
 | 
							SDL_PauseAudioDevice(studio.audioDevice, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static s32 textureLog2(s32 val)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	u32 rom = 0;
 | 
					 | 
				
			||||||
	while( val >>= 1 ) rom++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 1 << ++rom;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void initTouchGamepad()
 | 
					static void initTouchGamepad()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!studio.renderer)
 | 
						if (!studio.renderer)
 | 
				
			||||||
@@ -2234,8 +2217,7 @@ static void initTouchGamepad()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if(!studio.gamepad.texture)
 | 
						if(!studio.gamepad.texture)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		studio.gamepad.texture = SDL_CreateTexture(studio.renderer, STUDIO_PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING,
 | 
							studio.gamepad.texture = SDL_CreateTexture(studio.renderer, STUDIO_PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING, TEXTURE_SIZE, TEXTURE_SIZE);
 | 
				
			||||||
			textureLog2(TIC80_WIDTH), textureLog2(TIC80_HEIGHT));
 | 
					 | 
				
			||||||
		SDL_SetTextureBlendMode(studio.gamepad.texture, SDL_BLENDMODE_BLEND);
 | 
							SDL_SetTextureBlendMode(studio.gamepad.texture, SDL_BLENDMODE_BLEND);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2334,8 +2316,8 @@ static void onFSInitialized(FileSystem* fs)
 | 
				
			|||||||
	SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
 | 
						SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	studio.window = SDL_CreateWindow( TIC_TITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
 | 
						studio.window = SDL_CreateWindow( TIC_TITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
 | 
				
			||||||
		(TIC80_WIDTH+STUDIO_UI_BORDER) * STUDIO_UI_SCALE,
 | 
							(TIC80_FULLWIDTH) * STUDIO_UI_SCALE,
 | 
				
			||||||
		(TIC80_HEIGHT+STUDIO_UI_BORDER) * STUDIO_UI_SCALE,
 | 
							(TIC80_FULLHEIGHT) * STUDIO_UI_SCALE,
 | 
				
			||||||
		SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
 | 
							SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
 | 
				
			||||||
#if defined(__ARM_LINUX__)
 | 
					#if defined(__ARM_LINUX__)
 | 
				
			||||||
		| SDL_WINDOW_FULLSCREEN_DESKTOP
 | 
							| SDL_WINDOW_FULLSCREEN_DESKTOP
 | 
				
			||||||
@@ -2368,22 +2350,12 @@ static void onFSInitialized(FileSystem* fs)
 | 
				
			|||||||
	// set the window icon before renderer is created (issues on Linux)
 | 
						// set the window icon before renderer is created (issues on Linux)
 | 
				
			||||||
	setWindowIcon();
 | 
						setWindowIcon();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(__ARM_LINUX__)
 | 
						studio.renderer = SDL_CreateRenderer(studio.window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
 | 
				
			||||||
	s32 renderFlags = SDL_RENDERER_SOFTWARE;
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	s32 renderFlags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	studio.renderer = SDL_CreateRenderer(studio.window, -1, renderFlags);
 | 
						if(!studio.renderer)
 | 
				
			||||||
	studio.texture = SDL_CreateTexture(studio.renderer, STUDIO_PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING,
 | 
							studio.softwareRenderer = studio.renderer = SDL_CreateRenderer(studio.window, -1, SDL_RENDERER_SOFTWARE);
 | 
				
			||||||
		textureLog2(FULL_WIDTH), textureLog2(TIC80_HEIGHT));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if !defined(__ARM_LINUX__)
 | 
						studio.texture = SDL_CreateTexture(studio.renderer, STUDIO_PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING, TEXTURE_SIZE, TEXTURE_SIZE);
 | 
				
			||||||
	SDL_SetTextureBlendMode(studio.texture, SDL_BLENDMODE_BLEND);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	studio.borderTexture = SDL_CreateTexture(studio.renderer, STUDIO_PIXEL_FORMAT, SDL_TEXTUREACCESS_STREAMING,
 | 
					 | 
				
			||||||
		textureLog2(TIC80_WIDTH), textureLog2(TIC80_HEIGHT));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	initTouchGamepad();
 | 
						initTouchGamepad();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -2429,6 +2401,7 @@ s32 main(s32 argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	createFileSystem(onFSInitialized);
 | 
						createFileSystem(onFSInitialized);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
		u64 nextTick = SDL_GetPerformanceCounter();
 | 
							u64 nextTick = SDL_GetPerformanceCounter();
 | 
				
			||||||
		const u64 Delta = SDL_GetPerformanceFrequency() / TIC_FRAMERATE;
 | 
							const u64 Delta = SDL_GetPerformanceFrequency() / TIC_FRAMERATE;
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
@@ -2443,7 +2416,7 @@ s32 main(s32 argc, char **argv)
 | 
				
			|||||||
				SDL_Delay((u32)(delay * 1000 / SDL_GetPerformanceFrequency()));
 | 
									SDL_Delay((u32)(delay * 1000 / SDL_GetPerformanceFrequency()));
 | 
				
			||||||
			else nextTick -= delay;
 | 
								else nextTick -= delay;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2455,7 +2428,6 @@ s32 main(s32 argc, char **argv)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	SDL_DestroyTexture(studio.gamepad.texture);
 | 
						SDL_DestroyTexture(studio.gamepad.texture);
 | 
				
			||||||
	SDL_DestroyTexture(studio.texture);
 | 
						SDL_DestroyTexture(studio.texture);
 | 
				
			||||||
	SDL_DestroyTexture(studio.borderTexture);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(studio.mouse.texture)
 | 
						if(studio.mouse.texture)
 | 
				
			||||||
		SDL_DestroyTexture(studio.mouse.texture);
 | 
							SDL_DestroyTexture(studio.mouse.texture);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										99
									
								
								src/tic.c
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								src/tic.c
									
									
									
									
									
								
							@@ -493,6 +493,8 @@ static void api_clear(tic_mem* memory, u8 color)
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		api_rect(memory, machine->state.clip.l, machine->state.clip.t, machine->state.clip.r - machine->state.clip.l, machine->state.clip.b - machine->state.clip.t, color);
 | 
							api_rect(memory, machine->state.clip.l, machine->state.clip.t, machine->state.clip.r - machine->state.clip.l, machine->state.clip.b - machine->state.clip.t, color);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memory->ram.vram.vars.bg = color & 0xf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static s32 drawChar(tic_mem* memory, u8 symbol, s32 x, s32 y, s32 width, s32 height, u8 color, s32 scale)
 | 
					static s32 drawChar(tic_mem* memory, u8 symbol, s32 x, s32 y, s32 width, s32 height, u8 color, s32 scale)
 | 
				
			||||||
@@ -1638,6 +1640,102 @@ static s32 api_save(const tic_cartridge* cart, u8* buffer)
 | 
				
			|||||||
	return (s32)(buffer - start);
 | 
						return (s32)(buffer - start);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// copied from SDL2
 | 
				
			||||||
 | 
					inline void memset4(void *dst, u32 val, u32 dwords)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#if defined(__GNUC__) && defined(i386)
 | 
				
			||||||
 | 
					    s32 u0, u1, u2;
 | 
				
			||||||
 | 
					    __asm__ __volatile__ (
 | 
				
			||||||
 | 
					        "cld \n\t"
 | 
				
			||||||
 | 
					        "rep ; stosl \n\t"
 | 
				
			||||||
 | 
					        : "=&D" (u0), "=&a" (u1), "=&c" (u2)
 | 
				
			||||||
 | 
					        : "0" (dst), "1" (val), "2" (dwords)
 | 
				
			||||||
 | 
					        : "memory"
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    u32 _n = (dwords + 3) / 4;
 | 
				
			||||||
 | 
					    u32 *_p = (u32*)dst;
 | 
				
			||||||
 | 
					    u32 _val = (val);
 | 
				
			||||||
 | 
					    if (dwords == 0)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    switch (dwords % 4)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        case 0: do {    *_p++ = _val;
 | 
				
			||||||
 | 
					        case 3:         *_p++ = _val;
 | 
				
			||||||
 | 
					        case 2:         *_p++ = _val;
 | 
				
			||||||
 | 
					        case 1:         *_p++ = _val;
 | 
				
			||||||
 | 
					        } while ( --_n );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static u32* paletteBlit(tic_mem* tic)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static u32 pal[TIC_PALETTE_SIZE] = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const u8* src = tic->ram.vram.palette.data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(pal, 0xff, sizeof pal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8* dst = (u8*)pal;
 | 
				
			||||||
 | 
						const u8* end = src + sizeof(tic_palette);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum{RGB = sizeof(tic_rgb)};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(; src != end; dst++, src+=RGB)
 | 
				
			||||||
 | 
							for(s32 j = 0; j < RGB; j++)
 | 
				
			||||||
 | 
								*dst++ = *(src+(RGB-1)-j);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pal;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void api_blit(tic_mem* tic, u32* out, tic_scanline scanline)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const u32* pal = paletteBlit(tic);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(scanline)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							scanline(tic, 0);
 | 
				
			||||||
 | 
							pal = paletteBlit(tic);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enum {Top = (TIC80_FULLHEIGHT-TIC80_HEIGHT)/2, Bottom = Top};
 | 
				
			||||||
 | 
						enum {Left = (TIC80_FULLWIDTH-TIC80_WIDTH)/2, Right = Left};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset4(&out[0 * TIC80_FULLWIDTH], pal[tic->ram.vram.vars.border], TIC80_FULLWIDTH*Top);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(s32 r = 0; r < TIC80_HEIGHT; r++)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							memset4(&out[(r+Top) * TIC80_FULLWIDTH], pal[tic->ram.vram.vars.border], Left);
 | 
				
			||||||
 | 
							memset4(&out[(r+Top) * TIC80_FULLWIDTH + Left], pal[tic->ram.vram.vars.bg], TIC80_WIDTH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								s32 y = r + tic->ram.vram.vars.offset.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(y < 0 || y >= TIC80_HEIGHT) continue;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								for(s32 c = 0; c < TIC80_WIDTH; c++)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									s32 x = c + tic->ram.vram.vars.offset.x;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if(x < 0 || x >= TIC80_WIDTH) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									out[(c + Left) + (r+Top) * TIC80_FULLWIDTH] = pal[tic_tool_peek4(tic->ram.vram.screen.data, x + y * TIC80_WIDTH)];
 | 
				
			||||||
 | 
								}			
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memset4(&out[(r+Top) * TIC80_FULLWIDTH + (TIC80_FULLWIDTH-Right)], pal[tic->ram.vram.vars.border], Right);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(scanline && (r < TIC80_HEIGHT-1))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								scanline(tic, r+1);
 | 
				
			||||||
 | 
								pal = paletteBlit(tic);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset4(&out[(TIC80_FULLHEIGHT-Bottom) * TIC80_FULLWIDTH], pal[tic->ram.vram.vars.border], TIC80_FULLWIDTH*Bottom);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void initApi(tic_api* api)
 | 
					static void initApi(tic_api* api)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#define INIT_API(func) api->func = api_##func
 | 
					#define INIT_API(func) api->func = api_##func
 | 
				
			||||||
@@ -1682,6 +1780,7 @@ static void initApi(tic_api* api)
 | 
				
			|||||||
	INIT_API(save);
 | 
						INIT_API(save);
 | 
				
			||||||
	INIT_API(tick_start);
 | 
						INIT_API(tick_start);
 | 
				
			||||||
	INIT_API(tick_end);
 | 
						INIT_API(tick_end);
 | 
				
			||||||
 | 
						INIT_API(blit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef INIT_API
 | 
					#undef INIT_API
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								src/tic.h
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								src/tic.h
									
									
									
									
									
								
							@@ -355,7 +355,16 @@ typedef union
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		struct
 | 
							struct
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			u8 border;
 | 
								union
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									u8 colors;
 | 
				
			||||||
 | 
												
 | 
				
			||||||
 | 
									struct
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										u8 border:TIC_PALETTE_BPP;
 | 
				
			||||||
 | 
										u8 bg:TIC_PALETTE_BPP;
 | 
				
			||||||
 | 
									};
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			struct
 | 
								struct
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										48
									
								
								src/tic80.c
									
									
									
									
									
								
							
							
						
						
									
										48
									
								
								src/tic80.c
									
									
									
									
									
								
							@@ -111,52 +111,6 @@ TIC80_API void tic80_load(tic80* tic, void* cart, s32 size)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u32* srcPaletteBlit(const u8* src)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	static u32 pal[TIC_PALETTE_SIZE] = { 0 };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(pal, 0xff, sizeof pal);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	u8* dst = (u8*)pal;
 | 
					 | 
				
			||||||
	const u8* end = src + sizeof(tic_palette);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	enum { RGB = sizeof(tic_rgb) };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (; src != end; dst++, src += RGB)
 | 
					 | 
				
			||||||
		for (s32 j = 0; j < RGB; j++)
 | 
					 | 
				
			||||||
			*dst++ = *(src + (RGB - 1) - j);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return pal;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static u32* paletteBlit(tic_mem* memory)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return srcPaletteBlit(memory->ram.vram.palette.data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void blit(tic80* tic)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	tic80_local* tic80 = (tic80_local*)tic;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	u32* screen = tic->screen;
 | 
					 | 
				
			||||||
	u32* border = tic->border;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tic->offset.x = tic80->memory->ram.vram.vars.offset.x;
 | 
					 | 
				
			||||||
	tic->offset.y = tic80->memory->ram.vram.vars.offset.y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (s32 r = 0, pos = 0; r < TIC80_HEIGHT; r++, screen += TIC80_WIDTH)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		tic80->memory->api.scanline(tic80->memory, r);
 | 
					 | 
				
			||||||
		const u32* pal = paletteBlit(tic80->memory);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		tic->offset.rows[r] = tic80->memory->ram.vram.vars.offset.x;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		*border++ = pal[tic_tool_peek4(tic80->memory->ram.vram.mapping, tic80->memory->ram.vram.vars.border & 0xf)];
 | 
					 | 
				
			||||||
		for (u32* ptr = screen, c = 0; c < TIC80_WIDTH; c++, ptr++)
 | 
					 | 
				
			||||||
			*ptr = pal[tic_tool_peek4(tic80->memory->ram.vram.screen.data, pos++)];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
TIC80_API void tic80_tick(tic80* tic, tic80_input input)
 | 
					TIC80_API void tic80_tick(tic80* tic, tic80_input input)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	tic80_local* tic80 = (tic80_local*)tic;
 | 
						tic80_local* tic80 = (tic80_local*)tic;
 | 
				
			||||||
@@ -167,7 +121,7 @@ TIC80_API void tic80_tick(tic80* tic, tic80_input input)
 | 
				
			|||||||
	tic80->memory->api.tick(tic80->memory, &tic80->tickData);
 | 
						tic80->memory->api.tick(tic80->memory, &tic80->tickData);
 | 
				
			||||||
	tic80->memory->api.tick_end(tic80->memory);
 | 
						tic80->memory->api.tick_end(tic80->memory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	blit(tic);
 | 
						tic80->memory->api.blit(tic80->memory, tic->screen, tic80->memory->api.scanline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TickCounter++;
 | 
						TickCounter++;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -60,6 +60,7 @@ typedef struct
 | 
				
			|||||||
} tic_tick_data;
 | 
					} tic_tick_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct tic_mem tic_mem;
 | 
					typedef struct tic_mem tic_mem;
 | 
				
			||||||
 | 
					typedef void(*tic_scanline)(tic_mem* memory, s32 row);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct
 | 
					typedef struct
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -104,6 +105,7 @@ typedef struct
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	void (*tick_start)			(tic_mem* memory, const tic_sound* src);
 | 
						void (*tick_start)			(tic_mem* memory, const tic_sound* src);
 | 
				
			||||||
	void (*tick_end)			(tic_mem* memory);
 | 
						void (*tick_end)			(tic_mem* memory);
 | 
				
			||||||
 | 
						void (*blit)				(tic_mem* tic, u32* out, tic_scanline scanline);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tic_script_lang (*get_script)(tic_mem* memory);
 | 
						tic_script_lang (*get_script)(tic_mem* memory);
 | 
				
			||||||
} tic_api;
 | 
					} tic_api;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user