diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 66c2ab1415..02793895b5 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -2240,6 +2240,7 @@ async_reload_texture(TextureContext *tc) { nassertv(_loader != (Loader *)NULL); PT(AsyncTask) request = - new TextureReloadRequest(tc, _supports_compressed_texture); + new TextureReloadRequest(_prepared_objects, tc->get_texture(), + _supports_compressed_texture); _loader->load_async(request); } diff --git a/panda/src/gobj/Sources.pp b/panda/src/gobj/Sources.pp index 513b38a67a..031810712e 100644 --- a/panda/src/gobj/Sources.pp +++ b/panda/src/gobj/Sources.pp @@ -59,6 +59,7 @@ texturePeeker.I texturePeeker.h \ texturePool.I texturePool.h \ texturePoolFilter.I texturePoolFilter.h \ + textureReloadRequest.I textureReloadRequest.h \ textureStage.I textureStage.h \ transformBlend.I transformBlend.h \ transformBlendTable.I transformBlendTable.h \ @@ -123,6 +124,7 @@ texturePeeker.cxx \ texturePool.cxx \ texturePoolFilter.cxx \ + textureReloadRequest.cxx \ textureStage.cxx \ transformBlend.cxx \ transformBlendTable.cxx \ @@ -190,6 +192,7 @@ texturePeeker.I texturePeeker.h \ texturePool.I texturePool.h \ texturePoolFilter.I texturePoolFilter.h \ + textureReloadRequest.I textureReloadRequest.h \ textureStage.I textureStage.h \ transformBlend.I transformBlend.h \ transformBlendTable.I transformBlendTable.h \ diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index caf5208dcb..81485d1002 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -38,6 +38,7 @@ #include "sliderTable.h" #include "texture.h" #include "texturePoolFilter.h" +#include "textureReloadRequest.h" #include "textureStage.h" #include "textureContext.h" #include "shader.h" @@ -397,6 +398,16 @@ ConfigVariableInt adaptive_lru_max_updates_per_frame PRC_DESC("The number of pages the AdaptiveLru class will update per " "frame. Do not set this too high or it will degrade " "performance.")); + +ConfigVariableDouble async_load_delay +("async-load-delay", 0.0, +PRC_DESC("If this is nonzero, it represents an artificial delay, " + "in seconds, that is imposed on every asynchronous load attempt " + "(within the thread). Its purpose is to help debug errors that " + "may occur when an asynchronous load is delayed. The " + "delay is per-model, and all aync loads will be queued " + "up behind the delay--it is as if the time it takes to read a " + "file is increased by this amount per read.")); ConfigureFn(config_gobj) { @@ -435,6 +446,7 @@ ConfigureFn(config_gobj) { Texture::init_type(); TextureContext::init_type(); TexturePoolFilter::init_type(); + TextureReloadRequest::init_type(); TextureStage::init_type(); TransformBlend::init_type(); TransformBlendTable::init_type(); diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index ea1e3e196c..5914a62e13 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -95,6 +95,7 @@ extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_data_page_threads; extern EXPCL_PANDA_GOBJ ConfigVariableInt graphics_memory_limit; extern EXPCL_PANDA_GOBJ ConfigVariableDouble adaptive_lru_weight; extern EXPCL_PANDA_GOBJ ConfigVariableInt adaptive_lru_max_updates_per_frame; +extern EXPCL_PANDA_GOBJ ConfigVariableDouble async_load_delay; #endif diff --git a/panda/src/gobj/gobj_composite2.cxx b/panda/src/gobj/gobj_composite2.cxx index da30afad53..0a95ca1c09 100644 --- a/panda/src/gobj/gobj_composite2.cxx +++ b/panda/src/gobj/gobj_composite2.cxx @@ -17,6 +17,7 @@ #include "texturePeeker.cxx" #include "texturePool.cxx" #include "texturePoolFilter.cxx" +#include "textureReloadRequest.cxx" #include "textureStage.cxx" #include "transformBlend.cxx" #include "transformBlendTable.cxx" diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index 18bb967127..6aca503f77 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -71,6 +71,7 @@ PreparedGraphicsObjects:: TextureContext *tc = (*tci); tc->set_owning_chain(NULL); } + // Is this a leak? Should we delete these TextureContexts? _released_textures.clear(); release_all_geoms(); @@ -213,7 +214,7 @@ void PreparedGraphicsObjects:: release_texture(TextureContext *tc) { ReMutexHolder holder(_lock); - tc->get_texture()->clear_prepared(this); + tc->_texture->clear_prepared(this); // We have to set the Texture pointer to NULL at this point, since // the Texture itself might destruct at any time after it has been @@ -256,7 +257,7 @@ release_all_textures() { tci != _prepared_textures.end(); ++tci) { TextureContext *tc = (*tci); - tc->get_texture()->clear_prepared(this); + tc->_texture->clear_prepared(this); tc->_texture = (Texture *)NULL; _released_textures.insert(tc); diff --git a/panda/src/gobj/texture.cxx b/panda/src/gobj/texture.cxx index 9ad8d2a14f..982d1abb04 100644 --- a/panda/src/gobj/texture.cxx +++ b/panda/src/gobj/texture.cxx @@ -2010,6 +2010,26 @@ is_prepared(PreparedGraphicsObjects *prepared_objects) const { return prepared_objects->is_texture_queued(this); } +//////////////////////////////////////////////////////////////////// +// Function: Texture::was_image_modified +// Access: Published +// Description: Returns true if the texture needs to be re-loaded +// onto the indicated GSG, either because its image data +// is out-of-date, or because it's not fully prepared +// now. +//////////////////////////////////////////////////////////////////// +bool Texture:: +was_image_modified(PreparedGraphicsObjects *prepared_objects) const { + ReMutexHolder holder(_lock); + Contexts::const_iterator ci; + ci = _contexts.find(prepared_objects); + if (ci != _contexts.end()) { + TextureContext *tc = (*ci).second; + return tc->was_image_modified(); + } + return true; +} + //////////////////////////////////////////////////////////////////// // Function: Texture::release // Access: Published diff --git a/panda/src/gobj/texture.h b/panda/src/gobj/texture.h index e7c25c15e5..0bd5f50775 100644 --- a/panda/src/gobj/texture.h +++ b/panda/src/gobj/texture.h @@ -346,6 +346,7 @@ PUBLISHED: void prepare(PreparedGraphicsObjects *prepared_objects); bool is_prepared(PreparedGraphicsObjects *prepared_objects) const; + bool was_image_modified(PreparedGraphicsObjects *prepared_objects) const; bool release(PreparedGraphicsObjects *prepared_objects); int release_all(); diff --git a/panda/src/pgraph/textureReloadRequest.I b/panda/src/gobj/textureReloadRequest.I similarity index 68% rename from panda/src/pgraph/textureReloadRequest.I rename to panda/src/gobj/textureReloadRequest.I index b16fe3c53c..0febc81f4b 100644 --- a/panda/src/pgraph/textureReloadRequest.I +++ b/panda/src/gobj/textureReloadRequest.I @@ -20,24 +20,37 @@ // via load_async(), to begin an asynchronous load. //////////////////////////////////////////////////////////////////// INLINE TextureReloadRequest:: -TextureReloadRequest(TextureContext *tc, bool allow_compressed) : - _texture_context(tc), +TextureReloadRequest(PreparedGraphicsObjects *pgo, Texture *texture, + bool allow_compressed) : + _pgo(pgo), + _texture(texture), _allow_compressed(allow_compressed), _is_ready(false) { - nassertv(_texture_context != (TextureContext *)NULL); - _texture = _texture_context->get_texture(); + nassertv(_pgo != (PreparedGraphicsObjects *)NULL); + nassertv(_texture != (Texture *)NULL); } //////////////////////////////////////////////////////////////////// -// Function: TextureReloadRequest::get_texture_context +// Function: TextureReloadRequest::get_prepared_graphics_objects // Access: Published -// Description: Returns the TextureContext object associated with +// Description: Returns the PreparedGraphicsObjects object associated with // this asynchronous TextureReloadRequest. //////////////////////////////////////////////////////////////////// -INLINE TextureContext *TextureReloadRequest:: -get_texture_context() const { - return _texture_context; +INLINE PreparedGraphicsObjects *TextureReloadRequest:: +get_prepared_graphics_objects() const { + return _pgo; +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureReloadRequest::get_texture +// Access: Published +// Description: Returns the Texture object associated with +// this asynchronous TextureReloadRequest. +//////////////////////////////////////////////////////////////////// +INLINE Texture *TextureReloadRequest:: +get_texture() const { + return _texture; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/textureReloadRequest.cxx b/panda/src/gobj/textureReloadRequest.cxx similarity index 81% rename from panda/src/pgraph/textureReloadRequest.cxx rename to panda/src/gobj/textureReloadRequest.cxx index 539f70c8b6..3fe22aba06 100644 --- a/panda/src/pgraph/textureReloadRequest.cxx +++ b/panda/src/gobj/textureReloadRequest.cxx @@ -13,7 +13,7 @@ //////////////////////////////////////////////////////////////////// #include "textureReloadRequest.h" -#include "loader.h" +#include "textureContext.h" TypeHandle TextureReloadRequest::_type_handle; @@ -25,16 +25,18 @@ TypeHandle TextureReloadRequest::_type_handle; bool TextureReloadRequest:: do_task() { // Don't reload the texture if it doesn't need it. - if (_texture_context->was_image_modified()) { + if (_texture->was_image_modified(_pgo)) { double delay = async_load_delay; if (delay != 0.0) { Thread::sleep(delay); } - - if (_allow_compressed) { - _texture->get_ram_image(); - } else { - _texture->get_uncompressed_ram_image(); + + if (_texture->was_image_modified(_pgo)) { + if (_allow_compressed) { + _texture->get_ram_image(); + } else { + _texture->get_uncompressed_ram_image(); + } } } _is_ready = true; diff --git a/panda/src/pgraph/textureReloadRequest.h b/panda/src/gobj/textureReloadRequest.h similarity index 82% rename from panda/src/pgraph/textureReloadRequest.h rename to panda/src/gobj/textureReloadRequest.h index 5729aab3d9..35a2cebf57 100644 --- a/panda/src/pgraph/textureReloadRequest.h +++ b/panda/src/gobj/textureReloadRequest.h @@ -19,8 +19,9 @@ #include "asyncTask.h" #include "texture.h" -#include "textureContext.h" +#include "preparedGraphicsObjects.h" #include "pointerTo.h" +#include "pmutex.h" //////////////////////////////////////////////////////////////////// // Class : TextureReloadRequest @@ -30,14 +31,16 @@ // used by GraphicsStateGuardian::async_reload_texture(), // when get_incomplete_render() is true. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_PGRAPH TextureReloadRequest : public AsyncTask { +class EXPCL_PANDA_GOBJ TextureReloadRequest : public AsyncTask { public: ALLOC_DELETED_CHAIN(TextureReloadRequest); PUBLISHED: - INLINE TextureReloadRequest(TextureContext *tc, bool allow_compressed); + INLINE TextureReloadRequest(PreparedGraphicsObjects *pgo, Texture *texture, + bool allow_compressed); - INLINE TextureContext *get_texture_context() const; + INLINE PreparedGraphicsObjects *get_prepared_graphics_objects() const; + INLINE Texture *get_texture() const; INLINE bool get_allow_compressed() const; INLINE bool is_ready() const; @@ -45,9 +48,9 @@ protected: virtual bool do_task(); private: - TextureContext *_texture_context; - bool _allow_compressed; + PT(PreparedGraphicsObjects) _pgo; PT(Texture) _texture; + bool _allow_compressed; bool _is_ready; public: diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index 81d22966ee..82591aa979 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -118,7 +118,6 @@ textureAttrib.I textureAttrib.h \ texGenAttrib.I texGenAttrib.h \ textureCollection.I textureCollection.h \ - textureReloadRequest.I textureReloadRequest.h \ textureStageCollection.I textureStageCollection.h \ transformState.I transformState.h \ transparencyAttrib.I transparencyAttrib.h \ @@ -231,7 +230,6 @@ textureAttrib.cxx \ texGenAttrib.cxx \ textureCollection.cxx \ - textureReloadRequest.cxx \ textureStageCollection.cxx \ transformState.cxx \ transparencyAttrib.cxx \ @@ -342,7 +340,6 @@ textureAttrib.I textureAttrib.h \ texGenAttrib.I texGenAttrib.h \ textureCollection.I textureCollection.h \ - textureReloadRequest.I textureReloadRequest.h \ textureStageCollection.I textureStageCollection.h \ transformState.I transformState.h \ transparencyAttrib.I transparencyAttrib.h \ diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 7164850d35..806fd14100 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -94,7 +94,6 @@ #include "texMatrixAttrib.h" #include "texProjectorEffect.h" #include "textureAttrib.h" -#include "textureReloadRequest.h" #include "texGenAttrib.h" #include "transformState.h" #include "transparencyAttrib.h" @@ -274,16 +273,6 @@ ConfigVariableBool flatten_geoms "only the NodePath interfaces; you may still make the lower-level " "SceneGraphReducer calls directly.")); -ConfigVariableDouble async_load_delay -("async-load-delay", 0.0, -PRC_DESC("If this is nonzero, it represents an artificial delay, " - "in seconds, that is imposed on every asynchronous load attempt " - "(within the thread). Its purpose is to help debug errors that " - "may occur when an asynchronous load is delayed. The " - "delay is per-model, and all aync loads will be queued " - "up behind the delay--it is as if the time it takes to read a " - "file is increased by this amount per read.")); - ConfigVariableBool polylight_info ("polylight-info", false, PRC_DESC("Set this true to view some info statements regarding the polylight. " @@ -460,7 +449,6 @@ init_libpgraph() { TexMatrixAttrib::init_type(); TexProjectorEffect::init_type(); TextureAttrib::init_type(); - TextureReloadRequest::init_type(); TexGenAttrib::init_type(); TransformState::init_type(); TransparencyAttrib::init_type(); diff --git a/panda/src/pgraph/config_pgraph.h b/panda/src/pgraph/config_pgraph.h index f163825042..09d88daef7 100644 --- a/panda/src/pgraph/config_pgraph.h +++ b/panda/src/pgraph/config_pgraph.h @@ -53,7 +53,6 @@ extern ConfigVariableInt max_collect_indices; extern ConfigVariableBool premunge_data; extern ConfigVariableBool preserve_geom_nodes; extern ConfigVariableBool flatten_geoms; -extern ConfigVariableDouble async_load_delay; extern ConfigVariableBool polylight_info; extern ConfigVariableDouble lod_fade_time; diff --git a/panda/src/pgraph/pgraph_composite4.cxx b/panda/src/pgraph/pgraph_composite4.cxx index 6a62ffeaaa..683667bc54 100644 --- a/panda/src/pgraph/pgraph_composite4.cxx +++ b/panda/src/pgraph/pgraph_composite4.cxx @@ -25,7 +25,6 @@ #include "textureAttrib.cxx" #include "texGenAttrib.cxx" #include "textureCollection.cxx" -#include "textureReloadRequest.cxx" #include "textureStageCollection.cxx" #include "transformState.cxx" #include "transparencyAttrib.cxx" diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index 6683069da3..c5889f895b 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -765,13 +765,13 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, case AlphaTestAttrib::M_less: case AlphaTestAttrib::M_less_equal: alpha_test_state = 1; // aless - _c->zb->reference_alpha = (int)_target._alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX; + _c->zb->reference_alpha = (int)(_target._alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX); break; case AlphaTestAttrib::M_greater: case AlphaTestAttrib::M_greater_equal: alpha_test_state = 2; // amore - _c->zb->reference_alpha = (int)_target._alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX; + _c->zb->reference_alpha = (int)(_target._alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX); break; } diff --git a/panda/src/tinydisplay/zbuffer.h b/panda/src/tinydisplay/zbuffer.h index 83163f6370..98c9549ff2 100644 --- a/panda/src/tinydisplay/zbuffer.h +++ b/panda/src/tinydisplay/zbuffer.h @@ -78,15 +78,23 @@ typedef unsigned int PIXEL; #define PSZB 4 #define PSZSH 5 -#define PIXEL_MULT(p1, p2) \ - RGB_TO_PIXEL((PIXEL_R(p1) * PIXEL_R(p2)) >> 16, \ - (PIXEL_G(p1) * PIXEL_G(p2)) >> 16, \ - (PIXEL_B(p1) * PIXEL_B(p2)) >> 16) +// Returns an unsigned product of c1 * c2 +#define PCOMPONENT_MULT(c1, c2) \ + ((((unsigned int)(c1) * (unsigned int)(c2))) >> 16) + +// Returns a signed product of c1 * c2, where c1 is initially signed. +// We leave 2 bits on the top to differentiate between c1 < 0 and c1 > +// 0xffff; the result has the same sign. +#define PALPHA_MULT(c1, c2) \ + (((int)(((int)(c1) >> 2) * (unsigned int)(c2))) >> 14) + +#define PCOMPONENT_BLEND(c1, c2, a2) \ + ((((unsigned int)(c1) * ((unsigned int)0xffff - (unsigned int)(a2)) + (unsigned int)(c2) * (unsigned int)(a2))) >> 16) #define PIXEL_BLEND(r1, g1, b1, r2, g2, b2, a2) \ - RGBA_TO_PIXEL(((r1) * (0xffff - (a2)) + (r2) * (a2)) >> 16, \ - ((g1) * (0xffff - (a2)) + (g2) * (a2)) >> 16, \ - ((b1) * (0xffff - (a2)) + (b2) * (a2)) >> 16, \ + RGBA_TO_PIXEL(PCOMPONENT_BLEND(r1, r2, a2), \ + PCOMPONENT_BLEND(g1, g2, a2), \ + PCOMPONENT_BLEND(b1, b2, a2), \ a2) #define PIXEL_BLEND_RGB(rgb, r, g, b, a) \ PIXEL_BLEND(PIXEL_R(rgb), PIXEL_G(rgb), PIXEL_B(rgb), r, g, b, a) diff --git a/panda/src/tinydisplay/ztriangle_two.h b/panda/src/tinydisplay/ztriangle_two.h index 3f60426d16..90b7ae0fad 100644 --- a/panda/src/tinydisplay/ztriangle_two.h +++ b/panda/src/tinydisplay/ztriangle_two.h @@ -182,16 +182,16 @@ static void FNAME(flat_textured) (ZBuffer *zb, zz=z >> ZB_POINT_Z_FRAC_BITS; \ if (ZCMP(pz[_a], zz)) { \ tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \ - int a = oa0 * PIXEL_A(tmp) >> 16; \ + int a = PALPHA_MULT(oa0, PIXEL_A(tmp)); \ if (ACMP(zb, a)) { \ STORE_PIX(pp[_a], \ - RGBA_TO_PIXEL(or0 * PIXEL_R(tmp) >> 16, \ - og0 * PIXEL_G(tmp) >> 16, \ - ob0 * PIXEL_B(tmp) >> 16, \ + RGBA_TO_PIXEL(PCOMPONENT_MULT(or0, PIXEL_R(tmp)), \ + PCOMPONENT_MULT(og0, PIXEL_G(tmp)), \ + PCOMPONENT_MULT(ob0, PIXEL_B(tmp)), \ a), \ - or0 * PIXEL_R(tmp) >> 16, \ - og0 * PIXEL_G(tmp) >> 16, \ - ob0 * PIXEL_B(tmp) >> 16, \ + PCOMPONENT_MULT(or0, PIXEL_R(tmp)), \ + PCOMPONENT_MULT(og0, PIXEL_G(tmp)), \ + PCOMPONENT_MULT(ob0, PIXEL_B(tmp)), \ a); \ STORE_Z(pz[_a], zz); \ } \ @@ -243,16 +243,16 @@ static void FNAME(smooth_textured) (ZBuffer *zb, zz=z >> ZB_POINT_Z_FRAC_BITS; \ if (ZCMP(pz[_a], zz)) { \ tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \ - int a = oa1 * PIXEL_A(tmp) >> 16; \ + int a = PALPHA_MULT(oa1, PIXEL_A(tmp)); \ if (ACMP(zb, a)) { \ STORE_PIX(pp[_a], \ - RGBA_TO_PIXEL(or1 * PIXEL_R(tmp) >> 16, \ - og1 * PIXEL_G(tmp) >> 16, \ - ob1 * PIXEL_B(tmp) >> 16, \ + RGBA_TO_PIXEL(PCOMPONENT_MULT(or1, PIXEL_R(tmp)), \ + PCOMPONENT_MULT(og1, PIXEL_G(tmp)), \ + PCOMPONENT_MULT(ob1, PIXEL_B(tmp)), \ a), \ - or1 * PIXEL_R(tmp) >> 16, \ - og1 * PIXEL_G(tmp) >> 16, \ - ob1 * PIXEL_B(tmp) >> 16, \ + PCOMPONENT_MULT(or1, PIXEL_R(tmp)), \ + PCOMPONENT_MULT(og1, PIXEL_G(tmp)), \ + PCOMPONENT_MULT(ob1, PIXEL_B(tmp)), \ a); \ STORE_Z(pz[_a], zz); \ } \ @@ -422,16 +422,16 @@ static void FNAME(flat_perspective) (ZBuffer *zb, zz=z >> ZB_POINT_Z_FRAC_BITS; \ if (ZCMP(pz[_a], zz)) { \ tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \ - int a = oa0 * PIXEL_A(tmp) >> 16; \ + int a = PALPHA_MULT(oa0, PIXEL_A(tmp)); \ if (ACMP(zb, a)) { \ STORE_PIX(pp[_a], \ - RGBA_TO_PIXEL(or0 * PIXEL_R(tmp) >> 16, \ - og0 * PIXEL_G(tmp) >> 16, \ - ob0 * PIXEL_B(tmp) >> 16, \ + RGBA_TO_PIXEL(PCOMPONENT_MULT(or0, PIXEL_R(tmp)), \ + PCOMPONENT_MULT(og0, PIXEL_G(tmp)), \ + PCOMPONENT_MULT(ob0, PIXEL_B(tmp)), \ a), \ - or0 * PIXEL_R(tmp) >> 16, \ - og0 * PIXEL_G(tmp) >> 16, \ - ob0 * PIXEL_B(tmp) >> 16, \ + PCOMPONENT_MULT(or0, PIXEL_R(tmp)), \ + PCOMPONENT_MULT(og0, PIXEL_G(tmp)), \ + PCOMPONENT_MULT(ob0, PIXEL_B(tmp)), \ a); \ STORE_Z(pz[_a], zz); \ } \ @@ -556,17 +556,17 @@ static void FNAME(smooth_perspective) (ZBuffer *zb, { \ zz=z >> ZB_POINT_Z_FRAC_BITS; \ if (ZCMP(pz[_a], zz)) { \ - tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \ - int a = oa1 * PIXEL_A(tmp) >> 16; \ + tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \ + int a = PALPHA_MULT(oa1, PIXEL_A(tmp)); \ if (ACMP(zb, a)) { \ STORE_PIX(pp[_a], \ - RGBA_TO_PIXEL(or1 * PIXEL_R(tmp) >> 16, \ - og1 * PIXEL_G(tmp) >> 16, \ - ob1 * PIXEL_B(tmp) >> 16, \ + RGBA_TO_PIXEL(PCOMPONENT_MULT(or1, PIXEL_R(tmp)), \ + PCOMPONENT_MULT(og1, PIXEL_G(tmp)), \ + PCOMPONENT_MULT(ob1, PIXEL_B(tmp)), \ a), \ - or1 * PIXEL_R(tmp) >> 16, \ - og1 * PIXEL_G(tmp) >> 16, \ - ob1 * PIXEL_B(tmp) >> 16, \ + PCOMPONENT_MULT(or1, PIXEL_R(tmp)), \ + PCOMPONENT_MULT(og1, PIXEL_G(tmp)), \ + PCOMPONENT_MULT(ob1, PIXEL_B(tmp)), \ a); \ STORE_Z(pz[_a], zz); \ } \