//============================================================================== Error XmlElement::getMat4(Mat4& out) const { DArrayAuto<F64> arr(m_alloc); Error err = getFloats(arr); if(!err && arr.getSize() != 16) { ANKI_LOGE("Expecting 16 elements for Mat4"); err = ErrorCode::USER_DATA; } if(!err) { for(U i = 0; i < 16 && !err; i++) { out[i] = arr[i]; } } if(err) { ANKI_LOGE("Failed to return Mat4. Element: %s", m_el->Value()); } return err; }
//============================================================================== static ANKI_USE_RESULT Error loadTga(ResourceFilePtr fs, U32& width, U32& height, U32& bpp, DynamicArray<U8>& data, GenericMemoryPoolAllocator<U8>& alloc) { char myTgaHeader[12]; ANKI_CHECK(fs->read(&myTgaHeader[0], sizeof(myTgaHeader))); if(memcmp(tgaHeaderUncompressed, &myTgaHeader[0], sizeof(myTgaHeader)) == 0) { ANKI_CHECK(loadUncompressedTga(fs, width, height, bpp, data, alloc)); } else if(std::memcmp( tgaHeaderCompressed, &myTgaHeader[0], sizeof(myTgaHeader)) == 0) { ANKI_CHECK(loadCompressedTga(fs, width, height, bpp, data, alloc)); } else { ANKI_LOGE("Invalid image header"); return ErrorCode::USER_DATA; } if(bpp != 32 && bpp != 24) { ANKI_LOGE("Invalid bpp"); return ErrorCode::USER_DATA; } return ErrorCode::NONE; }
//============================================================================== Error XmlElement::getVec4(Vec4& out) const { DynamicArrayAuto<F64> arr(m_alloc); Error err = getFloats(arr); if(!err && arr.getSize() != 4) { ANKI_LOGE("Expecting 4 elements for Vec3"); err = ErrorCode::USER_DATA; } if(!err) { for(U i = 0; i < 4; i++) { out[i] = arr[i]; } } if(err) { ANKI_LOGE("Failed to return Vec4. Element: %s", m_el->Value()); } return err; }
//============================================================================== Error ShaderLoader::parseFileIncludes(ResourceFilename filename, U32 depth) { // first check the depth if(depth > MAX_INCLUDE_DEPTH) { ANKI_LOGE("The include depth is too high. " "Probably circular includance"); return ErrorCode::USER_DATA; } // load file in lines StringAuto txt(m_alloc); StringListAuto lines(m_alloc); ResourceFilePtr file; ANKI_CHECK(m_manager->getFilesystem().openFile(filename, file)); ANKI_CHECK(file->readAllText(TempResourceAllocator<char>(m_alloc), txt)); lines.splitString(txt.toCString(), '\n'); if(lines.getSize() < 1) { ANKI_LOGE("File is empty: %s", &filename[0]); return ErrorCode::USER_DATA; } for(const String& line : lines) { static const CString token = "#include \""; if(line.find(token) == 0) { // - Expect something between the quotes // - Expect the last char to be a quote if(line.getLength() >= token.getLength() + 2 && line[line.getLength() - 1] == '\"') { StringAuto filen(m_alloc); filen.create(line.begin() + token.getLength(), line.end() - 1); ANKI_CHECK(parseFileIncludes(filen.toCString(), depth + 1)); } else { ANKI_LOGE("Malformed #include: %s", &line[0]); return ErrorCode::USER_DATA; } } else { m_sourceLines.pushBackSprintf(m_alloc, "%s", &line[0]); } } return ErrorCode::NONE; }
//============================================================================== Error XmlDocument::loadFile(const CString& filename, GenericMemoryPoolAllocator<U8> alloc) { Error err = ErrorCode::NONE; File file; err = file.open(filename, File::OpenFlag::READ); if(err) { return err; } m_alloc = alloc; String text; err = file.readAllText(m_alloc, text); if(err) { return err; } if(m_doc.Parse(&text[0])) { ANKI_LOGE("Cannot parse file. Reason: %s", ((m_doc.GetErrorStr1() == nullptr) ? "unknown" : m_doc.GetErrorStr1())); } text.destroy(m_alloc); return err; }
//============================================================================== /// Given a string that defines blending return the GLenum static GLenum blendToEnum(const CString& str) { // Dont make idiotic mistakes #define TXT_AND_ENUM(x) \ if(str == #x) \ { \ return x; \ } TXT_AND_ENUM(GL_ZERO) TXT_AND_ENUM(GL_ONE) TXT_AND_ENUM(GL_DST_COLOR) TXT_AND_ENUM(GL_ONE_MINUS_DST_COLOR) TXT_AND_ENUM(GL_SRC_ALPHA) TXT_AND_ENUM(GL_ONE_MINUS_SRC_ALPHA) TXT_AND_ENUM(GL_DST_ALPHA) TXT_AND_ENUM(GL_ONE_MINUS_DST_ALPHA) TXT_AND_ENUM(GL_SRC_ALPHA_SATURATE) TXT_AND_ENUM(GL_SRC_COLOR) TXT_AND_ENUM(GL_ONE_MINUS_SRC_COLOR); ANKI_LOGE("Incorrect blend enum"); return 0; #undef TXT_AND_ENUM }
Error operator()(AsyncLoaderTaskContext& ctx) { if(m_count) { auto x = m_count->fetchAdd(1); if(m_id >= 0) { if(m_id != static_cast<I32>(x)) { ANKI_LOGE("Wrong excecution order"); return ErrorCode::FUNCTION_FAILED; } } } if(m_sleepTime != 0.0) { HighRezTimer::sleep(m_sleepTime); } if(m_barrier) { m_barrier->wait(); } ctx.m_pause = m_pause; ctx.m_resubmitTask = m_resubmit; m_resubmit = false; return ErrorCode::NONE; }
Error GrManagerImpl::initDevice(const GrManagerInitInfo& init) { uint32_t count = 0; vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &count, nullptr); ANKI_LOGI("VK: Number of queue families: %u\n", count); DynamicArrayAuto<VkQueueFamilyProperties> queueInfos(getAllocator()); queueInfos.create(count); vkGetPhysicalDeviceQueueFamilyProperties(m_physicalDevice, &count, &queueInfos[0]); uint32_t desiredFamilyIdx = MAX_U32; const VkQueueFlags DESITED_QUEUE_FLAGS = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; for(U i = 0; i < count; ++i) { if((queueInfos[i].queueFlags & DESITED_QUEUE_FLAGS) == DESITED_QUEUE_FLAGS) { VkBool32 supportsPresent = false; ANKI_VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(m_physicalDevice, i, m_surface, &supportsPresent)); if(supportsPresent) { desiredFamilyIdx = i; break; } } } if(desiredFamilyIdx == MAX_U32) { ANKI_LOGE("Couldn't find a queue family with graphics+compute+transfer+present." "The assumption was wrong. The code needs to be reworked"); return ErrorCode::FUNCTION_FAILED; } m_queueIdx = desiredFamilyIdx; F32 priority = 1.0; VkDeviceQueueCreateInfo q = {}; q.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; q.queueFamilyIndex = desiredFamilyIdx; q.queueCount = 1; q.pQueuePriorities = &priority; static Array<const char*, 1> DEV_EXTENSIONS = {{VK_KHR_SWAPCHAIN_EXTENSION_NAME}}; VkDeviceCreateInfo ci = {}; ci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; ci.queueCreateInfoCount = 1; ci.pQueueCreateInfos = &q; ci.enabledExtensionCount = DEV_EXTENSIONS.getSize(); ci.ppEnabledExtensionNames = &DEV_EXTENSIONS[0]; ci.pEnabledFeatures = &m_devFeatures; ANKI_VK_CHECK(vkCreateDevice(m_physicalDevice, &ci, nullptr, &m_device)); return ErrorCode::NONE; }
//============================================================================== ANKI_USE_RESULT Error XmlElement::check() const { Error err = ErrorCode::NONE; if(m_el == nullptr) { ANKI_LOGE("Empty element"); err = ErrorCode::USER_DATA; } return err; }
Error Pps::init(const ConfigSet& config) { Error err = initInternal(config); if(err) { ANKI_LOGE("Failed to init PPS"); } return err; }
Error Tiler::init() { Error err = initInternal(); if(err) { ANKI_LOGE("Failed to init tiler"); } return err; }
//============================================================================== Error createDirectory(const CString& dir) { Error err = ErrorCode::NONE; if(CreateDirectory(dir.get(), NULL) == 0) { ANKI_LOGE("Failed to create directory %s", dir.get()); err = ErrorCode::FUNCTION_FAILED; } return err; }
Error GrManagerImpl::init(const GrManagerInitInfo& init) { Error err = initInternal(init); if(err) { ANKI_LOGE("Vulkan initialization failed"); return ErrorCode::FUNCTION_FAILED; } return ErrorCode::NONE; }
Error CollisionResource::load(const ResourceFilename& filename) { XmlElement el; XmlDocument doc; ANKI_CHECK(openFileParseXml(filename, doc)); XmlElement collEl; ANKI_CHECK(doc.getChildElement("collisionShape", collEl)); ANKI_CHECK(collEl.getChildElement("type", el)); CString type; ANKI_CHECK(el.getText(type)); XmlElement valEl; ANKI_CHECK(collEl.getChildElement("value", valEl)); PhysicsWorld& physics = getManager().getPhysicsWorld(); PhysicsCollisionShapeInitInfo csInit; if(type == "sphere") { F64 tmp; ANKI_CHECK(valEl.getF64(tmp)); m_physicsShape = physics.newInstance<PhysicsSphere>(csInit, tmp); } else if(type == "box") { Vec3 extend; ANKI_CHECK(valEl.getVec3(extend)); m_physicsShape = physics.newInstance<PhysicsBox>(csInit, extend); } else if(type == "staticMesh") { CString meshfname; ANKI_CHECK(valEl.getText(meshfname)); MeshLoader loader(&getManager()); ANKI_CHECK(loader.load(meshfname)); m_physicsShape = physics.newInstance<PhysicsTriangleSoup>(csInit, reinterpret_cast<const Vec3*>(loader.getVertexData()), loader.getVertexSize(), reinterpret_cast<const U16*>(loader.getIndexData()), loader.getHeader().m_totalIndicesCount); } else { ANKI_LOGE("Incorrect collision type"); return ErrorCode::USER_DATA; } return ErrorCode::NONE; }
//============================================================================== ANKI_USE_RESULT Error XmlDocument::getChildElement( const CString& name, XmlElement& out) { Error err = ErrorCode::NONE; out = XmlElement(m_doc.FirstChildElement(&name[0]), m_alloc); if(!out) { ANKI_LOGE("Cannot find tag %s", &name[0]); err = ErrorCode::USER_DATA; } return err; }
//============================================================================== static ANKI_USE_RESULT Error loadTga(const CString& filename, U32& width, U32& height, U32& bpp, DArray<U8>& data, GenericMemoryPoolAllocator<U8>& alloc) { File fs; char myTgaHeader[12]; ANKI_CHECK(fs.open(filename, File::OpenFlag::READ | File::OpenFlag::BINARY)); ANKI_CHECK(fs.read(&myTgaHeader[0], sizeof(myTgaHeader))); if(std::memcmp( tgaHeaderUncompressed, &myTgaHeader[0], sizeof(myTgaHeader)) == 0) { ANKI_CHECK(loadUncompressedTga(fs, width, height, bpp, data, alloc)); } else if(std::memcmp(tgaHeaderCompressed, &myTgaHeader[0], sizeof(myTgaHeader)) == 0) { ANKI_CHECK(loadCompressedTga(fs, width, height, bpp, data, alloc)); } else { ANKI_LOGE("Invalid image header"); return ErrorCode::USER_DATA; } if(bpp != 32 && bpp != 24) { ANKI_LOGE("Invalid bpp"); return ErrorCode::USER_DATA; } return ErrorCode::NONE; }
//============================================================================== Error LuaBinder::evalString(const CString& str) { Error err = ErrorCode::NONE; int e = luaL_dostring(m_l, &str[0]); if(e) { ANKI_LOGE("%s", lua_tostring(m_l, -1)); lua_pop(m_l, 1); err = ErrorCode::USER_DATA; } lua_gc(m_l, LUA_GCCOLLECT, 0); return err; }
StdinListener::~StdinListener() { m_quit = true; Error err = m_thrd.join(); if(err) { ANKI_LOGE("Error when joining StdinListener"); } for(String& s : m_q) { s.destroy(m_alloc); } m_q.destroy(m_alloc); }
//============================================================================== Error removeDirectory(const CString& dirname) { Error err = ErrorCode::NONE; SHFILEOPSTRUCTA fileOperation; fileOperation.wFunc = FO_DELETE; fileOperation.pFrom = dirname.get(); fileOperation.fFlags = FOF_NO_UI | FOF_NOCONFIRMATION; I result = SHFileOperationA(&fileOperation); if(result != 0) { ANKI_LOGE("Could not delete directory %s", dirname.get()); err = ErrorCode::FUNCTION_FAILED; } return err; }
//============================================================================== Error GlFramebuffer::createFbo( const Array<U, MAX_COLOR_ATTACHMENTS + 1>& layers, GLenum depthStencilBindingPoint) { Error err = ErrorCode::NONE; ANKI_ASSERT(!isCreated()); glGenFramebuffers(1, &m_glName); ANKI_ASSERT(m_glName != 0); const GLenum target = GL_FRAMEBUFFER; glBindFramebuffer(target, m_glName); // Attach color for(U i = 0; i < MAX_COLOR_ATTACHMENTS; i++) { if(!m_attachments[i].isCreated()) { continue; } const GlTexture& tex = m_attachments[i]._get(); attachTextureInternal(GL_COLOR_ATTACHMENT0 + i, tex, layers[i]); } // Attach depth/stencil if(m_attachments[MAX_COLOR_ATTACHMENTS].isCreated()) { ANKI_ASSERT(depthStencilBindingPoint != GL_NONE); const GlTexture& tex = m_attachments[MAX_COLOR_ATTACHMENTS]._get(); attachTextureInternal(depthStencilBindingPoint, tex, layers[MAX_COLOR_ATTACHMENTS]); } // Check completeness GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if(status != GL_FRAMEBUFFER_COMPLETE) { ANKI_LOGE("FBO is incomplete"); destroy(); err = ErrorCode::FUNCTION_FAILED; } return err; }
//============================================================================== void RenderingThread::threadLoop() { prepare(); while(1) { CommandBufferPtr cmd; // Wait for something { LockGuard<Mutex> lock(m_mtx); while(m_tail == m_head) { m_condVar.wait(m_mtx); } // Check signals if(m_renderingThreadSignal == 1) { // Requested to stop break; } U64 idx = m_head % m_queue.getSize(); // Pop a command cmd = m_queue[idx]; m_queue[idx] = CommandBufferPtr(); // Insert empty cmd buffer ++m_head; } ANKI_TRACE_START_EVENT(GL_THREAD); Error err = cmd->getImplementation().executeAllCommands(); ANKI_TRACE_STOP_EVENT(GL_THREAD); if(err) { ANKI_LOGE("Error in rendering thread. Aborting"); abort(); } } finish(); }
//============================================================================== Error XmlElement::getFloats(DynamicArrayAuto<F64>& out) const { Error err = check(); const char* txt; if(!err) { txt = m_el->GetText(); if(txt == nullptr) { err = ErrorCode::USER_DATA; } } StringList list; if(!err) { list.splitString(m_alloc, txt, ' '); } out = DynamicArrayAuto<F64>(m_alloc); if(!err) { out.create(list.getSize()); } auto it = list.getBegin(); for(U i = 0; i < out.getSize() && !err; i++) { err = it->toF64(out[i]); ++it; } if(err) { ANKI_LOGE("Failed to return floats. Element: %s", m_el->Value()); } list.destroy(m_alloc); return err; }
Error PhysicsWorld::create(AllocAlignedCallback allocCb, void* allocCbData) { Error err = ErrorCode::NONE; m_alloc = HeapAllocator<U8>(allocCb, allocCbData); // Set allocators gAlloc = &m_alloc; NewtonSetMemorySystem(newtonAlloc, newtonFree); // Initialize world m_world = NewtonCreate(); if(!m_world) { ANKI_LOGE("NewtonCreate() failed"); return ErrorCode::FUNCTION_FAILED; } // Set the simplified solver mode (faster but less accurate) NewtonSetSolverModel(m_world, 1); // Create scene collision m_sceneCollision = NewtonCreateSceneCollision(m_world, 0); Mat4 trf = Mat4::getIdentity(); m_sceneBody = NewtonCreateDynamicBody(m_world, m_sceneCollision, &trf[0]); NewtonBodySetMaterialGroupID(m_sceneBody, NewtonMaterialGetDefaultGroupID(m_world)); NewtonDestroyCollision(m_sceneCollision); // destroy old scene m_sceneCollision = NewtonBodyGetCollision(m_sceneBody); // Set the post update listener NewtonWorldAddPostListener(m_world, "world", this, postUpdateCallback, destroyCallback); // Set callbacks NewtonMaterialSetCollisionCallback(m_world, NewtonMaterialGetDefaultGroupID(m_world), NewtonMaterialGetDefaultGroupID(m_world), nullptr, onAabbOverlapCallback, onContactCallback); return err; }
//============================================================================== Error XmlElement::getF64(F64& out) const { Error err = check(); if(!err) { const char* txt = m_el->GetText(); if(txt != nullptr) { err = CString(txt).toF64(out); } else { ANKI_LOGE("Failed to return float. Element: %s", m_el->Value()); err = ErrorCode::USER_DATA; } } return err; }
Error DescriptorSetAllocator::allocate(const DescriptorSetLayoutInfo& dsinf, VkDescriptorSet& out) { VkDescriptorSetLayout layout; ANKI_CHECK(m_layoutFactory.getOrCreateLayout(dsinf, layout)); out = VK_NULL_HANDLE; VkDescriptorSetAllocateInfo ci = {}; ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; ci.descriptorPool = m_globalDPool; ci.descriptorSetCount = 1; ci.pSetLayouts = &layout; LockGuard<Mutex> lock(m_mtx); if(++m_descriptorSetAllocationCount > MAX_RESOURCE_GROUPS) { ANKI_LOGE("Exceeded the MAX_RESOURCE_GROUPS"); return ErrorCode::OUT_OF_MEMORY; } ANKI_VK_CHECK(vkAllocateDescriptorSets(m_dev, &ci, &out)); return ErrorCode::NONE; }
//============================================================================== static ANKI_USE_RESULT Error loadUncompressedTga(ResourceFilePtr fs, U32& width, U32& height, U32& bpp, DynamicArray<U8>& data, GenericMemoryPoolAllocator<U8>& alloc) { Array<U8, 6> header6; // read the info from header ANKI_CHECK(fs->read((char*)&header6[0], sizeof(header6))); width = header6[1] * 256 + header6[0]; height = header6[3] * 256 + header6[2]; bpp = header6[4]; if((width == 0) || (height == 0) || ((bpp != 24) && (bpp != 32))) { ANKI_LOGE("Invalid image information"); return ErrorCode::USER_DATA; } // read the data I bytesPerPxl = (bpp / 8); I imageSize = bytesPerPxl * width * height; data.create(alloc, imageSize); ANKI_CHECK(fs->read(reinterpret_cast<char*>(&data[0]), imageSize)); // swap red with blue for(I i = 0; i < imageSize; i += bytesPerPxl) { U32 temp = data[i]; data[i] = data[i + 2]; data[i + 2] = temp; } return ErrorCode::NONE; }
Error fileExtensionToShaderType(const CString& filename, ShaderType& type) { type = ShaderType::COUNT; Error err = ErrorCode::NONE; // Find the shader type if(filename.find(".vert.glsl") != ResourceFilename::NPOS) { type = ShaderType::VERTEX; } else if(filename.find(".tc.glsl") != ResourceFilename::NPOS) { type = ShaderType::TESSELLATION_CONTROL; } else if(filename.find(".te.glsl") != ResourceFilename::NPOS) { type = ShaderType::TESSELLATION_EVALUATION; } else if(filename.find(".geom.glsl") != ResourceFilename::NPOS) { type = ShaderType::GEOMETRY; } else if(filename.find(".frag.glsl") != ResourceFilename::NPOS) { type = ShaderType::FRAGMENT; } else if(filename.find(".comp.glsl") != ResourceFilename::NPOS) { type = ShaderType::COMPUTE; } else { ANKI_LOGE("Wrong shader file format: %s", &filename[0]); err = ErrorCode::USER_DATA; } return err; }
//============================================================================== Error XmlElement::getChildElement(const CString& name, XmlElement& out) const { Error err = check(); if(err) { out = XmlElement(); return err; } err = getChildElementOptional(name, out); if(err) { return err; } if(!out) { ANKI_LOGE("Cannot find tag %s", &name[0]); err = ErrorCode::USER_DATA; } return err; }
//============================================================================== Error GrManagerImpl::initSurface(const GrManagerInitInfo& init) { SDL_SysWMinfo wminfo; SDL_VERSION(&wminfo.version); if(!SDL_GetWindowWMInfo(init.m_window->getNative().m_window, &wminfo)) { ANKI_LOGE("SDL_GetWindowWMInfo() failed"); return ErrorCode::NONE; } #if ANKI_OS == ANKI_OS_LINUX VkXcbSurfaceCreateInfoKHR ci = {}; ci.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR; ci.connection = XGetXCBConnection(wminfo.info.x11.display); ci.window = wminfo.info.x11.window; ANKI_VK_CHECK(vkCreateXcbSurfaceKHR(m_instance, &ci, nullptr, &m_surface)); #else #error TODO #endif return ErrorCode::NONE; }
Error DecalComponent::setLayer(CString texAtlasFname, CString texAtlasSubtexName, F32 blendFactor, LayerType type) { Layer& l = m_layers[type]; ANKI_CHECK(getSceneGraph().getResourceManager().loadResource(texAtlasFname, l.m_atlas)); ANKI_CHECK(l.m_atlas->getSubTextureInfo(texAtlasSubtexName, &l.m_uv[0])); // Add a border to the UVs to avoid complex shader logic if(l.m_atlas->getSubTextureMargin() < ATLAS_SUB_TEXTURE_MARGIN) { ANKI_LOGE("Need texture atlas with margin at least %u", ATLAS_SUB_TEXTURE_MARGIN); return ErrorCode::USER_DATA; } Vec2 marginf = F32(ATLAS_SUB_TEXTURE_MARGIN / 2) / Vec2(l.m_atlas->getWidth(), l.m_atlas->getHeight()); Vec2 minUv = l.m_uv.xy() - marginf; Vec2 sizeUv = (l.m_uv.zw() - l.m_uv.xy()) + 2.0f * marginf; l.m_uv = Vec4(minUv.x(), minUv.y(), minUv.x() + sizeUv.x(), minUv.y() + sizeUv.y()); l.m_blendFactor = blendFactor; return ErrorCode::NONE; }