const char *appSymbolName(address_t addr) { static char buf[256]; #if USE_DBGHELP if (appSymbolName(addr, ARRAY_ARG(buf))) return buf; #endif #if GET_EXTENDED_INFO HMODULE hModule = NULL; char moduleName[256]; char *s; MEMORY_BASIC_INFORMATION mbi; if (!VirtualQuery((void*)addr, &mbi, sizeof(mbi))) goto simple; if (!(hModule = (HMODULE)mbi.AllocationBase)) goto simple; if (!GetModuleFileName(hModule, ARRAY_ARG(moduleName))) goto simple; // if (s = strrchr(moduleName, '.')) // cut extension // *s = 0; if (s = strrchr(moduleName, '\\')) strcpy(moduleName, s+1); // remove "path\" part appSprintf(ARRAY_ARG(buf), "%s+0x%X", moduleName, (int)(addr - (size_t)hModule)); return buf; #endif // GET_EXTENDED_INFO simple: appSprintf(ARRAY_ARG(buf), "%08X", addr); return buf; }
/* =============== SV_StatusString Builds the string that is sent as heartbeats and status replies =============== */ static const char *SV_StatusString() { guard(SV_StatusString); static char status[MAX_MSGLEN - 16]; if (sv.attractloop) return ""; int statusLength = appSprintf(ARRAY_ARG(status), "%s\n", Cvar_BitInfo(CVAR_SERVERINFO)); for (int i = 0; i < sv_maxclients->integer; i++) { client_t *cl = &svs.clients[i]; if (cl->state == cs_connected || cl->state == cs_spawned) { char player[256]; int playerLength = appSprintf(ARRAY_ARG(player), "%d %d \"%s\"\n", cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, *cl->Name); if (statusLength + playerLength >= sizeof(status)) break; // can't hold any more memcpy(status + statusLength, player, playerLength+1); statusLength += playerLength; } } return status; unguard; }
static bool ScanGameDirectory(const char *dir, bool recurse) { guard(ScanGameDirectory); char Path[MAX_PACKAGE_PATH]; bool res = true; // printf("Scan %s\n", dir); #if _WIN32 appSprintf(ARRAY_ARG(Path), "%s/*.*", dir); _finddatai64_t found; long hFind = _findfirsti64(Path, &found); if (hFind == -1) return true; do { if (found.name[0] == '.') continue; // "." or ".." appSprintf(ARRAY_ARG(Path), "%s/%s", dir, found.name); // directory -> recurse if (found.attrib & _A_SUBDIR) { if (recurse) res = ScanGameDirectory(Path, recurse); else res = true; } else res = RegisterGameFile(Path); } while (res && _findnexti64(hFind, &found) != -1); _findclose(hFind); #else DIR *find = opendir(dir); if (!find) return true; struct dirent *ent; while (/*res &&*/ (ent = readdir(find))) { if (ent->d_name[0] == '.') continue; // "." or ".." appSprintf(ARRAY_ARG(Path), "%s/%s", dir, ent->d_name); // directory -> recurse // note: using 'stat64' here because 'stat' ignores large files struct stat64 buf; if (stat64(Path, &buf) < 0) continue; // or break? if (S_ISDIR(buf.st_mode)) { if (recurse) res = ScanGameDirectory(Path, recurse); else res = true; } else res = RegisterGameFile(Path); } closedir(find); #endif return res; unguard; }
void appUnwindPrefix(const char *fmt) { char buf[512]; appSprintf(ARRAY_ARG(buf), WasError ? " <- %s:" : "%s:", fmt); LogHistory(buf); WasError = false; }
/** Preprocesses a shader without performing compilation, and dump it out for debugging*/ void D3D9PreProcessShader( const TCHAR* strFilename, const FString& strShaderFile, vector<D3DXMACRO>& Defines, const FD3DIncludeEnvironment& Environment, const TCHAR* strShaderPath ) { TRefCountPtr<ID3DXBuffer> ShaderCode; TRefCountPtr<ID3DXBuffer> ErrorText; FTCHARToANSI AnsiShaderFile(strShaderFile.c_str()); FD3DIncludeEnvironment IncludeEnvironment(Environment); HRESULT ret = D3DXPreprocessShader( (ANSICHAR*)AnsiShaderFile, strShaderFile.size(), &Defines.at(0), &IncludeEnvironment, ShaderCode.GetInitReference(), ErrorText.GetInitReference() ); if( FAILED(ret) ) { debugf(NAME_Warning, TEXT("Preprocess failed for shader %s: %s"), strFilename, ANSI_TO_TCHAR(ErrorText->GetBufferPointer())); } else { TCHAR Tmp[MAX_SPRINTF]; appSprintf(Tmp, TEXT("%s%s.pre"), strShaderPath, strFilename); appSaveStringToFile(ANSI_TO_TCHAR(ShaderCode->GetBufferPointer()), Tmp); } }
bool UIProgressDialog::Tick() { char buffer[64]; appSprintf(ARRAY_ARG(buffer), "%d MBytes", (int)(GTotalAllocationSize >> 20)); MemoryLabel->SetText(buffer); appSprintf(ARRAY_ARG(buffer), "%d", UObject::GObjObjects.Num()); ObjectsLabel->SetText(buffer); return PumpMessages(); }
bool appSymbolName(address_t addr, char *buffer, int size) { InitSymbols(); char SymBuffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)SymBuffer; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; DWORD64 dwDisplacement = 0; if (SymFromAddr(hProcess, addr, &dwDisplacement, pSymbol)) { char OffsetBuffer[32]; if (dwDisplacement) appSprintf(ARRAY_ARG(OffsetBuffer), "+%X", dwDisplacement); else OffsetBuffer[0] = 0; #if EXTRA_UNDECORATE char undecBuffer[256]; if (UnDecorateSymbolName(pSymbol->Name, ARRAY_ARG(undecBuffer), UNDNAME_NO_LEADING_UNDERSCORES|UNDNAME_NO_LEADING_UNDERSCORES|UNDNAME_NO_ALLOCATION_LANGUAGE|UNDNAME_NO_ACCESS_SPECIFIERS)) { StripPrefix(undecBuffer, "virtual "); StripPrefix(undecBuffer, "class "); StripPrefix(undecBuffer, "struct "); appSprintf(buffer, size, "%s%s", undecBuffer, OffsetBuffer); } else { appSprintf(buffer, size, "%s%s", pSymbol->Name, OffsetBuffer); } #else appSprintf(buffer, size, "%s%s", pSymbol->Name, OffsetBuffer); #endif // EXTRA_UNDECORATE } else { appSprintf(buffer, size, "%08X", addr); } return true; }
const char* GetGameTag(int gameEnum) { static char buf[64]; int Count = ARRAY_COUNT(GListOfGames) - 1; // exclude TABLE_END marker const char* value = NULL; for (int i = 0; i < Count; i++) { if (GListOfGames[i].Enum == gameEnum) { value = GListOfGames[i].Switch; break; } } #if UNREAL4 if (!value && gameEnum >= GAME_UE4_BASE) { // generate tag int ue4ver = GAME_UE4_GET_MINOR(gameEnum); if (gameEnum == GAME_UE4(ue4ver)) { // exactly matching, i.e. not a custom UE4 version appSprintf(ARRAY_ARG(buf), "ue4.%d", ue4ver); return buf; } } #endif // UNREAL4 if (!value) { appSprintf(ARRAY_ARG(buf), "%X", gameEnum); return buf; } return value; }
FArchive *appCreateFileReader(const CGameFileInfo *info) { if (!info->FileSystem) { // regular file char buf[MAX_PACKAGE_PATH]; appSprintf(ARRAY_ARG(buf), "%s/%s", RootDirectory, info->RelativeName); return new FFileReader(buf); } else { // file from virtual file system return info->FileSystem->CreateReader(info->RelativeName); } }
UBOOL VGameViewportClient::Init(FString& OutError) { InitStaticData(); TCHAR Error[MAX_SPRINTF] = TEXT(""); // add console interaction _Console = ExactCast<VConsole>(VObject::StaticConstructObject(VObject::LoadClass(FName(_ConsoleClassName)))); if( _Console == NULL ) { appSprintf(Error, TEXT("Failed to create console system, in that illegal console class name(%s)"), _ConsoleClassName); OutError = Error; return FALSE; } if( InsertInteraction(_Console.GetReference()) == -1 ) { appSprintf(Error, TEXT("Faile to add interaction to global interaction array")); OutError = Error; return FALSE; } // add ui interaction _UIInteraction = ExactCast<VUIInteraction>(VObject::StaticConstructObject(VObject::LoadClass(FName(_UIInteractionClassName)))); if( _UIInteraction == NULL ) { appSprintf(Error, TEXT("Failed to create ui interaction system, in that illegal ui interaction class name(%s)"), _ConsoleClassName); OutError = Error; return FALSE; } if( InsertInteraction(_UIInteraction.GetReference()) == -1 ) { appSprintf(Error, TEXT("Faile to add interaction to global interaction array")); OutError = Error; return FALSE; } // add player interaction _PlayerInteraction = ExactCast<VPlayerInteraction>(VObject::StaticConstructObject(VObject::LoadClass(FName(_PlayerInteractionClassName)))); if( _PlayerInteraction == NULL ) { appSprintf(Error, TEXT("Failed to create player interaction system, in that illegal player interaction class name(%s)"), _PlayerInteractionClassName); OutError = Error; return FALSE; } if( InsertInteraction(_PlayerInteraction.GetReference()) == -1 ) { appSprintf(Error, TEXT("Faile to add interaction to global interaction array")); OutError = Error; return FALSE; } return TRUE; }
bool UIProgressDialog::Progress(const char* package, int index, int total) { // do not update UI too often int tick = appMilliseconds(); if (tick - lastTick < 50) return true; lastTick = tick; char buffer[512]; appSprintf(ARRAY_ARG(buffer), "%s %d/%d", DescriptionText, index+1, total); DescriptionLabel->SetText(buffer); PackageLabel->SetText(package); ProgressBar->SetValue((float)(index+1) / total); return Tick(); }
static void ExportMaterial(UUnrealMaterial* Mat, FArchive& Ar, int index, bool bLast) { char dummyName[64]; appSprintf(ARRAY_ARG(dummyName), "dummy_material_%d", index); CVec3 Color = GetMaterialDebugColor(index); Ar.Printf( " {\n" " \"name\" : \"%s\",\n" " \"pbrMetallicRoughness\" : {\n" " \"baseColorFactor\" : [ %g, %g, %g, 1.0 ],\n" " \"metallicFactor\" : 0.1,\n" " \"roughnessFactor\" : 0.5\n" " }\n" " }%s\n", Mat ? Mat->Name : dummyName, Color[0], Color[1], Color[2], bLast ? "" : "," ); }
static void ExportAnimations(ExportContext& Context, FArchive& Ar) { guard(ExportAnimations); const CAnimSet* Anim = Context.SkelMesh->Anim; int NumBones = Context.SkelMesh->RefSkeleton.Num(); // Build mesh to anim bone map TArray<int> BoneMap; BoneMap.Init(-1, NumBones); TArray<int> AnimBones; AnimBones.Empty(NumBones); for (int i = 0; i < NumBones; i++) { const CSkelMeshBone &B = Context.SkelMesh->RefSkeleton[i]; for (int j = 0; j < Anim->TrackBoneNames.Num(); j++) { if (!stricmp(B.Name, Anim->TrackBoneNames[j])) { BoneMap[i] = j; // lookup CAnimSet bone by mesh bone index AnimBones.Add(i); // indicate that the bone has animation break; } } } Ar.Printf( " \"animations\" : [\n" ); int FirstDataIndex = Context.Data.Num(); // Iterate over all animations for (int SeqIndex = 0; SeqIndex < Anim->Sequences.Num(); SeqIndex++) { const CAnimSequence &Seq = *Anim->Sequences[SeqIndex]; Ar.Printf( " {\n" " \"name\" : \"%s\",\n", *Seq.Name ); struct AnimSampler { enum ChannelType { TRANSLATION, ROTATION }; int BoneNodeIndex; ChannelType Type; const CAnimTrack* Track; }; TArray<AnimSampler> Samplers; Samplers.Empty(AnimBones.Num() * 2); //!! Optimization: //!! 1. there will be missing tracks (AnimRotationOnly etc) - drop such samplers //!! 2. store all time tracks in a single BufferView, all rotation tracks in another, and all position track in 3rd one - this //!! will reduce amount of BufferViews in json text (combine them by data type) // Prepare channels array Ar.Printf(" \"channels\" : [\n"); for (int BoneIndex = 0; BoneIndex < AnimBones.Num(); BoneIndex++) { int MeshBoneIndex = AnimBones[BoneIndex]; int AnimBoneIndex = BoneMap[MeshBoneIndex]; const CAnimTrack* Track = Seq.Tracks[AnimBoneIndex]; int TranslationSamplerIndex = Samplers.Num(); AnimSampler* Sampler = new (Samplers) AnimSampler; Sampler->Type = AnimSampler::TRANSLATION; Sampler->BoneNodeIndex = MeshBoneIndex + FIRST_BONE_NODE; Sampler->Track = Track; int RotationSamplerIndex = Samplers.Num(); Sampler = new (Samplers) AnimSampler; Sampler->Type = AnimSampler::ROTATION; Sampler->BoneNodeIndex = MeshBoneIndex + FIRST_BONE_NODE; Sampler->Track = Track; // Print glTF information. Not using usual formatting here to make output a little bit more compact. Ar.Printf( " { \"sampler\" : %d, \"target\" : { \"node\" : %d, \"path\" : \"%s\" } },\n", TranslationSamplerIndex, MeshBoneIndex + FIRST_BONE_NODE, "translation" ); Ar.Printf( " { \"sampler\" : %d, \"target\" : { \"node\" : %d, \"path\" : \"%s\" } }%s\n", RotationSamplerIndex, MeshBoneIndex + FIRST_BONE_NODE, "rotation", BoneIndex == AnimBones.Num()-1 ? "" : "," ); } Ar.Printf(" ],\n"); // Prepare samplers Ar.Printf(" \"samplers\" : [\n"); for (int SamplerIndex = 0; SamplerIndex < Samplers.Num(); SamplerIndex++) { const AnimSampler& Sampler = Samplers[SamplerIndex]; // Prepare time array const TArray<float>* TimeArray = (Sampler.Type == AnimSampler::TRANSLATION) ? &Sampler.Track->KeyPosTime : &Sampler.Track->KeyQuatTime; if (TimeArray->Num() == 0) { // For this situation, use track's time array TimeArray = &Sampler.Track->KeyTime; } int NumKeys = Sampler.Type == (AnimSampler::TRANSLATION) ? Sampler.Track->KeyPos.Num() : Sampler.Track->KeyQuat.Num(); int TimeBufIndex = Context.Data.AddZeroed(); BufferData& TimeBuf = Context.Data[TimeBufIndex]; TimeBuf.Setup(NumKeys, "SCALAR", BufferData::FLOAT, sizeof(float)); float RateScale = 1.0f / Seq.Rate; float LastFrameTime = 0; if (TimeArray->Num() == 0 || NumKeys == 1) { // Fill with equally spaced values for (int i = 0; i < NumKeys; i++) { TimeBuf.Put(i * RateScale); } LastFrameTime = NumKeys-1; } else { for (int i = 0; i < TimeArray->Num(); i++) { TimeBuf.Put((*TimeArray)[i] * RateScale); } LastFrameTime = (*TimeArray)[TimeArray->Num()-1]; } // Prepare min/max values for time track, it's required by glTF standard TimeBuf.BoundsMin = "[ 0 ]"; char buf[64]; appSprintf(ARRAY_ARG(buf), "[ %g ]", LastFrameTime * RateScale); TimeBuf.BoundsMax = buf; // Try to reuse TimeBuf from previous tracks TimeBufIndex = Context.GetFinalIndexForLastBlock(FirstDataIndex); // Prepare data int DataBufIndex = Context.Data.AddZeroed(); BufferData& DataBuf = Context.Data[DataBufIndex]; if (Sampler.Type == AnimSampler::TRANSLATION) { // Translation track DataBuf.Setup(NumKeys, "VEC3", BufferData::FLOAT, sizeof(CVec3)); for (int i = 0; i < NumKeys; i++) { CVec3 Pos = Sampler.Track->KeyPos[i]; TransformPosition(Pos); DataBuf.Put(Pos); } } else { // Rotation track DataBuf.Setup(NumKeys, "VEC4", BufferData::FLOAT, sizeof(CQuat)); for (int i = 0; i < NumKeys; i++) { CQuat Rot = Sampler.Track->KeyQuat[i]; TransformRotation(Rot); if (Sampler.BoneNodeIndex - FIRST_BONE_NODE == 0) { Rot.Conjugate(); } DataBuf.Put(Rot); } } // Try to reuse data block as well DataBufIndex = Context.GetFinalIndexForLastBlock(FirstDataIndex); // Write glTF info Ar.Printf( " { \"input\" : %d, \"output\" : %d }%s\n", TimeBufIndex, DataBufIndex, SamplerIndex == Samplers.Num()-1 ? "" : "," ); } Ar.Printf(" ]\n"); Ar.Printf(" }%s\n", SeqIndex == Anim->Sequences.Num()-1 ? "" : ","); } Ar.Printf(" ],\n"); unguard; }
static void ExportSection(ExportContext& Context, const CBaseMeshLod& Lod, const CMeshVertex* Verts, int SectonIndex, FArchive& Ar) { guard(ExportSection); int VertexSize = Context.IsSkeletal() ? sizeof(CSkelMeshVertex) : sizeof(CStaticMeshVertex); const CMeshSection& S = Lod.Sections[SectonIndex]; bool bLast = (SectonIndex == Lod.Sections.Num()-1); // Remap section indices to local indices CIndexBuffer::IndexAccessor_t GetIndex = Lod.Indices.GetAccessor(); TArray<int> indexRemap; // old vertex index -> new vertex index indexRemap.Init(-1, Lod.NumVerts); int numLocalVerts = 0; int numLocalIndices = S.NumFaces * 3; for (int idx = 0; idx < numLocalIndices; idx++) { int vertIndex = GetIndex(S.FirstIndex + idx); if (indexRemap[vertIndex] == -1) { indexRemap[vertIndex] = numLocalVerts++; } } // Prepare buffers int IndexBufIndex = Context.Data.AddZeroed(); int PositionBufIndex = Context.Data.AddZeroed(); int NormalBufIndex = Context.Data.AddZeroed(); int TangentBufIndex = Context.Data.AddZeroed(); int BonesBufIndex = -1; int WeightsBufIndex = -1; if (Context.IsSkeletal()) { BonesBufIndex = Context.Data.AddZeroed(); WeightsBufIndex = Context.Data.AddZeroed(); } int UVBufIndex[MAX_MESH_UV_SETS]; for (int i = 0; i < Lod.NumTexCoords; i++) { UVBufIndex[i] = Context.Data.AddZeroed(); } BufferData& IndexBuf = Context.Data[IndexBufIndex]; BufferData& PositionBuf = Context.Data[PositionBufIndex]; BufferData& NormalBuf = Context.Data[NormalBufIndex]; BufferData& TangentBuf = Context.Data[TangentBufIndex]; BufferData* UVBuf[MAX_MESH_UV_SETS]; BufferData* BonesBuf = NULL; BufferData* WeightsBuf = NULL; PositionBuf.Setup(numLocalVerts, "VEC3", BufferData::FLOAT, sizeof(CVec3)); NormalBuf.Setup(numLocalVerts, "VEC3", BufferData::FLOAT, sizeof(CVec3)); TangentBuf.Setup(numLocalVerts, "VEC4", BufferData::FLOAT, sizeof(CVec4)); for (int i = 0; i < Lod.NumTexCoords; i++) { UVBuf[i] = &Context.Data[UVBufIndex[i]]; UVBuf[i]->Setup(numLocalVerts, "VEC2", BufferData::FLOAT, sizeof(CMeshUVFloat)); } if (Context.IsSkeletal()) { BonesBuf = &Context.Data[BonesBufIndex]; WeightsBuf = &Context.Data[WeightsBufIndex]; BonesBuf->Setup(numLocalVerts, "VEC4", BufferData::UNSIGNED_SHORT, sizeof(uint16)*4); WeightsBuf->Setup(numLocalVerts, "VEC4", BufferData::UNSIGNED_BYTE, sizeof(uint32), /*InNormalized=*/ true); } // Prepare and build indices TArray<int> localIndices; localIndices.AddUninitialized(numLocalIndices); int* pIndex = localIndices.GetData(); for (int i = 0; i < numLocalIndices; i++) { *pIndex++ = GetIndex(S.FirstIndex + i); } if (numLocalVerts <= 65536) { IndexBuf.Setup(numLocalIndices, "SCALAR", BufferData::UNSIGNED_SHORT, sizeof(uint16)); for (int idx = 0; idx < numLocalIndices; idx++) { IndexBuf.Put<uint16>(indexRemap[localIndices[idx]]); } } else { IndexBuf.Setup(numLocalIndices, "SCALAR", BufferData::UNSIGNED_INT, sizeof(uint32)); for (int idx = 0; idx < numLocalIndices; idx++) { IndexBuf.Put<uint32>(indexRemap[localIndices[idx]]); } } // Build reverse index map for fast lookup of vertex by its new index. // It maps new vertex index to old vertex index. TArray<int> revIndexMap; revIndexMap.AddUninitialized(numLocalVerts); for (int i = 0; i < indexRemap.Num(); i++) { int newIndex = indexRemap[i]; if (newIndex != -1) { revIndexMap[newIndex] = i; } } // Build vertices for (int i = 0; i < numLocalVerts; i++) { int vertIndex = revIndexMap[i]; const CMeshVertex& V = VERT(vertIndex); CVec3 Position = V.Position; CVec4 Normal, Tangent; Unpack(Normal, V.Normal); Unpack(Tangent, V.Tangent); // Unreal (and we are) using normal.w for computing binormal. glTF // uses tangent.w for that. Make this value exactly 1.0 of -1.0 to make glTF // validator happy. #if 0 // There's some problem: V.Normal.W == 0x80 -> -1.008 instead of -1.0 if (Normal.w > 1.001 || Normal.w < -1.001) { appError("%X -> %g\n", V.Normal.Data, Normal.w); } #endif Tangent.w = (Normal.w < 0) ? -1 : 1; TransformPosition(Position); TransformDirection(Normal); TransformDirection(Tangent); Normal.Normalize(); Tangent.Normalize(); // Fill buffers PositionBuf.Put(Position); NormalBuf.Put(Normal.xyz); TangentBuf.Put(Tangent); UVBuf[0]->Put(V.UV); } // Compute bounds for PositionBuf CVec3 Mins, Maxs; ComputeBounds((CVec3*)PositionBuf.Data, numLocalVerts, sizeof(CVec3), Mins, Maxs); char buf[256]; appSprintf(ARRAY_ARG(buf), "[ %g, %g, %g ]", VECTOR_ARG(Mins)); PositionBuf.BoundsMin = buf; appSprintf(ARRAY_ARG(buf), "[ %g, %g, %g ]", VECTOR_ARG(Maxs)); PositionBuf.BoundsMax = buf; if (Context.IsSkeletal()) { for (int i = 0; i < numLocalVerts; i++) { int vertIndex = revIndexMap[i]; const CMeshVertex& V0 = VERT(vertIndex); const CSkelMeshVertex& V = static_cast<const CSkelMeshVertex&>(V0); int16 Bones[NUM_INFLUENCES]; static_assert(NUM_INFLUENCES == 4, "Code designed for 4 influences"); static_assert(sizeof(Bones) == sizeof(V.Bone), "Unexpected V.Bones size"); memcpy(Bones, V.Bone, sizeof(Bones)); for (int j = 0; j < NUM_INFLUENCES; j++) { // We have INDEX_NONE as list terminator, should replace with something else for glTF if (Bones[j] == INDEX_NONE) { Bones[j] = 0; } } BonesBuf->Put(*(uint64*)&Bones); WeightsBuf->Put(V.PackedWeights); } } // Secondary UVs for (int uvIndex = 1; uvIndex < Lod.NumTexCoords; uvIndex++) { BufferData* pBuf = UVBuf[uvIndex]; const CMeshUVFloat* srcUV = Lod.ExtraUV[uvIndex-1]; for (int i = 0; i < numLocalVerts; i++) { int vertIndex = revIndexMap[i]; pBuf->Put(srcUV[vertIndex]); } } // Write primitive information to json Ar.Printf( " {\n" " \"attributes\" : {\n" " \"POSITION\" : %d,\n" " \"NORMAL\" : %d,\n" " \"TANGENT\" : %d,\n", PositionBufIndex, NormalBufIndex, TangentBufIndex ); if (Context.IsSkeletal()) { Ar.Printf( " \"JOINTS_0\" : %d,\n" " \"WEIGHTS_0\" : %d,\n", BonesBufIndex, WeightsBufIndex ); } for (int i = 0; i < Lod.NumTexCoords; i++) { Ar.Printf( " \"TEXCOORD_%d\" : %d%s\n", i, UVBufIndex[i], i < (Lod.NumTexCoords-1) ? "," : "" ); } Ar.Printf( " },\n" " \"indices\" : %d,\n" " \"material\" : %d\n" " }%s\n", IndexBufIndex, SectonIndex, SectonIndex < (Lod.Sections.Num()-1) ? "," : "" ); unguard; }
void USkelModel::Serialize(FArchive &Ar) { guard(USkelModel::Serialize); assert(Ar.IsLoading); // no saving ... Super::Serialize(Ar); // USkelModel data int nummeshes; int numjoints; int numframes; int numsequences; int numskins; int rootjoint; FVector PosOffset; // Offset of creature relative to base FRotator RotOffset; // Offset of creatures rotation TArray<RMesh> meshes; TArray<RJoint> joints; TArray<FRSkelAnimSeq> AnimSeqs; // Compressed animation data for sequence TArray<RAnimFrame> frames; Ar << nummeshes << numjoints << numframes << numsequences << numskins << rootjoint; Ar << meshes << joints << AnimSeqs << frames << PosOffset << RotOffset; int modelIdx; // create all meshes first, then fill them (for better view order) for (modelIdx = 0; modelIdx < meshes.Num(); modelIdx++) { // create new USkeletalMesh // use "CreateClass()" instead of "new USkeletalMesh" to allow this object to be // placed in GObjObjects array and be browsable in a viewer USkeletalMesh *sm = static_cast<USkeletalMesh*>(CreateClass("SkeletalMesh")); char nameBuf[256]; appSprintf(ARRAY_ARG(nameBuf), "%s_%d", Name, modelIdx); const char *name = appStrdupPool(nameBuf); Meshes.Add(sm); // setup UOnject sm->Name = name; sm->Package = Package; sm->PackageIndex = INDEX_NONE; // not really exported sm->Outer = NULL; } // create animation Anim = static_cast<UMeshAnimation*>(CreateClass("MeshAnimation")); Anim->Name = Name; Anim->Package = Package; Anim->PackageIndex = INDEX_NONE; // not really exported Anim->Outer = NULL; ConvertRuneAnimations(*Anim, joints, AnimSeqs); Anim->ConvertAnims(); //?? second conversion // get baseframe assert(strcmp(Anim->AnimSeqs[0].Name, "baseframe") == 0); const TArray<AnalogTrack> &BaseAnim = Anim->Moves[0].AnimTracks; // compute bone coordinates TArray<CCoords> BoneCoords; BuildSkeleton(BoneCoords, joints, BaseAnim); // setup meshes for (modelIdx = 0; modelIdx < meshes.Num(); modelIdx++) { int i, j; const RMesh &src = meshes[modelIdx]; USkeletalMesh *sm = Meshes[modelIdx]; sm->Animation = Anim; // setup ULodMesh sm->RotOrigin = RotOffset; sm->MeshScale.Set(1, 1, 1); sm->MeshOrigin = PosOffset; // copy skeleton sm->RefSkeleton.Empty(joints.Num()); for (i = 0; i < joints.Num(); i++) { const RJoint &J = joints[i]; FMeshBone *B = new(sm->RefSkeleton) FMeshBone; B->Name = J.name; B->Flags = 0; B->ParentIndex = (J.parent > 0) ? J.parent : 0; // -1 -> 0 // copy bone orientations from base animation frame B->BonePos.Orientation = BaseAnim[i].KeyQuat[0]; B->BonePos.Position = BaseAnim[i].KeyPos[0]; } // copy vertices int VertexCount = sm->VertexCount = src.verts.Num(); sm->Points.Empty(VertexCount); for (i = 0; i < VertexCount; i++) { const RVertex &v1 = src.verts[i]; FVector *V = new(sm->Points) FVector; // transform point from local bone space to model space BoneCoords[v1.joint1].UnTransformPoint(CVT(v1.point1), CVT(*V)); } // copy triangles and create wedges // here we create 3 wedges for each triangle. // it is possible to reduce number of wedges by finding duplicates, but we don't // need it here ... int TrisCount = src.tris.Num(); sm->Triangles.Empty(TrisCount); sm->Wedges.Empty(TrisCount * 3); int numMaterials = 0; // should detect real material count for (i = 0; i < TrisCount; i++) { const RTriangle &tri = src.tris[i]; // create triangle VTriangle *T = new(sm->Triangles) VTriangle; T->MatIndex = tri.polygroup; if (numMaterials <= tri.polygroup) numMaterials = tri.polygroup+1; // create wedges for (j = 0; j < 3; j++) { T->WedgeIndex[j] = sm->Wedges.Num(); FMeshWedge *W = new(sm->Wedges) FMeshWedge; W->iVertex = tri.vIndex[j]; W->TexUV = tri.tex[j]; } // reverse order of triangle vertices Exchange(T->WedgeIndex[0], T->WedgeIndex[1]); } // build influences for (i = 0; i < VertexCount; i++) { const RVertex &v1 = src.verts[i]; FVertInfluence *Inf = new(sm->VertInfluences) FVertInfluence; Inf->PointIndex = i; Inf->BoneIndex = v1.joint1; Inf->Weight = v1.weight1; if (Inf->Weight != 1.0f) { // influence for 2nd bone Inf = new(sm->VertInfluences) FVertInfluence; Inf->PointIndex = i; Inf->BoneIndex = v1.joint2; Inf->Weight = 1.0f - v1.weight1; } } // create materials for (i = 0; i < numMaterials; i++) { const char *texName = src.PolyGroupSkinNames[i]; FMeshMaterial *M1 = new(sm->Materials) FMeshMaterial; M1->PolyFlags = src.GroupFlags[i]; M1->TextureIndex = sm->Textures.Num(); if (strcmp(texName, "None") == 0) { // texture should be set from script sm->Textures.Add(NULL); continue; } // find texture in object's package int texExportIdx = Package->FindExport(texName); if (texExportIdx == INDEX_NONE) { appPrintf("ERROR: unable to find export \"%s\" for mesh \"%s\" (%d)\n", texName, Name, modelIdx); continue; } // load and remember texture UMaterial *Tex = static_cast<UMaterial*>(Package->CreateExport(texExportIdx)); sm->Textures.Add(Tex); } // setup UPrimitive properties using 1st animation frame // note: this->BoundingBox and this->BoundingSphere are null const RAnimFrame &F = frames[0]; assert(strcmp(AnimSeqs[0].Name, "baseframe") == 0 && AnimSeqs[0].StartFrame == 0); CVec3 mins, maxs; sm->BoundingBox = F.bounds; mins = CVT(F.bounds.Min); maxs = CVT(F.bounds.Max); CVec3 ¢er = CVT(sm->BoundingSphere); for (i = 0; i < 3; i++) center[i] = (mins[i] + maxs[i]) / 2; sm->BoundingSphere.R = VectorDistance(center, mins); // create CSkeletalMesh sm->ConvertMesh(); } unguard; }
void LoadQ1BspFile() { guard(LoadQ1BspFile); dBsp1Hdr_t *header = (dBsp1Hdr_t *) bspfile.file; lumps = header->lumps; #if !LITTLE_ENDIAN // swap the header for (int i = 0; i < sizeof(dBsp1Hdr_t) / 4; i++) ((int *)bspfile.file)[i] = LittleLong(((int *)bspfile.file)[i]); #endif if (header->version == BSP1_VERSION) bspfile.type = map_q1; else bspfile.type = map_hl; Com_DPrintf("Loading %s bsp %s\n", bspfile.type == map_q1 ? "Q1" : "HL", *bspfile.Name); #define C(num,field,count,type) \ bspfile.count = CheckLump(dBsp1Hdr_t::LUMP_##num, (void**)&bspfile.field, sizeof(type)) C(LIGHTING, lighting, lightDataSize, byte); C(VERTEXES, vertexes2, numVertexes, CVec3); C(PLANES, planes2, numPlanes, dBsp2Plane_t); C(LEAFS, leafs1, numLeafs, dBsp1Leaf_t); C(NODES, nodes1, numNodes, dBsp1Node_t); C(TEXINFO, texinfo1, numTexinfo, dBsp1Texinfo_t); C(FACES, faces2, numFaces, dBspFace_t); C(MARKSURFACES, leaffaces2, numLeaffaces, unsigned short); C(SURFEDGES, surfedges, numSurfedges, int); C(EDGES, edges, numEdges, dEdge_t); C(MODELS, models1, numModels, dBsp1Model_t); // load miptex lump bspfile.miptex1 = (dBsp1MiptexLump_t*)(bspfile.file + lumps[dBsp1Hdr_t::LUMP_TEXTURES].fileofs); #if !LITTLE_ENDIAN //!! swap miptex1 lump #endif for (int miptex = 0; miptex < bspfile.miptex1->nummiptex; miptex++) { int offset = bspfile.miptex1->dataofs[miptex]; if (offset == -1) continue; dBsp1Miptex_t *tex = (dBsp1Miptex_t*)( (byte*)bspfile.miptex1 + offset ); // texture with data, but without name -- create default name if (!tex->name[0]) appSprintf(ARRAY_ARG(tex->name), "unnamed#%d", miptex); } #if !LITTLE_ENDIAN // swap everything SwapQ1BspFile(&bspfile); #endif ProcessQ1BspFile(&bspfile); // load visinfo byte *vis; int visDataSize = CheckLump(dBsp1Hdr_t::LUMP_VISIBILITY, (void**)&vis, 1); LoadQ1Vis(&bspfile, vis, visDataSize); // load entstring after all: we may require to change something char *entString = (char*)header + header->lumps[dBsp1Hdr_t::LUMP_ENTITIES].fileofs; bspfile.entStr = entString; #undef C unguard; }
// // Constructor. // UXViewport::UXViewport() : UViewport() , ViewportStatus( X_ViewportOpening ) { guard(UXViewport::UXViewport); // Open the display. XDisplay = XOpenDisplay(0); if (!XDisplay) appErrorf( TEXT("Can't open X server display. XViewport requires X windows.") ); // Create the default window. XSetWindowAttributes swa; swa.colormap = DefaultColormap(XDisplay, DefaultScreen(XDisplay)); swa.border_pixel = 0; swa.override_redirect = True; // swa.override_redirect = False; swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | ResizeRedirectMask | PointerMotionMask | FocusChangeMask; XWindow = XCreateWindow( XDisplay, DefaultRootWindow(XDisplay), 0, 0, 640, 480, 0, DefaultDepth(XDisplay, DefaultScreen(XDisplay)), InputOutput, DefaultVisual(XDisplay, DefaultScreen(XDisplay)), CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect, &swa ); TCHAR WindowName[80]; appSprintf( WindowName, TEXT("Unreal Tournament") ); XStoreName( XDisplay, XWindow, WindowName ); XMapWindow(XDisplay, XWindow); Mapped = True; // Set color bytes based on screen resolution. switch( DefaultDepth( XDisplay, 0 ) ) { case 8: ColorBytes = 2; break; case 16: ColorBytes = 2; Caps |= CC_RGB565; break; case 24: ColorBytes = 4; break; case 32: ColorBytes = 4; break; default: ColorBytes = 2; Caps |= CC_RGB565; break; } // Zero out Keysym map. for (INT i=0; i<65536; i++) KeysymMap[i] = 0; // Remap important keys. // TTY Functions. KeysymMap[XK_BackSpace] = IK_Backspace; KeysymMap[XK_Tab] = IK_Tab; KeysymMap[XK_Return] = IK_Enter; KeysymMap[XK_Pause] = IK_Pause; KeysymMap[XK_Escape] = IK_Escape; KeysymMap[XK_Delete] = IK_Delete; // Modifiers. KeysymMap[XK_Shift_L] = IK_LShift; KeysymMap[XK_Shift_R] = IK_RShift; KeysymMap[XK_Control_L] = IK_LControl; KeysymMap[XK_Control_R] = IK_RControl; KeysymMap[XK_Meta_L] = IK_Alt; KeysymMap[XK_Meta_R] = IK_Alt; KeysymMap[XK_Alt_L] = IK_Alt; KeysymMap[XK_Alt_R] = IK_Alt; // Special remaps. KeysymMap[XK_grave] = IK_Tilde; // Misc function keys. KeysymMap[XK_F1] = IK_F1; KeysymMap[XK_F2] = IK_F2; KeysymMap[XK_F3] = IK_F3; KeysymMap[XK_F4] = IK_F4; KeysymMap[XK_F5] = IK_F5; KeysymMap[XK_F6] = IK_F6; KeysymMap[XK_F7] = IK_F7; KeysymMap[XK_F8] = IK_F8; KeysymMap[XK_F9] = IK_F9; KeysymMap[XK_F10] = IK_F10; KeysymMap[XK_F11] = IK_F11; KeysymMap[XK_F12] = IK_F12; // Cursor control and motion. KeysymMap[XK_Home] = IK_Home; KeysymMap[XK_Left] = IK_Left; KeysymMap[XK_Up] = IK_Up; KeysymMap[XK_Right] = IK_Right; KeysymMap[XK_Down] = IK_Down; KeysymMap[XK_Page_Up] = IK_PageUp; KeysymMap[XK_Page_Down] = IK_PageDown; KeysymMap[XK_End] = IK_End; // Keypad functions and numbers. KeysymMap[XK_KP_Enter] = IK_Enter; KeysymMap[XK_KP_0] = IK_NumPad0; KeysymMap[XK_KP_1] = IK_NumPad1; KeysymMap[XK_KP_2] = IK_NumPad2; KeysymMap[XK_KP_3] = IK_NumPad3; KeysymMap[XK_KP_4] = IK_NumPad4; KeysymMap[XK_KP_5] = IK_NumPad5; KeysymMap[XK_KP_6] = IK_NumPad6; KeysymMap[XK_KP_7] = IK_NumPad7; KeysymMap[XK_KP_8] = IK_NumPad8; KeysymMap[XK_KP_9] = IK_NumPad9; KeysymMap[XK_KP_Multiply] = IK_GreyStar; KeysymMap[XK_KP_Add] = IK_GreyPlus; KeysymMap[XK_KP_Separator] = IK_Separator; KeysymMap[XK_KP_Subtract] = IK_GreyMinus; KeysymMap[XK_KP_Decimal] = IK_NumPadPeriod; KeysymMap[XK_KP_Divide] = IK_GreySlash; // Other KeysymMap[XK_minus] = IK_Minus; KeysymMap[XK_equal] = IK_Equals; // Zero out ShiftMask map. for (i=0; i<256; i++) ShiftMaskMap[i] = 0; // ShiftMask map. ShiftMaskMap['1'] = '!'; ShiftMaskMap['2'] = '@'; ShiftMaskMap['3'] = '#'; ShiftMaskMap['4'] = '$'; ShiftMaskMap['5'] = '%'; ShiftMaskMap['6'] = '^'; ShiftMaskMap['7'] = '&'; ShiftMaskMap['8'] = '*'; ShiftMaskMap['9'] = '('; ShiftMaskMap['0'] = ')'; ShiftMaskMap['-'] = '_'; ShiftMaskMap['='] = '+'; ShiftMaskMap['['] = '{'; ShiftMaskMap[']'] = '}'; ShiftMaskMap['\\'] = '|'; ShiftMaskMap[';'] = ':'; ShiftMaskMap['\''] = '\"'; ShiftMaskMap[','] = '<'; ShiftMaskMap['.'] = '>'; ShiftMaskMap['/'] = '?'; // WM_CHAR allowables. for (i=0; i<256; i++) WMCharMap[i] = 0; for (i='A'; i<='Z'; i++) WMCharMap[i] = 1; for (i='a'; i<='z'; i++) WMCharMap[i] = 1; WMCharMap[IK_Backspace] = 1; WMCharMap[IK_Space] = 1; WMCharMap[IK_Tab] = 1; WMCharMap[IK_Enter] = 1; WMCharMap['1'] = 1; WMCharMap['2'] = 1; WMCharMap['3'] = 1; WMCharMap['4'] = 1; WMCharMap['5'] = 1; WMCharMap['6'] = 1; WMCharMap['7'] = 1; WMCharMap['8'] = 1; WMCharMap['9'] = 1; WMCharMap['0'] = 1; WMCharMap['-'] = 1; WMCharMap['='] = 1; WMCharMap['['] = 1; WMCharMap[']'] = 1; WMCharMap['\\'] = 1; WMCharMap[';'] = 1; WMCharMap['\''] = 1; WMCharMap[','] = 1; WMCharMap['.'] = 1; WMCharMap['/'] = 1; WMCharMap['!'] = 1; WMCharMap['@'] = 1; WMCharMap['#'] = 1; WMCharMap['$'] = 1; WMCharMap['%'] = 1; WMCharMap['^'] = 1; WMCharMap['&'] = 1; WMCharMap['*'] = 1; WMCharMap['('] = 1; WMCharMap[')'] = 1; WMCharMap['_'] = 1; WMCharMap['+'] = 1; WMCharMap['{'] = 1; WMCharMap['}'] = 1; WMCharMap['|'] = 1; WMCharMap[':'] = 1; WMCharMap['\"'] = 1; WMCharMap['<'] = 1; WMCharMap['>'] = 1; WMCharMap['?'] = 1; // Zero out KeyRepeat map. for (i=0; i<256; i++) KeyRepeatMap[i] = 0; // Remember pointer settings. XGetPointerControl(XDisplay, &MouseAccel_N, &MouseAccel_D, &MouseThreshold); debugf( TEXT("Created and initialized a new X viewport.") ); unguard; }
char *Sys_ConsoleInput() { guard(Sys_ConsoleInput); #if !NO_DEDICATED if (console_drawInput) { // display input line Win32Log.WriteChar(']'); if (console_textlen) { console_text[console_textlen] = 0; Win32Log.WriteStr(console_text); } console_drawInput = false; } while (true) { DWORD numevents, numread; GetNumberOfConsoleInputEvents(hConInput, &numevents); if (numevents <= 0) break; INPUT_RECORD rec; ReadConsoleInput(hConInput, &rec, 1, &numread); if (rec.EventType == KEY_EVENT && rec.Event.KeyEvent.bKeyDown) { int ch = rec.Event.KeyEvent.uChar.AsciiChar; switch (ch) { case '\r': // ENTER Win32Log.WriteStr("\r\n"); console_drawInput = true; if (console_textlen) { console_textlen = 0; return console_text; } break; case '\b': // BACKSPACE if (console_textlen) { console_text[--console_textlen] = 0; Win32Log.WriteStr("\b \b"); } break; case '\t': // TAB { appSprintf(ARRAY_ARG(editLine), "]%s", console_text); CompleteCommand(); const char *s = editLine; if (s[0] == ']') s++; if (s[0] == '/') s++; int len = strlen(s); if (len > 0) { console_textlen = min(len, sizeof(console_text)-2); appStrncpyz(console_text, s, console_textlen+1); Win32Log.EraseInput(); console_drawInput = true; // next time ... } } break; case '\x1B': // ESC Win32Log.EraseInput(); console_textlen = 0; console_text[0] = 0; break; default: if (ch >= ' ') { if (console_textlen < sizeof(console_text)-2) { Win32Log.WriteChar(ch); console_text[console_textlen++] = ch; console_text[console_textlen] = 0; } } // else // appPrintf("%2X\n",ch); break; } } } #endif return NULL; unguard; }