Implement most of the drawing routine
This commit is contained in:
parent
b30613e98d
commit
ac6d32d1b9
@ -35,8 +35,9 @@ REM WX treat warnings as errors
|
|||||||
REM wd4100 ignore: unused argument parameters
|
REM wd4100 ignore: unused argument parameters
|
||||||
REM wd4201 ignore: nonstandard extension used: nameless struct/union
|
REM wd4201 ignore: nonstandard extension used: nameless struct/union
|
||||||
REM wd4189 ignore: local variable is initialised but not referenced
|
REM wd4189 ignore: local variable is initialised but not referenced
|
||||||
|
REM wd4505 ignore: unreference local functions that will be removed
|
||||||
|
|
||||||
set CompileFlags=-EHa- -GR- -Oi -MT -Z7 -W4 -WX -wd4100 -wd4201 -wd4189
|
set CompileFlags=-EHa- -GR- -Oi -MT -Z7 -W4 -WX -wd4100 -wd4201 -wd4189 -wd4505
|
||||||
|
|
||||||
REM Include directories
|
REM Include directories
|
||||||
set IncludeFlags=
|
set IncludeFlags=
|
||||||
|
177
src/dchip8.cpp
177
src/dchip8.cpp
@ -73,7 +73,6 @@ FILE_SCOPE RandPCGState pcgState;
|
|||||||
|
|
||||||
FILE_SCOPE void dchip8_init_memory(u8 *memory)
|
FILE_SCOPE void dchip8_init_memory(u8 *memory)
|
||||||
{
|
{
|
||||||
DQNT_ASSERT(memory.permanentMemSize == 4096);
|
|
||||||
const u8 PRESET_FONTS[] =
|
const u8 PRESET_FONTS[] =
|
||||||
{
|
{
|
||||||
// "0"
|
// "0"
|
||||||
@ -206,14 +205,10 @@ FILE_SCOPE void dchip8_init_cpu(Chip8CPU *chip8CPU)
|
|||||||
chip8CPU->state = chip8state_load_file;
|
chip8CPU->state = chip8state_load_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
FILE_SCOPE
|
||||||
PlatformMemory memory)
|
void dchip8_debug_draw_half_colored_screen_internal(
|
||||||
|
PlatformRenderBuffer renderBuffer)
|
||||||
{
|
{
|
||||||
DQNT_ASSERT(indexRegister >= 0 && indexRegister <= 0xFFF);
|
|
||||||
DQNT_ASSERT(programCounter >= 0 && programCounter <= 0xFFF);
|
|
||||||
|
|
||||||
DQNT_ASSERT(renderBuffer.bytesPerPixel == 4);
|
|
||||||
|
|
||||||
const i32 numPixels = renderBuffer.width * renderBuffer.height;
|
const i32 numPixels = renderBuffer.width * renderBuffer.height;
|
||||||
u32 *bitmapBuffer = (u32 *)renderBuffer.memory;
|
u32 *bitmapBuffer = (u32 *)renderBuffer.memory;
|
||||||
for (i32 i = 0; i < numPixels; i++)
|
for (i32 i = 0; i < numPixels; i++)
|
||||||
@ -251,22 +246,49 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
bitmapBuffer[i] = color;
|
bitmapBuffer[i] = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE void dchip8_init_display(PlatformRenderBuffer renderBuffer)
|
||||||
|
{
|
||||||
|
// Init screen to 0 alpha, and let alpha simulate "turning on a pixel"
|
||||||
|
i32 numPixels = renderBuffer.width * renderBuffer.height;
|
||||||
|
u32 *bitmapBuffer = (u32 *)renderBuffer.memory;
|
||||||
|
for (i32 i = 0; i < numPixels; i++)
|
||||||
|
{
|
||||||
|
u8 r = (u8)(0.0f);
|
||||||
|
u8 g = (u8)(0.0f);
|
||||||
|
u8 b = (u8)(0.0f);
|
||||||
|
u8 a = (u8)(0.0f);
|
||||||
|
|
||||||
|
u32 color = (a << 24) | (r << 16) | (g << 8) | (b << 0);
|
||||||
|
bitmapBuffer[i] = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
||||||
|
PlatformMemory memory)
|
||||||
|
{
|
||||||
|
DQNT_ASSERT(cpu.indexRegister >= 0 && cpu.indexRegister <= 0xFFF);
|
||||||
|
DQNT_ASSERT(cpu.programCounter >= 0 && cpu.programCounter <= 0xFFF);
|
||||||
|
DQNT_ASSERT(renderBuffer.bytesPerPixel == 4);
|
||||||
|
DQNT_ASSERT(memory.permanentMemSize == 4096);
|
||||||
|
|
||||||
u8 *mainMem = (u8 *)memory.permanentMem;
|
u8 *mainMem = (u8 *)memory.permanentMem;
|
||||||
if (cpu.state == chip8state_init)
|
if (cpu.state == chip8state_init)
|
||||||
{
|
{
|
||||||
dchip8_init_cpu(&cpu);
|
dchip8_init_cpu(&cpu);
|
||||||
dchip8_init_memory(mainMem);
|
dchip8_init_memory(mainMem);
|
||||||
|
dchip8_init_display(renderBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
if (cpu.state == chip8state_load_file)
|
if (cpu.state == chip8state_load_file)
|
||||||
{
|
{
|
||||||
PlatformFile file = {};
|
PlatformFile file = {};
|
||||||
if (platform_open_file(L"roms/PONG", &file))
|
if (platform_open_file(L"roms/BLITZ", &file))
|
||||||
{
|
{
|
||||||
DQNT_ASSERT((cpu.INIT_ADDRESS + file.size) <=
|
DQNT_ASSERT((cpu.INIT_ADDRESS + file.size) <=
|
||||||
DQNT_ARRAY_COUNT(mainMem));
|
memory.permanentMemSize);
|
||||||
|
|
||||||
void *loadToAddr = (void *)(&mainMem[cpu.INIT_ADDRESS]);
|
void *loadToAddr = (void *)(&mainMem[cpu.INIT_ADDRESS]);
|
||||||
if (platform_read_file(file, loadToAddr, (u32)file.size))
|
if (platform_read_file(file, loadToAddr, (u32)file.size))
|
||||||
@ -296,15 +318,12 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
// CLS - 00E0 - Clear the display
|
// CLS - 00E0 - Clear the display
|
||||||
if (opLowByte == 0xE0)
|
if (opLowByte == 0xE0)
|
||||||
{
|
{
|
||||||
u32 numBytesToClear = renderBuffer.width *
|
dchip8_init_display(renderBuffer);
|
||||||
renderBuffer.height *
|
|
||||||
renderBuffer.bytesPerPixel;
|
|
||||||
memset(renderBuffer.memory, 0, numBytesToClear);
|
|
||||||
}
|
}
|
||||||
// RET - 00EE - Return from subroutine
|
// RET - 00EE - Return from subroutine
|
||||||
else if (opLowByte == 0xEE)
|
else if (opLowByte == 0xEE)
|
||||||
{
|
{
|
||||||
cpu.programCounter = cpu.stack[cpu.stackPointer--];
|
cpu.programCounter = cpu.stack[--cpu.stackPointer];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -312,7 +331,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
case 0x10:
|
case 0x10:
|
||||||
case 0x20:
|
case 0x20:
|
||||||
{
|
{
|
||||||
u16 loc = ((0x0F & opHighByte) << 8) | (0xFF & opLowByte);
|
u16 loc = ((0x0F & opHighByte) << 8) | opLowByte;
|
||||||
DQNT_ASSERT(loc <= 0x0FFF);
|
DQNT_ASSERT(loc <= 0x0FFF);
|
||||||
|
|
||||||
// JP addr - 1nnn - Jump to location nnn
|
// JP addr - 1nnn - Jump to location nnn
|
||||||
@ -324,10 +343,8 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
DQNT_ASSERT(opFirstNibble == 0x20);
|
DQNT_ASSERT(opFirstNibble == 0x20);
|
||||||
|
cpu.stack[cpu.stackPointer++] = cpu.programCounter;
|
||||||
cpu.stackPointer++;
|
|
||||||
DQNT_ASSERT(cpu.stackPointer < DQNT_ARRAY_COUNT(cpu.stack));
|
DQNT_ASSERT(cpu.stackPointer < DQNT_ARRAY_COUNT(cpu.stack));
|
||||||
cpu.stack[cpu.stackPointer] = cpu.programCounter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu.programCounter = loc;
|
cpu.programCounter = loc;
|
||||||
@ -363,7 +380,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
u8 firstRegNum = (0x0F & opHighByte);
|
u8 firstRegNum = (0x0F & opHighByte);
|
||||||
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
||||||
|
|
||||||
u8 secondRegNum = (0xF0 & opLowByte);
|
u8 secondRegNum = (0xF0 & opLowByte) >> 4;
|
||||||
DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
||||||
|
|
||||||
if (cpu.registerArray[firstRegNum] ==
|
if (cpu.registerArray[firstRegNum] ==
|
||||||
@ -400,37 +417,38 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
u8 firstRegNum = (0x0F & opHighByte);
|
u8 firstRegNum = (0x0F & opHighByte);
|
||||||
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
||||||
|
|
||||||
u8 secondRegNum = (0xF0 & opLowByte);
|
u8 secondRegNum = (0xF0 & opLowByte) >> 4;
|
||||||
DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
||||||
|
|
||||||
u8 *vx = &cpu.registerArray[firstRegNum];
|
u8 *vx = &cpu.registerArray[firstRegNum];
|
||||||
u8 *vy = &cpu.registerArray[secondRegNum];
|
u8 *vy = &cpu.registerArray[secondRegNum];
|
||||||
|
|
||||||
|
u8 opFourthNibble = (opLowByte & 0x0F);
|
||||||
// LD Vx, Vy - 8xy0 - Set Vx = Vy
|
// LD Vx, Vy - 8xy0 - Set Vx = Vy
|
||||||
if (opLowByte == 0x00)
|
if (opFourthNibble == 0x00)
|
||||||
{
|
{
|
||||||
*vx = *vy;
|
*vx = *vy;
|
||||||
}
|
}
|
||||||
// OR Vx, Vy - 8xy1 - Set Vx = Vx OR Vy
|
// OR Vx, Vy - 8xy1 - Set Vx = Vx OR Vy
|
||||||
else if (opLowByte == 0x01)
|
else if (opFourthNibble == 0x01)
|
||||||
{
|
{
|
||||||
u8 result = (*vx | *vy);
|
u8 result = (*vx | *vy);
|
||||||
*vx = result;
|
*vx = result;
|
||||||
}
|
}
|
||||||
// AND Vx, Vy - 8xy2 - Set Vx = Vx AND Vy
|
// AND Vx, Vy - 8xy2 - Set Vx = Vx AND Vy
|
||||||
else if (opLowByte == 0x02)
|
else if (opFourthNibble == 0x02)
|
||||||
{
|
{
|
||||||
u8 result = (*vx & *vy);
|
u8 result = (*vx & *vy);
|
||||||
*vx = result;
|
*vx = result;
|
||||||
}
|
}
|
||||||
// XOR Vx, Vy - 8xy3 - Set Vx = Vx XOR Vy
|
// XOR Vx, Vy - 8xy3 - Set Vx = Vx XOR Vy
|
||||||
else if (opLowByte == 0x03)
|
else if (opFourthNibble == 0x03)
|
||||||
{
|
{
|
||||||
u8 result = (*vx & *vy);
|
u8 result = (*vx & *vy);
|
||||||
*vx = result;
|
*vx = result;
|
||||||
}
|
}
|
||||||
// ADD Vx, Vy - 8xy4 - Set Vx = Vx + Vy, set VF = carry
|
// ADD Vx, Vy - 8xy4 - Set Vx = Vx + Vy, set VF = carry
|
||||||
else if (opLowByte == 0x04)
|
else if (opFourthNibble == 0x04)
|
||||||
{
|
{
|
||||||
u16 result = (*vx + *vy);
|
u16 result = (*vx + *vy);
|
||||||
*vx = (u8)result;
|
*vx = (u8)result;
|
||||||
@ -438,7 +456,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
if (result > 255) cpu.VF = (result > 255) ? 1 : 0;
|
if (result > 255) cpu.VF = (result > 255) ? 1 : 0;
|
||||||
}
|
}
|
||||||
// SUB Vx, Vy - 8xy5 - Set Vx = Vx - Vy, set VF = NOT borrow
|
// SUB Vx, Vy - 8xy5 - Set Vx = Vx - Vy, set VF = NOT borrow
|
||||||
else if (opLowByte == 0x05)
|
else if (opFourthNibble == 0x05)
|
||||||
{
|
{
|
||||||
if (*vx > *vy)
|
if (*vx > *vy)
|
||||||
cpu.VF = 1;
|
cpu.VF = 1;
|
||||||
@ -448,7 +466,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
*vx -= *vy;
|
*vx -= *vy;
|
||||||
}
|
}
|
||||||
// SHR Vx {, Vy} - 8xy6 - Set Vx = Vx SHR 1
|
// SHR Vx {, Vy} - 8xy6 - Set Vx = Vx SHR 1
|
||||||
else if (opLowByte == 0x06)
|
else if (opFourthNibble == 0x06)
|
||||||
{
|
{
|
||||||
if (*vx & 1)
|
if (*vx & 1)
|
||||||
cpu.VF = 1;
|
cpu.VF = 1;
|
||||||
@ -458,7 +476,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
*vx >>= 1;
|
*vx >>= 1;
|
||||||
}
|
}
|
||||||
// SUBN Vx {, Vy} - 8xy7 - Set Vx = Vy - Vx, set VF = NOT borrow
|
// SUBN Vx {, Vy} - 8xy7 - Set Vx = Vy - Vx, set VF = NOT borrow
|
||||||
else if (opLowByte == 0x07)
|
else if (opFourthNibble == 0x07)
|
||||||
{
|
{
|
||||||
if (*vy > *vx)
|
if (*vy > *vx)
|
||||||
cpu.VF = 1;
|
cpu.VF = 1;
|
||||||
@ -470,7 +488,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
// SHL Vx {, Vy} - 8xyE - Set Vx = SHL 1
|
// SHL Vx {, Vy} - 8xyE - Set Vx = SHL 1
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DQNT_ASSERT(opLowByte == 0x0E);
|
DQNT_ASSERT(opFourthNibble == 0x0E);
|
||||||
if ((*vx >> 7) == 1)
|
if ((*vx >> 7) == 1)
|
||||||
cpu.VF = 1;
|
cpu.VF = 1;
|
||||||
else
|
else
|
||||||
@ -487,7 +505,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
u8 firstRegNum = (0x0F & opHighByte);
|
u8 firstRegNum = (0x0F & opHighByte);
|
||||||
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
DQNT_ASSERT(firstRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
||||||
|
|
||||||
u8 secondRegNum = (0xF0 & opLowByte);
|
u8 secondRegNum = (0xF0 & opLowByte) >> 4;
|
||||||
DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
DQNT_ASSERT(secondRegNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
||||||
|
|
||||||
u8 *vx = &cpu.registerArray[firstRegNum];
|
u8 *vx = &cpu.registerArray[firstRegNum];
|
||||||
@ -500,7 +518,7 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
// LD I, addr - Annn - Set I = nnn
|
// LD I, addr - Annn - Set I = nnn
|
||||||
case 0xA0:
|
case 0xA0:
|
||||||
{
|
{
|
||||||
u8 valToSet = opLowByte;
|
u16 valToSet = ((0x0F & opHighByte) << 8) | opLowByte;
|
||||||
cpu.indexRegister = valToSet;
|
cpu.indexRegister = valToSet;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -531,14 +549,73 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
// location I at (Vx, Vy), set VF = collision
|
// location I at (Vx, Vy), set VF = collision
|
||||||
case 0xD0:
|
case 0xD0:
|
||||||
{
|
{
|
||||||
// TODO(doyle): Implement drawing
|
u8 xRegister = (0x0F & opHighByte);
|
||||||
u8 posX = (0x0F & opHighByte);
|
u8 yRegister = (0xF0 & opLowByte) >> 4;
|
||||||
u8 posY = (0xF0 & opLowByte);
|
DQNT_ASSERT(xRegister < DQNT_ARRAY_COUNT(cpu.registerArray) &&
|
||||||
|
yRegister < DQNT_ARRAY_COUNT(cpu.registerArray));
|
||||||
|
|
||||||
|
u8 initPosX = cpu.registerArray[xRegister];
|
||||||
|
u8 initPosY = cpu.registerArray[yRegister];
|
||||||
|
|
||||||
u8 readNumBytesFromMem = (0x0F & opLowByte);
|
u8 readNumBytesFromMem = (0x0F & opLowByte);
|
||||||
|
// NOTE: can't be more than 16 in Y according to specs.
|
||||||
|
DQNT_ASSERT(readNumBytesFromMem < 16);
|
||||||
|
|
||||||
|
u8 *renderBitmap = (u8 *)renderBuffer.memory;
|
||||||
|
const i32 BYTES_PER_PIXEL = renderBuffer.bytesPerPixel;
|
||||||
|
i32 pitch = renderBuffer.width * BYTES_PER_PIXEL;
|
||||||
|
|
||||||
for (i32 i = 0; i < readNumBytesFromMem; i++)
|
for (i32 i = 0; i < readNumBytesFromMem; i++)
|
||||||
{
|
{
|
||||||
u8 *memPtr = &mainMem[cpu.indexRegister + i];
|
u8 spriteBytes = mainMem[cpu.indexRegister + i];
|
||||||
|
u8 posY = initPosY + (u8)i;
|
||||||
|
|
||||||
|
if (posY >= renderBuffer.height) posY = 0;
|
||||||
|
|
||||||
|
const i32 ALPHA_BYTE_INTERVAL = renderBuffer.bytesPerPixel;
|
||||||
|
const i32 BITS_IN_BYTE = 8;
|
||||||
|
i32 baseBitShift = BITS_IN_BYTE - 1;
|
||||||
|
for (i32 shift = 0; shift < BITS_IN_BYTE; shift++)
|
||||||
|
{
|
||||||
|
u8 posX = initPosX + (u8)shift;
|
||||||
|
|
||||||
|
if (posX >= renderBuffer.width) posX = 0;
|
||||||
|
u32 bitmapOffset =
|
||||||
|
(posX * BYTES_PER_PIXEL) + (posY * pitch);
|
||||||
|
|
||||||
|
// NOTE: Since we are using a 4bpp bitmap, let's use the
|
||||||
|
// alpha channel to determine if a pixel is on or not.
|
||||||
|
u32 *pixel = (u32 *)(&renderBitmap[bitmapOffset]);
|
||||||
|
u8 alphaBit = (*pixel >> 24);
|
||||||
|
|
||||||
|
DQNT_ASSERT(alphaBit == 0 || alphaBit == 255);
|
||||||
|
bool pixelWasOn = (alphaBit == 255) ? true : false;
|
||||||
|
|
||||||
|
i32 bitShift = baseBitShift - shift;
|
||||||
|
bool spriteBit = ((spriteBytes >> bitShift) & 1);
|
||||||
|
bool pixelIsOn = (pixelWasOn ^ spriteBit);
|
||||||
|
|
||||||
|
// TODO(doyle): wrap pixels around
|
||||||
|
// NOTE: If caused a pixel to XOR into off, then this is
|
||||||
|
// known as a "collision" in chip8
|
||||||
|
if (pixelWasOn && !pixelIsOn)
|
||||||
|
{
|
||||||
|
cpu.VF = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cpu.VF = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixelIsOn)
|
||||||
|
{
|
||||||
|
*pixel = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*pixel = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -599,12 +676,31 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
// LD F, Vx - Fx29 - Set I = location of sprite for digit Vx
|
// LD F, Vx - Fx29 - Set I = location of sprite for digit Vx
|
||||||
else if (opLowByte == 0x29)
|
else if (opLowByte == 0x29)
|
||||||
{
|
{
|
||||||
// TODO: Implement
|
u8 hexCharFromFontSet = (0x0F & opHighByte);
|
||||||
|
DQNT_ASSERT(hexCharFromFontSet >= 0x00 &&
|
||||||
|
hexCharFromFontSet <= 0x0F);
|
||||||
|
|
||||||
|
const u8 BITS_IN_BYTE = 8;
|
||||||
|
u8 fontSizeInMem = BITS_IN_BYTE * 5;
|
||||||
|
u16 startMemAddrOfFontSet = 0;
|
||||||
|
cpu.I = (hexCharFromFontSet * fontSizeInMem) *
|
||||||
|
startMemAddrOfFontSet;
|
||||||
}
|
}
|
||||||
// LD B, Vx - Fx33 - Store BCD representations of Vx in memory
|
// LD B, Vx - Fx33 - Store BCD representations of Vx in memory
|
||||||
// locations I, I+1 and I+2
|
// locations I, I+1 and I+2
|
||||||
else if (opLowByte == 0x33)
|
else if (opLowByte == 0x33)
|
||||||
{
|
{
|
||||||
|
DQNT_ASSERT(regNum < DQNT_ARRAY_COUNT(cpu.registerArray));
|
||||||
|
u8 vxVal = *vx;
|
||||||
|
|
||||||
|
const i32 NUM_DIGITS_IN_HUNDREDS = 3;
|
||||||
|
for (i32 i = 0; i < NUM_DIGITS_IN_HUNDREDS; i++)
|
||||||
|
{
|
||||||
|
u8 rem = vxVal % 10;
|
||||||
|
vxVal /= 10;
|
||||||
|
|
||||||
|
mainMem[cpu.I + ((NUM_DIGITS_IN_HUNDREDS-1) - i)] = rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// LD [I], Vx - Fx55 - Store register V0 through Vx in memory
|
// LD [I], Vx - Fx55 - Store register V0 through Vx in memory
|
||||||
// starting at location I.
|
// starting at location I.
|
||||||
@ -632,6 +728,11 @@ void dchip8_update(PlatformRenderBuffer renderBuffer, PlatformInput input,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (cpu.delayTimer > 0) cpu.delayTimer--;
|
||||||
|
|
||||||
|
// TODO(doyle): This needs to play a buzzing sound whilst timer > 0
|
||||||
|
if (cpu.soundTimer > 0) cpu.soundTimer--;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#include "dqnt.h"
|
#include "dqnt.h"
|
||||||
|
|
||||||
// NOTE: Platform buffers are expected to be bottom to top! I.e. origin is
|
// NOTE: Platform buffers are expected to be top to bottom! I.e. origin is top
|
||||||
// bottom left.
|
// left, also 4 bytes per pixel with packing order A R G B
|
||||||
typedef struct PlatformRenderBuffer
|
typedef struct PlatformRenderBuffer
|
||||||
{
|
{
|
||||||
i32 width;
|
i32 width;
|
||||||
|
44
src/dqnt.h
44
src/dqnt.h
@ -26,13 +26,7 @@ typedef float f32;
|
|||||||
|
|
||||||
#define DQNT_INVALID_CODE_PATH 0
|
#define DQNT_INVALID_CODE_PATH 0
|
||||||
#define DQNT_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
|
#define DQNT_ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
|
||||||
|
|
||||||
#ifdef DEBUG_MODE
|
|
||||||
#define DQNT_ASSERT(expr) if (!(expr)) { (*((i32 *)0)) = 0; }
|
#define DQNT_ASSERT(expr) if (!(expr)) { (*((i32 *)0)) = 0; }
|
||||||
#else
|
|
||||||
#define DQNT_ASSERT(expr)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define DQNT_MATH_ABS(x) (((x) < 0) ? (-(x)) : (x))
|
#define DQNT_MATH_ABS(x) (((x) < 0) ? (-(x)) : (x))
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -61,6 +55,7 @@ char *dqnt_strncpy(char *dest, const char *src, i32 numChars);
|
|||||||
|
|
||||||
bool dqnt_str_reverse(char *const buf, const i32 bufSize);
|
bool dqnt_str_reverse(char *const buf, const i32 bufSize);
|
||||||
i32 dqnt_str_to_i32 (char *const buf, const i32 bufSize);
|
i32 dqnt_str_to_i32 (char *const buf, const i32 bufSize);
|
||||||
|
void dqnt_i32_to_str (i32 value, char *buf, i32 bufSize);
|
||||||
|
|
||||||
wchar_t dqnt_wchar_ascii_to_lower(wchar_t character);
|
wchar_t dqnt_wchar_ascii_to_lower(wchar_t character);
|
||||||
i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b);
|
i32 dqnt_wstrcmp(const wchar_t *a, const wchar_t *b);
|
||||||
@ -208,6 +203,43 @@ i32 dqnt_str_to_i32(char *const buf, const i32 bufSize)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dqnt_i32_to_str(i32 value, char *buf, i32 bufSize)
|
||||||
|
{
|
||||||
|
if (!buf || bufSize == 0) return;
|
||||||
|
|
||||||
|
if (value == 0)
|
||||||
|
{
|
||||||
|
buf[0] = '0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(doyle): Max 32bit integer (+-)2147483647
|
||||||
|
i32 charIndex = 0;
|
||||||
|
bool negative = false;
|
||||||
|
if (value < 0) negative = true;
|
||||||
|
|
||||||
|
if (negative) buf[charIndex++] = '-';
|
||||||
|
|
||||||
|
i32 val = DQNT_MATH_ABS(value);
|
||||||
|
while (val != 0 && charIndex < bufSize)
|
||||||
|
{
|
||||||
|
i32 rem = val % 10;
|
||||||
|
buf[charIndex++] = (u8)rem + '0';
|
||||||
|
val /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(doyle): If string is negative, we only want to reverse starting
|
||||||
|
// from the second character, so we don't put the negative sign at the end
|
||||||
|
if (negative)
|
||||||
|
{
|
||||||
|
dqnt_str_reverse(buf + 1, charIndex - 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dqnt_str_reverse(buf, charIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wchar_t dqnt_wchar_ascii_to_lower(wchar_t character)
|
wchar_t dqnt_wchar_ascii_to_lower(wchar_t character)
|
||||||
{
|
{
|
||||||
if (character >= L'A' && character <= L'Z')
|
if (character >= L'A' && character <= L'Z')
|
||||||
|
@ -71,20 +71,28 @@ FILE_SCOPE void win32_display_render_bitmap(Win32RenderBitmap renderBitmap,
|
|||||||
HDC deviceContext, LONG width,
|
HDC deviceContext, LONG width,
|
||||||
LONG height)
|
LONG height)
|
||||||
{
|
{
|
||||||
|
HDC stretchDC = CreateCompatibleDC(deviceContext);
|
||||||
|
SelectObject(stretchDC, renderBitmap.handle);
|
||||||
|
|
||||||
|
StretchBlt(deviceContext, 0, 0, width, height, stretchDC, 0,
|
||||||
|
0, renderBitmap.width, renderBitmap.height, SRCCOPY);
|
||||||
|
|
||||||
|
// NOTE: Win32 AlphaBlend requires the RGB components to be premultiplied
|
||||||
|
// with alpha.
|
||||||
|
#if 0
|
||||||
BLENDFUNCTION blend = {};
|
BLENDFUNCTION blend = {};
|
||||||
blend.BlendOp = AC_SRC_OVER;
|
blend.BlendOp = AC_SRC_OVER;
|
||||||
blend.SourceConstantAlpha = 255;
|
blend.SourceConstantAlpha = 255;
|
||||||
blend.AlphaFormat = AC_SRC_ALPHA;
|
blend.AlphaFormat = AC_SRC_ALPHA;
|
||||||
|
|
||||||
HDC alphaBlendDC = CreateCompatibleDC(deviceContext);
|
if (!AlphaBlend(deviceContext, 0, 0, width, height, deviceContext, 0, 0,
|
||||||
SelectObject(alphaBlendDC, renderBitmap.handle);
|
width, height, blend))
|
||||||
|
{
|
||||||
|
OutputDebugString(L"AlphaBlend() failed.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
AlphaBlend(deviceContext, 0, 0, width, height, alphaBlendDC, 0, 0,
|
DeleteDC(stretchDC);
|
||||||
renderBitmap.width, renderBitmap.height, blend);
|
|
||||||
StretchBlt(deviceContext, 0, 0, width, height, deviceContext, 0, 0,
|
|
||||||
renderBitmap.width, renderBitmap.height, SRCCOPY);
|
|
||||||
|
|
||||||
DeleteDC(alphaBlendDC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE inline void win32_parse_key_msg(KeyState *key, MSG msg)
|
FILE_SCOPE inline void win32_parse_key_msg(KeyState *key, MSG msg)
|
||||||
@ -172,8 +180,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||||||
// is slightly smaller than 800x600. Windows provides a function to help
|
// is slightly smaller than 800x600. Windows provides a function to help
|
||||||
// calculate the size you'd need by accounting for the window style.
|
// calculate the size you'd need by accounting for the window style.
|
||||||
RECT rect = {};
|
RECT rect = {};
|
||||||
rect.right = 128;
|
rect.right = 256;
|
||||||
rect.bottom = 64;
|
rect.bottom = 128;
|
||||||
|
|
||||||
DWORD windowStyle =
|
DWORD windowStyle =
|
||||||
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
|
||||||
@ -253,6 +261,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|||||||
platformBuffer.memory = renderBitmap.memory;
|
platformBuffer.memory = renderBitmap.memory;
|
||||||
platformBuffer.height = renderBitmap.height;
|
platformBuffer.height = renderBitmap.height;
|
||||||
platformBuffer.width = renderBitmap.width;
|
platformBuffer.width = renderBitmap.width;
|
||||||
|
platformBuffer.bytesPerPixel = renderBitmap.bytesPerPixel;
|
||||||
dchip8_update(platformBuffer, platformInput, platformMemory);
|
dchip8_update(platformBuffer, platformInput, platformMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user