|
| 1 | +// Copyright (C) 2018-2020 - DevSH Graphics Programming Sp. z O.O. |
| 2 | +// This file is part of the "Nabla Engine". |
| 3 | +// For conditions of distribution and use, see copyright notice in nabla.h |
| 4 | + |
| 5 | +#define _NBL_STATIC_LIB_ |
| 6 | +#include <iostream> |
| 7 | +#include <cstdio> |
| 8 | +#include <nabla.h> |
| 9 | + |
| 10 | +//! I advise to check out this file, its a basic input handler |
| 11 | +#include "../common/QToQuitEventReceiver.h" |
| 12 | + |
| 13 | + |
| 14 | +using namespace nbl; |
| 15 | +using namespace core; |
| 16 | + |
| 17 | + |
| 18 | +#include "nbl/nblpack.h" |
| 19 | +struct VertexStruct |
| 20 | +{ |
| 21 | + /// every member needs to be at location aligned to its type size for GLSL |
| 22 | + float Pos[3]; /// uses float hence need 4 byte alignment |
| 23 | + uint8_t Col[2]; /// same logic needs 1 byte alignment |
| 24 | + uint8_t uselessPadding[2]; /// so if there is a member with 4 byte alignment then whole struct needs 4 byte align, so pad it |
| 25 | +} PACK_STRUCT; |
| 26 | +#include "nbl/nblunpack.h" |
| 27 | + |
| 28 | +const char* vertexSource = R"===( |
| 29 | +#version 430 core |
| 30 | +
|
| 31 | +layout(location = 0) in vec4 vPos; //only a 3d position is passed from irrlicht, but last (the W) coordinate gets filled with default 1.0 |
| 32 | +layout(location = 1) in vec4 vCol; |
| 33 | +
|
| 34 | +layout( push_constant, row_major ) uniform Block { |
| 35 | + mat4 modelViewProj; |
| 36 | +} PushConstants; |
| 37 | +
|
| 38 | +layout(location = 0) out vec4 Color; //per vertex output color, will be interpolated across the triangle |
| 39 | +
|
| 40 | +void main() |
| 41 | +{ |
| 42 | + gl_Position = PushConstants.modelViewProj*vPos; //only thing preventing the shader from being core-compliant |
| 43 | + Color = vCol; |
| 44 | +} |
| 45 | +)==="; |
| 46 | + |
| 47 | +const char* fragmentSource = R"===( |
| 48 | +#version 430 core |
| 49 | +
|
| 50 | +layout(location = 0) in vec4 Color; //per vertex output color, will be interpolated across the triangle |
| 51 | +
|
| 52 | +layout(location = 0) out vec4 pixelColor; |
| 53 | +
|
| 54 | +void main() |
| 55 | +{ |
| 56 | + pixelColor = Color; |
| 57 | +} |
| 58 | +)==="; |
| 59 | + |
| 60 | +int main() |
| 61 | +{ |
| 62 | + // create device with full flexibility over creation parameters |
| 63 | + // you can add more parameters if desired, check nbl::SIrrlichtCreationParameters |
| 64 | + nbl::SIrrlichtCreationParameters params; |
| 65 | + params.Bits = 24; //may have to set to 32bit for some platforms |
| 66 | + params.ZBufferBits = 24; //we'd like 32bit here |
| 67 | + params.DriverType = video::EDT_OPENGL; //! Only Well functioning driver, software renderer left for sake of 2D image drawing |
| 68 | + params.WindowSize = dimension2d<uint32_t>(1280, 720); |
| 69 | + params.Fullscreen = false; |
| 70 | + params.Vsync = true; //! If supported by target platform |
| 71 | + params.Doublebuffer = true; |
| 72 | + params.Stencilbuffer = false; //! This will not even be a choice soon |
| 73 | + auto device = createDeviceEx(params); |
| 74 | + |
| 75 | + if (!device) |
| 76 | + return 1; // could not create selected driver. |
| 77 | + |
| 78 | + |
| 79 | + //! disable mouse cursor, since camera will force it to the middle |
| 80 | + //! and we don't want a jittery cursor in the middle distracting us |
| 81 | + device->getCursorControl()->setVisible(false); |
| 82 | + |
| 83 | + //! Since our cursor will be enslaved, there will be no way to close the window |
| 84 | + //! So we listen for the "Q" key being pressed and exit the application |
| 85 | + QToQuitEventReceiver receiver; |
| 86 | + device->setEventReceiver(&receiver); |
| 87 | + |
| 88 | + |
| 89 | + auto* driver = device->getVideoDriver(); |
| 90 | + auto* smgr = device->getSceneManager(); |
| 91 | + |
| 92 | + // |
| 93 | + core::smart_refctd_ptr<video::IGPUMeshBuffer> mb; |
| 94 | + { |
| 95 | + VertexStruct vertices[8]; |
| 96 | + vertices[0] = VertexStruct{{-1.f,-1.f,-1.f},{ 0, 0}}; |
| 97 | + vertices[1] = VertexStruct{{ 1.f,-1.f,-1.f},{127, 0}}; |
| 98 | + vertices[2] = VertexStruct{{-1.f, 1.f,-1.f},{255, 0}}; |
| 99 | + vertices[3] = VertexStruct{{ 1.f, 1.f,-1.f},{ 0,127}}; |
| 100 | + vertices[4] = VertexStruct{{-1.f,-1.f, 1.f},{127,127}}; |
| 101 | + vertices[5] = VertexStruct{{ 1.f,-1.f, 1.f},{255,127}}; |
| 102 | + vertices[6] = VertexStruct{{-1.f, 1.f, 1.f},{ 0,255}}; |
| 103 | + vertices[7] = VertexStruct{{ 1.f, 1.f, 1.f},{127,255}}; |
| 104 | + |
| 105 | + uint16_t indices_indexed16[] = |
| 106 | + { |
| 107 | + 0,1,2,1,2,3, |
| 108 | + 4,5,6,5,6,7, |
| 109 | + 0,1,4,1,4,5, |
| 110 | + 2,3,6,3,6,7, |
| 111 | + 0,2,4,2,4,6, |
| 112 | + 1,3,5,3,5,7 |
| 113 | + }; |
| 114 | + |
| 115 | + asset::SPushConstantRange range[1] = {asset::ISpecializedShader::ESS_VERTEX,0u,sizeof(core::matrix4SIMD)}; |
| 116 | + |
| 117 | + auto createGPUSpecializedShaderFromSource = [=](const char* source, asset::ISpecializedShader::E_SHADER_STAGE stage) |
| 118 | + { |
| 119 | + auto spirv = device->getAssetManager()->getGLSLCompiler()->createSPIRVFromGLSL(source, stage, "main", "runtimeID"); |
| 120 | + auto unspec = driver->createGPUShader(std::move(spirv)); |
| 121 | + return driver->createGPUSpecializedShader(unspec.get(), { nullptr,nullptr,"main",stage }); |
| 122 | + }; |
| 123 | + // origFilepath is only relevant when you have filesystem #includes in your shader |
| 124 | + auto createGPUSpecializedShaderFromSourceWithIncludes = [&](const char* source, asset::ISpecializedShader::E_SHADER_STAGE stage, const char* origFilepath) |
| 125 | + { |
| 126 | + auto resolved_includes = device->getAssetManager()->getGLSLCompiler()->resolveIncludeDirectives(source, stage, origFilepath); |
| 127 | + return createGPUSpecializedShaderFromSource(reinterpret_cast<const char*>(resolved_includes->getSPVorGLSL()->getPointer()), stage); |
| 128 | + }; |
| 129 | + core::smart_refctd_ptr<video::IGPUSpecializedShader> shaders[2] = |
| 130 | + { |
| 131 | + createGPUSpecializedShaderFromSourceWithIncludes(vertexSource,asset::ISpecializedShader::ESS_VERTEX, "shader.vert"), |
| 132 | + createGPUSpecializedShaderFromSource(fragmentSource,asset::ISpecializedShader::ESS_FRAGMENT) |
| 133 | + }; |
| 134 | + auto shadersPtr = reinterpret_cast<video::IGPUSpecializedShader**>(shaders); |
| 135 | + |
| 136 | + asset::SVertexInputParams inputParams; |
| 137 | + inputParams.enabledAttribFlags = 0b11u; |
| 138 | + inputParams.enabledBindingFlags = 0b1u; |
| 139 | + inputParams.attributes[0].binding = 0u; |
| 140 | + inputParams.attributes[0].format = asset::EF_R32G32B32_SFLOAT; |
| 141 | + inputParams.attributes[0].relativeOffset = offsetof(VertexStruct,Pos[0]); |
| 142 | + inputParams.attributes[1].binding = 0u; |
| 143 | + inputParams.attributes[1].format = asset::EF_R8G8_UNORM; |
| 144 | + inputParams.attributes[1].relativeOffset = offsetof(VertexStruct,Col[0]); |
| 145 | + inputParams.bindings[0].stride = sizeof(VertexStruct); |
| 146 | + inputParams.bindings[0].inputRate = asset::EVIR_PER_VERTEX; |
| 147 | + |
| 148 | + asset::SBlendParams blendParams; // defaults are sane |
| 149 | + |
| 150 | + asset::SPrimitiveAssemblyParams assemblyParams = {asset::EPT_TRIANGLE_LIST,false,1u}; |
| 151 | + |
| 152 | + asset::SStencilOpParams defaultStencil; |
| 153 | + asset::SRasterizationParams rasterParams; |
| 154 | + rasterParams.faceCullingMode = asset::EFCM_NONE; |
| 155 | + auto pipeline = driver->createGPURenderpassIndependentPipeline( nullptr,driver->createGPUPipelineLayout(range,range+1u,nullptr,nullptr,nullptr,nullptr), |
| 156 | + shadersPtr,shadersPtr+sizeof(shaders)/sizeof(core::smart_refctd_ptr<video::IGPUSpecializedShader>), |
| 157 | + inputParams,blendParams,assemblyParams,rasterParams); |
| 158 | + |
| 159 | + asset::SBufferBinding<video::IGPUBuffer> bindings[video::IGPUMeshBuffer::MAX_ATTR_BUF_BINDING_COUNT]; |
| 160 | + bindings[0u] = {0u,driver->createFilledDeviceLocalGPUBufferOnDedMem(sizeof(vertices),vertices)}; |
| 161 | + mb = core::make_smart_refctd_ptr<video::IGPUMeshBuffer>(std::move(pipeline),nullptr,bindings,asset::SBufferBinding<video::IGPUBuffer>{0u,driver->createFilledDeviceLocalGPUBufferOnDedMem(sizeof(indices_indexed16),indices_indexed16)}); |
| 162 | + { |
| 163 | + mb->setIndexType(asset::EIT_16BIT); |
| 164 | + mb->setIndexCount(2*3*6); |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + |
| 169 | + //! we want to move around the scene and view it from different angles |
| 170 | + scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0,100.0f,0.001f); |
| 171 | + |
| 172 | + camera->setPosition(core::vector3df(-4,0,0)); |
| 173 | + camera->setTarget(core::vector3df(0,0,0)); |
| 174 | + camera->setNearValue(0.01f); |
| 175 | + camera->setFarValue(10.0f); |
| 176 | + |
| 177 | + smgr->setActiveCamera(camera); |
| 178 | + |
| 179 | + uint64_t lastFPSTime = 0; |
| 180 | + while(device->run() && receiver.keepOpen()) |
| 181 | + { |
| 182 | + driver->beginScene(true, true, video::SColor(255,255,255,255) ); |
| 183 | + //! This animates (moves) the camera and sets the transforms |
| 184 | + camera->OnAnimate(std::chrono::duration_cast<std::chrono::milliseconds>(device->getTimer()->getTime()).count()); |
| 185 | + camera->render(); |
| 186 | + core::matrix4SIMD mvp = camera->getConcatenatedMatrix(); |
| 187 | + |
| 188 | + //! Stress test for memleaks aside from demo how to create meshes that live on the GPU RAM |
| 189 | + { |
| 190 | + driver->bindGraphicsPipeline(mb->getPipeline()); |
| 191 | + driver->pushConstants(mb->getPipeline()->getLayout(), asset::ISpecializedShader::ESS_VERTEX, 0u, sizeof(core::matrix4SIMD), mvp.pointer()); |
| 192 | + driver->drawMeshBuffer(mb.get()); |
| 193 | + } |
| 194 | + driver->endScene(); |
| 195 | + |
| 196 | + // display frames per second in window title |
| 197 | + uint64_t time = device->getTimer()->getRealTime(); |
| 198 | + if (time-lastFPSTime > 1000) |
| 199 | + { |
| 200 | + std::wostringstream str; |
| 201 | + str << L"GPU Mesh Demo - Irrlicht Engine [" << driver->getName() << "] FPS:" << driver->getFPS() << " PrimitvesDrawn:" << driver->getPrimitiveCountDrawn(); |
| 202 | + |
| 203 | + device->setWindowCaption(str.str().c_str()); |
| 204 | + lastFPSTime = time; |
| 205 | + } |
| 206 | + } |
| 207 | + |
| 208 | + //create a screenshot |
| 209 | + { |
| 210 | + core::rect<uint32_t> sourceRect(0, 0, params.WindowSize.Width, params.WindowSize.Height); |
| 211 | + //ext::ScreenShot::dirtyCPUStallingScreenshot(device, "screenshot.png", sourceRect, asset::EF_R8G8B8_SRGB); |
| 212 | + } |
| 213 | + |
| 214 | + return 0; |
| 215 | +} |
0 commit comments