From bccfb404631794fdc0d47bc2a790844a4ef417c2 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 31 Jul 2004 15:49:22 +0000 Subject: [PATCH] clean up texture, projector more --- panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx | 3 +- panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx | 3 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 78 +++++++++++----- .../src/glstuff/glGraphicsStateGuardian_src.h | 5 ++ panda/src/glstuff/glTextureContext_src.h | 2 +- panda/src/gobj/pixelBuffer.I | 88 ------------------- panda/src/gobj/pixelBuffer.cxx | 18 ---- panda/src/gobj/pixelBuffer.h | 13 --- panda/src/gobj/texture.I | 20 +++++ panda/src/gobj/texture.cxx | 41 ++++++--- panda/src/gobj/texture.h | 5 ++ panda/src/pgraph/texProjectorEffect.cxx | 18 +++- 12 files changed, 136 insertions(+), 158 deletions(-) diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index 9cd04f04e5..8f33a41f7e 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -3067,7 +3067,8 @@ copy_texture(Texture *tex, const DisplayRegion *dr) { dr->get_region_pixels(xo, yo, w, h); PixelBuffer *pb = tex->_pbuffer; - pb->set_size(0,0,w-xo,h-yo); + pb->set_xsize(w-xo); + pb->set_ysize(h-yo); TextureContext *tc = tex->prepare_now(get_prepared_objects(), this); if (tc == (TextureContext *)NULL) { diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index de33da576a..e333d0bf64 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -3065,7 +3065,8 @@ copy_texture(Texture *tex, const DisplayRegion *dr) { dr->get_region_pixels(xo, yo, w, h); PixelBuffer *pb = tex->_pbuffer; - pb->set_size(0,0,w-xo,h-yo); + pb->set_xsize(w-xo); + pb->set_ysize(h-yo); TextureContext *tc = tex->prepare_now(get_prepared_objects(), this); if (tc == (TextureContext *)NULL) { diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 745e695e4d..5192351181 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -341,6 +341,27 @@ reset() { _edge_clamp = GL_CLAMP_TO_EDGE; } + _border_clamp = GL_CLAMP; + if (has_extension("GL_ARB_texture_border_clamp") || + is_at_least_version(1, 3)) { + _border_clamp = GL_CLAMP_TO_BORDER; + } + + _mirror_repeat = GL_REPEAT; + if (has_extension("GL_ARB_texture_mirrored_repeat") || + is_at_least_version(1, 4)) { + _mirror_repeat = GL_MIRRORED_REPEAT; + } + + _mirror_clamp = GL_CLAMP; + _mirror_edge_clamp = _edge_clamp; + _mirror_border_clamp = _border_clamp; + if (has_extension("GL_EXT_texture_mirror_clamp")) { + _mirror_clamp = GL_MIRROR_CLAMP_EXT; + _mirror_edge_clamp = GL_MIRROR_CLAMP_TO_EDGE_EXT; + _mirror_border_clamp = GL_MIRROR_CLAMP_TO_BORDER_EXT; + } + report_my_gl_errors(); _buffer_mask = 0; @@ -1850,11 +1871,11 @@ apply_texture(TextureContext *tc) { bind_texture(gtc); int dirty = gtc->get_dirty_flags(); - if ((dirty & (Texture::DF_wrap | Texture::DF_filter)) != 0) { + 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) { + 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); } @@ -2035,7 +2056,8 @@ copy_texture(Texture *tex, const DisplayRegion *dr) { #endif PixelBuffer *pb = tex->_pbuffer; - pb->set_size(xo,yo,w,h); + pb->set_xsize(w); + pb->set_ysize(h); TextureContext *tc = tex->prepare_now(get_prepared_objects(), this); nassertv(tc != (TextureContext *)NULL); @@ -2043,7 +2065,7 @@ copy_texture(Texture *tex, const DisplayRegion *dr) { GLP(CopyTexImage2D)(GL_TEXTURE_2D, 0, get_internal_image_format(pb->get_format()), - xo, yo, w, h, pb->get_border()); + xo, yo, w, h, tex->get_border_width()); // Clear the internal texture state, since we've just monkeyed with it. modify_state(get_untextured_state()); @@ -2138,7 +2160,7 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) { #ifdef GSG_VERBOSE GLCAT.debug() - << "glReadPixels(" << pb->get_xorg() << ", " << pb->get_yorg() + << "glReadPixels(" << xo << ", " << yo << ", " << pb->get_xsize() << ", " << pb->get_ysize() << ", "; switch (external_format) { @@ -2179,11 +2201,11 @@ copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) { // pixelbuffer "origin" represents upper left screen point at which // pixelbuffer should be drawn using draw_pixel_buffer nassertr(!pb->_image.empty(), false); - GLP(ReadPixels)(pb->get_xorg() + xo, pb->get_yorg() + yo, - pb->get_xsize(), pb->get_ysize(), - external_format, - get_image_type(pb->get_image_type()), - pb->_image.p()); + GLP(ReadPixels)(xo, yo, + pb->get_xsize(), pb->get_ysize(), + external_format, + get_image_type(pb->get_image_type()), + pb->_image.p()); // We may have to reverse the byte ordering of the image if GL // didn't do it for us. @@ -3207,6 +3229,10 @@ specify_texture(Texture *tex) { GLP(TexParameteri)(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, get_texture_wrap_mode(tex->get_wrapv())); + Colorf border_color = tex->get_border_color(); + GLP(TexParameterfv)(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, + border_color.get_data()); + Texture::FilterType minfilter = tex->get_minfilter(); Texture::FilterType magfilter = tex->get_magfilter(); @@ -3336,7 +3362,7 @@ apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex) { << "glTexImage2D(GL_TEXTURE_2D, " << (int)internal_format << ", " << width << ", " << height << ", " - << pb->get_border() << ", " << (int)external_format << ", " + << tex->get_border_width() << ", " << (int)external_format << ", " << (int)type << ", " << tex->get_name() << ")\n"; #endif @@ -3371,7 +3397,7 @@ apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex) { gtc->_internal_format = internal_format; gtc->_width = width; gtc->_height = height; - gtc->_border = 0; + gtc->_border_width = 0; #ifndef NDEBUG if (CLP(save_mipmaps)) { @@ -3387,22 +3413,22 @@ apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex) { } } - GLint border = pb->get_border(); + GLint border_width = tex->get_border_width(); if (!gtc->_already_applied || gtc->_internal_format != internal_format || gtc->_width != width || gtc->_height != height || - gtc->_border != border) { + gtc->_border_width != border_width) { // We need to reload a new image. GLP(TexImage2D)(GL_TEXTURE_2D, 0, internal_format, - width, height, pb->get_border(), + width, height, border_width, external_format, type, image); gtc->_already_applied = true; gtc->_internal_format = internal_format; gtc->_width = width; gtc->_height = height; - gtc->_border = border; + gtc->_border_width = border_width; } else { // We can reload the image over the previous image, saving on @@ -3623,11 +3649,11 @@ draw_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr) { << (void *)pb->_image.p() << ")" << endl; #endif - GLP(RasterPos2i)( pb->get_xorg(), pb->get_yorg() ); - GLP(DrawPixels)( pb->get_xsize(), pb->get_ysize(), - get_external_image_format(pb->get_format()), - get_image_type(pb->get_image_type()), - pb->_image.p() ); + GLP(RasterPos2i)(0, 0); + GLP(DrawPixels)(pb->get_xsize(), pb->get_ysize(), + get_external_image_format(pb->get_format()), + get_image_type(pb->get_image_type()), + pb->_image.p() ); GLP(MatrixMode)( GL_PROJECTION ); GLP(PopMatrix)(); @@ -3663,14 +3689,18 @@ get_texture_wrap_mode(Texture::WrapMode wm) { switch (wm) { case Texture::WM_clamp: return _edge_clamp; + case Texture::WM_repeat: return GL_REPEAT; case Texture::WM_mirror: + return _mirror_repeat; + case Texture::WM_mirror_once: + return _mirror_border_clamp; + case Texture::WM_border_color: - // These are unsupported for now. - return GL_REPEAT; + return _border_clamp; case Texture::WM_invalid: break; @@ -4684,7 +4714,7 @@ build_phony_mipmap_level(int level, int xsize, int ysize) { GLenum type = get_image_type(pb->get_image_type()); GLP(TexImage2D)(GL_TEXTURE_2D, level, internal_format, - pb->get_xsize(), pb->get_ysize(), pb->get_border(), + pb->get_xsize(), pb->get_ysize(), 0, external_format, type, pb->_image ); delete pb; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 028d25c7be..9c2eec4c90 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -337,6 +337,11 @@ public: PFNGLMULTITEXCOORD2FVPROC _glMultiTexCoord2fv; GLenum _edge_clamp; + GLenum _border_clamp; + GLenum _mirror_repeat; + GLenum _mirror_clamp; + GLenum _mirror_edge_clamp; + GLenum _mirror_border_clamp; public: static GraphicsStateGuardian * diff --git a/panda/src/glstuff/glTextureContext_src.h b/panda/src/glstuff/glTextureContext_src.h index 4ab86f2acb..682dfe311b 100644 --- a/panda/src/glstuff/glTextureContext_src.h +++ b/panda/src/glstuff/glTextureContext_src.h @@ -40,7 +40,7 @@ public: GLint _internal_format; GLsizei _width; GLsizei _height; - GLint _border; + GLint _border_width; public: static TypeHandle get_class_type() { diff --git a/panda/src/gobj/pixelBuffer.I b/panda/src/gobj/pixelBuffer.I index d94f4e9cdb..a566774c8f 100644 --- a/panda/src/gobj/pixelBuffer.I +++ b/panda/src/gobj/pixelBuffer.I @@ -97,63 +97,6 @@ INLINE void PixelBuffer::set_ysize(int size) } } -//////////////////////////////////////////////////////////////////// -// Function: PixelBuffer::set_xorg -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void PixelBuffer::set_xorg(int org) -{ - if (_xorg != org) { - _xorg = org; - make_dirty(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: PixelBuffer::set_yorg -// Access: -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void PixelBuffer::set_yorg(int org) -{ - if (_yorg != org) { - _yorg = org; - make_dirty(); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: PixelBuffer::set_size -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void PixelBuffer:: -set_size(int x_org, int y_org, int x_size, int y_size) { - if ((_xsize != x_size) || (_ysize != y_size) || - (_xorg != x_org) || (_yorg != y_org)) { - make_dirty(); - } - - _xsize = x_size; - _ysize = y_size; - _xorg = x_org; - _yorg = y_org; -} - -//////////////////////////////////////////////////////////////////// -// Function: PixelBuffer::set_border -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE void PixelBuffer:: -set_border(int border) { - if (_border != border) { - _border = border; - make_dirty(); - } -} - //////////////////////////////////////////////////////////////////// // Function: PixelBuffer::set_num_components // Access: Public @@ -236,37 +179,6 @@ get_ysize() const { return _ysize; } - -//////////////////////////////////////////////////////////////////// -// Function: PixelBuffer::get_xorg -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE int PixelBuffer:: -get_xorg() const { - return _xorg; -} - -//////////////////////////////////////////////////////////////////// -// Function: PixelBuffer::get_yorg -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE int PixelBuffer:: -get_yorg() const { - return _yorg; -} - -//////////////////////////////////////////////////////////////////// -// Function: PixelBuffer::get_border -// Access: Public -// Description: -//////////////////////////////////////////////////////////////////// -INLINE int PixelBuffer:: -get_border() const { - return _border; -} - //////////////////////////////////////////////////////////////////// // Function: PixelBuffer::get_num_components // Access: Public diff --git a/panda/src/gobj/pixelBuffer.cxx b/panda/src/gobj/pixelBuffer.cxx index 857c7f5bdd..2ed2262b7d 100644 --- a/panda/src/gobj/pixelBuffer.cxx +++ b/panda/src/gobj/pixelBuffer.cxx @@ -34,9 +34,6 @@ PixelBuffer(void) : ImageBuffer() { _xsize = 0; _ysize = 0; - _xorg = 0; - _yorg = 0; - _border = 0; _format = F_rgb; _type = T_unsigned_byte; _num_components = 3; @@ -58,9 +55,6 @@ PixelBuffer(int xsize, int ysize, int components, int component_width, { _xsize = xsize; _ysize = ysize; - _xorg = 0; - _yorg = 0; - _border = 0; _num_components = components; _component_width = component_width; _type = type; @@ -80,9 +74,6 @@ PixelBuffer(int xsize, int ysize, int components, int component_width, Type type { _xsize = xsize; _ysize = ysize; - _xorg = 0; - _yorg = 0; - _border = 0; _num_components = components; _component_width = component_width; _type = type; @@ -102,9 +93,6 @@ PixelBuffer:: PixelBuffer(const PixelBuffer ©) : _xsize(copy._xsize), _ysize(copy._ysize), - _xorg(copy._xorg), - _yorg(copy._yorg), - _border(copy._border), _num_components(copy._num_components), _component_width(copy._component_width), _format(copy._format), @@ -123,9 +111,6 @@ void PixelBuffer:: operator = (const PixelBuffer ©) { _xsize = copy._xsize; _ysize = copy._ysize; - _xorg = copy._xorg; - _yorg = copy._yorg; - _border = copy._border; _num_components = copy._num_components; _component_width = copy._component_width; _format = copy._format; @@ -409,11 +394,8 @@ store(PNMImage &pnmimage) const { void PixelBuffer:: copy(const PixelBuffer *pb) { nassertv(pb != NULL); - _xorg = pb->_xorg; - _yorg = pb->_yorg; _xsize = pb->_xsize; _ysize = pb->_ysize; - _border = pb->_border; _num_components = pb->_num_components; _component_width = pb->_component_width; _format = pb->_format; diff --git a/panda/src/gobj/pixelBuffer.h b/panda/src/gobj/pixelBuffer.h index 9bbddf5a88..0804ded40f 100644 --- a/panda/src/gobj/pixelBuffer.h +++ b/panda/src/gobj/pixelBuffer.h @@ -108,10 +108,6 @@ public: INLINE void set_xsize(int size); INLINE void set_ysize(int size); - INLINE void set_xorg(int org); - INLINE void set_yorg(int org); - INLINE void set_size(int x_org, int y_org, int x_size, int y_size); - INLINE void set_border(int border); INLINE void set_num_components(int num_components); INLINE void set_component_width(int component_width); INLINE void set_format(Format format); @@ -120,9 +116,6 @@ public: INLINE int get_xsize() const; INLINE int get_ysize() const; - INLINE int get_xorg() const; - INLINE int get_yorg() const; - INLINE int get_border() const; INLINE int get_num_components() const; INLINE int get_component_width() const; INLINE Format get_format() const; @@ -163,12 +156,6 @@ private: protected: int _xsize; int _ysize; - - // pixelbuffer "origin" represents upper left screen point at which - // pixelbuffer should be drawn using draw_pixel_buffer - int _xorg; - int _yorg; - int _border; int _num_components; int _component_width; Format _format; diff --git a/panda/src/gobj/texture.I b/panda/src/gobj/texture.I index 3a346faa77..80ee66da36 100644 --- a/panda/src/gobj/texture.I +++ b/panda/src/gobj/texture.I @@ -72,6 +72,26 @@ get_anisotropic_degree() const { return _anisotropic_degree; } +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_border_color +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE Colorf Texture:: +get_border_color() const { + return _border_color; +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::get_border_width +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE int Texture:: +get_border_width() const { + return _border_width; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::uses_mipmaps // Access: Public diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index a004282b39..54f8f62399 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -142,7 +142,8 @@ Texture() : ImageBuffer() { _pbuffer = new PixelBuffer; // _has_requested_size = false; _all_dirty_flags = 0; - memset(&_border_color,0,sizeof(Colorf)); + _border_color.set(0.0f, 0.0f, 0.0f, 1.0f); + _border_width = 0; } @@ -152,7 +153,8 @@ Texture() : ImageBuffer() { // Description: //////////////////////////////////////////////////////////////////// Texture:: -Texture(int xsize, int ysize, int components, int component_width, PixelBuffer::Type type, +Texture(int xsize, int ysize, int components, int component_width, + PixelBuffer::Type type, PixelBuffer::Format format, bool bAllocateRAM) : ImageBuffer() { _magfilter = FT_linear; _minfilter = FT_linear; @@ -163,7 +165,8 @@ Texture(int xsize, int ysize, int components, int component_width, PixelBuffer:: _pbuffer = new PixelBuffer(xsize,ysize,components,component_width,type,format,bAllocateRAM); // _has_requested_size = false; _all_dirty_flags = 0; - memset(&_border_color,0,sizeof(Colorf)); + _border_color.set(0.0f, 0.0f, 0.0f, 1.0f); + _border_width = 0; } //////////////////////////////////////////////////////////////////// @@ -406,11 +409,33 @@ set_anisotropic_degree(int anisotropic_degree) { //////////////////////////////////////////////////////////////////// // Function: Texture::set_border_color // Access: Published -// Description: +// Description: Specifies the uniform color of the texture border, if +// it has one (see set_border_width()), and if the +// border color is not part of the image. //////////////////////////////////////////////////////////////////// void Texture:: set_border_color(const Colorf &color) { - memcpy(&_border_color,&color,sizeof(Colorf)); + if (_border_color != color) { + mark_dirty(DF_border); + _border_color = color; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: Texture::set_border_width +// Access: Published +// Description: Specifies the width of the texture border, in pixels. +// Generally, this can be either 0 or 1, and the default +// is 0. This is intended to be used for tiling large +// textures, although it has one or two other +// applications. +//////////////////////////////////////////////////////////////////// +void Texture:: +set_border_width(int width) { + if (_border_width != width) { + mark_dirty(DF_border); + _border_width = width; + } } //////////////////////////////////////////////////////////////////// @@ -870,9 +895,6 @@ fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata) { _pbuffer->set_format(format); _pbuffer->set_xsize(scan.get_int32()); _pbuffer->set_ysize(scan.get_int32()); - _pbuffer->set_xorg(scan.get_int32()); - _pbuffer->set_yorg(scan.get_int32()); - _pbuffer->set_border(scan.get_uint8()); _pbuffer->set_image_type((PixelBuffer::Type)scan.get_uint8()); _pbuffer->set_num_components(scan.get_uint8()); _pbuffer->set_component_width(scan.get_uint8()); @@ -927,9 +949,6 @@ write_datagram(BamWriter *manager, Datagram &me) { if (has_rawdata) { me.add_int32(_pbuffer->get_xsize()); me.add_int32(_pbuffer->get_ysize()); - me.add_int32(_pbuffer->get_xorg()); - me.add_int32(_pbuffer->get_yorg()); - me.add_uint8(_pbuffer->get_border()); me.add_uint8(_pbuffer->get_image_type()); me.add_uint8(_pbuffer->get_num_components()); me.add_uint8(_pbuffer->get_component_width()); diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index 53ca2bd3cd..b85cb674ed 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -91,12 +91,15 @@ PUBLISHED: void set_magfilter(FilterType filter); void set_anisotropic_degree(int anisotropic_degree); void set_border_color(const Colorf &color); + void set_border_width(int border_width); INLINE WrapMode get_wrapu() const; INLINE WrapMode get_wrapv() const; INLINE FilterType get_minfilter() const; INLINE FilterType get_magfilter() const; INLINE int get_anisotropic_degree() const; + INLINE Colorf get_border_color() const; + INLINE int get_border_width() const; INLINE bool uses_mipmaps() const; void prepare(PreparedGraphicsObjects *prepared_objects); @@ -125,6 +128,7 @@ public: DF_wrap = 0x002, // The wrap properties have changed. DF_filter = 0x004, // The minfilter or magfilter have changed. DF_mipmap = 0x008, // The use of mipmaps or not has changed. + DF_border = 0x010, // The border has changed. }; void mark_dirty(int flags_to_set); @@ -142,6 +146,7 @@ private: int _anisotropic_degree; bool _keep_ram_image; Colorf _border_color; + int _border_width; // A Texture keeps a list (actually, a map) of all the // PreparedGraphicsObjects tables that it has been prepared into. diff --git a/panda/src/pgraph/texProjectorEffect.cxx b/panda/src/pgraph/texProjectorEffect.cxx index 206fafc434..b113c74428 100644 --- a/panda/src/pgraph/texProjectorEffect.cxx +++ b/panda/src/pgraph/texProjectorEffect.cxx @@ -219,7 +219,23 @@ cull_callback(CullTraverser *trav, CullTraverserData &data, if (def._to_lens_node != (LensNode *)NULL && def._to_lens_node->get_lens() != (Lens *)NULL) { - transform = TransformState::make_mat(def._to_lens_node->get_lens()->get_projection_mat())->compose(transform); + + // Get the lens's projection matrix, as a TransformState. + CPT(TransformState) projmat = TransformState::make_mat(def._to_lens_node->get_lens()->get_projection_mat()); + + // We need a special transform to convert the -0.5, 0.5 + // centering of the lens's projection matrix to UV's in the + // range of (0, 1). + static CPT(TransformState) fixmat; + if (fixmat == (TransformState *)NULL) { + fixmat = TransformState::make_pos_hpr_scale + (LVecBase3f(0.5f, 0.5f, 0.0f), + LVecBase3f(0.0f, 0.0f, 0.0f), + LVecBase3f(0.5f, 0.5f, 1.0f)); + } + + // Now apply both to the current transform. + transform = fixmat->compose(projmat)->compose(transform); } if (!transform->is_identity()) {