Bläddra i källkod

update

tags/day-25
Ledda 4 månader sedan
förälder
incheckning
45ccf2310d
5 ändrade filer med 295 tillägg och 45 borttagningar
  1. +1
    -1
      misc/bdebug.bat
  2. +1
    -1
      misc/brun.bat
  3. +5
    -0
      misc/build.bat
  4. +1
    -0
      misc/shell.bat
  5. +287
    -43
      src/main.cpp

+ 1
- 1
misc/bdebug.bat Visa fil

@@ -1,2 +1,2 @@
call build
call build || exit /b %errorlevel%
devenv .\build\main.exe

+ 1
- 1
misc/brun.bat Visa fil

@@ -1,2 +1,2 @@
call build
call build || exit /b %errorlevel%
.\build\main.exe

+ 5
- 0
misc/build.bat Visa fil

@@ -4,3 +4,8 @@ pushd .\build
pwd
cl -FC -Zi ..\src\main.cpp user32.lib Gdi32.lib
popd
exit /b

:error
echo Failed with error #%errorlevel%.
exit /b %errorlevel%

+ 1
- 0
misc/shell.bat Visa fil

@@ -1,4 +1,5 @@
@echo off
start "ProconXInput" "C:\Program Files\ProconXInput\ProconXInput.exe"
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
set path=C:\source\repos\handmade\misc;%path%
cd C:\source\repos\handmade\

+ 287
- 43
src/main.cpp Visa fil

@@ -1,10 +1,31 @@
#include <cstdarg>
#include <cstdio>
#include <cstdlib>
#include <windows.h>
#include <stdint.h>
#include <Xinput.h>
#include <dsound.h>
#include <math.h>

#define internal static // for functions
#define local_persist static // for static variables in a scope
#define global static // for global variables

typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;

typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;

typedef float real32;
typedef double real64;

typedef int32_t bool32;

