void kit::PixelBuffer::clear(std::vector<glm::vec4> colours, float depth) { kit::GL::depthMask(GL_TRUE); this->bind(); if(this->m_depthAttachment == nullptr) { KIT_THROW("Cant clear depth attachment as it does not exist, use the other clear method"); } if(colours.size() != this->m_colorAttachments.size()) { KIT_THROW("Wrong number of colors passed, one color per attachment is required."); } for(int32_t i = 0; i < this->m_colorAttachments.size(); i++) { float currColor[4] = {colours[i].x, colours[i].y, colours[i].z, colours[i].w}; KIT_GL(glClearBufferfv(GL_COLOR, i, &currColor[0])); } KIT_GL(glClearBufferfv(GL_DEPTH, 0, &depth)); }
kit::Texture::Ptr kit::PixelBuffer::getColorAttachment(uint32_t index) { if(index >= this->m_colorAttachments.size()) { KIT_THROW("Index out of range"); } return this->m_colorAttachments[index]; }
kit::Window* kit::Window::kitWFromGLFW(GLFWwindow* ptr) { for(auto currWindow : kit::Window::m_windows) { if(currWindow->getGLFWHandle() == ptr){ return currWindow; } } KIT_THROW("No such window registered."); return nullptr; // Compiler will nag if we dont return }
void kit::PixelBuffer::clearDepth(float d) { kit::GL::depthMask(GL_TRUE); this->bind(); if(this->m_depthAttachment == nullptr) { KIT_THROW("Cant clear depth attachment as it does not exist, use the other clear method"); } KIT_GL(glClearBufferfv(GL_DEPTH, 0, &d)); }
void kit::PixelBuffer::clearAttachment(uint32_t attachment, glm::ivec4 clearcolor) { this->bind(); if (attachment >= this->m_colorAttachments.size()) { KIT_THROW("Cant clear attachment, index out of range."); } GLint color[4] = { clearcolor.x, clearcolor.y, clearcolor.z, clearcolor.w }; KIT_GL(glClearBufferiv(GL_COLOR, attachment, &color[0])); }
kit::PixelBuffer::Ptr kit::PixelBuffer::create(glm::uvec2 resolution, kit::PixelBuffer::AttachmentList colorattachments) { kit::PixelBuffer::Ptr returner = std::make_shared<kit::PixelBuffer>(); returner->m_resolution = resolution; if(colorattachments.size() == 0) { KIT_GL(glNamedFramebufferDrawBuffer(returner->m_glHandle, GL_NONE)); } else { // Keep track of attachments and create a drawbuffers std::vector<GLenum> drawBuffers(colorattachments.size()); uint32_t currAttachment = 0; // Add/create color attachments for(auto & info : colorattachments) { // Fill the drawbuffer GLenum currEnum = GL_COLOR_ATTACHMENT0+ currAttachment; drawBuffers[currAttachment] = currEnum; currAttachment++; // Add texture if exists, otherwise create it if(info.texture != nullptr) { // Assert resolution if(info.texture->getResolution().x != resolution.x || info.texture->getResolution().y != resolution.y) { KIT_THROW("Pixelbuffer attachments must be of the same size"); } returner->m_colorAttachments.push_back(info.texture); KIT_GL(glNamedFramebufferTexture(returner->m_glHandle, currEnum, info.texture->getHandle(), 0)); } else { kit::Texture::Ptr adder = kit::Texture::create2D(resolution, info.format, info.edgeSamplingMode, info.minFilteringMode, info.magFilteringMode); returner->m_colorAttachments.push_back(adder); KIT_GL(glNamedFramebufferTexture(returner->m_glHandle, currEnum, adder->getHandle(), 0)); } } // Set drawbuffers KIT_GL(glNamedFramebufferDrawBuffers(returner->m_glHandle, (GLsizei)drawBuffers.size(), &drawBuffers[0])); } return returner; }
void kit::PixelBuffer::blitFrom(kit::PixelBuffer::Ptr source, bool colorMask, std::vector<std::array<bool, 4>> componentMask, bool depthMask, bool stencilMask) { bool clearColorMask = false; GLbitfield mask = 0; if (colorMask) { mask |= GL_COLOR_BUFFER_BIT; if (this->m_colorAttachments.size() != source->getNumColorAttachments()) { KIT_THROW("source: color attachment count mismatch"); return; } } if (depthMask) { mask |= GL_DEPTH_BUFFER_BIT; } if (stencilMask) { mask |= GL_STENCIL_BUFFER_BIT; } if (componentMask.size() != 0 && colorMask) { if (componentMask.size() != this->m_colorAttachments.size()) { KIT_ERR("componentMask: color attachment count mismatch"); return; } for (int i = 0; i < this->m_colorAttachments.size(); i++) { KIT_GL(glColorMaski(i, componentMask[i][0], componentMask[i][1], componentMask[i][2], componentMask[i][3])); } clearColorMask = true; } KIT_GL(glBlitNamedFramebuffer(source->getHandle(), this->getHandle(), 0, 0, source->getResolution().x, source->getResolution().y, 0, 0, this->getResolution().x, this->getResolution().y, mask, GL_LINEAR)); if (clearColorMask) { for (int i = 0; i < this->m_colorAttachments.size(); i++) { KIT_GL(glColorMaski(i, true, true, true, true)); } } }
void kit::PixelBuffer::clear(std::vector< glm::vec4 > colours) { this->bind(); if(colours.size() != this->m_colorAttachments.size()) { KIT_THROW("Wrong number of colors passed, one color per attachment is required."); } for(int32_t i = 0; i < this->m_colorAttachments.size(); i++) { float currColor[4] = {colours[i].x, colours[i].y, colours[i].z, colours[i].w}; KIT_GL(glClearBufferfv(GL_COLOR, i, &currColor[i])); } }
std::string kit::getDataDirectory(kit::DataSource source) { switch (source) { case kit::DataSource::Data: return KIT_DATA; break; case kit::DataSource::Static: return KIT_STATIC_DATA; break; case kit::DataSource::Editor: return KIT_EDITOR_DATA; break; } KIT_THROW("Invalid datasource"); }
void kit::Cubemap::setEdgeSamplingMode(kit::Cubemap::EdgeSamplingMode mode) { this->m_edgeSamplingMode = mode; this->bind(); switch(this->m_edgeSamplingMode) { case Repeat: glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_REPEAT); break; case RepeatMirrored: glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT); break; case Clamp: glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); break; #ifdef __unix__ case ClampMirrored: glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_MIRROR_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_MIRROR_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_MIRROR_CLAMP_TO_EDGE); break; #elif _WIN32 case ClampMirrored: KIT_THROW("ClampMirrored not supported on windows platforms."); break; #endif } kit::Cubemap::unbind(); }
kit::Texture::EdgeSamplingMode kit::Texture::getEdgeSamplingMode(EdgeSamplingAxis axis) { switch(axis) { case kit::Texture::All: KIT_THROW("Cant get edge sampling mode from all axes, do each one individually"); break; case kit::Texture::S: return this->m_edgeSamplingModeS; break; case kit::Texture::T: return this->m_edgeSamplingModeT; break; case kit::Texture::R: return this->m_edgeSamplingModeR; break; } KIT_ERR("Warning: Invalid parameter passed as axis"); return kit::Texture::ClampToEdge; }
kit::Window::Window(kit::Window::Args const & windowArgs) { kit::Window::m_instanceCount++; this->m_glfwHandle = nullptr; this->m_isFocused = true; this->m_isMinimized = false; this->m_virtualMouse = false; // Get the GLFW handle from the window to share resources with GLFWwindow * glfwSharedWindow = nullptr; if(windowArgs.sharedWindow != nullptr) { glfwSharedWindow = windowArgs.sharedWindow->getGLFWHandle(); } // Get the GLFW handle for the fullscreen monitor to use GLFWmonitor* glfwFullscreenMonitor = windowArgs.fullscreenMonitor->getGLFWHandle(); // Set OpenGL context hints. kit::Window::prepareGLFWHints(GLFW_CONTEXT_VERSION_MAJOR, 4); kit::Window::prepareGLFWHints(GLFW_CONTEXT_VERSION_MINOR, 3); kit::Window::prepareGLFWHints(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Set window-specific hints and create window according to our window-arguments switch(windowArgs.mode) { case kit::Window::Mode::Windowed: if(!windowArgs.resizable) { kit::Window::prepareGLFWHints(GLFW_RESIZABLE, GL_FALSE); } this->m_glfwHandle = glfwCreateWindow(windowArgs.resolution.x, windowArgs.resolution.y, windowArgs.title.c_str(), nullptr, glfwSharedWindow); break; case kit::Window::Mode::Fullscreen: this->m_glfwHandle = glfwCreateWindow(windowArgs.resolution.x, windowArgs.resolution.y, windowArgs.title.c_str(), glfwFullscreenMonitor, glfwSharedWindow); break; case kit::Window::Mode::Borderless: kit::Window::prepareGLFWHints(GLFW_DECORATED, GL_FALSE); kit::Window::prepareGLFWHints(GLFW_RESIZABLE, GL_FALSE); this->m_glfwHandle = glfwCreateWindow(windowArgs.resolution.x, windowArgs.resolution.y, windowArgs.title.c_str(), nullptr, glfwSharedWindow); break; default: KIT_THROW("Invalid window mode"); break; } // Reset the GLFW hints after creation kit::Window::restoreGLFWHints(); // Assert that we have a GLFW window if(!this->m_glfwHandle) { KIT_THROW("Failed to create GLFW window"); } // Register the window to the static list of windows, to keep track of events/callbacks kit::Window::m_windows.push_back(this); // Register GLFW callbacks for this window glfwSetWindowPosCallback(this->m_glfwHandle, kit::Window::__winfunc_position); glfwSetWindowSizeCallback(this->m_glfwHandle, kit::Window::__winfunc_size); glfwSetWindowCloseCallback(this->m_glfwHandle, kit::Window::__winfunc_close); glfwSetWindowFocusCallback(this->m_glfwHandle, kit::Window::__winfunc_focus); glfwSetWindowIconifyCallback(this->m_glfwHandle, kit::Window::__winfunc_minimize); glfwSetFramebufferSizeCallback(this->m_glfwHandle, kit::Window::__winfunc_framebuffersize); glfwSetMouseButtonCallback(this->m_glfwHandle, kit::Window::__infunc_mousebutton); glfwSetCursorPosCallback(this->m_glfwHandle, kit::Window::__infunc_cursorpos); glfwSetCursorEnterCallback(this->m_glfwHandle, kit::Window::__infunc_cursorenter); glfwSetScrollCallback(this->m_glfwHandle, kit::Window::__infunc_scroll); glfwSetKeyCallback(this->m_glfwHandle, kit::Window::__infunc_key); glfwSetCharCallback(this->m_glfwHandle, kit::Window::__infunc_char); // Activate the current windows context this->activateContext(); // Enable V-sync glfwSwapInterval(1); // Make sure GL3W is initialized, and set the viewport kit::initializeGL3W(); KIT_GL(glViewport(0, 0, this->getFramebufferSize().x , this->getFramebufferSize().y)); }
kit::Texture::Texture(const std::string & filename, kit::Texture::InternalFormat format, uint8_t levels, Type t) : kit::Texture(t) { std::cout << "Loading texture from file \"" << filename.c_str() << "\"" << std::endl; m_filename = filename; if(t == Type::Texture2D) { m_internalFormat = format; // Try to load data from file unsigned char* bufferdata; int x, y, n; stbi_set_flip_vertically_on_load(1); bufferdata = stbi_load(filename.c_str(), &x, &y, &n, 4); if (bufferdata == nullptr) { KIT_THROW(stbi_failure_reason()); } // Set resolution m_resolution = glm::uvec3(x, y, 0); uint8_t mipLevels = levels > 0 ? levels : calculateMipLevels(); // Specify storage and upload data to GPU #ifndef KIT_SHITTY_INTEL glTextureStorage2D(m_glHandle, mipLevels, m_internalFormat, m_resolution.x, m_resolution.y); glTextureSubImage2D(m_glHandle, 0, 0, 0, x, y, GL_RGBA, GL_UNSIGNED_BYTE, bufferdata); #else bind(); glTexStorage2D(m_type, mipLevels, m_internalFormat, m_resolution.x, m_resolution.y); glTexSubImage2D(m_type, 0, 0, 0, x, y, GL_RGBA, GL_UNSIGNED_BYTE, bufferdata); #endif // Free loaded data stbi_image_free(bufferdata); // Set parameters setEdgeSamplingMode(EdgeSamplingMode::Repeat); setMinFilteringMode(m_minFilteringMode); setMagFilteringMode(m_magFilteringMode); setAnisotropicLevel(1.0f); } if(t == Type::Texture3D) { m_internalFormat = format; // Try to load data from file unsigned char* bufferdata; int x, y, n; stbi_set_flip_vertically_on_load(0); bufferdata = stbi_load(filename.c_str(), &x, &y, &n, 4); if (bufferdata == nullptr) { KIT_THROW(stbi_failure_reason()); } if (y != x*x || y%y != 0) { KIT_THROW("Failed to load 3d texture from file, not perfectly cubical"); } // Set resolution m_resolution = glm::uvec3(x, x, x); // Specify storage and upload data to GPU #ifndef KIT_SHITTY_INTEL glTextureStorage3D(m_glHandle, 1, m_internalFormat, x, x, x); glTextureSubImage3D(m_glHandle, 0, 0, 0, 0, x, x, x, GL_RGBA, GL_UNSIGNED_BYTE, bufferdata); #else returner->bind(); glTexStorage3D(returner->m_type, 1, m_internalFormat, x, x, x); glTexSubImage3D(returner->m_type, 0, 0, 0, 0, x, x, x, GL_RGBA, GL_UNSIGNED_BYTE, bufferdata); #endif // Free loaded data stbi_image_free(bufferdata); setEdgeSamplingMode(EdgeSamplingMode::Repeat); setMinFilteringMode(m_minFilteringMode); setMagFilteringMode(m_magFilteringMode); setAnisotropicLevel(1.0f); } }
kit::BakedTerrain::BakedTerrain(std::string const & name) { glGenVertexArrays(1, &m_glVertexArray); glGenBuffers(1, &m_glVertexIndices); glGenBuffers(1, &m_glVertexBuffer); uint32_t vertexDataLen = 0; float * vertexData = nullptr; uint32_t * indexData = nullptr; std::string dataDirectory = "./data/terrains/" + name + "/baked/"; // Load data { std::cout << "Loading vertex data from disk" << std::endl; std::ifstream f(dataDirectory + "vertexdata", std::ios_base::in | std::ios_base::binary); if(!f) { KIT_THROW("Failed to load terrain \"" + name + "\": could not load vertexdata."); } // Read index-data length (in ints) m_indexCount = kit::readUint32(f); // Read index data indexData = new uint32_t[m_indexCount]; for (uint32_t i = 0; i < m_indexCount; i++) { indexData[i] = kit::readUint32(f); } // Read vertex-data length (in floats) vertexDataLen = kit::readUint32(f); // Read vertex data vertexData = new float[vertexDataLen]; for (uint32_t i = 0; i < vertexDataLen; i++) { vertexData[i] = kit::readFloat(f); } f.close(); } // Upload data { std::cout << "Uploading data to GPU" << std::endl; glBindVertexArray(m_glVertexArray); // Upload indices std::cout << "Uploading indices (" << (m_indexCount * sizeof(uint32_t)) << " bytes)" << std::endl; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_glVertexIndices); glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(uint32_t), &indexData[0], GL_STATIC_DRAW); // Upload vertices std::cout << "Uploading vertices (" << (vertexDataLen * sizeof(float)) << " bytes)" << std::endl; glBindBuffer(GL_ARRAY_BUFFER, m_glVertexBuffer); glBufferData(GL_ARRAY_BUFFER, vertexDataLen * sizeof(float) , &vertexData[0], GL_STATIC_DRAW); } // Cleanup data { std::cout << "Cleaning up CPU copy" << std::endl; delete[] indexData; delete[] vertexData; } // Configure attributes { std::cout << "Setting up GPU attributes" << std::endl; static const uint32_t attributeSize = sizeof(float) * 14; // Positions glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, attributeSize, (void*)0); // Texture coordinates glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, attributeSize, (void*) (sizeof(float) * 3) ); // Normals glEnableVertexAttribArray(2); glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, attributeSize, (void*) (sizeof(float) * 5) ); // Tangents glEnableVertexAttribArray(3); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, attributeSize, (void*) (sizeof(float) * 8) ); glEnableVertexAttribArray(4); glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, attributeSize, (void*) (sizeof(float) * 11) ); } // Load maps { std::cout << "Loading maps" << std::endl; m_arCache = new kit::Texture(dataDirectory + "arcache.tga"); m_arCache->setEdgeSamplingMode(Texture::Repeat); m_arCache->setMinFilteringMode(Texture::LinearMipmapLinear); m_arCache->setMagFilteringMode(Texture::Linear); m_arCache->setAnisotropicLevel(8.0f); m_arCache->generateMipmap(); m_nxCache = new kit::Texture(dataDirectory + "nxcache.tga"); m_nxCache->setEdgeSamplingMode(Texture::Repeat); m_nxCache->setMinFilteringMode(Texture::LinearMipmapLinear); m_nxCache->setMagFilteringMode(Texture::Linear); m_nxCache->setAnisotropicLevel(8.0f); m_nxCache->generateMipmap(); try { m_materialMask[0] = new kit::Texture(dataDirectory + "materialmask0.tga"); m_materialMask[0]->setEdgeSamplingMode(Texture::ClampToEdge); m_materialMask[0]->setMinFilteringMode(Texture::LinearMipmapLinear); m_materialMask[0]->setMagFilteringMode(Texture::Linear); m_materialMask[0]->setAnisotropicLevel(8.0f); m_materialMask[0]->generateMipmap(); m_materialMask[1] = new kit::Texture(dataDirectory + "materialmask1.tga"); m_materialMask[1]->setEdgeSamplingMode(Texture::ClampToEdge); m_materialMask[1]->setMinFilteringMode(Texture::LinearMipmapLinear); m_materialMask[1]->setMagFilteringMode(Texture::Linear); m_materialMask[1]->setAnisotropicLevel(8.0f); m_materialMask[1]->generateMipmap(); } catch (...) { } } // Load header { std::cout << "Loading header" << std::endl; std::string currLine; std::ifstream f(dataDirectory + "header", std::ios_base::in); if(!f) { KIT_THROW("Failed to load terrain \"" + name + "\": could not load header."); } while(std::getline(f, currLine)) { if(kit::trim(currLine) == "") { continue; } auto args = kit::splitString(currLine); if(args[0] == "xzscale" && args.size() == 2) { m_xzScale = (float)std::atof(args[1].c_str()); } if (args[0] == "yscale" && args.size() == 2) { m_yScale = (float)std::atof(args[1].c_str()); } if(args[0] == "numlayers" && args.size() == 2) { m_numLayers = std::atoi(args[1].c_str()); if(m_numLayers > 8) { KIT_THROW("Too many layers in terrain"); } } if(args[0] == "size" && args.size() == 3) { m_size.x = std::atoi(args[1].c_str()); m_size.y = std::atoi(args[2].c_str()); } if(args[0] == "layer" && args.size() == 3) { int currLayer = std::atoi(args[1].c_str()); if(currLayer >= 0 && currLayer <= 7 && currLayer < m_numLayers) { m_layerInfo[currLayer].uvScale = (float)std::atof(args[2].c_str()); m_layerInfo[currLayer].used = true; std::stringstream currAr; currAr << dataDirectory << "arlayer" << currLayer << ".tga"; m_layerInfo[currLayer].arCache = new kit::Texture(currAr.str()); m_layerInfo[currLayer].arCache->setEdgeSamplingMode(Texture::Repeat); m_layerInfo[currLayer].arCache->setMinFilteringMode(Texture::LinearMipmapLinear); m_layerInfo[currLayer].arCache->setMagFilteringMode(Texture::Linear); m_layerInfo[currLayer].arCache->setAnisotropicLevel(8.0f); m_layerInfo[currLayer].arCache->generateMipmap(); std::stringstream currNm; currNm << dataDirectory << "ndlayer" << currLayer << ".tga"; m_layerInfo[currLayer].ndCache = new kit::Texture(currNm.str()); m_layerInfo[currLayer].ndCache->setEdgeSamplingMode(Texture::Repeat); m_layerInfo[currLayer].ndCache->setMinFilteringMode(Texture::LinearMipmapLinear); m_layerInfo[currLayer].ndCache->setMagFilteringMode(Texture::Linear); m_layerInfo[currLayer].ndCache->setAnisotropicLevel(8.0f); m_layerInfo[currLayer].ndCache->generateMipmap(); } else { KIT_THROW("Invalid layer id"); } } } f.close(); } // Load height data { std::ifstream f(dataDirectory + "heightdata", std::ios_base::in | std::ios_base::binary); if (!f) { KIT_THROW("Failed to load terrain \"" + name + "\": could not load heightdata."); } // Reserve and load height data m_heightData.reserve(m_size.x * m_size.y); for (unsigned int i = 0; i < m_size.y * m_size.x; i++) { kit::BakedTerrain::Vertex adder; adder.m_height = kit::readFloat(f); adder.m_normal = kit::readVec3(f); m_heightData.push_back(adder); } } m_valid = true; std::cout << "Generating GPU program and verifying cache" << std::endl; updateGpuProgram(); }
kit::Skeleton::Ptr kit::Skeleton::load(std::string filename) { kit::Skeleton::Ptr returner = std::make_shared<kit::Skeleton>(); std::ifstream s(std::string(std::string("./data/skeletons/") + filename).c_str(), std::ios::in | std::ios::binary); std::cout << "Loading skeleton " << filename.c_str() << std::endl; if(!s) { KIT_THROW("Couldn't open file for reading"); } if (memcpy(&kit::readBytes(s, 4)[0], "KSKE", 4) != 0) { KIT_THROW("Bad signature"); } uint32_t numBones = kit::readUint32(s); returner->m_boneIndexId = std::vector<Bone::Ptr>(numBones); returner->m_inverseBindPose = std::vector<glm::mat4>(numBones); returner->m_skin = std::vector<glm::mat4>(numBones); uint32_t numAnimations = kit::readUint32(s); returner->m_globalInverseTransform = kit::readMat4(s); // ... Bones for(uint32_t i = 0; i < numBones; i++) { kit::Skeleton::Bone::Ptr newBone = std::make_shared<Bone>(); newBone->m_id = kit::readUint32(s); newBone->m_parentId = kit::readUint32(s); newBone->m_name = kit::readString(s); newBone->m_localTransform = kit::readMat4(s); newBone->m_globalTransform = glm::mat4(1.0); returner->m_inverseBindPose[newBone->m_id] = kit::readMat4(s); returner->m_boneIndexId[newBone->m_id] = newBone; returner->m_boneIndexName[newBone->m_name] = newBone; } // Fill in parents, rootbones and children for (auto & currBone : returner->m_boneIndexId) { if (currBone->m_parentId == 1337) { returner->m_rootBones.push_back(currBone); } else { currBone->m_parent = returner->getBone(currBone->m_parentId); } for (auto & currBoneB : returner->m_boneIndexId) { if (currBoneB->m_parentId == currBone->m_id) { currBone->m_children.push_back(currBoneB); } } } // .. Animations for(uint32_t i = 0; i < numAnimations; i++) { kit::Skeleton::Animation::Ptr newAnimation = std::make_shared<Animation>(); newAnimation->m_name = kit::readString(s); uint32_t numChannels = kit::readUint32(s); newAnimation->m_framesPerSecond = kit::readFloat(s); newAnimation->m_frameDuration = kit::readFloat(s); // Channels for(uint32_t ic = 0; ic < numChannels; ic++) { kit::Skeleton::AnimationChannel newChannel; uint32_t boneId = readUint32(s); uint32_t numtk = kit::readUint32(s); uint32_t numrk = kit::readUint32(s); uint32_t numsk = kit::readUint32(s); for(uint32_t ctk = 0; ctk < numtk; ctk++) { float time = kit::readFloat(s); newChannel.m_translationKeys[time] = kit::readVec3(s); } for(uint32_t crk = 0; crk < numrk; crk++) { float time = kit::readFloat(s); newChannel.m_rotationKeys[time] = kit::readQuat(s); } for(uint32_t csk = 0; csk < numsk; csk++) { float time = kit::readFloat(s); newChannel.m_scaleKeys[time] = kit::readVec3(s); } newAnimation->m_channels[boneId] = newChannel; } returner->m_animations[newAnimation->m_name] = newAnimation; } s.close(); return returner; }