For future readers
Don't code tired. It turns you into a wee bit of a dink.
My problem was that I had two separate outputs that appeared to collide with one another. One was beyond a return statement, so it was alarming that the code was being executed at all. However, it had not occurred to me to use Visual Studio's search function to check every other file to see if there was another reason I was getting output. To my knowledge at that time, there was only a single call to the LoadGLSLFromFile function, when there was actually two.
The results were extreme frustration on my end because I was positive that there was no other calls to that function, and that somehow there must be optimizations to my code that's either messing up the ordering of the function, or, the return statement is not functioning as it should (for whatever reason).
If you are going to post a question, I urge you to re-evaluate what is deemed as "relevant" code. You are here because you're not seeing something that others can, after all.
If you read the comments of this, you will see that StoryTeller was trying to get it through to me that what I was assuming was happening was indeed not possible, and that my methods of debugging were incorrect. StoryTeller, if you're reading this, I do sincerely apologize.
===============================
EDIT 2: Note that the issue I am having is that the function is not returning when I told it to. It continues execution beyond the return, inside the same function, until it hits a second one.
So, I am really lost as to why this is occurring, but this is my code. So, usually what I do is I check for critical failures, and if there is a serious issue, I return a known "error" value. However, the return is being ignored in multiple places, and the code is executing in the wrong order. (see the second image for the wrong order)
EDIT:
My problem is that the code is executing beyond the return statements.
#include "Loader.h"
#include <stdio.h>
#include <stdlib.h>
#include <direct.h>
#include <string.h>
#include <GL/glew.h>
#include <GL/GL.h>
#include <GL/GLU.h>
#include <GLFW/glfw3.h>
static const GLchar * VSource[] = {
"#version 450 core\n"
"layout (location = 0) in vec4 offset;\n"
"layout (location = 1) in vec4 color;\n"
"out VS_OUT {\n"
" vec4 color;"
"} vs_out;\n"
"void main(void)\n"
"{\n"
" const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0),\n"
" vec4(-0.25, -0.25, 0.5, 1.0),\n"
" vec4(0.25, 0.25, 0.5, 1.0));\n"
" gl_Position = vertices[gl_VertexID] + offset;\n"
" vs_out.color = color;"
"}\n"
};
static const GLchar* FSource[] = {
"#version 450 core\n"
"in VS_OUT {\n"
" vec4 color;\n"
"} fs_in;\n"
"out vec4 color;\n"
"void main(void)\n"
"{\n"
" color = fs_in.color;\n"
"}\n"
};
static const GLchar* TControlSource[] = {
"#version 450 core\n"
"layout (vertices = 3) out;\n"
"void main(void) {\n"
" if(gl_InvocationID == 0) {\n"
" gl_TessLevelInner[0] = 5.0;\n"
" gl_TessLevelOuter[0] = 5.0;\n"
" gl_TessLevelOuter[1] = 5.0;\n"
" gl_TessLevelOuter[2] = 5.0;\n"
" }\n"
" gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
"}"
};
GLuint LoadAllShaders() {
LoadGLSLFromFile("glsl", GL_VERTEX_SHADER);
GLuint VShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(VShader, 1, VSource, NULL);
glCompileShader(VShader);
LogCompileStatus(VShader, "VShader");
GLuint FShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(FShader, 1, FSource, NULL);
glCompileShader(FShader);
LogCompileStatus(FShader, "FShader");
GLuint TShader = glCreateShader(GL_TESS_CONTROL_SHADER);
glShaderSource(TShader, 1, TControlSource, NULL);
glCompileShader(TShader);
LogCompileStatus(TShader, "Tessellation Shader");
GLuint Program = glCreateProgram();
glAttachShader(Program, VShader);
glAttachShader(Program, FShader);
glAttachShader(Program, TShader);
glLinkProgram(Program);
glDeleteShader(VShader);
glDeleteShader(FShader);
glDeleteShader(TShader);
return Program;
}
void LogCompileStatus(GLuint Shader, char* ShaderName) {
// Checking compile status of VShader
if (ShaderName == NULL || sizeof(ShaderName) == 0)
ShaderName = ("Unnamed Shader with ID: %i" + (char)&Shader);
GLuint ShaderSuccess = GL_FALSE;
glGetShaderiv(Shader, GL_COMPILE_STATUS, &ShaderSuccess);
if (ShaderSuccess == GL_TRUE)
printf("%s successfully compiled\n", ShaderName);
else {
GLint LogLength;
glGetShaderiv(Shader, GL_INFO_LOG_LENGTH, &LogLength);
char* buffer = (char*)malloc(LogLength);
glGetShaderInfoLog(Shader, LogLength, NULL, buffer);
printf("%s failed to compile.\n%s\n", ShaderName, buffer);
free(buffer);
}
}
GLuint LoadGLSLFromFile(char* location, GLenum ShaderType) {
if (sizeof(location) < 6 || strstr(location, ".glsl") == NULL) {
fprintf(stderr, "Attempted to load invalid file.\n");
return 0;
}
switch (ShaderType) {
case(GL_COMPUTE_SHADER):
case(GL_VERTEX_SHADER):
case(GL_TESS_CONTROL_SHADER):
case(GL_TESS_EVALUATION_SHADER):
case(GL_GEOMETRY_SHADER):
case(GL_FRAGMENT_SHADER):
break;
default:
fprintf(stderr, "Invalid Shadertype\n");
break;
}
FILE* shaderFile = fopen(location, "r");
if (shaderFile == NULL) {
fprintf(stderr, "Wurbulgurb\n");
return 0;
}
size_t bufferSize = fseek(shaderFile, 0, SEEK_END);
printf("File Buffer size: %i\n", (int)bufferSize);
fclose(shaderFile);
/*
glShaderSource(shd, 1, VSource, NULL);
glCompileShader(shd);
LogCompileStatus(shd, "VShader");
*/
return 1;
}
The main file:
#include <stdio.h>
#include <stdlib.h>
#include <GL\glew.h>
#include <GL\GL.h>
#include <GL\GLU.h>
#include <GL\wglew.h>
#include <GLFW\glfw3.h>
#include "Loader.h"
#define CL_BUFFER (GLfloat[4]) { 0.3f, 0.3f, 0.3f, 1.0f }
int main(void);
void err(int error, const char * msg);
void keypress(GLFWwindow *window, int key, int scancode, int action, int mods);
static GLfloat attrib[] = { 0.0f, 0.0f, 0.5f, 1.0f };
int main(void) {
if (!glfwInit())
return -1;
GLFWwindow *window = glfwCreateWindow(1024, 768, "Fididdler", NULL, NULL);
glfwWindowHint(GLFW_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_VERSION_MINOR, 5);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
if (window == NULL)
return -1;
LoadGLSLFromFile("./Condoms.glsl", GL_VERTEX_SHADER);
glfwSetErrorCallback(err);
glfwSetKeyCallback(window, keypress);
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK)
return -1;
printf("GL Version String: %s \n", glGetString(GL_VERSION));
GLuint RProg = LoadAllShaders();
GLuint VAO;
glCreateVertexArrays(1, &VAO);
glBindVertexArray(VAO);
printf("Loading complete");
while (!glfwWindowShouldClose(window)) {
glClearBufferfv(GL_COLOR, 0, CL_BUFFER);
glUseProgram(RProg);
glVertexAttrib4fv(0, attrib);
glDrawArrays(GL_TRIANGLES, 0, 3);
/* End drawing logic*/
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteProgram(RProg);
glfwTerminate();
return 1;
}
void err(int error, const char * msg) {
printf("Error: %s", msg);
}
void keypress(GLFWwindow *window, int key, int scancode, int action, int mods) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
switch (key) {
case(GLFW_KEY_W):
attrib[1] += 0.01f;
printf("W pressed");
break;
case(GLFW_KEY_S):
attrib[1] -= 0.01f;
printf("S pressed");
break;
}
switch (key) {
case(GLFW_KEY_A):
attrib[0] -= 0.01f;
printf("A pressed");
break;
case(GLFW_KEY_D):
attrib[0] += 0.01f;
printf("D pressed");
break;
}
}
This is the console output for LoadGLSLFromFile("TessControl.glsl", GL_VERTEX_SHADER);. Note: Line 3 should not happen, as there was a return statement prior to it.
This is the console output for LoadGLSLFromFile("glsl", GL_VERTEX_SHADER);
Note: Line 3 should not happen, as there was a return statement prior to it.
There's a return statement specifically blocking further execution, and yet it still executes. I am quite puzzled with this behavior because as far as I am aware, return means "immediately go back to the line that called you".
Any and all assistance would be greatly appreciated.
You say that the return value is being ignored. That is exactly what your code is doing:
GLuint LoadAllShaders() {
// return value is ignored
LoadGLSLFromFile("glsl", GL_VERTEX_SHADER);
GLuint VShader = glCreateShader(GL_VERTEX_SHADER);
Because you don't check the return value, there is nothing to prevent your code from continuing.
Perhaps you're confusing return with exit(). The return statement returns a value from a function so that the calling function can decide how to proceed. The exit function causes the program to terminate, with the passed in value being the return value of your program.
If you want your program to quit, you should use exit. If not, then you need to check the return value in the above code and act accordingly.
EDIT:
This is why a MCVE is so important.
After posting your main code, the issue is that you're calling LoadGLSLFromFile twice. You first call it directly from main. Then main calls LoadAllShaders, which calls LoadGLSLFromFile again.
So "Wurbulgurb" prints on the first call, while either "Attempted to load invalid file" or "File Buffer size" is printed on the second call.
Related
I followed by vulkan tutorial, and i get segfault on vkCreateInstance.
I use arch (btw), and i install vulkan by paru -S vulkan-devel (also linux-firmware and mesa are installed). My CPU is AMD Ryzen 7 2700, and GPU is Radeon RX 580 4GB.
I saw a similar question, but the answer did not solve my problem (and besides, they use C++, not C)
#include <stdio.h>
#include <stdlib.h>
#include <vulkan/vulkan.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
const char* APPLICATION_NAME = "Vulkan Teach";
const uint16_t WIDTH = 800;
const uint16_t HEIGHT = 600;
static GLFWwindow* window;
static VkInstance instance;
void error(char* message, int code) {
fprintf(stderr, "%s (status code: %d)\n", message, code);
exit(code);
}
void initWindow() {
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, APPLICATION_NAME, NULL, NULL);
}
void mainLoop() {
while(!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
}
void createInsance() {
VkApplicationInfo appInfo;
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = APPLICATION_NAME;
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
uint32_t glfwExtensionsCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionsCount);
createInfo.enabledExtensionCount = glfwExtensionsCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
createInfo.enabledLayerCount = 0;
VkResult result = vkCreateInstance(&createInfo, NULL, &instance);
if(result != VK_SUCCESS) {
error("Failed to create vulkan instance.", result);
}
}
void initVulkan() {
createInsance();
}
void cleanup() {
vkDestroyInstance(instance, NULL);
glfwDestroyWindow(window);
glfwTerminate();
}
int main() {
initWindow();
initVulkan();
mainLoop();
cleanup();
return 0;
}
You are most probably passing uninitialized values to your instance creation. This part of the code:
VkInstanceCreateInfo createInfo;
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
Only initializes the sType and pApplicationInfo members of the create info, while other important members such as pNext are uninitialized and as such may contain values that the driver doesn't know how to handle, resulting in the segfault.
So as a general rule for all (Vulkan) structs: Zero initialize like this:
VkInstanceCreateInfo createInfo = {0};
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
Context:
OpenGL C API 4.1 ("modern" opengl)
Issue:
I am encoutering an INVALID OPERATION binding uniforms the wrong way with multiple shaders :
// Getting ids for each uniform
GLuint uniform1 = glGetUniformLocation(shader1_program.id, "mvp");
GLuint uniform2 = glGetUniformLocation(shader2_program.id, "mvp");
loop {
// Print mesh 1 shader 1
glUseProgram(shader1_program.id);
glUniformMatrix4fv(uniform1 , 1, GL_FALSE, mvp1);
check_gl_error(); // =============================> this one provides the error
glBindVertexArray(vao1);
glDrawArrays(GL_TRIANGLES, 0, vertex_number1);
// Print mesh 2 with shader2
glUseProgram(shader2_program.id);
glUniformMatrix4fv(uniform2 , 1, GL_FALSE, mvp2);
check_gl_error();
glBindVertexArray(vao2);
glDrawArrays(GL_TRIANGLES, 0, vertex_number2);
}
Here is the check_gl_error() function that get error code from glGetError and print signification:
typedef struct glmaperror_s {
GLenum err;
char *string_error;
} glmaperror_t;
static const glmaperror_t glmaperror[] = {
{ GL_INVALID_OPERATION, "GL_INVALID_OPERATION", },
{ GL_INVALID_ENUM, "GL_INVALID_ENUM", },
{ GL_INVALID_VALUE, "GL_INVALID_VALUE", },
{ GL_OUT_OF_MEMORY, "GL_OUT_OF_MEMORY", },
{ GL_INVALID_FRAMEBUFFER_OPERATION, "GL_INVALID_FRAMEBUFFER_OPERATION", },
};
int check_gl_error(void)
{
GLenum err;
char *error;
error = 0;
while ((err = glGetError()) != GL_NO_ERROR) {
error = "Unhandled GL error";
for (size_t i = 0; i * sizeof(glmaperror_t) < sizeof(glmaperror); i++) {
if (glmaperror[i].err == err) {
error = glmaperror[i].string_error;
}
}
fprintf(stderr, "[GL Error]: %s\n", error);
return (-1);
}
return (0);
}
Here are the two shaders :
shader1 :
#version 410
in vec3 position;
in vec3 color;
out vec4 _color;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(position, 1.0);
_color = vec4(color, 255.0);
}
shader2
#version 410
in vec3 position;
uniform mat4 mvp;
void main() {
gl_Position = mvp * vec4(position, 1.0);
}
Actually, only mesh 2 is rendered.
I have printed shader1_program.id and shader2_program.id, they are valid and have different values which is ok.
I have printed uniform1 and uniform2, they have the same numerical value.
Is it the right order to declare and bind uniform ?
shader1_program.id is the result of the compiled shader1 code from the glCompileShader function. shader2_program.id is the result of the compiled shader2 code from the glCompileShader function.
– Alrick 12 hours ago
So that's the problem then. glUseProgram expects a program object, not a shader object.
You create program objects by a call to glCreateProgram, followed by attaching your compiled shader stages with glAttachShader, and then calling glLinkProgram afterwards. You cannot call glUseProgram on a shader directly.
All the tutorials seem to indicate that I am doing things correctly, the vertex shader works, however it fails to recognize any input changes from the main program through the use of the glUniform1f function. I check glGetError after each line, there are no errors. I check glGetShaderiv and glGetShaderInfoLog, there are no issues. I am testing with OpenGL version 2.1 (unknown profile, but assuming the core profile) as reported by SDL.
#if defined(__WINDOWS__) || defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__)\
|| defined(__CYGWIN__)
/* Compiling for Windows */
#ifndef __WINDOWS__
#define __WINDOWS__
#endif
#include <windows.h>
#endif/* Predefined Windows macros */
#include <SDL2/SDL.h>
#include <GL/GL.h>
#include <stdlib.h>
#include <stdio.h>
#include <error.h>
//return type not verified
void glGenBuffers();
void glBindBuffer();
void glBufferData();
unsigned int glCreateShader();
void glShaderSource();
void glCompileShader();
void glGetShaderiv();
void glGetShaderInfoLog();
unsigned int glCreateProgram();
void glAttachShader();
void glLinkProgram();
void glGetProgramiv();
void glGetProgramInfoLog();
void glVertexAttribPointer();
void glEnableVertexAttribArray();
void glUseProgram();
void glDeleteShader();
void glGenVertexArrays();
void glBindVertexArray();
GLint glGetUniformLocation();
void glUniform1f();
void glDeleteProgram();
void glDeleteBuffers();
int fixSDLconsole() {
FILE *console = freopen("stdout.txt", "a",stdout);
if (console == NULL) {return errno;}
console = freopen("stdout.txt", "a",stderr);
if (console == NULL) {return errno;}
return 0;
}
void printGLVersionNumber() {
int majorVersion;
int minorVersion;
int profile;
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &majorVersion);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &minorVersion);
SDL_GL_GetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, &profile);
fprintf(stderr,"GL version %d.%d ",majorVersion,minorVersion);
switch (profile) {
case SDL_GL_CONTEXT_PROFILE_CORE: fprintf(stderr,"core (%d)\n",profile);break;
case SDL_GL_CONTEXT_PROFILE_COMPATIBILITY: fprintf(stderr,"compatibility (%d)\n",profile);break;
case SDL_GL_CONTEXT_PROFILE_ES: fprintf(stderr,"E.S. (%d)\n",profile);break;
default: fprintf(stderr, "unknown profile: %d\n",profile);break;
}
return;
}
#define checkGlError(label) {int error = glGetError();if (error != GL_NO_ERROR) {error_at_line(0,0,__FILE__,__LINE__,"error=%d", error);goto label;}}
int main(int argc, char **argv) {
SDL_Window *window = NULL;
SDL_GLContext context = NULL;
GLuint verticesGlIds[] = {0,0};
GLuint vertexShaderGlId = 0;
GLuint shaderProgramGlId = 0;
if (fixSDLconsole()) {
return errno;
}
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
error_at_line(1,0,__FILE__,__LINE__,"Unable to initialize SDL: %s",SDL_GetError());
goto error;
}
printGLVersionNumber();
window = SDL_CreateWindow("Window Title",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,640,640,SDL_WINDOW_OPENGL);
if (window == NULL) {
error_at_line(0,0,__FILE__,__LINE__,"Could not create window: %s", SDL_GetError());
goto error;
}
context = SDL_GL_CreateContext(window);
if (context == NULL) {
error_at_line(0,0,__FILE__,__LINE__,"Could not create OpenGL context: %s", SDL_GetError());
goto error;
}
glViewport(0,0,640,640);checkGlError(error);
glClearColor(.9f,.9f,.9f,1.f);checkGlError(error);
glEnableClientState(GL_VERTEX_ARRAY);checkGlError(error);
glEnableClientState(GL_COLOR_ARRAY);checkGlError(error);
float vertices[] = {
-.5f,0.f,0.f,
0.f,.5f,0.f,
0.f,-.5f,0.f,
0.f,.5f,0.f,
.5f,.5f,0.f,
0.f,0.f,0.f
};
float colors[] = {
1.f,0.f,0.f,//red
.5f,0.f,0.f,//red
0.f,1.f,0.f,//green
0.f,.5f,0.f,//green
0.f,0.f,1.f,//blue
0.f,0.f,.5f//blue
};
glGenBuffers(2, &verticesGlIds);checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[0]);checkGlError(error);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[1]);checkGlError(error);
glBufferData(GL_ARRAY_BUFFER,sizeof(colors),colors, GL_STATIC_DRAW);checkGlError(error);
char *vertexShader =
"#version 120\n"\
"attribute vec3 aPos;\n"\
"uniform float i;\n"\
"void main() {\n"\
"gl_FrontColor=gl_Color;\n"\
"gl_Position = vec4(aPos.x+i/2,aPos.y,aPos.z,1.0);\n"\
"}\n";
vertexShaderGlId = glCreateShader(GL_VERTEX_SHADER);checkGlError(error);
if (vertexShaderGlId == 0) {error_at_line(0,0,__FILE__,__LINE__,"vertex shader could not be created");goto error;}
glShaderSource(vertexShaderGlId, 1, &vertexShader, NULL);checkGlError(error);
glCompileShader(vertexShaderGlId);checkGlError(error);
{
GLint success;
glGetShaderiv(vertexShaderGlId, GL_COMPILE_STATUS, &success);checkGlError(error);
if (success == GL_FALSE) {
char infoLog[512];
glGetShaderInfoLog(vertexShaderGlId, 512, NULL, infoLog);checkGlError(error);
error_at_line(0,0,__FILE__,__LINE__,"Vertex Shader problem: %s", infoLog);
goto error;
}
}
shaderProgramGlId = glCreateProgram();checkGlError(error);
if (shaderProgramGlId == 0) {error_at_line(0,0,__FILE__,__LINE__,"shader program could not be created");goto error;}
glAttachShader(shaderProgramGlId, vertexShaderGlId);checkGlError(error);
glLinkProgram(shaderProgramGlId);checkGlError(error);
{
int success;
glGetProgramiv(shaderProgramGlId, GL_LINK_STATUS, &success);checkGlError(error);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(shaderProgramGlId, 512, NULL, infoLog);checkGlError(error);
error_at_line(0,0,__FILE__,__LINE__,"Shader program problem: %s", infoLog);
}
}
glDeleteShader(vertexShaderGlId);checkGlError(error);
GLint iLocation = glGetUniformLocation(shaderProgramGlId, "i");checkGlError(error);
if (iLocation == -1) {error_at_line(0,0,__FILE__,__LINE__,"uniform i not found in shader");goto error;}
error_at_line(0,0,__FILE__,__LINE__,"iLocation: %d", iLocation);
for (int frame = 0; frame < 100; ++frame) {
glClear(GL_COLOR_BUFFER_BIT);checkGlError(error);
glUseProgram(shaderProgramGlId);checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[0]); checkGlError(error);
glVertexPointer(3,GL_FLOAT,0,0); checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, verticesGlIds[1]); checkGlError(error);
glColorPointer(3,GL_FLOAT,0,0); checkGlError(error);
glUniform1f(iLocation, (float) (frame%2)); checkGlError(error);
glDrawArrays(GL_TRIANGLES, 0,sizeof(vertices)/sizeof(float)/3); checkGlError(error);
glBindBuffer(GL_ARRAY_BUFFER, 0); checkGlError(error);
SDL_GL_SwapWindow(window);
SDL_Delay(100);
}
glDeleteProgram(shaderProgramGlId);
glDeleteShader(vertexShaderGlId);
glDeleteBuffers(sizeof(verticesGlIds)/sizeof(GLuint), verticesGlIds);
SDL_GL_DeleteContext(context);
SDL_Delay(3000);
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
error:
glDeleteProgram(shaderProgramGlId);
glDeleteShader(vertexShaderGlId);
glDeleteBuffers(sizeof(verticesGlIds)/sizeof(GLuint), verticesGlIds);
if (context != NULL) SDL_GL_DeleteContext(context);
if (window != NULL) SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_FAILURE;
}
#if defined(__WINDOWS__)
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
char *argv[1] = {(char *) 0};
return main(0, argv);
}
#endif
note that I am not familiar with OpenGL's extension function loading issues and routines such as SDL's SDL_GL_LoadLibrary and SDL_GL_GetProcAddress I just manually define the method signatures at the top of the file and import GL through the linker. I don't expect this to be an issue but it is the only issue, I am aware of, that I haven't looked into, that may be causing my problems.
So you declare the function like this:
void glUniform1f();
By omitting any parameters, the compiler will assume that all arguments are of type int. For most other GL functions, this works by chance, because those arguments are just integer types in most cases anyway, but for glUniform1f, it will mean that the function argument is converted to integer, but the resulting bit-pattern is implicitely re-interpreted as GLfloat by the function since the actual prototype for glUniform1f is something like this
void glUniform1f(int location, GLfloat value);
note that I am not familiar with OpenGL's extension function loading issues and routines such as SDL's SDL_GL_LoadLibrary and SDL_GL_GetProcAddress I just manually define the method signatures at the top of the file and import GL through the linker.
You shouldn't do this. The GL functions you try to access might not even be exported by the library at all. If you do not want to manually deal with loading every function pointer, you can use one of the existing OpenGL loaders.
gl_Position expects Clip-space coordinates, which are a hiper-cube of size [2w,2w,2w,w].
For vec4(x, y, z, w) if any of the [x,y,z] is outside of [-w,w] range, then the vertex is clipped.
The coordinates will be automatically converted by the GPU to NDC-space x/w, y/w, z/w, 1 (aka "perspective division") before the fragment shader.
Your GLSL code gl_Position = vec4(aPos.x+i/2,aPos.y,aPos.z,1.0); uses the uniform i.
You update it by glUniform1f(iLocation, (float) (frame%2));
First issue is frame%2. Only 0 or 1 is passed to the GPU. With your current vertices data, only two pairs of triangles should be drawn.
Second issue is that frame is a value 0 <= frame < 100. So, if you pass frame instead of frame%2, then for most values aPos.x + i/2 will fall outside the Clip space and you will see only the first two triangle-pairs, or parts of them.
Say I have an ASCII encoded text file mytextfile.txt and I want to print it.
I have found various sources on MSDN, but none of it seems useful:
From here:
Defines a reusable object that sends output to a printer, when printing from a Windows Forms application.
public ref class PrintDocument : Component
However this is meant for C++ (not C)
I also found this, which defines several functions, none of which actually seem to have the ability to print:
IPrintDocumentPackageStatusEvent: Represents the progress of the print job.
IPrintDocumentPackageTarget: Allows users to enumerate the supported package target types and to create one with a given type ID. IPrintDocumentPackageTarget also supports the tracking of the package printing progress and cancelling.
IPrintDocumentPackageTargetFactory: Used with IPrintDocumentPackageTarget for starting a print job.
Ah! That looks like it! Well it turns out that this is also for C++:
IPrintDocumentPackageTargetFactory::CreateDocumentPackageTargetForPrintJob
I think it is impracticle (and difficult) to try and imitate classes in C.
I could use the print command:
system("print mytextfile.txt");
But this does seem to be a bit of a hack, is there a better way to print a file using functions?
To clarify: I want this printing on paper not in terminal.
Here is some sample printing code for you that should do the job properly. It is a minimal, self-contained example that you should be able to just compile and run. Based on that, you should then be able to adapt it to your specific needs. First, here's the code, and then some explanatory notes.
Please note that I have written this as a Console app, but that's probably not what you actually want. Also, the function that does all the work (print_file()) is now callable from C as requested. OK, here's the code:
#include <windows.h>
#include <conio.h>
#include <string>
#include <fstream>
#include <iostream>
#define SCALE_FACTOR 100 // percent
inline static int MM_TO_PIXELS (int mm, int dpi)
{
return MulDiv (mm * 100, dpi, 2540);
}
// Calculate the wrapped height of a string
static int calculate_wrapped_string_height (HDC hDC, int width, const std::string& s)
{
RECT r = { 0, 0, width, 16384 };
DrawText (hDC, s.c_str (), (int) s.length (), &r, DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK);
return (r.bottom == 16384) ? calculate_wrapped_string_height (hDC, width, " ") : r.bottom;
}
// Print a string in the width provided.
static void print_string (HDC hDC, int x, int y, int width, const std::string& s)
{
RECT r = { x, y, x + width, 16384 };
DrawText (hDC, s.c_str (), (int) s.length (), &r, DT_NOPREFIX | DT_WORDBREAK);
}
// Print page number. Returns (y + vertical space consumed)
static int print_pagenum (HDC hDC, int x, int y, int width, int& pagenum)
{
std::string hdr = "Page: " + std::to_string (++pagenum) + "\n";
int space_needed = calculate_wrapped_string_height (hDC, width, hdr);
print_string (hDC, x, y, width, hdr);
std::cout << "Printing page: " << pagenum << "\n";
return space_needed;
}
extern "C" bool print_file (const char *filename)
{
std::ifstream f;
f.open ("g:\\temp\\print_me.txt", std::ios_base::in);
if (!f)
{
std::cout << "Cannot open input file, error " << GetLastError () << "\n";
return false;
}
// Display print dialog
PRINTDLGEX pdex = { sizeof (pdex) };
PRINTPAGERANGE pr [10] = { };
HDC hDC;
pdex.hwndOwner = GetDesktopWindow ();
pdex.Flags = PD_ALLPAGES | PD_RETURNDC | PD_NOCURRENTPAGE | PD_NOSELECTION;
pdex.nMaxPageRanges = _countof (pr);
pdex.nPageRanges = 1;
pr [0].nFromPage = pr [0].nToPage = 1;
pdex.lpPageRanges = pr;
pdex.nMinPage = 1;
pdex.nMaxPage = 999999;
pdex.nCopies = 1;
pdex.nStartPage = START_PAGE_GENERAL;
HRESULT hr = PrintDlgEx (&pdex);
if (hr != S_OK)
{
std::cout << "PrintDlgEx failed, error " << GetLastError () << "\n";
return false;
}
if (pdex.dwResultAction == PD_RESULT_CANCEL)
return false;
hDC = pdex.hDC;
if (pdex.dwResultAction != PD_RESULT_PRINT)
{
DeleteDC (hDC);
return false;
}
// Only print what we need to
int max_page = 0x7fffffff;
if (pdex.Flags & PD_PAGENUMS)
{
max_page = 0;
for (int i = 0; i < (int) pdex.nPageRanges; ++i)
{
if ((int) pdex.lpPageRanges [i].nToPage > max_page)
max_page = pdex.lpPageRanges [i].nToPage;
}
}
constexpr int dpi = 96 * 100 / SCALE_FACTOR;
int lpx = GetDeviceCaps (hDC, LOGPIXELSX);
int lpy = GetDeviceCaps (hDC, LOGPIXELSX);
int res_x = GetDeviceCaps (hDC, HORZRES);
int res_y = GetDeviceCaps (hDC, VERTRES);
// margins
int left_margin = MM_TO_PIXELS (10, dpi);
int top_margin = MM_TO_PIXELS (20, dpi);
int right_margin = MM_TO_PIXELS (20, dpi);
int bottom_margin = MM_TO_PIXELS (20, dpi);
int width = MulDiv (res_x, dpi, lpx) - (left_margin + right_margin);
int y_max = MulDiv (res_y, dpi, lpy) - bottom_margin;
// Set up for SCALE_FACTOR
SetMapMode (hDC, MM_ANISOTROPIC);
SetWindowExtEx (hDC, dpi, dpi, NULL);
SetViewportExtEx (hDC, lpx, lpy, NULL);
SetStretchBltMode (hDC, HALFTONE);
DOCINFO di = { 0 };
di.cbSize = sizeof (di);
di.lpszDocName = "Stack Overflow";
int job_id = StartDoc (hDC, &di);
if (job_id <= 0)
{
std::cout << "StartDoc failed, error " << GetLastError () << "\n";
DeleteDC (hDC);
return false;
}
SetBkMode (hDC, TRANSPARENT);
LOGFONT lf = { 0 };
lf.lfWeight = FW_NORMAL;
lf.lfHeight = -12;
HFONT hTextFont = CreateFontIndirect (&lf);
HFONT hOldFont = (HFONT) GetCurrentObject (hDC, OBJ_FONT);
SelectObject (hDC, hTextFont);
int x = left_margin;
int y = top_margin;
int pagenum = 0;
int err = StartPage (hDC);
if (err <= 0)
{
std::cout << "StartPage failed, error " << GetLastError () << "\n";
DeleteDC (hDC);
return false;
}
y += print_pagenum (hDC, x, y, width, pagenum);
// Printing loop, per line
for ( ; ; )
{
if (_kbhit ())
{
AbortDoc (hDC);
break;
}
std::string line;
std::getline (f, line);
if (!f)
break;
int space_needed = calculate_wrapped_string_height (hDC, width, line);
if (space_needed > y_max - y)
{
if (pagenum >= max_page)
break;
if (EndPage (hDC) < 0 || StartPage (hDC) < 0)
break;
y = top_margin;
y += print_pagenum (hDC, x, y, width, pagenum);
}
print_string (hDC, x, y, width, line);
y += space_needed;
}
EndPage (hDC);
EndDoc (hDC);
SelectObject (hDC, hOldFont);
DeleteObject (hTextFont);
DeleteDC (hDC);
return true;
}
// main
int main ()
{
bool ok = print_file ("g:\\temp\\print_me.txt");
return !ok;
}
Notes:
The code shows how to paginate the output properly. I included page numbers in he printed output, just for fun.
Input filename is hard-coded. Please adapt this to your needs.
As I say, this is written as a Console app. If you were including this in a Windows app you would use a different parent window handle and a different mechanism (a modeless dialog, typically) to report progress and to allow the user to cancel the print job.
The code as written expects to be compiled as ANSI (purely for convenience). I'm sure you can fix that.
This code doesn't handle page ranges entered by the user in the Windows standard Print dialog properly. I leave that as an exercise for the reader.
To make this code callable from C, compile it as a separate .cpp file (excluding main of course) and then prototype print_file (in a
separate .h file) as:
extern "C" bool print_file (const char *filename);
Then #include this file in both your .cpp file and your .c file (s).
Please note that bool is a predefined type - sort of - in C99 and later, see:
https://stackoverflow.com/a/1608350/5743288
You could read a line, print a line, in a loop, until EOF
Following EDITED to output to printer
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUF_SIZE 1024
int main( void )
{
char buffer[ MAX_BUF_SIZE ];
FILE *fin = fopen( "mytextfile.txt", "f" );
if( ! fin )
{
perror( "fopen failed for reading file" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
FILE *printer = fopen("LPT1", "w");
if( !printer )
{
perror( "fopen failed for printing" );
exit( EXIT_FAILURE );
}
// implied else, fopen successful
while( fgets( buffer, sizeof buffer, fin ) )
{
fprintf( printer, "%s", buffer );
}
fprintf( printer, "%s", "\n" );
fclose( fin );
fclose( printer );
return 0;
}
So I tryed to make something on SDL, but on first programm I have memory lear (idk leak or not) so there is some code:
#include <stdio.h>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#define SCREENSIZEX 180
#define SCREENSIZEY 300
SDL_Window* mainwind = NULL;
SDL_Renderer* rend = NULL;
TTF_Font* Usefont = NULL;
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
Uint32 windowflags;
windowflags = SDL_WINDOW_SHOWN;
mainwind = SDL_CreateWindow("FooBar",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
SCREENSIZEX,
SCREENSIZEY,
windowflags);
rend = SDL_CreateRenderer(mainwind, -1, SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor(rend, 255, 255, 255, 255);
int imgFlags = IMG_INIT_PNG;
IMG_Init(imgFlags);
TTF_Init();
Usefont = TTF_OpenFont("DOTMBold.TTF",90);
SDL_Surface* TextSurf = NULL;
SDL_Texture* TextTexture = NULL;
SDL_Color UsingColor;
UsingColor.r=0;
UsingColor.g=255;
UsingColor.b=255;
UsingColor.a=100;
bool exit = false;
char Text[500];
int counter = 0;
SDL_Event evneet;
while(!exit)
{
SDL_PollEvent(&evneet);
SDL_RenderClear(rend);
counter++;
TextSurf = TTF_RenderUTF8_Blended(Usefont, Text, UsingColor);
TextTexture = SDL_CreateTextureFromSurface(rend, TextSurf);
SDL_FreeSurface(TextSurf);
TextSurf = NULL;
SDL_RenderCopy(rend, TextTexture, NULL, NULL);
TextTexture = NULL;
SDL_DestroyTexture(TextTexture);
SDL_RenderPresent(rend);
}
SDL_FreeSurface(TextSurf);
TextSurf = NULL;
SDL_DestroyTexture(TextTexture);
SDL_DestroyRenderer(rend);
SDL_DestroyWindow(mainwind);
SDL_Quit();
return 0;
}
Problem:
some screenshots
Idk how to fix this and tryed to do a lot of freeing and memory manipulations.
This programm do only one task. Just counting frames (in code only 0 displayed)
Its 3rd my try to make rendering and always i got the same.
Please help!
This looks suspicious:
while(!exit)
{
...
TextTexture = SDL_CreateTextureFromSurface(rend, TextSurf);
...
TextTexture = NULL; // A
SDL_DestroyTexture(TextTexture); // B
...
}
SDL_DestroyTexture() doesn't get a valid handle here, but a NULL-Pointer is passed. You have to swap the lines A and B, so the Texture can be freed properly.
The answer was strange. Thanks Ctx thats first part of this big mess with rerenderring surfaces and textuers. As for me big mistake was NULLing texture when i need to pass "nullptr".
SDL_FreeSurface(AlreadyDrawedAndUsedOnSurface);
AlreadyDrawedAndUsedOnSurface = NULL; //BAD!
AlreadyDrawedAndUsedOnSurface = nullptr; //good)
Very strange for me but it works!