/** * Test: BgfxRenderer Visual Triangle Test * * Renders a colored triangle using bgfx with SDL2 windowing. * This validates the full rendering pipeline including shaders. */ #include #include #include #include #include #include #include // ============================================================================ // Embedded Shaders (from bgfx examples - drawstress) // ============================================================================ // Include pre-compiled shader bytecode for all platforms #include "../../modules/BgfxRenderer/Shaders/vs_color.bin.h" #include "../../modules/BgfxRenderer/Shaders/fs_color.bin.h" // ============================================================================ // Shader loading helper // ============================================================================ static const bgfx::Memory* loadShaderMem(const uint8_t* data, uint32_t size) { return bgfx::copy(data, size); } bgfx::ShaderHandle loadShader(bgfx::RendererType::Enum type, const char* name) { const uint8_t* data = nullptr; uint32_t size = 0; // Select shader based on renderer type bool isVertex = (name[0] == 'v'); switch (type) { case bgfx::RendererType::OpenGL: if (isVertex) { data = vs_drawstress_glsl; size = sizeof(vs_drawstress_glsl); } else { data = fs_drawstress_glsl; size = sizeof(fs_drawstress_glsl); } break; case bgfx::RendererType::OpenGLES: if (isVertex) { data = vs_drawstress_essl; size = sizeof(vs_drawstress_essl); } else { data = fs_drawstress_essl; size = sizeof(fs_drawstress_essl); } break; case bgfx::RendererType::Vulkan: if (isVertex) { data = vs_drawstress_spv; size = sizeof(vs_drawstress_spv); } else { data = fs_drawstress_spv; size = sizeof(fs_drawstress_spv); } break; case bgfx::RendererType::Direct3D11: case bgfx::RendererType::Direct3D12: if (isVertex) { data = vs_drawstress_dx11; size = sizeof(vs_drawstress_dx11); } else { data = fs_drawstress_dx11; size = sizeof(fs_drawstress_dx11); } break; case bgfx::RendererType::Metal: if (isVertex) { data = vs_drawstress_mtl; size = sizeof(vs_drawstress_mtl); } else { data = fs_drawstress_mtl; size = sizeof(fs_drawstress_mtl); } break; default: std::cerr << "Unsupported renderer type for shaders\n"; return BGFX_INVALID_HANDLE; } return bgfx::createShader(loadShaderMem(data, size)); } // ============================================================================ // Vertex Data // ============================================================================ struct PosColorVertex { float x, y, z; uint32_t abgr; static bgfx::VertexLayout layout; static void init() { layout .begin() .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float) .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true) .end(); } }; bgfx::VertexLayout PosColorVertex::layout; // Triangle vertices (colored) - centered at origin static PosColorVertex s_triangleVertices[] = { { -0.5f, -0.5f, 0.0f, 0xff0000ff }, // Red (ABGR format) { 0.5f, -0.5f, 0.0f, 0xff00ff00 }, // Green { 0.0f, 0.5f, 0.0f, 0xffff0000 }, // Blue }; static const uint16_t s_triangleIndices[] = { 0, 1, 2, }; // ============================================================================ // Main // ============================================================================ int main(int argc, char* argv[]) { std::cout << "========================================\n"; std::cout << "BgfxRenderer Visual Triangle Test\n"; std::cout << "========================================\n\n"; // Initialize SDL if (SDL_Init(SDL_INIT_VIDEO) < 0) { std::cerr << "SDL_Init failed: " << SDL_GetError() << "\n"; return 1; } // Create window const int width = 800; const int height = 600; SDL_Window* window = SDL_CreateWindow( "BgfxRenderer Triangle Test - Press ESC to exit", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE ); if (!window) { std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << "\n"; SDL_Quit(); return 1; } // Get native window handle SDL_SysWMinfo wmi; SDL_VERSION(&wmi.version); if (!SDL_GetWindowWMInfo(window, &wmi)) { std::cerr << "SDL_GetWindowWMInfo failed: " << SDL_GetError() << "\n"; SDL_DestroyWindow(window); SDL_Quit(); return 1; } // Setup bgfx platform data bgfx::PlatformData pd; pd.ndt = wmi.info.x11.display; pd.nwh = (void*)(uintptr_t)wmi.info.x11.window; pd.context = nullptr; pd.backBuffer = nullptr; pd.backBufferDS = nullptr; bgfx::setPlatformData(pd); // Initialize bgfx bgfx::Init init; init.type = bgfx::RendererType::Count; // Auto-select init.resolution.width = width; init.resolution.height = height; init.resolution.reset = BGFX_RESET_VSYNC; init.platformData = pd; std::cout << "Initializing bgfx...\n"; if (!bgfx::init(init)) { std::cerr << "bgfx::init failed\n"; SDL_DestroyWindow(window); SDL_Quit(); return 1; } // Print renderer info const bgfx::Caps* caps = bgfx::getCaps(); std::cout << "Renderer: " << bgfx::getRendererName(caps->rendererType) << "\n"; std::cout << "Resolution: " << width << "x" << height << "\n"; // Setup view bgfx::setViewClear(0, BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH, 0x303030ff, 1.0f, 0); bgfx::setViewRect(0, 0, 0, width, height); // Initialize vertex layout PosColorVertex::init(); // Create vertex buffer bgfx::VertexBufferHandle vbh = bgfx::createVertexBuffer( bgfx::makeRef(s_triangleVertices, sizeof(s_triangleVertices)), PosColorVertex::layout ); // Create index buffer bgfx::IndexBufferHandle ibh = bgfx::createIndexBuffer( bgfx::makeRef(s_triangleIndices, sizeof(s_triangleIndices)) ); // Load shaders std::cout << "Loading shaders for " << bgfx::getRendererName(caps->rendererType) << "...\n"; bgfx::ShaderHandle vsh = loadShader(caps->rendererType, "vs_color"); bgfx::ShaderHandle fsh = loadShader(caps->rendererType, "fs_color"); if (!bgfx::isValid(vsh) || !bgfx::isValid(fsh)) { std::cerr << "Failed to load shaders\n"; bgfx::shutdown(); SDL_DestroyWindow(window); SDL_Quit(); return 1; } // Create program bgfx::ProgramHandle program = bgfx::createProgram(vsh, fsh, true); if (!bgfx::isValid(program)) { std::cerr << "Failed to create shader program\n"; bgfx::shutdown(); SDL_DestroyWindow(window); SDL_Quit(); return 1; } std::cout << "\n*** Rendering colored triangle ***\n"; std::cout << "Press ESC to exit or wait 5 seconds\n\n"; // Main loop bool running = true; uint32_t frameCount = 0; Uint32 startTime = SDL_GetTicks(); const Uint32 testDuration = 5000; // 5 seconds while (running) { // Process events SDL_Event event; while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { running = false; } if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) { running = false; } } // Check timeout if (SDL_GetTicks() - startTime > testDuration) { running = false; } // Set view transform (identity for 2D) float view[16]; float proj[16]; bx::mtxIdentity(view); bx::mtxOrtho(proj, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 0.0f, caps->homogeneousDepth); bgfx::setViewTransform(0, view, proj); // Touch view 0 to ensure clear bgfx::touch(0); // Set model transform (identity) float model[16]; bx::mtxIdentity(model); bgfx::setTransform(model); // Set vertex and index buffers bgfx::setVertexBuffer(0, vbh); bgfx::setIndexBuffer(ibh); // Set render state uint64_t state = BGFX_STATE_WRITE_RGB | BGFX_STATE_WRITE_A | BGFX_STATE_WRITE_Z | BGFX_STATE_DEPTH_TEST_LESS | BGFX_STATE_MSAA; bgfx::setState(state); // Submit draw call bgfx::submit(0, program); // Submit frame bgfx::frame(); frameCount++; } float elapsed = (SDL_GetTicks() - startTime) / 1000.0f; float fps = frameCount / elapsed; std::cout << "Test completed!\n"; std::cout << " Frames: " << frameCount << "\n"; std::cout << " Time: " << elapsed << "s\n"; std::cout << " FPS: " << fps << "\n"; // Cleanup bgfx::destroy(program); bgfx::destroy(vbh); bgfx::destroy(ibh); bgfx::shutdown(); SDL_DestroyWindow(window); SDL_Quit(); std::cout << "\n========================================\n"; std::cout << "PASS: Colored triangle rendered!\n"; std::cout << "========================================\n"; return 0; }