mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
flesh out MultitexReducer some more
This commit is contained in:
parent
9f8ae63333
commit
7d1a5fc226
@ -368,11 +368,21 @@ get_next_normal(NormalIterator &niterator) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE Geom::TexCoordIterator Geom::
|
INLINE Geom::TexCoordIterator Geom::
|
||||||
make_texcoord_iterator() const {
|
make_texcoord_iterator() const {
|
||||||
|
return make_texcoord_iterator(TexCoordName::get_default());
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: Geom::make_texcoord_iterator
|
||||||
|
// Access: Public
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE Geom::TexCoordIterator Geom::
|
||||||
|
make_texcoord_iterator(const TexCoordName *texcoord_name) const {
|
||||||
check_config();
|
check_config();
|
||||||
TexCoordIterator i;
|
TexCoordIterator i;
|
||||||
|
|
||||||
TexCoordsByName::const_iterator tci =
|
TexCoordsByName::const_iterator tci =
|
||||||
_texcoords_by_name.find(TexCoordName::get_default());
|
_texcoords_by_name.find(texcoord_name);
|
||||||
if (tci != _texcoords_by_name.end()) {
|
if (tci != _texcoords_by_name.end()) {
|
||||||
i._array = (*tci).second._texcoords;
|
i._array = (*tci).second._texcoords;
|
||||||
i._index = (*tci).second._tindex;;
|
i._index = (*tci).second._tindex;;
|
||||||
|
@ -223,6 +223,7 @@ public:
|
|||||||
INLINE const Normalf &get_next_normal(NormalIterator &niterator) const;
|
INLINE const Normalf &get_next_normal(NormalIterator &niterator) const;
|
||||||
|
|
||||||
INLINE TexCoordIterator make_texcoord_iterator() const;
|
INLINE TexCoordIterator make_texcoord_iterator() const;
|
||||||
|
INLINE TexCoordIterator make_texcoord_iterator(const TexCoordName *texcoord_name) const;
|
||||||
INLINE const TexCoordf &get_next_texcoord(TexCoordIterator &tciterator) const;
|
INLINE const TexCoordf &get_next_texcoord(TexCoordIterator &tciterator) const;
|
||||||
void setup_multitexcoord_iterator(MultiTexCoordIterator &iterator,
|
void setup_multitexcoord_iterator(MultiTexCoordIterator &iterator,
|
||||||
const ActiveTextureStages &active_stages,
|
const ActiveTextureStages &active_stages,
|
||||||
|
@ -17,6 +17,33 @@
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: MultitexReducer::scan
|
||||||
|
// Access: Published
|
||||||
|
// Description: Starts scanning the hierarchy beginning at the
|
||||||
|
// indicated node. Any GeomNodes discovered in the
|
||||||
|
// hierarchy with multitexture will be added to internal
|
||||||
|
// structures in the MultitexReducer so that a future
|
||||||
|
// call to flatten() will operate on all of these at
|
||||||
|
// once.
|
||||||
|
//
|
||||||
|
// The second parameter represents the NodePath from
|
||||||
|
// which to accumulate the state that is considered for
|
||||||
|
// the multitexture. The default is to accumulate all
|
||||||
|
// the state from the root of the graph, but you may
|
||||||
|
// specify some other node here in order to not consider
|
||||||
|
// nodes above that as contributing to the state to be
|
||||||
|
// flattened. This is particularly useful if you have
|
||||||
|
// some texture stage which is applied globally to a
|
||||||
|
// scene (for instance, a caustics effect), which you
|
||||||
|
// don't want to be considered for flattening by the
|
||||||
|
// MultitexReducer.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
INLINE void MultitexReducer::
|
||||||
|
scan(const NodePath &node, const NodePath &state_from) {
|
||||||
|
scan(node.node(), node.get_state(state_from), node.get_transform(state_from));
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: MultitexReducer::StageInfo::operator <
|
// Function: MultitexReducer::StageInfo::operator <
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -43,7 +70,10 @@ operator < (const MultitexReducer::StageInfo &other) const {
|
|||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE MultitexReducer::GeomInfo::
|
INLINE MultitexReducer::GeomInfo::
|
||||||
GeomInfo(GeomNode *geom_node, int index) :
|
GeomInfo(const RenderState *state, const RenderState *geom_net_state,
|
||||||
|
GeomNode *geom_node, int index) :
|
||||||
|
_state(state),
|
||||||
|
_geom_net_state(geom_net_state),
|
||||||
_geom_node(geom_node),
|
_geom_node(geom_node),
|
||||||
_index(index)
|
_index(index)
|
||||||
{
|
{
|
||||||
|
@ -26,12 +26,14 @@
|
|||||||
#include "graphicsChannel.h"
|
#include "graphicsChannel.h"
|
||||||
#include "graphicsLayer.h"
|
#include "graphicsLayer.h"
|
||||||
#include "displayRegion.h"
|
#include "displayRegion.h"
|
||||||
#include "nodePath.h"
|
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
#include "orthographicLens.h"
|
#include "orthographicLens.h"
|
||||||
#include "cardMaker.h"
|
#include "cardMaker.h"
|
||||||
|
#include "colorAttrib.h"
|
||||||
|
#include "colorScaleAttrib.h"
|
||||||
#include "colorBlendAttrib.h"
|
#include "colorBlendAttrib.h"
|
||||||
#include "config_grutil.h"
|
#include "config_grutil.h"
|
||||||
|
#include "config_gobj.h"
|
||||||
#include "dcast.h"
|
#include "dcast.h"
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -42,6 +44,8 @@
|
|||||||
MultitexReducer::
|
MultitexReducer::
|
||||||
MultitexReducer() {
|
MultitexReducer() {
|
||||||
_target_stage = TextureStage::get_default();
|
_target_stage = TextureStage::get_default();
|
||||||
|
_use_geom = false;
|
||||||
|
_allow_tex_mat = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -81,8 +85,8 @@ clear() {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MultitexReducer::
|
void MultitexReducer::
|
||||||
scan(PandaNode *node, const RenderState *state, const TransformState *transform) {
|
scan(PandaNode *node, const RenderState *state, const TransformState *transform) {
|
||||||
CPT(RenderState) next_state = node->get_state()->compose(state);
|
CPT(RenderState) next_state = state->compose(node->get_state());
|
||||||
CPT(TransformState) next_transform = node->get_transform()->compose(transform);
|
CPT(TransformState) next_transform = transform->compose(node->get_transform());
|
||||||
|
|
||||||
if (node->is_geom_node()) {
|
if (node->is_geom_node()) {
|
||||||
scan_geom_node(DCAST(GeomNode, node), next_state, next_transform);
|
scan_geom_node(DCAST(GeomNode, node), next_state, next_transform);
|
||||||
@ -107,6 +111,61 @@ set_target(TextureStage *stage) {
|
|||||||
_target_stage = stage;
|
_target_stage = stage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: MultitexReducer::set_use_geom
|
||||||
|
// Access: Published
|
||||||
|
// Description: Indicates whether the actual geometry will be used to
|
||||||
|
// generate the textures.
|
||||||
|
//
|
||||||
|
// If this is set to true, the geometry discovered by
|
||||||
|
// scan() will be used to generate the textures, which
|
||||||
|
// allows for the vertex and polygon colors to be made
|
||||||
|
// part of the texture itself (and makes the M_decal
|
||||||
|
// multitexture mode more reliable). However, this only
|
||||||
|
// works if the geometry does not contain multiple
|
||||||
|
// different polygons that map to the same UV range.
|
||||||
|
//
|
||||||
|
// If this is set to false (the default), a plain flat
|
||||||
|
// card will be used to generate the textures, which is
|
||||||
|
// more robust in general, but the resulting texture
|
||||||
|
// will not include vertex colors and M_decal won't work
|
||||||
|
// properly.
|
||||||
|
//
|
||||||
|
// Note that in case multiple sets of texture
|
||||||
|
// coordinates are in effect, then the additional sets
|
||||||
|
// will always use the geometry anyway regardless of the
|
||||||
|
// setting of this flag (but this will not affect vertex
|
||||||
|
// color).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void MultitexReducer::
|
||||||
|
set_use_geom(bool use_geom) {
|
||||||
|
_use_geom = use_geom;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: MultitexReducer::set_allow_tex_mat
|
||||||
|
// Access: Published
|
||||||
|
// Description: Indicates whether the resulting texture should be
|
||||||
|
// expected to be animated beyond its current range via
|
||||||
|
// a texture matrix (true), or whether the current range
|
||||||
|
// of texture coordinates will be sufficient forever
|
||||||
|
// (false).
|
||||||
|
//
|
||||||
|
// If this is set to true, then the entire texture image
|
||||||
|
// must be generated, in the assumption that the user
|
||||||
|
// may animate the texture around on the surface after
|
||||||
|
// it has been composed.
|
||||||
|
//
|
||||||
|
// If this is set to false (the default), then only the
|
||||||
|
// portion of the texture image which is actually in use
|
||||||
|
// must be generated, which may be a significant savings
|
||||||
|
// in texture memory.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void MultitexReducer::
|
||||||
|
set_allow_tex_mat(bool allow_tex_mat) {
|
||||||
|
_allow_tex_mat = allow_tex_mat;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: MultitexReducer::flatten
|
// Function: MultitexReducer::flatten
|
||||||
// Access: Published
|
// Access: Published
|
||||||
@ -155,10 +214,35 @@ flatten(GraphicsOutput *window) {
|
|||||||
const GeomList &geom_list = (*mi).second;
|
const GeomList &geom_list = (*mi).second;
|
||||||
|
|
||||||
// Create an offscreen buffer in which to render the new texture.
|
// Create an offscreen buffer in which to render the new texture.
|
||||||
int x_size, y_size, aniso_degree;
|
|
||||||
Texture::FilterType minfilter, magfilter;
|
// Start by choosing a model TextureStage to determine the new
|
||||||
determine_size(x_size, y_size, aniso_degree,
|
// texture's properties.
|
||||||
minfilter, magfilter, stage_list);
|
const StageInfo &model_stage = stage_list[choose_model_stage(stage_list)];
|
||||||
|
|
||||||
|
Texture *model_tex = model_stage._tex;
|
||||||
|
int aniso_degree = model_tex->get_anisotropic_degree();
|
||||||
|
Texture::FilterType minfilter = model_tex->get_minfilter();
|
||||||
|
Texture::FilterType magfilter = model_tex->get_magfilter();
|
||||||
|
|
||||||
|
// What is the UV range of the model stage?
|
||||||
|
TexCoordf min_uv, max_uv;
|
||||||
|
determine_uv_range(min_uv, max_uv, model_stage, geom_list);
|
||||||
|
|
||||||
|
// Maybe we only use a small portion of the texture, or maybe we
|
||||||
|
// need to repeat the texture several times.
|
||||||
|
LVecBase2f uv_scale;
|
||||||
|
LVecBase2f uv_trans;
|
||||||
|
get_uv_scale(uv_scale, uv_trans, min_uv, max_uv);
|
||||||
|
|
||||||
|
// Also, if there is now a scale on the UV's (in conjunction with
|
||||||
|
// whatever texture matrix might be applied on the model stage),
|
||||||
|
// we may be able to adjust the image size accordingly, to keep
|
||||||
|
// the pixels at about the same scale--but we have to keep it to a
|
||||||
|
// power of 2.
|
||||||
|
int x_size;
|
||||||
|
int y_size;
|
||||||
|
choose_texture_size(x_size, y_size, model_stage, uv_scale,
|
||||||
|
window);
|
||||||
|
|
||||||
GraphicsOutput *buffer =
|
GraphicsOutput *buffer =
|
||||||
window->make_texture_buffer("multitex", x_size, y_size);
|
window->make_texture_buffer("multitex", x_size, y_size);
|
||||||
@ -178,6 +262,10 @@ flatten(GraphicsOutput *window) {
|
|||||||
lens->set_film_size(1.0f, 1.0f);
|
lens->set_film_size(1.0f, 1.0f);
|
||||||
lens->set_film_offset(0.5f, 0.5f);
|
lens->set_film_offset(0.5f, 0.5f);
|
||||||
lens->set_near_far(-1000.0f, 1000.0f);
|
lens->set_near_far(-1000.0f, 1000.0f);
|
||||||
|
lens->set_view_mat(LMatrix4f(uv_scale[0], 0.0f, 0.0, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0, 0.0f,
|
||||||
|
0.0f, 0.0f, uv_scale[1], 0.0f,
|
||||||
|
uv_trans[0], 0.0f, uv_trans[1], 1.0f));
|
||||||
cam_node->set_lens(lens);
|
cam_node->set_lens(lens);
|
||||||
|
|
||||||
// Create a root node for the buffer's scene graph, and set up
|
// Create a root node for the buffer's scene graph, and set up
|
||||||
@ -191,11 +279,22 @@ flatten(GraphicsOutput *window) {
|
|||||||
NodePath cam = render.attach_new_node(cam_node);
|
NodePath cam = render.attach_new_node(cam_node);
|
||||||
dr->set_camera(cam);
|
dr->set_camera(cam);
|
||||||
|
|
||||||
// Put one plain white card in the background for the first
|
if (!_use_geom) {
|
||||||
// texture layer to apply onto.
|
// Put one plain white card in the background for the first
|
||||||
CardMaker cm("background");
|
// texture layer to apply onto.
|
||||||
cm.set_frame(0.0f, 1.0f, 0.0f, 1.0f);
|
|
||||||
render.attach_new_node(cm.generate());
|
CardMaker cm("background");
|
||||||
|
cm.set_frame(0.0f, 1.0f, 0.0f, 1.0f);
|
||||||
|
render.attach_new_node(cm.generate());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Put a colored model of the geometry in the background for the
|
||||||
|
// first texture layer to apply only.
|
||||||
|
PT(GeomNode) geom_node = new GeomNode("background");
|
||||||
|
transfer_geom(geom_node, NULL, geom_list, true);
|
||||||
|
|
||||||
|
render.attach_new_node(geom_node);
|
||||||
|
}
|
||||||
|
|
||||||
StageList::const_iterator si;
|
StageList::const_iterator si;
|
||||||
for (si = stage_list.begin(); si != stage_list.end(); ++si) {
|
for (si = stage_list.begin(); si != stage_list.end(); ++si) {
|
||||||
@ -216,6 +315,42 @@ flatten(GraphicsOutput *window) {
|
|||||||
CPT(RenderState) geom_state =
|
CPT(RenderState) geom_state =
|
||||||
geom_info._geom_node->get_geom_state(geom_info._index);
|
geom_info._geom_node->get_geom_state(geom_info._index);
|
||||||
geom_state = geom_state->add_attrib(new_ta);
|
geom_state = geom_state->add_attrib(new_ta);
|
||||||
|
|
||||||
|
if (_use_geom) {
|
||||||
|
// If we have use_geom in effect, we have to be sure to
|
||||||
|
// disable coloring on the new fragment (the color has been
|
||||||
|
// baked into the texture).
|
||||||
|
geom_state = geom_state->add_attrib(ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 1.0f, 1.0f)));
|
||||||
|
geom_state = geom_state->add_attrib(ColorScaleAttrib::make_off());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine what tex matrix should be on the Geom.
|
||||||
|
CPT(TransformState) tex_mat = TransformState::make_identity();
|
||||||
|
|
||||||
|
const RenderAttrib *ra = geom_info._state->get_attrib(TexMatrixAttrib::get_class_type());
|
||||||
|
if (ra != (const RenderAttrib *)NULL) {
|
||||||
|
// There is a texture matrix inherited from above; put an
|
||||||
|
// inverse matrix on the Geom to compensate.
|
||||||
|
const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, ra);
|
||||||
|
CPT(TransformState) tex_mat = tma->get_transform(_target_stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
tex_mat = tex_mat->compose(TransformState::make_pos_hpr_scale
|
||||||
|
(LVecBase3f(uv_trans[0], uv_trans[1], 0.0f),
|
||||||
|
LVecBase3f(0.0f, 0.0f, 0.0f),
|
||||||
|
LVecBase3f(uv_scale[0], uv_scale[1], 1.0f)));
|
||||||
|
|
||||||
|
if (tex_mat->is_identity()) {
|
||||||
|
// There should be no texture matrix on the Geom.
|
||||||
|
geom_state = geom_state->remove_attrib(TexMatrixAttrib::get_class_type());
|
||||||
|
} else {
|
||||||
|
// The texture matrix should be as computed.
|
||||||
|
CPT(RenderAttrib) new_tma = TexMatrixAttrib::make
|
||||||
|
(_target_stage, tex_mat->invert_compose(TransformState::make_identity()));
|
||||||
|
geom_state = geom_state->add_attrib(new_tma);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
geom_info._geom_node->set_geom_state(geom_info._index, geom_state);
|
geom_info._geom_node->set_geom_state(geom_info._index, geom_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -239,7 +374,7 @@ scan_geom_node(GeomNode *node, const RenderState *state,
|
|||||||
int num_geoms = node->get_num_geoms();
|
int num_geoms = node->get_num_geoms();
|
||||||
for (int gi = 0; gi < num_geoms; gi++) {
|
for (int gi = 0; gi < num_geoms; gi++) {
|
||||||
CPT(RenderState) geom_net_state =
|
CPT(RenderState) geom_net_state =
|
||||||
node->get_geom_state(gi)->compose(state);
|
state->compose(node->get_geom_state(gi));
|
||||||
|
|
||||||
// Get out the net TextureAttrib and TexMatrixAttrib from the state.
|
// Get out the net TextureAttrib and TexMatrixAttrib from the state.
|
||||||
const RenderAttrib *attrib;
|
const RenderAttrib *attrib;
|
||||||
@ -267,7 +402,7 @@ scan_geom_node(GeomNode *node, const RenderState *state,
|
|||||||
stage_list.push_back(StageInfo(stage, ta, tma));
|
stage_list.push_back(StageInfo(stage, ta, tma));
|
||||||
}
|
}
|
||||||
|
|
||||||
record_stage_list(stage_list, GeomInfo(node, gi));
|
record_stage_list(stage_list, GeomInfo(state, geom_net_state, node, gi));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,45 +433,182 @@ record_stage_list(const MultitexReducer::StageList &stage_list,
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: MultitexReducer::determine_size
|
// Function: MultitexReducer::choose_model_stage
|
||||||
// Access: Private
|
// Access: Private
|
||||||
// Description: Tries to guess what size to make the new, collapsed
|
// Description: Chooses one of the TextureStages in the stage_list to
|
||||||
// texture based on the sizes of all of the textures
|
// serve as the model to determine the size and
|
||||||
// used in the stage_list.
|
// properties of the resulting texture.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MultitexReducer::
|
size_t MultitexReducer::
|
||||||
determine_size(int &x_size, int &y_size, int &aniso_degree,
|
choose_model_stage(const MultitexReducer::StageList &stage_list) const {
|
||||||
Texture::FilterType &minfilter, Texture::FilterType &magfilter,
|
for (size_t si = 0; si < stage_list.size(); si++) {
|
||||||
const MultitexReducer::StageList &stage_list) const {
|
const StageInfo &stage_info = stage_list[si];
|
||||||
x_size = 0;
|
|
||||||
y_size = 0;
|
|
||||||
aniso_degree = 0;
|
|
||||||
minfilter = Texture::FT_nearest;
|
|
||||||
magfilter = Texture::FT_nearest;
|
|
||||||
|
|
||||||
StageList::const_iterator si;
|
|
||||||
for (si = stage_list.begin(); si != stage_list.end(); ++si) {
|
|
||||||
const StageInfo &stage_info = (*si);
|
|
||||||
Texture *tex = stage_info._tex;
|
|
||||||
PixelBuffer *pbuffer = tex->_pbuffer;
|
|
||||||
|
|
||||||
if (stage_info._stage == _target_stage) {
|
if (stage_info._stage == _target_stage) {
|
||||||
// If we find the target stage, use that.
|
// If we find the target stage, use that.
|
||||||
x_size = pbuffer->get_xsize();
|
return si;
|
||||||
y_size = pbuffer->get_ysize();
|
|
||||||
aniso_degree = tex->get_anisotropic_degree();
|
|
||||||
minfilter = tex->get_minfilter();
|
|
||||||
magfilter = tex->get_magfilter();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we never run across the target stage, just use the maximum
|
// If none of the stages are the target stage, use the bottom image.
|
||||||
// of all encountered textures.
|
return 0;
|
||||||
x_size = max(x_size, pbuffer->get_xsize());
|
}
|
||||||
y_size = max(y_size, pbuffer->get_ysize());
|
|
||||||
aniso_degree = max(aniso_degree, tex->get_anisotropic_degree());
|
////////////////////////////////////////////////////////////////////
|
||||||
minfilter = (Texture::FilterType)max((int)minfilter, (int)tex->get_minfilter());
|
// Function: MultitexReducer::determine_uv_range
|
||||||
magfilter = (Texture::FilterType)max((int)magfilter, (int)tex->get_magfilter());
|
// Access: Private
|
||||||
|
// Description: Determines what the effective UV range for the
|
||||||
|
// indicated texture is across its geoms. Returns true
|
||||||
|
// if any UV's are found, false otherwise.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
bool MultitexReducer::
|
||||||
|
determine_uv_range(TexCoordf &min_uv, TexCoordf &max_uv,
|
||||||
|
const MultitexReducer::StageInfo &model_stage,
|
||||||
|
const MultitexReducer::GeomList &geom_list) const {
|
||||||
|
const TexCoordName *model_name = model_stage._stage->get_texcoord_name();
|
||||||
|
bool got_any = false;
|
||||||
|
|
||||||
|
GeomList::const_iterator gi;
|
||||||
|
for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
|
||||||
|
const GeomInfo &geom_info = (*gi);
|
||||||
|
|
||||||
|
PT(Geom) geom =
|
||||||
|
geom_info._geom_node->get_geom(geom_info._index)->make_copy();
|
||||||
|
|
||||||
|
int num_vertices = geom->get_num_vertices();
|
||||||
|
if (geom->has_texcoords(model_name) && num_vertices > 0) {
|
||||||
|
Geom::TexCoordIterator ti = geom->make_texcoord_iterator(model_name);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
const TexCoordf &uv = geom->get_next_texcoord(ti);
|
||||||
|
if (!got_any) {
|
||||||
|
min_uv = max_uv = uv;
|
||||||
|
got_any = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
min_uv.set(min(min_uv[0], uv[0]), min(min_uv[1], uv[1]));
|
||||||
|
max_uv.set(max(max_uv[0], uv[0]), max(max_uv[1], uv[1]));
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
|
||||||
|
while (i < num_vertices) {
|
||||||
|
const TexCoordf &uv = geom->get_next_texcoord(ti);
|
||||||
|
min_uv.set(min(min_uv[0], uv[0]), min(min_uv[1], uv[1]));
|
||||||
|
max_uv.set(max(max_uv[0], uv[0]), max(max_uv[1], uv[1]));
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!got_any) {
|
||||||
|
min_uv.set(0.0f, 0.0f);
|
||||||
|
max_uv.set(1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return got_any;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: MultitexReducer::get_uv_scale
|
||||||
|
// Access: Private
|
||||||
|
// Description: Chooses an appropriate transform to apply to all of
|
||||||
|
// the UV's on the generated texture, based on the
|
||||||
|
// coverage of the model stage. If only a portion of
|
||||||
|
// the model stage is used, we scale the UV's up to zoom
|
||||||
|
// into that one portion; on the other hand, if the
|
||||||
|
// texture repeats many times, we scale the UV's down to
|
||||||
|
// to include all of the repeating image.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void MultitexReducer::
|
||||||
|
get_uv_scale(LVecBase2f &uv_scale, LVecBase2f &uv_trans,
|
||||||
|
const TexCoordf &min_uv, const TexCoordf &max_uv) const {
|
||||||
|
if (max_uv[0] != min_uv[0]) {
|
||||||
|
uv_scale[0] = (max_uv[0] - min_uv[0]);
|
||||||
|
} else {
|
||||||
|
uv_scale[0] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_uv[1] != min_uv[1]) {
|
||||||
|
uv_scale[1] = (max_uv[1] - min_uv[1]);
|
||||||
|
} else {
|
||||||
|
uv_scale[1] = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
uv_trans[0] = (min_uv[0] + max_uv[0]) / 2.0f - uv_scale[0] * 0.5f;
|
||||||
|
uv_trans[1] = (min_uv[1] + max_uv[1]) / 2.0f - uv_scale[1] * 0.5f;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: MultitexReducer::choose_texture_size
|
||||||
|
// Access: Private
|
||||||
|
// Description: Chooses an appropriate size to make the new texture,
|
||||||
|
// based on the size of the original model stage's
|
||||||
|
// texture, and the scale applied to the UV's.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void MultitexReducer::
|
||||||
|
choose_texture_size(int &x_size, int &y_size,
|
||||||
|
const MultitexReducer::StageInfo &model_stage,
|
||||||
|
const LVecBase2f &uv_scale,
|
||||||
|
GraphicsOutput *window) const {
|
||||||
|
Texture *model_tex = model_stage._tex;
|
||||||
|
PixelBuffer *model_pbuffer = model_tex->_pbuffer;
|
||||||
|
|
||||||
|
// Start with the same size as the model texture.
|
||||||
|
x_size = model_pbuffer->get_xsize();
|
||||||
|
y_size = model_pbuffer->get_ysize();
|
||||||
|
|
||||||
|
// But we might be looking at just a subset of that texture (scale <
|
||||||
|
// 1) or a superset of the texture (scale > 1). In this case, we
|
||||||
|
// should adjust the pixel size accordingly, although we have to
|
||||||
|
// keep it to a power of 2.
|
||||||
|
|
||||||
|
LVecBase3f inherited_scale = model_stage._tex_mat->get_scale();
|
||||||
|
|
||||||
|
float u_scale = inherited_scale[0] * uv_scale[0];
|
||||||
|
if (u_scale != 0.0f) {
|
||||||
|
while (u_scale >= 2.0f) {
|
||||||
|
x_size *= 2;
|
||||||
|
u_scale *= 0.5f;
|
||||||
|
}
|
||||||
|
while (u_scale <= 0.5f) {
|
||||||
|
x_size /= 2;
|
||||||
|
u_scale *= 2.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float v_scale = inherited_scale[1] * uv_scale[1];
|
||||||
|
if (v_scale != 0.0f) {
|
||||||
|
while (v_scale >= 2.0f) {
|
||||||
|
y_size *= 2;
|
||||||
|
v_scale *= 0.5f;
|
||||||
|
}
|
||||||
|
while (v_scale <= 0.5f) {
|
||||||
|
y_size /= 2;
|
||||||
|
v_scale *= 2.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constrain the x_size and y_size to the max_texture_dimension.
|
||||||
|
if (max_texture_dimension > 0) {
|
||||||
|
x_size = min(x_size, max_texture_dimension);
|
||||||
|
y_size = min(y_size, max_texture_dimension);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, make sure the new sizes fit within the window, so we can
|
||||||
|
// use a parasite buffer.
|
||||||
|
int win_x_size = window->get_x_size();
|
||||||
|
if (win_x_size != 0 && x_size > win_x_size) {
|
||||||
|
x_size /= 2;
|
||||||
|
while (x_size > win_x_size) {
|
||||||
|
x_size /= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int win_y_size = window->get_y_size();
|
||||||
|
if (win_y_size != 0 && y_size > win_y_size) {
|
||||||
|
y_size /= 2;
|
||||||
|
while (y_size > win_y_size) {
|
||||||
|
y_size /= 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +666,7 @@ make_texture_layer(const NodePath &render,
|
|||||||
|
|
||||||
NodePath geom;
|
NodePath geom;
|
||||||
|
|
||||||
if (stage_info._stage->get_texcoord_name() == _target_stage->get_texcoord_name()) {
|
if (!_use_geom && stage_info._stage->get_texcoord_name() == _target_stage->get_texcoord_name()) {
|
||||||
// If this TextureStage uses the target texcoords, we can just
|
// If this TextureStage uses the target texcoords, we can just
|
||||||
// generate a simple card the fills the entire buffer.
|
// generate a simple card the fills the entire buffer.
|
||||||
CardMaker cm(stage_info._tex->get_name());
|
CardMaker cm(stage_info._tex->get_name());
|
||||||
@ -405,18 +677,19 @@ make_texture_layer(const NodePath &render,
|
|||||||
geom = render.attach_new_node(cm.generate());
|
geom = render.attach_new_node(cm.generate());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// If this TextureStage uses some other texcoords, we have to
|
// If this TextureStage uses some other texcoords (or if use_geom
|
||||||
// generate geometry that maps the texcoords to the target space.
|
// is true), we have to generate geometry that maps the texcoords
|
||||||
// This will work only for very simple cases where the geometry is
|
// to the target space. This will work only for very simple cases
|
||||||
// not too extensive and doesn't repeat over the same UV's.
|
// where the geometry is not too extensive and doesn't repeat over
|
||||||
|
// the same UV's.
|
||||||
PT(GeomNode) geom_node = new GeomNode(stage_info._tex->get_name());
|
PT(GeomNode) geom_node = new GeomNode(stage_info._tex->get_name());
|
||||||
transfer_geom(geom_node, stage_info._stage->get_texcoord_name(),
|
transfer_geom(geom_node, stage_info._stage->get_texcoord_name(),
|
||||||
geom_list);
|
geom_list, false);
|
||||||
|
|
||||||
geom = render.attach_new_node(geom_node);
|
geom = render.attach_new_node(geom_node);
|
||||||
|
|
||||||
// Make sure we override the vertex color, so we don't pollute the
|
// Make sure we override the vertex color, so we don't pollute
|
||||||
// texture with geometry color.
|
// the texture with geometry color.
|
||||||
geom.set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
|
geom.set_color(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,7 +712,8 @@ make_texture_layer(const NodePath &render,
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void MultitexReducer::
|
void MultitexReducer::
|
||||||
transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
|
transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
|
||||||
const MultitexReducer::GeomList &geom_list) {
|
const MultitexReducer::GeomList &geom_list,
|
||||||
|
bool preserve_color) {
|
||||||
GeomList::const_iterator gi;
|
GeomList::const_iterator gi;
|
||||||
for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
|
for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
|
||||||
const GeomInfo &geom_info = (*gi);
|
const GeomInfo &geom_info = (*gi);
|
||||||
@ -458,11 +732,26 @@ transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
geom->set_coords(coords, geom->get_texcoords_index(_target_stage->get_texcoord_name()));
|
geom->set_coords(coords, geom->get_texcoords_index(_target_stage->get_texcoord_name()));
|
||||||
geom->set_texcoords(TexCoordName::get_default(),
|
if (texcoord_name != (const TexCoordName *)NULL) {
|
||||||
geom->get_texcoords_array(texcoord_name),
|
geom->set_texcoords(TexCoordName::get_default(),
|
||||||
geom->get_texcoords_index(texcoord_name));
|
geom->get_texcoords_array(texcoord_name),
|
||||||
|
geom->get_texcoords_index(texcoord_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
CPT(RenderState) geom_state = RenderState::make_empty();
|
||||||
|
if (preserve_color) {
|
||||||
|
// Be sure to preserve whatever colors are on the geom.
|
||||||
|
const RenderAttrib *ca = geom_info._geom_net_state->get_attrib(ColorAttrib::get_class_type());
|
||||||
|
if (ca != (const RenderAttrib *)NULL) {
|
||||||
|
geom_state->add_attrib(ca);
|
||||||
|
}
|
||||||
|
const RenderAttrib *csa = geom_info._geom_net_state->get_attrib(ColorScaleAttrib::get_class_type());
|
||||||
|
if (csa != (const RenderAttrib *)NULL) {
|
||||||
|
geom_state->add_attrib(csa);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
geom_node->add_geom(geom);
|
geom_node->add_geom(geom, geom_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "texMatrixAttrib.h"
|
#include "texMatrixAttrib.h"
|
||||||
#include "transformState.h"
|
#include "transformState.h"
|
||||||
#include "geomNode.h"
|
#include "geomNode.h"
|
||||||
|
#include "nodePath.h"
|
||||||
#include "luse.h"
|
#include "luse.h"
|
||||||
#include "pointerTo.h"
|
#include "pointerTo.h"
|
||||||
#include "pmap.h"
|
#include "pmap.h"
|
||||||
@ -58,10 +59,13 @@ PUBLISHED:
|
|||||||
~MultitexReducer();
|
~MultitexReducer();
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
INLINE void scan(const NodePath &node, const NodePath &state_from = NodePath());
|
||||||
void scan(PandaNode *node, const RenderState *state,
|
void scan(PandaNode *node, const RenderState *state,
|
||||||
const TransformState *transform);
|
const TransformState *transform);
|
||||||
|
|
||||||
void set_target(TextureStage *stage);
|
void set_target(TextureStage *stage);
|
||||||
|
void set_use_geom(bool use_geom);
|
||||||
|
void set_allow_tex_mat(bool allow_tex_mat);
|
||||||
|
|
||||||
void flatten(GraphicsOutput *window);
|
void flatten(GraphicsOutput *window);
|
||||||
|
|
||||||
@ -82,8 +86,11 @@ private:
|
|||||||
|
|
||||||
class GeomInfo {
|
class GeomInfo {
|
||||||
public:
|
public:
|
||||||
INLINE GeomInfo(GeomNode *geom_node, int index);
|
INLINE GeomInfo(const RenderState *state, const RenderState *geom_net_state,
|
||||||
|
GeomNode *geom_node, int index);
|
||||||
|
|
||||||
|
CPT(RenderState) _state;
|
||||||
|
CPT(RenderState) _geom_net_state;
|
||||||
PT(GeomNode) _geom_node;
|
PT(GeomNode) _geom_node;
|
||||||
int _index;
|
int _index;
|
||||||
};
|
};
|
||||||
@ -94,6 +101,8 @@ private:
|
|||||||
Stages _stages;
|
Stages _stages;
|
||||||
|
|
||||||
PT(TextureStage) _target_stage;
|
PT(TextureStage) _target_stage;
|
||||||
|
bool _use_geom;
|
||||||
|
bool _allow_tex_mat;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void scan_geom_node(GeomNode *node, const RenderState *state,
|
void scan_geom_node(GeomNode *node, const RenderState *state,
|
||||||
@ -102,16 +111,24 @@ private:
|
|||||||
void record_stage_list(const StageList &stage_list,
|
void record_stage_list(const StageList &stage_list,
|
||||||
const GeomInfo &geom_info);
|
const GeomInfo &geom_info);
|
||||||
|
|
||||||
void determine_size(int &x_size, int &y_size, int &aniso_degree,
|
size_t choose_model_stage(const StageList &stage_list) const;
|
||||||
Texture::FilterType &minfilter,
|
bool determine_uv_range(TexCoordf &min_uv, TexCoordf &max_uv,
|
||||||
Texture::FilterType &magfilter,
|
const StageInfo &model_stage,
|
||||||
const MultitexReducer::StageList &stage_list) const;
|
const GeomList &geom_list) const;
|
||||||
|
|
||||||
|
void get_uv_scale(LVecBase2f &uv_scale, LVecBase2f &uv_trans,
|
||||||
|
const TexCoordf &min_uv, const TexCoordf &max_uv) const;
|
||||||
|
|
||||||
|
void choose_texture_size(int &x_size, int &y_size,
|
||||||
|
const StageInfo &model_stage,
|
||||||
|
const LVecBase2f &uv_scale,
|
||||||
|
GraphicsOutput *window) const;
|
||||||
|
|
||||||
void make_texture_layer(const NodePath &render,
|
void make_texture_layer(const NodePath &render,
|
||||||
const StageInfo &stage_info,
|
const StageInfo &stage_info,
|
||||||
const GeomList &geom_list);
|
const GeomList &geom_list);
|
||||||
void transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
|
void transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
|
||||||
const MultitexReducer::GeomList &geom_list);
|
const GeomList &geom_list, bool preserve_color);
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "multitexReducer.I"
|
#include "multitexReducer.I"
|
||||||
|
@ -109,9 +109,9 @@ void
|
|||||||
event_0(CPT_Event event, void *) {
|
event_0(CPT_Event event, void *) {
|
||||||
// 0: run hacky test.
|
// 0: run hacky test.
|
||||||
MultitexReducer mr;
|
MultitexReducer mr;
|
||||||
|
mr.set_use_geom(true);
|
||||||
|
|
||||||
NodePath models = framework.get_models();
|
mr.scan(framework.get_models());
|
||||||
mr.scan(models.node(), models.get_net_state(), models.get_net_transform());
|
|
||||||
|
|
||||||
WindowFramework *wf = framework.get_window(0);
|
WindowFramework *wf = framework.get_window(0);
|
||||||
GraphicsWindow *win = wf->get_graphics_window();
|
GraphicsWindow *win = wf->get_graphics_window();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user