diff --git a/BuildTools/README.md b/BuildTools/README.md new file mode 100644 index 00000000..62e973c2 --- /dev/null +++ b/BuildTools/README.md @@ -0,0 +1,33 @@ +BuildTools +========== + +## Description + +This repository contains tools used for building projects stored at https://github.com/gildor2/. It contains a stripped binary set from MSys2 (bash, perl etc, +exe and dll files in bin directory) and a few custom scripts. If you already have MSys2 or Git for Windows installed and referenced in PATH environment variable, +you'd probably won't need exe and dll files from bin directory. + +A tool which should be mentioned separately is [Jom](https://wiki.qt.io/Jom) - a Microsoft nmake replacement with support for running multiple build tasks in +parallel. Originally it was a part of Qt library, but later became a separate tool. This repository uses jom to speedup Windows builds a few times, it is selected +by vc32tools automatically when available. + +## Tools + +- [vc32tools](bin/vc32tools) - a helper script which can find and launch Visual C++ compiler +- [vcfilt](bin/vcfilt) - a helper script which colorizes Visual C++ output + +## Usage + +#### vc32tools + +Basically you can run the script without arguments to see the command line. Please note that some parameters are order-dependent: if you'll specify "--64" +after "--version=...", it won't take any effect. The same applies to commands, like if you'll provide "--version" after "--make", it won't be processed. + +#### vcfilt + +It is used automatically from "--make" or "--compile" commands. If you'd like to use it with another build system, check vc32tools source to see how it +use vcfilt. + +## License + +All binary files from MSys2 directory are covered with GNU Public License. Tools represented in this repository are [public domain](https://unlicense.org/). diff --git a/BuildTools/bin/bash.exe b/BuildTools/bin/bash.exe new file mode 100644 index 00000000..cee8a2bf Binary files /dev/null and b/BuildTools/bin/bash.exe differ diff --git a/BuildTools/bin/cat.exe b/BuildTools/bin/cat.exe new file mode 100644 index 00000000..04da19bd Binary files /dev/null and b/BuildTools/bin/cat.exe differ diff --git a/BuildTools/bin/cp.exe b/BuildTools/bin/cp.exe new file mode 100644 index 00000000..3ee8426f Binary files /dev/null and b/BuildTools/bin/cp.exe differ diff --git a/BuildTools/bin/diff.exe b/BuildTools/bin/diff.exe new file mode 100644 index 00000000..40e91432 Binary files /dev/null and b/BuildTools/bin/diff.exe differ diff --git a/BuildTools/bin/find.exe b/BuildTools/bin/find.exe new file mode 100644 index 00000000..94e6ab1f Binary files /dev/null and b/BuildTools/bin/find.exe differ diff --git a/BuildTools/bin/jom.exe b/BuildTools/bin/jom.exe new file mode 100644 index 00000000..2506b4ed Binary files /dev/null and b/BuildTools/bin/jom.exe differ diff --git a/BuildTools/bin/less.exe b/BuildTools/bin/less.exe new file mode 100644 index 00000000..4ba02ee2 Binary files /dev/null and b/BuildTools/bin/less.exe differ diff --git a/BuildTools/bin/ls.exe b/BuildTools/bin/ls.exe new file mode 100644 index 00000000..2f358308 Binary files /dev/null and b/BuildTools/bin/ls.exe differ diff --git a/BuildTools/bin/mkdir.exe b/BuildTools/bin/mkdir.exe new file mode 100644 index 00000000..b472731b Binary files /dev/null and b/BuildTools/bin/mkdir.exe differ diff --git a/BuildTools/bin/msys-1.0.dll b/BuildTools/bin/msys-1.0.dll new file mode 100644 index 00000000..f2e50358 Binary files /dev/null and b/BuildTools/bin/msys-1.0.dll differ diff --git a/BuildTools/bin/msys-crypt-0.dll b/BuildTools/bin/msys-crypt-0.dll new file mode 100644 index 00000000..5c6f3cb8 Binary files /dev/null and b/BuildTools/bin/msys-crypt-0.dll differ diff --git a/BuildTools/bin/msys-iconv-2.dll b/BuildTools/bin/msys-iconv-2.dll new file mode 100644 index 00000000..622c181f Binary files /dev/null and b/BuildTools/bin/msys-iconv-2.dll differ diff --git a/BuildTools/bin/msys-intl-8.dll b/BuildTools/bin/msys-intl-8.dll new file mode 100644 index 00000000..892acba7 Binary files /dev/null and b/BuildTools/bin/msys-intl-8.dll differ diff --git a/BuildTools/bin/msys-perl5_8.dll b/BuildTools/bin/msys-perl5_8.dll new file mode 100644 index 00000000..b43f91ad Binary files /dev/null and b/BuildTools/bin/msys-perl5_8.dll differ diff --git a/BuildTools/bin/msys-regex-1.dll b/BuildTools/bin/msys-regex-1.dll new file mode 100644 index 00000000..379c6b39 Binary files /dev/null and b/BuildTools/bin/msys-regex-1.dll differ diff --git a/BuildTools/bin/msys-termcap-0.dll b/BuildTools/bin/msys-termcap-0.dll new file mode 100644 index 00000000..8f5ac266 Binary files /dev/null and b/BuildTools/bin/msys-termcap-0.dll differ diff --git a/BuildTools/bin/perl.exe b/BuildTools/bin/perl.exe new file mode 100644 index 00000000..b1e1c73f Binary files /dev/null and b/BuildTools/bin/perl.exe differ diff --git a/BuildTools/bin/rm.exe b/BuildTools/bin/rm.exe new file mode 100644 index 00000000..9f6de62a Binary files /dev/null and b/BuildTools/bin/rm.exe differ diff --git a/BuildTools/bin/rmdir.exe b/BuildTools/bin/rmdir.exe new file mode 100644 index 00000000..4f80153b Binary files /dev/null and b/BuildTools/bin/rmdir.exe differ diff --git a/BuildTools/bin/sh.exe b/BuildTools/bin/sh.exe new file mode 100644 index 00000000..cee8a2bf Binary files /dev/null and b/BuildTools/bin/sh.exe differ diff --git a/BuildTools/bin/sleep.exe b/BuildTools/bin/sleep.exe new file mode 100644 index 00000000..dfecc2d8 Binary files /dev/null and b/BuildTools/bin/sleep.exe differ diff --git a/BuildTools/bin/sort.exe b/BuildTools/bin/sort.exe new file mode 100644 index 00000000..c92bb0dd Binary files /dev/null and b/BuildTools/bin/sort.exe differ diff --git a/BuildTools/bin/tee.exe b/BuildTools/bin/tee.exe new file mode 100644 index 00000000..ba553ff4 Binary files /dev/null and b/BuildTools/bin/tee.exe differ diff --git a/BuildTools/bin/vc32tools b/BuildTools/bin/vc32tools new file mode 100644 index 00000000..4f16d666 --- /dev/null +++ b/BuildTools/bin/vc32tools @@ -0,0 +1,485 @@ +#!/bin/bash + +# Visual C++ compiler (CL) helper script. +# The main purpose of this is to locate the compiler, setup environment and execute it with provided parameters. +# It has a possibility to build makefiles using NMAKE or JOM backend, or compile (and possibly link) separate +# C/C++ files for small applications. To get list of possible options run vc32tools without arguments. + +# Created by Konstantin Nosov (Gildor) +# https://github.com/gildor2/BuildTools +# Public Domain (https://unlicense.org/) + + +# Some references for VS2017+ compiler location. +# Article: https://devblogs.microsoft.com/cppblog/finding-the-visual-c-compiler-tools-in-visual-studio-2017/. +# Vswhere does not enumerate toolsets: https://github.com/Microsoft/vswhere/issues/151 +# Useful batch files: +# "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" +# - top-level batch, calls other, like vsdevcmd.bat, core\vsdevcmd_start.bat, parse_cmd.bat +# "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\vsdevcmd\ext\vcvars.bat" +# - final batch, selected toolset version is in __VCVARS_VERSION env variable. + + +# Color constants +norm="\\033[0m" +hgl="\\033[1" +force_nmake="" + +# Usage: CheckVC [params...] +# $1 = path - typical path to Visual Studio installation, not used since VC2017 +# $2 = vc_version - classic version number +# $3 = vc_year - "year" version +# $4 = toolset - toolset version, used when multiple C++ toolsets are installed for single VS +# Output: +# $workpath - base path to VS installation +# $found_vc - 'classic' version of VS which is located +# $found_vc_year - 'year' version +# $vs_compiler - path to compiler, used for VS2017+ + +function CheckVC() +{ + platform="32 bit" + [ "$amd64" ] && platform="64 bit" + + # special case for VS2017+ + # see https://github.com/Microsoft/vswhere/wiki/Find-VC for details (PowerShell case) + if [ $3 -ge 2017 ]; then + vswhere="$progs/Microsoft Visual Studio/Installer/vswhere.exe" + [ -f "$vswhere" ] || return + version_filter="-version [$2.0,$(($2+1)).0)" + display_name=`"$vswhere" $version_filter -property displayName` + base_path=`"$vswhere" $version_filter -property installationPath` + [ "$base_path" ] || return + # get version file for specified toolset + version_file="$base_path/VC/Auxiliary/Build/Microsoft.VCToolsVersion.v$4.default.txt" + if ! [ -f "$version_file" ]; then + # get any toolset (most likely that will select toolset for current compiler) + version_file="$base_path/VC/Auxiliary/Build/Microsoft.VCToolsVersion.default.txt" + [ -f "$version_file" ] || return + fi + vs_subver=`cat "$version_file"` + vs_compiler="$base_path/VC/Tools/MSVC/$vs_subver" + [ -d "$vs_compiler" ] || return + workpath="$base_path/VC" + found_vc=$2 + found_vc_year=$3 + echo "$display_name toolset $4 ($vs_subver) [$platform] found at \"$base_path\" ..." + else + # pre-VS2017 path + # verify presence + vspath="$1" + if [ -f "$vspath/bin/nmake.exe" ]; then + if [ "$amd64" ] && ! [ -f "$vspath/bin/amd64/nmake.exe" ]; then + return + fi + workpath="$vspath" + found_vc=$2 + found_vc_year=$3 + echo "Using Visual C++ $2 ($3) [$platform] found at \"$vspath\" ..." + fi + fi +} + + +function CheckSDK() +{ + if [ "$sdkpath" ]; then + return # already found + fi + # verify presence + if [ -d "$1" ] && [ -f "$1/bin/rc.exe" ]; then +# sdkpath="/cygdrive/${1//:/}" # d:/path -> /cygdrive/d/path - CygWin +# sdkpath="/${1//:/}" # d:/path -> /d/path - MSys + sdkpath="$1" # no path replacement + echo "Found Win32 SDK at \"$1\" ..." + fi +} + + +function AddPath() +{ + # Unix has multiple items separated with ":" which is used as drive separator on Windows systems +# local p="/cygdrive/${1//:/}" # d:/path -> /cygdrive/d/path - CygWin + local p="/${1//:/}" # d:/path -> /d/path - MSys + # Add new path before previously defined ones, so for example if older path has "link.exe" (part of Git), + # we'll use one from Visual Studio (i.e. the correct one) + PATH="$p:$PATH" +} + + +# Parameters: +# $1 = version, which is either version (6, 7, ...), year (2008, 2010, ...) or "latest" +function LocateSuitableVC() +{ + local VC=( + # Format: + "$progs/microsoft visual studio/vc98" 6 0 0 # 6.0 + "$progs/microsoft visual studio .net/vc7" 7 2002 0 # 7.0 + "$progs/microsoft visual studio .net 2003/vc7" 7 2003 0 # 7.1 + "$progs/microsoft visual studio 8/vc" 8 2005 0 # 8.0 + "$progs/microsoft visual studio 9.0/vc" 9 2008 90 # 9.0 + "$progs/microsoft visual studio 10.0/vc" 10 2010 100 # 10.0 + "$progs/microsoft visual studio 11.0/vc" 11 2012 0 # 11.0 + "$progs/microsoft visual studio 12.0/vc" 12 2013 120 # 12.0 + "$progs/microsoft visual studio 14.0/vc" 14 2015 140 # 14.0 + "" 15 2017 141 # 15.0 + "" 16 2019 142 # 16.0 + "" 17 2022 143 # 17.0 + ) + + if [ "$1" == "latest" ]; then + # Find newest VC, should iterate array in reverse order + local i=${#VC[@]} + while [ $i -gt 0 ]; do + ((i=$i-4)) + local vc_path="${VC[$i]}" + local vc_num="${VC[$i+1]}" + local vc_year="${VC[$i+2]}" + local vc_tool="${VC[$i+3]}" +# echo "($vc_path) $vc_num $vc_year toolset=$vc_tool" + + CheckVC "$vc_path" $vc_num $vc_year $vc_tool + [ "$workpath" ] && break + done + else + local i=0 + toolset=0 + while [ $i -lt ${#VC[@]} ]; do + local vc_path="${VC[$i]}" + local vc_num="${VC[$i+1]}" + local vc_year="${VC[$i+2]}" + local vc_tool="${VC[$i+3]}" + ((i=$i+4)) +# echo "($vc_path) $vc_num $vc_year toolset=$vc_tool" + + if [ "$1" ]; then + # "continue" if version is not large enough + if [ "$1" -gt 2000 ]; then + # this is year-based version + [ "$1" -gt "$vc_year" ] && continue + else + [ "$1" -gt "$vc_num" ] && continue + fi + fi + [ $toolset == 0 ] && toolset=$vc_tool + + CheckVC "$vc_path" $vc_num $vc_year $toolset + [ "$workpath" ] && break + done + fi +} + + +function PrepareVC() +{ + if [ "$workpath" ]; then + return # action already performed + fi + + # find "Program Files" dir + # note: on 64-bit systems "PROGRAMFILES" will contain path to (x86) dir + if [ "$PROGRAMFILES" ]; then + progs="${PROGRAMFILES//\\//}" # get from environment with slash replacement + else + progs="c:/program files" + fi + # When running 64-bit bash on Windows, it will use 64-bit Program Files by default. However, + # Visual Studio is always located in x86 directory, so switch to using it. + if [ -d "$progs (x86)" ]; then + progs="$progs (x86)" + fi + + # ---------- Find Visual Studio ---------- + + LocateSuitableVC $vc_ver + + if [ ! "$workpath" ]; then + echo -e "${hgl};31mERROR: Visual C++ was not found.${norm}" + exit 1 + fi + + # compute path to additional dlls + case $found_vc in + 6) ide="$workpath/../common/msdev98/bin" + ;; + *) ide="$workpath/../common7/IDE" + ;; + esac + + # setup environment variables + if [ $found_vc -ge 15 ]; then + if [ "$amd64" ]; then + AddPath "$vs_compiler/bin/Hostx64/x64" + LIB="$vs_compiler/lib/x64" + else + # Note: AddPath will prepend PATH, so we're adding x64 before x86, however x86 will be first for lookup + AddPath "$vs_compiler/bin/Hostx64/x64" # pick dlls from another target's toolset for mspdbcore.dll + AddPath "$vs_compiler/bin/Hostx64/x86" + LIB="$vs_compiler/lib/x86" + fi + INCLUDE="$vs_compiler/include" + else + # pre-VS2017 paths + if [ "$amd64" ]; then + AddPath "$workpath/bin/amd64" + else + AddPath "$workpath/bin" + AddPath "$ide" + fi + INCLUDE="$workpath/INCLUDE" + INCLUDE="$INCLUDE;$workpath/MFC/INCLUDE;$workpath/PlatformSDK/Include;$workpath/PlatformSDK/Include/prerelease" #?? may be not needed to include this + #?? Again, "PlatformSDK" is below - it seems that was for VS 2003 + if [ -z "$amd64" ]; then + LIB="$workpath/LIB;$workpath/PlatformSDK/LIB" + else + LIB="$workpath/LIB/amd64;$workpath/PlatformSDK/LIB/x64" + fi + fi + + # ---------- Find Platform SDK ---------- + + CheckSDK "$progs/Microsoft SDKs/Windows/v7.1" + CheckSDK "$progs/Microsoft SDKs/Windows/v7.0A" + CheckSDK "C:/Program Files/Microsoft SDKs/Windows/v6.0A" # NOTE: not in "Program Files (x86)" + + if [ "$sdkpath" ]; then + INCLUDE="$INCLUDE;$sdkpath/Include" + if [ -z "$amd64" ]; then + LIB="$LIB;$sdkpath/Lib" + else + LIB="$LIB;$sdkpath/Lib/x64" + fi + AddPath "$sdkpath/bin" # VC9+ has no RC.exe in its bin directory, using it from the SDK + fi + + # ---------- CRT for modern C++ compilers ---------- + + if [ -z "$sdkpath" ] || [ $found_vc -ge 14 ]; then + # VS starting with 2015 version doesn't have CRT, it uses UCRT from Windows Kits/10 + win10sdk="$progs/Windows Kits/10" + if [ -d "$win10sdk" ]; then +# olddir="$PWD" +# cd "$win10sdk/Include" + win10sdk_ver="0.0.0.0" +# for d in "$win10sdk/Include/*"; do - changing dir + return to olddir will not work correctly for symlink'ed current directory + for d in `ls "$win10sdk/Include"`; do # we're using 'ls ...' here because simple "path_with_spaces/*" will not work + if [[ $d > $win10sdk_ver ]]; then + win10sdk_ver=$d + fi + done +# cd "$olddir" + INCLUDE="$INCLUDE;$win10sdk/Include/$win10sdk_ver/ucrt;$win10sdk/Include/$win10sdk_ver/um;$win10sdk/Include/$win10sdk_ver/shared" + if [ -z "$amd64" ]; then + lib_subdir=x86 + else + lib_subdir=x64 + fi + LIB="$LIB;$win10sdk/Lib/$win10sdk_ver/ucrt/$lib_subdir;$win10sdk/Lib/$win10sdk_ver/um/$lib_subdir" + # include SDK bin directory (required for rc.exe) + AddPath "$win10sdk/bin/$lib_subdir" + AddPath "$win10sdk/bin/$win10sdk_ver/$lib_subdir" + else + echo "ERROR: $win10sdk not found" + exit 1 + fi + fi + +# echo " -- PATH: $workpath : $sdkpath" +# echo " -- INC: $INCLUDE" +# echo " -- LIB: $LIB" + export INCLUDE LIB +} + + +# Generate sound event using Visual Studio settings +function VSEvent() +{ + Sound=$1 + # We're using PowerShell to access registry and play sounds. + # Note: using '&' at the end to issue sound asynchronously, so script will not wait till sound completed. + { + cat < LNK: <$linkopt>" +# linker option "-merge:.rdata=.data" will merge sections, but produce warnings + vcfilt cl -nologo -O1 -MD $cppopt $filename -link -filealign:512 $linkopt + return ${PIPESTATUS[0]} # use return instead of exit +} + + +function Link() +{ + PrepareVC + link $* +} + +function Usage() +{ +cat<] [--make ] [--check] [--help] + +Compiler secection options: + --version= minimal Visual C++ version to use (version option must go first) + --64 use 64-bit compiler (by default 32-bit compiler is used) + + is VC year number or its version. Example: For VS2015 use --version=2015 or 14. + Use "--version=latest" to use most recent version available on the system. When not specified, + the first available (i.e. oldest) compiler version will be used. + +Compiling source code: + --compile compile c/cpp source file(s) + +Extra options for compile: + file(s) to compile + --debug create pdb file + /link pass all following options directly to linker + +Executing makefile: + --make build specified makefile + --nmake force NMAKE build, do not use JOM (should go before --make) + +Calling linker: + --link link source files + +Other options: + --check verify availability of VC++ + --help display compiler help pages +EOF +} + + +# NOTE: this will try to parse command even when called via "source ", i.e. included +while [ "1" ]; do + + case "$1" in + --version=*) # specify preferred compiler version + vc_ver=${1:10} + shift + continue # process other switches + ;; + --64) + amd64=1 + shift + continue + ;; + --nmake) + force_nmake=1 + shift + continue + ;; + --compile) + shift + Compile $* + exit + ;; + --link) + shift + Link $* + exit + ;; + --make) + shift + Make $* + exit + ;; + --check) + PrepareVC + break + ;; + --help) + PrepareVC + cl -? + exit 0 + ;; + "") # no commands + Usage + exit 0 + ;; + *) + echo "Invalid vc32tools option $1" + exit 1 + ;; + esac + +done diff --git a/BuildTools/bin/vcfilt b/BuildTools/bin/vcfilt new file mode 100644 index 00000000..a0ccca5f --- /dev/null +++ b/BuildTools/bin/vcfilt @@ -0,0 +1,90 @@ +#!/usr/bin/perl -w + +# Visual C++ compiler (CL) output colorizer. +# It is intended to highlight error and warning messages from compiler to make them more noticeable. +# The script works as output filter, however it starts compiler itself, so usual use is +# `perl vcfilt `. + +# Created by Konstantin Nosov (Gildor) +# https://github.com/gildor2/BuildTools +# Public Domain (https://unlicense.org/) + +# Changes: +# 20.09.2014 +# - removed 'nice' call - probably not needed anymore (previously used to give priority to this +# filter process over compiler, so there was no lags in output) +# 31.01.2012 +# - do not use colorizing when not attached to terminal (redirected to a file) +# 14.10.2011 +# - fixed strange bug with Win7 + new CygWin - pipe were not created when arguments are quoted + + +sub color { + my ($line, $color) = @_; + return "\033[1;${color}m".$line."\033[0m"; +} + +$log = 0; +if (exists $ENV{"logfile"}) { + $log = 1; + open (LOG, ">>".$ENV{"logfile"}) or $log = 0; +} + +#setpriority(PRIO_PROCESS, $PID, -20); -- unimplemented + +# wisely combine command line, adding quotes when needed +# other (smaller) variants: +# $cmdline = "\"".join("\" \"", @ARGV)."\""; +# - this could raise to error "Can't pipe to ..." because executable name is quoted +# $cmdline = join(" ", @ARGV); +# - combine without quotes, will not process spaces at all +$cmdline = $ARGV[0]; +shift @ARGV; +foreach $arg (@ARGV) +{ + if ($arg =~ /\s/) { + $cmdline .= " \"$arg\""; + } else { + $cmdline .= " $arg"; + } +} +die "Usage: vcfilt \n" if !defined($cmdline); + + +# set priority of executed tool lower, then this filter' priority +#!!$cmdline = "nice -n 5 $cmdline"; + +# create process with piped output +#-- open(IN, "-|", "2>&1 $cmdline") or die "Can't pipe to @ARGV[0]\n"; +open(IN, "$cmdline 2>&1|") or die "Can't pipe to $ARGV[0]\n"; +$isConsole = (-t STDOUT); + +while ($line = ) +{ + if (!$isConsole) { + print($line); + print(LOG $line) if $log; + next; + } + my $line2 = $line; + if ($line =~ /Microsoft|Copyright/) { + $line2 = color ($line, 30); + } elsif ($line =~ /: fatal/) { + $line2 = color ($line, 35); + } elsif ($line =~ /: error/) { + $line2 = color ($line, 31); + } elsif ($line =~ /: warning/) { + $line2 = color ($line, 33); + } elsif ($line =~ /: attention/) { #!! temporary + $line2 = color ($line, 34); + } + print($line2); + print(LOG $line) if $log; +} +close(IN); +$ret = $?; + +close(LOG) if $log; + +# return code => out; note: code 256 could be converted to 0 (8 bit value!) so convert it to 0 or 1 +exit($ret != 0); diff --git a/Exporters/ExportMaterial.cpp b/Exporters/ExportMaterial.cpp index 527d6a26..e7040c1f 100644 --- a/Exporters/ExportMaterial.cpp +++ b/Exporters/ExportMaterial.cpp @@ -4,10 +4,71 @@ #include "UnObject.h" #include "UnrealMaterial/UnMaterial.h" #include "UnrealMaterial/UnMaterial3.h" - +#include "UnrealMaterial/UnMaterialExpression.h" +#include "unrealPackage/UnPackage.h" #include "Exporters.h" + +bool IsValidCString(const char* str, size_t maxLen = 1024) +{ + if (!str) return false; + + __try { + for (size_t i = 0; i < maxLen; ++i) + { + if (str[i] == '\0') return true; // found null terminator + } + return false; // too long or unterminated + } + __except (EXCEPTION_EXECUTE_HANDLER) { + return false; // access violation or bad pointer + } +} + +//Hack. get texture type by addition in texture name +FString GetTextureType(const UUnrealMaterial* Tex) +{ + struct TextureSuffix { + const char* suffix; + const char* type; + }; + + TextureSuffix suffixMap[] = + { + { "_D", "Diffuse" }, + { "_D2", "Diffuse" }, + //{ "_pack", "Diffuse"}, // ... In custom materials, but used common + { "_N", "Normal" }, + { "_MASK", "Mask" }, + { "_Cube", "Cubemap" }, + { "_crl", "Detail"}, // ??? + }; + + if(IsValidCString(Tex->Name) == false) + { + printf("Invalid texture name / pointer \n"); + return ""; + } + + const char* name = Tex->Name; + int nameLen = strlen(name); + + for (int i = 0; i < ARRAY_COUNT(suffixMap); i++) + { + const char* suffix = suffixMap[i].suffix; + int suffixLen = strlen(suffix); + + if (nameLen >= suffixLen && stricmp(name + nameLen - suffixLen, suffix) == 0) + { + printf("Type: %s for texture %s\n", suffixMap[i].type, name); + return FString(suffixMap[i].type); + } + } + + return ""; +} + void ExportMaterial(const UUnrealMaterial* Mat) { guard(ExportMaterial); @@ -32,22 +93,29 @@ void ExportMaterial(const UUnrealMaterial* Mat) //todo: remove separate texture handling from Main.cpp exporter registraction TArray AllTextures; - Mat->AppendReferencedTextures(AllTextures, false); - CMaterialParams Params; - Mat->GetParams(Params); - if ((Params.IsNull() || Params.Diffuse == Mat) && AllTextures.Num() == 0) - { - // empty/unknown material, or material itself is a texture - appPrintf("Ignoring %s'%s' due to empty parameters\n", Mat->GetClassName(), Mat->Name); - return; - } + + Mat->AppendReferencedTextures(AllTextures, false); FArchive* Ar = CreateExportArchive(Mat, EFileArchiveOptions::TextFile, "%s.mat", Mat->Name); if (!Ar) return; TArray ToExport; + if (Mat->IsA("Material3")) + { + const UMaterial3* Mat3 = static_cast(Mat); + for (int i = 0; i < Mat3->ReferencedTextures.Num(); i++) + { + UTexture3* Tex = Mat3->ReferencedTextures[i]; + if (Tex) + { + appPrintf("Exporting raw texture [%d]: %s\n", i, Tex->Name); + ToExport.AddUnique(Tex); + } + } + } + #define PROC(Arg) \ if (Params.Arg) \ { \ @@ -56,6 +124,7 @@ void ExportMaterial(const UUnrealMaterial* Mat) } PROC(Diffuse); + //PROC(DiffuseColor); PROC(Normal); PROC(Specular); PROC(SpecPower); @@ -64,6 +133,23 @@ void ExportMaterial(const UUnrealMaterial* Mat) PROC(Cube); PROC(Mask); + //Testing these: + PROC(Detail); + PROC(AO); + PROC(GlowMap); + PROC(PaintMask); + PROC(TeamColor); + PROC(ColorLookup); + PROC(DecalTexture); + PROC(TilingPattern); + PROC(HexMask); + PROC(Environment); + PROC(Reflection); + PROC(Overlay); + PROC(Noise); + PROC(Roughness); + PROC(Metallic); + // Dump material properties to a separate file FArchive* PropAr = CreateExportArchive(Mat, EFileArchiveOptions::TextFile, "%s.props.txt", Mat->Name); if (PropAr) @@ -72,22 +158,237 @@ void ExportMaterial(const UUnrealMaterial* Mat) delete PropAr; } - // Export other textures + TArray> ExportTexMap; + + // HACK - First iterration, to gather all type-texture map. The type is assumed based on texture name, so there is no guarantee it is correct. int numOtherTextures = 0; for (int i = 0; i < AllTextures.Num(); i++) { + //Export with texture type name UUnrealMaterial* Tex = AllTextures[i]; - if (ToExport.FindItem(Tex) < 0) + if (!Tex) continue; + + if (IsValidCString(Tex->Name) == false) { + continue; + } + const char* TexPath = appStrdup(Tex->Name); + printf("Processing texture [%d]: %s\n", i, TexPath); + + //This works but is hacky + FString TextureType = GetTextureType(Tex); + if (TextureType.Len() > 0) { - Ar->Printf("Other[%d]=%s\n", numOtherTextures++, Tex->Name); - ToExport.Add(Tex); + const char* paramName = appStrdup(*TextureType); + printf("Adding texture parameter %s=%s\n", paramName, TexPath); + ExportTexMap.Add({ appStrdup (paramName), TexPath }); } + else + { + char OtherType[64]; + appSprintf(ARRAY_ARG(OtherType), "Other[%d]", numOtherTextures++); + const char* safeOther = appStrdup(OtherType); + + + printf("Adding texture parameter %s=%s\n", safeOther, TexPath); + ExportTexMap.Add({ safeOther, appStrdup(TexPath) }); + + } + } + + // Second iteration: export named texture parameters from material expressions and overwrite the previous list. + // There can be a mistake if few parameters are using the same texture path... + const UMaterial3* Material = static_cast(Mat); + for (int i = 0; i < Material->Expressions.Num(); i++) + { + if (Material->Expressions[i] == nullptr) continue; + + const char* paramName = nullptr; + const char* texPath = nullptr; + + printf("Expression %d: %s\n", i, Material->Expressions[i]->GetClassName()); + + // UMaterialExpressionTextureSampleParameter2D is inherited from UMaterialExpressionTextureSampleParameter, so no need to check it separately + // TODO MaterialExpressionTextureSampleParameterCube - not implemented yet + auto *TexSampleParameter = static_cast(Material->Expressions[i]); + if (TexSampleParameter) + { + printf("Found texture sample parameter expression\n"); + auto ExpTex = TexSampleParameter->Texture; + if (ExpTex == nullptr) + continue; + if (TexSampleParameter->Texture == nullptr) + continue; + + paramName = TexSampleParameter->ParameterName ? TexSampleParameter->ParameterName : ""; + printf(" Parameter name: %s\n", paramName); + + texPath = nullptr; + if (ExpTex && IsValidCString(ExpTex->Name)) + { + printf(" Texture name: %s\n", ExpTex->Name); + texPath = appStrdup(ExpTex->Name); + } + else + { + printf(" Texture name is null\n"); + texPath = appStrdup("Unknown"); + continue; + } + bool KeyChanged = false; + + printf(" Texture path: %s\n", texPath); + + for (int x = 0; x < ExportTexMap.Num(); x++) + { + printf(" Map %d: %s=%s\n", x, ExportTexMap[x].Key, ExportTexMap[x].Value); + if (ExportTexMap[x].Key == nullptr || ExportTexMap[x].Value == nullptr || paramName == nullptr || ExpTex->Name == nullptr) + { + continue; + } + //appPrintf("texPath ptr=%p ExportTexMap[%d].Value ptr=%p\n", (void*)texPath, x, (void*)ExportTexMap[x].Value); + + printf(" Comparing %s to %s\n", ExportTexMap[x].Value, texPath); + if (!paramName || !texPath) continue; + if (strlen(paramName) > 4096 || strlen(texPath) > 4096) continue; + + //printf("%d Comparing parameter %s=%s to %s=%s\n", ExportTexMap.Num(), ExportTexMap[x].Key, ExportTexMap[x].Value, paramName, texPath); + + if (ExportTexMap[x].Value == texPath) + { + appPrintf("Changing texture parameter %s=%s to %s=%s\n", ExportTexMap[x].Key, ExportTexMap[x].Value, paramName, texPath); + ExportTexMap[x].Key = paramName; + KeyChanged = true; + break; + } + } + + if (KeyChanged == false) + { + printf("Added %s=%s\n", paramName, texPath); + ExportTexMap.Add({ appStrdup(paramName), appStrdup(texPath) }); + } + } + } + /* + if (Mat) + { + // Try cast mnaterial to UMaterial3 to get more information about used textures + + if (Mat->IsA("Material3")) + { + UMaterial3* Material = (UMaterial3*)Mat; + + if (Material != nullptr) + { + + printf("Loading Material3 CollectedTextureParameters:\n"); + // 1) Collected texture parameters + for (int i = 0; i < Material->CollectedTextureParameters.Num(); ++i) + { + const CTextureParameterValue& P = Material->CollectedTextureParameters[i]; + + if (IsValidCString(P.Name)) + { + appPrintf("CollectedTexture param: %s\n", P.Name); + } + } + /* + for (UObject* E : Material->Expressions) + { + if (E && E->IsA("MaterialExpressionTextureSampleParameter")) + { + auto* TS = static_cast(E); + /* + if(TS !=nullptr && IsValidCString(TS->ParameterName)) + { + printf("Expr param %s =", TS->ParameterName); + + printf("Expr param %s -> texture %s\n", + TS->ParameterName ? TS->ParameterName : "None", + TS->Texture ? TS->Texture->Name : "None"); + + } + + + + } + } + */ + /* + if (Material->DiffuseColor) + printf("Diffuse input connected to %s\n", Material->DiffuseColor->Name); + else + printf("Diffuse input not connected\n"); + */ + + /* + for (int i = 0; i < Material->Expressions.Num(); ++i) + { + UObject* Eobj = Material->Expressions[i]; + if (!Eobj) continue; + const char* cls = Eobj->GetClassName(); + appPrintf("Expr[%d] class=%s name=%s\n", i, cls, Eobj->Name); + + if (Eobj->IsA("MaterialExpressionTextureSampleParameter") || Eobj->IsA("MaterialExpressionTextureSample")) + { + const char* matname = Material->Name ? Material->Name : "None"; + auto* TS = static_cast(Eobj); + const char* pname = TS->ParameterName ? TS->ParameterName : "None"; + const char* tex = (TS->Texture && TS->Texture->Name) ? TS->Texture->Name : "None"; + + appPrintf(" TextureSampleParam: ParameterName=%s Texture=%s Material=%s\n", pname, tex, matname); + + // If your UMaterialExpression has an Outputs[] or LinkedTo[] array, follow them: + // for each output->LinkedTo: if a link target is the material's input node, you have a connected input. + } + } + */ + /* + // 2) GetParams (fast canonical check) + CMaterialParams Params; + Material->GetParams(Params); // signature depends on your fork + if (!Params.IsNull()) + { + if (Params.Diffuse) printf("Diffuse connected -> %s\n", Params.Diffuse->Name); + else printf("Diffuse not connected\n"); + // repeat for other fields... + } + */ + /* + } + } + } + */ + + + + + + for (int i = 0; i < ExportTexMap.Num(); i++) + { + printf("Adding to texture to archive"); + const char* safeKey = ExportTexMap[i].Key != nullptr ? ExportTexMap[i].Key : "Null"; + const char* safeValue = ExportTexMap[i].Value != nullptr ? ExportTexMap[i].Value : "Null"; // value can be still null + printf("Exporting texture parameter %s=%s\n", safeKey, safeValue); + + if (safeKey != "None") + Ar->Printf("%s=%s\n", safeKey, safeValue); } + + for (int i = 0; i < AllTextures.Num(); i++) + { + UUnrealMaterial* ExpMat = AllTextures[i]; + if (ExpMat == NULL) continue; + ToExport.AddUnique(ExpMat); + } + + delete Ar; // close .mat file // We have done with current object, now let's export referenced objects. + for (UObject* Obj : ToExport) { if (Obj != Mat) // UTextureCube::GetParams() adds self to "Cube" field @@ -98,13 +399,17 @@ void ExportMaterial(const UUnrealMaterial* Mat) if (Mat->IsA("MaterialInstanceConstant")) { const UMaterialInstanceConstant* Inst = static_cast(Mat); - if (Inst->Parent) + if (Inst !=nullptr && Inst->Parent) { ExportMaterial(Inst->Parent); } } + #endif // RENDERING unguardf("%s'%s'", Mat->GetClassName(), Mat->Name); } + + + diff --git a/TestRun.bat b/TestRun.bat new file mode 100644 index 00000000..33d0df1c --- /dev/null +++ b/TestRun.bat @@ -0,0 +1 @@ +python TestRun.py \ No newline at end of file diff --git a/TestRun.py b/TestRun.py new file mode 100644 index 00000000..6b847b8d --- /dev/null +++ b/TestRun.py @@ -0,0 +1,27 @@ +import subprocess +import os + +# Paths +umodel_path = "C:/Users/lauri/Documents/Github/UEViewer/umodel.exe" +game_path = "C:/Program Files/Epic Games/rocketleague" +package_path = os.path.join(game_path, "TAGame/CookedPCConsole/Stadium_P.upk") +output_path = "C:/Users/lauri/Desktop/RocketLeague/Automation" + +# Command +command = [ + umodel_path, + "-export", + "-game=rocketleague", + f"-path={game_path}", + f"-out={output_path}", + package_path +] + +# Run UModel +try: + subprocess.run(command, check=True) + print("UModel export completed successfully.") +except subprocess.CalledProcessError as e: + print(f"UModel failed with error code {e.returncode}") +except FileNotFoundError: + print("UModel executable not found. Check the path.") \ No newline at end of file diff --git a/Tools/genmake b/Tools/genmake index 9b44f782..8e618d15 100755 --- a/Tools/genmake +++ b/Tools/genmake @@ -568,14 +568,17 @@ sub EmitCompilerDefs { $defs2 .= " -d _WIN64 -d WIN64"; } # Compiler - print "CPP = cl.exe -nologo -c $defs1 -D _WINDOWS${winxp}\n"; + #print "CPP = cl.exe -nologo -c $defs1 -D _WINDOWS${winxp}\n"; + print "CPP = cl.exe -nologo -c /MT $defs1 -D _WINDOWS${winxp}\n"; # Linker my $machine = ($PLATFORM eq "win64") ? "X64" : "X86"; print "LINK = link.exe -nologo -filealign:512 -incremental:no -machine:$machine\n"; # Library manager print "AR = link.exe -lib -nologo\n"; # cannot use "LIB" name # Resource compiler - print "RC = rc.exe -nologo -dNDEBUG -l 0x409${winxp}${defs2}\n" + + print "RC = rc.exe -nologo -dNDEBUG -l 0x409${winxp}${defs2}\n"; + print "LIBS = ucrt.lib legacy_stdio_definitions.lib msvcrt.lib kernel32.lib user32.lib advapi32.lib shell32.lib\n"; } elsif ($COMPILER eq "GnuC") { my $platf = "gcc"; # platform override @@ -1274,6 +1277,8 @@ sub FlushTargetText { return $prefix."\t\$(AR) -out:\"$n\"$fileList"; } $line = "\t\$(LINK) -out:\"$n\""; + $line .= " \$(LIBS)"; + $line .= " /NODEFAULTLIB:LIBCMT"; $line .= GenerateOptions ($libpath, "-libpath:") if $libpath ne ""; $line .= " $stdlibs" if $stdlibs ne ""; $line .= " $libs" if $libs ne ""; diff --git a/Unreal/UnObject.cpp b/Unreal/UnObject.cpp index e0585881..24cda9e3 100644 --- a/Unreal/UnObject.cpp +++ b/Unreal/UnObject.cpp @@ -71,9 +71,16 @@ void UObject::GetFullName(char *buf, int bufSize, bool IncludeObjectName, bool I guard(UObject::GetFullName); if (!Package) { + // Simulate package name for dummy textures + if (PackageIndex == INDEX_NONE && Name) + { + appSprintf(buf, bufSize, "Texture2D'%s.%s'", "MissingPackage", Name); + return; + } buf[0] = 0; return; } + #if UNREAL4 if (Package != NULL && Package->Game >= GAME_UE4_BASE) { @@ -92,7 +99,15 @@ void UObject::GetFullName(char *buf, int bufSize, bool IncludeObjectName, bool I #endif // UNREAL4 if (PackageIndex == INDEX_NONE) { - // This is a dummy generated export + // Handle dummy textures with missing package + if (!Package) + { + // Use fallback name if available + appSprintf(buf, bufSize, "MissingPackage.%s", Name ? Name : "Unnamed"); + return; + } + + // Normal dummy export with known package appSprintf(buf, bufSize, "%s.%s", Package->Name, Name); return; } diff --git a/Unreal/UnRenderer.cpp b/Unreal/UnRenderer.cpp index 49e640cb..cc54f1f9 100644 --- a/Unreal/UnRenderer.cpp +++ b/Unreal/UnRenderer.cpp @@ -1743,8 +1743,8 @@ void UUnreal3Material::GetParams(CMaterialParams &Params) const Params.Normal = Tex; else if (!stricmp(Name + len - 2, "_m")) Params.Mask = Tex; -// else -// appPrintf("Tex: %s\n", Name); + else + appPrintf("Tex: %s\n", Name); } Params.SpecularMaskChannel = TC_G; @@ -1977,6 +1977,12 @@ void UMaterial3::GetParams(CMaterialParams &Params) const Super::GetParams(Params); int DiffWeight = 0, NormWeight = 0, SpecWeight = 0, SpecPowWeight = 0, OpWeight = 0, EmWeight = 0, CubeWeight = 0; + + int DetailWeight = 0, AOWEIGHT = 0, GlowMapWeight = 0, PaintMaskWeight = 0; + int TeamColorWeight = 0, ColorLookupWeight = 0, DecalTextureWeight = 0, TilingPatternWeight = 0; + int HexMaskWeight = 0, EnvironmentWeight = 0, ReflectionWeight = 0, OverlayWeight = 0; + int NoiseWeight = 0, RoughnessWeight = 0, MetallicWeight = 0; + #define DIFFUSE(check,weight) \ if (weight > DiffWeight && check) \ { \ @@ -2040,6 +2046,110 @@ void UMaterial3::GetParams(CMaterialParams &Params) const Params.EmissiveColor = Color; \ EmcWeight = weight; \ } +#define DETAIL(check,weight) \ + if (weight > DetailWeight && check) \ + { \ + Params.Detail = Tex; \ + DetailWeight = weight; \ + } + +#define AO(check,weight) \ + if (weight > AOWEIGHT && check) \ + { \ + Params.AO = Tex; \ + AOWEIGHT = weight; \ + } + +#define GLOWMAP(check,weight) \ + if (weight > GlowMapWeight && check) \ + { \ + Params.GlowMap = Tex; \ + GlowMapWeight = weight; \ + } + +#define PAINTMASK(check,weight) \ + if (weight > PaintMaskWeight && check) \ + { \ + Params.PaintMask = Tex; \ + PaintMaskWeight = weight; \ + } + +#define TEAMCOLOR(check,weight) \ + if (weight > TeamColorWeight && check) \ + { \ + Params.TeamColor = Tex; \ + TeamColorWeight = weight; \ + } + +#define COLORLOOKUP(check,weight) \ + if (weight > ColorLookupWeight && check) \ + { \ + Params.ColorLookup = Tex; \ + ColorLookupWeight = weight; \ + } + +#define DECALTEXTURE(check,weight) \ + if (weight > DecalTextureWeight && check) \ + { \ + Params.DecalTexture = Tex; \ + DecalTextureWeight = weight; \ + } + +#define TILINGPATTERN(check,weight) \ + if (weight > TilingPatternWeight && check) \ + { \ + Params.TilingPattern = Tex; \ + TilingPatternWeight = weight; \ + } + +#define HEXMASK(check,weight) \ + if (weight > HexMaskWeight && check) \ + { \ + Params.HexMask = Tex; \ + HexMaskWeight = weight; \ + } + +#define ENVIRONMENT(check,weight) \ + if (weight > EnvironmentWeight && check) \ + { \ + Params.Environment = Tex; \ + EnvironmentWeight = weight; \ + } + +#define REFLECTION(check,weight) \ + if (weight > ReflectionWeight && check) \ + { \ + Params.Reflection = Tex; \ + ReflectionWeight = weight; \ + } + +#define OVERLAY(check,weight) \ + if (weight > OverlayWeight && check) \ + { \ + Params.Overlay = Tex; \ + OverlayWeight = weight; \ + } + +#define NOISE(check,weight) \ + if (weight > NoiseWeight && check) \ + { \ + Params.Noise = Tex; \ + NoiseWeight = weight; \ + } + +#define ROUGHNESS(check,weight) \ + if (weight > RoughnessWeight && check) \ + { \ + Params.Roughness = Tex; \ + RoughnessWeight = weight; \ + } + +#define METALLIC(check,weight) \ + if (weight > MetallicWeight && check) \ + { \ + Params.Metallic = Tex; \ + MetallicWeight = weight; \ + } int ArGame = GetGame(); @@ -2056,8 +2166,8 @@ void UMaterial3::GetParams(CMaterialParams &Params) const //!! - separate code (common for UMaterial3 + UMaterialInstanceConstant) //!! - may implement with tables + macros //!! - catch normalmap, specular and emissive textures - if (strstr(Name, "noise")) continue; - if (strstr(Name, "detail")) continue; + //if (strstr(Name, "noise")) continue; + //if (strstr(Name, "detail")) continue; DIFFUSE(strstr(Name, "diff"), 100); NORMAL (strstr(Name, "norm"), 100); @@ -2065,6 +2175,27 @@ void UMaterial3::GetParams(CMaterialParams &Params) const DIFFUSE(strstr(Name, "_tex"), 60); DIFFUSE(!strcmp(Name + len - 2, "_d"), 20); OPACITY(strstr(Name, "_om"), 20); + // + /* + * + * PROC(Detail); + PROC(AO); + PROC(GlowMap); + PROC(PaintMask); + PROC(TeamColor); + PROC(ColorLookup); + PROC(DecalTexture); + PROC(TilingPattern); + PROC(HexMask); + PROC(Environment); + PROC(Reflection); + PROC(Overlay); + PROC(Noise); + PROC(Roughness); + PROC(Metallic); + * */ + // + // // CUBEMAP(strstr(Name, "cubemap"), 100); -- bad #if 0 if (!strcmp(Name + len - 3, "_di")) // The Last Remnant ... @@ -2152,12 +2283,35 @@ void UMaterial3::AppendReferencedTextures(TArray& OutTextures, for (int i = 0; i < ReferencedTextures.Num(); i++) { if (ReferencedTextures[i]) - OutTextures.AddUnique(ReferencedTextures[i]); + OutTextures.Add(ReferencedTextures[i]); } + for (int i = 0; i < Expressions.Num(); i++) + { + UObject* Expr = Expressions[i]; + if (Expr && Expr->IsA("Texture3")) + { + UTexture3* Tex = static_cast(Expr); + if (Tex) + OutTextures.AddUnique(Tex); + } + } + + for (int i = 0; i < Expressions.Num(); i++) + { + UObject* Expr = Expressions[i]; + if (Expr) + appPrintf("Expr[%d]: %s (%s)\n", i, Expr->Name, Expr->GetClassName()); + } + + if (ReferencedTextures.Num() == 0) + appPrintf("Warning: Material %s has no ReferencedTextures\n", Name); + } unguard; } + + void UTexture2D::SetupGL() { guard(UTexture2D::SetupGL); @@ -2572,6 +2726,7 @@ void UMaterialInstanceConstant::GetParams(CMaterialParams &Params) const void UMaterialInstanceConstant::AppendReferencedTextures(TArray& OutTextures, bool onlyRendered) const { guard(UMaterialInstanceConstant::AppendReferencedTextures); + if (onlyRendered) { // default implementation does that @@ -2579,10 +2734,14 @@ void UMaterialInstanceConstant::AppendReferencedTextures(TArrayName : ""); + if (Param.ParameterValue) + OutTextures.AddUnique(Param.ParameterValue); + } if (Parent && Parent != this) Parent->AppendReferencedTextures(OutTextures, onlyRendered); } diff --git a/Unreal/UnrealMaterial/UnMaterial.h b/Unreal/UnrealMaterial/UnMaterial.h index 18be6aec..4c9eeb5d 100644 --- a/Unreal/UnrealMaterial/UnMaterial.h +++ b/Unreal/UnrealMaterial/UnMaterial.h @@ -37,7 +37,22 @@ struct CMaterialParams PARAM(Opacity) \ PARAM(Emissive) \ PARAM(Cube) \ - PARAM(Mask) + PARAM(Mask) \ + PARAM(Detail) \ + PARAM(AO) \ + PARAM(GlowMap) \ + PARAM(PaintMask) \ + PARAM(TeamColor) \ + PARAM(ColorLookup) \ + PARAM(DecalTexture) \ + PARAM(TilingPattern) \ + PARAM(HexMask) \ + PARAM(Environment) \ + PARAM(Reflection) \ + PARAM(Overlay) \ + PARAM(Noise) \ + PARAM(Roughness) \ + PARAM(Metallic) bool IsNull() const { @@ -64,6 +79,24 @@ struct CMaterialParams UUnrealMaterial *Emissive; UUnrealMaterial *Cube; UUnrealMaterial *Mask; // multiple mask textures baked into a single one + //New + UUnrealMaterial* Detail; + UUnrealMaterial* AO; + UUnrealMaterial* GlowMap; + UUnrealMaterial* PaintMask; + UUnrealMaterial* TeamColor; + UUnrealMaterial* ColorLookup; + UUnrealMaterial* DecalTexture; + UUnrealMaterial* TilingPattern; + UUnrealMaterial* HexMask; + UUnrealMaterial* Environment; + UUnrealMaterial* Reflection; + UUnrealMaterial* Overlay; + UUnrealMaterial* Noise; + UUnrealMaterial* Roughness; + UUnrealMaterial* Metallic; + + // channels (used with Mask texture) ETextureCannel EmissiveChannel; ETextureCannel SpecularMaskChannel; diff --git a/Unreal/UnrealMaterial/UnMaterialExpression.h b/Unreal/UnrealMaterial/UnMaterialExpression.h index eadbb117..716966c6 100644 --- a/Unreal/UnrealMaterial/UnMaterialExpression.h +++ b/Unreal/UnrealMaterial/UnMaterialExpression.h @@ -122,6 +122,9 @@ class UMaterialExpressionVectorParameter : public UMaterialExpressionParameter REGISTER_CLASS(UMaterialExpressionScalarParameter) \ REGISTER_CLASS(UMaterialExpressionStaticBoolParameter) \ REGISTER_CLASS(UMaterialExpressionStaticSwitchParameter) \ - REGISTER_CLASS(UMaterialExpressionVectorParameter) + REGISTER_CLASS(UMaterialExpressionVectorParameter) + //REGISTER_CLASS(MaterialExpressionTextureSampleParameterCube) #endif // __UNMATERIAL_EXPRESSION_H__ + +//TODDO: MaterialExpressionTextureSampleParameterCube \ No newline at end of file diff --git a/Unreal/UnrealMaterial/UnTexture3.cpp b/Unreal/UnrealMaterial/UnTexture3.cpp index f37080aa..a03e060e 100644 --- a/Unreal/UnrealMaterial/UnTexture3.cpp +++ b/Unreal/UnrealMaterial/UnTexture3.cpp @@ -1146,6 +1146,10 @@ void UMaterial3::Serialize(FArchive &Ar) #endif Super::Serialize(Ar); + //printf("UMaterial3::Serialize: %s\n", Name); + //for() + + #if UNREAL4 if (Ar.Game >= GAME_UE4_BASE) { @@ -1193,25 +1197,32 @@ void UMaterial3::Serialize(FArchive &Ar) mask: int unkMask; // default 1 Ar << unkMask; - } - if (Ar.ArVer >= 656) + } if (Ar.ArVer >= 656) { guard(SerializeFMaterialResource); // Starting with version 656 UE3 has deprecated ReferencedTextures array. // This array is serialized inside FMaterialResource which is not needed // for us in other case. // FMaterialResource serialization is below + + TArray f10; - TMap f1C; + TMap TextureMap; int f58; FGuid f60; int f80; - Ar << f10 << f1C << f58 << f60 << f80; - if (Ar.ArVer >= 656) Ar << ReferencedTextures; // that is ... - // other fields are not interesting ... + //TArray sus; + + Ar << f10 << TextureMap << f58 << f60 << f80; + Ar << ReferencedTextures; + + + unguard; } DROP_REMAINING_DATA(Ar); //?? drop native data } + + #endif // UNREAL3 diff --git a/Unreal/UnrealPackage/UnPackage.cpp b/Unreal/UnrealPackage/UnPackage.cpp index 9c7ec1b2..91e834d8 100644 --- a/Unreal/UnrealPackage/UnPackage.cpp +++ b/Unreal/UnrealPackage/UnPackage.cpp @@ -13,6 +13,23 @@ /*----------------------------------------------------------------------------- Unreal package structures -----------------------------------------------------------------------------*/ +class UMissingTexture : public UObject +{ +public: + + FString TexturePath; + + static const CTypeInfo* StaticGetTypeinfo() + { + static const CTypeInfo type("UTexture2D", NULL, sizeof(UMissingTexture), NULL, 0, TYPE_None, NULL, NULL); + return &type; + } + virtual const CTypeInfo* GetTypeinfo() const override + { + return StaticGetTypeinfo(); + } + +}; bool FPackageFileSummary::Serialize(FArchive &Ar) { @@ -1141,10 +1158,29 @@ UObject* UnPackage::CreateImport(int index) if (ObjIndex == INDEX_NONE) { appPrintf("WARNING: Import(%s.%s) was not found\n", PackageName, *Imp.ObjectName); - Imp.Missing = true; - return NULL; + //Imp.Missing = true; + UObject* Dummy = new UMissingTexture(); + + Dummy->Name = Imp.ObjectName; + Dummy->PackageIndex = INDEX_NONE; + //Dummy->Package = NULL; + + //UnPackage* FakePackage = new UnPackage("MissingPackage.upk", NULL, true); + Dummy->Package = NULL; + + // Cast to access TexturePath + UMissingTexture* MissingTex = static_cast(Dummy); + char buf[256]; + appSprintf(ARRAY_ARG(buf), "%s.%s", PackageName, *Imp.ObjectName); + MissingTex->TexturePath = buf; + + appPrintf("Creating dummy texture for metadata: %s\n", *MissingTex->TexturePath); + return MissingTex; + } } + + #endif // UNREAL3 // at this point we have either Package == NULL (not found) or Package != NULL and ObjIndex is valid @@ -1365,3 +1401,4 @@ TArray MissingPackages; unguardf("%s", *File->GetRelativeName()); } + diff --git a/build.bat b/build.bat new file mode 100644 index 00000000..13fc8438 --- /dev/null +++ b/build.bat @@ -0,0 +1,42 @@ +@echo off +setlocal + +set "PATH=C:\Users\lauri\Documents\Github\UEViewer\BuildTools\bin;%PATH%" + +rem Source and destination +set "SRC=.\umodel_64.exe" +set "DST=C:\p4v\laurynas_RocketLeague\Plugins\ProjectPlugins\MapImporter\Source\MapImporter\UModel\umodel_64.exe" + +rem Build first (bash returns nonzero on failure) +bash build.sh --64 +if errorlevel 1 ( + echo Build failed, aborting. + exit /b 1 +) + +rem If destination exists, delete it and verify deletion succeeded +if exist "%DST%" ( + echo Destination exists, attempting to delete "%DST%". + del /F /Q "%DST%" + if exist "%DST%" ( + echo ERROR: failed to delete "%DST%". + exit /b 1 + ) + echo Deleted existing file. +) + +rem Copy and verify +copy /Y "%SRC%" "%DST%" >nul +if errorlevel 1 ( + echo ERROR: copy failed. + exit /b 1 +) + +if not exist "%DST%" ( + echo ERROR: destination not found after copy. + exit /b 1 +) + +echo Copy succeeded. +endlocal +exit /b 0 \ No newline at end of file diff --git a/umodel.exe b/umodel.exe deleted file mode 100644 index 9e202fb5..00000000 Binary files a/umodel.exe and /dev/null differ