public static void apply(final TextureState state) {
// ask for the current state record
final RenderContext context = ContextManager.getCurrentContext();
final ContextCapabilities caps = context.getCapabilities();
final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(StateType.Texture);
context.setCurrentState(StateType.Texture, state);
if (state.isEnabled()) {
Texture texture;
Texture.Type type;
TextureUnitRecord unitRecord;
TextureRecord texRecord;
final int glHint = LwjglTextureUtil.getPerspHint(state.getCorrectionType());
if (!record.isValid() || record.hint != glHint) {
// set up correction mode
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, glHint);
record.hint = glHint;
}
// loop through all available texture units...
for (int i = 0; i < caps.getNumberOfTotalTextureUnits(); i++) {
unitRecord = record.units[i];
// grab a texture for this unit, if available
texture = state.getTexture(i);
// pull our texture id for this texture, for this context.
int textureId = texture != null ? texture.getTextureIdForContext(context.getGlContextRep()) : 0;
// check for invalid textures - ones that have no opengl id and
// no image data
if (texture != null && textureId == 0 && texture.getImage() == null) {
texture = null;
}
// null textures above fixed limit do not need to be disabled
// since they are not really part of the pipeline.
if (texture == null) {
if (i >= caps.getNumberOfFixedTextureUnits()) {
continue;
} else {
// a null texture indicates no texturing at this unit
// Disable texturing on this unit if enabled.
disableTexturing(unitRecord, record, i, caps);
if (i < state._keyCache.length) {
state._keyCache[i] = null;
}
// next texture!
continue;
}
}
type = texture.getType();
// disable other texturing types for this unit, if enabled.
disableTexturing(unitRecord, record, i, type, caps);
// Time to bind the texture, so see if we need to load in image
// data for this texture.
if (textureId == 0) {
// texture not yet loaded.
// this will load and bind and set the records...
load(texture, i);
textureId = texture.getTextureIdForContext(context.getGlContextRep());
if (textureId == 0) {
continue;
}
} else if (texture.isDirty(context.getGlContextRep())) {
update(texture, i);
textureId = texture.getTextureIdForContext(context.getGlContextRep());
if (textureId == 0) {
continue;
}
} else {
// texture already exists in OpenGL, just bind it if needed
if (!unitRecord.isValid() || unitRecord.boundTexture != textureId) {
checkAndSetUnit(i, record, caps);
GL11.glBindTexture(getGLType(type), textureId);
if (Constants.stats) {
StatCollector.addStat(StatType.STAT_TEXTURE_BINDS, 1);
}
unitRecord.boundTexture = textureId;
}
}
// Use the Java Integer object for the getTextureRecord call to avoid
// boxing/unboxing ints for map lookups.
final Integer textureIdInteger = texture.getTextureIdForContextAsInteger(context.getGlContextRep());
// Grab our record for this texture
texRecord = record.getTextureRecord(textureIdInteger, texture.getType());
// Set the keyCache value for this unit of this texture state
// This is done so during state comparison we don't have to
// spend a lot of time pulling out classes and finding field
// data.
state._keyCache[i] = texture.getTextureKey();
// Some texture things only apply to fixed function pipeline
if (i < caps.getNumberOfFixedTextureUnits()) {
// Enable 2D texturing on this unit if not enabled.
if (!unitRecord.isValid() || !unitRecord.enabled[type.ordinal()]) {
checkAndSetUnit(i, record, caps);
GL11.glEnable(getGLType(type));
unitRecord.enabled[type.ordinal()] = true;
}
// Set our blend color, if needed.
applyBlendColor(texture, unitRecord, i, record, caps);
// Set the texture environment mode if this unit isn't
// already set properly
applyEnvMode(texture.getApply(), unitRecord, i, record, caps);
// If our mode is combine, and we support multitexturing
// apply combine settings.
if (texture.getApply() == ApplyMode.Combine && caps.isMultitextureSupported()
&& caps.isEnvCombineSupported()) {
applyCombineFactors(texture, unitRecord, i, record, caps);
}
}
// Other items only apply to textures below the frag unit limit
if (i < caps.getNumberOfFragmentTextureUnits()) {
// texture specific params
applyFilter(texture, texRecord, i, record, caps);
applyWrap(texture, texRecord, i, record, caps);
applyShadow(texture, texRecord, i, record, caps);
// Set our border color, if needed.
applyBorderColor(texture, texRecord, i, record);
// all states have now been applied for a tex record, so we
// can safely make it valid
if (!texRecord.isValid()) {
texRecord.validate();
}
}
// Other items only apply to textures below the frag tex coord
// unit limit
if (i < caps.getNumberOfFragmentTexCoordUnits()) {
// Now time to play with texture matrices
// Determine which transforms to do.
applyTextureTransforms(texture, i, record, caps);
// Now let's look at automatic texture coordinate
// generation.
applyTexCoordGeneration(texture, unitRecord, i, record, caps);
// Set our texture lod bias, if needed.
applyLodBias(texture, unitRecord, i, record, caps);
}
}
} else {
// turn off texturing
TextureUnitRecord unitRecord;
if (caps.isMultitextureSupported()) {
for (int i = 0; i < caps.getNumberOfFixedTextureUnits(); i++) {
unitRecord = record.units[i];
disableTexturing(unitRecord, record, i, caps);
}
} else {
unitRecord = record.units[0];
disableTexturing(unitRecord, record, 0, caps);
}
}
if (!record.isValid()) {
record.validate();
}
}