// //--------------------------------------------------------------------------- // // Copyright (c) 2018-2022 Marisa Kirisame, UnSX Team // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. // //-------------------------------------------------------------------------- // #include "filesystem.h" #include "cmdlib.h" #include "model_ue1.h" #include "texturemanager.h" #include "modelrenderer.h" float unpackuvert( uint32_t n, int c ) { switch( c ) { case 0: return ((int16_t)((n&0x7ff)<<5))/128.f; case 1: return ((int16_t)(((n>>11)&0x7ff)<<5))/128.f; case 2: return ((int16_t)(((n>>22)&0x3ff)<<6))/128.f; default: return 0.f; } } bool FUE1Model::Load( const char *filename, int lumpnum, const char *buffer, int length ) { int lumpnum2; hasSurfaces = true; FString realfilename = fileSystem.GetFileFullName(lumpnum); if ( (size_t)realfilename.IndexOf("_d.3d") == realfilename.Len()-5 ) { realfilename.Substitute("_d.3d","_a.3d"); lumpnum2 = fileSystem.CheckNumForFullName(realfilename.GetChars()); mDataLump = lumpnum; mAnivLump = lumpnum2; } else { realfilename.Substitute("_a.3d","_d.3d"); lumpnum2 = fileSystem.CheckNumForFullName(realfilename.GetChars()); mAnivLump = lumpnum; mDataLump = lumpnum2; } return true; } void FUE1Model::LoadGeometry() { const char *buffer, *buffer2; auto lump = fileSystem.ReadFile(mDataLump); buffer = lump.GetString(); auto lump2 = fileSystem.ReadFile(mAnivLump); buffer2 = lump2.GetString(); // map structures dhead = (const d3dhead*)(buffer); dpolys = (const d3dpoly*)(buffer+sizeof(d3dhead)); ahead = (const a3dhead*)(buffer2); // detect deus ex format if ( (ahead->framesize/dhead->numverts) == 8 ) { averts = nullptr; dxverts = (const dxvert*)(buffer2+sizeof(a3dhead)); } else { averts = (const uint32_t*)(buffer2+sizeof(a3dhead)); dxverts = nullptr; } // set counters numVerts = dhead->numverts; numFrames = ahead->numframes; numPolys = dhead->numpolys; numGroups = 0; // populate vertex arrays for ( int i=0; i= numFrames) return FErr_NotFound; return index; } void FUE1Model::RenderFrame( FModelRenderer *renderer, FGameTexture *skin, int frame, int frame2, double inter, int translation, const FTextureID* surfaceskinids, const TArray& boneData, int boneStartPosition) { // the moment of magic if ( (frame < 0) || (frame2 < 0) || (frame >= numFrames) || (frame2 >= numFrames) ) return; renderer->SetInterpolation(inter); int vsize, fsize = 0, vofs = 0; for ( int i=0; iSetMaterial(sskin,false,translation); renderer->SetupFrame(this, vofs + frame * fsize, vofs + frame2 * fsize, vsize, {}, -1); renderer->DrawArrays(0,vsize); vofs += vsize; } renderer->SetInterpolation(0.f); } void FUE1Model::BuildVertexBuffer( FModelRenderer *renderer ) { if (GetVertexBuffer(renderer->GetType())) return; LoadGeometry(); int vsize = 0; for ( int i=0; iCreateVertexBuffer(false,numFrames==1); SetVertexBuffer(renderer->GetType(), vbuf); FModelVertex *vptr = vbuf->LockVertexBuffer(vsize); int vidx = 0; for ( int i=0; iSet(V.Pos.X,V.Pos.Y,V.Pos.Z,C.X,C.Y); if ( groups[j].type&PT_Curvy ) // use facet normal { vert->SetNormal(polys[groups[j].P[k]].Normals[i].X, polys[groups[j].P[k]].Normals[i].Y, polys[groups[j].P[k]].Normals[i].Z); } else vert->SetNormal(V.Normal.X,V.Normal.Y,V.Normal.Z); } } } } vbuf->UnlockVertexBuffer(); UnloadGeometry(); // don't forget this, save precious RAM } void FUE1Model::AddSkins( uint8_t *hitlist, const FTextureID* surfaceskinids) { for (int i = 0; i < numGroups; i++) { int ssIndex = groups[i].texNum; if (surfaceskinids && surfaceskinids[ssIndex].isValid()) hitlist[surfaceskinids[ssIndex].GetIndex()] |= FTextureManager::HIT_Flat; } } FUE1Model::~FUE1Model() { groups.Reset(); }