Advertisement

Again Inclusion question

Started by October 08, 2017 04:51 PM
29 comments, last by MarcusAseth 7 years, 5 months ago
2 minutes ago, matt77hias said:

Fair point, but what if you want to change the directory of your assets? How many changes does that inccur at the moment?

Exactly 1.  Hold ALT pressed inside of visual studio, do a rectangle box selection, write the new directory name. And this is why I have them all lined up inside a single file. The way you guy suggest, request go inside of each and every file 1 by 1 and fix it.

8 minutes ago, MarcusAseth said:

Exactly 1.  Hold ALT pressed inside of visual studio, do a rectangle box selection, write the new directory name. And this is why I have them all lined up inside a single file. The way you guy suggest, request go inside of each and every file 1 by 1 and fix it.

Ok but in Software Engineering a change is a change independent of some solution (.sln) wide global search-and-replace (which does multiple changes for you). The latter is some handy utility to help you do it efficiently, but it is no remedy for the disease (referring to implicit dependencies).

🧙

Advertisement
15 hours ago, matt77hias said:

inline const std::string my_string = "MyString";

Thought of using this today, but VSC++ compiler team is lagging behind :(

🧙

Why are you loading textures manually in one place, but also passing the path in a different (seemingly unrelated) place? Your original post says it's to be able to request the texture again, but why would you ever want that?

I would have expected the tile to only hold a pointer to its texture. Upon creation, load the texture (if need be, have some caching system or similar to prevent multiple loads of the same texture) and store a pointer to the texture in each tile/object.

Hello to all my stalkers.

I wouldnt trust C++11/14/17 support anyways but thats another topic.

To quote Hodgman, game IO should be a lot more limited than generic IO and so your game should anyways NOT use full paths to read Assets from disk. What I do in my framework is to set a fixed working directory and address my assets relative to that using "./" if necessary  (to address packages)

I do not fully understand objections because however you change paths/files, you do it in one single file used in many other files anyways so changing a string constant or function return should be regardless. However, global string constants have disadvantages as mentioned in any above post due to initialization order and local unit copies where inline header functions are optimized away mostly and directly accessed without code impact. Another option is for sure using macro constants so you wont have any access overhead.

It is ok for small projects and debugging code to go for direct file access but in medium or larger ones there should at least be some kind of package for disk aligning and IO performance reasons

46 minutes ago, Lactose said:

Why are you loading textures manually in one place, but also passing the path in a different (seemingly unrelated) place? Your original post says it's to be able to request the texture again, but why would you ever want that?

I would have expected the tile to only hold a pointer to its texture. Upon creation, load the texture (if need be, have some caching system or similar to prevent multiple loads of the same texture) and store a pointer to the texture in each tile/object.

Because that imply Tile is responsible for freeying up memory, and if that is my pattern, then I have to remember to destroy my textures in every Entity type destructor I create in my game, therefore is the same as using new and deletes because I am bound to forget to destroy a texture, sooner or later.

My setup is that App loads a texture upon request into a map<string,SDL_Texture*> in case the texture wasn't already loaded, so each class constructor actually prompt a texture load the first time a type of class is called if the texture wasn't already loaded (and I can also manually prompt a series of texture load at the beggining of a level if I know I will need them), but App destructor is responsible to free all in a single for range loop.


SDL_Texture* App::GetTexture(std::string texturePath)
{
	auto Texture = Textures.find(texturePath);
	if (Texture != Textures.end()) {
		return Texture->second;
	}
	else
	{
		LoadTexture(texturePath);
		return Textures[texturePath];
	}
}

App::~App()
{
	for (auto& T : Textures) {
		SDL_DestroyTexture(T.second);
	}
	if (Window) {
		SDL_DestroyWindow(Window);
	}
	if (Renderer) {
		SDL_DestroyRenderer(Renderer);
	}
}

Clean, compact and not error prone, imo :)

Edit: my bad, seems I am already doing what you're saying @Lactose and I had misunderstood

But still, maybe I want to load a bunch of texture upfront, so I might need to have those paths somewhere else too.

Advertisement
26 minutes ago, MarcusAseth said:

But still, maybe I want to load a bunch of texture upfront, so I might need to have those paths somewhere else too

How do you refer to your level/scene construction set? Normally you will have a file somewhere on disk that describes how your scene is assembled, what objects are instantiated, what materials do they load and so on

9 hours ago, MarcusAseth said:

So from what I am understanding, in practice would look something like this, and it will live in the Global.h:

Declare the function there; don't define it there. Define it in Global.cpp or some other appropriate translation unit.

9 hours ago, MarcusAseth said:

But the problem is, when is that static initialized?! If it is when I run the program, then App wouldn't be initialized yet... is that the case? If so, then I still don't get it how to do it...

The static will be initialized the first time the function is called. The purpose of doing this is to provide a mechanism to guarantee the initialization order: you call the function when you need it initialized. You do not control the initialization order of static data across translation units (that's the static initialization order fiasco). If you were to just "extern AppInfo GlobalAppInfo;" some place, you could very easily refer to that GlobalAppInfo in another TU before it was initialized, and then you crash. If you're lucky you crash there, but probably you crash somewhere later because of bogus data.

This example you've provided as a counterpoint here is significantly different from your original. I would argue that the problems with this secondary "AppInfo" example are more to do with the broader problem of over-reliance on pointless globals. Your first example is trivially convertible to a function with no loss of generality:

 

8 hours ago, MarcusAseth said:

if I understand correctly what you're saying, that's seems messy to me because then I have to compose in place the name of the thing I want to load like string(MyGame::Constants::Files()) + "Graphics/Checker.png" and I have to remember the name of stuff all over the place, much easier to just call Paths::Images::CHECKER and let it do the right thing.

You can write this: "Paths::Images::CHECKER," and potentially be subject to the initialization problems above, or you can write this: "Paths::Images::CHECKER()" and not be. The second option is functionally equivalent to the first and does not require you to "compose" anything, change values in more than one place, et cetera.

Also, since this is diverging quickly into two different subjects, I suggest you make a new topic if you'd like further discussion on your larger texture/object/level lifetime management issues. Or come ask about it in the Discord server. I'd like to keep threads reasonably scoped to their original concerns.

@jpetrie my apologize, sometimes I just reply to the notify message and I completely forgot what a topic was about x_x I'll try harder. But no further OT from me, since your reply above totally clarified how to use that function and it makes perfect sense, so thanks! :) 

This topic is closed to new replies.

Advertisement