convert line ends
[canaan.git] / prj / cam / src / render / meshtex.cpp
blob1735c49a4c139da2bed07e6c938e42bb9a2187e8
1 /*
2 @Copyright Looking Glass Studios, Inc.
3 1996,1997,1998,1999,2000 Unpublished Work.
4 */
6 // $Header: r:/t2repos/thief2/src/render/meshtex.cpp,v 1.1 2000/01/14 10:40:19 MAT Exp $
8 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
9 meshtex.cpp
11 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
14 #include <2d.h>
15 #include <lgd3d.h>
16 #include <tmgr.h>
17 #include <mms.h>
18 #include <mm.h>
19 #include <resapi.h>
20 #include <storeapi.h>
21 #include <imgrstyp.h>
22 #include <palrstyp.h>
23 #include <dynarray.h>
25 #include <prophash.h>
26 #include <dataops.h>
27 #include <obprpimp.h>
28 #include <sdesbase.h>
29 #include <sdesc.h>
30 #include <objsys.h>
32 #include <command.h>
33 #include <palmgr.h>
34 #include <objmodel.h>
35 #include <crjoint.h>
36 #include <face.h>
38 #include <meshtex.h>
39 #include <dbmem.h>
40 #include <initguid.h>
41 #include <meshtexg.h>
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
46 // regular ones.
47 EXTERN ISearchPath *MeshModelTexturesPath;
50 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
52 predeclarations
54 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
56 struct sMeshTexRemap;
59 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
61 constants
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 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
74 globals
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;
83 struct sResTexture
85 char m_aszName[16];
86 IRes *m_pRes;
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];
94 // other
95 static IResMan *g_pResMan;
98 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
100 our property
102 We have a horrible little struct which holds the parts of the mesh
103 model which we swap in on-the-fly.
105 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
107 struct sTexture
109 char m_aszDefault[16];
110 char m_aszCustom[16];
113 struct sTextureSubst
115 int m_iMaterialIndex; // within mms_model, that is
116 grs_bitmap *m_pBitmap;
120 ///////////////////////////////////////////////
121 // the structure used for the property
123 struct sMeshTexRemap
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));
132 m_bSet = FALSE;
134 return *this;
138 // data
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
152 #undef INTERFACE
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
165 "MeshTex",
166 0, // flags
167 NULL, // constraints
168 1, 0, // version
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
187 public:
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));
201 } else {
202 pRemap->m_TextureSubst.SetSize(0);
204 pRemap->m_bSet = FALSE;
208 STANDARD_DESCRIBE_TYPE(cMeshTexProperty);
210 protected:
211 void CreateEditor();
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 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
294 helpers
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])
306 continue;
308 int iMat;
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))
314 break;
316 #ifndef SHIP
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)));
321 break;
323 #endif // ~SHIP
325 sTextureSubst Subst;
326 Subst.m_iMaterialIndex = iMat;
327 Subst.m_pBitmap=MeshTexGetBitmap(pRemap->m_Texture[iTexSub].m_aszCustom);
329 #ifndef SHIP
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)));
334 break;
336 #endif // ~SHIP
338 pRemap->m_TextureSubst.Append(Subst);
341 pRemap->m_bSet = TRUE;
345 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
347 commands
349 \* --<<= -+-\-\-\=\=\/\- <<< ((( ((( \ / ))) ))) >>> -/\/=/=/-/-/-+- =>>-- */
351 #ifdef EDITOR
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},
364 #endif // EDITOR
367 /* --<<= -+-/-/-/=/=/\/- <<< ((( ((( / \ ))) ))) >>> -\/\=\=\-\-\-+- =>>-- *\
369 exposed functions
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)
377 strlwr(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);
385 if (!pRes)
386 return 0;
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);
396 if (pPallRes) {
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);
402 if (b != pbm->align)
403 if ((g_tmgr != NULL) && (pbm->flags & BMF_LOADED)) {
404 lgd3d_unload_texture(pbm);
405 lgd3d_load_texture(pbm);
408 pRes->Unlock();
409 pPallRes->Unlock();
410 // We're done with the palette; the palette manager will now
411 // take charge of it. So we can drop it from memory.
412 pPallRes->Drop();
413 pPallRes->Release();
416 pCanonStore->Release();
418 sResTexture NewPair;
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;
428 void MeshTexInit()
430 g_pMeshTexProperty = new cMeshTexProperty(&g_MeshTexDesc);
431 g_pResMan = AppGetObj(IResMan);
432 FaceInit();
434 #ifdef EDITOR
435 COMMANDS(g_aCommands, HK_ALL);
436 #endif // EDITOR
440 void MeshTexTerm()
442 FaceTerm();
446 void MeshTexReset()
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);
453 FaceReset();
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)) {
464 g_pCurrentModel = 0;
465 return;
468 g_pCurrentModel = pModel;
469 g_CurrentObj = Obj;
470 g_pCurrentRemap = pRemap;
472 if (!pRemap->m_bSet)
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)
496 return;
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];
506 FacePostrender();