Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reworked Base texture class #76

Merged
merged 2 commits into from
Feb 9, 2017
Merged

Conversation

Quaker762
Copy link
Member

Textures can now be bound for operations by OpenGL, as well as the
ability to be loaded by the new Virtual File System we have. Textures
are stored as their pixel array in a vector.

Currently, 8-bit textures aren't supported because for reasons that
elude me, they are palletted, and I have no clue as to where the
pallete is (or what data it contains).

The header was also fixed up, as it was missing a 16-bit unused value,
which was distorting the number of bytes passed to the Virtual File
System to load the texture.

@Quaker762 Quaker762 requested a review from z33ky February 1, 2017 13:50
Copy link
Collaborator

@z33ky z33ky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The texture also needs to be deleted at some point.

Have you considered bindless textures? I don't know if that is something we do want to use, it's just something that I've heard about and lingers in my mind.

Log(LogLevel::WARN, "sh3_texture::Load( ): Header only read %d bytes of data! It should have been %d", ret, sizeof(sh3_texture_header));

if(header.bpp == 8)
die("8-bit textures are currently unsupported!");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think die() is a little drastic. We should warn here and get things rendering, even if it's messed up at the moment.
We could also check for other bpps we don't expect.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think die() is a little drastic

I thought so too, but the screen will end up looking like vomit as you can see here. I'll remove it and log for now though.

sh3_arc_vfile file(mft, filename);
sh3_arc_vfile::read_error e;

