• Forum
  • Lounge
  • Conversion From OpenGL 1.x to Modern-ish

 
Conversion From OpenGL 1.x to Modern-ish OpenGL

Pages: 12
Okay, now it's time for my game engine to completely switch from the FF pipeline to shaders. I finished a shader and program wrapper (oh how I wish I just used SFML), and now all that's left is writing shader code.

This is one of the largest tasks I've faced, and I don't know where to start. The fog system? Textures? 3D Models?
Last edited on
Obligatory link to arcsythesis tutorial:

http://www.arcsynthesis.org/gltut/
Duh, I forgot about that one... thanks for reminding me for the 7 billionth time, I have really bad memory sometimes.

Thanks for having the patience with me as well :P
Sorry for double post, but I have a question. How should I store linked programs? In my resource manager along with my shaders?
Last edited on
You meant the linked shader programs?

Nowhere. You should compile and link them every time your program is run. They are dependent on the hardware you're running on, so a program built on one machine might not work on another.
No, I mean like in system ram. I compile each shader, but I'm not sure if linking is an expensive process. I don't want my program to be inefficient and creating a new program for every in-game object.
closed account (o1vk4iN6)
So you are thinking of creating duplicate shader programs for every in-game object ? Yah don't do that.
What xerzi said.

Shaders, like textures, are resources and should be shared by multiple objects. You do not want to load the same shader into memory for multiple different objects for the same reason you don't want to have each object having it's own copy of the texture.
No I meant I DON'T want to do that. I use my resource manager to manage shaders, but where would I manage programs? In a separate program manager? Or in the resource manager?
Once you load the program into OpenGL, you get an ID number. At that point, you can unload any other data you have related to the shader (including the compiled GL shaders used to link the program -- once the actual program is linked you don't need them any more).

Before you render any polygons, you call glUseProgram. You give that function the ID number mentioned above. That indicates which shaders are to be used when drawing that function.


So to have multiple objects share the same shader... all you need to do is give them that ID number.
I know how to use programs (Though I didn't know I could free the shaders after linking the program). I'm wondering how I can MANAGE the program. (Let my engine figure whether to unload the program or not) I have a class that wraps OpenGL lightly. Shaders themselves aren't the problem, but the program is. Should I give programs a name? That'd make it so much easier to manage.

(Never used SFML shaders, I was trying to do something similar to how they were done in examples)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
class CF::Video::Shader
{
	public:
		Shader(const std::string location, ShaderType t)
		{
			type = t;
			GLenum stype = 0;

			std::ifstream file;
			std::string source;
			const char* charSource = nullptr;
			int status = 0;

			// Convert engine enum to OpenGL enum.
			if(t == VERT_SHADER)
				stype = GL_VERTEX_SHADER;
			else
				stype = GL_FRAGMENT_SHADER;

			file.open(location);

			if(file)
			{
				std::string buffer;

				// Loop through the file
				while(std::getline(file, buffer))
				{
					source.append(buffer + "\n");
				}

				charSource = source.c_str();

				id = glCreateShader(stype);

				glShaderSource(id, 1, &charSource, nullptr);

				glCompileShader(id);

				// Get compile status.
				glGetShaderiv(id, GL_COMPILE_STATUS, &status);

				if(status == GL_FALSE)
				{
					int logSize = 0;
					glGetShaderiv(id, GL_INFO_LOG_LENGTH, &logSize);

					char* log = nullptr;
					
					log = new char[logSize];

					glGetShaderInfoLog(id, logSize, &logSize, log);
					
					std::string str;
					
					str  = "CF::Video::Shader::Shader() - Error with compiling ";
					str += location;
					str += ": \n\n";
					str += log;

					glDeleteShader(id); // Free the shader
					delete log;         // Free the log data

					throw Error(str);
				}
			}

			else
			{
				std::stringstream ss;

				ss << "CF::Video::Shader::Shader() - Failure opening shader" << location << ".";

				throw Error(ss.str());
			}
		}

		unsigned int getID() const{return id;}
		ShaderType getType() const{return type;}

	private:
		ShaderType type;
		unsigned int id;
};

class CF::Video::ShaderProgram
{
	public:
		ShaderProgram()
		{
			id = glCreateProgram();
		}

		void AttachShader(std::shared_ptr<Resource<Shader>> &shader)
		{
			shaders.push_back(shader);

			glAttachShader(id, shader->getResource()->getID());
		}

		void Link()
		{
			glLinkProgram(id);
		}

		void Use()
		{
			glUseProgram(id);
		}

		void StopUse()
		{
			glUseProgram(0);
		}

		int GetCoreAttrib(const std::string name) const
		{
			return glGetAttribLocation(id, name.c_str());
		}

		~ShaderProgram()
		{
			for(unsigned int i = 0; i < shaders.size(); i++)
			{
				glDetachShader(id, shaders[i]->getResource()->getID());
			}

			glDeleteProgram(id);
		}

	private:
		std::vector<std::shared_ptr<Resource<Shader>>> shaders;

		unsigned int id;
};


I can run shaders and everything just fine, I just want to know a good way to design things.
Last edited on
I know how to use programs (Though I didn't know I could free the shaders after linking the program). I'm wondering how I can MANAGE the program. (Let my engine figure whether to unload the program or not)


You're already doing this for textures, right?

Just do the same thing for shaders/programs.

For my resource managers I typically just use a map<string,resource> where the string is the filename. You could do the same thing here, although a more abstract name instead of a filename might be more suitable (since a program might be multiple files).

I think what I did recently was actually have a short text file that had a list of all the shaders used in a program. So then the map key here would actually be the filename.

(Never used SFML shaders, I was trying to do something similar to how they were done in examples)


Neither have I. SFML seems like it would get in the way if you are going to be doing this directly. I pretty much use it to set up the window(s), get input and do audio. And maybe for text output.
Oh, okay, thanks again. I just didn't want to end up doing something I'll have to reprogram later.

For my resource managers I typically just use a map<string,resource> where the string is the filename. You could do the same thing here, although a more abstract name instead of a filename might be more suitable (since a program might be multiple files).
I do the same, but I use a vector. I guess I emulate maps in my manager though. Too lazy to change that atm.

I think what I did recently was actually have a short text file that had a list of all the shaders used in a program. So then the map key here would actually be the filename.
I see. But shaders take up memory, and it seems bad to load them all up at once.

Neither have I. SFML seems like it would get in the way if you are going to be doing this directly. I pretty much use it to set up the window(s), get input and do audio. And maybe for text output.
Not to derail my own thread, but does SFML have 3D Audio support?
Last edited on
I do the same, but I use a vector. I guess I emulate maps in my manager though. Too lazy to change that atm.


Whatever works. I find maps easier because it eliminates the need for a separate key (index). You have to have a filename to load the file.. so you might as well have that double as the key. Having to keep an integral ID along with the string filename just seems like it'd be more work.

I see. But shaders take up memory, and it seems bad to load them all up at once.


So do textures. =P

Like textures, you could load them on demand.

Not to derail my own thread, but does SFML have 3D Audio support?


Yes.
Yea I use the file names as a key as well. I just have a buttload of functions that act like maps.
closed account (3qX21hU5)
I see. But shaders take up memory, and it seems bad to load them all up at once.



Personally I would suggest against loading them on demand and instead load all the textures, shaders, fonts, sound clips, ect. that you will need for the certain "level" at the beginning of that "level". Yes this might give you a bit longer of a loading pause then loading one at a time whenever you need it but in my opinion it is a much better way to do it.

The reason why is that loading heavyweight resources like textures or shaders is a extremely expensive operation and will take time. And you really can't progress until it has finished (Or I should say you should not progress). So if you load them up individually whenever you need them you will be causing numerous "freezes" in your game while the resources load.

So instead of a bit longer load screen at the beginning of a "level" when the player expects it, they will instead experience numerous shorter freezes of game play while they are playing which in my opinion would be very annoying.

So in my opinion never load up heavyweight resources on demand if you don't have to, instead load them all (Meaning the ones you will need for that level) up at once usually at the beginning of each "level".

There is exceptions to this such as when you just have to many resources to load them all up at once in the start of the level but really you won't have to worry about that for the scale of indie games usually.
Last edited on
That's why I'm looking into threads, I'll give one to the resource manager for loading resources and the rest go to a thread pool.
closed account (3qX21hU5)
Threads won't help you load on demand you will still be stuck having to wait for the resource to load in order to continue with the game as normal. You can't use a resource that is loading so either way (Using threading or not) you will have to wait for it to load before it can be used.

So you will still experience "freezing" or gameplay artifacts in your game while your resources load on demand which is why I would recommend preloading your resources at the start of your levels or at set loading screens. It is much easier to manage and won't cause you as much headaches.

I should point out that if you are just creating a small sized game with minimal resources you should be able to implement loading your resources on demand without any consequences. Though most of the time it is better to preload your resources instead.



Also if you want to try using threads you could use a thread pool while preloading your resources to decrease the load times.

Most likely it won't make to much of a difference in small games but it would help gain experience with threading in general. You would just need one thread to handling the loading screen then you can dedicate the rest of them to loading the resources in the background. Again this is probably overkill but it can help gain experience.
Last edited on
Oh, I thought you meant load EVERYTHING at the beginning of the program. I'm not really making a game atm, I'm making an engine, which once finished I will proceed to make a game with.
OpenGL is a giant state machine. I would not advise changing its state simultaneously in multiple threads.

Since most of the work involved with loading a shader requires compiling/linking in OpenGL, this effectively means you can't do it while you're drawing a scene. So putting the loading for this in another thread is probably not very benefitial.


On the other hand... decompressing a texture into a memory buffer in one thread... then loading it into OpenGL in your main thread once it's decompressed and ready could be benefitial. And in fact... doing as much loading as you can that does not require OpenGL interaction can be done in a separate thread (like level data).

EDIT:

and yeah.. this would be a job for a thread pool. And I pretty much agree with everything else Zereo is saying.
Last edited on
Pages: 12