Merge branch 'new_blit'

This commit is contained in:
BADIM-PC\Vadim 2017-11-06 12:43:20 +03:00
commit a4826af052
9 changed files with 234 additions and 197 deletions

View File

@ -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>

View File

@ -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;

View File

@ -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

View File

@ -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"),

View File

@ -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,43 +1864,74 @@ 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;
switch(studio.mode)
{ {
rect.y += studio.tic->ram.vram.vars.offset.y * Pixel; case TIC_RUN_MODE:
scanline = tic->api.scanline;
{ break;
void* bgPixels = NULL; case TIC_SPRITE_MODE:
s32 bgPitch = 0; scanline = studio.sprite.scanline;
SDL_LockTexture(studio.borderTexture, NULL, &bgPixels, &bgPitch); break;
blit(pixels, bgPixels, pitch, bgPitch); case TIC_MAP_MODE:
SDL_UnlockTexture(studio.borderTexture); scanline = studio.map.scanline;
break;
{ default:
SDL_Rect srcRect = {0, 0, TIC80_WIDTH, TIC80_HEIGHT}; break;
SDL_RenderCopy(studio.renderer, studio.borderTexture, &srcRect, NULL);
}
}
} }
else blit(pixels, NULL, pitch, 0);
recordFrame(pixels, pitch); tic->api.blit(tic, pixels, scanline);
recordFrame(pixels);
SDL_UnlockTexture(studio.texture); SDL_UnlockTexture(studio.texture);
{ {
SDL_Rect srcRect = {0, 0, FULL_WIDTH, TIC80_HEIGHT}; enum {Header = OFFSET_TOP};
SDL_RenderCopy(studio.renderer, studio.texture, &srcRect, &rect); 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);
} }
} }
@ -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,22 +2401,23 @@ s32 main(s32 argc, char **argv)
createFileSystem(onFSInitialized); createFileSystem(onFSInitialized);
u64 nextTick = SDL_GetPerformanceCounter();
const u64 Delta = SDL_GetPerformanceFrequency() / TIC_FRAMERATE;
while (!studio.quitFlag)
{ {
nextTick += Delta; u64 nextTick = SDL_GetPerformanceCounter();
tick(); const u64 Delta = SDL_GetPerformanceFrequency() / TIC_FRAMERATE;
while (!studio.quitFlag)
{
nextTick += Delta;
tick();
s64 delay = nextTick - SDL_GetPerformanceCounter(); s64 delay = nextTick - SDL_GetPerformanceCounter();
if(delay > 0) if(delay > 0)
SDL_Delay((u32)(delay * 1000 / SDL_GetPerformanceFrequency())); SDL_Delay((u32)(delay * 1000 / SDL_GetPerformanceFrequency()));
else nextTick -= delay; else nextTick -= delay;
}
} }
#endif #endif
if(studio.tic80local) if(studio.tic80local)
@ -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);

View File

@ -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
} }

View File

@ -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
{ {

View File

@ -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++;
} }

View File

@ -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;