#include <boo/boo.hpp> #include "logvisor/logvisor.hpp" #include <athena/MemoryWriter.hpp> #include "hecl/Runtime.hpp" #include "hecl/HMDLMeta.hpp" #include <math.h> #include <thread> #include <mutex> #include <condition_variable> namespace hecl { namespace Database { std::vector<const struct DataSpecEntry*> DATA_SPEC_REGISTRY; } } struct HECLWindowCallback : boo::IWindowCallback { bool m_sizeDirty = false; boo::SWindowRect m_latestSize; void resized(const boo::SWindowRect& rect) { m_sizeDirty = true; m_latestSize = rect; } bool m_destroyed = false; void destroyed() { m_destroyed = true; } }; struct HECLApplicationCallback : boo::IApplicationCallback { HECLWindowCallback m_windowCb; boo::IWindow* m_mainWindow = nullptr; bool m_running = true; int appMain(boo::IApplication* app) { /* Setup boo window */ m_mainWindow = app->newWindow(_S("HECL Test"), 1); m_mainWindow->setCallback(&m_windowCb); boo::ITextureR* renderTex = nullptr; boo::IGraphicsBufferD* vubo = nullptr; boo::IShaderDataBinding* binding = nullptr; struct VertexUBO { float modelview[4][4] = {}; float modelviewInv[4][4] = {}; float projection[4][4] = {}; VertexUBO() { modelview[0][0] = 1.0; modelview[1][1] = 1.0; modelview[2][2] = 1.0; modelview[3][3] = 1.0; modelviewInv[0][0] = 1.0; modelviewInv[1][1] = 1.0; modelviewInv[2][2] = 1.0; modelviewInv[3][3] = 1.0; projection[0][0] = 1.0; projection[1][1] = 1.0; projection[2][2] = 1.0; projection[3][3] = 1.0; } } vuboData; std::mutex initmt; std::condition_variable initcv; std::mutex loadmt; std::condition_variable loadcv; std::unique_lock<std::mutex> outerLk(initmt); std::thread loaderThr([&]() { std::unique_lock<std::mutex> innerLk(initmt); boo::IGraphicsDataFactory* gfxF = m_mainWindow->getLoadContextDataFactory(); /* HECL managers */ hecl::Runtime::FileStoreManager fileMgr(app->getUniqueName()); hecl::Runtime::ShaderCacheManager shaderMgr(fileMgr, gfxF); /* Compile HECL shader */ static std::string testShader = "HECLOpaque(Texture(0, UV(0)))"; //static std::string testShader = "HECLOpaque(vec4(1.0,1.0,1.0,1.0))"; hecl::Runtime::ShaderTag testShaderTag(testShader, 0, 1, 0, 0, 0, boo::Primitive::TriStrips, false, false, false); std::shared_ptr<hecl::Runtime::ShaderPipelines> testShaderObj = shaderMgr.buildShader(testShaderTag, testShader, "testShader", *gfxF); boo::GraphicsDataToken data = gfxF->commitTransaction([&](boo::IGraphicsDataFactory::Context& ctx) -> bool { boo::SWindowRect mainWindowRect = m_mainWindow->getWindowFrame(); renderTex = ctx.newRenderTexture(mainWindowRect.size[0], mainWindowRect.size[1], false, false); /* Generate meta structure (usually statically serialized) */ hecl::HMDLMeta testMeta; testMeta.topology = hecl::HMDLTopology::TriStrips; testMeta.vertStride = 32; testMeta.vertCount = 4; testMeta.indexCount = 4; testMeta.colorCount = 0; testMeta.uvCount = 1; testMeta.weightCount = 0; testMeta.bankCount = 0; /* Binary form of meta structure */ atUint8 testMetaBuf[HECL_HMDL_META_SZ]; athena::io::MemoryWriter testMetaWriter(testMetaBuf, HECL_HMDL_META_SZ); testMeta.write(testMetaWriter); /* Make Tri-strip VBO */ struct Vert { float pos[3]; float norm[3]; float uv[2]; }; static const Vert quad[4] = { {{0.5,0.5},{},{1.0,1.0}}, {{-0.5,0.5},{},{0.0,1.0}}, {{0.5,-0.5},{},{1.0,0.0}}, {{-0.5,-0.5},{},{0.0,0.0}} }; /* Now simple IBO */ static const uint32_t ibo[4] = {0,1,2,3}; /* Construct quad mesh against boo factory */ hecl::Runtime::HMDLData testData(ctx, testMetaBuf, quad, ibo); /* Make ramp texture */ using Pixel = uint8_t[4]; static Pixel tex[256][256]; for (int i=0 ; i<256 ; ++i) for (int j=0 ; j<256 ; ++j) { tex[i][j][0] = i; tex[i][j][1] = j; tex[i][j][2] = 0; tex[i][j][3] = 0xff; } boo::ITexture* texture = ctx.newStaticTexture(256, 256, 1, boo::TextureFormat::RGBA8, tex, 256*256*4); /* Make vertex uniform buffer */ vubo = ctx.newDynamicBuffer(boo::BufferUse::Uniform, sizeof(VertexUBO), 1); /* Assemble data binding */ binding = testData.newShaderDataBindng(ctx, testShaderObj->m_pipelines[0], 1, (boo::IGraphicsBuffer**)&vubo, nullptr, 1, &texture); return true; }); /* Return control to main thread */ innerLk.unlock(); initcv.notify_one(); /* Wait for exit */ std::unique_lock<std::mutex> lk(loadmt); while (m_running) { loadcv.wait(lk); } }); initcv.wait(outerLk); m_mainWindow->showWindow(); m_windowCb.m_latestSize = m_mainWindow->getWindowFrame(); boo::IGraphicsCommandQueue* gfxQ = m_mainWindow->getCommandQueue(); m_mainWindow->getMainContextDataFactory(); size_t frameIdx = 0; while (m_running) { m_mainWindow->waitForRetrace(); if (m_windowCb.m_destroyed) { m_running = false; break; } if (m_windowCb.m_sizeDirty) { gfxQ->resizeRenderTexture(renderTex, m_windowCb.m_latestSize.size[0], m_windowCb.m_latestSize.size[1]); m_windowCb.m_sizeDirty = false; } gfxQ->setRenderTarget(renderTex); boo::SWindowRect r = m_windowCb.m_latestSize; r.location[0] = 0; r.location[1] = 0; gfxQ->setViewport(r); gfxQ->setScissor(r); float rgba[] = {sinf(frameIdx / 60.0), cosf(frameIdx / 60.0), 0.0, 1.0}; gfxQ->setClearColor(rgba); gfxQ->clearTarget(); vuboData.modelview[3][0] = sinf(frameIdx / 60.0) * 0.5; vuboData.modelview[3][1] = cosf(frameIdx / 60.0) * 0.5; vubo->load(&vuboData, sizeof(vuboData)); gfxQ->setShaderDataBinding(binding); gfxQ->drawIndexed(0, 4); gfxQ->resolveDisplay(renderTex); gfxQ->execute(); ++frameIdx; } std::unique_lock<std::mutex> finallk(loadmt); finallk.unlock(); gfxQ->stopRenderer(); loadcv.notify_one(); loaderThr.join(); return 0; } void appQuitting(boo::IApplication* app) { m_running = false; } }; void AthenaExcHandler(athena::error::Level level, const char* file, const char* function, int line, const char* fmt, ...) { static logvisor::Module Log("heclTest::AthenaExcHandler"); va_list ap; va_start(ap, fmt); Log.reportSource(logvisor::Level(level), file, line, fmt, ap); va_end(ap); } #if _WIN32 int wmain(int argc, const boo::SystemChar** argv) #else int main(int argc, const boo::SystemChar** argv) #endif { atSetExceptionHandler(AthenaExcHandler); logvisor::RegisterStandardExceptions(); logvisor::RegisterConsoleLogger(); HECLApplicationCallback appCb; int ret = boo::ApplicationRun(boo::IApplication::EPlatformType::Auto, appCb, _S("heclTest"), _S("HECL Test"), argc, argv); printf("IM DYING!!\n"); return ret; } #if _WIN32 int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR lpCmdLine, int) { int argc = 0; const boo::SystemChar** argv = (const wchar_t**)(CommandLineToArgvW(lpCmdLine, &argc)); static boo::SystemChar selfPath[1024]; GetModuleFileNameW(nullptr, selfPath, 1024); static const boo::SystemChar* booArgv[32] = {}; booArgv[0] = selfPath; for (int i=0 ; i<argc ; ++i) booArgv[i+1] = argv[i]; logvisor::CreateWin32Console(); return wmain(argc+1, booArgv); } #endif