|
@@ -1439,9 +1439,7 @@ draw_sprite(GeomSprite *geom, GeomContext *) {
|
|
|
Texture *tex = geom->get_texture();
|
|
Texture *tex = geom->get_texture();
|
|
|
if(tex != NULL) {
|
|
if(tex != NULL) {
|
|
|
// set up the texture-rendering state
|
|
// set up the texture-rendering state
|
|
|
- modify_state(RenderState::make
|
|
|
|
|
- (TextureAttrib::make(tex),
|
|
|
|
|
- TextureApplyAttrib::make(TextureApplyAttrib::M_modulate)));
|
|
|
|
|
|
|
+ modify_state(RenderState::make(TextureAttrib::make(tex)));
|
|
|
tex_x_size = tex->get_x_size();
|
|
tex_x_size = tex->get_x_size();
|
|
|
tex_y_size = tex->get_y_size();
|
|
tex_y_size = tex->get_y_size();
|
|
|
}
|
|
}
|
|
@@ -2759,12 +2757,12 @@ end_draw_primitives() {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: GLGraphicsStateGuardian::prepare_texture
|
|
// Function: GLGraphicsStateGuardian::prepare_texture
|
|
|
// Access: Public, Virtual
|
|
// Access: Public, Virtual
|
|
|
-// Description: Creates a new retained-mode representation of the
|
|
|
|
|
-// given texture, and returns a newly-allocated
|
|
|
|
|
-// TextureContext pointer to reference it. It is the
|
|
|
|
|
-// responsibility of the calling function to later
|
|
|
|
|
-// call release_texture() with this same pointer (which
|
|
|
|
|
-// will also delete the pointer).
|
|
|
|
|
|
|
+// Description: Creates whatever structures the GSG requires to
|
|
|
|
|
+// represent the texture internally, and returns a
|
|
|
|
|
+// newly-allocated TextureContext object with this data.
|
|
|
|
|
+// It is the responsibility of the calling function to
|
|
|
|
|
+// later call release_texture() with this same pointer
|
|
|
|
|
+// (which will also delete the pointer).
|
|
|
//
|
|
//
|
|
|
// This function should not be called directly to
|
|
// This function should not be called directly to
|
|
|
// prepare a texture. Instead, call Texture::prepare().
|
|
// prepare a texture. Instead, call Texture::prepare().
|
|
@@ -2773,42 +2771,10 @@ TextureContext *CLP(GraphicsStateGuardian)::
|
|
|
prepare_texture(Texture *tex) {
|
|
prepare_texture(Texture *tex) {
|
|
|
CLP(TextureContext) *gtc = new CLP(TextureContext)(tex);
|
|
CLP(TextureContext) *gtc = new CLP(TextureContext)(tex);
|
|
|
GLP(GenTextures)(1, >c->_index);
|
|
GLP(GenTextures)(1, >c->_index);
|
|
|
-
|
|
|
|
|
- bind_texture(gtc);
|
|
|
|
|
- GLP(PrioritizeTextures)(1, >c->_index, >c->_priority);
|
|
|
|
|
- specify_texture(tex);
|
|
|
|
|
- apply_texture_immediate(gtc, tex);
|
|
|
|
|
-
|
|
|
|
|
report_my_gl_errors();
|
|
report_my_gl_errors();
|
|
|
- return gtc;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::apply_texture
|
|
|
|
|
-// Access: Public, Virtual
|
|
|
|
|
-// Description: Makes the texture the currently available texture for
|
|
|
|
|
-// rendering.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-apply_texture(TextureContext *tc, int index) {
|
|
|
|
|
- CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
|
|
|
|
-
|
|
|
|
|
- add_to_texture_record(gtc);
|
|
|
|
|
- bind_texture(gtc);
|
|
|
|
|
-
|
|
|
|
|
- int dirty = gtc->get_dirty_flags();
|
|
|
|
|
- if ((dirty & (Texture::DF_wrap | Texture::DF_filter | Texture::DF_border)) != 0) {
|
|
|
|
|
- // We need to re-specify the texture properties.
|
|
|
|
|
- specify_texture(gtc->_texture);
|
|
|
|
|
- }
|
|
|
|
|
- if ((dirty & (Texture::DF_image | Texture::DF_mipmap | Texture::DF_border)) != 0) {
|
|
|
|
|
- // We need to re-apply the image.
|
|
|
|
|
- apply_texture_immediate(gtc, gtc->_texture);
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- gtc->clear_dirty_flags();
|
|
|
|
|
-
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
|
|
+ apply_texture(gtc);
|
|
|
|
|
+ return gtc;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
@@ -3283,7 +3249,14 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
|
|
|
|
|
|
|
|
TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
|
|
TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
|
|
|
nassertv(tc != (TextureContext *)NULL);
|
|
nassertv(tc != (TextureContext *)NULL);
|
|
|
- bind_texture(tc);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
|
|
|
|
+ GLenum target = get_texture_target(tex->get_texture_type());
|
|
|
|
|
+ if (target == GL_NONE) {
|
|
|
|
|
+ // Invalid texture, can't copy to it.
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ GLP(BindTexture)(target, gtc->_index);
|
|
|
|
|
|
|
|
if (z >= 0) {
|
|
if (z >= 0) {
|
|
|
// Copy to a cube map face.
|
|
// Copy to a cube map face.
|
|
@@ -3439,7 +3412,8 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
|
|
|
// Access: Public, Virtual
|
|
// Access: Public, Virtual
|
|
|
// Description:
|
|
// Description:
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void CLP(GraphicsStateGuardian)::apply_material(const Material *material) {
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+apply_material(const Material *material) {
|
|
|
GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT;
|
|
GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT;
|
|
|
|
|
|
|
|
GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data());
|
|
GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data());
|
|
@@ -3783,18 +3757,6 @@ issue_rescale_normal(const RescaleNormalAttrib *attrib) {
|
|
|
report_my_gl_errors();
|
|
report_my_gl_errors();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::issue_texture_apply
|
|
|
|
|
-// Access: Public, Virtual
|
|
|
|
|
-// Description:
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-issue_texture_apply(const TextureApplyAttrib *) {
|
|
|
|
|
- // This attrib is no longer used; it is replaced by the parameters
|
|
|
|
|
- // within TextureStage.
|
|
|
|
|
- return;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: GLGraphicsStateGuardian::issue_color_write
|
|
// Function: GLGraphicsStateGuardian::issue_color_write
|
|
|
// Access: Public, Virtual
|
|
// Access: Public, Virtual
|
|
@@ -4391,1991 +4353,1999 @@ set_read_buffer(const RenderBuffer &rb) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::bind_texture
|
|
|
|
|
-// Access: Protected
|
|
|
|
|
-// Description:
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_numeric_type
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the Geom's internal numeric type symbols
|
|
|
|
|
+// to GL's.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-bind_texture(TextureContext *tc) {
|
|
|
|
|
- CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
|
|
+GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_numeric_type(qpGeom::NumericType numeric_type) {
|
|
|
|
|
+ switch (numeric_type) {
|
|
|
|
|
+ case qpGeom::NT_uint16:
|
|
|
|
|
+ return GL_UNSIGNED_SHORT;
|
|
|
|
|
|
|
|
-#ifdef GSG_VERBOSE
|
|
|
|
|
- Texture *tex = tc->_texture;
|
|
|
|
|
- GLCAT.spam()
|
|
|
|
|
- << "glBindTexture(): " << tex->get_name() << "(" << (int)gtc->_index
|
|
|
|
|
- << ")" << endl;
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+ case qpGeom::NT_uint32:
|
|
|
|
|
+ return GL_UNSIGNED_INT;
|
|
|
|
|
|
|
|
- GLenum target = get_texture_target(tc->_texture->get_texture_type());
|
|
|
|
|
- if (target != GL_NONE) {
|
|
|
|
|
- GLP(BindTexture)(target, gtc->_index);
|
|
|
|
|
|
|
+ case qpGeom::NT_uint8:
|
|
|
|
|
+ case qpGeom::NT_packed_dcba:
|
|
|
|
|
+ case qpGeom::NT_packed_dabc:
|
|
|
|
|
+ return GL_UNSIGNED_BYTE;
|
|
|
|
|
+
|
|
|
|
|
+ case qpGeom::NT_float32:
|
|
|
|
|
+ return GL_FLOAT;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Invalid NumericType value (" << (int)numeric_type << ")\n";
|
|
|
|
|
+ return GL_UNSIGNED_BYTE;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::specify_texture
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_texture_target
|
|
|
// Access: Protected
|
|
// Access: Protected
|
|
|
-// Description:
|
|
|
|
|
|
|
+// Description: Maps from the Texture's texture type symbols to
|
|
|
|
|
+// GL's.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-specify_texture(Texture *tex) {
|
|
|
|
|
- GLenum target = get_texture_target(tex->get_texture_type());
|
|
|
|
|
- if (target == GL_NONE) {
|
|
|
|
|
- // Unsupported target (e.g. 3-d texturing on GL 1.1).
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- GLP(TexParameteri)(target, GL_TEXTURE_WRAP_S,
|
|
|
|
|
- get_texture_wrap_mode(tex->get_wrap_u()));
|
|
|
|
|
- if (target != GL_TEXTURE_1D) {
|
|
|
|
|
- GLP(TexParameteri)(target, GL_TEXTURE_WRAP_T,
|
|
|
|
|
- get_texture_wrap_mode(tex->get_wrap_v()));
|
|
|
|
|
- }
|
|
|
|
|
- if (target == GL_TEXTURE_3D) {
|
|
|
|
|
- GLP(TexParameteri)(target, GL_TEXTURE_WRAP_R,
|
|
|
|
|
- get_texture_wrap_mode(tex->get_wrap_w()));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- Colorf border_color = tex->get_border_color();
|
|
|
|
|
- GLP(TexParameterfv)(target, GL_TEXTURE_BORDER_COLOR,
|
|
|
|
|
- border_color.get_data());
|
|
|
|
|
-
|
|
|
|
|
- Texture::FilterType minfilter = tex->get_minfilter();
|
|
|
|
|
- Texture::FilterType magfilter = tex->get_magfilter();
|
|
|
|
|
- bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps);
|
|
|
|
|
|
|
+GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_texture_target(Texture::TextureType texture_type) const {
|
|
|
|
|
+ switch (texture_type) {
|
|
|
|
|
+ case Texture::TT_1d_texture:
|
|
|
|
|
+ return GL_TEXTURE_1D;
|
|
|
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- if (CLP(force_mipmaps)) {
|
|
|
|
|
- minfilter = Texture::FT_linear_mipmap_linear;
|
|
|
|
|
- magfilter = Texture::FT_linear;
|
|
|
|
|
- uses_mipmaps = true;
|
|
|
|
|
- }
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+ case Texture::TT_2d_texture:
|
|
|
|
|
+ return GL_TEXTURE_2D;
|
|
|
|
|
|
|
|
- if (_supports_generate_mipmap &&
|
|
|
|
|
- (auto_generate_mipmaps || !tex->might_have_ram_image())) {
|
|
|
|
|
- // If the hardware can automatically generate mipmaps, ask it to
|
|
|
|
|
- // do so now, but only if the texture requires them.
|
|
|
|
|
- GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, uses_mipmaps);
|
|
|
|
|
|
|
+ case Texture::TT_3d_texture:
|
|
|
|
|
+ if (_supports_3d_texture) {
|
|
|
|
|
+ return GL_TEXTURE_3D;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return GL_NONE;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- } else if (!tex->might_have_ram_image()) {
|
|
|
|
|
- // If the hardware can't automatically generate mipmaps, but it's
|
|
|
|
|
- // a dynamically generated texture (that is, the RAM image isn't
|
|
|
|
|
- // available so it didn't pass through the CPU), then we'd better
|
|
|
|
|
- // not try to enable mipmap filtering, since we can't generate
|
|
|
|
|
- // mipmaps.
|
|
|
|
|
- uses_mipmaps = false;
|
|
|
|
|
|
|
+ case Texture::TT_cube_map:
|
|
|
|
|
+ if (_supports_cube_map) {
|
|
|
|
|
+ return GL_TEXTURE_CUBE_MAP;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return GL_NONE;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER,
|
|
|
|
|
- get_texture_filter_type(minfilter, !uses_mipmaps));
|
|
|
|
|
- GLP(TexParameteri)(target, GL_TEXTURE_MAG_FILTER,
|
|
|
|
|
- get_texture_filter_type(magfilter, true));
|
|
|
|
|
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
|
|
+ GLCAT.error() << "Invalid Texture::TextureType value!\n";
|
|
|
|
|
+ return GL_TEXTURE_2D;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: compute_gl_image_size
|
|
|
|
|
-// Description: Calculates how many bytes GL will expect to read for
|
|
|
|
|
-// a texture image, based on the number of pixels and
|
|
|
|
|
-// the GL format and type. This is only used for
|
|
|
|
|
-// debugging.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_texture_wrap_mode
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the Texture's internal wrap mode symbols to
|
|
|
|
|
+// GL's.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-static int
|
|
|
|
|
-compute_gl_image_size(int x_size, int y_size, int z_size,
|
|
|
|
|
- int external_format, int type) {
|
|
|
|
|
- int num_components = 0;
|
|
|
|
|
- switch (external_format) {
|
|
|
|
|
- case GL_COLOR_INDEX:
|
|
|
|
|
- case GL_STENCIL_INDEX:
|
|
|
|
|
- case GL_DEPTH_COMPONENT:
|
|
|
|
|
- case GL_RED:
|
|
|
|
|
- case GL_GREEN:
|
|
|
|
|
- case GL_BLUE:
|
|
|
|
|
- case GL_ALPHA:
|
|
|
|
|
- case GL_LUMINANCE:
|
|
|
|
|
- num_components = 1;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case GL_LUMINANCE_ALPHA:
|
|
|
|
|
- num_components = 2;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case GL_BGR:
|
|
|
|
|
- case GL_RGB:
|
|
|
|
|
- num_components = 3;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case GL_BGRA:
|
|
|
|
|
- case GL_RGBA:
|
|
|
|
|
- num_components = 4;
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_texture_wrap_mode(Texture::WrapMode wm) {
|
|
|
|
|
+ if (CLP(ignore_clamp)) {
|
|
|
|
|
+ return GL_REPEAT;
|
|
|
}
|
|
}
|
|
|
|
|
+ switch (wm) {
|
|
|
|
|
+ case Texture::WM_clamp:
|
|
|
|
|
+ return _edge_clamp;
|
|
|
|
|
|
|
|
- int pixel_width = 0;
|
|
|
|
|
- switch (type) {
|
|
|
|
|
- case GL_UNSIGNED_BYTE:
|
|
|
|
|
- pixel_width = 1 * num_components;
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ case Texture::WM_repeat:
|
|
|
|
|
+ return GL_REPEAT;
|
|
|
|
|
|
|
|
- case GL_UNSIGNED_SHORT:
|
|
|
|
|
- pixel_width = 2 * num_components;
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ case Texture::WM_mirror:
|
|
|
|
|
+ return _mirror_repeat;
|
|
|
|
|
|
|
|
- case GL_UNSIGNED_BYTE_3_3_2:
|
|
|
|
|
- nassertr(num_components == 3, 0);
|
|
|
|
|
- pixel_width = 1;
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ case Texture::WM_mirror_once:
|
|
|
|
|
+ return _mirror_border_clamp;
|
|
|
|
|
|
|
|
- case GL_FLOAT:
|
|
|
|
|
- pixel_width = 4 * num_components;
|
|
|
|
|
|
|
+ case Texture::WM_border_color:
|
|
|
|
|
+ return _border_clamp;
|
|
|
|
|
+
|
|
|
|
|
+ case Texture::WM_invalid:
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return x_size * y_size * z_size * pixel_width;
|
|
|
|
|
|
|
+ GLCAT.error() << "Invalid Texture::WrapMode value!\n";
|
|
|
|
|
+ return _edge_clamp;
|
|
|
}
|
|
}
|
|
|
-#endif // NDEBUG
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::apply_texture_immediate
|
|
|
|
|
-// Access: Protected
|
|
|
|
|
-// Description: Sends the texture image to GL. This can be used to
|
|
|
|
|
-// render a texture in immediate mode, or as part of the
|
|
|
|
|
-// process of creating a GL texture object.
|
|
|
|
|
-//
|
|
|
|
|
-// The return value is true if successful, or false if
|
|
|
|
|
-// the texture has no image.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_texture_filter_type
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the Texture's internal filter type symbols
|
|
|
|
|
+// to GL's.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-bool CLP(GraphicsStateGuardian)::
|
|
|
|
|
-apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex) {
|
|
|
|
|
- CPTA_uchar image = tex->get_ram_image();
|
|
|
|
|
- if (image.is_null()) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int width = tex->get_x_size();
|
|
|
|
|
- int height = tex->get_y_size();
|
|
|
|
|
- int depth = tex->get_z_size();
|
|
|
|
|
-
|
|
|
|
|
- GLint internal_format = get_internal_image_format(tex->get_format());
|
|
|
|
|
- GLint external_format = get_external_image_format(tex->get_format());
|
|
|
|
|
- GLenum component_type = get_component_type(tex->get_component_type());
|
|
|
|
|
|
|
+GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps) {
|
|
|
|
|
+ if (CLP(ignore_filters)) {
|
|
|
|
|
+ return GL_NEAREST;
|
|
|
|
|
|
|
|
- // Ensure that the texture fits within the GL's specified limits.
|
|
|
|
|
- int max_dimension;
|
|
|
|
|
- switch (tex->get_texture_type()) {
|
|
|
|
|
- case Texture::TT_3d_texture:
|
|
|
|
|
- max_dimension = _max_3d_texture_dimension;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case Texture::TT_cube_map:
|
|
|
|
|
- max_dimension = _max_cube_map_dimension;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- default:
|
|
|
|
|
- max_dimension = _max_texture_dimension;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ } else if (ignore_mipmaps) {
|
|
|
|
|
+ switch (ft) {
|
|
|
|
|
+ case Texture::FT_nearest_mipmap_nearest:
|
|
|
|
|
+ case Texture::FT_nearest:
|
|
|
|
|
+ return GL_NEAREST;
|
|
|
|
|
+ case Texture::FT_linear:
|
|
|
|
|
+ case Texture::FT_linear_mipmap_nearest:
|
|
|
|
|
+ case Texture::FT_nearest_mipmap_linear:
|
|
|
|
|
+ case Texture::FT_linear_mipmap_linear:
|
|
|
|
|
+ return GL_LINEAR;
|
|
|
|
|
+ case Texture::FT_invalid:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (max_dimension == 0) {
|
|
|
|
|
- // Guess this GL doesn't support cube mapping/3d textures.
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ switch (ft) {
|
|
|
|
|
+ case Texture::FT_nearest:
|
|
|
|
|
+ return GL_NEAREST;
|
|
|
|
|
+ case Texture::FT_linear:
|
|
|
|
|
+ return GL_LINEAR;
|
|
|
|
|
+ case Texture::FT_nearest_mipmap_nearest:
|
|
|
|
|
+ return GL_NEAREST_MIPMAP_NEAREST;
|
|
|
|
|
+ case Texture::FT_linear_mipmap_nearest:
|
|
|
|
|
+ return GL_LINEAR_MIPMAP_NEAREST;
|
|
|
|
|
+ case Texture::FT_nearest_mipmap_linear:
|
|
|
|
|
+ return GL_NEAREST_MIPMAP_LINEAR;
|
|
|
|
|
+ case Texture::FT_linear_mipmap_linear:
|
|
|
|
|
+ return GL_LINEAR_MIPMAP_LINEAR;
|
|
|
|
|
+ case Texture::FT_invalid:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ GLCAT.error() << "Invalid Texture::FilterType value!\n";
|
|
|
|
|
+ return GL_NEAREST;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- int texel_size = tex->get_num_components() * tex->get_component_width();
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_component_type
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the Texture's internal ComponentType symbols
|
|
|
|
|
+// to GL's.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_component_type(Texture::ComponentType component_type) {
|
|
|
|
|
+ switch (component_type) {
|
|
|
|
|
+ case Texture::T_unsigned_byte:
|
|
|
|
|
+ return GL_UNSIGNED_BYTE;
|
|
|
|
|
+ case Texture::T_unsigned_short:
|
|
|
|
|
+ return GL_UNSIGNED_SHORT;
|
|
|
|
|
+ case Texture::T_float:
|
|
|
|
|
+ return GL_FLOAT;
|
|
|
|
|
|
|
|
- // If it doesn't fit, we have to reduce it on-the-fly. This is kind
|
|
|
|
|
- // of expensive and it doesn't look great; it would have been better
|
|
|
|
|
- // if the user had specified max-texture-dimension to reduce the
|
|
|
|
|
- // texture at load time instead. Of course, the user doesn't always
|
|
|
|
|
- // know ahead of time what the hardware limits are.
|
|
|
|
|
- if (max_dimension > 0) {
|
|
|
|
|
- if (width > max_dimension) {
|
|
|
|
|
- int byte_chunk = texel_size;
|
|
|
|
|
- int stride = 1;
|
|
|
|
|
- int new_width = width;
|
|
|
|
|
- while (new_width > max_dimension) {
|
|
|
|
|
- stride <<= 1;
|
|
|
|
|
- new_width >>= 1;
|
|
|
|
|
- }
|
|
|
|
|
- GLCAT.info()
|
|
|
|
|
- << "Reducing width of " << tex->get_name()
|
|
|
|
|
- << " from " << width << " to " << new_width << "\n";
|
|
|
|
|
- image = reduce_image(image, byte_chunk, stride);
|
|
|
|
|
- width = new_width;
|
|
|
|
|
- }
|
|
|
|
|
- if (height > max_dimension) {
|
|
|
|
|
- int byte_chunk = width * texel_size;
|
|
|
|
|
- int stride = 1;
|
|
|
|
|
- int new_height = height;
|
|
|
|
|
- while (new_height > max_dimension) {
|
|
|
|
|
- stride <<= 1;
|
|
|
|
|
- new_height >>= 1;
|
|
|
|
|
- }
|
|
|
|
|
- GLCAT.info()
|
|
|
|
|
- << "Reducing height of " << tex->get_name()
|
|
|
|
|
- << " from " << height << " to " << new_height << "\n";
|
|
|
|
|
- image = reduce_image(image, byte_chunk, stride);
|
|
|
|
|
- height = new_height;
|
|
|
|
|
- }
|
|
|
|
|
- if (depth > max_dimension) {
|
|
|
|
|
- int byte_chunk = height * width * texel_size;
|
|
|
|
|
- int stride = 1;
|
|
|
|
|
- int new_depth = depth;
|
|
|
|
|
- while (new_depth > max_dimension) {
|
|
|
|
|
- stride <<= 1;
|
|
|
|
|
- new_depth >>= 1;
|
|
|
|
|
- }
|
|
|
|
|
- GLCAT.info()
|
|
|
|
|
- << "Reducing depth of " << tex->get_name()
|
|
|
|
|
- << " from " << depth << " to " << new_depth << "\n";
|
|
|
|
|
- image = reduce_image(image, byte_chunk, stride);
|
|
|
|
|
- depth = new_depth;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ default:
|
|
|
|
|
+ GLCAT.error() << "Invalid Texture::Type value!\n";
|
|
|
|
|
+ return GL_UNSIGNED_BYTE;
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- if (!_supports_bgr) {
|
|
|
|
|
- // If the GL doesn't claim to support BGR, we may have to reverse
|
|
|
|
|
- // the component ordering of the image.
|
|
|
|
|
- image = fix_component_ordering(image, external_format, tex);
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_external_image_format
|
|
|
|
|
+// Access: Protected
|
|
|
|
|
+// Description: Maps from the Texture's Format symbols
|
|
|
|
|
+// to GL's.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_external_image_format(Texture::Format format) const {
|
|
|
|
|
+ switch (format) {
|
|
|
|
|
+ case Texture::F_color_index:
|
|
|
|
|
+ return GL_COLOR_INDEX;
|
|
|
|
|
+ case Texture::F_stencil_index:
|
|
|
|
|
+ return GL_STENCIL_INDEX;
|
|
|
|
|
+ case Texture::F_depth_component:
|
|
|
|
|
+ return GL_DEPTH_COMPONENT;
|
|
|
|
|
+ case Texture::F_red:
|
|
|
|
|
+ return GL_RED;
|
|
|
|
|
+ case Texture::F_green:
|
|
|
|
|
+ return GL_GREEN;
|
|
|
|
|
+ case Texture::F_blue:
|
|
|
|
|
+ return GL_BLUE;
|
|
|
|
|
+ case Texture::F_alpha:
|
|
|
|
|
+ return GL_ALPHA;
|
|
|
|
|
+ case Texture::F_rgb:
|
|
|
|
|
+ case Texture::F_rgb5:
|
|
|
|
|
+ case Texture::F_rgb8:
|
|
|
|
|
+ case Texture::F_rgb12:
|
|
|
|
|
+ case Texture::F_rgb332:
|
|
|
|
|
+ return _supports_bgr ? GL_BGR : GL_RGB;
|
|
|
|
|
+ case Texture::F_rgba:
|
|
|
|
|
+ case Texture::F_rgbm:
|
|
|
|
|
+ case Texture::F_rgba4:
|
|
|
|
|
+ case Texture::F_rgba5:
|
|
|
|
|
+ case Texture::F_rgba8:
|
|
|
|
|
+ case Texture::F_rgba12:
|
|
|
|
|
+ return _supports_bgr ? GL_BGRA : GL_RGBA;
|
|
|
|
|
+ case Texture::F_luminance:
|
|
|
|
|
+ return GL_LUMINANCE;
|
|
|
|
|
+ case Texture::F_luminance_alphamask:
|
|
|
|
|
+ case Texture::F_luminance_alpha:
|
|
|
|
|
+ return GL_LUMINANCE_ALPHA;
|
|
|
}
|
|
}
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Invalid Texture::Format value in get_external_image_format(): "
|
|
|
|
|
+ << (int)format << "\n";
|
|
|
|
|
+ return GL_RGB;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- int wanted_size =
|
|
|
|
|
- compute_gl_image_size(width, height, depth, external_format, component_type);
|
|
|
|
|
- nassertr(wanted_size == (int)image.size(), false);
|
|
|
|
|
-#endif // NDEBUG
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_internal_image_format
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the Texture's Format symbols to a
|
|
|
|
|
+// suitable internal format for GL textures.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_internal_image_format(Texture::Format format) {
|
|
|
|
|
+ switch (format) {
|
|
|
|
|
+ case Texture::F_rgba:
|
|
|
|
|
+ case Texture::F_rgbm:
|
|
|
|
|
+ return GL_RGBA;
|
|
|
|
|
+ case Texture::F_rgba4:
|
|
|
|
|
+ return GL_RGBA4;
|
|
|
|
|
+ case Texture::F_rgba8:
|
|
|
|
|
+ return GL_RGBA8;
|
|
|
|
|
+ case Texture::F_rgba12:
|
|
|
|
|
+ return GL_RGBA12;
|
|
|
|
|
|
|
|
- GLP(PixelStorei)(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
|
|
|
+ case Texture::F_rgb:
|
|
|
|
|
+ return GL_RGB;
|
|
|
|
|
+ case Texture::F_rgb5:
|
|
|
|
|
+ return GL_RGB5;
|
|
|
|
|
+ case Texture::F_rgba5:
|
|
|
|
|
+ return GL_RGB5_A1;
|
|
|
|
|
+ case Texture::F_rgb8:
|
|
|
|
|
+ return GL_RGB8;
|
|
|
|
|
+ case Texture::F_rgb12:
|
|
|
|
|
+ return GL_RGB12;
|
|
|
|
|
+ case Texture::F_rgb332:
|
|
|
|
|
+ return GL_R3_G3_B2;
|
|
|
|
|
|
|
|
- bool uses_mipmaps = (tex->uses_mipmaps() && !CLP(ignore_mipmaps)) || CLP(force_mipmaps);
|
|
|
|
|
|
|
+ case Texture::F_alpha:
|
|
|
|
|
+ return GL_ALPHA;
|
|
|
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- if (CLP(force_mipmaps)) {
|
|
|
|
|
- uses_mipmaps = true;
|
|
|
|
|
|
|
+ case Texture::F_red:
|
|
|
|
|
+ case Texture::F_green:
|
|
|
|
|
+ case Texture::F_blue:
|
|
|
|
|
+ case Texture::F_luminance:
|
|
|
|
|
+ return GL_LUMINANCE;
|
|
|
|
|
+ case Texture::F_luminance_alpha:
|
|
|
|
|
+ case Texture::F_luminance_alphamask:
|
|
|
|
|
+ return GL_LUMINANCE_ALPHA;
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Invalid image format in get_internal_image_format(): "
|
|
|
|
|
+ << (int)format << "\n";
|
|
|
|
|
+ return GL_RGB;
|
|
|
}
|
|
}
|
|
|
-#endif
|
|
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- bool success = true;
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_external_texture_bytes
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Computes the number of bytes that should be in the
|
|
|
|
|
+// "external", or local, texture buffer before
|
|
|
|
|
+// transferring to OpenGL. This is just used for
|
|
|
|
|
+// sending data to PStats.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+int CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_external_texture_bytes(int width, int height, int depth,
|
|
|
|
|
+ GLint external_format, GLenum component_type) {
|
|
|
|
|
+ int num_components;
|
|
|
|
|
+ switch (external_format) {
|
|
|
|
|
+ case GL_COLOR_INDEX:
|
|
|
|
|
+ case GL_STENCIL_INDEX:
|
|
|
|
|
+ case GL_DEPTH_COMPONENT:
|
|
|
|
|
+ case GL_RED:
|
|
|
|
|
+ case GL_GREEN:
|
|
|
|
|
+ case GL_BLUE:
|
|
|
|
|
+ case GL_ALPHA:
|
|
|
|
|
+ case GL_LUMINANCE:
|
|
|
|
|
+ num_components = 1;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- if (tex->get_texture_type() == Texture::TT_cube_map) {
|
|
|
|
|
- // A cube map must load six different 2-d images (which are stored
|
|
|
|
|
- // as the six pages of the system ram image).
|
|
|
|
|
- if (!_supports_cube_map) {
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ case GL_LUMINANCE_ALPHA:
|
|
|
|
|
+ num_components = 2;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- size_t page_size = height * width * texel_size;
|
|
|
|
|
- const unsigned char *image_base = image;
|
|
|
|
|
-
|
|
|
|
|
- success = success && upload_texture_image
|
|
|
|
|
- (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
|
|
|
|
|
- internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
- image_base);
|
|
|
|
|
- image_base += page_size;
|
|
|
|
|
-
|
|
|
|
|
- success = success && upload_texture_image
|
|
|
|
|
- (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
|
|
|
|
- internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
- image_base);
|
|
|
|
|
- image_base += page_size;
|
|
|
|
|
-
|
|
|
|
|
- success = success && upload_texture_image
|
|
|
|
|
- (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
|
|
|
|
|
- internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
- image_base);
|
|
|
|
|
- image_base += page_size;
|
|
|
|
|
-
|
|
|
|
|
- success = success && upload_texture_image
|
|
|
|
|
- (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
|
|
|
|
- internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
- image_base);
|
|
|
|
|
- image_base += page_size;
|
|
|
|
|
-
|
|
|
|
|
- success = success && upload_texture_image
|
|
|
|
|
- (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
|
|
|
|
|
- internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
- image_base);
|
|
|
|
|
- image_base += page_size;
|
|
|
|
|
-
|
|
|
|
|
- success = success && upload_texture_image
|
|
|
|
|
- (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
|
|
|
|
- internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
- image_base);
|
|
|
|
|
- image_base += page_size;
|
|
|
|
|
-
|
|
|
|
|
- nassertr((size_t)(image_base - image) == image.size(), false);
|
|
|
|
|
|
|
+ case GL_BGR:
|
|
|
|
|
+ case GL_RGB:
|
|
|
|
|
+ num_components = 3;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- } else {
|
|
|
|
|
- // Any other kind of texture can be loaded all at once.
|
|
|
|
|
- success = upload_texture_image
|
|
|
|
|
- (gtc, uses_mipmaps, get_texture_target(tex->get_texture_type()),
|
|
|
|
|
- internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
- image);
|
|
|
|
|
|
|
+ case GL_BGRA:
|
|
|
|
|
+ case GL_RGBA:
|
|
|
|
|
+ num_components = 4;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Unexpected external_format in get_external_texture_bytes(): "
|
|
|
|
|
+ << hex << external_format << dec << "\n";
|
|
|
|
|
+ num_components = 3;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (success) {
|
|
|
|
|
- gtc->_already_applied = true;
|
|
|
|
|
- gtc->_internal_format = internal_format;
|
|
|
|
|
- gtc->_width = width;
|
|
|
|
|
- gtc->_height = height;
|
|
|
|
|
- gtc->_depth = depth;
|
|
|
|
|
|
|
+ int component_width;
|
|
|
|
|
+ switch (component_type) {
|
|
|
|
|
+ case GL_UNSIGNED_BYTE:
|
|
|
|
|
+ component_width = 1;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- if (uses_mipmaps && CLP(save_mipmaps)) {
|
|
|
|
|
- save_mipmap_images(tex);
|
|
|
|
|
- }
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+ case GL_UNSIGNED_SHORT:
|
|
|
|
|
+ component_width = 2;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
- return true;
|
|
|
|
|
|
|
+ case GL_FLOAT:
|
|
|
|
|
+ component_width = 4;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Unexpected component_type in get_external_texture_bytes(): "
|
|
|
|
|
+ << hex << component_type << dec << "\n";
|
|
|
|
|
+ component_width = 1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+ return width * height * depth * num_components * component_width;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::upload_texture_image
|
|
|
|
|
-// Access: Protected
|
|
|
|
|
-// Description: Loads a texture image, or one page of a cube map
|
|
|
|
|
-// image, from system RAM to texture memory.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_texture_apply_mode_type
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the texture stage's mode types
|
|
|
|
|
+// to the corresponding OpenGL ids
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-bool CLP(GraphicsStateGuardian)::
|
|
|
|
|
-upload_texture_image(CLP(TextureContext) *gtc,
|
|
|
|
|
- bool uses_mipmaps,
|
|
|
|
|
- GLenum target, GLint internal_format,
|
|
|
|
|
- int width, int height, int depth,
|
|
|
|
|
- GLint external_format, GLenum component_type,
|
|
|
|
|
- const unsigned char *image) {
|
|
|
|
|
- if (target == GL_NONE) {
|
|
|
|
|
- // Unsupported target (e.g. 3-d texturing on GL 1.1).
|
|
|
|
|
- return false;
|
|
|
|
|
|
|
+GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_texture_apply_mode_type(TextureStage::Mode am) {
|
|
|
|
|
+ switch (am) {
|
|
|
|
|
+ case TextureStage::M_modulate: return GL_MODULATE;
|
|
|
|
|
+ case TextureStage::M_decal: return GL_DECAL;
|
|
|
|
|
+ case TextureStage::M_blend: return GL_BLEND;
|
|
|
|
|
+ case TextureStage::M_replace: return GL_REPLACE;
|
|
|
|
|
+ case TextureStage::M_add: return GL_ADD;
|
|
|
|
|
+ case TextureStage::M_combine: return GL_COMBINE;
|
|
|
|
|
+ case TextureStage::M_blend_color_scale: return GL_BLEND;
|
|
|
}
|
|
}
|
|
|
- PStatTimer timer(_load_texture_pcollector);
|
|
|
|
|
-
|
|
|
|
|
- if (uses_mipmaps) {
|
|
|
|
|
-#ifndef NDEBUG
|
|
|
|
|
- if (CLP(show_mipmaps) && target == GL_TEXTURE_2D) {
|
|
|
|
|
- build_phony_mipmaps(gtc->_texture);
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
- return true;
|
|
|
|
|
-
|
|
|
|
|
- } else
|
|
|
|
|
-#endif
|
|
|
|
|
- if (!_supports_generate_mipmap || !auto_generate_mipmaps) {
|
|
|
|
|
- // We only need to build the mipmaps by hand if the GL
|
|
|
|
|
- // doesn't support generating them automatically.
|
|
|
|
|
- bool success = true;
|
|
|
|
|
-#ifdef DO_PSTATS
|
|
|
|
|
- _data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type) * 4 / 3);
|
|
|
|
|
-#endif
|
|
|
|
|
- switch (target) {
|
|
|
|
|
- case GL_TEXTURE_1D:
|
|
|
|
|
- GLUP(Build1DMipmaps)(target, internal_format, width,
|
|
|
|
|
- external_format, component_type, image);
|
|
|
|
|
- break;
|
|
|
|
|
|
|
|
|
|
- case GL_TEXTURE_3D:
|
|
|
|
|
-#ifdef GLU_VERSION_1_3
|
|
|
|
|
- GLUP(Build3DMipmaps)(target, internal_format,
|
|
|
|
|
- width, height, depth,
|
|
|
|
|
- external_format, component_type, image);
|
|
|
|
|
-#else // GLU_VERSION_1_3
|
|
|
|
|
- // Prior to GLU 1.3, there was no gluBuild3DMipmaps() call.
|
|
|
|
|
- // Just fall through and load the texture without mipmaps.
|
|
|
|
|
- GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
|
- success = false;
|
|
|
|
|
-#endif // GLU_VERSION_1_3
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Invalid TextureStage::Mode value" << endl;
|
|
|
|
|
+ return GL_MODULATE;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- default:
|
|
|
|
|
- GLUP(Build2DMipmaps)(target, internal_format,
|
|
|
|
|
- width, height,
|
|
|
|
|
- external_format, component_type, image);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_texture_combine_type
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the texture stage's CombineMode types
|
|
|
|
|
+// to the corresponding OpenGL ids
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_texture_combine_type(TextureStage::CombineMode cm) {
|
|
|
|
|
+ switch (cm) {
|
|
|
|
|
+ case TextureStage::CM_undefined: // fall through
|
|
|
|
|
+ case TextureStage::CM_replace: return GL_REPLACE;
|
|
|
|
|
+ case TextureStage::CM_modulate: return GL_MODULATE;
|
|
|
|
|
+ case TextureStage::CM_add: return GL_ADD;
|
|
|
|
|
+ case TextureStage::CM_add_signed: return GL_ADD_SIGNED;
|
|
|
|
|
+ case TextureStage::CM_interpolate: return GL_INTERPOLATE;
|
|
|
|
|
+ case TextureStage::CM_subtract: return GL_SUBTRACT;
|
|
|
|
|
+ case TextureStage::CM_dot3_rgb: return GL_DOT3_RGB;
|
|
|
|
|
+ case TextureStage::CM_dot3_rgba: return GL_DOT3_RGBA;
|
|
|
|
|
+ }
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Invalid TextureStage::CombineMode value" << endl;
|
|
|
|
|
+ return GL_REPLACE;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
- if (success) {
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_texture_src_type
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the texture stage's CombineSource types
|
|
|
|
|
+// to the corresponding OpenGL ids
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_texture_src_type(TextureStage::CombineSource cs) {
|
|
|
|
|
+ switch (cs) {
|
|
|
|
|
+ case TextureStage::CS_undefined: // fall through
|
|
|
|
|
+ case TextureStage::CS_texture: return GL_TEXTURE;
|
|
|
|
|
+ case TextureStage::CS_constant: return GL_CONSTANT;
|
|
|
|
|
+ case TextureStage::CS_primary_color: return GL_PRIMARY_COLOR;
|
|
|
|
|
+ case TextureStage::CS_previous: return GL_PREVIOUS;
|
|
|
|
|
+ case TextureStage::CS_constant_color_scale: return GL_CONSTANT;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!gtc->_already_applied ||
|
|
|
|
|
- gtc->_internal_format != internal_format ||
|
|
|
|
|
- gtc->_width != width ||
|
|
|
|
|
- gtc->_height != height ||
|
|
|
|
|
- gtc->_depth != depth) {
|
|
|
|
|
- // We need to reload a new image.
|
|
|
|
|
-#ifdef DO_PSTATS
|
|
|
|
|
- _data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type));
|
|
|
|
|
-#endif
|
|
|
|
|
- switch (target) {
|
|
|
|
|
- case GL_TEXTURE_1D:
|
|
|
|
|
- GLP(TexImage1D)(target, 0, internal_format,
|
|
|
|
|
- width, 0,
|
|
|
|
|
- external_format, component_type, image);
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Invalid TextureStage::CombineSource value" << endl;
|
|
|
|
|
+ return GL_TEXTURE;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- case GL_TEXTURE_3D:
|
|
|
|
|
- if (_supports_3d_texture) {
|
|
|
|
|
- _glTexImage3D(target, 0, internal_format,
|
|
|
|
|
- width, height, depth, 0,
|
|
|
|
|
- external_format, component_type, image);
|
|
|
|
|
- } else {
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_texture_operand_type
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the texture stage's CombineOperand types
|
|
|
|
|
+// to the corresponding OpenGL ids
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_texture_operand_type(TextureStage::CombineOperand co) {
|
|
|
|
|
+ switch (co) {
|
|
|
|
|
+ case TextureStage::CO_undefined: // fall through
|
|
|
|
|
+ case TextureStage::CO_src_alpha: return GL_SRC_ALPHA;
|
|
|
|
|
+ case TextureStage::CO_one_minus_src_alpha: return GL_ONE_MINUS_SRC_ALPHA;
|
|
|
|
|
+ case TextureStage::CO_src_color: return GL_SRC_COLOR;
|
|
|
|
|
+ case TextureStage::CO_one_minus_src_color: return GL_ONE_MINUS_SRC_COLOR;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- default:
|
|
|
|
|
- GLP(TexImage2D)(target, 0, internal_format,
|
|
|
|
|
- width, height, 0,
|
|
|
|
|
- external_format, component_type, image);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- // We can reload the image over the previous image, possibly
|
|
|
|
|
- // saving on texture memory fragmentation.
|
|
|
|
|
- switch (target) {
|
|
|
|
|
- case GL_TEXTURE_1D:
|
|
|
|
|
- GLP(TexSubImage1D)(target, 0, 0, width,
|
|
|
|
|
- external_format, component_type, image);
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case GL_TEXTURE_3D:
|
|
|
|
|
- if (_supports_3d_texture) {
|
|
|
|
|
- _glTexSubImage3D(target, 0, 0, 0, 0, width, height, depth,
|
|
|
|
|
- external_format, component_type, image);
|
|
|
|
|
- } else {
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Invalid TextureStage::CombineOperand value" << endl;
|
|
|
|
|
+ return GL_SRC_COLOR;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- default:
|
|
|
|
|
- GLP(TexSubImage2D)(target, 0, 0, 0, width, height,
|
|
|
|
|
- external_format, component_type, image);
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_fog_mode_type
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from the fog types to gl version
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_fog_mode_type(Fog::Mode m) {
|
|
|
|
|
+ switch(m) {
|
|
|
|
|
+ case Fog::M_linear: return GL_LINEAR;
|
|
|
|
|
+ case Fog::M_exponential: return GL_EXP;
|
|
|
|
|
+ case Fog::M_exponential_squared: return GL_EXP2;
|
|
|
|
|
+ /*
|
|
|
|
|
+ case Fog::M_spline: return GL_FOG_FUNC_SGIS;
|
|
|
|
|
+ */
|
|
|
|
|
|
|
|
- // Report the error message explicitly if the GL texture creation
|
|
|
|
|
- // failed.
|
|
|
|
|
- GLenum error_code = GLP(GetError)();
|
|
|
|
|
- if (error_code != GL_NO_ERROR) {
|
|
|
|
|
- const GLubyte *error_string = GLUP(ErrorString)(error_code);
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "GL texture creation failed for " << gtc->_texture->get_name();
|
|
|
|
|
- if (error_string != (const GLubyte *)NULL) {
|
|
|
|
|
- GLCAT.error(false)
|
|
|
|
|
- << " : " << error_string;
|
|
|
|
|
- }
|
|
|
|
|
- GLCAT.error(false)
|
|
|
|
|
- << "\n";
|
|
|
|
|
|
|
+ default:
|
|
|
|
|
+ GLCAT.error() << "Invalid Fog::Mode value" << endl;
|
|
|
|
|
+ return GL_EXP;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return true;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_numeric_type
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_blend_equation_type
|
|
|
// Access: Protected, Static
|
|
// Access: Protected, Static
|
|
|
-// Description: Maps from the Geom's internal numeric type symbols
|
|
|
|
|
-// to GL's.
|
|
|
|
|
|
|
+// Description: Maps from ColorBlendAttrib::Mode to glBlendEquation
|
|
|
|
|
+// value.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
GLenum CLP(GraphicsStateGuardian)::
|
|
GLenum CLP(GraphicsStateGuardian)::
|
|
|
-get_numeric_type(qpGeom::NumericType numeric_type) {
|
|
|
|
|
- switch (numeric_type) {
|
|
|
|
|
- case qpGeom::NT_uint16:
|
|
|
|
|
- return GL_UNSIGNED_SHORT;
|
|
|
|
|
-
|
|
|
|
|
- case qpGeom::NT_uint32:
|
|
|
|
|
- return GL_UNSIGNED_INT;
|
|
|
|
|
-
|
|
|
|
|
- case qpGeom::NT_uint8:
|
|
|
|
|
- case qpGeom::NT_packed_dcba:
|
|
|
|
|
- case qpGeom::NT_packed_dabc:
|
|
|
|
|
- return GL_UNSIGNED_BYTE;
|
|
|
|
|
|
|
+get_blend_equation_type(ColorBlendAttrib::Mode mode) {
|
|
|
|
|
+ switch (mode) {
|
|
|
|
|
+ case ColorBlendAttrib::M_none:
|
|
|
|
|
+ case ColorBlendAttrib::M_add:
|
|
|
|
|
+ return GL_FUNC_ADD;
|
|
|
|
|
|
|
|
- case qpGeom::NT_float32:
|
|
|
|
|
- return GL_FLOAT;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ case ColorBlendAttrib::M_subtract:
|
|
|
|
|
+ return GL_FUNC_SUBTRACT;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::M_inv_subtract:
|
|
|
|
|
+ return GL_FUNC_REVERSE_SUBTRACT;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::M_min:
|
|
|
|
|
+ return GL_MIN;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::M_max:
|
|
|
|
|
+ return GL_MAX;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
GLCAT.error()
|
|
GLCAT.error()
|
|
|
- << "Invalid NumericType value (" << (int)numeric_type << ")\n";
|
|
|
|
|
- return GL_UNSIGNED_BYTE;
|
|
|
|
|
|
|
+ << "Unknown color blend mode " << (int)mode << endl;
|
|
|
|
|
+ return GL_FUNC_ADD;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_texture_target
|
|
|
|
|
-// Access: Protected
|
|
|
|
|
-// Description: Maps from the Texture's texture type symbols to
|
|
|
|
|
-// GL's.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_blend_func
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Maps from ColorBlendAttrib::Operand to glBlendFunc
|
|
|
|
|
+// value.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
GLenum CLP(GraphicsStateGuardian)::
|
|
GLenum CLP(GraphicsStateGuardian)::
|
|
|
-get_texture_target(Texture::TextureType texture_type) const {
|
|
|
|
|
- switch (texture_type) {
|
|
|
|
|
- case Texture::TT_1d_texture:
|
|
|
|
|
- return GL_TEXTURE_1D;
|
|
|
|
|
|
|
+get_blend_func(ColorBlendAttrib::Operand operand) {
|
|
|
|
|
+ switch (operand) {
|
|
|
|
|
+ case ColorBlendAttrib::O_zero:
|
|
|
|
|
+ return GL_ZERO;
|
|
|
|
|
|
|
|
- case Texture::TT_2d_texture:
|
|
|
|
|
- return GL_TEXTURE_2D;
|
|
|
|
|
|
|
+ case ColorBlendAttrib::O_one:
|
|
|
|
|
+ return GL_ONE;
|
|
|
|
|
|
|
|
- case Texture::TT_3d_texture:
|
|
|
|
|
- if (_supports_3d_texture) {
|
|
|
|
|
- return GL_TEXTURE_3D;
|
|
|
|
|
- } else {
|
|
|
|
|
- return GL_NONE;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ case ColorBlendAttrib::O_incoming_color:
|
|
|
|
|
+ return GL_SRC_COLOR;
|
|
|
|
|
|
|
|
- case Texture::TT_cube_map:
|
|
|
|
|
- if (_supports_cube_map) {
|
|
|
|
|
- return GL_TEXTURE_CUBE_MAP;
|
|
|
|
|
- } else {
|
|
|
|
|
- return GL_NONE;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ case ColorBlendAttrib::O_one_minus_incoming_color:
|
|
|
|
|
+ return GL_ONE_MINUS_SRC_COLOR;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_fbuffer_color:
|
|
|
|
|
+ return GL_DST_COLOR;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_one_minus_fbuffer_color:
|
|
|
|
|
+ return GL_ONE_MINUS_DST_COLOR;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_incoming_alpha:
|
|
|
|
|
+ return GL_SRC_ALPHA;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_one_minus_incoming_alpha:
|
|
|
|
|
+ return GL_ONE_MINUS_SRC_ALPHA;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_fbuffer_alpha:
|
|
|
|
|
+ return GL_DST_ALPHA;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
|
|
|
|
|
+ return GL_ONE_MINUS_DST_ALPHA;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_constant_color:
|
|
|
|
|
+ case ColorBlendAttrib::O_color_scale:
|
|
|
|
|
+ return GL_CONSTANT_COLOR;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_one_minus_constant_color:
|
|
|
|
|
+ case ColorBlendAttrib::O_one_minus_color_scale:
|
|
|
|
|
+ return GL_ONE_MINUS_CONSTANT_COLOR;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_constant_alpha:
|
|
|
|
|
+ case ColorBlendAttrib::O_alpha_scale:
|
|
|
|
|
+ return GL_CONSTANT_ALPHA;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_one_minus_constant_alpha:
|
|
|
|
|
+ case ColorBlendAttrib::O_one_minus_alpha_scale:
|
|
|
|
|
+ return GL_ONE_MINUS_CONSTANT_ALPHA;
|
|
|
|
|
+
|
|
|
|
|
+ case ColorBlendAttrib::O_incoming_color_saturate:
|
|
|
|
|
+ return GL_SRC_ALPHA_SATURATE;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- GLCAT.error() << "Invalid Texture::TextureType value!\n";
|
|
|
|
|
- return GL_TEXTURE_2D;
|
|
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Unknown color blend operand " << (int)operand << endl;
|
|
|
|
|
+ return GL_ZERO;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_texture_wrap_mode
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from the Texture's internal wrap mode symbols to
|
|
|
|
|
-// GL's.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_usage
|
|
|
|
|
+// Access: Public, Static
|
|
|
|
|
+// Description: Maps from UsageHint to the GL symbol.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
GLenum CLP(GraphicsStateGuardian)::
|
|
GLenum CLP(GraphicsStateGuardian)::
|
|
|
-get_texture_wrap_mode(Texture::WrapMode wm) {
|
|
|
|
|
- if (CLP(ignore_clamp)) {
|
|
|
|
|
- return GL_REPEAT;
|
|
|
|
|
- }
|
|
|
|
|
- switch (wm) {
|
|
|
|
|
- case Texture::WM_clamp:
|
|
|
|
|
- return _edge_clamp;
|
|
|
|
|
-
|
|
|
|
|
- case Texture::WM_repeat:
|
|
|
|
|
- return GL_REPEAT;
|
|
|
|
|
-
|
|
|
|
|
- case Texture::WM_mirror:
|
|
|
|
|
- return _mirror_repeat;
|
|
|
|
|
|
|
+get_usage(qpGeom::UsageHint usage_hint) {
|
|
|
|
|
+ switch (usage_hint) {
|
|
|
|
|
+ case qpGeom::UH_stream:
|
|
|
|
|
+ return GL_STREAM_DRAW;
|
|
|
|
|
|
|
|
- case Texture::WM_mirror_once:
|
|
|
|
|
- return _mirror_border_clamp;
|
|
|
|
|
|
|
+ case qpGeom::UH_static:
|
|
|
|
|
+ case qpGeom::UH_unspecified:
|
|
|
|
|
+ return GL_STATIC_DRAW;
|
|
|
|
|
|
|
|
- case Texture::WM_border_color:
|
|
|
|
|
- return _border_clamp;
|
|
|
|
|
|
|
+ case qpGeom::UH_dynamic:
|
|
|
|
|
+ return GL_DYNAMIC_DRAW;
|
|
|
|
|
|
|
|
- case Texture::WM_invalid:
|
|
|
|
|
|
|
+ case qpGeom::UH_client:
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- GLCAT.error() << "Invalid Texture::WrapMode value!\n";
|
|
|
|
|
- return _edge_clamp;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "Unexpected usage_hint " << (int)usage_hint << endl;
|
|
|
|
|
+ return GL_STATIC_DRAW;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_texture_filter_type
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from the Texture's internal filter type symbols
|
|
|
|
|
-// to GL's.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::print_gfx_visual
|
|
|
|
|
+// Access: Public
|
|
|
|
|
+// Description: Prints a description of the current visual selected.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps) {
|
|
|
|
|
- if (CLP(ignore_filters)) {
|
|
|
|
|
- return GL_NEAREST;
|
|
|
|
|
-
|
|
|
|
|
- } else if (ignore_mipmaps) {
|
|
|
|
|
- switch (ft) {
|
|
|
|
|
- case Texture::FT_nearest_mipmap_nearest:
|
|
|
|
|
- case Texture::FT_nearest:
|
|
|
|
|
- return GL_NEAREST;
|
|
|
|
|
- case Texture::FT_linear:
|
|
|
|
|
- case Texture::FT_linear_mipmap_nearest:
|
|
|
|
|
- case Texture::FT_nearest_mipmap_linear:
|
|
|
|
|
- case Texture::FT_linear_mipmap_linear:
|
|
|
|
|
- return GL_LINEAR;
|
|
|
|
|
- case Texture::FT_invalid:
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+print_gfx_visual() {
|
|
|
|
|
+ GLint i;
|
|
|
|
|
+ GLboolean j;
|
|
|
|
|
+ cout << "Graphics Visual Info (# bits of each):" << endl;
|
|
|
|
|
|
|
|
- } else {
|
|
|
|
|
- switch (ft) {
|
|
|
|
|
- case Texture::FT_nearest:
|
|
|
|
|
- return GL_NEAREST;
|
|
|
|
|
- case Texture::FT_linear:
|
|
|
|
|
- return GL_LINEAR;
|
|
|
|
|
- case Texture::FT_nearest_mipmap_nearest:
|
|
|
|
|
- return GL_NEAREST_MIPMAP_NEAREST;
|
|
|
|
|
- case Texture::FT_linear_mipmap_nearest:
|
|
|
|
|
- return GL_LINEAR_MIPMAP_NEAREST;
|
|
|
|
|
- case Texture::FT_nearest_mipmap_linear:
|
|
|
|
|
- return GL_NEAREST_MIPMAP_LINEAR;
|
|
|
|
|
- case Texture::FT_linear_mipmap_linear:
|
|
|
|
|
- return GL_LINEAR_MIPMAP_LINEAR;
|
|
|
|
|
- case Texture::FT_invalid:
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ cout << "RGBA: ";
|
|
|
|
|
+ GLP(GetIntegerv)( GL_RED_BITS, &i ); cout << i << " ";
|
|
|
|
|
+ GLP(GetIntegerv)( GL_GREEN_BITS, &i ); cout << i << " ";
|
|
|
|
|
+ GLP(GetIntegerv)( GL_BLUE_BITS, &i ); cout << i << " ";
|
|
|
|
|
+ GLP(GetIntegerv)( GL_ALPHA_BITS, &i ); cout << i << endl;
|
|
|
|
|
+
|
|
|
|
|
+ cout << "Accum RGBA: ";
|
|
|
|
|
+ GLP(GetIntegerv)( GL_ACCUM_RED_BITS, &i ); cout << i << " ";
|
|
|
|
|
+ GLP(GetIntegerv)( GL_ACCUM_GREEN_BITS, &i ); cout << i << " ";
|
|
|
|
|
+ GLP(GetIntegerv)( GL_ACCUM_BLUE_BITS, &i ); cout << i << " ";
|
|
|
|
|
+ GLP(GetIntegerv)( GL_ACCUM_ALPHA_BITS, &i ); cout << i << endl;
|
|
|
|
|
+
|
|
|
|
|
+ GLP(GetIntegerv)( GL_INDEX_BITS, &i ); cout << "Color Index: " << i << endl;
|
|
|
|
|
+
|
|
|
|
|
+ GLP(GetIntegerv)( GL_DEPTH_BITS, &i ); cout << "Depth: " << i << endl;
|
|
|
|
|
+ GLP(GetIntegerv)( GL_ALPHA_BITS, &i ); cout << "Alpha: " << i << endl;
|
|
|
|
|
+ GLP(GetIntegerv)( GL_STENCIL_BITS, &i ); cout << "Stencil: " << i << endl;
|
|
|
|
|
+
|
|
|
|
|
+ GLP(GetBooleanv)( GL_DOUBLEBUFFER, &j ); cout << "DoubleBuffer? "
|
|
|
|
|
+ << (int)j << endl;
|
|
|
|
|
+
|
|
|
|
|
+ GLP(GetBooleanv)( GL_STEREO, &j ); cout << "Stereo? " << (int)j << endl;
|
|
|
|
|
+
|
|
|
|
|
+ if (_supports_multisample) {
|
|
|
|
|
+ GLP(GetBooleanv)( GL_MULTISAMPLE, &j ); cout << "Multisample? " << (int)j << endl;
|
|
|
|
|
+ GLP(GetIntegerv)( GL_SAMPLES, &i ); cout << "Samples: " << i << endl;
|
|
|
}
|
|
}
|
|
|
- GLCAT.error() << "Invalid Texture::FilterType value!\n";
|
|
|
|
|
- return GL_NEAREST;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ GLP(GetBooleanv)( GL_BLEND, &j ); cout << "Blend? " << (int)j << endl;
|
|
|
|
|
+ GLP(GetBooleanv)( GL_POINT_SMOOTH, &j ); cout << "Point Smooth? "
|
|
|
|
|
+ << (int)j << endl;
|
|
|
|
|
+ GLP(GetBooleanv)( GL_LINE_SMOOTH, &j ); cout << "Line Smooth? "
|
|
|
|
|
+ << (int)j << endl;
|
|
|
|
|
+
|
|
|
|
|
+ GLP(GetIntegerv)( GL_AUX_BUFFERS, &i ); cout << "Aux Buffers: " << i << endl;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_component_type
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from the Texture's internal ComponentType symbols
|
|
|
|
|
-// to GL's.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::issue_scaled_color
|
|
|
|
|
+// Access: Public
|
|
|
|
|
+// Description: Transform the color by the current color matrix, and
|
|
|
|
|
+// calls the appropriate glColor function.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_component_type(Texture::ComponentType component_type) {
|
|
|
|
|
- switch (component_type) {
|
|
|
|
|
- case Texture::T_unsigned_byte:
|
|
|
|
|
- return GL_UNSIGNED_BYTE;
|
|
|
|
|
- case Texture::T_unsigned_short:
|
|
|
|
|
- return GL_UNSIGNED_SHORT;
|
|
|
|
|
- case Texture::T_float:
|
|
|
|
|
- return GL_FLOAT;
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+issue_scaled_color(const Colorf &color) const {
|
|
|
|
|
+ Colorf transformed
|
|
|
|
|
+ (color[0] * _current_color_scale[0],
|
|
|
|
|
+ color[1] * _current_color_scale[1],
|
|
|
|
|
+ color[2] * _current_color_scale[2],
|
|
|
|
|
+ color[3] * _current_color_scale[3]);
|
|
|
|
|
|
|
|
- default:
|
|
|
|
|
- GLCAT.error() << "Invalid Texture::Type value!\n";
|
|
|
|
|
- return GL_UNSIGNED_BYTE;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ GLP(Color4fv)(transformed.get_data());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_external_image_format
|
|
|
|
|
-// Access: Protected
|
|
|
|
|
-// Description: Maps from the Texture's Format symbols
|
|
|
|
|
-// to GL's.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::slot_new_light
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: This will be called by the base class before a
|
|
|
|
|
+// particular light id will be used for the first time.
|
|
|
|
|
+// It is intended to allow the derived class to reserve
|
|
|
|
|
+// any additional resources, if required, for the new
|
|
|
|
|
+// light; and also to indicate whether the hardware
|
|
|
|
|
+// supports this many simultaneous lights.
|
|
|
|
|
+//
|
|
|
|
|
+// The return value should be true if the additional
|
|
|
|
|
+// light is supported, or false if it is not.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_external_image_format(Texture::Format format) const {
|
|
|
|
|
- switch (format) {
|
|
|
|
|
- case Texture::F_color_index:
|
|
|
|
|
- return GL_COLOR_INDEX;
|
|
|
|
|
- case Texture::F_stencil_index:
|
|
|
|
|
- return GL_STENCIL_INDEX;
|
|
|
|
|
- case Texture::F_depth_component:
|
|
|
|
|
- return GL_DEPTH_COMPONENT;
|
|
|
|
|
- case Texture::F_red:
|
|
|
|
|
- return GL_RED;
|
|
|
|
|
- case Texture::F_green:
|
|
|
|
|
- return GL_GREEN;
|
|
|
|
|
- case Texture::F_blue:
|
|
|
|
|
- return GL_BLUE;
|
|
|
|
|
- case Texture::F_alpha:
|
|
|
|
|
- return GL_ALPHA;
|
|
|
|
|
- case Texture::F_rgb:
|
|
|
|
|
- case Texture::F_rgb5:
|
|
|
|
|
- case Texture::F_rgb8:
|
|
|
|
|
- case Texture::F_rgb12:
|
|
|
|
|
- case Texture::F_rgb332:
|
|
|
|
|
- return _supports_bgr ? GL_BGR : GL_RGB;
|
|
|
|
|
- case Texture::F_rgba:
|
|
|
|
|
- case Texture::F_rgbm:
|
|
|
|
|
- case Texture::F_rgba4:
|
|
|
|
|
- case Texture::F_rgba5:
|
|
|
|
|
- case Texture::F_rgba8:
|
|
|
|
|
- case Texture::F_rgba12:
|
|
|
|
|
- return _supports_bgr ? GL_BGRA : GL_RGBA;
|
|
|
|
|
- case Texture::F_luminance:
|
|
|
|
|
- return GL_LUMINANCE;
|
|
|
|
|
- case Texture::F_luminance_alphamask:
|
|
|
|
|
- case Texture::F_luminance_alpha:
|
|
|
|
|
- return GL_LUMINANCE_ALPHA;
|
|
|
|
|
- }
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Invalid Texture::Format value in get_external_image_format(): "
|
|
|
|
|
- << (int)format << "\n";
|
|
|
|
|
- return GL_RGB;
|
|
|
|
|
|
|
+bool CLP(GraphicsStateGuardian)::
|
|
|
|
|
+slot_new_light(int light_id) {
|
|
|
|
|
+ return (light_id < _max_lights);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_internal_image_format
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from the Texture's Format symbols to a
|
|
|
|
|
-// suitable internal format for GL textures.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::enable_lighting
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Intended to be overridden by a derived class to
|
|
|
|
|
+// enable or disable the use of lighting overall. This
|
|
|
|
|
+// is called by issue_light() according to whether any
|
|
|
|
|
+// lights are in use or not.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_internal_image_format(Texture::Format format) {
|
|
|
|
|
- switch (format) {
|
|
|
|
|
- case Texture::F_rgba:
|
|
|
|
|
- case Texture::F_rgbm:
|
|
|
|
|
- return GL_RGBA;
|
|
|
|
|
- case Texture::F_rgba4:
|
|
|
|
|
- return GL_RGBA4;
|
|
|
|
|
- case Texture::F_rgba8:
|
|
|
|
|
- return GL_RGBA8;
|
|
|
|
|
- case Texture::F_rgba12:
|
|
|
|
|
- return GL_RGBA12;
|
|
|
|
|
-
|
|
|
|
|
- case Texture::F_rgb:
|
|
|
|
|
- return GL_RGB;
|
|
|
|
|
- case Texture::F_rgb5:
|
|
|
|
|
- return GL_RGB5;
|
|
|
|
|
- case Texture::F_rgba5:
|
|
|
|
|
- return GL_RGB5_A1;
|
|
|
|
|
- case Texture::F_rgb8:
|
|
|
|
|
- return GL_RGB8;
|
|
|
|
|
- case Texture::F_rgb12:
|
|
|
|
|
- return GL_RGB12;
|
|
|
|
|
- case Texture::F_rgb332:
|
|
|
|
|
- return GL_R3_G3_B2;
|
|
|
|
|
-
|
|
|
|
|
- case Texture::F_alpha:
|
|
|
|
|
- return GL_ALPHA;
|
|
|
|
|
-
|
|
|
|
|
- case Texture::F_red:
|
|
|
|
|
- case Texture::F_green:
|
|
|
|
|
- case Texture::F_blue:
|
|
|
|
|
- case Texture::F_luminance:
|
|
|
|
|
- return GL_LUMINANCE;
|
|
|
|
|
- case Texture::F_luminance_alpha:
|
|
|
|
|
- case Texture::F_luminance_alphamask:
|
|
|
|
|
- return GL_LUMINANCE_ALPHA;
|
|
|
|
|
-
|
|
|
|
|
- default:
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Invalid image format in get_internal_image_format(): "
|
|
|
|
|
- << (int)format << "\n";
|
|
|
|
|
- return GL_RGB;
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+enable_lighting(bool enable) {
|
|
|
|
|
+ if (enable) {
|
|
|
|
|
+ GLP(Enable)(GL_LIGHTING);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ GLP(Disable)(GL_LIGHTING);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_external_texture_bytes
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Computes the number of bytes that should be in the
|
|
|
|
|
-// "external", or local, texture buffer before
|
|
|
|
|
-// transferring to OpenGL. This is just used for
|
|
|
|
|
-// sending data to PStats.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::set_ambient_light
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Intended to be overridden by a derived class to
|
|
|
|
|
+// indicate the color of the ambient light that should
|
|
|
|
|
+// be in effect. This is called by issue_light() after
|
|
|
|
|
+// all other lights have been enabled or disabled.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-int CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_external_texture_bytes(int width, int height, int depth,
|
|
|
|
|
- GLint external_format, GLenum component_type) {
|
|
|
|
|
- int num_components;
|
|
|
|
|
- switch (external_format) {
|
|
|
|
|
- case GL_COLOR_INDEX:
|
|
|
|
|
- case GL_STENCIL_INDEX:
|
|
|
|
|
- case GL_DEPTH_COMPONENT:
|
|
|
|
|
- case GL_RED:
|
|
|
|
|
- case GL_GREEN:
|
|
|
|
|
- case GL_BLUE:
|
|
|
|
|
- case GL_ALPHA:
|
|
|
|
|
- case GL_LUMINANCE:
|
|
|
|
|
- num_components = 1;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case GL_LUMINANCE_ALPHA:
|
|
|
|
|
- num_components = 2;
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+set_ambient_light(const Colorf &color) {
|
|
|
|
|
+ GLP(LightModelfv)(GL_LIGHT_MODEL_AMBIENT, color.get_data());
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- case GL_BGR:
|
|
|
|
|
- case GL_RGB:
|
|
|
|
|
- num_components = 3;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case GL_BGRA:
|
|
|
|
|
- case GL_RGBA:
|
|
|
|
|
- num_components = 4;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- default:
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Unexpected external_format in get_external_texture_bytes(): "
|
|
|
|
|
- << hex << external_format << dec << "\n";
|
|
|
|
|
- num_components = 3;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int component_width;
|
|
|
|
|
- switch (component_type) {
|
|
|
|
|
- case GL_UNSIGNED_BYTE:
|
|
|
|
|
- component_width = 1;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case GL_UNSIGNED_SHORT:
|
|
|
|
|
- component_width = 2;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case GL_FLOAT:
|
|
|
|
|
- component_width = 4;
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- default:
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Unexpected component_type in get_external_texture_bytes(): "
|
|
|
|
|
- << hex << component_type << dec << "\n";
|
|
|
|
|
- component_width = 1;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return width * height * depth * num_components * component_width;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::enable_light
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Intended to be overridden by a derived class to
|
|
|
|
|
+// enable the indicated light id. A specific Light will
|
|
|
|
|
+// already have been bound to this id via bind_light().
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+enable_light(int light_id, bool enable) {
|
|
|
|
|
+ if (enable) {
|
|
|
|
|
+ GLP(Enable)(get_light_id(light_id));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ GLP(Disable)(get_light_id(light_id));
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_texture_apply_mode_type
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from the texture stage's mode types
|
|
|
|
|
-// to the corresponding OpenGL ids
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::begin_bind_lights
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Called immediately before bind_light() is called,
|
|
|
|
|
+// this is intended to provide the derived class a hook
|
|
|
|
|
+// in which to set up some state (like transform) that
|
|
|
|
|
+// might apply to several lights.
|
|
|
|
|
+//
|
|
|
|
|
+// The sequence is: begin_bind_lights() will be called,
|
|
|
|
|
+// then one or more bind_light() calls, then
|
|
|
|
|
+// end_bind_lights().
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_texture_apply_mode_type(TextureStage::Mode am) {
|
|
|
|
|
- switch (am) {
|
|
|
|
|
- case TextureStage::M_modulate: return GL_MODULATE;
|
|
|
|
|
- case TextureStage::M_decal: return GL_DECAL;
|
|
|
|
|
- case TextureStage::M_blend: return GL_BLEND;
|
|
|
|
|
- case TextureStage::M_replace: return GL_REPLACE;
|
|
|
|
|
- case TextureStage::M_add: return GL_ADD;
|
|
|
|
|
- case TextureStage::M_combine: return GL_COMBINE;
|
|
|
|
|
- case TextureStage::M_blend_color_scale: return GL_BLEND;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Invalid TextureStage::Mode value" << endl;
|
|
|
|
|
- return GL_MODULATE;
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+begin_bind_lights() {
|
|
|
|
|
+ // We need to temporarily load a new matrix so we can define the
|
|
|
|
|
+ // light in a known coordinate system. We pick the transform of the
|
|
|
|
|
+ // root. (Alternatively, we could leave the current transform where
|
|
|
|
|
+ // it is and compute the light position relative to that transform
|
|
|
|
|
+ // instead of relative to the root, by composing with the matrix
|
|
|
|
|
+ // computed by _transform->invert_compose(render_transform). But I
|
|
|
|
|
+ // think loading a completely new matrix is simpler.)
|
|
|
|
|
+ GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
+ GLP(PushMatrix)();
|
|
|
|
|
+ GLP(LoadMatrixf)(_scene_setup->get_render_transform()->get_mat().get_data());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_texture_combine_type
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from the texture stage's CombineMode types
|
|
|
|
|
-// to the corresponding OpenGL ids
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::end_bind_lights
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Called after before bind_light() has been called one
|
|
|
|
|
+// or more times (but before any geometry is issued or
|
|
|
|
|
+// additional state is changed), this is intended to
|
|
|
|
|
+// clean up any temporary changes to the state that may
|
|
|
|
|
+// have been made by begin_bind_lights().
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_texture_combine_type(TextureStage::CombineMode cm) {
|
|
|
|
|
- switch (cm) {
|
|
|
|
|
- case TextureStage::CM_undefined: // fall through
|
|
|
|
|
- case TextureStage::CM_replace: return GL_REPLACE;
|
|
|
|
|
- case TextureStage::CM_modulate: return GL_MODULATE;
|
|
|
|
|
- case TextureStage::CM_add: return GL_ADD;
|
|
|
|
|
- case TextureStage::CM_add_signed: return GL_ADD_SIGNED;
|
|
|
|
|
- case TextureStage::CM_interpolate: return GL_INTERPOLATE;
|
|
|
|
|
- case TextureStage::CM_subtract: return GL_SUBTRACT;
|
|
|
|
|
- case TextureStage::CM_dot3_rgb: return GL_DOT3_RGB;
|
|
|
|
|
- case TextureStage::CM_dot3_rgba: return GL_DOT3_RGBA;
|
|
|
|
|
- }
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Invalid TextureStage::CombineMode value" << endl;
|
|
|
|
|
- return GL_REPLACE;
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+end_bind_lights() {
|
|
|
|
|
+ GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
+ GLP(PopMatrix)();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_texture_src_type
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from the texture stage's CombineSource types
|
|
|
|
|
-// to the corresponding OpenGL ids
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::slot_new_clip_plane
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: This will be called by the base class before a
|
|
|
|
|
+// particular clip plane id will be used for the first
|
|
|
|
|
+// time. It is intended to allow the derived class to
|
|
|
|
|
+// reserve any additional resources, if required, for
|
|
|
|
|
+// the new clip plane; and also to indicate whether the
|
|
|
|
|
+// hardware supports this many simultaneous clipping
|
|
|
|
|
+// planes.
|
|
|
|
|
+//
|
|
|
|
|
+// The return value should be true if the additional
|
|
|
|
|
+// plane is supported, or false if it is not.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_texture_src_type(TextureStage::CombineSource cs) {
|
|
|
|
|
- switch (cs) {
|
|
|
|
|
- case TextureStage::CS_undefined: // fall through
|
|
|
|
|
- case TextureStage::CS_texture: return GL_TEXTURE;
|
|
|
|
|
- case TextureStage::CS_constant: return GL_CONSTANT;
|
|
|
|
|
- case TextureStage::CS_primary_color: return GL_PRIMARY_COLOR;
|
|
|
|
|
- case TextureStage::CS_previous: return GL_PREVIOUS;
|
|
|
|
|
- case TextureStage::CS_constant_color_scale: return GL_CONSTANT;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Invalid TextureStage::CombineSource value" << endl;
|
|
|
|
|
- return GL_TEXTURE;
|
|
|
|
|
|
|
+bool CLP(GraphicsStateGuardian)::
|
|
|
|
|
+slot_new_clip_plane(int plane_id) {
|
|
|
|
|
+ return (plane_id < _max_clip_planes);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_texture_operand_type
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from the texture stage's CombineOperand types
|
|
|
|
|
-// to the corresponding OpenGL ids
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::enable_clip_plane
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Intended to be overridden by a derived class to
|
|
|
|
|
+// enable the indicated clip_plane id. A specific
|
|
|
|
|
+// PlaneNode will already have been bound to this id via
|
|
|
|
|
+// bind_clip_plane().
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLint CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_texture_operand_type(TextureStage::CombineOperand co) {
|
|
|
|
|
- switch (co) {
|
|
|
|
|
- case TextureStage::CO_undefined: // fall through
|
|
|
|
|
- case TextureStage::CO_src_alpha: return GL_SRC_ALPHA;
|
|
|
|
|
- case TextureStage::CO_one_minus_src_alpha: return GL_ONE_MINUS_SRC_ALPHA;
|
|
|
|
|
- case TextureStage::CO_src_color: return GL_SRC_COLOR;
|
|
|
|
|
- case TextureStage::CO_one_minus_src_color: return GL_ONE_MINUS_SRC_COLOR;
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+enable_clip_plane(int plane_id, bool enable) {
|
|
|
|
|
+ if (enable) {
|
|
|
|
|
+ GLP(Enable)(get_clip_plane_id(plane_id));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ GLP(Disable)(get_clip_plane_id(plane_id));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Invalid TextureStage::CombineOperand value" << endl;
|
|
|
|
|
- return GL_SRC_COLOR;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_fog_mode_type
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from the fog types to gl version
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::begin_bind_clip_planes
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Called immediately before bind_clip_plane() is called,
|
|
|
|
|
+// this is intended to provide the derived class a hook
|
|
|
|
|
+// in which to set up some state (like transform) that
|
|
|
|
|
+// might apply to several clip_planes.
|
|
|
|
|
+//
|
|
|
|
|
+// The sequence is: begin_bind_clip_planes() will be called,
|
|
|
|
|
+// then one or more bind_clip_plane() calls, then
|
|
|
|
|
+// end_bind_clip_planes().
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_fog_mode_type(Fog::Mode m) {
|
|
|
|
|
- switch(m) {
|
|
|
|
|
- case Fog::M_linear: return GL_LINEAR;
|
|
|
|
|
- case Fog::M_exponential: return GL_EXP;
|
|
|
|
|
- case Fog::M_exponential_squared: return GL_EXP2;
|
|
|
|
|
- /*
|
|
|
|
|
- case Fog::M_spline: return GL_FOG_FUNC_SGIS;
|
|
|
|
|
- */
|
|
|
|
|
-
|
|
|
|
|
- default:
|
|
|
|
|
- GLCAT.error() << "Invalid Fog::Mode value" << endl;
|
|
|
|
|
- return GL_EXP;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+begin_bind_clip_planes() {
|
|
|
|
|
+ // We need to temporarily load a new matrix so we can define the
|
|
|
|
|
+ // clip_plane in a known coordinate system. We pick the transform of the
|
|
|
|
|
+ // root. (Alternatively, we could leave the current transform where
|
|
|
|
|
+ // it is and compute the clip_plane position relative to that transform
|
|
|
|
|
+ // instead of relative to the root, by composing with the matrix
|
|
|
|
|
+ // computed by _transform->invert_compose(render_transform). But I
|
|
|
|
|
+ // think loading a completely new matrix is simpler.)
|
|
|
|
|
+ GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
+ GLP(PushMatrix)();
|
|
|
|
|
+ GLP(LoadMatrixf)(_scene_setup->get_render_transform()->get_mat().get_data());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_blend_equation_type
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from ColorBlendAttrib::Mode to glBlendEquation
|
|
|
|
|
-// value.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::bind_clip_plane
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Called the first time a particular clip_plane has been
|
|
|
|
|
+// bound to a given id within a frame, this should set
|
|
|
|
|
+// up the associated hardware clip_plane with the clip_plane's
|
|
|
|
|
+// properties.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_blend_equation_type(ColorBlendAttrib::Mode mode) {
|
|
|
|
|
- switch (mode) {
|
|
|
|
|
- case ColorBlendAttrib::M_none:
|
|
|
|
|
- case ColorBlendAttrib::M_add:
|
|
|
|
|
- return GL_FUNC_ADD;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::M_subtract:
|
|
|
|
|
- return GL_FUNC_SUBTRACT;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::M_inv_subtract:
|
|
|
|
|
- return GL_FUNC_REVERSE_SUBTRACT;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::M_min:
|
|
|
|
|
- return GL_MIN;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::M_max:
|
|
|
|
|
- return GL_MAX;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+bind_clip_plane(const NodePath &plane, int plane_id) {
|
|
|
|
|
+ GLenum id = get_clip_plane_id(plane_id);
|
|
|
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Unknown color blend mode " << (int)mode << endl;
|
|
|
|
|
- return GL_FUNC_ADD;
|
|
|
|
|
|
|
+ CPT(TransformState) transform = plane.get_transform(_scene_setup->get_scene_root());
|
|
|
|
|
+ const PlaneNode *plane_node;
|
|
|
|
|
+ DCAST_INTO_V(plane_node, plane.node());
|
|
|
|
|
+ Planef xformed_plane = plane_node->get_plane() * transform->get_mat();
|
|
|
|
|
+
|
|
|
|
|
+ Planed double_plane(LCAST(double, xformed_plane));
|
|
|
|
|
+ GLP(ClipPlane)(id, double_plane.get_data());
|
|
|
|
|
+
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_blend_func
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Maps from ColorBlendAttrib::Operand to glBlendFunc
|
|
|
|
|
-// value.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_blend_func(ColorBlendAttrib::Operand operand) {
|
|
|
|
|
- switch (operand) {
|
|
|
|
|
- case ColorBlendAttrib::O_zero:
|
|
|
|
|
- return GL_ZERO;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_one:
|
|
|
|
|
- return GL_ONE;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_incoming_color:
|
|
|
|
|
- return GL_SRC_COLOR;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_one_minus_incoming_color:
|
|
|
|
|
- return GL_ONE_MINUS_SRC_COLOR;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_fbuffer_color:
|
|
|
|
|
- return GL_DST_COLOR;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_one_minus_fbuffer_color:
|
|
|
|
|
- return GL_ONE_MINUS_DST_COLOR;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_incoming_alpha:
|
|
|
|
|
- return GL_SRC_ALPHA;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_one_minus_incoming_alpha:
|
|
|
|
|
- return GL_ONE_MINUS_SRC_ALPHA;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_fbuffer_alpha:
|
|
|
|
|
- return GL_DST_ALPHA;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
|
|
|
|
|
- return GL_ONE_MINUS_DST_ALPHA;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_constant_color:
|
|
|
|
|
- case ColorBlendAttrib::O_color_scale:
|
|
|
|
|
- return GL_CONSTANT_COLOR;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_one_minus_constant_color:
|
|
|
|
|
- case ColorBlendAttrib::O_one_minus_color_scale:
|
|
|
|
|
- return GL_ONE_MINUS_CONSTANT_COLOR;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_constant_alpha:
|
|
|
|
|
- case ColorBlendAttrib::O_alpha_scale:
|
|
|
|
|
- return GL_CONSTANT_ALPHA;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_one_minus_constant_alpha:
|
|
|
|
|
- case ColorBlendAttrib::O_one_minus_alpha_scale:
|
|
|
|
|
- return GL_ONE_MINUS_CONSTANT_ALPHA;
|
|
|
|
|
-
|
|
|
|
|
- case ColorBlendAttrib::O_incoming_color_saturate:
|
|
|
|
|
- return GL_SRC_ALPHA_SATURATE;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Unknown color blend operand " << (int)operand << endl;
|
|
|
|
|
- return GL_ZERO;
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::end_bind_clip_planes
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Called after before bind_clip_plane() has been called one
|
|
|
|
|
+// or more times (but before any geometry is issued or
|
|
|
|
|
+// additional state is changed), this is intended to
|
|
|
|
|
+// clean up any temporary changes to the state that may
|
|
|
|
|
+// have been made by begin_bind_clip_planes().
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+end_bind_clip_planes() {
|
|
|
|
|
+ GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
+ GLP(PopMatrix)();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_usage
|
|
|
|
|
-// Access: Public, Static
|
|
|
|
|
-// Description: Maps from UsageHint to the GL symbol.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::set_blend_mode
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Called after any of the things that might change
|
|
|
|
|
+// blending state have changed, this function is
|
|
|
|
|
+// responsible for setting the appropriate color
|
|
|
|
|
+// blending mode based on the current properties.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-GLenum CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_usage(qpGeom::UsageHint usage_hint) {
|
|
|
|
|
- switch (usage_hint) {
|
|
|
|
|
- case qpGeom::UH_stream:
|
|
|
|
|
- return GL_STREAM_DRAW;
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+set_blend_mode() {
|
|
|
|
|
+ // If color_write_mode is off, we disable writing to the color using
|
|
|
|
|
+ // blending. This case is only used if we can't use GLP(ColorMask) to
|
|
|
|
|
+ // disable the color writing for some reason (usually a driver
|
|
|
|
|
+ // problem).
|
|
|
|
|
+ if (_color_write_mode == ColorWriteAttrib::M_off) {
|
|
|
|
|
+ enable_multisample_alpha_one(false);
|
|
|
|
|
+ enable_multisample_alpha_mask(false);
|
|
|
|
|
+ enable_blend(true);
|
|
|
|
|
+ _glBlendEquation(GL_FUNC_ADD);
|
|
|
|
|
+ GLP(BlendFunc)(GL_ZERO, GL_ONE);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- case qpGeom::UH_static:
|
|
|
|
|
- case qpGeom::UH_unspecified:
|
|
|
|
|
- return GL_STATIC_DRAW;
|
|
|
|
|
|
|
+ // Is there a color blend set?
|
|
|
|
|
+ if (_color_blend_mode != ColorBlendAttrib::M_none) {
|
|
|
|
|
+ enable_multisample_alpha_one(false);
|
|
|
|
|
+ enable_multisample_alpha_mask(false);
|
|
|
|
|
+ enable_blend(true);
|
|
|
|
|
+ _glBlendEquation(get_blend_equation_type(_color_blend_mode));
|
|
|
|
|
+ GLP(BlendFunc)(get_blend_func(_color_blend->get_operand_a()),
|
|
|
|
|
+ get_blend_func(_color_blend->get_operand_b()));
|
|
|
|
|
|
|
|
- case qpGeom::UH_dynamic:
|
|
|
|
|
- return GL_DYNAMIC_DRAW;
|
|
|
|
|
|
|
+ if (_color_blend_involves_color_scale) {
|
|
|
|
|
+ // Apply the current color scale to the blend mode.
|
|
|
|
|
+ _glBlendColor(_current_color_scale[0], _current_color_scale[1],
|
|
|
|
|
+ _current_color_scale[2], _current_color_scale[3]);
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ Colorf c = _color_blend->get_color();
|
|
|
|
|
+ _glBlendColor(c[0], c[1], c[2], c[3]);
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- case qpGeom::UH_client:
|
|
|
|
|
|
|
+ // No color blend; is there a transparency set?
|
|
|
|
|
+ switch (_transparency_mode) {
|
|
|
|
|
+ case TransparencyAttrib::M_none:
|
|
|
|
|
+ case TransparencyAttrib::M_binary:
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case TransparencyAttrib::M_alpha:
|
|
|
|
|
+ case TransparencyAttrib::M_dual:
|
|
|
|
|
+ enable_multisample_alpha_one(false);
|
|
|
|
|
+ enable_multisample_alpha_mask(false);
|
|
|
|
|
+ enable_blend(true);
|
|
|
|
|
+ _glBlendEquation(GL_FUNC_ADD);
|
|
|
|
|
+ GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ case TransparencyAttrib::M_multisample:
|
|
|
|
|
+ // We need to enable *both* of these in M_multisample case.
|
|
|
|
|
+ enable_multisample_alpha_one(true);
|
|
|
|
|
+ enable_multisample_alpha_mask(true);
|
|
|
|
|
+ enable_blend(false);
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ case TransparencyAttrib::M_multisample_mask:
|
|
|
|
|
+ enable_multisample_alpha_one(false);
|
|
|
|
|
+ enable_multisample_alpha_mask(true);
|
|
|
|
|
+ enable_blend(false);
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "invalid transparency mode " << (int)_transparency_mode << endl;
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "Unexpected usage_hint " << (int)usage_hint << endl;
|
|
|
|
|
- return GL_STATIC_DRAW;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ if (_line_smooth_enabled || _point_smooth_enabled) {
|
|
|
|
|
+ // If we have either of these turned on, we also need to have
|
|
|
|
|
+ // blend mode enabled in order to see it.
|
|
|
|
|
+ enable_multisample_alpha_one(false);
|
|
|
|
|
+ enable_multisample_alpha_mask(false);
|
|
|
|
|
+ enable_blend(true);
|
|
|
|
|
+ _glBlendEquation(GL_FUNC_ADD);
|
|
|
|
|
+ GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // For best polygon smoothing, we need:
|
|
|
|
|
+ // (1) a frame buffer that supports alpha
|
|
|
|
|
+ // (2) sort polygons front-to-back
|
|
|
|
|
+ // (3) glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
|
|
|
|
|
+ //
|
|
|
|
|
+ // Since these modes have other implications for the application, we
|
|
|
|
|
+ // don't attempt to do this by default. If you really want good
|
|
|
|
|
+ // polygon smoothing (and you don't have multisample support), do
|
|
|
|
|
+ // all this yourself.
|
|
|
|
|
|
|
|
|
|
+ // Nothing's set, so disable blending.
|
|
|
|
|
+ enable_multisample_alpha_one(false);
|
|
|
|
|
+ enable_multisample_alpha_mask(false);
|
|
|
|
|
+ enable_blend(false);
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::print_gfx_visual
|
|
|
|
|
-// Access: Public
|
|
|
|
|
-// Description: Prints a description of the current visual selected.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::finish_modify_state
|
|
|
|
|
+// Access: Protected, Virtual
|
|
|
|
|
+// Description: Called after the GSG state has been modified via
|
|
|
|
|
+// modify_state() or set_state(), this hook is provided
|
|
|
|
|
+// for the derived class to do any further state setup
|
|
|
|
|
+// work.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void CLP(GraphicsStateGuardian)::
|
|
void CLP(GraphicsStateGuardian)::
|
|
|
-print_gfx_visual() {
|
|
|
|
|
- GLint i;
|
|
|
|
|
- GLboolean j;
|
|
|
|
|
- cout << "Graphics Visual Info (# bits of each):" << endl;
|
|
|
|
|
-
|
|
|
|
|
- cout << "RGBA: ";
|
|
|
|
|
- GLP(GetIntegerv)( GL_RED_BITS, &i ); cout << i << " ";
|
|
|
|
|
- GLP(GetIntegerv)( GL_GREEN_BITS, &i ); cout << i << " ";
|
|
|
|
|
- GLP(GetIntegerv)( GL_BLUE_BITS, &i ); cout << i << " ";
|
|
|
|
|
- GLP(GetIntegerv)( GL_ALPHA_BITS, &i ); cout << i << endl;
|
|
|
|
|
-
|
|
|
|
|
- cout << "Accum RGBA: ";
|
|
|
|
|
- GLP(GetIntegerv)( GL_ACCUM_RED_BITS, &i ); cout << i << " ";
|
|
|
|
|
- GLP(GetIntegerv)( GL_ACCUM_GREEN_BITS, &i ); cout << i << " ";
|
|
|
|
|
- GLP(GetIntegerv)( GL_ACCUM_BLUE_BITS, &i ); cout << i << " ";
|
|
|
|
|
- GLP(GetIntegerv)( GL_ACCUM_ALPHA_BITS, &i ); cout << i << endl;
|
|
|
|
|
|
|
+finish_modify_state() {
|
|
|
|
|
+ GraphicsStateGuardian::finish_modify_state();
|
|
|
|
|
|
|
|
- GLP(GetIntegerv)( GL_INDEX_BITS, &i ); cout << "Color Index: " << i << endl;
|
|
|
|
|
|
|
+ // Apply the texture, if it needs to be reapplied.
|
|
|
|
|
+ if (_texture_stale) {
|
|
|
|
|
+ _texture_stale = false;
|
|
|
|
|
+ do_issue_texture();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- GLP(GetIntegerv)( GL_DEPTH_BITS, &i ); cout << "Depth: " << i << endl;
|
|
|
|
|
- GLP(GetIntegerv)( GL_ALPHA_BITS, &i ); cout << "Alpha: " << i << endl;
|
|
|
|
|
- GLP(GetIntegerv)( GL_STENCIL_BITS, &i ); cout << "Stencil: " << i << endl;
|
|
|
|
|
|
|
+ // If one of the previously-loaded TexGen modes modified the texture
|
|
|
|
|
+ // matrix, then if either state changed, we have to change both of
|
|
|
|
|
+ // them now.
|
|
|
|
|
+ if (_tex_gen_modifies_mat &&
|
|
|
|
|
+ (_needs_tex_mat || _needs_tex_gen)) {
|
|
|
|
|
+ _needs_tex_mat = true;
|
|
|
|
|
+ _needs_tex_gen = true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- GLP(GetBooleanv)( GL_DOUBLEBUFFER, &j ); cout << "DoubleBuffer? "
|
|
|
|
|
- << (int)j << endl;
|
|
|
|
|
|
|
+ // Apply the texture matrix, if needed.
|
|
|
|
|
+ if (_needs_tex_mat) {
|
|
|
|
|
+ _needs_tex_mat = false;
|
|
|
|
|
|
|
|
- GLP(GetBooleanv)( GL_STEREO, &j ); cout << "Stereo? " << (int)j << endl;
|
|
|
|
|
|
|
+ int num_stages = _current_texture->get_num_on_stages();
|
|
|
|
|
+ nassertv(num_stages <= _max_texture_stages);
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < num_stages; i++) {
|
|
|
|
|
+ TextureStage *stage = _current_texture->get_on_stage(i);
|
|
|
|
|
+ _glActiveTexture(GL_TEXTURE0 + i);
|
|
|
|
|
+
|
|
|
|
|
+ GLP(MatrixMode)(GL_TEXTURE);
|
|
|
|
|
+ if (_current_tex_mat->has_stage(stage)) {
|
|
|
|
|
+ GLP(LoadMatrixf)(_current_tex_mat->get_mat(stage).get_data());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ GLP(LoadIdentity)();
|
|
|
|
|
|
|
|
- if (_supports_multisample) {
|
|
|
|
|
- GLP(GetBooleanv)( GL_MULTISAMPLE, &j ); cout << "Multisample? " << (int)j << endl;
|
|
|
|
|
- GLP(GetIntegerv)( GL_SAMPLES, &i ); cout << "Samples: " << i << endl;
|
|
|
|
|
|
|
+ // For some reason, the glLoadIdentity() call doesn't work on
|
|
|
|
|
+ // my Dell laptop's IBM OpenGL driver, when used in
|
|
|
|
|
+ // conjunction with glTexGen(), below. But explicitly loading
|
|
|
|
|
+ // an identity matrix does work. But this buggy-driver
|
|
|
|
|
+ // workaround might have other performance implications, so I
|
|
|
|
|
+ // leave it out.
|
|
|
|
|
+ //GLP(LoadMatrixf)(LMatrix4f::ident_mat().get_data());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- GLP(GetBooleanv)( GL_BLEND, &j ); cout << "Blend? " << (int)j << endl;
|
|
|
|
|
- GLP(GetBooleanv)( GL_POINT_SMOOTH, &j ); cout << "Point Smooth? "
|
|
|
|
|
- << (int)j << endl;
|
|
|
|
|
- GLP(GetBooleanv)( GL_LINE_SMOOTH, &j ); cout << "Line Smooth? "
|
|
|
|
|
- << (int)j << endl;
|
|
|
|
|
|
|
+ if (_needs_tex_gen) {
|
|
|
|
|
+ _needs_tex_gen = false;
|
|
|
|
|
+ bool force_normal = false;
|
|
|
|
|
|
|
|
- GLP(GetIntegerv)( GL_AUX_BUFFERS, &i ); cout << "Aux Buffers: " << i << endl;
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ int num_stages = _current_texture->get_num_on_stages();
|
|
|
|
|
+ nassertv(num_stages <= _max_texture_stages);
|
|
|
|
|
+
|
|
|
|
|
+ // These are passed in for the four OBJECT_PLANE or EYE_PLANE
|
|
|
|
|
+ // values; they effectively define an identity matrix that maps
|
|
|
|
|
+ // the spatial coordinates one-for-one to UV's. If you want a
|
|
|
|
|
+ // mapping other than identity, use a TexMatrixAttrib (or a
|
|
|
|
|
+ // TexProjectorEffect).
|
|
|
|
|
+ static const float s_data[4] = { 1, 0, 0, 0 };
|
|
|
|
|
+ static const float t_data[4] = { 0, 1, 0, 0 };
|
|
|
|
|
+ static const float r_data[4] = { 0, 0, 1, 0 };
|
|
|
|
|
+ static const float q_data[4] = { 0, 0, 0, 1 };
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::issue_scaled_color
|
|
|
|
|
-// Access: Public
|
|
|
|
|
-// Description: Transform the color by the current color matrix, and
|
|
|
|
|
-// calls the appropriate glColor function.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-issue_scaled_color(const Colorf &color) const {
|
|
|
|
|
- Colorf transformed
|
|
|
|
|
- (color[0] * _current_color_scale[0],
|
|
|
|
|
- color[1] * _current_color_scale[1],
|
|
|
|
|
- color[2] * _current_color_scale[2],
|
|
|
|
|
- color[3] * _current_color_scale[3]);
|
|
|
|
|
|
|
+ _tex_gen_modifies_mat = false;
|
|
|
|
|
|
|
|
- GLP(Color4fv)(transformed.get_data());
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ bool got_point_sprites = false;
|
|
|
|
|
+
|
|
|
|
|
+ for (int i = 0; i < num_stages; i++) {
|
|
|
|
|
+ TextureStage *stage = _current_texture->get_on_stage(i);
|
|
|
|
|
+ _glActiveTexture(GL_TEXTURE0 + i);
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_GEN_Q);
|
|
|
|
|
+ if (_supports_point_sprite) {
|
|
|
|
|
+ GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::slot_new_light
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: This will be called by the base class before a
|
|
|
|
|
-// particular light id will be used for the first time.
|
|
|
|
|
-// It is intended to allow the derived class to reserve
|
|
|
|
|
-// any additional resources, if required, for the new
|
|
|
|
|
-// light; and also to indicate whether the hardware
|
|
|
|
|
-// supports this many simultaneous lights.
|
|
|
|
|
-//
|
|
|
|
|
-// The return value should be true if the additional
|
|
|
|
|
-// light is supported, or false if it is not.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-bool CLP(GraphicsStateGuardian)::
|
|
|
|
|
-slot_new_light(int light_id) {
|
|
|
|
|
- return (light_id < _max_lights);
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage);
|
|
|
|
|
+ switch (mode) {
|
|
|
|
|
+ case TexGenAttrib::M_off:
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case TexGenAttrib::M_eye_sphere_map:
|
|
|
|
|
+ GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
|
|
|
|
+ GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
+ force_normal = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case TexGenAttrib::M_eye_cube_map:
|
|
|
|
|
+ case TexGenAttrib::M_world_cube_map:
|
|
|
|
|
+ if (_supports_cube_map) {
|
|
|
|
|
+ if (mode != TexGenAttrib::M_eye_cube_map) {
|
|
|
|
|
+ // We dynamically transform normals from eye space to
|
|
|
|
|
+ // world space by applying the appropriate rotation
|
|
|
|
|
+ // transform to the current texture matrix. Although it's
|
|
|
|
|
+ // tempting to try, we can't safely convert to object
|
|
|
|
|
+ // space, since this method doesn't get called with each
|
|
|
|
|
+ // different object.
|
|
|
|
|
+ CPT(TransformState) transform = _scene_setup->get_render_transform();
|
|
|
|
|
+ transform = transform->invert_compose(TransformState::make_identity());
|
|
|
|
|
+ LMatrix4f mat = transform->get_mat();
|
|
|
|
|
+ mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
|
|
|
|
|
+ GLP(MatrixMode)(GL_TEXTURE);
|
|
|
|
|
+ GLP(MultMatrixf)(mat.get_data());
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::enable_lighting
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Intended to be overridden by a derived class to
|
|
|
|
|
-// enable or disable the use of lighting overall. This
|
|
|
|
|
-// is called by issue_light() according to whether any
|
|
|
|
|
-// lights are in use or not.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-enable_lighting(bool enable) {
|
|
|
|
|
- if (enable) {
|
|
|
|
|
- GLP(Enable)(GL_LIGHTING);
|
|
|
|
|
- } else {
|
|
|
|
|
- GLP(Disable)(GL_LIGHTING);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ // Now we need to reset the texture matrix next time
|
|
|
|
|
+ // around to undo this.
|
|
|
|
|
+ _tex_gen_modifies_mat = true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::set_ambient_light
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Intended to be overridden by a derived class to
|
|
|
|
|
-// indicate the color of the ambient light that should
|
|
|
|
|
-// be in effect. This is called by issue_light() after
|
|
|
|
|
-// all other lights have been enabled or disabled.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-set_ambient_light(const Colorf &color) {
|
|
|
|
|
- GLP(LightModelfv)(GL_LIGHT_MODEL_AMBIENT, color.get_data());
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
|
|
|
|
+ GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
|
|
|
|
+ GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
+ force_normal = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case TexGenAttrib::M_eye_normal:
|
|
|
|
|
+ case TexGenAttrib::M_world_normal:
|
|
|
|
|
+ if (_supports_cube_map) {
|
|
|
|
|
+ if (mode != TexGenAttrib::M_eye_normal) {
|
|
|
|
|
+ // We dynamically transform normals from eye space to
|
|
|
|
|
+ // world space by applying the appropriate rotation
|
|
|
|
|
+ // transform to the current texture matrix. Although it's
|
|
|
|
|
+ // tempting to try, we can't safely convert to object
|
|
|
|
|
+ // space, since this method doesn't get called with each
|
|
|
|
|
+ // different object.
|
|
|
|
|
+ CPT(TransformState) transform = _scene_setup->get_render_transform();
|
|
|
|
|
+ transform = transform->invert_compose(TransformState::make_identity());
|
|
|
|
|
+ LMatrix4f mat = transform->get_mat();
|
|
|
|
|
+ mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
|
|
|
|
|
+ GLP(MatrixMode)(GL_TEXTURE);
|
|
|
|
|
+ GLP(MultMatrixf)(mat.get_data());
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::enable_light
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Intended to be overridden by a derived class to
|
|
|
|
|
-// enable the indicated light id. A specific Light will
|
|
|
|
|
-// already have been bound to this id via bind_light().
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-enable_light(int light_id, bool enable) {
|
|
|
|
|
- if (enable) {
|
|
|
|
|
- GLP(Enable)(get_light_id(light_id));
|
|
|
|
|
- } else {
|
|
|
|
|
- GLP(Disable)(get_light_id(light_id));
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ // Now we need to reset the texture matrix next time
|
|
|
|
|
+ // around to undo this.
|
|
|
|
|
+ _tex_gen_modifies_mat = true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::begin_bind_lights
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Called immediately before bind_light() is called,
|
|
|
|
|
-// this is intended to provide the derived class a hook
|
|
|
|
|
-// in which to set up some state (like transform) that
|
|
|
|
|
-// might apply to several lights.
|
|
|
|
|
-//
|
|
|
|
|
-// The sequence is: begin_bind_lights() will be called,
|
|
|
|
|
-// then one or more bind_light() calls, then
|
|
|
|
|
-// end_bind_lights().
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-begin_bind_lights() {
|
|
|
|
|
- // We need to temporarily load a new matrix so we can define the
|
|
|
|
|
- // light in a known coordinate system. We pick the transform of the
|
|
|
|
|
- // root. (Alternatively, we could leave the current transform where
|
|
|
|
|
- // it is and compute the light position relative to that transform
|
|
|
|
|
- // instead of relative to the root, by composing with the matrix
|
|
|
|
|
- // computed by _transform->invert_compose(render_transform). But I
|
|
|
|
|
- // think loading a completely new matrix is simpler.)
|
|
|
|
|
- GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
- GLP(PushMatrix)();
|
|
|
|
|
- GLP(LoadMatrixf)(_scene_setup->get_render_transform()->get_mat().get_data());
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
|
|
|
|
|
+ GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
|
|
|
|
|
+ GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
+ force_normal = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::end_bind_lights
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Called after before bind_light() has been called one
|
|
|
|
|
-// or more times (but before any geometry is issued or
|
|
|
|
|
-// additional state is changed), this is intended to
|
|
|
|
|
-// clean up any temporary changes to the state that may
|
|
|
|
|
-// have been made by begin_bind_lights().
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-end_bind_lights() {
|
|
|
|
|
- GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
- GLP(PopMatrix)();
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ case TexGenAttrib::M_object_position:
|
|
|
|
|
+ GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
|
|
|
+ GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
|
|
|
+ GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
|
|
|
+ GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
|
|
|
+
|
|
|
|
|
+ GLP(TexGenfv)(GL_S, GL_OBJECT_PLANE, s_data);
|
|
|
|
|
+ GLP(TexGenfv)(GL_T, GL_OBJECT_PLANE, t_data);
|
|
|
|
|
+ GLP(TexGenfv)(GL_R, GL_OBJECT_PLANE, r_data);
|
|
|
|
|
+ GLP(TexGenfv)(GL_Q, GL_OBJECT_PLANE, q_data);
|
|
|
|
|
+
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_Q);
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::slot_new_clip_plane
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: This will be called by the base class before a
|
|
|
|
|
-// particular clip plane id will be used for the first
|
|
|
|
|
-// time. It is intended to allow the derived class to
|
|
|
|
|
-// reserve any additional resources, if required, for
|
|
|
|
|
-// the new clip plane; and also to indicate whether the
|
|
|
|
|
-// hardware supports this many simultaneous clipping
|
|
|
|
|
-// planes.
|
|
|
|
|
-//
|
|
|
|
|
-// The return value should be true if the additional
|
|
|
|
|
-// plane is supported, or false if it is not.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-bool CLP(GraphicsStateGuardian)::
|
|
|
|
|
-slot_new_clip_plane(int plane_id) {
|
|
|
|
|
- return (plane_id < _max_clip_planes);
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ case TexGenAttrib::M_eye_position:
|
|
|
|
|
+ // To represent eye position correctly, we need to temporarily
|
|
|
|
|
+ // load the coordinate-system transform.
|
|
|
|
|
+ GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
+ GLP(PushMatrix)();
|
|
|
|
|
+ GLP(LoadMatrixf)(_scene_setup->get_cs_transform()->get_mat().get_data());
|
|
|
|
|
+
|
|
|
|
|
+ GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
+ GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
+ GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
+ GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
+
|
|
|
|
|
+ GLP(TexGenfv)(GL_S, GL_EYE_PLANE, s_data);
|
|
|
|
|
+ GLP(TexGenfv)(GL_T, GL_EYE_PLANE, t_data);
|
|
|
|
|
+ GLP(TexGenfv)(GL_R, GL_EYE_PLANE, r_data);
|
|
|
|
|
+ GLP(TexGenfv)(GL_Q, GL_EYE_PLANE, q_data);
|
|
|
|
|
+
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_Q);
|
|
|
|
|
+
|
|
|
|
|
+ GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
+ GLP(PopMatrix)();
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case TexGenAttrib::M_world_position:
|
|
|
|
|
+ // We achieve world position coordinates by using the eye
|
|
|
|
|
+ // position mode, and loading the transform of the root
|
|
|
|
|
+ // node--thus putting the "eye" at the root.
|
|
|
|
|
+ {
|
|
|
|
|
+ GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
+ GLP(PushMatrix)();
|
|
|
|
|
+ CPT(TransformState) root_transform = _scene_setup->get_render_transform();
|
|
|
|
|
+ GLP(LoadMatrixf)(root_transform->get_mat().get_data());
|
|
|
|
|
+ GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
+ GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
+ GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
+ GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
+
|
|
|
|
|
+ GLP(TexGenfv)(GL_S, GL_EYE_PLANE, s_data);
|
|
|
|
|
+ GLP(TexGenfv)(GL_T, GL_EYE_PLANE, t_data);
|
|
|
|
|
+ GLP(TexGenfv)(GL_R, GL_EYE_PLANE, r_data);
|
|
|
|
|
+ GLP(TexGenfv)(GL_Q, GL_EYE_PLANE, q_data);
|
|
|
|
|
+
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
+ GLP(Enable)(GL_TEXTURE_GEN_Q);
|
|
|
|
|
+
|
|
|
|
|
+ GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
+ GLP(PopMatrix)();
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case TexGenAttrib::M_point_sprite:
|
|
|
|
|
+ nassertv(_supports_point_sprite);
|
|
|
|
|
+ GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
|
|
|
|
|
+ got_point_sprites = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (got_point_sprites != _tex_gen_point_sprite) {
|
|
|
|
|
+ _tex_gen_point_sprite = got_point_sprites;
|
|
|
|
|
+ if (_tex_gen_point_sprite) {
|
|
|
|
|
+ GLP(Enable)(GL_POINT_SPRITE_ARB);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ GLP(Disable)(GL_POINT_SPRITE_ARB);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::enable_clip_plane
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Intended to be overridden by a derived class to
|
|
|
|
|
-// enable the indicated clip_plane id. A specific
|
|
|
|
|
-// PlaneNode will already have been bound to this id via
|
|
|
|
|
-// bind_clip_plane().
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-enable_clip_plane(int plane_id, bool enable) {
|
|
|
|
|
- if (enable) {
|
|
|
|
|
- GLP(Enable)(get_clip_plane_id(plane_id));
|
|
|
|
|
- } else {
|
|
|
|
|
- GLP(Disable)(get_clip_plane_id(plane_id));
|
|
|
|
|
|
|
+ // Certain texgen modes (sphere_map, cube_map) require forcing the
|
|
|
|
|
+ // normal to be sent to the GL while the texgen mode is in effect.
|
|
|
|
|
+ if (force_normal != _texgen_forced_normal) {
|
|
|
|
|
+ if (force_normal) {
|
|
|
|
|
+ force_normals();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ undo_force_normals();
|
|
|
|
|
+ }
|
|
|
|
|
+ _texgen_forced_normal = force_normal;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::begin_bind_clip_planes
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::free_pointers
|
|
|
// Access: Protected, Virtual
|
|
// Access: Protected, Virtual
|
|
|
-// Description: Called immediately before bind_clip_plane() is called,
|
|
|
|
|
-// this is intended to provide the derived class a hook
|
|
|
|
|
-// in which to set up some state (like transform) that
|
|
|
|
|
-// might apply to several clip_planes.
|
|
|
|
|
-//
|
|
|
|
|
-// The sequence is: begin_bind_clip_planes() will be called,
|
|
|
|
|
-// then one or more bind_clip_plane() calls, then
|
|
|
|
|
-// end_bind_clip_planes().
|
|
|
|
|
|
|
+// Description: Frees some memory that was explicitly allocated
|
|
|
|
|
+// within the glgsg.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void CLP(GraphicsStateGuardian)::
|
|
void CLP(GraphicsStateGuardian)::
|
|
|
-begin_bind_clip_planes() {
|
|
|
|
|
- // We need to temporarily load a new matrix so we can define the
|
|
|
|
|
- // clip_plane in a known coordinate system. We pick the transform of the
|
|
|
|
|
- // root. (Alternatively, we could leave the current transform where
|
|
|
|
|
- // it is and compute the clip_plane position relative to that transform
|
|
|
|
|
- // instead of relative to the root, by composing with the matrix
|
|
|
|
|
- // computed by _transform->invert_compose(render_transform). But I
|
|
|
|
|
- // think loading a completely new matrix is simpler.)
|
|
|
|
|
- GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
- GLP(PushMatrix)();
|
|
|
|
|
- GLP(LoadMatrixf)(_scene_setup->get_render_transform()->get_mat().get_data());
|
|
|
|
|
|
|
+free_pointers() {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::bind_clip_plane
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Called the first time a particular clip_plane has been
|
|
|
|
|
-// bound to a given id within a frame, this should set
|
|
|
|
|
-// up the associated hardware clip_plane with the clip_plane's
|
|
|
|
|
-// properties.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_untextured_state
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Returns a RenderState object that represents
|
|
|
|
|
+// texturing off.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-bind_clip_plane(const NodePath &plane, int plane_id) {
|
|
|
|
|
- GLenum id = get_clip_plane_id(plane_id);
|
|
|
|
|
-
|
|
|
|
|
- CPT(TransformState) transform = plane.get_transform(_scene_setup->get_scene_root());
|
|
|
|
|
- const PlaneNode *plane_node;
|
|
|
|
|
- DCAST_INTO_V(plane_node, plane.node());
|
|
|
|
|
- Planef xformed_plane = plane_node->get_plane() * transform->get_mat();
|
|
|
|
|
-
|
|
|
|
|
- Planed double_plane(LCAST(double, xformed_plane));
|
|
|
|
|
- GLP(ClipPlane)(id, double_plane.get_data());
|
|
|
|
|
-
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
|
|
+CPT(RenderState) CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_untextured_state() {
|
|
|
|
|
+ static CPT(RenderState) state;
|
|
|
|
|
+ if (state == (RenderState *)NULL) {
|
|
|
|
|
+ state = RenderState::make(TextureAttrib::make_off());
|
|
|
|
|
+ }
|
|
|
|
|
+ return state;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::end_bind_clip_planes
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Called after before bind_clip_plane() has been called one
|
|
|
|
|
-// or more times (but before any geometry is issued or
|
|
|
|
|
-// additional state is changed), this is intended to
|
|
|
|
|
-// clean up any temporary changes to the state that may
|
|
|
|
|
-// have been made by begin_bind_clip_planes().
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_smooth_state
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Returns a RenderState object that represents
|
|
|
|
|
+// smooth, per-vertex shading.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-end_bind_clip_planes() {
|
|
|
|
|
- GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
- GLP(PopMatrix)();
|
|
|
|
|
|
|
+CPT(RenderState) CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_smooth_state() {
|
|
|
|
|
+ static CPT(RenderState) state;
|
|
|
|
|
+ if (state == (RenderState *)NULL) {
|
|
|
|
|
+ state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_smooth));
|
|
|
|
|
+ }
|
|
|
|
|
+ return state;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::set_blend_mode
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Called after any of the things that might change
|
|
|
|
|
-// blending state have changed, this function is
|
|
|
|
|
-// responsible for setting the appropriate color
|
|
|
|
|
-// blending mode based on the current properties.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::get_flat_state
|
|
|
|
|
+// Access: Protected, Static
|
|
|
|
|
+// Description: Returns a RenderState object that represents
|
|
|
|
|
+// flat, per-primitive shading.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-set_blend_mode() {
|
|
|
|
|
- // If color_write_mode is off, we disable writing to the color using
|
|
|
|
|
- // blending. This case is only used if we can't use GLP(ColorMask) to
|
|
|
|
|
- // disable the color writing for some reason (usually a driver
|
|
|
|
|
- // problem).
|
|
|
|
|
- if (_color_write_mode == ColorWriteAttrib::M_off) {
|
|
|
|
|
- enable_multisample_alpha_one(false);
|
|
|
|
|
- enable_multisample_alpha_mask(false);
|
|
|
|
|
- enable_blend(true);
|
|
|
|
|
- _glBlendEquation(GL_FUNC_ADD);
|
|
|
|
|
- GLP(BlendFunc)(GL_ZERO, GL_ONE);
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Is there a color blend set?
|
|
|
|
|
- if (_color_blend_mode != ColorBlendAttrib::M_none) {
|
|
|
|
|
- enable_multisample_alpha_one(false);
|
|
|
|
|
- enable_multisample_alpha_mask(false);
|
|
|
|
|
- enable_blend(true);
|
|
|
|
|
- _glBlendEquation(get_blend_equation_type(_color_blend_mode));
|
|
|
|
|
- GLP(BlendFunc)(get_blend_func(_color_blend->get_operand_a()),
|
|
|
|
|
- get_blend_func(_color_blend->get_operand_b()));
|
|
|
|
|
-
|
|
|
|
|
- if (_color_blend_involves_color_scale) {
|
|
|
|
|
- // Apply the current color scale to the blend mode.
|
|
|
|
|
- _glBlendColor(_current_color_scale[0], _current_color_scale[1],
|
|
|
|
|
- _current_color_scale[2], _current_color_scale[3]);
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- Colorf c = _color_blend->get_color();
|
|
|
|
|
- _glBlendColor(c[0], c[1], c[2], c[3]);
|
|
|
|
|
- }
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // No color blend; is there a transparency set?
|
|
|
|
|
- switch (_transparency_mode) {
|
|
|
|
|
- case TransparencyAttrib::M_none:
|
|
|
|
|
- case TransparencyAttrib::M_binary:
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case TransparencyAttrib::M_alpha:
|
|
|
|
|
- case TransparencyAttrib::M_dual:
|
|
|
|
|
- enable_multisample_alpha_one(false);
|
|
|
|
|
- enable_multisample_alpha_mask(false);
|
|
|
|
|
- enable_blend(true);
|
|
|
|
|
- _glBlendEquation(GL_FUNC_ADD);
|
|
|
|
|
- GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
- return;
|
|
|
|
|
-
|
|
|
|
|
- case TransparencyAttrib::M_multisample:
|
|
|
|
|
- // We need to enable *both* of these in M_multisample case.
|
|
|
|
|
- enable_multisample_alpha_one(true);
|
|
|
|
|
- enable_multisample_alpha_mask(true);
|
|
|
|
|
- enable_blend(false);
|
|
|
|
|
- return;
|
|
|
|
|
-
|
|
|
|
|
- case TransparencyAttrib::M_multisample_mask:
|
|
|
|
|
- enable_multisample_alpha_one(false);
|
|
|
|
|
- enable_multisample_alpha_mask(true);
|
|
|
|
|
- enable_blend(false);
|
|
|
|
|
- return;
|
|
|
|
|
-
|
|
|
|
|
- default:
|
|
|
|
|
- GLCAT.error()
|
|
|
|
|
- << "invalid transparency mode " << (int)_transparency_mode << endl;
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (_line_smooth_enabled || _point_smooth_enabled) {
|
|
|
|
|
- // If we have either of these turned on, we also need to have
|
|
|
|
|
- // blend mode enabled in order to see it.
|
|
|
|
|
- enable_multisample_alpha_one(false);
|
|
|
|
|
- enable_multisample_alpha_mask(false);
|
|
|
|
|
- enable_blend(true);
|
|
|
|
|
- _glBlendEquation(GL_FUNC_ADD);
|
|
|
|
|
- GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+CPT(RenderState) CLP(GraphicsStateGuardian)::
|
|
|
|
|
+get_flat_state() {
|
|
|
|
|
+ static CPT(RenderState) state;
|
|
|
|
|
+ if (state == (RenderState *)NULL) {
|
|
|
|
|
+ state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_flat));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // For best polygon smoothing, we need:
|
|
|
|
|
- // (1) a frame buffer that supports alpha
|
|
|
|
|
- // (2) sort polygons front-to-back
|
|
|
|
|
- // (3) glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
|
|
|
|
|
- //
|
|
|
|
|
- // Since these modes have other implications for the application, we
|
|
|
|
|
- // don't attempt to do this by default. If you really want good
|
|
|
|
|
- // polygon smoothing (and you don't have multisample support), do
|
|
|
|
|
- // all this yourself.
|
|
|
|
|
-
|
|
|
|
|
- // Nothing's set, so disable blending.
|
|
|
|
|
- enable_multisample_alpha_one(false);
|
|
|
|
|
- enable_multisample_alpha_mask(false);
|
|
|
|
|
- enable_blend(false);
|
|
|
|
|
|
|
+ return state;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::finish_modify_state
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Called after the GSG state has been modified via
|
|
|
|
|
-// modify_state() or set_state(), this hook is provided
|
|
|
|
|
-// for the derived class to do any further state setup
|
|
|
|
|
-// work.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::do_auto_rescale_normal
|
|
|
|
|
+// Access: Protected
|
|
|
|
|
+// Description: Issues the appropriate GL commands to either rescale
|
|
|
|
|
+// or normalize the normals according to the current
|
|
|
|
|
+// transform.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-finish_modify_state() {
|
|
|
|
|
- GraphicsStateGuardian::finish_modify_state();
|
|
|
|
|
-
|
|
|
|
|
- // Apply the texture, if it needs to be reapplied.
|
|
|
|
|
- if (_texture_stale) {
|
|
|
|
|
- _texture_stale = false;
|
|
|
|
|
- do_issue_texture();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // If one of the previously-loaded TexGen modes modified the texture
|
|
|
|
|
- // matrix, then if either state changed, we have to change both of
|
|
|
|
|
- // them now.
|
|
|
|
|
- if (_tex_gen_modifies_mat &&
|
|
|
|
|
- (_needs_tex_mat || _needs_tex_gen)) {
|
|
|
|
|
- _needs_tex_mat = true;
|
|
|
|
|
- _needs_tex_gen = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Apply the texture matrix, if needed.
|
|
|
|
|
- if (_needs_tex_mat) {
|
|
|
|
|
- _needs_tex_mat = false;
|
|
|
|
|
-
|
|
|
|
|
- int num_stages = _current_texture->get_num_on_stages();
|
|
|
|
|
- nassertv(num_stages <= _max_texture_stages);
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 0; i < num_stages; i++) {
|
|
|
|
|
- TextureStage *stage = _current_texture->get_on_stage(i);
|
|
|
|
|
- _glActiveTexture(GL_TEXTURE0 + i);
|
|
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+do_auto_rescale_normal() {
|
|
|
|
|
+ if (_transform->has_uniform_scale()) {
|
|
|
|
|
+ if (IS_NEARLY_EQUAL(_transform->get_uniform_scale(), 1.0f)) {
|
|
|
|
|
+ // If there's no scale at all, don't do anything.
|
|
|
|
|
+ GLP(Disable)(GL_NORMALIZE);
|
|
|
|
|
+ if (_supports_rescale_normal) {
|
|
|
|
|
+ GLP(Disable)(GL_RESCALE_NORMAL);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- GLP(MatrixMode)(GL_TEXTURE);
|
|
|
|
|
- if (_current_tex_mat->has_stage(stage)) {
|
|
|
|
|
- GLP(LoadMatrixf)(_current_tex_mat->get_mat(stage).get_data());
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // There's a uniform scale; use the rescale feature if available.
|
|
|
|
|
+ if (_supports_rescale_normal) {
|
|
|
|
|
+ GLP(Enable)(GL_RESCALE_NORMAL);
|
|
|
|
|
+ GLP(Disable)(GL_NORMALIZE);
|
|
|
} else {
|
|
} else {
|
|
|
- GLP(LoadIdentity)();
|
|
|
|
|
-
|
|
|
|
|
- // For some reason, the glLoadIdentity() call doesn't work on
|
|
|
|
|
- // my Dell laptop's IBM OpenGL driver, when used in
|
|
|
|
|
- // conjunction with glTexGen(), below. But explicitly loading
|
|
|
|
|
- // an identity matrix does work. But this buggy-driver
|
|
|
|
|
- // workaround might have other performance implications, so I
|
|
|
|
|
- // leave it out.
|
|
|
|
|
- //GLP(LoadMatrixf)(LMatrix4f::ident_mat().get_data());
|
|
|
|
|
|
|
+ GLP(Enable)(GL_NORMALIZE);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- report_my_gl_errors();
|
|
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // If there's a non-uniform scale, normalize everything.
|
|
|
|
|
+ GLP(Enable)(GL_NORMALIZE);
|
|
|
|
|
+ if (_supports_rescale_normal) {
|
|
|
|
|
+ GLP(Disable)(GL_RESCALE_NORMAL);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- if (_needs_tex_gen) {
|
|
|
|
|
- _needs_tex_gen = false;
|
|
|
|
|
- bool force_normal = false;
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::do_issue_texture
|
|
|
|
|
+// Access: Protected
|
|
|
|
|
+// Description: This is called by finish_modify_state() when the
|
|
|
|
|
+// texture state has changed.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void CLP(GraphicsStateGuardian)::
|
|
|
|
|
+do_issue_texture() {
|
|
|
|
|
+ DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
|
|
|
|
|
|
|
|
- int num_stages = _current_texture->get_num_on_stages();
|
|
|
|
|
- nassertv(num_stages <= _max_texture_stages);
|
|
|
|
|
-
|
|
|
|
|
- // These are passed in for the four OBJECT_PLANE or EYE_PLANE
|
|
|
|
|
- // values; they effectively define an identity matrix that maps
|
|
|
|
|
- // the spatial coordinates one-for-one to UV's. If you want a
|
|
|
|
|
- // mapping other than identity, use a TexMatrixAttrib (or a
|
|
|
|
|
- // TexProjectorEffect).
|
|
|
|
|
- static const float s_data[4] = { 1, 0, 0, 0 };
|
|
|
|
|
- static const float t_data[4] = { 0, 1, 0, 0 };
|
|
|
|
|
- static const float r_data[4] = { 0, 0, 1, 0 };
|
|
|
|
|
- static const float q_data[4] = { 0, 0, 0, 1 };
|
|
|
|
|
|
|
+ CPT(TextureAttrib) new_texture = _pending_texture->filter_to_max(_max_texture_stages);
|
|
|
|
|
+
|
|
|
|
|
+ int num_stages = new_texture->get_num_on_stages();
|
|
|
|
|
+ int num_old_stages = _current_texture->get_num_on_stages();
|
|
|
|
|
|
|
|
- _tex_gen_modifies_mat = false;
|
|
|
|
|
|
|
+ nassertv(num_stages <= _max_texture_stages &&
|
|
|
|
|
+ num_old_stages <= _max_texture_stages);
|
|
|
|
|
|
|
|
- bool got_point_sprites = false;
|
|
|
|
|
|
|
+ _texture_involves_color_scale = false;
|
|
|
|
|
+
|
|
|
|
|
+ int i;
|
|
|
|
|
+ for (i = 0; i < num_stages; i++) {
|
|
|
|
|
+ TextureStage *stage = new_texture->get_on_stage(i);
|
|
|
|
|
+ Texture *texture = new_texture->get_on_texture(stage);
|
|
|
|
|
+ nassertv(texture != (Texture *)NULL);
|
|
|
|
|
|
|
|
- for (int i = 0; i < num_stages; i++) {
|
|
|
|
|
- TextureStage *stage = _current_texture->get_on_stage(i);
|
|
|
|
|
|
|
+ if (i >= num_old_stages ||
|
|
|
|
|
+ stage != _current_texture->get_on_stage(i) ||
|
|
|
|
|
+ texture != _current_texture->get_on_texture(stage) ||
|
|
|
|
|
+ stage->involves_color_scale()) {
|
|
|
|
|
+ // Stage i has changed. Issue the texture on this stage.
|
|
|
_glActiveTexture(GL_TEXTURE0 + i);
|
|
_glActiveTexture(GL_TEXTURE0 + i);
|
|
|
- GLP(Disable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_GEN_Q);
|
|
|
|
|
- if (_supports_point_sprite) {
|
|
|
|
|
- GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ GLenum target = get_texture_target(texture->get_texture_type());
|
|
|
|
|
+
|
|
|
|
|
+ // First, turn off the previous texture mode.
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_1D);
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_2D);
|
|
|
|
|
+ if (_supports_3d_texture) {
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_3D);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (_supports_cube_map) {
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_CUBE_MAP);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage);
|
|
|
|
|
- switch (mode) {
|
|
|
|
|
- case TexGenAttrib::M_off:
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case TexGenAttrib::M_eye_sphere_map:
|
|
|
|
|
- GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
|
|
|
|
- GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
- force_normal = true;
|
|
|
|
|
|
|
+ // Then, turn on the current texture mode.
|
|
|
|
|
+ if (target == GL_NONE) {
|
|
|
|
|
+ // Unsupported texture mode.
|
|
|
break;
|
|
break;
|
|
|
-
|
|
|
|
|
- case TexGenAttrib::M_eye_cube_map:
|
|
|
|
|
- case TexGenAttrib::M_world_cube_map:
|
|
|
|
|
- if (_supports_cube_map) {
|
|
|
|
|
- if (mode != TexGenAttrib::M_eye_cube_map) {
|
|
|
|
|
- // We dynamically transform normals from eye space to
|
|
|
|
|
- // world space by applying the appropriate rotation
|
|
|
|
|
- // transform to the current texture matrix. Although it's
|
|
|
|
|
- // tempting to try, we can't safely convert to object
|
|
|
|
|
- // space, since this method doesn't get called with each
|
|
|
|
|
- // different object.
|
|
|
|
|
- CPT(TransformState) transform = _scene_setup->get_render_transform();
|
|
|
|
|
- transform = transform->invert_compose(TransformState::make_identity());
|
|
|
|
|
- LMatrix4f mat = transform->get_mat();
|
|
|
|
|
- mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
|
|
|
|
|
- GLP(MatrixMode)(GL_TEXTURE);
|
|
|
|
|
- GLP(MultMatrixf)(mat.get_data());
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ GLP(Enable)(target);
|
|
|
|
|
+
|
|
|
|
|
+ TextureContext *tc = texture->prepare_now(_prepared_objects, this);
|
|
|
|
|
+ apply_texture(tc);
|
|
|
|
|
|
|
|
- // Now we need to reset the texture matrix next time
|
|
|
|
|
- // around to undo this.
|
|
|
|
|
- _tex_gen_modifies_mat = true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (stage->involves_color_scale() && _color_scale_enabled) {
|
|
|
|
|
+ Colorf color = stage->get_color();
|
|
|
|
|
+ color.set(color[0] * _current_color_scale[0],
|
|
|
|
|
+ color[1] * _current_color_scale[1],
|
|
|
|
|
+ color[2] * _current_color_scale[2],
|
|
|
|
|
+ color[3] * _current_color_scale[3]);
|
|
|
|
|
+ _texture_involves_color_scale = true;
|
|
|
|
|
+ GLP(TexEnvfv)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color.get_data());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ GLP(TexEnvfv)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, stage->get_color().get_data());
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
|
|
|
|
- GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
|
|
|
|
- GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
- force_normal = true;
|
|
|
|
|
|
|
+ if (stage->get_mode() == TextureStage::M_decal) {
|
|
|
|
|
+ if (texture->get_num_components() < 3) {
|
|
|
|
|
+ // Make a special case for 1- and 2-channel decal textures.
|
|
|
|
|
+ // OpenGL does not define their use with GL_DECAL for some
|
|
|
|
|
+ // reason, so implement them using the combiner instead.
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Normal 3- and 4-channel decal textures.
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
|
|
}
|
|
}
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case TexGenAttrib::M_eye_normal:
|
|
|
|
|
- case TexGenAttrib::M_world_normal:
|
|
|
|
|
- if (_supports_cube_map) {
|
|
|
|
|
- if (mode != TexGenAttrib::M_eye_normal) {
|
|
|
|
|
- // We dynamically transform normals from eye space to
|
|
|
|
|
- // world space by applying the appropriate rotation
|
|
|
|
|
- // transform to the current texture matrix. Although it's
|
|
|
|
|
- // tempting to try, we can't safely convert to object
|
|
|
|
|
- // space, since this method doesn't get called with each
|
|
|
|
|
- // different object.
|
|
|
|
|
- CPT(TransformState) transform = _scene_setup->get_render_transform();
|
|
|
|
|
- transform = transform->invert_compose(TransformState::make_identity());
|
|
|
|
|
- LMatrix4f mat = transform->get_mat();
|
|
|
|
|
- mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
|
|
|
|
|
- GLP(MatrixMode)(GL_TEXTURE);
|
|
|
|
|
- GLP(MultMatrixf)(mat.get_data());
|
|
|
|
|
|
|
|
|
|
- // Now we need to reset the texture matrix next time
|
|
|
|
|
- // around to undo this.
|
|
|
|
|
- _tex_gen_modifies_mat = true;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ } else if (stage->get_mode() == TextureStage::M_combine) {
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_RGB_SCALE, stage->get_rgb_scale());
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_ALPHA_SCALE, stage->get_alpha_scale());
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB,
|
|
|
|
|
+ get_texture_combine_type(stage->get_combine_rgb_mode()));
|
|
|
|
|
|
|
|
- GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
|
|
|
|
|
- GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
|
|
|
|
|
- GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
- force_normal = true;
|
|
|
|
|
- }
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ switch (stage->get_num_combine_rgb_operands()) {
|
|
|
|
|
+ case 3:
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_RGB,
|
|
|
|
|
+ get_texture_src_type(stage->get_combine_rgb_source2()));
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_RGB,
|
|
|
|
|
+ get_texture_operand_type(stage->get_combine_rgb_operand2()));
|
|
|
|
|
+ // fall through
|
|
|
|
|
|
|
|
- case TexGenAttrib::M_object_position:
|
|
|
|
|
- GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
|
|
|
- GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
|
|
|
- GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
|
|
|
- GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
|
|
|
|
|
-
|
|
|
|
|
- GLP(TexGenfv)(GL_S, GL_OBJECT_PLANE, s_data);
|
|
|
|
|
- GLP(TexGenfv)(GL_T, GL_OBJECT_PLANE, t_data);
|
|
|
|
|
- GLP(TexGenfv)(GL_R, GL_OBJECT_PLANE, r_data);
|
|
|
|
|
- GLP(TexGenfv)(GL_Q, GL_OBJECT_PLANE, q_data);
|
|
|
|
|
-
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_Q);
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ case 2:
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_RGB,
|
|
|
|
|
+ get_texture_src_type(stage->get_combine_rgb_source1()));
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB,
|
|
|
|
|
+ get_texture_operand_type(stage->get_combine_rgb_operand1()));
|
|
|
|
|
+ // fall through
|
|
|
|
|
+
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_RGB,
|
|
|
|
|
+ get_texture_src_type(stage->get_combine_rgb_source0()));
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND0_RGB,
|
|
|
|
|
+ get_texture_operand_type(stage->get_combine_rgb_operand0()));
|
|
|
|
|
+ // fall through
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_ALPHA,
|
|
|
|
|
+ get_texture_combine_type(stage->get_combine_alpha_mode()));
|
|
|
|
|
|
|
|
- case TexGenAttrib::M_eye_position:
|
|
|
|
|
- // To represent eye position correctly, we need to temporarily
|
|
|
|
|
- // load the coordinate-system transform.
|
|
|
|
|
- GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
- GLP(PushMatrix)();
|
|
|
|
|
- GLP(LoadMatrixf)(_scene_setup->get_cs_transform()->get_mat().get_data());
|
|
|
|
|
|
|
+ switch (stage->get_num_combine_alpha_operands()) {
|
|
|
|
|
+ case 3:
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_ALPHA,
|
|
|
|
|
+ get_texture_src_type(stage->get_combine_alpha_source2()));
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
|
|
|
|
|
+ get_texture_operand_type(stage->get_combine_alpha_operand2()));
|
|
|
|
|
+ // fall through
|
|
|
|
|
|
|
|
- GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
- GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
- GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
- GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
-
|
|
|
|
|
- GLP(TexGenfv)(GL_S, GL_EYE_PLANE, s_data);
|
|
|
|
|
- GLP(TexGenfv)(GL_T, GL_EYE_PLANE, t_data);
|
|
|
|
|
- GLP(TexGenfv)(GL_R, GL_EYE_PLANE, r_data);
|
|
|
|
|
- GLP(TexGenfv)(GL_Q, GL_EYE_PLANE, q_data);
|
|
|
|
|
-
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_Q);
|
|
|
|
|
|
|
+ case 2:
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_ALPHA,
|
|
|
|
|
+ get_texture_src_type(stage->get_combine_alpha_source1()));
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
|
|
|
|
|
+ get_texture_operand_type(stage->get_combine_alpha_operand1()));
|
|
|
|
|
+ // fall through
|
|
|
|
|
|
|
|
- GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
- GLP(PopMatrix)();
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_ALPHA,
|
|
|
|
|
+ get_texture_src_type(stage->get_combine_alpha_source0()));
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
|
|
|
|
|
+ get_texture_operand_type(stage->get_combine_alpha_operand0()));
|
|
|
|
|
+ // fall through
|
|
|
|
|
|
|
|
- case TexGenAttrib::M_world_position:
|
|
|
|
|
- // We achieve world position coordinates by using the eye
|
|
|
|
|
- // position mode, and loading the transform of the root
|
|
|
|
|
- // node--thus putting the "eye" at the root.
|
|
|
|
|
- {
|
|
|
|
|
- GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
- GLP(PushMatrix)();
|
|
|
|
|
- CPT(TransformState) root_transform = _scene_setup->get_render_transform();
|
|
|
|
|
- GLP(LoadMatrixf)(root_transform->get_mat().get_data());
|
|
|
|
|
- GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
- GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
- GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
- GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
|
|
|
|
|
-
|
|
|
|
|
- GLP(TexGenfv)(GL_S, GL_EYE_PLANE, s_data);
|
|
|
|
|
- GLP(TexGenfv)(GL_T, GL_EYE_PLANE, t_data);
|
|
|
|
|
- GLP(TexGenfv)(GL_R, GL_EYE_PLANE, r_data);
|
|
|
|
|
- GLP(TexGenfv)(GL_Q, GL_EYE_PLANE, q_data);
|
|
|
|
|
-
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_S);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_T);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_R);
|
|
|
|
|
- GLP(Enable)(GL_TEXTURE_GEN_Q);
|
|
|
|
|
-
|
|
|
|
|
- GLP(MatrixMode)(GL_MODELVIEW);
|
|
|
|
|
- GLP(PopMatrix)();
|
|
|
|
|
|
|
+ default:
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
- break;
|
|
|
|
|
|
|
|
|
|
- case TexGenAttrib::M_point_sprite:
|
|
|
|
|
- nassertv(_supports_point_sprite);
|
|
|
|
|
- GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
|
|
|
|
|
- got_point_sprites = true;
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ GLint glmode = get_texture_apply_mode_type(stage->get_mode());
|
|
|
|
|
+ GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, glmode);
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
- if (got_point_sprites != _tex_gen_point_sprite) {
|
|
|
|
|
- _tex_gen_point_sprite = got_point_sprites;
|
|
|
|
|
- if (_tex_gen_point_sprite) {
|
|
|
|
|
- GLP(Enable)(GL_POINT_SPRITE_ARB);
|
|
|
|
|
|
|
+ GLP(MatrixMode)(GL_TEXTURE);
|
|
|
|
|
+ if (_current_tex_mat->has_stage(stage)) {
|
|
|
|
|
+ GLP(LoadMatrixf)(_current_tex_mat->get_mat(stage).get_data());
|
|
|
} else {
|
|
} else {
|
|
|
- GLP(Disable)(GL_POINT_SPRITE_ARB);
|
|
|
|
|
|
|
+ GLP(LoadIdentity)();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Certain texgen modes (sphere_map, cube_map) require forcing the
|
|
|
|
|
- // normal to be sent to the GL while the texgen mode is in effect.
|
|
|
|
|
- if (force_normal != _texgen_forced_normal) {
|
|
|
|
|
- if (force_normal) {
|
|
|
|
|
- force_normals();
|
|
|
|
|
- } else {
|
|
|
|
|
- undo_force_normals();
|
|
|
|
|
- }
|
|
|
|
|
- _texgen_forced_normal = force_normal;
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Disable the texture stages that are no longer used.
|
|
|
|
|
+ for (i = num_stages; i < num_old_stages; i++) {
|
|
|
|
|
+ _glActiveTexture(GL_TEXTURE0 + i);
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_1D);
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_2D);
|
|
|
|
|
+ if (_supports_3d_texture) {
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_3D);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (_supports_cube_map) {
|
|
|
|
|
+ GLP(Disable)(GL_TEXTURE_CUBE_MAP);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ _current_texture = new_texture;
|
|
|
|
|
+
|
|
|
|
|
+ // Changing the set of texture stages will require us to reissue the
|
|
|
|
|
+ // texgen and texmat attribs.
|
|
|
|
|
+ _needs_tex_gen = true;
|
|
|
|
|
+ _needs_tex_mat = true;
|
|
|
|
|
+
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::free_pointers
|
|
|
|
|
-// Access: Protected, Virtual
|
|
|
|
|
-// Description: Frees some memory that was explicitly allocated
|
|
|
|
|
-// within the glgsg.
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::specify_texture
|
|
|
|
|
+// Access: Protected
|
|
|
|
|
+// Description: Specifies the texture parameters.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void CLP(GraphicsStateGuardian)::
|
|
void CLP(GraphicsStateGuardian)::
|
|
|
-free_pointers() {
|
|
|
|
|
-}
|
|
|
|
|
|
|
+specify_texture(Texture *tex) {
|
|
|
|
|
+ GLenum target = get_texture_target(tex->get_texture_type());
|
|
|
|
|
+ if (target == GL_NONE) {
|
|
|
|
|
+ // Unsupported target (e.g. 3-d texturing on GL 1.1).
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::get_untextured_state
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Returns a RenderState object that represents
|
|
|
|
|
-// texturing off.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-CPT(RenderState) CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_untextured_state() {
|
|
|
|
|
- static CPT(RenderState) state;
|
|
|
|
|
- if (state == (RenderState *)NULL) {
|
|
|
|
|
- state = RenderState::make(TextureAttrib::make_off());
|
|
|
|
|
|
|
+ GLP(TexParameteri)(target, GL_TEXTURE_WRAP_S,
|
|
|
|
|
+ get_texture_wrap_mode(tex->get_wrap_u()));
|
|
|
|
|
+ if (target != GL_TEXTURE_1D) {
|
|
|
|
|
+ GLP(TexParameteri)(target, GL_TEXTURE_WRAP_T,
|
|
|
|
|
+ get_texture_wrap_mode(tex->get_wrap_v()));
|
|
|
}
|
|
}
|
|
|
- return state;
|
|
|
|
|
|
|
+ if (target == GL_TEXTURE_3D) {
|
|
|
|
|
+ GLP(TexParameteri)(target, GL_TEXTURE_WRAP_R,
|
|
|
|
|
+ get_texture_wrap_mode(tex->get_wrap_w()));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Colorf border_color = tex->get_border_color();
|
|
|
|
|
+ GLP(TexParameterfv)(target, GL_TEXTURE_BORDER_COLOR,
|
|
|
|
|
+ border_color.get_data());
|
|
|
|
|
+
|
|
|
|
|
+ Texture::FilterType minfilter = tex->get_minfilter();
|
|
|
|
|
+ Texture::FilterType magfilter = tex->get_magfilter();
|
|
|
|
|
+ bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps);
|
|
|
|
|
+
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (CLP(force_mipmaps)) {
|
|
|
|
|
+ minfilter = Texture::FT_linear_mipmap_linear;
|
|
|
|
|
+ magfilter = Texture::FT_linear;
|
|
|
|
|
+ uses_mipmaps = true;
|
|
|
|
|
+ }
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ if (_supports_generate_mipmap &&
|
|
|
|
|
+ (auto_generate_mipmaps || !tex->might_have_ram_image())) {
|
|
|
|
|
+ // If the hardware can automatically generate mipmaps, ask it to
|
|
|
|
|
+ // do so now, but only if the texture requires them.
|
|
|
|
|
+ GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, uses_mipmaps);
|
|
|
|
|
+
|
|
|
|
|
+ } else if (!tex->might_have_ram_image()) {
|
|
|
|
|
+ // If the hardware can't automatically generate mipmaps, but it's
|
|
|
|
|
+ // a dynamically generated texture (that is, the RAM image isn't
|
|
|
|
|
+ // available so it didn't pass through the CPU), then we'd better
|
|
|
|
|
+ // not try to enable mipmap filtering, since we can't generate
|
|
|
|
|
+ // mipmaps.
|
|
|
|
|
+ uses_mipmaps = false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER,
|
|
|
|
|
+ get_texture_filter_type(minfilter, !uses_mipmaps));
|
|
|
|
|
+ GLP(TexParameteri)(target, GL_TEXTURE_MAG_FILTER,
|
|
|
|
|
+ get_texture_filter_type(magfilter, true));
|
|
|
|
|
+
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::get_smooth_state
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Returns a RenderState object that represents
|
|
|
|
|
-// smooth, per-vertex shading.
|
|
|
|
|
|
|
+// Function: compute_gl_image_size
|
|
|
|
|
+// Description: Calculates how many bytes GL will expect to read for
|
|
|
|
|
+// a texture image, based on the number of pixels and
|
|
|
|
|
+// the GL format and type. This is only used for
|
|
|
|
|
+// debugging.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-CPT(RenderState) CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_smooth_state() {
|
|
|
|
|
- static CPT(RenderState) state;
|
|
|
|
|
- if (state == (RenderState *)NULL) {
|
|
|
|
|
- state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_smooth));
|
|
|
|
|
|
|
+static int
|
|
|
|
|
+compute_gl_image_size(int x_size, int y_size, int z_size,
|
|
|
|
|
+ int external_format, int type) {
|
|
|
|
|
+ int num_components = 0;
|
|
|
|
|
+ switch (external_format) {
|
|
|
|
|
+ case GL_COLOR_INDEX:
|
|
|
|
|
+ case GL_STENCIL_INDEX:
|
|
|
|
|
+ case GL_DEPTH_COMPONENT:
|
|
|
|
|
+ case GL_RED:
|
|
|
|
|
+ case GL_GREEN:
|
|
|
|
|
+ case GL_BLUE:
|
|
|
|
|
+ case GL_ALPHA:
|
|
|
|
|
+ case GL_LUMINANCE:
|
|
|
|
|
+ num_components = 1;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case GL_LUMINANCE_ALPHA:
|
|
|
|
|
+ num_components = 2;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case GL_BGR:
|
|
|
|
|
+ case GL_RGB:
|
|
|
|
|
+ num_components = 3;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case GL_BGRA:
|
|
|
|
|
+ case GL_RGBA:
|
|
|
|
|
+ num_components = 4;
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
- return state;
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: GLGraphicsStateGuardian::get_flat_state
|
|
|
|
|
-// Access: Protected, Static
|
|
|
|
|
-// Description: Returns a RenderState object that represents
|
|
|
|
|
-// flat, per-primitive shading.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-CPT(RenderState) CLP(GraphicsStateGuardian)::
|
|
|
|
|
-get_flat_state() {
|
|
|
|
|
- static CPT(RenderState) state;
|
|
|
|
|
- if (state == (RenderState *)NULL) {
|
|
|
|
|
- state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_flat));
|
|
|
|
|
|
|
+ int pixel_width = 0;
|
|
|
|
|
+ switch (type) {
|
|
|
|
|
+ case GL_UNSIGNED_BYTE:
|
|
|
|
|
+ pixel_width = 1 * num_components;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case GL_UNSIGNED_SHORT:
|
|
|
|
|
+ pixel_width = 2 * num_components;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case GL_UNSIGNED_BYTE_3_3_2:
|
|
|
|
|
+ nassertr(num_components == 3, 0);
|
|
|
|
|
+ pixel_width = 1;
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case GL_FLOAT:
|
|
|
|
|
+ pixel_width = 4 * num_components;
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
- return state;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ return x_size * y_size * z_size * pixel_width;
|
|
|
}
|
|
}
|
|
|
|
|
+#endif // NDEBUG
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::do_auto_rescale_normal
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::apply_texture
|
|
|
// Access: Protected
|
|
// Access: Protected
|
|
|
-// Description: Issues the appropriate GL commands to either rescale
|
|
|
|
|
-// or normalize the normals according to the current
|
|
|
|
|
-// transform.
|
|
|
|
|
|
|
+// Description: Updates OpenGL with the current information for this
|
|
|
|
|
+// texture, and makes it the current texture available
|
|
|
|
|
+// for rendering.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void CLP(GraphicsStateGuardian)::
|
|
void CLP(GraphicsStateGuardian)::
|
|
|
-do_auto_rescale_normal() {
|
|
|
|
|
- if (_transform->has_uniform_scale()) {
|
|
|
|
|
- if (IS_NEARLY_EQUAL(_transform->get_uniform_scale(), 1.0f)) {
|
|
|
|
|
- // If there's no scale at all, don't do anything.
|
|
|
|
|
- GLP(Disable)(GL_NORMALIZE);
|
|
|
|
|
- if (_supports_rescale_normal) {
|
|
|
|
|
- GLP(Disable)(GL_RESCALE_NORMAL);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- // There's a uniform scale; use the rescale feature if available.
|
|
|
|
|
- if (_supports_rescale_normal) {
|
|
|
|
|
- GLP(Enable)(GL_RESCALE_NORMAL);
|
|
|
|
|
- GLP(Disable)(GL_NORMALIZE);
|
|
|
|
|
- } else {
|
|
|
|
|
- GLP(Enable)(GL_NORMALIZE);
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+apply_texture(TextureContext *tc) {
|
|
|
|
|
+ CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
|
|
|
|
|
|
|
|
- } else {
|
|
|
|
|
- // If there's a non-uniform scale, normalize everything.
|
|
|
|
|
- GLP(Enable)(GL_NORMALIZE);
|
|
|
|
|
- if (_supports_rescale_normal) {
|
|
|
|
|
- GLP(Disable)(GL_RESCALE_NORMAL);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ add_to_texture_record(gtc);
|
|
|
|
|
+ GLenum target = get_texture_target(gtc->_texture->get_texture_type());
|
|
|
|
|
+ if (target == GL_NONE) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ GLP(BindTexture)(target, gtc->_index);
|
|
|
|
|
+
|
|
|
|
|
+ int dirty = gtc->get_dirty_flags();
|
|
|
|
|
+ if ((dirty & (Texture::DF_wrap | Texture::DF_filter | Texture::DF_border)) != 0) {
|
|
|
|
|
+ // We need to re-specify the texture properties.
|
|
|
|
|
+ specify_texture(gtc->_texture);
|
|
|
|
|
+ }
|
|
|
|
|
+ if ((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) {
|
|
|
|
|
+ // We need to re-upload the image.
|
|
|
|
|
+ upload_texture(gtc);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ gtc->clear_dirty_flags();
|
|
|
|
|
+
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GLGraphicsStateGuardian::do_issue_texture
|
|
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::upload_texture
|
|
|
// Access: Protected
|
|
// Access: Protected
|
|
|
-// Description: This is called by finish_modify_state() when the
|
|
|
|
|
-// texture state has changed.
|
|
|
|
|
|
|
+// Description: Uploads the entire texture image to OpenGL, including
|
|
|
|
|
+// all pages.
|
|
|
|
|
+//
|
|
|
|
|
+// The return value is true if successful, or false if
|
|
|
|
|
+// the texture has no image.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-void CLP(GraphicsStateGuardian)::
|
|
|
|
|
-do_issue_texture() {
|
|
|
|
|
- DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
|
|
|
|
|
|
|
+bool CLP(GraphicsStateGuardian)::
|
|
|
|
|
+upload_texture(CLP(TextureContext) *gtc) {
|
|
|
|
|
+ Texture *tex = gtc->_texture;
|
|
|
|
|
+ CPTA_uchar image = tex->get_ram_image();
|
|
|
|
|
+ if (image.is_null()) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- CPT(TextureAttrib) new_texture = _pending_texture->filter_to_max(_max_texture_stages);
|
|
|
|
|
-
|
|
|
|
|
- int num_stages = new_texture->get_num_on_stages();
|
|
|
|
|
- int num_old_stages = _current_texture->get_num_on_stages();
|
|
|
|
|
|
|
+ int width = tex->get_x_size();
|
|
|
|
|
+ int height = tex->get_y_size();
|
|
|
|
|
+ int depth = tex->get_z_size();
|
|
|
|
|
|
|
|
- nassertv(num_stages <= _max_texture_stages &&
|
|
|
|
|
- num_old_stages <= _max_texture_stages);
|
|
|
|
|
|
|
+ GLint internal_format = get_internal_image_format(tex->get_format());
|
|
|
|
|
+ GLint external_format = get_external_image_format(tex->get_format());
|
|
|
|
|
+ GLenum component_type = get_component_type(tex->get_component_type());
|
|
|
|
|
|
|
|
- _texture_involves_color_scale = false;
|
|
|
|
|
|
|
+ // Ensure that the texture fits within the GL's specified limits.
|
|
|
|
|
+ int max_dimension;
|
|
|
|
|
+ switch (tex->get_texture_type()) {
|
|
|
|
|
+ case Texture::TT_3d_texture:
|
|
|
|
|
+ max_dimension = _max_3d_texture_dimension;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- int i;
|
|
|
|
|
- for (i = 0; i < num_stages; i++) {
|
|
|
|
|
- TextureStage *stage = new_texture->get_on_stage(i);
|
|
|
|
|
- Texture *texture = new_texture->get_on_texture(stage);
|
|
|
|
|
- nassertv(texture != (Texture *)NULL);
|
|
|
|
|
-
|
|
|
|
|
- if (i >= num_old_stages ||
|
|
|
|
|
- stage != _current_texture->get_on_stage(i) ||
|
|
|
|
|
- texture != _current_texture->get_on_texture(stage) ||
|
|
|
|
|
- stage->involves_color_scale()) {
|
|
|
|
|
- // Stage i has changed. Issue the texture on this stage.
|
|
|
|
|
- _glActiveTexture(GL_TEXTURE0 + i);
|
|
|
|
|
|
|
+ case Texture::TT_cube_map:
|
|
|
|
|
+ max_dimension = _max_cube_map_dimension;
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- GLenum target = get_texture_target(texture->get_texture_type());
|
|
|
|
|
|
|
+ default:
|
|
|
|
|
+ max_dimension = _max_texture_dimension;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // First, turn off the previous texture mode.
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_1D);
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_2D);
|
|
|
|
|
- if (_supports_3d_texture) {
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_3D);
|
|
|
|
|
|
|
+ if (max_dimension == 0) {
|
|
|
|
|
+ // Guess this GL doesn't support cube mapping/3d textures.
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int texel_size = tex->get_num_components() * tex->get_component_width();
|
|
|
|
|
+
|
|
|
|
|
+ // If it doesn't fit, we have to reduce it on-the-fly. This is kind
|
|
|
|
|
+ // of expensive and it doesn't look great; it would have been better
|
|
|
|
|
+ // if the user had specified max-texture-dimension to reduce the
|
|
|
|
|
+ // texture at load time instead. Of course, the user doesn't always
|
|
|
|
|
+ // know ahead of time what the hardware limits are.
|
|
|
|
|
+ if (max_dimension > 0) {
|
|
|
|
|
+ if (width > max_dimension) {
|
|
|
|
|
+ int byte_chunk = texel_size;
|
|
|
|
|
+ int stride = 1;
|
|
|
|
|
+ int new_width = width;
|
|
|
|
|
+ while (new_width > max_dimension) {
|
|
|
|
|
+ stride <<= 1;
|
|
|
|
|
+ new_width >>= 1;
|
|
|
}
|
|
}
|
|
|
- if (_supports_cube_map) {
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_CUBE_MAP);
|
|
|
|
|
|
|
+ GLCAT.info()
|
|
|
|
|
+ << "Reducing width of " << tex->get_name()
|
|
|
|
|
+ << " from " << width << " to " << new_width << "\n";
|
|
|
|
|
+ image = reduce_image(image, byte_chunk, stride);
|
|
|
|
|
+ width = new_width;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (height > max_dimension) {
|
|
|
|
|
+ int byte_chunk = width * texel_size;
|
|
|
|
|
+ int stride = 1;
|
|
|
|
|
+ int new_height = height;
|
|
|
|
|
+ while (new_height > max_dimension) {
|
|
|
|
|
+ stride <<= 1;
|
|
|
|
|
+ new_height >>= 1;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Then, turn on the current texture mode.
|
|
|
|
|
- if (target == GL_NONE) {
|
|
|
|
|
- // Unsupported texture mode.
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ GLCAT.info()
|
|
|
|
|
+ << "Reducing height of " << tex->get_name()
|
|
|
|
|
+ << " from " << height << " to " << new_height << "\n";
|
|
|
|
|
+ image = reduce_image(image, byte_chunk, stride);
|
|
|
|
|
+ height = new_height;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (depth > max_dimension) {
|
|
|
|
|
+ int byte_chunk = height * width * texel_size;
|
|
|
|
|
+ int stride = 1;
|
|
|
|
|
+ int new_depth = depth;
|
|
|
|
|
+ while (new_depth > max_dimension) {
|
|
|
|
|
+ stride <<= 1;
|
|
|
|
|
+ new_depth >>= 1;
|
|
|
}
|
|
}
|
|
|
- GLP(Enable)(target);
|
|
|
|
|
-
|
|
|
|
|
- TextureContext *tc = texture->prepare_now(_prepared_objects, this);
|
|
|
|
|
- apply_texture(tc);
|
|
|
|
|
|
|
+ GLCAT.info()
|
|
|
|
|
+ << "Reducing depth of " << tex->get_name()
|
|
|
|
|
+ << " from " << depth << " to " << new_depth << "\n";
|
|
|
|
|
+ image = reduce_image(image, byte_chunk, stride);
|
|
|
|
|
+ depth = new_depth;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (stage->involves_color_scale() && _color_scale_enabled) {
|
|
|
|
|
- Colorf color = stage->get_color();
|
|
|
|
|
- color.set(color[0] * _current_color_scale[0],
|
|
|
|
|
- color[1] * _current_color_scale[1],
|
|
|
|
|
- color[2] * _current_color_scale[2],
|
|
|
|
|
- color[3] * _current_color_scale[3]);
|
|
|
|
|
- _texture_involves_color_scale = true;
|
|
|
|
|
- GLP(TexEnvfv)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color.get_data());
|
|
|
|
|
- } else {
|
|
|
|
|
- GLP(TexEnvfv)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, stage->get_color().get_data());
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (!_supports_bgr) {
|
|
|
|
|
+ // If the GL doesn't claim to support BGR, we may have to reverse
|
|
|
|
|
+ // the component ordering of the image.
|
|
|
|
|
+ image = fix_component_ordering(image, external_format, tex);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- if (stage->get_mode() == TextureStage::M_decal) {
|
|
|
|
|
- if (texture->get_num_components() < 3) {
|
|
|
|
|
- // Make a special case for 1- and 2-channel decal textures.
|
|
|
|
|
- // OpenGL does not define their use with GL_DECAL for some
|
|
|
|
|
- // reason, so implement them using the combiner instead.
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- // Normal 3- and 4-channel decal textures.
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ int wanted_size =
|
|
|
|
|
+ compute_gl_image_size(width, height, depth, external_format, component_type);
|
|
|
|
|
+ nassertr(wanted_size == (int)image.size(), false);
|
|
|
|
|
+#endif // NDEBUG
|
|
|
|
|
+
|
|
|
|
|
+ GLP(PixelStorei)(GL_UNPACK_ALIGNMENT, 1);
|
|
|
|
|
+
|
|
|
|
|
+ bool uses_mipmaps = (tex->uses_mipmaps() && !CLP(ignore_mipmaps)) || CLP(force_mipmaps);
|
|
|
|
|
+
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (CLP(force_mipmaps)) {
|
|
|
|
|
+ uses_mipmaps = true;
|
|
|
|
|
+ }
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+ bool success = true;
|
|
|
|
|
+
|
|
|
|
|
+ if (tex->get_texture_type() == Texture::TT_cube_map) {
|
|
|
|
|
+ // A cube map must load six different 2-d images (which are stored
|
|
|
|
|
+ // as the six pages of the system ram image).
|
|
|
|
|
+ if (!_supports_cube_map) {
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ size_t page_size = height * width * texel_size;
|
|
|
|
|
+ const unsigned char *image_base = image;
|
|
|
|
|
+
|
|
|
|
|
+ success = success && upload_texture_image
|
|
|
|
|
+ (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
|
|
|
|
|
+ internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
+ image_base);
|
|
|
|
|
+ image_base += page_size;
|
|
|
|
|
+
|
|
|
|
|
+ success = success && upload_texture_image
|
|
|
|
|
+ (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
|
|
|
|
|
+ internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
+ image_base);
|
|
|
|
|
+ image_base += page_size;
|
|
|
|
|
+
|
|
|
|
|
+ success = success && upload_texture_image
|
|
|
|
|
+ (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
|
|
|
|
|
+ internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
+ image_base);
|
|
|
|
|
+ image_base += page_size;
|
|
|
|
|
+
|
|
|
|
|
+ success = success && upload_texture_image
|
|
|
|
|
+ (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
|
|
|
|
|
+ internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
+ image_base);
|
|
|
|
|
+ image_base += page_size;
|
|
|
|
|
+
|
|
|
|
|
+ success = success && upload_texture_image
|
|
|
|
|
+ (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
|
|
|
|
|
+ internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
+ image_base);
|
|
|
|
|
+ image_base += page_size;
|
|
|
|
|
+
|
|
|
|
|
+ success = success && upload_texture_image
|
|
|
|
|
+ (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
|
|
|
|
|
+ internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
+ image_base);
|
|
|
|
|
+ image_base += page_size;
|
|
|
|
|
+
|
|
|
|
|
+ nassertr((size_t)(image_base - image) == image.size(), false);
|
|
|
|
|
|
|
|
- } else if (stage->get_mode() == TextureStage::M_combine) {
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_RGB_SCALE, stage->get_rgb_scale());
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_ALPHA_SCALE, stage->get_alpha_scale());
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB,
|
|
|
|
|
- get_texture_combine_type(stage->get_combine_rgb_mode()));
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Any other kind of texture can be loaded all at once.
|
|
|
|
|
+ success = upload_texture_image
|
|
|
|
|
+ (gtc, uses_mipmaps, get_texture_target(tex->get_texture_type()),
|
|
|
|
|
+ internal_format, width, height, depth, external_format, component_type,
|
|
|
|
|
+ image);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- switch (stage->get_num_combine_rgb_operands()) {
|
|
|
|
|
- case 3:
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_RGB,
|
|
|
|
|
- get_texture_src_type(stage->get_combine_rgb_source2()));
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_RGB,
|
|
|
|
|
- get_texture_operand_type(stage->get_combine_rgb_operand2()));
|
|
|
|
|
- // fall through
|
|
|
|
|
|
|
+ if (success) {
|
|
|
|
|
+ gtc->_already_applied = true;
|
|
|
|
|
+ gtc->_internal_format = internal_format;
|
|
|
|
|
+ gtc->_width = width;
|
|
|
|
|
+ gtc->_height = height;
|
|
|
|
|
+ gtc->_depth = depth;
|
|
|
|
|
|
|
|
- case 2:
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_RGB,
|
|
|
|
|
- get_texture_src_type(stage->get_combine_rgb_source1()));
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB,
|
|
|
|
|
- get_texture_operand_type(stage->get_combine_rgb_operand1()));
|
|
|
|
|
- // fall through
|
|
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (uses_mipmaps && CLP(save_mipmaps)) {
|
|
|
|
|
+ save_mipmap_images(tex);
|
|
|
|
|
+ }
|
|
|
|
|
+#endif
|
|
|
|
|
|
|
|
- case 1:
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_RGB,
|
|
|
|
|
- get_texture_src_type(stage->get_combine_rgb_source0()));
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND0_RGB,
|
|
|
|
|
- get_texture_operand_type(stage->get_combine_rgb_operand0()));
|
|
|
|
|
- // fall through
|
|
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- default:
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_ALPHA,
|
|
|
|
|
- get_texture_combine_type(stage->get_combine_alpha_mode()));
|
|
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- switch (stage->get_num_combine_alpha_operands()) {
|
|
|
|
|
- case 3:
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_ALPHA,
|
|
|
|
|
- get_texture_src_type(stage->get_combine_alpha_source2()));
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
|
|
|
|
|
- get_texture_operand_type(stage->get_combine_alpha_operand2()));
|
|
|
|
|
- // fall through
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: GLGraphicsStateGuardian::upload_texture_image
|
|
|
|
|
+// Access: Protected
|
|
|
|
|
+// Description: Loads a texture image, or one page of a cube map
|
|
|
|
|
+// image, from system RAM to texture memory.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+bool CLP(GraphicsStateGuardian)::
|
|
|
|
|
+upload_texture_image(CLP(TextureContext) *gtc,
|
|
|
|
|
+ bool uses_mipmaps,
|
|
|
|
|
+ GLenum target, GLint internal_format,
|
|
|
|
|
+ int width, int height, int depth,
|
|
|
|
|
+ GLint external_format, GLenum component_type,
|
|
|
|
|
+ const unsigned char *image) {
|
|
|
|
|
+ if (target == GL_NONE) {
|
|
|
|
|
+ // Unsupported target (e.g. 3-d texturing on GL 1.1).
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ PStatTimer timer(_load_texture_pcollector);
|
|
|
|
|
|
|
|
- case 2:
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_ALPHA,
|
|
|
|
|
- get_texture_src_type(stage->get_combine_alpha_source1()));
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
|
|
|
|
|
- get_texture_operand_type(stage->get_combine_alpha_operand1()));
|
|
|
|
|
- // fall through
|
|
|
|
|
|
|
+ if (uses_mipmaps) {
|
|
|
|
|
+#ifndef NDEBUG
|
|
|
|
|
+ if (CLP(show_mipmaps) && target == GL_TEXTURE_2D) {
|
|
|
|
|
+ build_phony_mipmaps(gtc->_texture);
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
|
|
+ return true;
|
|
|
|
|
+
|
|
|
|
|
+ } else
|
|
|
|
|
+#endif
|
|
|
|
|
+ if (!_supports_generate_mipmap || !auto_generate_mipmaps) {
|
|
|
|
|
+ // We only need to build the mipmaps by hand if the GL
|
|
|
|
|
+ // doesn't support generating them automatically.
|
|
|
|
|
+ bool success = true;
|
|
|
|
|
+#ifdef DO_PSTATS
|
|
|
|
|
+ _data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type) * 4 / 3);
|
|
|
|
|
+#endif
|
|
|
|
|
+ switch (target) {
|
|
|
|
|
+ case GL_TEXTURE_1D:
|
|
|
|
|
+ GLUP(Build1DMipmaps)(target, internal_format, width,
|
|
|
|
|
+ external_format, component_type, image);
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- case 1:
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_ALPHA,
|
|
|
|
|
- get_texture_src_type(stage->get_combine_alpha_source0()));
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
|
|
|
|
|
- get_texture_operand_type(stage->get_combine_alpha_operand0()));
|
|
|
|
|
- // fall through
|
|
|
|
|
|
|
+ case GL_TEXTURE_3D:
|
|
|
|
|
+#ifdef GLU_VERSION_1_3
|
|
|
|
|
+ GLUP(Build3DMipmaps)(target, internal_format,
|
|
|
|
|
+ width, height, depth,
|
|
|
|
|
+ external_format, component_type, image);
|
|
|
|
|
+#else // GLU_VERSION_1_3
|
|
|
|
|
+ // Prior to GLU 1.3, there was no gluBuild3DMipmaps() call.
|
|
|
|
|
+ // Just fall through and load the texture without mipmaps.
|
|
|
|
|
+ GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
|
+ success = false;
|
|
|
|
|
+#endif // GLU_VERSION_1_3
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
default:
|
|
default:
|
|
|
- break;
|
|
|
|
|
|
|
+ GLUP(Build2DMipmaps)(target, internal_format,
|
|
|
|
|
+ width, height,
|
|
|
|
|
+ external_format, component_type, image);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
|
|
+ if (success) {
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!gtc->_already_applied ||
|
|
|
|
|
+ gtc->_internal_format != internal_format ||
|
|
|
|
|
+ gtc->_width != width ||
|
|
|
|
|
+ gtc->_height != height ||
|
|
|
|
|
+ gtc->_depth != depth) {
|
|
|
|
|
+ // We need to reload a new image.
|
|
|
|
|
+#ifdef DO_PSTATS
|
|
|
|
|
+ _data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type));
|
|
|
|
|
+#endif
|
|
|
|
|
+ switch (target) {
|
|
|
|
|
+ case GL_TEXTURE_1D:
|
|
|
|
|
+ GLP(TexImage1D)(target, 0, internal_format,
|
|
|
|
|
+ width, 0,
|
|
|
|
|
+ external_format, component_type, image);
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
|
|
+ case GL_TEXTURE_3D:
|
|
|
|
|
+ if (_supports_3d_texture) {
|
|
|
|
|
+ _glTexImage3D(target, 0, internal_format,
|
|
|
|
|
+ width, height, depth, 0,
|
|
|
|
|
+ external_format, component_type, image);
|
|
|
} else {
|
|
} else {
|
|
|
- GLint glmode = get_texture_apply_mode_type(stage->get_mode());
|
|
|
|
|
- GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, glmode);
|
|
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
+ break;
|
|
|
|
|
|
|
|
- GLP(MatrixMode)(GL_TEXTURE);
|
|
|
|
|
- if (_current_tex_mat->has_stage(stage)) {
|
|
|
|
|
- GLP(LoadMatrixf)(_current_tex_mat->get_mat(stage).get_data());
|
|
|
|
|
|
|
+ default:
|
|
|
|
|
+ GLP(TexImage2D)(target, 0, internal_format,
|
|
|
|
|
+ width, height, 0,
|
|
|
|
|
+ external_format, component_type, image);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // We can reload the image over the previous image, possibly
|
|
|
|
|
+ // saving on texture memory fragmentation.
|
|
|
|
|
+ switch (target) {
|
|
|
|
|
+ case GL_TEXTURE_1D:
|
|
|
|
|
+ GLP(TexSubImage1D)(target, 0, 0, width,
|
|
|
|
|
+ external_format, component_type, image);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case GL_TEXTURE_3D:
|
|
|
|
|
+ if (_supports_3d_texture) {
|
|
|
|
|
+ _glTexSubImage3D(target, 0, 0, 0, 0, width, height, depth,
|
|
|
|
|
+ external_format, component_type, image);
|
|
|
} else {
|
|
} else {
|
|
|
- GLP(LoadIdentity)();
|
|
|
|
|
|
|
+ report_my_gl_errors();
|
|
|
|
|
+ return false;
|
|
|
}
|
|
}
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ GLP(TexSubImage2D)(target, 0, 0, 0, width, height,
|
|
|
|
|
+ external_format, component_type, image);
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Disable the texture stages that are no longer used.
|
|
|
|
|
- for (i = num_stages; i < num_old_stages; i++) {
|
|
|
|
|
- _glActiveTexture(GL_TEXTURE0 + i);
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_1D);
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_2D);
|
|
|
|
|
- if (_supports_3d_texture) {
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_3D);
|
|
|
|
|
- }
|
|
|
|
|
- if (_supports_cube_map) {
|
|
|
|
|
- GLP(Disable)(GL_TEXTURE_CUBE_MAP);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Report the error message explicitly if the GL texture creation
|
|
|
|
|
+ // failed.
|
|
|
|
|
+ GLenum error_code = GLP(GetError)();
|
|
|
|
|
+ if (error_code != GL_NO_ERROR) {
|
|
|
|
|
+ const GLubyte *error_string = GLUP(ErrorString)(error_code);
|
|
|
|
|
+ GLCAT.error()
|
|
|
|
|
+ << "GL texture creation failed for " << gtc->_texture->get_name();
|
|
|
|
|
+ if (error_string != (const GLubyte *)NULL) {
|
|
|
|
|
+ GLCAT.error(false)
|
|
|
|
|
+ << " : " << error_string;
|
|
|
}
|
|
}
|
|
|
|
|
+ GLCAT.error(false)
|
|
|
|
|
+ << "\n";
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _current_texture = new_texture;
|
|
|
|
|
-
|
|
|
|
|
- // Changing the set of texture stages will require us to reissue the
|
|
|
|
|
- // texgen and texmat attribs.
|
|
|
|
|
- _needs_tex_gen = true;
|
|
|
|
|
- _needs_tex_mat = true;
|
|
|
|
|
-
|
|
|
|
|
- report_my_gl_errors();
|
|
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|