int ret = file.ReadData(&header, sizeof(sh3_texture_header), e); // Read in the header
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be std::size_t.
I"m also in favor of using sizeof(header) (generally sizeof(variable) where applicable) because the intention here is to read the size of the variable header, which just happens to be a sh3_texture_header here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I"m also in favor of using sizeof(header) (generally sizeof(variable)

I'll do this from now on then. I think the whole sizeof(typename) has stuck from not only books I've read, but other peoples' code I've looked through.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still missing.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

{
die("sh3_graphics::texture::Load( ): Unable to find file %s!", filename.c_str());
}
data.resize(header.texSize);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could check that texSize == texWidth * texHeight * bpp. That should apply, right?
If it doesn't we should make sure that there's no out-of-bounds read from data.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As in an assertion??

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assertions should only be present in debug mode, so I think this should be a regular check & log.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still missing.

// Now actually create a logical texture with OpenGL on the gpu
glGenTextures(1, &tex);

glBindTexture(GL_TEXTURE_2D, tex);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use Bind() and later Unbind(). Though apart from being shorter I don't see much benefit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could use Bind() and later Unbind()

I have this weird habit of not using class functions inside other class functions... Strange I know..

@Quaker762
Copy link
Member Author

The texture also needs to be deleted at some point.

Lmao

Have you considered bindless textures? I don't know if that is something we do want to use, it's just something that I've heard about and lingers in my mind.

I had never even heard of these until I googled them. It seems a little bit weird though (and the Khronos site even mentions it's a bit complex here)
I feel like binding makes a little bit more sense. You bind the texture you want to do something on, perform it, and then let it free. They'd be cool to look into and implement though, as long as they're not overly complex haha.

@Quaker762
Copy link
Member Author

Also I just realised I should add texture units into bind, so we can bind to different texture units for different textures as it explained here

*/
load_error Load(const std::string& filename, sh3_arc& arc);
void Bind(GLenum textureUnit);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 space too many

Log(LogLevel::WARN, "sh3_texture::Load( ): Header only read %d bytes of data! It should have been %d", ret, sizeof(sh3_texture_header));

if(header.bpp == 8)
die("8-bit textures are currently unsupported!");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

die() and Log()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crap I forgot to change this...

int ret = file.ReadData(&header, sizeof(sh3_texture_header), e); // Read in the header

if(ret != sizeof(sh3_texture_header))
Log(LogLevel::WARN, "sh3_texture::Load( ): Header only read %d bytes of data! It should have been %d", ret, sizeof(sh3_texture_header));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may want to fallback on a dummy texture when this happens, since it would be very cumbersome to ensure we don't read uninitialized struct fields.
For now this would be a good place to die(), though add a //TODO that we want to use a fallback texture in the future.

@z33ky
Copy link
Collaborator

z33ky commented Feb 2, 2017

I feel like binding makes a little bit more sense. You bind the texture you want to do something on, perform it, and then let it free. They'd be cool to look into and implement though, as long as they're not overly complex haha.

I find the stateful implementation weirder than the stateless one. The stateless version is OOP-like do_stuff(thingToDoStuffOn, parameters...); whereas the stateful has this verbose pattern of

make_thing_active(thingToDoStuffOn);
do_stuff(parameters...);
//sometimes: make_thing_inactive(thingToDoStuffOn);

Even worse if you made some function-calls between make_thing_active and do_stuff, because you have to hope that thingToDoStuffOn is still active, or you need to re-activate it just in case.
At least this is my understanding of the concept, without having read anything about the actual API.

@Quaker762
Copy link
Member Author

I find the stateful implementation weirder than the stateless one

Aren't programming paradigms and semantics fun haha.

Even worse if you made some function-calls between make_thing_active and do_stuff, because you have to hope that thingToDoStuffOn is still active, or you need to re-activate it just in case.

Very true, though the chance of that happening are pretty slim with the amount we're reviewing each others code. Though I do see the problem in this. OpenGL wont shit itself if this happens, so your calls just silently fail or even worse corrupt something.

At least this is my understanding of the concept, without having read anything about the actual API.

It seems like it. The only other issue I have is this is an ARB extension, which I assume most modern graphics cards support, but the chances of this being run on someone's grandma's PC is pretty high haha.

@z33ky
Copy link
Collaborator

z33ky commented Feb 2, 2017

The only other issue I have is this is an ARB extension, which I assume most modern graphics cards support, but the chances of this being run on someone's grandma's PC is pretty high haha.

I might have an idea how we can support both in a uniform API. I'll try that when this PR is merged rebased ;).

@Quaker762
Copy link
Member Author

I'll try that when this PR is merged rebased ;)

What do you need me to rebase?? Or is this the new workflow method you were talking about in #72 haha?

@z33ky
Copy link
Collaborator

z33ky commented Feb 3, 2017

Or is this the new workflow method you were talking about in #72 haha?

Yeah. The rebase will happen automatically if there's no conflicts.

@Quaker762
Copy link
Member Author

The rebase will happen automatically if there's no conflicts.

How the hell does that work!?!?!

@z33ky
Copy link
Collaborator

z33ky commented Feb 7, 2017

See #76 (review)


glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, header.texWidth, header.texHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, &data[0]);
glBindTexture(GL_TEXTURE_2D, 0); // Unbind this texture
Copy link
Collaborator

@z33ky z33ky Feb 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this restore the previously bound texture (can be obtained via glGetIntegerv(GL_TEXTURE_BINDING_2D, &prevTex); I think)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand why we'd want to bind the previous texture? This only changes a few parameters for this texture during a load. When the actual game is running, textures are bound and unbound when they're drawn (or rather, bound to different texture units and drawn) .

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean they'll be (re-)bound per frame? That won't be an issue then.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah they have to be to be drawn. Basically (how I'm thinking it'll work), is each mesh has a texture (*.tex). Everything is loaded before the scene is rendered. During the render loop, we transverse a list containing each mesh. Its VBO and texture is bound and drawn etc.

When you generate a texture I'm pretty sure it's recommended you unbind it. Otherwise you could add a bunch of stuff to another texture without realising it.

{
die("sh3_graphics::texture::Load( ): Unable to find file %s!", filename.c_str());
}
data.resize(header.texSize);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still missing.

sh3_arc_vfile file(mft, filename);
sh3_arc_vfile::read_error e;

int ret = file.ReadData(&header, sizeof(sh3_texture_header), e); // Read in the header
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still missing.

@z33ky z33ky mentioned this pull request Feb 8, 2017
Textures can now be bound for operations by OpenGL, as well as the
ability to be loaded by the new Virtual File System we have. Textures
are stored as their pixel array in a vector.

Currently, 8-bit textures aren't supported because for reasons that
elude me, they are palletted, and I have no clue as to where the
pallete is (or what data it contains).

The header was also fixed up, as it was missing a 16-bit unused value,
which was distorting the number of bytes passed to the Virtual File
System to load the texture.
if(arc.LoadFile(filename, pixbuff) == ARC_FILE_NOT_FOUND)
data.resize(header.texSize);

if(header.texSize == header.texWidth * header.texHeight * header.bpp)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do an early return, i.e. instead of

if(x)
{
    A;
}
else
{
    B;
    return;
}

do

if(!x)
{
    B;
    return;
}
A;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Once we upload the texture data to the Graphics Card, it is a waste of
conventional memory to keep this around...
@z33ky z33ky merged commit f38ab55 into Palm-Studios:master Feb 9, 2017
@Quaker762 Quaker762 deleted the textures branch February 10, 2017 01:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants