2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
6 // $Header: r:/t2repos/thief2/src/render/meshtex.cpp,v 1.1 2000/01/14 10:40:19 MAT Exp $
8 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
11 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
44 // @HACK: We want to load textures using an internal objmodel path so
45 // the custom mesh textures can be in the same directories as the
47 EXTERN ISearchPath
*MeshModelTexturesPath
;
50 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
54 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
59 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
63 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
65 // number of things in property
66 static const int kNumTextures
= 12;
68 // max materials we can handle
69 static const int kMaxTextureSubst
= 128;
72 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
76 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
78 // info on the object we're rendering
79 static mms_model
*g_pCurrentModel
;
80 static ObjID g_CurrentObj
;
81 static sMeshTexRemap
*g_pCurrentRemap
;
87 grs_bitmap
*m_pBitmap
;
89 static cDynArray
<sResTexture
> g_Textures
;
91 // to stash off the parts of the real model we'll be overwriting
92 static ulong g_aszDefaultMaterial
[kMaxTextureSubst
];
95 static IResMan
*g_pResMan
;
98 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
102 We have a horrible little struct which holds the parts of the mesh
103 model which we swap in on-the-fly.
105 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
109 char m_aszDefault
[16];
110 char m_aszCustom
[16];
115 int m_iMaterialIndex
; // within mms_model, that is
116 grs_bitmap
*m_pBitmap
;
120 ///////////////////////////////////////////////
121 // the structure used for the property
125 // We do this so the cDynArrays won't try to get copied on load,
126 // with their pointers left over from when they were saved off.
127 // The data we're losing is derived from the data we're keeping.
128 sMeshTexRemap
&operator=(const sMeshTexRemap
&from
)
130 memcpy(&m_Texture
, &from
.m_Texture
, sizeof(m_Texture
));
131 memset(&m_TextureSubst
, 0, sizeof(m_TextureSubst
));
140 ///////////////////////////////////////////////
141 // Here's the part which the designer sets.
142 sTexture m_Texture
[kNumTextures
];
144 ///////////////////////////////////////////////
145 // This part is set up whenever the property is modified. It's the
146 // actual stuff we swap in and out.
147 cDynArray
<sTextureSubst
> m_TextureSubst
;
148 BOOL m_bSet
; // TRUE if this instance has been set up since load
153 #define INTERFACE IMeshTexProperty
155 DECLARE_PROPERTY_INTERFACE(IMeshTexProperty
)
157 DECLARE_UNKNOWN_PURE();
158 DECLARE_PROPERTY_PURE();
159 DECLARE_PROPERTY_ACCESSORS(sMeshTexRemap
*);
163 static sPropertyDesc g_MeshTexDesc
169 { "Renderer", "Mesh Textures", "Mesh Texture Substitution" },
170 kPropertyChangeLocally
,
173 class cMeshTexOps
: public cClassDataOps
<sMeshTexRemap
>
177 class cMeshTexStore
: public cHashPropertyStore
<cMeshTexOps
>
181 typedef cSpecificProperty
<IMeshTexProperty
,
182 &IID_IMeshTexProperty
, sMeshTexRemap
*,
183 cMeshTexStore
> cBaseMeshTexProperty
;
185 class cMeshTexProperty
: public cBaseMeshTexProperty
188 cMeshTexProperty(const sPropertyDesc
*desc
)
189 : cBaseMeshTexProperty(desc
)
193 void OnListenMsg(ePropertyListenMsg msg
, ObjID obj
, uPropListenerValue val
)
195 sMeshTexRemap
*pRemap
= (sMeshTexRemap
*) val
.ptrval
;
197 // Zero out the dynarrays on load/modify
198 if (msg
& (kListenPropLoad
| kListenPropModify
)) {
199 if (msg
& kListenPropLoad
) {
200 memset(&pRemap
->m_TextureSubst
, 0, sizeof(pRemap
->m_TextureSubst
));
202 pRemap
->m_TextureSubst
.SetSize(0);
204 pRemap
->m_bSet
= FALSE
;
208 STANDARD_DESCRIBE_TYPE(cMeshTexProperty
);
215 static sFieldDesc g_aMeshTexFieldDesc
[]
217 { "texture in model", kFieldTypeString
,
218 FieldLocation(sMeshTexRemap
, m_Texture
[0].m_aszDefault
) },
219 { "replace with", kFieldTypeString
,
220 FieldLocation(sMeshTexRemap
, m_Texture
[0].m_aszCustom
) },
222 { "texture in model", kFieldTypeString
,
223 FieldLocation(sMeshTexRemap
, m_Texture
[1].m_aszDefault
) },
224 { "replace with", kFieldTypeString
,
225 FieldLocation(sMeshTexRemap
, m_Texture
[1].m_aszCustom
) },
227 { "texture in model", kFieldTypeString
,
228 FieldLocation(sMeshTexRemap
, m_Texture
[2].m_aszDefault
) },
229 { "replace with", kFieldTypeString
,
230 FieldLocation(sMeshTexRemap
, m_Texture
[2].m_aszCustom
) },
232 { "texture in model", kFieldTypeString
,
233 FieldLocation(sMeshTexRemap
, m_Texture
[3].m_aszDefault
) },
234 { "replace with", kFieldTypeString
,
235 FieldLocation(sMeshTexRemap
, m_Texture
[3].m_aszCustom
) },
237 { "texture in model", kFieldTypeString
,
238 FieldLocation(sMeshTexRemap
, m_Texture
[4].m_aszDefault
) },
239 { "replace with", kFieldTypeString
,
240 FieldLocation(sMeshTexRemap
, m_Texture
[4].m_aszCustom
) },
242 { "texture in model", kFieldTypeString
,
243 FieldLocation(sMeshTexRemap
, m_Texture
[5].m_aszDefault
) },
244 { "replace with", kFieldTypeString
,
245 FieldLocation(sMeshTexRemap
, m_Texture
[5].m_aszCustom
) },
247 { "texture in model", kFieldTypeString
,
248 FieldLocation(sMeshTexRemap
, m_Texture
[6].m_aszDefault
) },
249 { "replace with", kFieldTypeString
,
250 FieldLocation(sMeshTexRemap
, m_Texture
[6].m_aszCustom
) },
252 { "texture in model", kFieldTypeString
,
253 FieldLocation(sMeshTexRemap
, m_Texture
[7].m_aszDefault
) },
254 { "replace with", kFieldTypeString
,
255 FieldLocation(sMeshTexRemap
, m_Texture
[7].m_aszCustom
) },
257 { "texture in model", kFieldTypeString
,
258 FieldLocation(sMeshTexRemap
, m_Texture
[8].m_aszDefault
) },
259 { "replace with", kFieldTypeString
,
260 FieldLocation(sMeshTexRemap
, m_Texture
[8].m_aszCustom
) },
262 { "texture in model", kFieldTypeString
,
263 FieldLocation(sMeshTexRemap
, m_Texture
[9].m_aszDefault
) },
264 { "replace with", kFieldTypeString
,
265 FieldLocation(sMeshTexRemap
, m_Texture
[9].m_aszCustom
) },
267 { "texture in model", kFieldTypeString
,
268 FieldLocation(sMeshTexRemap
, m_Texture
[10].m_aszDefault
) },
269 { "replace with", kFieldTypeString
,
270 FieldLocation(sMeshTexRemap
, m_Texture
[10].m_aszCustom
) },
272 { "texture in model", kFieldTypeString
,
273 FieldLocation(sMeshTexRemap
, m_Texture
[11].m_aszDefault
) },
274 { "replace with", kFieldTypeString
,
275 FieldLocation(sMeshTexRemap
, m_Texture
[11].m_aszCustom
) },
278 static sStructDesc g_MeshTexStructDesc
279 = StructDescBuild(cMeshTexProperty
, kStructFlagNone
,
280 g_aMeshTexFieldDesc
);
282 void cMeshTexProperty::CreateEditor()
284 AutoAppIPtr(StructDescTools
);
285 pStructDescTools
->Register(&g_MeshTexStructDesc
);
286 cPropertyBase::CreateEditor(this);
289 IMeshTexProperty
*g_pMeshTexProperty
;
292 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
296 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
298 static void SetUpRemap(ObjID Obj
, mms_model
*pModel
, sMeshTexRemap
*pRemap
)
300 mms_smatr
*pMaterial
= mm_smatr_list(pModel
);
301 mms_segment
*pSegment
= mm_segment_list(pModel
);
303 // set up remapping of textures
304 for (int iTexSub
= 0; iTexSub
< kNumTextures
; ++iTexSub
) {
305 if (!pRemap
->m_Texture
[iTexSub
].m_aszDefault
[0])
310 // find material which matches our string
311 for (iMat
= 0; iMat
< pModel
->smatrs
; ++iMat
)
312 if (!stricmp(pMaterial
[iMat
].name
,
313 pRemap
->m_Texture
[iTexSub
].m_aszDefault
))
317 if (iMat
== pModel
->smatrs
) {
318 Warning(("meshtex: Can't find texture %s for object %s.\n",
319 pRemap
->m_Texture
[iTexSub
].m_aszDefault
,
320 AppGetObj(IObjectSystem
)->GetName(Obj
)));
326 Subst
.m_iMaterialIndex
= iMat
;
327 Subst
.m_pBitmap
=MeshTexGetBitmap(pRemap
->m_Texture
[iTexSub
].m_aszCustom
);
330 if (Subst
.m_pBitmap
== 0) {
331 Warning(("meshtex: Can't find texture %s for object %s.\n",
332 pRemap
->m_Texture
[iTexSub
].m_aszCustom
,
333 AppGetObj(IObjectSystem
)->GetName(Obj
)));
338 pRemap
->m_TextureSubst
.Append(Subst
);
341 pRemap
->m_bSet
= TRUE
;
345 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
349 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
353 static void DoNothing()
358 static Command g_aCommands
[]
360 { "mesh_nothing", FUNC_VOID
, &DoNothing
, "Maybe later.", HK_ALL
},
361 { "face_process", FUNC_VOID
, &BuildFacePosFile
,
362 "find textures to match speech samples.", HK_ALL
},
367 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
371 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
373 // If there's no texture for the name we return 0, but don't warn
374 // because it's the callers business whether the texture is needed.
375 grs_bitmap
*MeshTexGetBitmap(char *pszName
)
379 // Do we already have this one? We usually will.
380 for (int i
= 0; i
< g_Textures
.Size(); ++i
)
381 if (!strcmp(g_Textures
[i
].m_aszName
, pszName
))
382 return g_Textures
[i
].m_pBitmap
;
384 IRes
*pRes
= g_pResMan
->Bind(pszName
, RESTYPE_IMAGE
, MeshModelTexturesPath
);
388 // @HACK: This bit here where we distinguish regular textures
389 // from palletized ones is copied directly from objmodel, and
390 // duplicates the "txt16" path used there rather than relying
391 // on a constant shared by both modules. Ain't I a bum.
392 IStore
*pCanonStore
= pRes
->GetCanonStore();
393 if (!stricmp(pCanonStore
->GetName(), "txt16\\")) {
394 // Okay. Get the palette...
395 IRes
*pPallRes
= g_pResMan
->Retype(pRes
, RESTYPE_PALETTE
, 0);
397 void *pPall
= pPallRes
->Lock();
398 grs_bitmap
*pbm
= (grs_bitmap
*) pRes
->Lock();
400 uchar b
= pbm
->align
;
401 pbm
->align
= palmgr_alloc_pal((uchar
*) pPall
);
403 if ((g_tmgr
!= NULL
) && (pbm
->flags
& BMF_LOADED
)) {
404 lgd3d_unload_texture(pbm
);
405 lgd3d_load_texture(pbm
);
410 // We're done with the palette; the palette manager will now
411 // take charge of it. So we can drop it from memory.
416 pCanonStore
->Release();
419 strncpy(NewPair
.m_aszName
, pszName
, 16);
420 NewPair
.m_pRes
= pRes
;
421 NewPair
.m_pBitmap
= (grs_bitmap
*) pRes
->Lock();
422 g_Textures
.Append(NewPair
);
424 return NewPair
.m_pBitmap
;
430 g_pMeshTexProperty
= new cMeshTexProperty(&g_MeshTexDesc
);
431 g_pResMan
= AppGetObj(IResMan
);
435 COMMANDS(g_aCommands
, HK_ALL
);
448 for (int i
= 0; i
< g_Textures
.Size(); ++i
) {
449 g_Textures
[i
].m_pRes
->Unlock();
450 g_Textures
[i
].m_pRes
->Release();
452 g_Textures
.SetSize(0);
457 // stamp in our substitute textures, storing off the originals
458 void MeshTexPrerender(ObjID Obj
, mms_model
*pModel
)
460 sMeshTexRemap
*pRemap
;
462 // Does this object have our special property?
463 if (!g_pMeshTexProperty
->Get(Obj
, &pRemap
)) {
468 g_pCurrentModel
= pModel
;
470 g_pCurrentRemap
= pRemap
;
473 SetUpRemap(Obj
, pModel
, pRemap
);
475 mms_smatr
*pMaterial
= mm_smatr_list(pModel
);
476 int iNumTextureSubst
= pRemap
->m_TextureSubst
.Size();
477 sTextureSubst
*pTextureSubst
= pRemap
->m_TextureSubst
.AsPointer();
479 Assert_(iNumTextureSubst
<= kMaxTextureSubst
);
481 for (int i
= 0; i
< iNumTextureSubst
; ++i
) {
482 g_aszDefaultMaterial
[i
]
483 = pMaterial
[pTextureSubst
[i
].m_iMaterialIndex
].handle
;
484 pMaterial
[pTextureSubst
[i
].m_iMaterialIndex
].handle
485 = (ulong
) pTextureSubst
[i
].m_pBitmap
;
488 FacePrerender(Obj
, pModel
);
492 // restore the regular textures to the model
493 void MeshTexPostrender()
495 if (!g_pCurrentModel
)
498 mms_smatr
*pMaterial
= mm_smatr_list(g_pCurrentModel
);
499 int iNumTextureSubst
= g_pCurrentRemap
->m_TextureSubst
.Size();
500 sTextureSubst
*pTextureSubst
= g_pCurrentRemap
->m_TextureSubst
.AsPointer();
502 for (int i
= 0; i
< iNumTextureSubst
; ++i
)
503 pMaterial
[pTextureSubst
[i
].m_iMaterialIndex
].handle
504 = g_aszDefaultMaterial
[i
];