update
This commit is contained in:
@@ -2,22 +2,41 @@
|
||||
|
||||
#define PI32 3.141592653589f
|
||||
|
||||
internal void renderPlayer(GameOffscreenBuffer *buffer, int playerX, int playerY) {
|
||||
uint8 *endOfBuffer = (uint8 *)buffer->memory + buffer->pitch*buffer->height;
|
||||
uint32 color = 0xFFFFFFFF;
|
||||
int top = playerY;
|
||||
int bottom = playerY + 10;
|
||||
for (int x = playerX; x < playerX + 10; x++) {
|
||||
uint8 *pixel = ((uint8 *)buffer->memory + x * buffer->bytesPerPixel + top*buffer->pitch);
|
||||
for (int y = top; y < bottom; y++) {
|
||||
if ((pixel >= buffer->memory) && (pixel + 4 < endOfBuffer)) {
|
||||
*(uint32 *)pixel = color;
|
||||
}
|
||||
pixel += buffer->pitch;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal void outputSineSound(GameSoundOutputBuffer *soundBuffer, GameState *state) {
|
||||
int16 toneVolume = 3000;
|
||||
int wavePeriod = soundBuffer->samplesPerSecond/state->toneHz;
|
||||
|
||||
int16 *sampleOut = soundBuffer->samples;
|
||||
for (int sampleIndex = 0; sampleIndex < soundBuffer->sampleCount; sampleIndex++) {
|
||||
int16 sampleValue = (int16)(sin(state->tSine) * (real32)toneVolume);
|
||||
*sampleOut++ = sampleValue;
|
||||
*sampleOut++ = sampleValue;
|
||||
state->tSine += 2.0f * PI32 / (real32)wavePeriod;
|
||||
#if 0
|
||||
int16 sampleValue = (int16)(sin(state->tSine) * (real32)toneVolume);
|
||||
#else
|
||||
int16 sampleValue = 0;
|
||||
#endif
|
||||
*sampleOut++ = sampleValue;
|
||||
*sampleOut++ = sampleValue;
|
||||
}
|
||||
}
|
||||
|
||||
internal void renderWeirdGradient(GameOffscreenBuffer *buffer, int xOffset, int yOffset) {
|
||||
int bytesPerPixel = 4;
|
||||
int pitch = buffer->width*bytesPerPixel;
|
||||
uint8 *row = (uint8 *)buffer->memory;
|
||||
for (int y = 0; y < buffer->height; y++) {
|
||||
uint32 *pixel = (uint32*)row;
|
||||
@@ -26,7 +45,7 @@ internal void renderWeirdGradient(GameOffscreenBuffer *buffer, int xOffset, int
|
||||
uint8 green = (uint8)(y + yOffset);
|
||||
*pixel++ = (green << 8) | blue;
|
||||
}
|
||||
row += pitch;
|
||||
row += buffer->pitch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,11 +65,16 @@ extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) {
|
||||
|
||||
state->toneHz = 440;
|
||||
state->tSine = 0;
|
||||
state->playerY = 100;
|
||||
state->playerX = 100;
|
||||
state->blueOffset = 0;
|
||||
state->greenOffset = 0;
|
||||
memory->isInitialised = true;
|
||||
}
|
||||
|
||||
for (int controllerIndex = 0; controllerIndex < ArrayCount(input->controllers); controllerIndex++) {
|
||||
GameControllerInput *controllerInput = &input->controllers[controllerIndex];
|
||||
/*
|
||||
if (controllerInput->isAnalog) {
|
||||
state->toneHz = 440 + (int)(128.0f*controllerInput->stickAvgX);
|
||||
state->greenOffset -= (int)(20.0f*controllerInput->stickAvgX);
|
||||
@@ -69,9 +93,18 @@ extern "C" GAME_UPDATE_AND_RENDER(gameUpdateAndRender) {
|
||||
state->blueOffset -= 10;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (controllerInput->btnDown.endedDown) {
|
||||
state->playerY -= 30;
|
||||
}
|
||||
|
||||
state->playerX += (int)(4.0f*controllerInput->stickAvgX);
|
||||
state->playerY -= (int)(4.0f*controllerInput->stickAvgY);
|
||||
}
|
||||
|
||||
renderWeirdGradient(videoBuf, state->greenOffset, state->blueOffset);
|
||||
renderPlayer(videoBuf, state->playerX, state->playerY);
|
||||
}
|
||||
|
||||
extern "C" GAME_GET_SOUND_SAMPLES(gameGetSoundSamples) {
|
||||
|
||||
@@ -97,6 +97,8 @@ struct GameOffscreenBuffer {
|
||||
void *memory;
|
||||
int width;
|
||||
int height;
|
||||
int bytesPerPixel;
|
||||
int pitch; // Bytes per row
|
||||
};
|
||||
|
||||
struct GameButtonState {
|
||||
@@ -151,6 +153,8 @@ struct GameState {
|
||||
int greenOffset;
|
||||
int blueOffset;
|
||||
real32 tSine;
|
||||
int playerY;
|
||||
int playerX;
|
||||
};
|
||||
|
||||
// === Game to platform services ===
|
||||
|
||||
@@ -104,6 +104,7 @@ internal void resizeDIBSection(Win32OffscreenBuffer *buffer, int width, int heig
|
||||
buffer->width = width;
|
||||
buffer->height = height;
|
||||
buffer->bytesPerPixel = 4;
|
||||
buffer->pitch = buffer->width*buffer->bytesPerPixel;
|
||||
|
||||
buffer->info.bmiHeader.biSize = sizeof(buffer->info.bmiHeader);
|
||||
buffer->info.bmiHeader.biWidth = buffer->width;
|
||||
@@ -359,7 +360,56 @@ internal void win32FillSoundBuffer(Win32SoundOutput *soundOutput, DWORD byteToLo
|
||||
}
|
||||
}
|
||||
|
||||
internal void win32ProcessPendingMessages(GameControllerInput *keyboardController) {
|
||||
internal void win32BeginRecordingInput(Win32State *win32State, int inputRecordingIndex) {
|
||||
win32State->inputRecordingIndex = inputRecordingIndex;
|
||||
char *filename = "recording.hmi";
|
||||
win32State->recordingHandle = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, NULL, NULL);
|
||||
DWORD bytesToWrite = (DWORD)win32State->gameMemoryTotalSize;
|
||||
Assert(bytesToWrite < 0xFFFFFFFF);
|
||||
DWORD bytesWritten;
|
||||
WriteFile(win32State->recordingHandle, win32State->gameMemoryBlock, bytesToWrite, &bytesWritten, NULL);
|
||||
}
|
||||
|
||||
internal void win32EndRecordingInput(Win32State *win32State) {
|
||||
CloseHandle(win32State->recordingHandle);
|
||||
win32State->inputRecordingIndex = 0;
|
||||
}
|
||||
|
||||
internal void win32RecordInput(Win32State *win32State, GameInput *newInput) {
|
||||
DWORD bytesWritten;
|
||||
WriteFile(win32State->recordingHandle, newInput, sizeof(*newInput), &bytesWritten, NULL);
|
||||
}
|
||||
|
||||
internal void win32BeginInputPlayback(Win32State *win32State, int inputPlayingIndex) {
|
||||
win32State->inputPlayingIndex = inputPlayingIndex;
|
||||
char *filename = "recording.hmi";
|
||||
win32State->playbackHandle = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
|
||||
DWORD bytesToRead = (DWORD)win32State->gameMemoryTotalSize;
|
||||
Assert(bytesToRead < 0xFFFFFFFF);
|
||||
DWORD bytesRead;
|
||||
ReadFile(win32State->playbackHandle, win32State->gameMemoryBlock, bytesToRead, &bytesRead, NULL);
|
||||
}
|
||||
|
||||
internal void win32EndInputPlayback(Win32State *win32State) {
|
||||
CloseHandle(win32State->playbackHandle);
|
||||
win32State->inputPlayingIndex = 0;
|
||||
}
|
||||
|
||||
internal void win32PlaybackInput(Win32State *win32State, GameInput *newInput) {
|
||||
DWORD bytesRead;
|
||||
if (ReadFile(win32State->playbackHandle, newInput, sizeof(*newInput), &bytesRead, NULL)) {
|
||||
if (bytesRead == 0) {
|
||||
// Restart
|
||||
int playingIndex = win32State->inputPlayingIndex;
|
||||
win32EndInputPlayback(win32State);
|
||||
win32BeginInputPlayback(win32State, playingIndex);
|
||||
} else {
|
||||
// there's still input, read next input
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void win32ProcessPendingMessages(Win32State *win32State, GameControllerInput *keyboardController) {
|
||||
MSG message;
|
||||
while (PeekMessageA(&message, NULL, NULL, NULL, PM_REMOVE)) {
|
||||
if (message.message == WM_QUIT) {
|
||||
@@ -397,6 +447,15 @@ internal void win32ProcessPendingMessages(GameControllerInput *keyboardControlle
|
||||
} else if (VKCode == VK_RIGHT) {
|
||||
win32ProcessKeyboardKeypress(&keyboardController->btnRight, isDown);
|
||||
} else if (VKCode == VK_SPACE) {
|
||||
} else if (VKCode == 'L') {
|
||||
if (isDown) {
|
||||
if (win32State->inputRecordingIndex == 0) {
|
||||
win32BeginRecordingInput(win32State, 1);
|
||||
} else {
|
||||
win32EndRecordingInput(win32State);
|
||||
win32BeginInputPlayback(win32State, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -430,12 +489,11 @@ inline real32 win32GetSecondsElapsed(LARGE_INTEGER start, LARGE_INTEGER end) {
|
||||
#define monitorRefreshHz 60
|
||||
#define gameUpdateHz (monitorRefreshHz / 2)
|
||||
|
||||
internal void win32DebugDrawVertical(Win32OffscreenBuffer *screenBuffer, int x, int top, int bottom, int32 color) {
|
||||
int pitch = screenBuffer->width*screenBuffer->bytesPerPixel;
|
||||
uint8 *pixel = (uint8 *)screenBuffer->memory + top * pitch + x*screenBuffer->bytesPerPixel;
|
||||
internal void win32DebugDrawVertical(Win32OffscreenBuffer *buffer, int x, int top, int bottom, int32 color) {
|
||||
uint8 *pixel = (uint8 *)buffer->memory + top * buffer->pitch + x*buffer->bytesPerPixel;
|
||||
for (int y = top; y < bottom; y++) {
|
||||
*(uint32 *)pixel = color;
|
||||
pixel += pitch;
|
||||
pixel += buffer->pitch;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,26 +503,27 @@ inline void win32DrawSoundBufferMarker(Win32OffscreenBuffer *buffer, Win32SoundO
|
||||
win32DebugDrawVertical(buffer, x, top, bottom, color);
|
||||
}
|
||||
|
||||
internal void win32DebugSyncDisplay(Win32OffscreenBuffer *screenBuffer, int markerCount, Win32DebugTimeMarker *markers, Win32SoundOutput *soundOutput, real32 targetSecondsPerFrame) {
|
||||
internal void win32DebugSyncDisplay(Win32OffscreenBuffer *buffer, int markerCount, Win32DebugTimeMarker *markers, Win32SoundOutput *soundOutput, real32 targetSecondsPerFrame) {
|
||||
int padX = 16;
|
||||
int padY = 16;
|
||||
|
||||
int top = padY;
|
||||
int bottom = screenBuffer->height - padY;
|
||||
int renderWidth = screenBuffer->width - 2 *padX;
|
||||
int bottom = buffer->height - padY;
|
||||
int renderWidth = buffer->width - 2 *padX;
|
||||
|
||||
real32 pxPerSoundBufferEntry = (real32)renderWidth / (real32)soundOutput->secondaryBufferSize;
|
||||
int pitch = screenBuffer->width*screenBuffer->bytesPerPixel;
|
||||
|
||||
#if 0
|
||||
for (int markerIndex = 0; markerIndex < markerCount; markerIndex++) {
|
||||
Win32DebugTimeMarker *thisMarker = &markers[markerIndex];
|
||||
real32 alpha = ((real32)(markerIndex + 1) / (real32)markerCount);
|
||||
int x = padX + (int)(pxPerSoundBufferEntry * (real32)thisMarker->writeCursor);
|
||||
uint8 *pixel = (uint8 *)screenBuffer->memory + top * pitch + x*screenBuffer->bytesPerPixel;
|
||||
uint8 *pixel = (uint8 *)buffer->memory + top * buffer->pitch + x*buffer->bytesPerPixel;
|
||||
uint32 newPixel = (uint32)((real32)alpha * 0xFFFFFFFF + (1.0f - alpha) * (*(uint32 *)pixel));
|
||||
win32DrawSoundBufferMarker(screenBuffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->playCursor, newPixel);
|
||||
win32DrawSoundBufferMarker(screenBuffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->writeCursor, 0x00FF0000);
|
||||
win32DrawSoundBufferMarker(buffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->playCursor, newPixel);
|
||||
win32DrawSoundBufferMarker(buffer, soundOutput, pxPerSoundBufferEntry, padX, top, bottom, thisMarker->writeCursor, 0x00FF0000);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void catStrings(size_t sourceACount, char *sourceA, size_t sourceBCount, char *sourceB, size_t destCount, char *dest) {
|
||||
@@ -536,6 +595,8 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
RegisterHotKey(window, HH_CTRLW, MOD_CONTROL, 'W');
|
||||
|
||||
globalRunning = true;
|
||||
Win32State win32State = {};
|
||||
|
||||
GameInput input[2] = {};
|
||||
GameInput *oldInput = &input[0];
|
||||
GameInput *newInput = &input[1];
|
||||
@@ -568,8 +629,9 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
gameMemory.debugReadEntireFile = debugReadEntireFile;
|
||||
gameMemory.debug_printf = debug_printf;
|
||||
|
||||
uint64 totalSize = gameMemory.permanentStorageSize + gameMemory.transientStorageSize;
|
||||
gameMemory.permanentStorage = VirtualAlloc(baseAddress, totalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
win32State.gameMemoryTotalSize = gameMemory.permanentStorageSize + gameMemory.transientStorageSize;
|
||||
win32State.gameMemoryBlock = VirtualAlloc(baseAddress, win32State.gameMemoryTotalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
gameMemory.permanentStorage = win32State.gameMemoryBlock;
|
||||
gameMemory.transientStorage = ((uint8 *)gameMemory.permanentStorage + gameMemory.permanentStorageSize);
|
||||
|
||||
win32InitSound(window, soundOutput.samplesPerSecond, soundOutput.secondaryBufferSize);
|
||||
@@ -602,7 +664,7 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
newKeyboardController->buttons[buttonIndex].endedDown = oldKeyboardController->buttons[buttonIndex].endedDown;
|
||||
}
|
||||
|
||||
win32ProcessPendingMessages(newKeyboardController);
|
||||
win32ProcessPendingMessages(&win32State, newKeyboardController);
|
||||
|
||||
XINPUT_STATE controllerState;
|
||||
int maxControllerCount = XUSER_MAX_COUNT;
|
||||
@@ -670,6 +732,16 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, PSTR commandLin
|
||||
videoBuffer.memory = globalBackBuffer.memory;
|
||||
videoBuffer.width = globalBackBuffer.width;
|
||||
videoBuffer.height = globalBackBuffer.height;
|
||||
videoBuffer.pitch = globalBackBuffer.pitch;
|
||||
videoBuffer.bytesPerPixel = globalBackBuffer.bytesPerPixel;
|
||||
|
||||
if (win32State.inputRecordingIndex) {
|
||||
win32RecordInput(&win32State, newInput);
|
||||
}
|
||||
if (win32State.inputPlayingIndex) {
|
||||
win32PlaybackInput(&win32State, newInput);
|
||||
}
|
||||
|
||||
game.updateAndRender(&gameMemory, &videoBuffer, newInput);
|
||||
|
||||
DWORD playCursor = 0;
|
||||
|
||||
@@ -6,6 +6,7 @@ struct Win32OffscreenBuffer {
|
||||
int width;
|
||||
int height;
|
||||
int bytesPerPixel;
|
||||
int pitch;
|
||||
};
|
||||
|
||||
struct Win32WindowDimensions {
|
||||
@@ -27,3 +28,17 @@ struct Win32DebugTimeMarker {
|
||||
DWORD playCursor;
|
||||
DWORD writeCursor;
|
||||
};
|
||||
|
||||
struct Win32RecordedInput {
|
||||
int inputCount;
|
||||
GameInput *inputStream;
|
||||
};
|
||||
|
||||
struct Win32State {
|
||||
HANDLE recordingHandle;
|
||||
uint32 inputRecordingIndex;
|
||||
HANDLE playbackHandle;
|
||||
uint32 inputPlayingIndex;
|
||||
uint64 gameMemoryTotalSize;
|
||||
void *gameMemoryBlock;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user