So the question above pretty much explains my problem, I have a program that prints the code size of my fragment shader and vertex shader, it is part of my Game engine project I have been working on for the past few days as a learning experience to get more knowledge of low-level c++ programming, but the problem is when I list where both shaders are placed in the project, my program proceeds to crash with a memory leak, the answer I need is exactly why this is happening
PipeLine.h:
#include <iostream>
#include <vector>
namespace G_piplne
{
class EdtrPipeLine
{
public:
//grabs the file path to the frag file of the glsl shader file
EdtrPipeLine(const std::string& vertFilePath, const std::string& fragFilePath);
private:
//gets the file path of both the frag file and vert file
static std::vector<char> readFile(const std::string& filepath);
//grabs the file path to the vert file of the glsl shader file
void createGraphicsPipeLine(const std::string& vertFilePath, const std::string& fragFilePath);
};
}
PipeLine.cpp used for initiating the functions in the PipeLine header file
#include "shaders_h/PipeLine.h"
#include <fstream>
#include <stdexcept>
namespace G_piplne
{
EdtrPipeLine::EdtrPipeLine(const std::string& vertFilePath, const std::string& fragFilePath)
{
createGraphicsPipeLine(vertFilePath, fragFilePath);
}
std::vector<char> EdtrPipeLine::readFile(const std::string& filepath)
{
std::ifstream file(filepath, std::ios::ate | std::ios::binary);
if (!file.is_open())
{
throw std::runtime_error("failed to open file: " + filepath);
}
size_t filesize = static_cast<size_t>(file.tellg());
std::vector<char> buffer(filesize);
file.seekg(0);
file.read(buffer.data(), filesize);
file.close();
return buffer;
}
void EdtrPipeLine::createGraphicsPipeLine(const std::string& vertFilePath, const std::string& fragFilePath)
{
//Reads Frag and Vert Code Size
auto vertCode = readFile(vertFilePath);
auto fragCode = readFile(fragFilePath);
//Prints Frag and Vert Code Size
std::cout << "Vertex Shader Code Size: " << vertCode.size() << "\n";
std::cout << "Frag Shader Code Size: " << fragCode.size() << "\n";
}
}
and finally, the EditorConfigWindow header file which uses the function to display my vert and frag code size
#pragma once
#include "EditorWindow.h"
#include "../shaders_h/PipeLine.h"
namespace G_editor
{
class EditorWindowConfig
{
public:
//Init Varibles for the size of the Editor Window
static constexpr int WIDTH = 800;
static constexpr int HEIGHT = 600;
void run();
private:
//init Window with name GPRPG
EditorWindow editorWindow{ WIDTH, HEIGHT, "GPRPG" };
//Display vert and frag code size
G_piplne::EdtrPipeLine edtrPipeLine{"../../Shaders/simpleShader.vert.spv ", "../../Shaders/simpleShader.frag.spv"};
};
}
All shader files are in the right place and listed correctly, I double-checked the names and they are correct as well, the error is as listed below
Unhandled exception at 0x00007FF8F0154F69 in GPRPG.exe: Microsoft C++ exception: std::runtime_error at memory location 0x00000064240FEEA8.
this error is hit at the breakpoint right when the createGraphicsPipeLine function is called from the EditorWindowConfig Header file, I've tried moving the shader files around in the project but it leads to the same problem, thank you in advance for any assistance given that may point me in the right direction to solve this problem
In researching, I found that adding the absolute path to my shader file actually outputs the size as expected, the program didn't like the short path I was inputting for some reason
Related
I'm trying to determine how big a file i'm reading is in bytes so I used Fseek to jump to the end and it triggered the error: file.exe has triggered a breakpoint.
Heses the code:
FileUtils.cpp:
#include "FileUtils.h"
namespace impact {
std::string read_file(const char* filepath)
{
FILE* file = fopen(filepath, "rt");
fseek(file, 0, SEEK_END);
unsigned long length = ftell(file);
char* data = new char[length + 1];
memset(data, 0, length + 1);
fseek(file, 0 ,SEEK_SET);
fread(data, 1, length, file);
fclose(file);
std::string result(data);
delete[] data;
return result;
}
}
FileUtils.h:
#pragma once
#include <stdio.h>
#include <string>
#include <fstream>
namespace impact {
std::string read_file(const char* filepath);
}
If more info is required just ask me for it I would be more than happy to provide more!
You are doing this in the C way, C++ has much better (in my opinion) ways of handling files.
Your error looks like it may be caused because the file didn't open correctly (you need to check if file != nullptr).
To do this in C++17 you should use the standard library filesystem
(Note: You can also do this with C++11 experimental/filesystem using std::experimental::filesystem namespace)
Example:
std::string read_file(const std::filesystem::path& filepath) {
auto f_size = std::filesystem::file_size(filepath);
...
}
Additionally to read a file in C++ you do not need to know the size of the file. You can use streams:
std::string read_file(const std::filesystem::path& filepath) {
std::ifstream file(filepath); // Open the file
// Throw if failed to open the file
if (!file) throw std::runtime_error("File failed to open");
std::stringstream data; // Create the buffer
data << file.rdbuf(); // Read into the buffer the internal buffer of the file
return data.str(); // Convert the stringstream to string and return it
}
As you can see, the C++ way of doing it is much shorter and much easier to debug (helpful exceptions with descriptions are thrown when something goes wrong)
I am load a bmp file into a CImg object and I save it into pfm file. Successful. And this .pfm file I am using it into another library, but this library doesn't accept big-endian, just little endian.
CImg<float> image;
image.load_bmp(_T("D:\\Temp\\memorial.bmp"));
image.normalize(0.0, 1.0);
image.save_pfm(_T("D:\\Temp\\memorial.pfm"));
So, how can I save bmp file to pfm file as little endian, not big endian .. it is possible ?
Later edit:
I have checked first 5 elements from .pfm header file. This is the result without invert_endianness:
CImg<float> image;
image.load_bmp(_T("D:\\Temp\\memorial.bmp"));
image.normalize(0.0, 1.0);
image.save_pfm(_T("D:\\Temp\\memorial.pfm"));
PF
512
768
1.0
=øøù=€€=‘>
and this is the result with invert_endianness:
CImg<float> image;
image.load_bmp(_T("D:\\Temp\\memorial.bmp"));
image.invert_endianness();
image.normalize(0.0, 1.0);
image.save_pfm(_T("D:\\Temp\\memorial.pfm"));
PF
512
768
1.0
?yôx?!ù=‚ì:„ç‹?
Result is the same.
This is definitely not a proper answer but might work as a workaround for the time being.
I didn't find out how to properly invert the endianness using CImgs functions, so I modified the resulting file instead. It's a hack. The result opens fine in GIMP an looks very close to the original image, but I can't say if it works with the library you are using. It may be worth a try.
Comments in the code:
#include "CImg/CImg.h"
#include <algorithm>
#include <filesystem> // >= C++17 must be selected as Language Standard
#include <ios>
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
using namespace cimg_library;
namespace fs = std::filesystem;
// a class to remove temporary files
class remove_after_use {
public:
remove_after_use(const std::string& filename) : name(filename) {}
remove_after_use(const remove_after_use&) = delete;
remove_after_use& operator=(const remove_after_use&) = delete;
const char* c_str() const { return name.c_str(); }
operator std::string const& () const { return name; }
~remove_after_use() {
try {
fs::remove(name);
}
catch (const std::exception & ex) {
std::cerr << "remove_after_use: " << ex.what() << "\n";
}
}
private:
std::string name;
};
// The function to hack the file saved by CImg
template<typename T>
bool save_pfm_endianness_inverted(const T& img, const std::string& filename) {
remove_after_use tempfile("tmp.pfm");
// get CImg's endianness inverted image and save it to a temporary file
img.get_invert_endianness().save_pfm(tempfile.c_str());
// open the final file
std::ofstream os(filename, std::ios::binary);
// read "tmp.pfm" and modify
// The Scale Factor / Endianness line
if (std::ifstream is; os && (is = std::ifstream(tempfile, std::ios::binary))) {
std::string lines[3];
// Read the 3 PFM header lines as they happen to be formatted by
// CImg. Will maybe not work with another library.
size_t co = 0;
for (; co < std::size(lines) && std::getline(is, lines[co]); ++co);
if (co == std::size(lines)) { // success
// write the first two lines back unharmed:
os << lines[0] << '\n' << lines[1] << '\n';
if (lines[2].empty()) {
std::cerr << "something is wrong with the pfm header\n";
return false;
}
// add a '-' if it's missing, remove it if it's there:
if (lines[2][0] == '-') { // remove the - to invert
os << lines[2].substr(1);
}
else { // add a - to invert
os << '-' << lines[2] << '\n';
}
// copy all the rest as-is:
std::copy(std::istreambuf_iterator<char>(is),
std::istreambuf_iterator<char>{},
std::ostreambuf_iterator<char>(os));
}
else {
std::cerr << "failed reading pfm header\n";
return false;
}
}
else {
std::cerr << "opening files failed\n";
return false;
}
return true;
}
int main()
{
CImg<float> img("memorial.bmp");
img.normalize(0.f, 1.f);
std::cout << "saved ok: " << std::boolalpha
<< save_pfm_endianness_inverted(img, "memorial.pfm") << "\n";
}
Wanting to solve the same issue in classic C++ style (as language sake), I wrote:
BOOL CMyDoc::SavePfmEndiannessInverted(CImg<float>& img, const CString sFileName)
{
CString sDrive, sDir;
_splitpath(sFileName, sDrive.GetBuffer(), sDir.GetBuffer(), NULL, NULL);
CString sTemp;
sTemp.Format(_T("%s%sTemp.tmp"), sDrive, sDir);
sDrive.ReleaseBuffer();
sDir.ReleaseBuffer();
CRemoveAfterUse TempFile(sTemp);
img.get_invert_endianness().save_pfm(TempFile.c_str());
CFile fileTemp;
if (! fileTemp.Open(sTemp, CFile::typeBinary))
return FALSE;
char c;
UINT nRead = 0;
int nCount = 0;
ULONGLONG nPosition = 0;
CString sScale;
CByteArray arrHeader, arrData;
do
{
nRead = fileTemp.Read((char*)&c, sizeof(char));
switch (nCount)
{
case 0:
case 1:
arrHeader.Add(static_cast<BYTE>(c));
break;
case 2: // retrieve the '1.0' string
sScale += c;
break;
}
if ('\n' == c) // is new line
{
nCount++;
}
if (nCount >= 3) // read the header, so go out
{
nPosition = fileTemp.GetPosition();
break;
}
}while (nRead > 0);
if (nPosition > 1)
{
arrData.SetSize(fileTemp.GetLength() - nPosition);
fileTemp.Read(arrData.GetData(), (UINT)arrData.GetSize());
}
fileTemp.Close();
CFile file;
if (! file.Open(sFileName, CFile::typeBinary | CFile::modeCreate | CFile::modeReadWrite))
return FALSE;
CByteArray arrTemp;
ConvertCStringToByteArray(sScale, arrTemp);
arrHeader.Append(arrTemp);
arrHeader.Append(arrData);
file.Write(arrHeader.GetData(), (UINT)arrHeader.GetSize());
file.Close();
return TRUE;
}
But seem to not do the job, because the image result is darker
What I have done wrong here ? The code seem to me very clear, still, is not work as expected ...
Of course, this approach is more inefficient, I know, but as I said before, just for language sake.
I think it is nothing wrong with my code :)
Here is the trial:
CImg<float> image;
image.load_bmp(_T("D:\\Temp\\memorial.bmp"));
image.normalize(0.0f, 1.0f);
image.save_pfm(_T("D:\\Temp\\memorial.pfm"));
image.get_invert_endianness().save(_T("D:\\Temp\\memorial_inverted.pfm"));
and the memorial.pfm looks like this:
and memorial_inverted.pfm looks like this:
I'm trying to read file, which contains Cyrillic characters in their path, and got ifstream.is_open() == false
This is my code:
std::string ReadFile(const std::string &path) {
std::string newLine, fileContent;
std::ifstream in(path.c_str(), std::ios::in);
if (!in.is_open()) {
return std::string("isn't opened");
}
while (in.good()) {
getline(in, newLine);
fileContent += newLine;
}
in.close();
return fileContent;
}
int main() {
std::string path = "C:\\test\\документ.txt";
std::string content = ReadFile(path);
std::cout << content << std::endl;
return 0;
}
Specified file exists
I'm trying to find solution in google, but I got nothing
Here is links, which I saw:
I don't need wstring
The same as previous
no answer here
is not about C++
has no answer too
P.S. I need to get file's content in string, not in wstring
THIS IS ENCODING SETTINGS OF MY IDE (CLION 2017.1)
You'll need an up-to-date compiler or Boost. std::filesystem::path can handle these names, but it's new in the C++17 standard. Your compiler may still have it as std::experimental::filesystem::path, or else you'd use the third-party boost::filesystem::path. The interfaces are pretty comparable as the Boost version served as the inspiration.
The definition for std::string is std::basic_string, so your Cyrillic chararecters are not stored as intended. Atleast, try to use std::wstring to store your file path and then you can read from file using std::string.
First of all, set your project settings to use UTF-8 encoding instead of windows-1251. Until standard library gets really good (not any time soon) you basically can not rely on it if you want to deal with io properly. To make input stream read from files on Windows you need to write your own custom input stream buffer that opens files using 2-byte wide chars or rely on some third-party implementations of such routines. Here is some incomplete (but sufficient for your example) implementation:
// assuming that usual Windows SDK macros such as _UNICODE, WIN32_LEAN_AND_MEAN are defined above
#include <Windows.h>
#include <string>
#include <iostream>
#include <system_error>
#include <memory>
#include <utility>
#include <cstdlib>
#include <cstdio>
static_assert(2 == sizeof(wchar_t), "wchar_t size must be 2 bytes");
using namespace ::std;
class MyStreamBuf final: public streambuf
{
#pragma region Fields
private: ::HANDLE const m_file_handle;
private: char m_buffer; // typically buffer should be much bigger
#pragma endregion
public: explicit
MyStreamBuf(wchar_t const * psz_file_path)
: m_file_handle(::CreateFileW(psz_file_path, FILE_GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))
, m_buffer{}
{
if(INVALID_HANDLE_VALUE == m_file_handle)
{
auto const error_code{::GetLastError()};
throw(system_error(static_cast< int >(error_code), system_category(), "::CreateFileW call failed"));
}
}
public:
~MyStreamBuf(void)
{
auto const closed{::CloseHandle(m_file_handle)};
if(FALSE == closed)
{
auto const error_code{::GetLastError()};
//throw(::std::system_error(static_cast< int >(error_code), system_category(), "::CloseHandle call failed"));
// throwing in destructor is kinda wrong
// but if CloseHandle returned false then our program is in inconsistent state
// and must be terminated anyway
(void) error_code; // not used
abort();
}
}
private: auto
underflow(void) -> int_type override
{
::DWORD bytes_count_to_read{1};
::DWORD read_bytes_count{};
{
auto const succeeded{::ReadFile(m_file_handle, addressof(m_buffer), bytes_count_to_read, addressof(read_bytes_count), nullptr)};
if(FALSE == succeeded)
{
auto const error_code{::GetLastError()};
setg(nullptr, nullptr, nullptr);
throw(system_error(static_cast< int >(error_code), system_category(), "::ReadFile call failed"));
}
}
if(0 == read_bytes_count)
{
setg(nullptr, nullptr, nullptr);
return(EOF);
}
setg(addressof(m_buffer), addressof(m_buffer), addressof(m_buffer) + 1);
return(m_buffer);
}
};
string
MyReadFile(wchar_t const * psz_file_path)
{
istream in(new MyStreamBuf(psz_file_path)); // note that we create normal stream
string new_line;
string file_content;
while(in.good())
{
getline(in, new_line);
file_content += new_line;
}
return(::std::move(file_content));
}
int
main(void)
{
string content = MyReadFile(L"C:\\test\\документ.txt"); // note that path is a wide string
cout << content << endl;
return 0;
}
Change your code to use wstring and save your file using Unicode encoding (non UTF8 one, use USC-2, UTF16 or something like that). MSVC has non-standard overload specifically for this reason to be able to handle non-ascii chars in filenames:
std::string ReadFile(const std::wstring &path)
{
std::string newLine, fileContent;
std::ifstream in(path.c_str(), std::ios::in);
if (!in)
return std::string("isn't opened");
while (getline(in, newLine))
fileContent += newLine;
return fileContent;
}
int main()
{
std::wstring path = L"C:\\test\\документ.txt";
std::string content = ReadFile(path);
std::cout << content << std::endl;
}
Also, note corrected ReadFile code.
Well this is a bit of an embarrasing problem, I can't seem to load any sort of file through a program I made. My program fails everytime regardless of the file i try to load, so I'm not quite sure what's going on. Specifically, the program is supposed to be loading GLSL shaders, and it hasn't been working. Here is my code:
static inline GLuint GetProgram(const char* vert,const char* frag)
{
GLuint vertex,fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
std::string vCode,fCode;
std::ifstream vss(vert);
std::ifstream fss(frag);
if(vss.is_open())
{
std::string line;
while(std::getline(vss,line))
{
vCode += line + '\n';
}
}
else
{
OutputDebugStringA("ERROR READING VERTEX SHADER\n");
}
if(fss.is_open())
{
std::string line;
while(std::getline(fss,line))
{
fCode += line + '\n';
}
}
else
{
OutputDebugStringA("ERROR READING FRAGMENT SHADER\n");
}
vss.close();
fss.close();
char const* vsp = vCode.c_str();
char const* fsp = fCode.c_str();
glShaderSource(vertex,1,&vsp,NULL);
glShaderSource(fragment,1,&fsp,NULL);
OutputDebugStringA("Vertex Source:\n");
OutputDebugStringA(vsp + '\n');
OutputDebugStringA("Fragment Source:\n");
OutputDebugStringA(fsp + '\n');
glCompileShader(vertex);
glCompileShader(fragment);
GLuint prog = glCreateProgram();
glAttachShader(prog,vertex);
glAttachShader(prog,fragment);
glLinkProgram(prog);
char errbuf[1024];
GLsizei len;
glGetProgramInfoLog(prog,sizeof(errbuf),&len,errbuf);
OutputDebugStringA(errbuf);
glUseProgram(prog);
return prog;
}
vss.is_open() and fss.is_open() return false everytime. This problem only occurs with this program too, I have another that runs the exact same function listed and it works just fine.
How I am calling it:
GLuint program = Shader::GetProgram("v.vert","f.frag");
The directory:
Finally got it! Just had to use _getcwd(), move my files to that location and append the file names of the two shaders. Here is my code now:
static inline GLuint GetProgram(const char* vert,const char* frag)
{
GLuint vertex,fragment;
vertex = glCreateShader(GL_VERTEX_SHADER);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
const char* dir = _getcwd(NULL,0);
std::string var1 = dir;
std::string vCode,fCode;
std::fstream vss;
std::fstream fss;
char* var2 = "/";
std::string vertpath = var1;
std::string fragpath = var1;
vertpath.append(var2);
fragpath.append(var2);
fragpath.append(frag);
vertpath.append(vert);
vss.open(vertpath);
fss.open(fragpath);
I run into the following problem.I load my shaders from files.The shader program ,when trying to compile, throws these errors for the vertex and fragment shaders:
Vertex info
0(12) : error C0000: syntax error, unexpected $undefined at token ""
Fragment info
0(10) : error C0000: syntax error, unexpected $undefined at token ""
When inspecting the loaded content of the files I can see all kinds of garbage text is attached at the beginnings and the ends of the shader files.Like this one:
#version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;
smooth out vec4 theColor;
void main()
{
gl_Position = position;
theColor = color;
}ýýýý««««««««þîþîþîþ
The methods loading the shaders look as follows:
void ShaderLoader::loadShaders(char * vertexShaderFile,char *fragmentShaderFile){
vs = loadFile(vertexShaderFile,vlen);
fs = loadFile(fragmentShaderFile,flen);
}
char *ShaderLoader::loadFile(char *fname,GLint &fSize){
ifstream::pos_type size;
char * memblock;
string text;
// file read based on example in cplusplus.com tutorial
ifstream file (fname, ios::in|ios::binary|ios::ate);
if (file.is_open())
{
size = file.tellg();
fSize = (GLuint) size;
memblock = new char [size];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
cout << "file " << fname << " loaded" << endl;
text.assign(memblock);
}
else
{
cout << "Unable to open file " << fname << endl;
exit(1);
}
return memblock;
}
I tried to change the encoding from UTF-8 top ANSI ,also tried to edit outside the visual studio but the problem still persists .Any help on this will be greatly appreciated.
You're using C++, so I suggest you leverage that. Instead of reading into a self allocated char array I suggest you read into a std::string:
#include <string>
#include <fstream>
std::string loadFileToString(char const * const fname)
{
std::ifstream ifile(fname);
std::string filetext;
while( ifile.good() ) {
std::string line;
std::getline(ifile, line);
filetext.append(line + "\n");
}
return filetext;
}
That automatically takes care of all memory allocation and proper delimiting -- the keyword is RAII: Resource Allocation Is Initialization. Later on you can upload the shader source with something like
void glcppShaderSource(GLuint shader, std::string const &shader_string)
{
GLchar const *shader_source = shader_string.c_str();
GLint const shader_length = shader_string.size();
glShaderSource(shader, 1, &shader_source, &shader_length);
}
void load_shader(GLuint shaderobject, char * const shadersourcefilename)
{
glcppShaderSource(shaderobject, loadFileToString(shadersourcefilename));
}
It looks like all you have to do is allocate one more byte of memory in which you can place a null ('\0'):
...
memblock = new char[1 + fSize];
file.seekg (0, ios::beg);
file.read (memblock, size);
file.close();
memblock[size] = '\0';
...
edit
I changed my code to use fSize in the array rather than size, since it is a GLint, which is just a typedef over an integer. Also, I tried this fix on my machine, and it works as far as I can tell - no junk at the beginning, and none at the end.