WError WImage::Load(std::string filename, bool bDynamic) { // check if file exists FILE* fp; fopen_s(&fp, filename.c_str(), "r"); if (fp) fclose(fp); else return WError(W_FILENOTFOUND); int n = 4, w, h; unsigned char *data; if (stbi_info(filename.c_str(), &w, &h, &n) == 0) return WError(W_INVALIDFILEFORMAT); data = stbi_load(filename.c_str(), &w, &h, &n, 0); if (!data) return WError(W_INVALIDFILEFORMAT); // convert from 8-bit char components to 32-bit float components float* pixels = new float[w*h*n]; for (int i = 0; i < w*h*n; i++) { float f = (float)data[i] / (float)(unsigned char)(-1); pixels[i] = f; } free(data); WError err = CreateFromPixelsArray(pixels, w, h, bDynamic, n); delete[] pixels; return err; }
WError WMaterial::Bind(WRenderTarget* rt, unsigned int num_vertex_buffers) { if (!Valid()) return WError(W_NOTVALID); VkDevice device = m_app->GetVulkanDevice(); VkCommandBuffer renderCmdBuffer = rt->GetCommnadBuffer(); if (!renderCmdBuffer) return WError(W_NORENDERTARGET); int curDSIndex = 0; for (int i = 0; i < m_sampler_info.size(); i++) { W_BOUND_RESOURCE* info = m_sampler_info[i].sampler_info; if (m_sampler_info[i].img && m_sampler_info[i].img->Valid()) { m_sampler_info[i].descriptor.imageView = m_sampler_info[i].img->GetView(); VkWriteDescriptorSet writeDescriptorSet = {}; writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptorSet.dstSet = m_descriptorSet; writeDescriptorSet.descriptorCount = 1; writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; writeDescriptorSet.pImageInfo = &m_sampler_info[i].descriptor; writeDescriptorSet.dstBinding = info->binding_index; m_writeDescriptorSets[curDSIndex++] = writeDescriptorSet; } } if (curDSIndex) vkUpdateDescriptorSets(device, curDSIndex, m_writeDescriptorSets.data(), 0, NULL); vkCmdBindDescriptorSets(renderCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, *m_effect->GetPipelineLayout(), 0, 1, &m_descriptorSet, 0, NULL); return m_effect->Bind(rt, num_vertex_buffers); }
WSockets::WSockets() { if (!(m_RefCount++)) { if (WSAStartup(0x0101, &m_wsaData)) throw WError(SOCKETS_CANT_INITIALIZE); if (m_wsaData.wVersion != 0x0101) throw WError(SOCKETS_WRONG_VERSION); } }
WError WMaterial::SaveToStream(WFile* file, std::ostream& outputStream) { if (!Valid()) return WError(W_NOTVALID); VkDevice device = m_app->GetVulkanDevice(); // write the UBO data uint tmp = m_uniformBuffers.size(); outputStream.write((char*)&tmp, sizeof(tmp)); for (uint i = 0; i < m_uniformBuffers.size(); i++) { UNIFORM_BUFFER_INFO* UBO = &m_uniformBuffers[i]; outputStream.write((char*)&UBO->descriptor.range, sizeof(UBO->descriptor.range)); void* data; VkResult vkRes = vkMapMemory(device, m_uniformBuffers[i].memory, 0, UBO->descriptor.range, 0, (void **)&data); if (vkRes) return WError(W_UNABLETOMAPBUFFER); outputStream.write((char*)data, UBO->descriptor.range); vkUnmapMemory(device, m_uniformBuffers[0].memory); } // write the texture data tmp = m_sampler_info.size(); outputStream.write((char*)&tmp, sizeof(tmp)); std::streampos texturesOffset = outputStream.tellp(); for (uint i = 0; i < m_sampler_info.size(); i++) { SAMPLER_INFO* SI = &m_sampler_info[i]; tmp = 0; outputStream.write((char*)&tmp, sizeof(tmp)); outputStream.write((char*)&SI->sampler_info->binding_index, sizeof(SI->sampler_info->binding_index)); } outputStream.write((char*)&tmp, sizeof(tmp)); // effect id _MarkFileEnd(file, outputStream.tellp()); // save dependencies for (uint i = 0; i < m_sampler_info.size(); i++) { SAMPLER_INFO* SI = &m_sampler_info[i]; if (SI->img) { WError err = file->SaveAsset(SI->img, &tmp); if (!err) return err; outputStream.seekp(texturesOffset + std::streamoff(i * (2 * sizeof(uint)))); outputStream.write((char*)&tmp, sizeof(tmp)); } } WError err = file->SaveAsset(m_effect, &tmp); if (!err) return err; outputStream.seekp(texturesOffset + std::streamoff(m_sampler_info.size() * (2 * sizeof(uint)))); outputStream.write((char*)&tmp, sizeof(tmp)); return WError(W_SUCCEEDED); }
WError WImage::MapPixels(void** const pixels, bool bReadOnly) { if (!Valid() || !m_stagingMemory) return WError(W_NOTVALID); VkDevice device = m_app->GetVulkanDevice(); m_readOnlyMap = bReadOnly; VkResult err = vkMapMemory(device, m_stagingMemory, 0, m_mapSize, 0, pixels); if (err) return WError(W_NOTVALID); return WError(W_SUCCEEDED); }
Image::AutoPtr ImageFactory::open(const std::wstring& wpath) { BasicIo::AutoPtr io(new FileIo(wpath)); Image::AutoPtr image = open(io); // may throw if (image.get() == 0) throw WError(11, wpath); return image; }
WError WImageManager::Load() { m_checker_image = new WImage(m_app); int size = 256; int comp_size = 4; int check_size = 16; float* pixels = new float[size * size * comp_size]; for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { int col = ((y/ check_size) + ((x/ check_size) % 2)) % 2; float fCol = col == 0 ? 0.1f : 1.0f; if (comp_size > 0) pixels[(y*size + x) * comp_size + 0] = fCol; if (comp_size > 1) pixels[(y*size + x) * comp_size + 1] = fCol; if (comp_size > 2) pixels[(y*size + x) * comp_size + 2] = fCol; if (comp_size > 3) pixels[(y*size + x) * comp_size + 3] = 1; } } WError werr = m_checker_image->CreateFromPixelsArray(pixels, size, size, false, comp_size); delete[] pixels; if (!werr) { W_SAFE_REMOVEREF(m_checker_image); return werr; } return WError(W_SUCCEEDED); }
DataBuf readFile(const std::wstring& wpath) { FileIo file(wpath); if (file.open("rb") != 0) { throw WError(10, wpath, "rb", strError().c_str()); } struct _stat st; if (0 != ::_wstat(wpath.c_str(), &st)) { throw WError(2, wpath, strError().c_str(), "::_wstat"); } DataBuf buf(st.st_size); long len = file.read(buf.pData_, buf.size_); if (len != buf.size_) { throw WError(2, wpath, strError().c_str(), "FileIo::read"); } return buf; }
long writeFile(const DataBuf& buf, const std::wstring& wpath) { FileIo file(wpath); if (file.open("wb") != 0) { throw WError(10, wpath, "wb", strError().c_str()); } return file.write(buf.pData_, buf.size_); }
WError WSound::SaveToWS(std::string filename) const { if (Valid() && m_dataV.size()) //only attempt to save if the sound is valid and there is something to save { //open the file for writing fstream file; file.open(filename, ios::out | ios::binary); if (!file.is_open()) return WError(W_FILENOTFOUND); float temp[3]; //write pitch & volume alGetSourcef(m_source, AL_PITCH, &temp[0]); alGetSourcef(m_source, AL_GAIN, &temp[1]); file.write((char*)temp, 2 * sizeof(float)); //write position & direction alGetSource3f(m_source, AL_POSITION, &temp[0], &temp[1], &temp[2]); file.write((char*)temp, 3 * sizeof(float)); alGetSource3f(m_source, AL_DIRECTION, &temp[0], &temp[1], &temp[2]); file.write((char*)temp, 3 * sizeof(float)); char numBuffers = m_dataV.size(); file.write((char*)&numBuffers, 1); for (uint i = 0; i < numBuffers; i++) { file.write((char*)&m_dataV[i].buffer, 4); //buffer index file.write((char*)&m_dataV[i].format, sizeof ALenum); //buffer format alGetBufferf(m_buffers[m_dataV[i].buffer], AL_FREQUENCY, &temp[0]); file.write((char*)&temp[0], 4); //frequency file.write((char*)&m_dataV[i].dataSize, 4); //size of data file.write((char*)&m_dataV[i].data, m_dataV[i].dataSize); //data } file.close(); } else return WError(W_NOTVALID); return WError(W_SUCCEEDED); }
void WTcp::Abort(WERROR_CODE Error) { m_LastError = WSAGetLastError(); // save error before doing anything else // // Assume we're being called during construction; when we throw the exception, // our destructor will NOT be called, so clean up resources explicitly first. // closesocket(m_ListenSock); closesocket(m_ConnectSock); throw WError(Error, m_LastError); }
WError WMaterial::SetInstancingTexture(WImage* img) { if (!Valid()) return WError(W_NOTVALID); unsigned int binding_index = -1; for (int i = 0; i < m_effect->m_shaders.size() && binding_index == -1; i++) { if (m_effect->m_shaders[i]->m_desc.type == W_VERTEX_SHADER) binding_index = m_effect->m_shaders[i]->m_desc.instancing_texture_index; } return SetTexture(binding_index, img); }
WError WSound::LoadFromWS(basic_filebuf<char>* buff, uint pos, bool bSaveData) { //use the given stream fstream file; if (!buff) return WError(W_INVALIDPARAM); file.set_rdbuf(buff); file.seekg(pos); float temp[3]; //read pitch & volume file.read((char*)temp, 2 * sizeof(float)); alSourcef(m_source, AL_PITCH, temp[0]); alSourcef(m_source, AL_GAIN, temp[1]); //read position & direction file.read((char*)temp, 3 * sizeof(float)); alSource3f(m_source, AL_POSITION, temp[0], temp[1], temp[2]); file.read((char*)temp, 3 * sizeof(float)); alSource3f(m_source, AL_DIRECTION, temp[0], temp[1], temp[2]); char numBuffers = 0; file.read((char*)&numBuffers, 1); for (uint i = 0; i < numBuffers; i++) { __SAVEDATA data; file.read((char*)&data.buffer, 4); //buffer index file.read((char*)&data.format, sizeof ALenum); //buffer format file.read((char*)&temp[0], 4); //frequency file.read((char*)&data.dataSize, 4); //size of data data.data = W_SAFE_ALLOC(data.dataSize); file.read((char*)&data.data, m_dataV[i].dataSize); //data WError err = LoadFromMemory(data.buffer, data.data, data.dataSize, data.format, temp[0], bSaveData); W_SAFE_FREE(data.data); return WError(err); } return WError(W_SUCCEEDED); }
WError WSound::LoadFromMemory(uint buffer, void* data, size_t dataSize, ALenum format, uint frequency, bool bSaveData) { if (!m_bCheck(true)) return WError(W_ERRORUNK); alBufferData(m_buffers[buffer], format, data, dataSize, frequency); // Attach buffer to source alSourcei(m_source, AL_BUFFER, m_buffers[buffer]); //save data if required if (bSaveData) { __SAVEDATA saveData; saveData.buffer = buffer; saveData.dataSize = dataSize; saveData.format = format; saveData.data = W_SAFE_ALLOC(dataSize); memcpy(saveData.data, data, dataSize); m_dataV.push_back(saveData); } return WError(W_SUCCEEDED); }
WError WSound::LoadFromWS(std::string filename, bool bSaveData) { fstream file; file.open(filename, ios::in | ios::binary); if (file.fail()) return WError(W_FILENOTFOUND); float temp[3]; //read pitch & volume file.read((char*)temp, 2 * sizeof(float)); alSourcef(m_source, AL_PITCH, temp[0]); alSourcef(m_source, AL_GAIN, temp[1]); //read position & direction file.read((char*)temp, 3 * sizeof(float)); alSource3f(m_source, AL_POSITION, temp[0], temp[1], temp[2]); file.read((char*)temp, 3 * sizeof(float)); alSource3f(m_source, AL_DIRECTION, temp[0], temp[1], temp[2]); char numBuffers = 0; file.read((char*)&numBuffers, 1); for (uint i = 0; i < numBuffers; i++) { __SAVEDATA data; file.read((char*)&data.buffer, 4); //buffer index file.read((char*)&data.format, sizeof ALenum); //buffer format file.read((char*)&temp[0], 4); //frequency file.read((char*)&data.dataSize, 4); //size of data data.data = W_SAFE_ALLOC(data.dataSize); file.read((char*)&data.data, m_dataV[i].dataSize); //data LoadFromMemory(data.buffer, data.data, data.dataSize, data.format, temp[0], bSaveData); W_SAFE_FREE(data.data); } file.close(); return WError(W_SUCCEEDED); }
WError WSound::SaveToWS(basic_filebuf<char>* buff, uint pos) const { if (Valid() && m_dataV.size()) //only attempt to save if the sound is valid and there is something to save { //use the given stream fstream file; if (!buff) return WError(W_INVALIDPARAM); file.set_rdbuf(buff); file.seekp(pos); float temp[3]; //write pitch & volume alGetSourcef(m_source, AL_PITCH, &temp[0]); alGetSourcef(m_source, AL_GAIN, &temp[1]); file.write((char*)temp, 2 * sizeof(float)); //write position & direction alGetSource3f(m_source, AL_POSITION, &temp[0], &temp[1], &temp[2]); file.write((char*)temp, 3 * sizeof(float)); alGetSource3f(m_source, AL_DIRECTION, &temp[0], &temp[1], &temp[2]); file.write((char*)temp, 3 * sizeof(float)); char numBuffers = m_dataV.size(); file.write((char*)&numBuffers, 1); for (uint i = 0; i < numBuffers; i++) { file.write((char*)&m_dataV[i].buffer, 4); //buffer index file.write((char*)&m_dataV[i].format, sizeof ALenum); //buffer format alGetBufferf(m_buffers[m_dataV[i].buffer], AL_FREQUENCY, &temp[0]); file.write((char*)&temp[0], 4); //frequency file.write((char*)&m_dataV[i].dataSize, 4); //size of data file.write((char*)&m_dataV[i].data, m_dataV[i].dataSize); //data } } else return WError(W_NOTVALID); return WError(W_SUCCEEDED); }
WError WImage::CopyFrom(WImage* const image) { if (!image || !image->Valid() || !image->m_stagingBuffer) return WError(W_INVALIDPARAM); void* pixels; WError res = image->MapPixels(&pixels, true); if (!res) return res; res = CreateFromPixelsArray(pixels, image->m_width, image->m_height, true, image->m_numComponents, image->m_format, image->m_componentSize); image->UnmapPixels(); return res; }
Image::AutoPtr ImageFactory::create(int type, const std::wstring& wpath) { std::auto_ptr<FileIo> fileIo(new FileIo(wpath)); // Create or overwrite the file, then close it if (fileIo->open("w+b") != 0) { throw WError(10, wpath, "w+b", strError().c_str()); } fileIo->close(); BasicIo::AutoPtr io(fileIo); Image::AutoPtr image = create(type, io); if (image.get() == 0) throw Error(13, type); return image; }
BasicIo::AutoPtr FileIo::temporary() const { BasicIo::AutoPtr basicIo; Impl::StructStat buf; int ret = p_->stat(buf); #if defined WIN32 && !defined __CYGWIN__ DWORD nlink = p_->winNumberOfLinks(); #else nlink_t nlink = buf.st_nlink; #endif // If file is > 1MB and doesn't have hard links then use a file, otherwise // use a memory buffer. I.e., files with hard links always use a memory // buffer, which is a workaround to ensure that the links don't get broken. if (ret != 0 || (buf.st_size > 1048576 && nlink == 1)) { pid_t pid = ::getpid(); std::auto_ptr<FileIo> fileIo; #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { std::wstring tmpname = wpath() + s2ws(toString(pid)); fileIo = std::auto_ptr<FileIo>(new FileIo(tmpname)); } else #endif { std::string tmpname = path() + toString(pid); fileIo = std::auto_ptr<FileIo>(new FileIo(tmpname)); } if (fileIo->open("w+b") != 0) { #ifdef EXV_UNICODE_PATH if (p_->wpMode_ == Impl::wpUnicode) { throw WError(10, wpath(), "w+b", strError().c_str()); } else #endif { throw Error(10, path(), "w+b", strError()); } } fileIo->p_->copyXattrFrom(*this); basicIo = fileIo; } else { basicIo.reset(new MemIo); } return basicIo; }
WError WMaterial::SetVariableData(const char* varName, void* data, int len) { VkDevice device = m_app->GetVulkanDevice(); bool isFound = false; for (int i = 0; i < m_uniformBuffers.size(); i++) { W_BOUND_RESOURCE* info = m_uniformBuffers[i].ubo_info; for (int j = 0; j < info->variables.size(); j++) { if (strcmp(info->variables[j].name.c_str(), varName) == 0) { size_t varsize = info->variables[j].GetSize(); size_t offset = info->OffsetAtVariable(j); if (varsize < len) return WError(W_INVALIDPARAM); uint8_t *pData; VkResult vkRes = vkMapMemory(device, m_uniformBuffers[i].memory, offset, len, 0, (void **)&pData); if (vkRes) return WError(W_UNABLETOMAPBUFFER); memcpy(pData, data, len); vkUnmapMemory(device, m_uniformBuffers[0].memory); isFound = true; } } } return WError(isFound ? W_SUCCEEDED : W_INVALIDPARAM); }
WTcp::WTcp(LPCSTR HostName, DWORD Port, LPCSTR ServerIP, bool UsingReadEvent, EXCEPTION_HANDLER Handler) { m_AmServer = (HostName == NULL); // null host name means we're a server m_ListenSock = INVALID_SOCKET; m_ConnectSock = INVALID_SOCKET; memset(&m_RemoteAddr, 0, sizeof(SOCKADDR_IN)); m_Port = Port; m_LastError = 0; m_ExceptionHandler = Handler; m_ConnectionHandler = NULL; m_ConnectionHandlerArg = NULL; m_AmConnected = FALSE; m_ReadEvent.Create(NULL, TRUE, FALSE, NULL, "WTcp Read"); // manual reset m_ReadDoneEvent.Create(NULL, FALSE, FALSE, NULL, "WTcp Done"); if (m_ReadEvent == NULL || m_ReadDoneEvent == NULL) throw WError(TCP_CANT_CREATE_EVENT); // // If we're a server, create a listening socket; if we're a client, connect to // the specified server. // if (m_AmServer) Listen(ServerIP); else { if (Port != UINT_MAX) // if not in GetConnection Connect(HostName); } // // If we're a server, or we're a client that's using event-driven reads, launch // the receive thread. Servers ALWAYS use event-driven reads. // if (m_AmServer || UsingReadEvent) { m_ReceiveThread.Create(NULL, 0, ReceiveThread, this, 0, NULL, "WTcp Receive"); if (m_ReceiveThread == NULL) throw WError(TCP_CANT_LAUNCH_THREAD); } }
WError WCore::Init(int width, int height) { WError err = WindowComponent->Initialize(width, height); if (!err) return err; /* Create Vulkan instance */ VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = (const char*)engineParams["appName"]; appInfo.pEngineName = "Wasabi"; appInfo.apiVersion = VK_API_VERSION_1_0; std::vector<const char*> enabledExtensions = { VK_KHR_SURFACE_EXTENSION_NAME }; // Enable surface extensions depending on os #if defined(_WIN32) enabledExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #elif defined(__linux__) enabledExtensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); #endif VkInstanceCreateInfo instanceCreateInfo = {}; instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceCreateInfo.pNext = NULL; instanceCreateInfo.pApplicationInfo = &appInfo; if (enabledExtensions.size() > 0) { instanceCreateInfo.enabledExtensionCount = (uint32_t)enabledExtensions.size(); instanceCreateInfo.ppEnabledExtensionNames = enabledExtensions.data(); } VkResult r = vkCreateInstance(&instanceCreateInfo, nullptr, &vkInstance); if (r != VK_SUCCESS) return WError(W_FAILEDTOCREATEINSTANCE); return WError(W_SUCCEEDED); }
WError WImage::SaveToStream(WFile* file, std::ostream& outputStream) { if (!Valid()) return WError(W_NOTVALID); outputStream.write((char*)&m_width, sizeof(m_width)); outputStream.write((char*)&m_height, sizeof(m_height)); outputStream.write((char*)&m_numComponents, sizeof(m_numComponents)); outputStream.write((char*)&m_componentSize, sizeof(m_componentSize)); outputStream.write((char*)&m_format, sizeof(m_format)); void* pixels; WError err = MapPixels(&pixels, true); if (err) { outputStream.write((char*)pixels, m_width * m_height * m_numComponents * m_componentSize); UnmapPixels(); } return err; }
WTcp::~WTcp() { // // Close all sockets. Any sockets function that's blocked on one of these // sockets will immediately unblock, and return an error. // closesocket(m_ListenSock); closesocket(m_ConnectSock); m_ReadDoneEvent.Set(); // in case receive thread is blocked on this // // If the receive thread was launched, kill it. It should exit immediately, // because we've closed both sockets and set m_ReadDoneEvent. If it fails to // exit in a reasonable amount of time, throw an error. // if (m_ReceiveThread != NULL) { if (WaitForSingleObject(m_ReceiveThread, THREAD_EXIT_TIMEOUT) != WAIT_OBJECT_0) throw WError(TCP_CANT_KILL_THREAD); m_ReceiveThread.Close(); } }
WError WImage::LoadFromStream(WFile* file, std::istream& inputStream) { bool bDynamic = false; unsigned int width, height, numComponents, componentSize; VkFormat format; inputStream.read((char*)&width, sizeof(m_width)); inputStream.read((char*)&height, sizeof(m_height)); inputStream.read((char*)&numComponents, sizeof(m_numComponents)); inputStream.read((char*)&componentSize, sizeof(m_componentSize)); inputStream.read((char*)&format, sizeof(m_format)); unsigned int dataSize = width * height * numComponents * componentSize; void* pixels = W_SAFE_ALLOC(dataSize); if (!pixels) return WError(W_OUTOFMEMORY); inputStream.read((char*)pixels, dataSize); WError err = CreateFromPixelsArray(pixels, width, height, bDynamic, numComponents, format, componentSize); W_SAFE_FREE(pixels); return err; }
WError WMaterial::SetTexture(int binding_index, WImage* img) { VkDevice device = m_app->GetVulkanDevice(); bool isFound = false; for (int i = 0; i < m_sampler_info.size(); i++) { W_BOUND_RESOURCE* info = m_sampler_info[i].sampler_info; if (info->binding_index == binding_index) { if (m_sampler_info[i].img) W_SAFE_REMOVEREF(m_sampler_info[i].img); if (img) { m_sampler_info[i].img = img; img->AddReference(); } else { m_sampler_info[i].img = m_app->ImageManager->GetDefaultImage(); m_app->ImageManager->GetDefaultImage()->AddReference(); } isFound = true; } } return WError(isFound ? W_SUCCEEDED : W_INVALIDPARAM); }
WError WImage::CreateFromPixelsArray( void* pixels, unsigned int width, unsigned int height, bool bDynamic, unsigned int num_components, VkFormat fmt, size_t comp_size) { VkDevice device = m_app->GetVulkanDevice(); VkResult err; VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo(); VkMemoryRequirements memReqs = {}; VkBufferImageCopy bufferCopyRegion = {}; VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo(); VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(); uint8_t *data; VkFormat format = fmt; if (fmt == VK_FORMAT_UNDEFINED) { switch (num_components) { case 1: format = VK_FORMAT_R32_SFLOAT; break; case 2: format = VK_FORMAT_R32G32_SFLOAT; break; case 3: format = VK_FORMAT_R32G32B32_SFLOAT; break; case 4: format = VK_FORMAT_R32G32B32A32_SFLOAT; break; default: return WError(W_INVALIDPARAM); } comp_size = 4; } _DestroyResources(); // Create a host-visible staging buffer that contains the raw image data bufferCreateInfo.size = width * height * num_components * comp_size; // This buffer is used as a transfer source for the buffer copy bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; err = vkCreateBuffer(device, &bufferCreateInfo, nullptr, &m_stagingBuffer); if (err) { _DestroyResources(); return WError(W_OUTOFMEMORY); } // Get memory requirements for the staging buffer (alignment, memory type bits) vkGetBufferMemoryRequirements(device, m_stagingBuffer, &memReqs); memAllocInfo.allocationSize = memReqs.size; // Get memory type index for a host visible buffer m_app->GetMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &m_stagingMemory); if (err) { vkDestroyBuffer(device, m_stagingBuffer, nullptr); _DestroyResources(); return WError(W_OUTOFMEMORY); } err = vkBindBufferMemory(device, m_stagingBuffer, m_stagingMemory, 0); if (err) goto free_buffers; // Copy texture data into staging buffer if (pixels) { err = vkMapMemory(device, m_stagingMemory, 0, memReqs.size, 0, (void **)&data); if (err) goto free_buffers; memcpy(data, pixels, bufferCreateInfo.size); vkUnmapMemory(device, m_stagingMemory); } // Create optimal tiled target image imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = format; imageCreateInfo.mipLevels = 1; // TODO: USE m_app->engineParams["numGeneratedMips"] imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; imageCreateInfo.extent = { width, height, 1 }; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; err = vkCreateImage(device, &imageCreateInfo, nullptr, &m_image); if (err) goto free_buffers; vkGetImageMemoryRequirements(device, m_image, &memReqs); memAllocInfo.allocationSize = memReqs.size; m_app->GetMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); err = vkAllocateMemory(device, &memAllocInfo, nullptr, &m_deviceMemory); if (err) goto free_buffers; err = vkBindImageMemory(device, m_image, m_deviceMemory, 0); if (err) goto free_buffers; // Setup buffer copy regions for each mip level bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; bufferCopyRegion.imageSubresource.mipLevel = 0; bufferCopyRegion.imageSubresource.baseArrayLayer = 0; bufferCopyRegion.imageSubresource.layerCount = 1; bufferCopyRegion.imageExtent.width = width; bufferCopyRegion.imageExtent.height = height; bufferCopyRegion.imageExtent.depth = 1; bufferCopyRegion.bufferOffset = 0; err = m_app->BeginCommandBuffer(); if (err) goto free_buffers; // Image barrier for optimal image (target) // Optimal image will be used as destination for the copy vkTools::setImageLayout( m_app->GetCommandBuffer(), m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); // Copy mip levels from staging buffer vkCmdCopyBufferToImage( m_app->GetCommandBuffer(), m_stagingBuffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion ); // Change texture image layout to shader read after all mip levels have been copied vkTools::setImageLayout( m_app->GetCommandBuffer(), m_image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); err = m_app->EndCommandBuffer(); if (err) goto free_buffers; free_buffers: // Clean up staging resources if (err || !bDynamic) { vkFreeMemory(device, m_stagingMemory, nullptr); vkDestroyBuffer(device, m_stagingBuffer, nullptr); m_stagingMemory = VK_NULL_HANDLE; m_stagingBuffer = VK_NULL_HANDLE; } if (err) { _DestroyResources(); return WError(W_OUTOFMEMORY); } // Create image view // Textures are not directly accessed by the shaders and // are abstracted by image views containing additional // information and sub resource ranges VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo(); view.image = VK_NULL_HANDLE; view.viewType = VK_IMAGE_VIEW_TYPE_2D; view.format = format; view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; view.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; view.subresourceRange.baseMipLevel = 0; view.subresourceRange.baseArrayLayer = 0; view.subresourceRange.layerCount = 1; // Linear tiling usually won't support mip maps // Only set mip map count if optimal tiling is used view.subresourceRange.levelCount = 1; // mips view.image = m_image; err = vkCreateImageView(device, &view, nullptr, &m_view); if (err) { _DestroyResources(); return WError(W_UNABLETOCREATEIMAGE); } m_width = width; m_height = height; m_numComponents = num_components; m_componentSize = comp_size; m_mapSize = bufferCreateInfo.size; m_format = format; return WError(W_SUCCEEDED); }
WError WSound::LoadWAV(std::string Filename, uint buffer, bool bSaveData) { if (!m_bCheck(true)) return WError(W_ERRORUNK); fstream file(Filename, ios::in | ios::binary); if (!file.is_open()) return WError(W_FILENOTFOUND); ALenum format; uint dataSize; uint freq; bool bLittleEndian = true; char buffer4Bytes[4] = { 0 }; char buffer2Bytes[2] = { 0 }; //frequency at offset 24 (4 bytes long) file.seekg(0); file.read(buffer4Bytes, 4); if (buffer4Bytes[3] == 'F') //RIFF bLittleEndian = true; else if (buffer4Bytes[3] == 'X') //RIFX bLittleEndian = false; else return WError(W_INVALIDFILEFORMAT); //frequency at offset 24 (4 bytes long) file.seekg(24); file.read(buffer4Bytes, 4); freq = BytesTo<__int32>((BYTE*)buffer4Bytes, bLittleEndian); //data size at offset 22 (2 bytes long) file.seekg(22); file.read(buffer2Bytes, 2); uint numChannels = BytesTo<__int16>((BYTE*)buffer2Bytes, bLittleEndian); //bits per sample at offset 34 (2 bytes long) file.seekg(34); file.read(buffer2Bytes, 2); uint bps = BytesTo<__int16>((BYTE*)buffer2Bytes, bLittleEndian); if (numChannels == 1) format = bps == 8 ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16; else if (numChannels == 2) format = bps == 8 ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16; else { file.close(); return WError(W_INVALIDFILEFORMAT); } //find "data" word int offset = 36; while (offset < 260) { file.seekg(offset); file.read(buffer4Bytes, 4); if (buffer4Bytes[0] == 'd' && buffer4Bytes[1] == 'a' && buffer4Bytes[2] == 't' && buffer4Bytes[3] == 'a') { offset += 4; break; } offset++; } if (offset == 60) { file.close(); return WError(W_INVALIDFILEFORMAT); } //data size at offset (4 bytes long) file.seekg(offset); file.read(buffer4Bytes, 4); dataSize = BytesTo<__int32>((BYTE*)buffer4Bytes, bLittleEndian); //data at offset+4 (dataSize bytes long) file.seekg(offset + 4); void* data = W_SAFE_ALLOC(dataSize); file.read((char*)data, dataSize); //set buffer data alBufferData(m_buffers[buffer], format, data, dataSize, freq); if (alGetError() != AL_NO_ERROR) return WError(W_INVALIDFILEFORMAT); //release read bytes if (!bSaveData) { W_SAFE_FREE(data); } else { __SAVEDATA saveData; saveData.buffer = buffer; saveData.dataSize = dataSize; saveData.format = format; saveData.data = W_SAFE_ALLOC(dataSize); memcpy(saveData.data, data, dataSize); m_dataV.push_back(saveData); } file.close(); // Attach buffer to source alSourcei(m_source, AL_BUFFER, m_buffers[buffer]); m_valid = true; return WError(W_SUCCEEDED); }
WError Wasabi::Resize(int width, int height) { return WError(W_SUCCEEDED); }
WError Wasabi::StartEngine(int width, int height) { WError err = WindowComponent->Initialize(width, height); if (!err) return err; /* Create vulkan instance */ vkInstance = CreateVKInstance((const char*)engineParams["appName"], "Wasabi"); if (!vkInstance) return WError(W_FAILEDTOCREATEINSTANCE); /*// Physical device uint32_t gpuCount = 0; // Get number of available physical devices err = vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr); assert(!err); assert(gpuCount > 0); // Enumerate devices std::vector<VkPhysicalDevice> physicalDevices(gpuCount); err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data()); if (err) { vkTools::exitFatal("Could not enumerate phyiscal devices : \n" + vkTools::errorString(err), "Fatal error"); } // Note : // This example will always use the first physical device reported, // change the vector index if you have multiple Vulkan devices installed // and want to use another one physicalDevice = physicalDevices[0]; // Find a queue that supports graphics operations uint32_t graphicsQueueIndex = 0; uint32_t queueCount; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL); assert(queueCount >= 1); std::vector<VkQueueFamilyProperties> queueProps; queueProps.resize(queueCount); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps.data()); for (graphicsQueueIndex = 0; graphicsQueueIndex < queueCount; graphicsQueueIndex++) { if (queueProps[graphicsQueueIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) break; } assert(graphicsQueueIndex < queueCount); // Vulkan device std::array<float, 1> queuePriorities = { 0.0f }; VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = graphicsQueueIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = queuePriorities.data(); err = createDevice(queueCreateInfo, enableValidation); assert(!err); // Store properties (including limits) and features of the phyiscal device // So examples can check against them and see if a feature is actually supported vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); #if defined(__ANDROID__) LOGD(deviceProperties.deviceName); #endif // Gather physical device memory properties vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties); // Get the graphics queue vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue); // Find a suitable depth format VkBool32 validDepthFormat = vkTools::getSupportedDepthFormat(physicalDevice, &depthFormat); assert(validDepthFormat); swapChain.connect(instance, physicalDevice, device); // Create synchronization objects VkSemaphoreCreateInfo semaphoreCreateInfo = vkTools::initializers::semaphoreCreateInfo(); // Create a semaphore used to synchronize image presentation // Ensures that the image is displayed before we start submitting new commands to the queu err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.presentComplete); assert(!err); // Create a semaphore used to synchronize command submission // Ensures that the image is not presented until all commands have been sumbitted and executed err = vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &semaphores.renderComplete); assert(!err); // Set up submit info structure // Semaphores will stay the same during application lifetime // Command buffer submission info is set by each example submitInfo = vkTools::initializers::submitInfo(); submitInfo.pWaitDstStageMask = &submitPipelineStages; submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = &semaphores.presentComplete; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &semaphores.renderComplete;*/ return WError(W_SUCCEEDED); }