struct Win32OffscreenBuffer {
BITMAPINFO info;
void *memory;
@@ -18,25 +39,46 @@ struct Win32WindowDimensions {
int height;
};

#define PI32 3.141592653589f

global ATOM HH_CTRLW;
global bool running;
global Win32OffscreenBuffer globalBackBuffer;
global LPDIRECTSOUNDBUFFER globalSecondaryBuffer;

typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
void debug_printf(char* format, ...) {
int bufsize = strlen(format)*10;
char *output = (char*)malloc(bufsize);
va_list list;
va_start(list, format);
vsprintf_s(output, bufsize, format, list);
OutputDebugStringA(output);
free(output);
}

// XInputGetState
#define X_INPUT_GET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_STATE *pState)
typedef X_INPUT_GET_STATE(XInputGetStateFn);
X_INPUT_GET_STATE(XInputGetStateStub) { return ERROR_DEVICE_NOT_CONNECTED; }
global XInputGetStateFn *XInputGetStateDyn = XInputGetStateStub;
#define XInputGetState XInputGetStateDyn

// XInputSetState
#define X_INPUT_SET_STATE(name) DWORD WINAPI name(DWORD dwUserIndex, XINPUT_VIBRATION *pVibration)
typedef X_INPUT_SET_STATE(XInputSetStateFn);
X_INPUT_SET_STATE(XInputSetStateStub) { return ERROR_DEVICE_NOT_CONNECTED; }
global XInputSetStateFn *XInputSetStateDyn = XInputSetStateStub;
#define XInputSetState XInputSetStateDyn

typedef HRESULT WINAPI DirectSoundCreateFn(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter);

internal void renderWeirdGradient(Win32OffscreenBuffer buffer, int xOffset, int yOffset) {
internal void renderWeirdGradient(Win32OffscreenBuffer *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++) {
int pitch = buffer->width*bytesPerPixel;
uint8 *row = (uint8 *)buffer->memory;
for (int y = 0; y < buffer->height; y++) {
uint32 *pixel = (uint32*)row;
for (int x = 0; x < buffer.width; x++) {
for (int x = 0; x < buffer->width; x++) {
uint8 blue = x + xOffset;
uint8 green = y + yOffset;
*pixel++ = (green << 8) | blue;
@@ -54,22 +96,18 @@ internal void resizeDIBSection(Win32OffscreenBuffer *buffer, int width, int heig
buffer->height = height;
buffer->bytesPerPixel = 4;

buffer->info = {
.bmiHeader = {
.biSize = sizeof(buffer->info.bmiHeader),
.biWidth = buffer->width,
.biHeight = -buffer->height,
.biPlanes = 1,
.biBitCount = 32,
.biCompression = BI_RGB,
},
};
buffer->info.bmiHeader.biSize = sizeof(buffer->info.bmiHeader);
buffer->info.bmiHeader.biWidth = buffer->width;
buffer->info.bmiHeader.biHeight = -buffer->height;
buffer->info.bmiHeader.biPlanes = 1;
buffer->info.bmiHeader.biBitCount = 32;
buffer->info.bmiHeader.biCompression = BI_RGB;

int bitmapSize = buffer->width*buffer->height*buffer->bytesPerPixel;
buffer->memory = VirtualAlloc(NULL, bitmapSize, MEM_COMMIT, PAGE_READWRITE);
}

Win32WindowDimensions win32GetWindowDimensions(HWND window) {
internal Win32WindowDimensions win32GetWindowDimensions(HWND window) {
Win32WindowDimensions result;
RECT clientRect;
GetClientRect(window, &clientRect);
@@ -78,19 +116,78 @@ Win32WindowDimensions win32GetWindowDimensions(HWND window) {
return result;
}

void win32DrawBufferInWindow(Win32OffscreenBuffer buffer, HWND window) {
internal void win32DrawBufferInWindow(Win32OffscreenBuffer *buffer, HWND window) {
Win32WindowDimensions winDims = win32GetWindowDimensions(window);
StretchDIBits(
GetDC(window),
0, 0, winDims.width, winDims.height,
0, 0, buffer.width, buffer.height,
buffer.memory,
&buffer.info,
0, 0, buffer->width, buffer->height,
buffer->memory,
&buffer->info,
DIB_RGB_COLORS,
SRCCOPY
);
}

internal void win32LoadXInput() {
HMODULE xInputLib = LoadLibrary("xinput1_4.dll");
if (!xInputLib) {
xInputLib = LoadLibrary("xinput1_3.dll");
}

if (xInputLib) {
XInputGetState = (XInputGetStateFn *)GetProcAddress(xInputLib, "XInputGetState");
XInputSetState = (XInputSetStateFn *)GetProcAddress(xInputLib, "XInputSetState");
}
}

internal void win32InitSound(HWND window, int32 samplesPerSec, int bufferSize) {
HMODULE dSoundLibrary = LoadLibraryA("dsound.dll");
if (dSoundLibrary) {
DirectSoundCreateFn *DirectSoundCreate = (DirectSoundCreateFn*)GetProcAddress(dSoundLibrary, "DirectSoundCreate");
LPDIRECTSOUND DirectSound;
if (DirectSoundCreate && SUCCEEDED(DirectSoundCreate(0, &DirectSound, 0))) {
WAVEFORMATEX waveFormat = {};
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = 2;
waveFormat.nSamplesPerSec = samplesPerSec;
waveFormat.wBitsPerSample = 16;
waveFormat.nBlockAlign = (waveFormat.nChannels*waveFormat.wBitsPerSample) / 8;
waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec*waveFormat.nBlockAlign;
waveFormat.cbSize = 0;

if (SUCCEEDED(DirectSound->SetCooperativeLevel(window, DSSCL_PRIORITY))) {
DSBUFFERDESC bufferDescription = {};
bufferDescription.dwSize = sizeof(bufferDescription);
bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;

LPDIRECTSOUNDBUFFER primaryBuffer;
if (SUCCEEDED(DirectSound->CreateSoundBuffer(&bufferDescription, &primaryBuffer, 0))) {
if (SUCCEEDED(primaryBuffer->SetFormat(&waveFormat))) {
OutputDebugStringA("Primary buffer format was set.\n");
} else {
//No sound! (?)
}
}
} else {
// No sound! (?)
}

DSBUFFERDESC bufferDescription = {};
bufferDescription.dwSize = sizeof(bufferDescription);
bufferDescription.dwFlags = 0;
bufferDescription.dwBufferBytes = bufferSize;
bufferDescription.lpwfxFormat = &waveFormat;

if (SUCCEEDED(DirectSound->CreateSoundBuffer(&bufferDescription, &globalSecondaryBuffer, 0))) {
OutputDebugStringA("Secondary buffer created successfully!\n");
}
} else {
// No sound! (?)
}
}
}

LRESULT mainWindowCallback(
HWND window,
UINT message,
@@ -103,7 +200,7 @@ LRESULT mainWindowCallback(
} break;

case WM_DESTROY: {
//OutputDebugStringA("WM_DESTROY\n");
OutputDebugStringA("WM_DESTROY\n");
} break;

case WM_CLOSE: {
@@ -117,34 +214,109 @@ LRESULT mainWindowCallback(
int y = paint.rcPaint.top;
int width = paint.rcPaint.right - paint.rcPaint.left;
int height = paint.rcPaint.bottom - paint.rcPaint.top;
win32DrawBufferInWindow(globalBackBuffer, window);
win32DrawBufferInWindow(&globalBackBuffer, window);
EndPaint(window, &paint);
} break;

case WM_ACTIVATEAPP: {
running = false;
} break;

case WM_HOTKEY: {
if (wParam == HH_CTRLW) {
running = false;
}
} break;

case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYUP:
case WM_KEYDOWN: {
uint32 VKCode = wParam;
bool wasDown = (lParam & (1 << 30)) != 0;
bool isDown = (lParam & (1 << 31)) == 0;
if (wasDown != isDown) {
if (VKCode == 'W') {
} else if (VKCode == 'A') {
} else if (VKCode == 'S') {
} else if (VKCode == 'D') {
} else if (VKCode == 'Q') {
} else if (VKCode == 'E') {
} else if (VKCode == VK_ESCAPE) {
} else if (VKCode == VK_UP) {
} else if (VKCode == VK_LEFT) {
} else if (VKCode == VK_DOWN) {
} else if (VKCode == VK_RIGHT) {
} else if (VKCode == VK_SPACE) {
}
}

bool32 altKeyWasDown = lParam & (1 << 29);
if (altKeyWasDown && VKCode == VK_F4) {
running = false;
}
} break;

default: {
result = DefWindowProcA(window, message, wParam, lParam);
//OutputDebugStringA("default\n");
} break;
}
return result;
}

struct Win32SoundOutput {
int samplesPerSecond;
int toneHz;
int wavePeriod;
int16 toneVolume;
uint32 runningSampleIndex;
int bytesPerSample;
int secondaryBufferSize;
};

internal void win32FillSoundBuffer(Win32SoundOutput *soundOutput, DWORD byteToLock, DWORD bytesToWrite) {
VOID *region1;
DWORD region1Size;
VOID *region2;
DWORD region2Size;
HRESULT lock = globalSecondaryBuffer->Lock(byteToLock, bytesToWrite, &region1, &region1Size, &region2, &region2Size, 0);
if (SUCCEEDED(lock)) {
DWORD region1SampleCount = region1Size/soundOutput->bytesPerSample;
int16 *sampleOut = (int16*)region1;
for (DWORD sampleIndex = 0; sampleIndex < region1SampleCount; sampleIndex++) {
real32 t = 2.0f * PI32 * (real32)soundOutput->runningSampleIndex / (real32)soundOutput->wavePeriod;
int16 sampleValue = (int16)(sin(t) * (real32)soundOutput->toneVolume);
*sampleOut++ = sampleValue;
*sampleOut++ = sampleValue;
soundOutput->runningSampleIndex++;
}
DWORD region2SampleCount = region2Size/soundOutput->bytesPerSample;
sampleOut = (int16*)region2;
for (DWORD sampleIndex = 0; sampleIndex < region2SampleCount; sampleIndex++) {
real32 t = 2.0f * PI32 * (real32)soundOutput->runningSampleIndex / (real32)soundOutput->wavePeriod;
int16 sampleValue = (int16)(sin(t) * soundOutput->toneVolume);
*sampleOut++ = sampleValue;
*sampleOut++ = sampleValue;
soundOutput->runningSampleIndex++;
}
globalSecondaryBuffer->Unlock(region1, region1Size, region2, region2Size);
} else {
OutputDebugStringA("No lock!\n");
}
}

int APIENTRY WinMain(
HINSTANCE instance,
HINSTANCE prevInstance,
PSTR commandLine,
int commandShow
) {
WNDCLASS windowClass = {
.style = CS_VREDRAW | CS_HREDRAW,
.lpfnWndProc = &mainWindowCallback,
.hInstance = instance,
.lpszClassName = "HandmadeHeroWindowClass",
};
win32LoadXInput();

WNDCLASSA windowClass = {};
windowClass.style = CS_VREDRAW | CS_HREDRAW;
windowClass.lpfnWndProc = &mainWindowCallback;
windowClass.hInstance = instance;
windowClass.lpszClassName = "HandmadeHeroWindowClass";

resizeDIBSection(&globalBackBuffer, 1280, 720);

@@ -164,22 +336,94 @@ int APIENTRY WinMain(
NULL
);
if (window) {
HH_CTRLW = GlobalAddAtomA("HH_CTRLW");
RegisterHotKey(window, HH_CTRLW, MOD_CONTROL, 'W');

MSG message;
running = true;

// graphics test
int xOffset = 0;
int yOffset = 0;

// sound test
Win32SoundOutput soundOutput = {};
soundOutput.samplesPerSecond = 48000;
soundOutput.toneHz = 440; // A above middle C
soundOutput.wavePeriod = soundOutput.samplesPerSecond / soundOutput.toneHz;
soundOutput.toneVolume = 6000;
soundOutput.runningSampleIndex = 0;
soundOutput.bytesPerSample = sizeof(int16)*2;
soundOutput.secondaryBufferSize = soundOutput.samplesPerSecond*soundOutput.bytesPerSample;

win32InitSound(window, soundOutput.samplesPerSecond, soundOutput.secondaryBufferSize);
win32FillSoundBuffer(&soundOutput, 0, soundOutput.secondaryBufferSize);
globalSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);

while (running) {
while(PeekMessageA(&message, NULL, NULL, NULL, PM_REMOVE)) {
while (PeekMessageA(&message, NULL, NULL, NULL, PM_REMOVE)) {
if (message.message == WM_QUIT) {
running = false;
}
TranslateMessage(&message);
DispatchMessage(&message);
}
renderWeirdGradient(globalBackBuffer, xOffset, yOffset);
win32DrawBufferInWindow(globalBackBuffer, window);
xOffset++;
yOffset++;

XINPUT_STATE controllerState;
for (DWORD controllerIndex = 0; controllerIndex < XUSER_MAX_COUNT; controllerIndex++) {
if (XInputGetState(controllerIndex, &controllerState) == ERROR_SUCCESS) {
break;
} else {
// controller not available
}
}
XINPUT_GAMEPAD *Pad = &controllerState.Gamepad;
bool up = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_UP);
bool down = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_DOWN);
bool left = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_LEFT);
bool right = (Pad->wButtons & XINPUT_GAMEPAD_DPAD_RIGHT);
bool start = (Pad->wButtons & XINPUT_GAMEPAD_START);
bool back = (Pad->wButtons & XINPUT_GAMEPAD_BACK);
bool leftShoulder = (Pad->wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER);
bool rightShoulder = (Pad->wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER);
bool aButton = (Pad->wButtons & XINPUT_GAMEPAD_A);
bool bButton = (Pad->wButtons & XINPUT_GAMEPAD_B);
bool xButton = (Pad->wButtons & XINPUT_GAMEPAD_X);
bool yButton = (Pad->wButtons & XINPUT_GAMEPAD_Y);
int16 stickX = Pad->sThumbLX;
int16 stickY = Pad->sThumbLY;

float stickYNorm = 0;
float stickXNorm = 0;
if (stickY != 0 && abs(stickY) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
stickYNorm = stickY / 32767.0;
}
if (stickX != 0 && abs(stickX) > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) {
stickXNorm = stickX / 32767.0;
}

yOffset += stickY/5000;
xOffset -= stickX/5000;

renderWeirdGradient(&globalBackBuffer, xOffset, yOffset);

// Sound test
DWORD playCursor;
DWORD writeCursor;
if (SUCCEEDED(globalSecondaryBuffer->GetCurrentPosition(&playCursor, &writeCursor))) {
DWORD byteToLock = (soundOutput.runningSampleIndex*soundOutput.bytesPerSample) % soundOutput.secondaryBufferSize;
DWORD bytesToWrite;
if (byteToLock == playCursor) {
bytesToWrite = 0;
} else if (byteToLock > playCursor) {
bytesToWrite = soundOutput.secondaryBufferSize - byteToLock + playCursor;
} else {
bytesToWrite = playCursor - byteToLock;
}
win32FillSoundBuffer(&soundOutput, byteToLock, bytesToWrite);
}

win32DrawBufferInWindow(&globalBackBuffer, window);
}
} else {
// failed


Laddar…
Avbryt
Spara