mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
multitexture
This commit is contained in:
parent
bffab12c27
commit
db3ab1f6ba
@ -24,7 +24,9 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE DXGeomMunger8::
|
||||
DXGeomMunger8(GraphicsStateGuardian *gsg, const RenderState *state) :
|
||||
StandardMunger(gsg, state, 1, NT_packed_dabc, C_color)
|
||||
StandardMunger(gsg, state, 1, NT_packed_dabc, C_color),
|
||||
_texture(state->get_texture()->filter_to_max(gsg->get_max_texture_stages())),
|
||||
_tex_gen(state->get_tex_gen())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -49,8 +49,6 @@ munge_format_impl(const qpGeomVertexFormat *orig,
|
||||
const qpGeomVertexColumn *vertex_type = orig->get_vertex_column();
|
||||
const qpGeomVertexColumn *normal_type = orig->get_normal_column();
|
||||
const qpGeomVertexColumn *color_type = orig->get_color_column();
|
||||
const qpGeomVertexColumn *texcoord_type =
|
||||
orig->get_column(InternalName::get_texcoord());
|
||||
|
||||
if (vertex_type != (const qpGeomVertexColumn *)NULL) {
|
||||
new_array_format->add_column
|
||||
@ -103,13 +101,36 @@ munge_format_impl(const qpGeomVertexFormat *orig,
|
||||
}
|
||||
|
||||
// To support multitexture, we will need to add all of the relevant
|
||||
// texcoord types, and in the correct order (or at least in a known
|
||||
// order). For now, we just add the default texcoords only.
|
||||
// texcoord types, and in the correct order.
|
||||
|
||||
// Now set up each of the active texture coordinate stages--or at
|
||||
// least those for which we're not generating texture coordinates
|
||||
// automatically.
|
||||
|
||||
// Now copy all of the texture coordinates in, in order by stage
|
||||
// index. But we have to reuse previous columns.
|
||||
typedef pset<const InternalName *> UsedStages;
|
||||
UsedStages used_stages;
|
||||
|
||||
int num_stages = _texture->get_num_on_stages();
|
||||
for (int i = 0; i < num_stages; ++i) {
|
||||
TextureStage *stage = _texture->get_on_stage(i);
|
||||
|
||||
const InternalName *name = stage->get_texcoord_name();
|
||||
if (used_stages.insert(name).second) {
|
||||
// This is the first time we've encountered this texcoord name.
|
||||
const qpGeomVertexColumn *texcoord_type = orig->get_column(name);
|
||||
|
||||
if (texcoord_type != (const qpGeomVertexColumn *)NULL) {
|
||||
new_array_format->add_column
|
||||
(InternalName::get_texcoord(), texcoord_type->get_num_values(),
|
||||
NT_float32, C_texcoord);
|
||||
new_format->remove_column(texcoord_type->get_name());
|
||||
(name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
|
||||
} else {
|
||||
// We have to add something as a placeholder, even if the
|
||||
// texture coordinates aren't defined.
|
||||
new_array_format->add_column(name, 2, NT_float32, C_texcoord);
|
||||
}
|
||||
new_format->remove_column(name);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_array_format->is_data_subset_of(*orig->get_array(0))) {
|
||||
@ -123,3 +144,48 @@ munge_format_impl(const qpGeomVertexFormat *orig,
|
||||
new_format->insert_array(0, new_array_format);
|
||||
return qpGeomVertexFormat::register_format(new_format);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGeomMunger8::compare_to_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called to compare two GeomMungers who are known to be
|
||||
// of the same type, for an apples-to-apples comparison.
|
||||
// This will never be called on two pointers of a
|
||||
// different type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int DXGeomMunger8::
|
||||
compare_to_impl(const qpGeomMunger *other) const {
|
||||
const DXGeomMunger8 *om = DCAST(DXGeomMunger8, other);
|
||||
if (_texture != om->_texture) {
|
||||
return _texture < om->_texture ? -1 : 1;
|
||||
}
|
||||
if (_tex_gen != om->_tex_gen) {
|
||||
return _tex_gen < om->_tex_gen ? -1 : 1;
|
||||
}
|
||||
|
||||
return StandardMunger::compare_to_impl(other);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DXGeomMunger8::geom_compare_to_impl
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called to compare two GeomMungers who are known to be
|
||||
// of the same type, for an apples-to-apples comparison.
|
||||
// This will never be called on two pointers of a
|
||||
// different type.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int DXGeomMunger8::
|
||||
geom_compare_to_impl(const qpGeomMunger *other) const {
|
||||
// Unlike GLGeomMunger, we do consider _texture and _tex_gen
|
||||
// important for this purpose, since they control the number and
|
||||
// order of texture coordinates we might put into the FVF.
|
||||
const DXGeomMunger8 *om = DCAST(DXGeomMunger8, other);
|
||||
if (_texture != om->_texture) {
|
||||
return _texture < om->_texture ? -1 : 1;
|
||||
}
|
||||
if (_tex_gen != om->_tex_gen) {
|
||||
return _tex_gen < om->_tex_gen ? -1 : 1;
|
||||
}
|
||||
|
||||
return StandardMunger::geom_compare_to_impl(other);
|
||||
}
|
||||
|
@ -39,10 +39,16 @@ protected:
|
||||
virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig,
|
||||
const qpGeomVertexAnimationSpec &animation);
|
||||
|
||||
virtual int compare_to_impl(const qpGeomMunger *other) const;
|
||||
virtual int geom_compare_to_impl(const qpGeomMunger *other) const;
|
||||
|
||||
public:
|
||||
INLINE void *operator new(size_t size);
|
||||
|
||||
private:
|
||||
CPT(TextureAttrib) _texture;
|
||||
CPT(TexGenAttrib) _tex_gen;
|
||||
|
||||
static qpGeomMunger *_deleted_chain;
|
||||
|
||||
public:
|
||||
|
@ -1506,6 +1506,7 @@ reset() {
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
_max_texture_stages = d3dCaps.MaxSimultaneousTextures;
|
||||
_max_lights = d3dCaps.MaxActiveLights;
|
||||
_max_clip_planes = d3dCaps.MaxUserClipPlanes;
|
||||
_max_vertex_transforms = d3dCaps.MaxVertexBlendMatrices;
|
||||
@ -1918,24 +1919,8 @@ issue_depth_offset(const DepthOffsetAttrib *attrib) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DXGraphicsStateGuardian8::
|
||||
issue_tex_gen(const TexGenAttrib *attrib) {
|
||||
TexGenAttrib::Mode mode = attrib->get_mode(TextureStage::get_default());
|
||||
switch (mode) {
|
||||
case TexGenAttrib::M_off:
|
||||
_pD3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
|
||||
_pD3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
|
||||
break;
|
||||
|
||||
case TexGenAttrib::M_eye_sphere_map:
|
||||
_pD3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX,
|
||||
D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
|
||||
_pD3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
|
||||
break;
|
||||
|
||||
case TexGenAttrib::M_point_sprite:
|
||||
_pD3DDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);
|
||||
_pD3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
|
||||
break;
|
||||
}
|
||||
_current_tex_gen = attrib;
|
||||
_texture_stale = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -2200,30 +2185,87 @@ do_issue_texture() {
|
||||
|
||||
_texture_involves_color_scale = false;
|
||||
|
||||
// We have to match up the texcoord stage index to the order written
|
||||
// out by the DXGeomMunger. This means the texcoord names are
|
||||
// written in the order they are referenced by the TextureAttrib,
|
||||
// except that if a name is repeated its index number is reused from
|
||||
// the first time.
|
||||
typedef pmap<const InternalName *, int> UsedTexcoordIndex;
|
||||
UsedTexcoordIndex used_texcoord_index;
|
||||
|
||||
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.
|
||||
const InternalName *name = stage->get_texcoord_name();
|
||||
|
||||
// This pair of lines will get the next consecutive texcoord index
|
||||
// number if this is the first time we have referenced this
|
||||
// particular texcoord name; otherwise, it will return the same
|
||||
// index number it returned before.
|
||||
UsedTexcoordIndex::iterator ti = used_texcoord_index.insert(UsedTexcoordIndex::value_type(name, (int)used_texcoord_index.size())).first;
|
||||
int texcoord_index = (*ti).second;
|
||||
|
||||
// We always reissue every stage in DX, just in case the texcoord
|
||||
// index or texgen mode or some other property has changed.
|
||||
TextureContext *tc = texture->prepare_now(_prepared_objects, this);
|
||||
apply_texture(i, tc);
|
||||
|
||||
set_texture_blend_mode(i, stage);
|
||||
|
||||
bool has_tex_mat = false;
|
||||
LMatrix4f tex_mat;
|
||||
|
||||
if (_current_tex_mat->has_stage(stage)) {
|
||||
// We have to reorder the elements of the matrix for some reason.
|
||||
const LMatrix4f &m = _current_tex_mat->get_mat(stage);
|
||||
LMatrix4f dm(m(0, 0), m(0, 1), m(0, 3), 0.0f,
|
||||
tex_mat.set(m(0, 0), m(0, 1), m(0, 3), 0.0f,
|
||||
m(1, 0), m(1, 1), m(1, 3), 0.0f,
|
||||
m(3, 0), m(3, 1), m(3, 3), 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
_pD3DDevice->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)dm.get_data());
|
||||
has_tex_mat = true;
|
||||
}
|
||||
|
||||
// Issue the texgen mode.
|
||||
TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage);
|
||||
bool any_point_sprite = false;
|
||||
switch (mode) {
|
||||
case TexGenAttrib::M_off:
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, texcoord_index);
|
||||
break;
|
||||
|
||||
case TexGenAttrib::M_eye_sphere_map:
|
||||
{
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX,
|
||||
texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
|
||||
// This texture matrix, applied on top of the texcoord
|
||||
// computed by D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR,
|
||||
// approximates the effect produced by OpenGL's GL_SPHERE_MAP.
|
||||
LMatrix4f sphere_map(0.33f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.33f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, 0.0f, 1.0f);
|
||||
|
||||
if (has_tex_mat) {
|
||||
tex_mat = sphere_map * tex_mat;
|
||||
} else {
|
||||
tex_mat = sphere_map;
|
||||
has_tex_mat = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TexGenAttrib::M_point_sprite:
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, texcoord_index);
|
||||
any_point_sprite = true;
|
||||
break;
|
||||
}
|
||||
|
||||
_pD3DDevice->SetRenderState(D3DRS_POINTSPRITEENABLE, any_point_sprite);
|
||||
|
||||
if (has_tex_mat) {
|
||||
_pD3DDevice->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)tex_mat.get_data());
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS,
|
||||
D3DTTFF_COUNT2);
|
||||
} else {
|
||||
@ -2235,7 +2277,6 @@ do_issue_texture() {
|
||||
_pD3DDevice->SetTransform(get_tex_mat_sym(i), &matIdentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disable the texture stages that are no longer used.
|
||||
for (i = num_stages; i < num_old_stages; i++) {
|
||||
@ -2243,11 +2284,6 @@ do_issue_texture() {
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -2789,20 +2825,20 @@ set_texture_blend_mode(int i, const TextureStage *stage) {
|
||||
// want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv)
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
|
||||
break;
|
||||
|
||||
case TextureStage::M_decal:
|
||||
// emulates GL_DECAL glTexEnv mode
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_BLENDTEXTUREALPHA);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
|
||||
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_CURRENT);
|
||||
break;
|
||||
|
||||
case TextureStage::M_replace:
|
||||
@ -2816,13 +2852,13 @@ set_texture_blend_mode(int i, const TextureStage *stage) {
|
||||
case TextureStage::M_add:
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_ADD);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_COLORARG2, D3DTA_CURRENT);
|
||||
|
||||
// since I'm making up 'add' mode, use modulate. "adding" alpha
|
||||
// never makes sense right?
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
_pD3DDevice->SetTextureStageState(i, D3DTSS_ALPHAARG2, D3DTA_CURRENT);
|
||||
break;
|
||||
|
||||
case TextureStage::M_blend:
|
||||
|
@ -106,29 +106,60 @@ DXVertexBufferContext8(qpGeomVertexArrayData *data) :
|
||||
++n;
|
||||
}
|
||||
|
||||
// For multitexture support, we will need to look for all of the
|
||||
// texcoord names and enable them in order.
|
||||
if (n < num_columns &&
|
||||
array_format->get_column(n)->get_name() == InternalName::get_texcoord()) {
|
||||
// Now look for all of the texcoord names and enable them in the
|
||||
// same order they appear in the array.
|
||||
int texcoord_index = 0;
|
||||
while (n < num_columns &&
|
||||
array_format->get_column(n)->get_contents() == qpGeom::C_texcoord) {
|
||||
const qpGeomVertexColumn *column = array_format->get_column(n);
|
||||
switch (column->get_num_values()) {
|
||||
case 1:
|
||||
_fvf |= D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE1(0);
|
||||
_fvf |= D3DFVF_TEXCOORDSIZE1(texcoord_index);
|
||||
++n;
|
||||
break;
|
||||
case 2:
|
||||
_fvf |= D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0);
|
||||
_fvf |= D3DFVF_TEXCOORDSIZE2(texcoord_index);
|
||||
++n;
|
||||
break;
|
||||
case 3:
|
||||
_fvf |= D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0);
|
||||
_fvf |= D3DFVF_TEXCOORDSIZE3(texcoord_index);
|
||||
++n;
|
||||
break;
|
||||
case 4:
|
||||
_fvf |= D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE4(0);
|
||||
_fvf |= D3DFVF_TEXCOORDSIZE4(texcoord_index);
|
||||
++n;
|
||||
break;
|
||||
}
|
||||
++texcoord_index;
|
||||
}
|
||||
|
||||
switch (texcoord_index) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
_fvf |= D3DFVF_TEX1;
|
||||
break;
|
||||
case 2:
|
||||
_fvf |= D3DFVF_TEX2;
|
||||
break;
|
||||
case 3:
|
||||
_fvf |= D3DFVF_TEX3;
|
||||
break;
|
||||
case 4:
|
||||
_fvf |= D3DFVF_TEX4;
|
||||
break;
|
||||
case 5:
|
||||
_fvf |= D3DFVF_TEX5;
|
||||
break;
|
||||
case 6:
|
||||
_fvf |= D3DFVF_TEX6;
|
||||
break;
|
||||
case 7:
|
||||
_fvf |= D3DFVF_TEX7;
|
||||
break;
|
||||
case 8:
|
||||
_fvf |= D3DFVF_TEX8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user