#include "rendering.h" #include "tier0/platform.h" #include "tier1/utlvector.h" #include "console.h" #include "tier1/commandline.h" #include "input.h" #define NS_PRIVATE_IMPLEMENTATION #define MTL_PRIVATE_IMPLEMENTATION #define MTK_PRIVATE_IMPLEMENTATION #define CA_PRIVATE_IMPLEMENTATION #include "tier0/minmax_off.h" #include "QuartzCore/CAMetalLayer.hpp" #include "Metal/Metal.hpp" #include "SDL3/SDL.h" #include "SDL3/SDL_keycode.h" #include "SDL3/SDL_metal.h" #include "SDL3/SDL_events.h" #include "tier0/minmax.h" #include "ml_video.h" char g_bConfigNotify = 0; uint32_t g_nWindowWidth = 1280; uint32_t g_nWindowHeight = 720; SDL_Window *g_window; SDL_MetalView g_mlView; CA::MetalLayer *g_mlLayer; MTL::Device *g_mlDevice; MTL::CommandQueue *g_mlCommandQueue; MTL::CommandBuffer *g_mlCommandBuffer; NS::AutoreleasePool *g_mlPool; MTL::Texture *g_mlDrawableTexture; MTL::PixelFormat g_swapchainFormat; #if defined(__APPLE__) && defined(__MACH__) #include "TargetConditionals.h" #if TARGET_OS_IPHONE // iOS #define SDL_METAL_VIEW UI::View #define STBI_NO_THREAD_LOCALS #else // macOS #define SDL_METAL_VIEW NS::View #endif #else // Other platforms #endif void IInput::SetInputMode( EInputMode mode ) { switch (mode) { case INPUT_MODE_GAME: g_currentInputMode = INPUT_MODE_GAME; SDL_SetWindowRelativeMouseMode(g_window, true); return; default: g_currentInputMode = INPUT_MODE_MENU; SDL_SetWindowRelativeMouseMode(g_window, false); return; } } EInputKey ISDL_KeyName(SDL_Keycode key) { switch(key) { case SDLK_ESCAPE: return KEY_ESCAPE; case SDLK_TAB: return KEY_TAB; case SDLK_RETURN: return KEY_ENTER; case SDLK_RCTRL: return KEY_CONTROL; case SDLK_LCTRL: return KEY_CONTROL; case SDLK_RSHIFT: return KEY_SHIFT; case SDLK_LSHIFT: return KEY_SHIFT; case SDLK_RALT: return KEY_ALT; case SDLK_LALT: return KEY_ALT; case SDLK_SPACE: return KEY_SPACE; case SDLK_F1: return KEY_F1; case SDLK_F2: return KEY_F2; case SDLK_F3: return KEY_F3; case SDLK_F4: return KEY_F4; case SDLK_F5: return KEY_F5; case SDLK_F6: return KEY_F6; case SDLK_F7: return KEY_F7; case SDLK_F8: return KEY_F8; case SDLK_F9: return KEY_F9; case SDLK_F10: return KEY_F10; case SDLK_F11: return KEY_F11; case SDLK_F12: return KEY_F12; case SDLK_1: return KEY_1; case SDLK_2: return KEY_2; case SDLK_3: return KEY_3; case SDLK_4: return KEY_4; case SDLK_5: return KEY_5; case SDLK_6: return KEY_6; case SDLK_7: return KEY_7; case SDLK_8: return KEY_8; case SDLK_9: return KEY_9; case SDLK_0: return KEY_0; case SDLK_A: return KEY_A; case SDLK_B: return KEY_B; case SDLK_C: return KEY_C; case SDLK_D: return KEY_D; case SDLK_E: return KEY_E; case SDLK_F: return KEY_F; case SDLK_G: return KEY_G; case SDLK_H: return KEY_H; case SDLK_I: return KEY_I; case SDLK_J: return KEY_J; case SDLK_K: return KEY_K; case SDLK_L: return KEY_L; case SDLK_M: return KEY_M; case SDLK_N: return KEY_N; case SDLK_O: return KEY_O; case SDLK_P: return KEY_P; case SDLK_Q: return KEY_Q; case SDLK_R: return KEY_R; case SDLK_S: return KEY_S; case SDLK_T: return KEY_T; case SDLK_U: return KEY_U; case SDLK_V: return KEY_V; case SDLK_W: return KEY_W; case SDLK_X: return KEY_X; case SDLK_Y: return KEY_Y; case SDLK_Z: return KEY_Z; } return KEY_NONE; }; void IVideo_HandleEvents() { SDL_Event event; while (SDL_PollEvent(&event)) { SDL_KeyboardEvent *key = &event.key; SDL_MouseMotionEvent *motion = &event.motion; switch (event.type) { case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: g_nWindowWidth = event.window.data1; g_nWindowHeight = event.window.data2; g_bConfigNotify = 2; break; case SDL_EVENT_KEY_DOWN: if (!key->repeat) IInput::KeyEvent(ISDL_KeyName(key->key),KEY_EVENT_TYPE_DOWN); break; case SDL_EVENT_KEY_UP: key = &event.key; if (!key->repeat) IInput::KeyEvent(ISDL_KeyName(key->key),KEY_EVENT_TYPE_UP); break; case SDL_EVENT_MOUSE_MOTION: IInput::AxisEvent(AXIS_MOUSE_X, motion->yrel*0.022); IInput::AxisEvent(AXIS_MOUSE_Y, -motion->xrel*0.022); break; case SDL_EVENT_GAMEPAD_AXIS_MOTION: { SDL_GamepadAxis axis = (SDL_GamepadAxis)event.gaxis.axis; float value = event.gaxis.value / 32768.0f; if (abs(event.gaxis.value)<1000) value = 0; SDL_JoystickID id = event.gaxis.which; if (axis == SDL_GAMEPAD_AXIS_RIGHTY) { IInput::AxisEvent(AXIS_CONTROLLER_PITCH, value); } if (axis == SDL_GAMEPAD_AXIS_RIGHTX) { IInput::AxisEvent(AXIS_CONTROLLER_YAW, -value); } } break; case SDL_EVENT_GAMEPAD_BUTTON_DOWN: break; case SDL_EVENT_GAMEPAD_BUTTON_UP: break; } }; }; void APPLE_ConfigureLayer(CA::MetalLayer* pMetalLayer); void IVideo::Init() { SDL_SetHint(SDL_HINT_RENDER_VSYNC, "0"); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_GAMEPAD); g_window = SDL_CreateWindow("rtt", 1280, 720, SDL_WINDOW_METAL | SDL_WINDOW_HIGH_PIXEL_DENSITY); int nNumGamepads = 0; SDL_JoystickID *pGamepads = SDL_GetGamepads(&nNumGamepads); for ( uint32_t i = 0; i < nNumGamepads; i++ ) { SDL_OpenGamepad(pGamepads[i]); } g_mlView = SDL_Metal_CreateView(g_window); g_mlLayer = (CA::MetalLayer*)SDL_Metal_GetLayer(g_mlView); g_mlDevice = MTL::CreateSystemDefaultDevice(); g_mlLayer->setDevice(g_mlDevice); g_mlLayer->setPixelFormat(MTL::PixelFormatBGRA8Unorm); g_swapchainFormat = MTL::PixelFormatBGRA8Unorm; g_mlCommandQueue = g_mlDevice->newCommandQueue(); g_mlLayer->setDrawableSize(CGSizeMake(1280, 720)); g_mlLayer->setFramebufferOnly(false); IMetal::Init(); } void IVideo::Frame( float fDelta ) { IVideo_HandleEvents(); NS::AutoreleasePool *pool = NS::AutoreleasePool::alloc()->init(); g_mlLayer->setDrawableSize(CGSizeMake(g_nWindowWidth, g_nWindowHeight)); CA::MetalDrawable *drawable = g_mlLayer->nextDrawable(); if (!drawable) return; g_mlDrawableTexture = drawable->texture(); g_mlCommandBuffer = g_mlCommandQueue->commandBuffer(); IMetal::Frame(); g_mlCommandBuffer->presentDrawable(drawable); g_mlCommandBuffer->commit(); g_mlCommandBuffer->waitUntilCompleted(); for (auto &image: g_destroyImageBuffer) { image->release(); } for (auto &buffer: g_destroyBuffersBuffer) { buffer->release(); } g_destroyImageBuffer = {}; g_destroyBuffersBuffer = {}; pool->release(); g_bConfigNotify = 0; } void IVideo::Deinit() { g_mlCommandQueue->release(); g_mlDevice->release(); }; void IVideo::CreatePipelines( ) { IMetal::CreatePipelines(); }