commit 681c69c4ac267fd6bebd891e8cd6bcc929f8c7e8 Author: Christian Semmler Date: Thu May 16 19:42:54 2024 -0400 initial commit diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..5d97094c --- /dev/null +++ b/.clang-format @@ -0,0 +1,36 @@ +BasedOnStyle: Microsoft + +AccessModifierOffset: -4 +AlignAfterOpenBracket: BlockIndent +AllowAllArgumentsOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BracedInitializerIndentWidth: 4 +BraceWrapping: + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterStruct: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +EmptyLineBeforeAccessModifier: Always +IncludeBlocks: Regroup +IndentAccessModifiers: false +IndentWidth: 4 +InsertNewlineAtEOF: true +PointerAlignment: Left +QualifierAlignment: Custom +QualifierOrder: + - inline + - static + - friend + - const + - volatile + - type +RemoveSemicolon: true +SpaceAfterCStyleCast: true +TabWidth: 4 +UseTab: ForContinuationAndIndentation diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000..189ddf5a --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,6 @@ +Checks: > + -*, + readability-braces-around-statements, + modernize-use-override +WarningsAsErrors: '-*,readability-braces-around-statements,modernize-use-override' +HeaderFilterRegex: ".*" diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..4ec14ca6 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +root = true + +[*.{py,txt,editorconfig}] +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{cpp,h}] +indent_style = tab +tab_width = 4 +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..232342c7 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +*.MD text eol=lf diff=markdown +*.cpp text eol=lf diff=cpp +*.h text eol=lf diff=cpp +*.py text eol=lf diff=python +*.html text eol=lf diff=html +*.mdp binary +*.mak text eol=crlf diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml new file mode 100644 index 00000000..8e903cc1 --- /dev/null +++ b/.github/workflows/analyze.yml @@ -0,0 +1,26 @@ +name: Analyze + +on: [push, pull_request] + +jobs: + decomplint-isle: + name: '${{ matrix.who }} annotations' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + who: + - CONFIG + - ISLE + - LEGO1 + + steps: + - uses: actions/checkout@v4 + + - name: Install python libraries + run: | + python -m pip install -r tools/requirements.txt + + - name: Run decomplint.py + run: | + tools/decomplint/decomplint.py ${{ matrix.who }} --module ${{ matrix.who }} --warnfail diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..efbe1c2e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,209 @@ +name: Build + +on: [push, pull_request] + +jobs: + fetch-deps: + name: Download original binaries + uses: ./.github/workflows/legobin.yml + + build-current-toolchain: + name: 'Current ${{ matrix.toolchain.name }}' + runs-on: windows-latest + defaults: + run: + shell: ${{ matrix.toolchain.shell }} + strategy: + fail-fast: false + matrix: + toolchain: + - { name: 'MSVC', shell: 'sh', setup-cmake: true, setup-ninja: true, setup-msvc: true } + - { name: 'msys2 mingw32', shell: 'msys2 {0}', msystem: mingw32, msys-env: mingw-w64-i686, clang-tidy: true, werror: true } + - { name: 'msys2 clang32', shell: 'msys2 {0}', msystem: clang32, msys-env: mingw-w64-clang-i686, clang-tidy: true, werror: true, no-dx5-libs: true } + + steps: + - name: Set up MSYS2 + if: ${{ !!matrix.toolchain.msystem }} + uses: msys2/setup-msys2@v2 + with: + msystem: ${{ matrix.toolchain.msystem }} + install: >- + ${{ matrix.toolchain.msys-env }}-cc + ${{ matrix.toolchain.msys-env }}-cmake + ${{ matrix.toolchain.msys-env }}-ninja + ${{ matrix.toolchain.msys-env }}-clang-tools-extra + + - name: Setup cmake + if: matrix.toolchain.setup-cmake + uses: jwlawson/actions-setup-cmake@v1.13 + + - name: Setup ninja + if: matrix.toolchain.setup-ninja + uses: ashutoshvarma/setup-ninja@master + + - name: Setup vcvars + if: matrix.toolchain.setup-msvc + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: amd64_x86 # Use the 64-bit x64-native cross tools to build 32-bit x86 code + + - uses: actions/checkout@v4 + + - name: Build + run: | + cmake -S . -B build -GNinja \ + -DCMAKE_BUILD_TYPE=Debug \ + -DISLE_USE_DX5_LIBS=${{ !matrix.toolchain.no-dx5-libs }} \ + -DENABLE_CLANG_TIDY=${{ !!matrix.toolchain.clang-tidy }} \ + -DISLE_WERROR=${{ !!matrix.toolchain.werror }} \ + -Werror=dev + cmake --build build -- -k0 + + build: + name: 'MSVC 4.20' + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + + - uses: actions/checkout@v4 + with: + repository: 'itsmattkc/msvc420' + path: msvc420 + + - name: Setup cmake + uses: jwlawson/actions-setup-cmake@v1.13 + with: + # Use minimum supported version + cmake-version: '3.15.x' + + - name: Patch MSVC 4.2 + run: | + tools/patch_c2.py msvc420/bin/C2.EXE + + - name: Build + shell: cmd + run: | + call .\msvc420\bin\VCVARS32.BAT x86 + cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -G "NMake Makefiles" + cmake --build build + + - name: Upload Artifact + uses: actions/upload-artifact@master + with: + name: Win32 + path: | + build/CONFIG.EXE + build/CONFIG.PDB + build/ISLE.EXE + build/ISLE.PDB + build/LEGO1.DLL + build/LEGO1.PDB + + compare: + name: 'Compare with master' + needs: [build, fetch-deps] + runs-on: windows-latest + steps: + - uses: actions/checkout@master + + - uses: actions/download-artifact@master + with: + name: Win32 + path: build + + - name: Restore cached original binaries + id: cache-original-binaries + uses: actions/cache/restore@v3 + with: + enableCrossOsArchive: true + path: legobin + key: legobin + + - name: Install python packages + shell: bash + run: | + pip install -r tools/requirements.txt + + - name: Summarize Accuracy + shell: bash + run: | + python3 tools/reccmp/reccmp.py -S CONFIGPROGRESS.SVG --svg-icon tools/reccmp/config.png -H CONFIGPROGRESS.HTML legobin/CONFIG.EXE build/CONFIG.EXE build/CONFIG.PDB . | tee CONFIGPROGRESS.TXT + python3 tools/reccmp/reccmp.py -S ISLEPROGRESS.SVG --svg-icon tools/reccmp/isle.png -H ISLEPROGRESS.HTML legobin/ISLE.EXE build/ISLE.EXE build/ISLE.PDB . | tee ISLEPROGRESS.TXT + python3 tools/reccmp/reccmp.py -S LEGO1PROGRESS.SVG -T 4252 --svg-icon tools/reccmp/lego1.png -H LEGO1PROGRESS.HTML legobin/LEGO1.DLL build/LEGO1.DLL build/LEGO1.PDB . | tee LEGO1PROGRESS.TXT + + - name: Compare Accuracy With Current Master + shell: bash + run: | + # Compare with current master + curl -fLSs -o CONFIGPROGRESS-OLD.TXT https://github.com/isledecomp/isle/releases/download/continuous/CONFIGPROGRESS.TXT || echo "" >CONFIGPROGRESS-OLD.TXT + curl -fLSs -o ISLEPROGRESS-OLD.TXT https://github.com/isledecomp/isle/releases/download/continuous/ISLEPROGRESS.TXT || echo "" >ISLEPROGRESS-OLD.TXT + curl -fLSs -o LEGO1PROGRESS-OLD.TXT https://github.com/isledecomp/isle/releases/download/continuous/LEGO1PROGRESS.TXT || echo "" >LEGO1PROGRESS-OLD.TXT + + diff -u0 CONFIGPROGRESS-OLD.TXT CONFIGPROGRESS.TXT || true + diff -u0 ISLEPROGRESS-OLD.TXT ISLEPROGRESS.TXT || true + diff -u0 LEGO1PROGRESS-OLD.TXT LEGO1PROGRESS.TXT || true + + - name: Test Exports + shell: bash + run: | + tools/verexp/verexp.py legobin/LEGO1.DLL build/LEGO1.DLL + + - name: Check Vtables + shell: bash + run: | + python3 tools/vtable/vtable.py legobin/CONFIG.EXE build/CONFIG.EXE build/CONFIG.PDB . + python3 tools/vtable/vtable.py legobin/ISLE.EXE build/ISLE.EXE build/ISLE.PDB . + python3 tools/vtable/vtable.py legobin/LEGO1.DLL build/LEGO1.DLL build/LEGO1.PDB . + + - name: Check Variables + shell: bash + run: | + python3 tools/datacmp.py legobin/CONFIG.EXE build/CONFIG.EXE build/CONFIG.PDB . + python3 tools/datacmp.py legobin/ISLE.EXE build/ISLE.EXE build/ISLE.PDB . + python3 tools/datacmp.py legobin/LEGO1.DLL build/LEGO1.DLL build/LEGO1.PDB . + + - name: Upload Artifact + uses: actions/upload-artifact@master + with: + name: Accuracy Report + path: | + CONFIGPROGRESS.* + ISLEPROGRESS.* + LEGO1PROGRESS.* + + upload: + name: 'Upload artifacts' + needs: [build, compare] + runs-on: ubuntu-latest + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'isledecomp/isle' }} + steps: + - uses: actions/checkout@v4 + with: + repository: 'probonopd/uploadtool' + + - uses: actions/download-artifact@master + with: + name: Win32 + path: build + + - uses: actions/download-artifact@master + with: + name: Accuracy Report + + - name: Upload Continuous Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + UPLOAD_KEY: ${{ secrets.UPLOAD_KEY }} + run: | + ./upload.sh \ + build/CONFIG.EXE \ + build/ISLE.EXE \ + build/LEGO1.DLL \ + CONFIGPROGRESS.* \ + ISLEPROGRESS.* \ + LEGO1PROGRESS.* + + curl -X POST -F key=$UPLOAD_KEY -F 'file=@CONFIGPROGRESS.SVG' https://legoisland.org/progress/ + curl -X POST -F key=$UPLOAD_KEY -F 'file=@ISLEPROGRESS.SVG' https://legoisland.org/progress/ + curl -X POST -F key=$UPLOAD_KEY -F 'file=@LEGO1PROGRESS.SVG' https://legoisland.org/progress/ diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 00000000..9432beb0 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,37 @@ +name: Format + +on: [push, pull_request] + +jobs: + clang-format: + name: 'C++' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Run clang-format + run: | + find CONFIG LEGO1 ISLE -iname '*.h' -o -iname '*.cpp' | xargs \ + pipx run "clang-format>=17,<18" \ + --style=file \ + -i + git diff --exit-code + + python-format: + name: 'Python' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install python libraries + shell: bash + run: | + pip install black==23.* pylint==3.* pytest==7.* -r tools/requirements.txt + + - name: Run pylint and black + shell: bash + run: | + pylint tools --ignore=build,ncc + black --check tools --exclude=ncc diff --git a/.github/workflows/legobin.yml b/.github/workflows/legobin.yml new file mode 100644 index 00000000..d9b42bc2 --- /dev/null +++ b/.github/workflows/legobin.yml @@ -0,0 +1,32 @@ +name: Download legobin + +on: + workflow_call: + +jobs: + fetch: + runs-on: ubuntu-latest + steps: + + - name: Restore cached original binaries + id: cache-original-binaries + uses: actions/cache/restore@v3 + with: + enableCrossOsArchive: true + path: legobin + key: legobin + + - name: Download original island binaries + if: ${{ !steps.cache-original-binaries.outputs.cache-hit }} + run: | + wget https://legoisland.org/download/CONFIG.EXE --directory-prefix=legobin + wget https://legoisland.org/download/ISLE.EXE --directory-prefix=legobin + wget https://legoisland.org/download/LEGO1.DLL --directory-prefix=legobin + + - name: Cache original binaries + if: ${{ !steps.cache-original-binaries.outputs.cache-hit }} + uses: actions/cache/save@v3 + with: + enableCrossOsArchive: true + path: legobin + key: legobin diff --git a/.github/workflows/naming.yml b/.github/workflows/naming.yml new file mode 100644 index 00000000..3afed885 --- /dev/null +++ b/.github/workflows/naming.yml @@ -0,0 +1,43 @@ +name: Naming + +on: [push, pull_request] + +jobs: + ncc: + name: 'C++' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install LLVM and Clang + uses: KyleMayes/install-llvm-action@v1 + with: + version: "16" + + - name: Install python libraries + run: | + pip install -r tools/requirements.txt + + - name: Run ncc + run: | + action_headers=$(find LEGO1/lego/legoomni/include/actions \ + -name '*.h' -print0 | xargs -0 echo) + + python3 tools/ncc/ncc.py \ + --clang-lib ${{ env.LLVM_PATH }}/lib/libclang.so \ + --recurse \ + --style tools/ncc/ncc.style \ + --skip tools/ncc/skip.yml \ + --definition WINAPI FAR BOOL CALLBACK HWND__=HWND \ + --include \ + util \ + LEGO1 \ + LEGO1/omni/include \ + LEGO1/lego/legoomni/include \ + LEGO1/lego/sources \ + --exclude \ + LEGO1/omni/include/flic.h \ + LEGO1/omni/src/video/flic.cpp \ + $action_headers \ + --path LEGO1/omni LEGO1/lego/legoomni diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml new file mode 100644 index 00000000..b1dee943 --- /dev/null +++ b/.github/workflows/unittest.yml @@ -0,0 +1,60 @@ +name: Test + +on: [push, pull_request] + +jobs: + fetch-deps: + name: Download original binaries + uses: ./.github/workflows/legobin.yml + + pytest-win: + name: 'Python Windows' + runs-on: windows-latest + needs: fetch-deps + + steps: + - uses: actions/checkout@v4 + + - name: Restore cached original binaries + id: cache-original-binaries + uses: actions/cache/restore@v3 + with: + enableCrossOsArchive: true + path: legobin + key: legobin + + - name: Install python libraries + shell: bash + run: | + pip install pytest -r tools/requirements.txt + + - name: Run python unit tests (Windows) + shell: bash + run: | + pytest tools/isledecomp --lego1=legobin/LEGO1.DLL + + pytest-ubuntu: + name: 'Python Linux' + runs-on: ubuntu-latest + needs: fetch-deps + + steps: + - uses: actions/checkout@v4 + + - name: Restore cached original binaries + id: cache-original-binaries + uses: actions/cache/restore@v3 + with: + enableCrossOsArchive: true + path: legobin + key: legobin + + - name: Install python libraries + shell: bash + run: | + pip install pytest -r tools/requirements.txt + + - name: Run python unit tests (Ubuntu) + shell: bash + run: | + pytest tools/isledecomp --lego1=legobin/LEGO1.DLL diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7e16a6ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +Debug/ +Release/ +*.ncb +/.vs +/.vscode +/.idea +.env +.venv +env/ +venv/ +ENV/ +VENV/ +env.bak/ +venv.bak/ +ISLE.EXE +LEGO1.DLL +/build/ +*.swp +LEGO1PROGRESS.* +ISLEPROGRESS.* +*.pyc diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 00000000..ab83fceb --- /dev/null +++ b/.pylintrc @@ -0,0 +1,635 @@ +[MAIN] + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Clear in-memory caches upon conclusion of linting. Useful if running pylint +# in a server-like mode. +clear-cache-post-run=no + +# Load and enable all available extensions. Use --list-extensions to see a list +# all available extensions. +#enable-all-extensions= + +# In error mode, messages with a category besides ERROR or FATAL are +# suppressed, and no reports are done by default. Error mode is compatible with +# disabling specific errors. +#errors-only= + +# Always return a 0 (non-error) status code, even if lint errors are found. +# This is primarily useful in continuous integration scripts. +#exit-zero= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. +extension-pkg-allow-list= + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code. (This is an alternative name to extension-pkg-allow-list +# for backward compatibility.) +extension-pkg-whitelist= + +# Return non-zero exit code if any of these messages/categories are detected, +# even if score is above --fail-under value. Syntax same as enable. Messages +# specified are enabled, while categories only check already-enabled messages. +fail-on= + +# Specify a score threshold under which the program will exit with error. +fail-under=10 + +# Interpret the stdin as a python script, whose filename needs to be passed as +# the module_or_package argument. +#from-stdin= + +# Files or directories to be skipped. They should be base names, not paths. +ignore=CVS + +# Add files or directories matching the regular expressions patterns to the +# ignore-list. The regex matches against paths and can be in Posix or Windows +# format. Because '\\' represents the directory delimiter on Windows systems, +# it can't be used as an escape character. +ignore-paths= + +# Files or directories matching the regular expression patterns are skipped. +# The regex matches against base names, not paths. The default value ignores +# Emacs file locks +ignore-patterns=^\.# + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis). It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use, and will cap the count on Windows to +# avoid hangs. +jobs=1 + +# Control the amount of potential inferred values when inferring a single +# object. This can help the performance when dealing with large functions or +# complex, nested conditions. +limit-inference-results=100 + +# List of plugins (as comma separated values of python module names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Minimum Python version to use for version dependent checks. Will default to +# the version used to run pylint. +py-version=3.11 + +# Discover python modules and packages in the file system subtree. +recursive=no + +# Add paths to the list of the source roots. Supports globbing patterns. The +# source root is an absolute path or a path relative to the current working +# directory used to determine a package namespace for modules located under the +# source root. +source-roots= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages. +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# In verbose mode, extra non-checker-related info will be displayed. +#verbose= + + +[BASIC] + +# Naming style matching correct argument names. +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style. If left empty, argument names will be checked with the set +# naming style. +#argument-rgx= + +# Naming style matching correct attribute names. +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style. If left empty, attribute names will be checked with the set naming +# style. +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma. +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Bad variable names regexes, separated by a comma. If names match any regex, +# they will always be refused +bad-names-rgxs= + +# Naming style matching correct class attribute names. +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style. If left empty, class attribute names will be checked +# with the set naming style. +#class-attribute-rgx= + +# Naming style matching correct class constant names. +class-const-naming-style=UPPER_CASE + +# Regular expression matching correct class constant names. Overrides class- +# const-naming-style. If left empty, class constant names will be checked with +# the set naming style. +#class-const-rgx= + +# Naming style matching correct class names. +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming- +# style. If left empty, class names will be checked with the set naming style. +#class-rgx= + +# Naming style matching correct constant names. +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style. If left empty, constant names will be checked with the set naming +# style. +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names. +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style. If left empty, function names will be checked with the set +# naming style. +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma. +good-names=i, + j, + k, + ex, + Run, + _ + +# Good variable names regexes, separated by a comma. If names match any regex, +# they will always be accepted +good-names-rgxs= + +# Include a hint for the correct naming format with invalid-name. +include-naming-hint=no + +# Naming style matching correct inline iteration names. +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style. If left empty, inline iteration names will be checked +# with the set naming style. +#inlinevar-rgx= + +# Naming style matching correct method names. +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style. If left empty, method names will be checked with the set naming style. +#method-rgx= + +# Naming style matching correct module names. +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style. If left empty, module names will be checked with the set naming style. +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +# These decorators are taken in consideration only for invalid-name. +property-classes=abc.abstractproperty + +# Regular expression matching correct type alias names. If left empty, type +# alias names will be checked with the set naming style. +#typealias-rgx= + +# Regular expression matching correct type variable names. If left empty, type +# variable names will be checked with the set naming style. +#typevar-rgx= + +# Naming style matching correct variable names. +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style. If left empty, variable names will be checked with the set +# naming style. +#variable-rgx= + + +[CLASSES] + +# Warn about protected attribute access inside special methods +check-protected-access-in-special-methods=no + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp, + asyncSetUp, + __post_init__ + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# List of regular expressions of class ancestor names to ignore when counting +# public methods (see R0903) +exclude-too-few-public-methods= + +# List of qualified class names to ignore when counting class parents (see +# R0901) +ignored-parents= + +# Maximum number of arguments for function / method. +max-args=6 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in an if statement (see R0916). +max-bool-expr=5 + +# Maximum number of branch for function / method body. +max-branches=30 + +# Maximum number of locals for function / method body. +max-locals=30 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body. +max-returns=6 + +# Maximum number of statements in function / method body. +max-statements=75 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=0 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when caught. +overgeneral-exceptions=builtins.BaseException,builtins.Exception + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=2 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=200 + +# Maximum number of lines in a module. +max-module-lines=1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[IMPORTS] + +# List of modules that can be imported at any level, not just the top level +# one. +allow-any-import-level= + +# Allow explicit reexports by alias from a package __init__. +allow-reexport-from-package=no + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Deprecated modules which should not be used, separated by a comma. +deprecated-modules= + +# Output a graph (.gv or any supported image format) of external dependencies +# to the given file (report RP0402 must not be disabled). +ext-import-graph= + +# Output a graph (.gv or any supported image format) of all (i.e. internal and +# external) dependencies to the given file (report RP0402 must not be +# disabled). +import-graph= + +# Output a graph (.gv or any supported image format) of internal dependencies +# to the given file (report RP0402 must not be disabled). +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + +# Couples of modules and preferred modules, separated by a comma. +preferred-modules= + + +[LOGGING] + +# The type of string formatting that logging methods do. `old` means using % +# formatting, `new` is for `{}` formatting. +logging-format-style=old + +# Logging modules to check that the string format arguments are in logging +# function parameter format. +logging-modules=logging + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE, +# UNDEFINED. +confidence=HIGH, + CONTROL_FLOW, + INFERENCE, + INFERENCE_FAILURE, + UNDEFINED + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once). You can also use "--disable=all" to +# disable everything first and then re-enable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use "--disable=all --enable=classes +# --disable=W". +disable=raw-checker-failed, + bad-inline-option, + locally-disabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + use-symbolic-message-instead, + missing-class-docstring, + missing-function-docstring, + missing-module-docstring, + fixme + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[METHOD_ARGS] + +# List of qualified names (i.e., library.method) which require a timeout +# parameter e.g. 'requests.api.get,requests.api.post' +timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + +# Regular expression of note tags to take in consideration. +notes-rgx= + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=sys.exit,argparse.parse_error + + +[REPORTS] + +# Python expression which should return a score less than or equal to 10. You +# have access to the variables 'fatal', 'error', 'warning', 'refactor', +# 'convention', and 'info' which contain the number of messages in each +# category, as well as 'statement' which is the total number of statements +# analyzed. This score is used by the global evaluation report (RP0004). +evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details. +msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio). You can also give a reporter class, e.g. +# mypackage.mymodule.MyReporterClass. +#output-format= + +# Tells whether to display a full report or only the messages. +reports=no + +# Activate the evaluation score. +score=yes + + +[SIMILARITIES] + +# Comments are removed from the similarity computation +ignore-comments=yes + +# Docstrings are removed from the similarity computation +ignore-docstrings=yes + +# Imports are removed from the similarity computation +ignore-imports=yes + +# Signatures are removed from the similarity computation +ignore-signatures=yes + +# Minimum lines number of a similarity. +min-similarity-lines=16 + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes. +max-spelling-suggestions=4 + +# Spelling dictionary name. No available dictionaries : You need to install +# both the python package and the system dependency for enchant to work.. +spelling-dict= + +# List of comma separated words that should be considered directives if they +# appear at the beginning of a comment and should not be checked. +spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy: + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains the private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to the private dictionary (see the +# --spelling-private-dict-file option) instead of raising a message. +spelling-store-unknown-words=no + + +[STRING] + +# This flag controls whether inconsistent-quotes generates a warning when the +# character used as a quote delimiter is used inconsistently within a module. +check-quote-consistency=no + +# This flag controls whether the implicit-str-concat should generate a warning +# on implicit string concatenation in sequences defined over several lines. +check-str-concat-over-line-jumps=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether to warn about missing members when the owner of the attribute +# is inferred to be None. +ignore-none=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of symbolic message names to ignore for Mixin members. +ignored-checks-for-mixins=no-member, + not-async-context-manager, + not-context-manager, + attribute-defined-outside-init + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + +# Regex pattern to define which classes are considered mixins. +mixin-class-rgx=.*[Mm]ixin + +# List of decorators that change the signature of a decorated function. +signature-mutators= + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid defining new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of names allowed to shadow builtins +allowed-redefined-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expected to +# not be used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io diff --git a/3rdparty/dx5/inc/d3d.h b/3rdparty/dx5/inc/d3d.h new file mode 100644 index 00000000..b50fe404 --- /dev/null +++ b/3rdparty/dx5/inc/d3d.h @@ -0,0 +1,896 @@ +/*==========================================================================; + * + * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. + * + * File: d3d.h + * Content: Direct3D include file + * + ***************************************************************************/ + +#ifndef _D3D_H_ +#define _D3D_H_ + +#include + +#ifdef _WIN32 +#define COM_NO_WINDOWS_H +#include +#else +#include "d3dcom.h" +#endif + +#ifdef _WIN32 +#define D3DAPI WINAPI +#else +#define D3DAPI +#endif + +/* + * Interface IID's + */ +#if defined( _WIN32 ) && !defined( _NO_COM) +DEFINE_GUID( IID_IDirect3D, 0x3BBA0080,0x2421,0x11CF,0xA3,0x1A,0x00,0xAA,0x00,0xB9,0x33,0x56 ); +DEFINE_GUID( IID_IDirect3D2, 0x6aae1ec1,0x662a,0x11d0,0x88,0x9d,0x00,0xaa,0x00,0xbb,0xb7,0x6a); + +DEFINE_GUID( IID_IDirect3DRampDevice, 0xF2086B20,0x259F,0x11CF,0xA3,0x1A,0x00,0xAA,0x00,0xB9,0x33,0x56 ); +DEFINE_GUID( IID_IDirect3DRGBDevice, 0xA4665C60,0x2673,0x11CF,0xA3,0x1A,0x00,0xAA,0x00,0xB9,0x33,0x56 ); +DEFINE_GUID( IID_IDirect3DHALDevice, 0x84E63dE0,0x46AA,0x11CF,0x81,0x6F,0x00,0x00,0xC0,0x20,0x15,0x6E ); +DEFINE_GUID( IID_IDirect3DMMXDevice, 0x881949a1,0xd6f3,0x11d0,0x89,0xab,0x00,0xa0,0xc9,0x05,0x41,0x29 ); + +DEFINE_GUID( IID_IDirect3DDevice, 0x64108800,0x957d,0X11d0,0x89,0xab,0x00,0xa0,0xc9,0x05,0x41,0x29 ); +DEFINE_GUID( IID_IDirect3DDevice2, 0x93281501, 0x8cf8, 0x11d0, 0x89, 0xab, 0x0, 0xa0, 0xc9, 0x5, 0x41, 0x29); +DEFINE_GUID( IID_IDirect3DTexture, 0x2CDCD9E0,0x25A0,0x11CF,0xA3,0x1A,0x00,0xAA,0x00,0xB9,0x33,0x56 ); +DEFINE_GUID( IID_IDirect3DTexture2, 0x93281502, 0x8cf8, 0x11d0, 0x89, 0xab, 0x0, 0xa0, 0xc9, 0x5, 0x41, 0x29); +DEFINE_GUID( IID_IDirect3DLight, 0x4417C142,0x33AD,0x11CF,0x81,0x6F,0x00,0x00,0xC0,0x20,0x15,0x6E ); +DEFINE_GUID( IID_IDirect3DMaterial, 0x4417C144,0x33AD,0x11CF,0x81,0x6F,0x00,0x00,0xC0,0x20,0x15,0x6E ); +DEFINE_GUID( IID_IDirect3DMaterial2, 0x93281503, 0x8cf8, 0x11d0, 0x89, 0xab, 0x0, 0xa0, 0xc9, 0x5, 0x41, 0x29); +DEFINE_GUID( IID_IDirect3DExecuteBuffer,0x4417C145,0x33AD,0x11CF,0x81,0x6F,0x00,0x00,0xC0,0x20,0x15,0x6E ); +DEFINE_GUID( IID_IDirect3DViewport, 0x4417C146,0x33AD,0x11CF,0x81,0x6F,0x00,0x00,0xC0,0x20,0x15,0x6E ); +DEFINE_GUID( IID_IDirect3DViewport2, 0x93281500, 0x8cf8, 0x11d0, 0x89, 0xab, 0x0, 0xa0, 0xc9, 0x5, 0x41, 0x29); +#endif + +/* + * Data structures + */ +#ifdef __cplusplus + +/* 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined */ +struct IDirect3D; +struct IDirect3D2; +struct IDirect3DDevice; +struct IDirect3DDevice2; +struct IDirect3DExecuteBuffer; +struct IDirect3DLight; +struct IDirect3DMaterial; +struct IDirect3DMaterial2; +struct IDirect3DTexture; +struct IDirect3DTexture2; +struct IDirect3DViewport; +struct IDirect3DViewport2; +typedef struct IDirect3D *LPDIRECT3D; +typedef struct IDirect3D2 *LPDIRECT3D2; +typedef struct IDirect3DDevice *LPDIRECT3DDEVICE; +typedef struct IDirect3DDevice2 *LPDIRECT3DDEVICE2; +typedef struct IDirect3DExecuteBuffer *LPDIRECT3DEXECUTEBUFFER; +typedef struct IDirect3DLight *LPDIRECT3DLIGHT; +typedef struct IDirect3DMaterial *LPDIRECT3DMATERIAL; +typedef struct IDirect3DMaterial2 *LPDIRECT3DMATERIAL2; +typedef struct IDirect3DTexture *LPDIRECT3DTEXTURE; +typedef struct IDirect3DTexture2 *LPDIRECT3DTEXTURE2; +typedef struct IDirect3DViewport *LPDIRECT3DVIEWPORT; +typedef struct IDirect3DViewport2 *LPDIRECT3DVIEWPORT2; + +#else + +typedef struct IDirect3D *LPDIRECT3D; +typedef struct IDirect3D2 *LPDIRECT3D2; +typedef struct IDirect3DDevice *LPDIRECT3DDEVICE; +typedef struct IDirect3DDevice2 *LPDIRECT3DDEVICE2; +typedef struct IDirect3DExecuteBuffer *LPDIRECT3DEXECUTEBUFFER; +typedef struct IDirect3DLight *LPDIRECT3DLIGHT; +typedef struct IDirect3DMaterial *LPDIRECT3DMATERIAL; +typedef struct IDirect3DMaterial2 *LPDIRECT3DMATERIAL2; +typedef struct IDirect3DTexture *LPDIRECT3DTEXTURE; +typedef struct IDirect3DTexture2 *LPDIRECT3DTEXTURE2; +typedef struct IDirect3DViewport *LPDIRECT3DVIEWPORT; +typedef struct IDirect3DViewport2 *LPDIRECT3DVIEWPORT2; + +#endif + +#include "d3dtypes.h" +#include "d3dcaps.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * IDirect3D + */ +#undef INTERFACE +#define INTERFACE IDirect3D +DECLARE_INTERFACE_(IDirect3D, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3D methods ***/ + STDMETHOD(Initialize) (THIS_ REFIID) PURE; + STDMETHOD(EnumDevices)(THIS_ LPD3DENUMDEVICESCALLBACK, LPVOID) PURE; + STDMETHOD(CreateLight) (THIS_ LPDIRECT3DLIGHT*, IUnknown*) PURE; + STDMETHOD(CreateMaterial) (THIS_ LPDIRECT3DMATERIAL*, IUnknown*) PURE; + STDMETHOD(CreateViewport) (THIS_ LPDIRECT3DVIEWPORT*, IUnknown*) PURE; + STDMETHOD(FindDevice)(THIS_ LPD3DFINDDEVICESEARCH, LPD3DFINDDEVICERESULT) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3D_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3D_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3D_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3D_Initialize(p, a) (p)->lpVtbl->Initialize(p, a) +#define IDirect3D_EnumDevices(p, a, b) (p)->lpVtbl->EnumDevices(p, a, b) +#define IDirect3D_CreateLight(p, a, b) (p)->lpVtbl->CreateLight(p, a, b) +#define IDirect3D_CreateMaterial(p, a, b) (p)->lpVtbl->CreateMaterial(p, a, b) +#define IDirect3D_CreateViewport(p, a, b) (p)->lpVtbl->CreateViewport(p, a, b) +#define IDirect3D_FindDevice(p, a, b) (p)->lpVtbl->FindDevice(p, a, b) +#else +#define IDirect3D_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3D_AddRef(p) (p)->AddRef() +#define IDirect3D_Release(p) (p)->Release() +#define IDirect3D_Initialize(p, a) (p)->Initialize(a) +#define IDirect3D_EnumDevices(p, a, b) (p)->EnumDevices(a, b) +#define IDirect3D_CreateLight(p, a, b) (p)->CreateLight(a, b) +#define IDirect3D_CreateMaterial(p, a, b) (p)->CreateMaterial(a, b) +#define IDirect3D_CreateViewport(p, a, b) (p)->CreateViewport(a, b) +#define IDirect3D_FindDevice(p, a, b) (p)->FindDevice(a, b) +#endif + +/* + * IDirect3D2 + */ +#undef INTERFACE +#define INTERFACE IDirect3D2 +DECLARE_INTERFACE_(IDirect3D2, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3D methods ***/ + STDMETHOD(EnumDevices)(THIS_ LPD3DENUMDEVICESCALLBACK, LPVOID) PURE; + STDMETHOD(CreateLight) (THIS_ LPDIRECT3DLIGHT*, IUnknown*) PURE; + STDMETHOD(CreateMaterial) (THIS_ LPDIRECT3DMATERIAL2*, IUnknown*) PURE; + STDMETHOD(CreateViewport) (THIS_ LPDIRECT3DVIEWPORT2*, IUnknown*) PURE; + STDMETHOD(FindDevice)(THIS_ LPD3DFINDDEVICESEARCH, LPD3DFINDDEVICERESULT) PURE; + + STDMETHOD(CreateDevice)(THIS_ REFCLSID, LPDIRECTDRAWSURFACE, LPDIRECT3DDEVICE2 *) PURE; + +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3D2_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3D2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3D2_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3D2_EnumDevices(p, a, b) (p)->lpVtbl->EnumDevices(p, a, b) +#define IDirect3D2_CreateLight(p, a, b) (p)->lpVtbl->CreateLight(p, a, b) +#define IDirect3D2_CreateMaterial(p, a, b) (p)->lpVtbl->CreateMaterial(p, a, b) +#define IDirect3D2_CreateViewport(p, a, b) (p)->lpVtbl->CreateViewport(p, a, b) +#define IDirect3D2_FindDevice(p, a, b) (p)->lpVtbl->FindDevice(p, a, b) +#define IDirect3D2_CreateDevice(p, a, b, c) (p)->lpVtbl->CreateDevice(p, a, b, c) +#else +#define IDirect3D2_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3D2_AddRef(p) (p)->AddRef() +#define IDirect3D2_Release(p) (p)->Release() +#define IDirect3D2_EnumDevices(p, a, b) (p)->EnumDevices(a, b) +#define IDirect3D2_CreateLight(p, a, b) (p)->CreateLight(a, b) +#define IDirect3D2_CreateMaterial(p, a, b) (p)->CreateMaterial(a, b) +#define IDirect3D2_CreateViewport(p, a, b) (p)->CreateViewport(a, b) +#define IDirect3D2_FindDevice(p, a, b) (p)->FindDevice(a, b) +#define IDirect3D2_CreateDevice(p, a, b, c) (p)->CreateDevice(a, b, c) +#endif + +/* + * IDirect3DDevice + */ +#undef INTERFACE +#define INTERFACE IDirect3DDevice +DECLARE_INTERFACE_(IDirect3DDevice, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DDevice methods ***/ + STDMETHOD(Initialize) (THIS_ LPDIRECT3D, LPGUID, LPD3DDEVICEDESC) PURE; + STDMETHOD(GetCaps) (THIS_ LPD3DDEVICEDESC, LPD3DDEVICEDESC) PURE; + STDMETHOD(SwapTextureHandles) (THIS_ LPDIRECT3DTEXTURE, LPDIRECT3DTEXTURE) PURE; + STDMETHOD(CreateExecuteBuffer) (THIS_ LPD3DEXECUTEBUFFERDESC, LPDIRECT3DEXECUTEBUFFER*, IUnknown*) PURE; + STDMETHOD(GetStats) (THIS_ LPD3DSTATS) PURE; + STDMETHOD(Execute) (THIS_ LPDIRECT3DEXECUTEBUFFER, LPDIRECT3DVIEWPORT, DWORD) PURE; + STDMETHOD(AddViewport) (THIS_ LPDIRECT3DVIEWPORT) PURE; + STDMETHOD(DeleteViewport) (THIS_ LPDIRECT3DVIEWPORT) PURE; + STDMETHOD(NextViewport) (THIS_ LPDIRECT3DVIEWPORT, LPDIRECT3DVIEWPORT*, DWORD) PURE; + STDMETHOD(Pick) (THIS_ LPDIRECT3DEXECUTEBUFFER, LPDIRECT3DVIEWPORT, DWORD, LPD3DRECT) PURE; + STDMETHOD(GetPickRecords)(THIS_ LPDWORD, LPD3DPICKRECORD) PURE; + STDMETHOD(EnumTextureFormats) (THIS_ LPD3DENUMTEXTUREFORMATSCALLBACK, LPVOID) PURE; + STDMETHOD(CreateMatrix) (THIS_ LPD3DMATRIXHANDLE) PURE; + STDMETHOD(SetMatrix) (THIS_ D3DMATRIXHANDLE, const LPD3DMATRIX) PURE; + STDMETHOD(GetMatrix) (THIS_ D3DMATRIXHANDLE, LPD3DMATRIX) PURE; + STDMETHOD(DeleteMatrix) (THIS_ D3DMATRIXHANDLE) PURE; + STDMETHOD_(HRESULT, BeginScene) (THIS) PURE; + STDMETHOD_(HRESULT, EndScene) (THIS) PURE; + STDMETHOD(GetDirect3D) (THIS_ LPDIRECT3D*) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DDevice_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DDevice_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DDevice_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DDevice_Initialize(p, a, b, c) (p)->lpVtbl->Initialize(p, a, b, c) +#define IDirect3DDevice_GetCaps(p, a, b) (p)->lpVtbl->GetCaps(p, a, b) +#define IDirect3DDevice_SwapTextureHandles(p, a, b) (p)->lpVtbl->SwapTextureHandles(p, a, b) +#define IDirect3DDevice_CreateExecuteBuffer(p, a, b, c) (p)->lpVtbl->CreateExecuteBuffer(p, a, b, c) +#define IDirect3DDevice_GetStats(p, a) (p)->lpVtbl->GetStats(p, a) +#define IDirect3DDevice_Execute(p, a, b, c) (p)->lpVtbl->Execute(p, a, b, c) +#define IDirect3DDevice_AddViewport(p, a) (p)->lpVtbl->AddViewport(p, a) +#define IDirect3DDevice_DeleteViewport(p, a) (p)->lpVtbl->DeleteViewport(p, a) +#define IDirect3DDevice_NextViewport(p, a, b) (p)->lpVtbl->NextViewport(p, a, b) +#define IDirect3DDevice_Pick(p, a, b, c, d) (p)->lpVtbl->Pick(p, a, b, c, d) +#define IDirect3DDevice_GetPickRecords(p, a, b) (p)->lpVtbl->GetPickRecords(p, a, b) +#define IDirect3DDevice_EnumTextureFormats(p, a, b) (p)->lpVtbl->EnumTextureFormats(p, a, b) +#define IDirect3DDevice_CreateMatrix(p, a) (p)->lpVtbl->CreateMatrix(p, a) +#define IDirect3DDevice_SetMatrix(p, a, b) (p)->lpVtbl->SetMatrix(p, a, b) +#define IDirect3DDevice_GetMatrix(p, a, b) (p)->lpVtbl->GetMatrix(p, a, b) +#define IDirect3DDevice_DeleteMatrix(p, a) (p)->lpVtbl->DeleteMatrix(p, a) +#define IDirect3DDevice_BeginScene(p) (p)->lpVtbl->BeginScene(p) +#define IDirect3DDevice_EndScene(p) (p)->lpVtbl->EndScene(p) +#define IDirect3DDevice_GetDirect3D(p, a) (p)->lpVtbl->GetDirect3D(p, a) +#else +#define IDirect3DDevice_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DDevice_AddRef(p) (p)->AddRef() +#define IDirect3DDevice_Release(p) (p)->Release() +#define IDirect3DDevice_Initialize(p, a, b, c) (p)->Initialize(a, b, c) +#define IDirect3DDevice_GetCaps(p, a, b) (p)->GetCaps(a, b) +#define IDirect3DDevice_SwapTextureHandles(p, a, b) (p)->SwapTextureHandles(a, b) +#define IDirect3DDevice_CreateExecuteBuffer(p, a, b, c) (p)->CreateExecuteBuffer(a, b, c) +#define IDirect3DDevice_GetStats(p, a) (p)->GetStats(a) +#define IDirect3DDevice_Execute(p, a, b, c) (p)->Execute(a, b, c) +#define IDirect3DDevice_AddViewport(p, a) (p)->AddViewport(a) +#define IDirect3DDevice_DeleteViewport(p, a) (p)->DeleteViewport(a) +#define IDirect3DDevice_NextViewport(p, a, b) (p)->NextViewport(a, b) +#define IDirect3DDevice_Pick(p, a, b, c, d) (p)->Pick(a, b, c, d) +#define IDirect3DDevice_GetPickRecords(p, a, b) (p)->GetPickRecords(a, b) +#define IDirect3DDevice_EnumTextureFormats(p, a, b) (p)->EnumTextureFormats(a, b) +#define IDirect3DDevice_CreateMatrix(p, a) (p)->CreateMatrix(a) +#define IDirect3DDevice_SetMatrix(p, a, b) (p)->SetMatrix(a, b) +#define IDirect3DDevice_GetMatrix(p, a, b) (p)->GetMatrix(a, b) +#define IDirect3DDevice_DeleteMatrix(p, a) (p)->DeleteMatrix(a) +#define IDirect3DDevice_BeginScene(p) (p)->BeginScene() +#define IDirect3DDevice_EndScene(p) (p)->EndScene() +#define IDirect3DDevice_GetDirect3D(p, a) (p)->GetDirect3D(a) +#endif + +/* + * IDirect3DDevice2 + */ +#undef INTERFACE +#define INTERFACE IDirect3DDevice2 +DECLARE_INTERFACE_(IDirect3DDevice2, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DDevice2 methods ***/ + STDMETHOD(GetCaps) (THIS_ LPD3DDEVICEDESC, LPD3DDEVICEDESC) PURE; + STDMETHOD(SwapTextureHandles) (THIS_ LPDIRECT3DTEXTURE2, LPDIRECT3DTEXTURE2) PURE; + STDMETHOD(GetStats) (THIS_ LPD3DSTATS) PURE; + STDMETHOD(AddViewport) (THIS_ LPDIRECT3DVIEWPORT2) PURE; + STDMETHOD(DeleteViewport) (THIS_ LPDIRECT3DVIEWPORT2) PURE; + STDMETHOD(NextViewport) (THIS_ LPDIRECT3DVIEWPORT2, LPDIRECT3DVIEWPORT2*, DWORD) PURE; + STDMETHOD(EnumTextureFormats) (THIS_ LPD3DENUMTEXTUREFORMATSCALLBACK, LPVOID) PURE; + STDMETHOD_(HRESULT, BeginScene) (THIS) PURE; + STDMETHOD_(HRESULT, EndScene) (THIS) PURE; + STDMETHOD(GetDirect3D) (THIS_ LPDIRECT3D2*) PURE; + + /*** DrawPrimitive API ***/ + STDMETHOD(SetCurrentViewport) (THIS_ LPDIRECT3DVIEWPORT2) PURE; + STDMETHOD(GetCurrentViewport) (THIS_ LPDIRECT3DVIEWPORT2 *) PURE; + + STDMETHOD(SetRenderTarget) (THIS_ LPDIRECTDRAWSURFACE, DWORD) PURE; + STDMETHOD(GetRenderTarget) (THIS_ LPDIRECTDRAWSURFACE *) PURE; + + STDMETHOD(Begin) (THIS_ D3DPRIMITIVETYPE, D3DVERTEXTYPE, DWORD) PURE; + STDMETHOD(BeginIndexed) (THIS_ D3DPRIMITIVETYPE, D3DVERTEXTYPE, LPVOID, DWORD, DWORD) PURE; + STDMETHOD(Vertex) (THIS_ LPVOID) PURE; + STDMETHOD(Index) (THIS_ WORD) PURE; + STDMETHOD(End) (THIS_ DWORD) PURE; + + STDMETHOD(GetRenderState) (THIS_ D3DRENDERSTATETYPE, LPDWORD) PURE; + STDMETHOD(SetRenderState) (THIS_ D3DRENDERSTATETYPE, DWORD) PURE; + STDMETHOD(GetLightState) (THIS_ D3DLIGHTSTATETYPE, LPDWORD) PURE; + STDMETHOD(SetLightState) (THIS_ D3DLIGHTSTATETYPE, DWORD) PURE; + STDMETHOD(SetTransform) (THIS_ D3DTRANSFORMSTATETYPE, LPD3DMATRIX) PURE; + STDMETHOD(GetTransform) (THIS_ D3DTRANSFORMSTATETYPE, LPD3DMATRIX) PURE; + STDMETHOD(MultiplyTransform) (THIS_ D3DTRANSFORMSTATETYPE, LPD3DMATRIX) PURE; + + STDMETHOD(DrawPrimitive) (THIS_ D3DPRIMITIVETYPE, D3DVERTEXTYPE, LPVOID, DWORD, DWORD) PURE; + STDMETHOD(DrawIndexedPrimitive) (THIS_ D3DPRIMITIVETYPE, D3DVERTEXTYPE, LPVOID, DWORD, LPWORD, DWORD, DWORD) PURE; + + STDMETHOD(SetClipStatus) (THIS_ LPD3DCLIPSTATUS) PURE; + STDMETHOD(GetClipStatus) (THIS_ LPD3DCLIPSTATUS) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DDevice2_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DDevice2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DDevice2_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DDevice2_GetCaps(p, a, b) (p)->lpVtbl->GetCaps(p, a, b) +#define IDirect3DDevice2_SwapTextureHandles(p, a, b) (p)->lpVtbl->SwapTextureHandles(p, a, b) +#define IDirect3DDevice2_GetStats(p, a) (p)->lpVtbl->CreateViewport(p, a) +#define IDirect3DDevice2_AddViewport(p, a) (p)->lpVtbl->AddViewport(p, a) +#define IDirect3DDevice2_DeleteViewport(p, a) (p)->lpVtbl->DeleteViewport(p, a) +#define IDirect3DDevice2_NextViewport(p, a, b) (p)->lpVtbl->NextViewport(p, a, b) +#define IDirect3DDevice2_EnumTextureFormats(p, a, b) (p)->lpVtbl->EnumTextureFormats(p, a, b) +#define IDirect3DDevice2_BeginScene(p) (p)->lpVtbl->BeginScene(p) +#define IDirect3DDevice2_EndScene(p) (p)->lpVtbl->EndScene(p) +#define IDirect3DDevice2_GetDirect3D(p, a) (p)->lpVtbl->GetDirect3D(p, a) + +#define IDirect3DDevice2_SetCurrentViewport(p, a) (p)->lpVtbl->SetCurrentViewport(p, a) +#define IDirect3DDevice2_GetCurrentViewport(p, a) (p)->lpVtbl->GetCurrentViewport(p, a) + +#define IDirect3DDevice2_SetRenderTarget(p, a, b) (p)->lpVtbl->SetRenderTarget(p, a, b) +#define IDirect3DDevice2_GetRenderTarget(p, a) (p)->lpVtbl->GetRenderTarget(p, a) + +#define IDirect3DDevice2_Begin(p, a, b, c) (p)->lpVtbl->Begin(p, a, b, c) +#define IDirect3DDevice2_BeginIndexed(p, a, b, c, d, e) (p)->lpVtbl->Begin(p, a, b, c, d, e) +#define IDirect3DDevice2_Vertex(p, a) (p)->lpVtbl->Vertex(p, a) +#define IDirect3DDevice2_Index(p, a) (p)->lpVtbl->Index(p, a) +#define IDirect3DDevice2_End(p, a) (p)->lpVtbl->End(p, a) + +#define IDirect3DDevice2_GetRenderState(p, a, b) (p)->lpVtbl->GetRenderState(p, a, b) +#define IDirect3DDevice2_SetRenderState(p, a, b) (p)->lpVtbl->SetRenderState(p, a, b) +#define IDirect3DDevice2_GetLightState(p, a, b) (p)->lpVtbl->GetLightState(p, a, b) +#define IDirect3DDevice2_SetLightState(p, a, b) (p)->lpVtbl->SetLightState(p, a, b) +#define IDirect3DDevice2_SetTransform(p, a, b) (p)->lpVtbl->SetTransform(p, a, b) +#define IDirect3DDevice2_GetTransform(p, a, b) (p)->lpVtbl->GetTransform(p, a, b) +#define IDirect3DDevice2_MultiplyTransform(p, a, b) (p)->lpVtbl->MultiplyTransform(p, a, b) + +#define IDirect3DDevice2_DrawPrimitive(p, a, b, c, d, e) (p)->lpVtbl->DrawPrimitive(p, a, b, c, d, e) +#define IDirect3DDevice2_DrawIndexedPrimitive(p, a, b, c, d, e, f, g) \ + (p)->lpVtbl->DrawIndexedPrimitive(p, a, b, c, d, e, f, g) +#define IDirect3DDevice2_SetClipStatus(p, a) (p)->lpVtbl->SetClipStatus(p, a) +#define IDirect3DDevice2_GetClipStatus(p, a) (p)->lpVtbl->GetClipStatus(p, a) +#else +#define IDirect3DDevice2_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DDevice2_AddRef(p) (p)->AddRef() +#define IDirect3DDevice2_Release(p) (p)->Release() +#define IDirect3DDevice2_GetCaps(p, a, b) (p)->GetCaps(a, b) +#define IDirect3DDevice2_SwapTextureHandles(p, a, b) (p)->SwapTextureHandles(a, b) +#define IDirect3DDevice2_GetStats(p, a) (p)->CreateViewport(a) +#define IDirect3DDevice2_AddViewport(p, a) (p)->AddViewport(a) +#define IDirect3DDevice2_DeleteViewport(p, a) (p)->DeleteViewport(a) +#define IDirect3DDevice2_NextViewport(p, a, b) (p)->NextViewport(a, b) +#define IDirect3DDevice2_EnumTextureFormats(p, a, b) (p)->EnumTextureFormats(a, b) +#define IDirect3DDevice2_BeginScene(p) (p)->BeginScene() +#define IDirect3DDevice2_EndScene(p) (p)->EndScene() +#define IDirect3DDevice2_GetDirect3D(p, a) (p)->GetDirect3D(a) + +#define IDirect3DDevice2_SetCurrentViewport(p, a) (p)->SetCurrentViewport(a) +#define IDirect3DDevice2_GetCurrentViewport(p, a) (p)->GetCurrentViewport(a) + +#define IDirect3DDevice2_SetRenderTarget(p, a, b) (p)->SetRenderTarget(a, b) +#define IDirect3DDevice2_GetRenderTarget(p, a) (p)->GetRenderTarget(a) + +#define IDirect3DDevice2_Begin(p, a, b, c) (p)->Begin(a, b, c) +#define IDirect3DDevice2_BeginIndexed(p, a, b, c, d, e) (p)->Begin(a, b, c, d, e) +#define IDirect3DDevice2_Vertex(p, a) (p)->Vertex(a) +#define IDirect3DDevice2_Index(p, a) (p)->Index(a) +#define IDirect3DDevice2_End(p, a) (p)->End(a) + +#define IDirect3DDevice2_GetRenderState(p, a, b) (p)->GetRenderState(a, b) +#define IDirect3DDevice2_SetRenderState(p, a, b) (p)->SetRenderState(a, b) +#define IDirect3DDevice2_GetLightState(p, a, b) (p)->GetLightState(a, b) +#define IDirect3DDevice2_SetLightState(p, a, b) (p)->SetLightState(a, b) +#define IDirect3DDevice2_SetTransform(p, a, b) (p)->SetTransform(a, b) +#define IDirect3DDevice2_GetTransform(p, a, b) (p)->GetTransform(a, b) +#define IDirect3DDevice2_MultiplyTransform(p, a, b) (p)->MultiplyTransform(a, b) + +#define IDirect3DDevice2_DrawPrimitive(p, a, b, c, d, e) (p)->DrawPrimitive(a, b, c, d, e) +#define IDirect3DDevice2_DrawIndexedPrimitive(p, a, b, c, d, e, f, g) \ + (p)->DrawIndexedPrimitive(a, b, c, d, e, f, g) +#define IDirect3DDevice2_SetClipStatus(p, a) (p)->SetClipStatus(a) +#define IDirect3DDevice2_GetClipStatus(p, a) (p)->GetClipStatus(a) + +#endif + +/* + * IDirect3DExecuteBuffer + */ +#undef INTERFACE +#define INTERFACE IDirect3DExecuteBuffer +DECLARE_INTERFACE_(IDirect3DExecuteBuffer, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DExecuteBuffer methods ***/ + STDMETHOD(Initialize) (THIS_ LPDIRECT3DDEVICE, LPD3DEXECUTEBUFFERDESC) PURE; + STDMETHOD(Lock) (THIS_ LPD3DEXECUTEBUFFERDESC) PURE; + STDMETHOD_(HRESULT, Unlock) (THIS) PURE; + STDMETHOD(SetExecuteData) (THIS_ LPD3DEXECUTEDATA) PURE; + STDMETHOD(GetExecuteData) (THIS_ LPD3DEXECUTEDATA) PURE; + STDMETHOD(Validate) (THIS_ LPDWORD, LPD3DVALIDATECALLBACK, LPVOID, DWORD) PURE; + STDMETHOD(Optimize) (THIS_ DWORD) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DExecuteBuffer_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DExecuteBuffer_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DExecuteBuffer_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DExecuteBuffer_Initialize(p, a, b) (p)->lpVtbl->Initialize(p, a, b) +#define IDirect3DExecuteBuffer_Lock(p, a) (p)->lpVtbl->Lock(p, a) +#define IDirect3DExecuteBuffer_Unlock(p) (p)->lpVtbl->Unlock(p) +#define IDirect3DExecuteBuffer_SetExecuteData(p, a) (p)->lpVtbl->SetExecuteData(p, a) +#define IDirect3DExecuteBuffer_GetExecuteData(p, a) (p)->lpVtbl->GetExecuteData(p, a) +#define IDirect3DExecuteBuffer_Validate(p, a, b, c, d) (p)->lpVtbl->Validate(p, a, b, c, d) +#define IDirect3DExecuteBuffer_Optimize(p, a) (p)->lpVtbl->Optimize(p, a) +#else +#define IDirect3DExecuteBuffer_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DExecuteBuffer_AddRef(p) (p)->AddRef() +#define IDirect3DExecuteBuffer_Release(p) (p)->Release() +#define IDirect3DExecuteBuffer_Initialize(p, a, b) (p)->Initialize(a, b) +#define IDirect3DExecuteBuffer_Lock(p, a) (p)->Lock(a) +#define IDirect3DExecuteBuffer_Unlock(p) (p)->Unlock() +#define IDirect3DExecuteBuffer_SetExecuteData(p, a) (p)->SetExecuteData(a) +#define IDirect3DExecuteBuffer_GetExecuteData(p, a) (p)->GetExecuteData(a) +#define IDirect3DExecuteBuffer_Validate(p, a, b, c, d) (p)->Validate(a, b, c, d) +#define IDirect3DExecuteBuffer_Optimize(p, a) (p)->Optimize(a) +#endif + +/* + * IDirect3DLight + */ +#undef INTERFACE +#define INTERFACE IDirect3DLight +DECLARE_INTERFACE_(IDirect3DLight, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DLight methods ***/ + STDMETHOD(Initialize) (THIS_ LPDIRECT3D) PURE; + STDMETHOD(SetLight) (THIS_ LPD3DLIGHT) PURE; + STDMETHOD(GetLight) (THIS_ LPD3DLIGHT) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DLight_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DLight_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DLight_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DLight_Initialize(p, a) (p)->lpVtbl->Initialize(p, a) +#define IDirect3DLight_SetLight(p, a) (p)->lpVtbl->SetLight(p, a) +#define IDirect3DLight_GetLight(p, a) (p)->lpVtbl->GetLight(p, a) +#else +#define IDirect3DLight_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DLight_AddRef(p) (p)->AddRef() +#define IDirect3DLight_Release(p) (p)->Release() +#define IDirect3DLight_Initialize(p, a) (p)->Initialize(a) +#define IDirect3DLight_SetLight(p, a) (p)->SetLight(a) +#define IDirect3DLight_GetLight(p, a) (p)->GetLight(a) +#endif + +/* + * IDirect3DMaterial + */ +#undef INTERFACE +#define INTERFACE IDirect3DMaterial +DECLARE_INTERFACE_(IDirect3DMaterial, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DMaterial methods ***/ + STDMETHOD(Initialize) (THIS_ LPDIRECT3D) PURE; + STDMETHOD(SetMaterial) (THIS_ LPD3DMATERIAL) PURE; + STDMETHOD(GetMaterial) (THIS_ LPD3DMATERIAL) PURE; + STDMETHOD(GetHandle) (THIS_ LPDIRECT3DDEVICE, LPD3DMATERIALHANDLE) PURE; + STDMETHOD_(HRESULT, Reserve) (THIS) PURE; + STDMETHOD_(HRESULT, Unreserve) (THIS) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DMaterial_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DMaterial_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DMaterial_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DMaterial_Initialize(p, a) (p)->lpVtbl->Initialize(p, a) +#define IDirect3DMaterial_SetMaterial(p, a) (p)->lpVtbl->SetMaterial(p, a) +#define IDirect3DMaterial_GetMaterial(p, a) (p)->lpVtbl->GetMaterial(p, a) +#define IDirect3DMaterial_GetHandle(p, a, b) (p)->lpVtbl->GetHandle(p, a, b) +#define IDirect3DMaterial_Reserve(p) (p)->lpVtbl->Reserve(p) +#define IDirect3DMaterial_Unreserve(p) (p)->lpVtbl->Unreserve(p) +#else +#define IDirect3DMaterial_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DMaterial_AddRef(p) (p)->AddRef() +#define IDirect3DMaterial_Release(p) (p)->Release() +#define IDirect3DMaterial_Initialize(p, a) (p)->Initialize(a) +#define IDirect3DMaterial_SetMaterial(p, a) (p)->SetMaterial(a) +#define IDirect3DMaterial_GetMaterial(p, a) (p)->GetMaterial(a) +#define IDirect3DMaterial_GetHandle(p, a, b) (p)->GetHandle(a, b) +#define IDirect3DMaterial_Reserve(p) (p)->Reserve() +#define IDirect3DMaterial_Unreserve(p) (p)->Unreserve() +#endif + +/* + * IDirect3DMaterial2 + */ +#undef INTERFACE +#define INTERFACE IDirect3DMaterial2 +DECLARE_INTERFACE_(IDirect3DMaterial2, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DMaterial2 methods ***/ + STDMETHOD(SetMaterial) (THIS_ LPD3DMATERIAL) PURE; + STDMETHOD(GetMaterial) (THIS_ LPD3DMATERIAL) PURE; + STDMETHOD(GetHandle) (THIS_ LPDIRECT3DDEVICE2, LPD3DMATERIALHANDLE) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DMaterial2_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DMaterial2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DMaterial2_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DMaterial2_SetMaterial(p, a) (p)->lpVtbl->SetMaterial(p, a) +#define IDirect3DMaterial2_GetMaterial(p, a) (p)->lpVtbl->GetMaterial(p, a) +#define IDirect3DMaterial2_GetHandle(p, a, b) (p)->lpVtbl->GetHandle(p, a, b) +#else +#define IDirect3DMaterial2_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DMaterial2_AddRef(p) (p)->AddRef() +#define IDirect3DMaterial2_Release(p) (p)->Release() +#define IDirect3DMaterial2_SetMaterial(p, a) (p)->SetMaterial(a) +#define IDirect3DMaterial2_GetMaterial(p, a) (p)->GetMaterial(a) +#define IDirect3DMaterial2_GetHandle(p, a, b) (p)->GetHandle(a, b) +#endif + +/* + * IDirect3DTexture + */ +#undef INTERFACE +#define INTERFACE IDirect3DTexture +DECLARE_INTERFACE_(IDirect3DTexture, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DTexture methods ***/ + STDMETHOD(Initialize) (THIS_ LPDIRECT3DDEVICE, LPDIRECTDRAWSURFACE) PURE; + STDMETHOD(GetHandle) (THIS_ LPDIRECT3DDEVICE, LPD3DTEXTUREHANDLE) PURE; + STDMETHOD(PaletteChanged) (THIS_ DWORD, DWORD) PURE; + STDMETHOD(Load) (THIS_ LPDIRECT3DTEXTURE) PURE; + STDMETHOD_(HRESULT, Unload) (THIS) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DTexture_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DTexture_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DTexture_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DTexture_Initialize(p, a, b) (p)->lpVtbl->Initialize(p, a, b) +#define IDirect3DTexture_GetHandle(p, a, b) (p)->lpVtbl->GetHandle(p, a, b) +#define IDirect3DTexture_PaletteChanged(p, a, b) (p)->lpVtbl->PaletteChanged(p, a, b) +#define IDirect3DTexture_Load(p, a) (p)->lpVtbl->Load(p, a) +#define IDirect3DTexture_Unload(p) (p)->lpVtbl->Unload(p) +#else +#define IDirect3DTexture_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DTexture_AddRef(p) (p)->AddRef() +#define IDirect3DTexture_Release(p) (p)->Release() +#define IDirect3DTexture_Initialize(p, a, b) (p)->Initialize(a, b) +#define IDirect3DTexture_GetHandle(p, a, b) (p)->GetHandle(a, b) +#define IDirect3DTexture_PaletteChanged(p, a, b) (p)->PaletteChanged(a, b) +#define IDirect3DTexture_Load(p, a) (p)->Load(a) +#define IDirect3DTexture_Unload(p) (p)->Unload() +#endif + +/* + * IDirect3DTexture2 + */ +#undef INTERFACE +#define INTERFACE IDirect3DTexture2 +DECLARE_INTERFACE_(IDirect3DTexture2, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DTexture2 methods ***/ + STDMETHOD(GetHandle) (THIS_ LPDIRECT3DDEVICE2, LPD3DTEXTUREHANDLE) PURE; + STDMETHOD(PaletteChanged) (THIS_ DWORD, DWORD) PURE; + STDMETHOD(Load) (THIS_ LPDIRECT3DTEXTURE2) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DTexture2_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DTexture2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DTexture2_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DTexture2_GetHandle(p, a, b) (p)->lpVtbl->GetHandle(p, a, b) +#define IDirect3DTexture2_PaletteChanged(p, a, b) (p)->lpVtbl->PaletteChanged(p, a, b) +#define IDirect3DTexture2_Load(p, a) (p)->lpVtbl->Load(p, a) +#else +#define IDirect3DTexture2_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DTexture2_AddRef(p) (p)->AddRef() +#define IDirect3DTexture2_Release(p) (p)->Release() +#define IDirect3DTexture2_GetHandle(p, a, b) (p)->GetHandle(a, b) +#define IDirect3DTexture2_PaletteChanged(p, a, b) (p)->PaletteChanged(a, b) +#define IDirect3DTexture2_Load(p, a) (p)->Load(a) +#endif + +/* + * IDirect3DViewport + */ +#undef INTERFACE +#define INTERFACE IDirect3DViewport +DECLARE_INTERFACE_(IDirect3DViewport, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DViewport methods ***/ + STDMETHOD(Initialize) (THIS_ LPDIRECT3D) PURE; + STDMETHOD(GetViewport) (THIS_ LPD3DVIEWPORT) PURE; + STDMETHOD(SetViewport) (THIS_ LPD3DVIEWPORT) PURE; + STDMETHOD(TransformVertices) (THIS_ DWORD, LPD3DTRANSFORMDATA, DWORD, LPDWORD) PURE; + STDMETHOD(LightElements) (THIS_ DWORD, LPD3DLIGHTDATA) PURE; + STDMETHOD(SetBackground) (THIS_ D3DMATERIALHANDLE) PURE; + STDMETHOD(GetBackground) (THIS_ LPD3DMATERIALHANDLE, LPBOOL) PURE; + STDMETHOD(SetBackgroundDepth) (THIS_ LPDIRECTDRAWSURFACE) PURE; + STDMETHOD(GetBackgroundDepth) (THIS_ LPDIRECTDRAWSURFACE*, LPBOOL) PURE; + STDMETHOD(Clear) (THIS_ DWORD, LPD3DRECT, DWORD) PURE; + STDMETHOD(AddLight) (THIS_ LPDIRECT3DLIGHT) PURE; + STDMETHOD(DeleteLight) (THIS_ LPDIRECT3DLIGHT) PURE; + STDMETHOD(NextLight) (THIS_ LPDIRECT3DLIGHT, LPDIRECT3DLIGHT*, DWORD) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DViewport_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DViewport_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DViewport_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DViewport_Initialize(p, a) (p)->lpVtbl->Initialize(p, a) +#define IDirect3DViewport_GetViewport(p, a) (p)->lpVtbl->GetViewport(p, a) +#define IDirect3DViewport_SetViewport(p, a) (p)->lpVtbl->SetViewport(p, a) +#define IDirect3DViewport_TransformVertices(p, a, b, c, d) (p)->lpVtbl->TransformVertices(p, a, b, c, d) +#define IDirect3DViewport_LightElements(p, a, b) (p)->lpVtbl->LightElements(p, a, b) +#define IDirect3DViewport_SetBackground(p, a) (p)->lpVtbl->SetBackground(p, a) +#define IDirect3DViewport_GetBackground(p, a, b) (p)->lpVtbl->GetBackground(p, a, b) +#define IDirect3DViewport_SetBackgroundDepth(p, a) (p)->lpVtbl->SetBackgroundDepth(p, a) +#define IDirect3DViewport_GetBackgroundDepth(p, a, b) (p)->lpVtbl->GetBackgroundDepth(p, a, b) +#define IDirect3DViewport_Clear(p, a, b, c) (p)->lpVtbl->Clear(p, a, b, c) +#define IDirect3DViewport_AddLight(p, a) (p)->lpVtbl->AddLight(p, a) +#define IDirect3DViewport_DeleteLight(p, a) (p)->lpVtbl->DeleteLight(p, a) +#define IDirect3DViewport_NextLight(p, a, b, c) (p)->lpVtbl->NextLight(p, a, b, c) +#else +#define IDirect3DViewport_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DViewport_AddRef(p) (p)->AddRef() +#define IDirect3DViewport_Release(p) (p)->Release() +#define IDirect3DViewport_Initialize(p, a) (p)->Initialize(a) +#define IDirect3DViewport_GetViewport(p, a) (p)->GetViewport(a) +#define IDirect3DViewport_SetViewport(p, a) (p)->SetViewport(a) +#define IDirect3DViewport_TransformVertices(p, a, b, c, d) (p)->TransformVertices(a, b, c, d) +#define IDirect3DViewport_LightElements(p, a, b) (p)->LightElements(a, b) +#define IDirect3DViewport_SetBackground(p, a) (p)->SetBackground(a) +#define IDirect3DViewport_GetBackground(p, a, b) (p)->GetBackground(a, b) +#define IDirect3DViewport_SetBackgroundDepth(p, a) (p)->SetBackgroundDepth(a) +#define IDirect3DViewport_GetBackgroundDepth(p, a, b) (p)->GetBackgroundDepth(a, b) +#define IDirect3DViewport_Clear(p, a, b, c) (p)->Clear(a, b, c) +#define IDirect3DViewport_AddLight(p, a) (p)->AddLight(a) +#define IDirect3DViewport_DeleteLight(p, a) (p)->DeleteLight(a) +#define IDirect3DViewport_NextLight(p, a, b, c) (p)->NextLight(a, b, c) +#endif + +/* + * IDirect3DViewport2 + */ +#undef INTERFACE +#define INTERFACE IDirect3DViewport2 +DECLARE_INTERFACE_(IDirect3DViewport2, IDirect3DViewport) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID* ppvObj) PURE; + STDMETHOD_(ULONG, AddRef) (THIS) PURE; + STDMETHOD_(ULONG, Release) (THIS) PURE; + /*** IDirect3DViewport methods ***/ + STDMETHOD(Initialize) (THIS_ LPDIRECT3D) PURE; + STDMETHOD(GetViewport) (THIS_ LPD3DVIEWPORT) PURE; + STDMETHOD(SetViewport) (THIS_ LPD3DVIEWPORT) PURE; + STDMETHOD(TransformVertices) (THIS_ DWORD, LPD3DTRANSFORMDATA, DWORD, LPDWORD) PURE; + STDMETHOD(LightElements) (THIS_ DWORD, LPD3DLIGHTDATA) PURE; + STDMETHOD(SetBackground) (THIS_ D3DMATERIALHANDLE) PURE; + STDMETHOD(GetBackground) (THIS_ LPD3DMATERIALHANDLE, LPBOOL) PURE; + STDMETHOD(SetBackgroundDepth) (THIS_ LPDIRECTDRAWSURFACE) PURE; + STDMETHOD(GetBackgroundDepth) (THIS_ LPDIRECTDRAWSURFACE*, LPBOOL) PURE; + STDMETHOD(Clear) (THIS_ DWORD, LPD3DRECT, DWORD) PURE; + STDMETHOD(AddLight) (THIS_ LPDIRECT3DLIGHT) PURE; + STDMETHOD(DeleteLight) (THIS_ LPDIRECT3DLIGHT) PURE; + STDMETHOD(NextLight) (THIS_ LPDIRECT3DLIGHT, LPDIRECT3DLIGHT*, DWORD) PURE; + /*** IDirect3DViewport2 methods ***/ + STDMETHOD(GetViewport2) (THIS_ LPD3DVIEWPORT2) PURE; + STDMETHOD(SetViewport2) (THIS_ LPD3DVIEWPORT2) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirect3DViewport2_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirect3DViewport2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirect3DViewport2_Release(p) (p)->lpVtbl->Release(p) +#define IDirect3DViewport2_Initialize(p, a) (p)->lpVtbl->Initialize(p, a) +#define IDirect3DViewport2_GetViewport(p, a) (p)->lpVtbl->GetViewport(p, a) +#define IDirect3DViewport2_SetViewport(p, a) (p)->lpVtbl->SetViewport(p, a) +#define IDirect3DViewport2_TransformVertices(p, a, b, c, d) (p)->lpVtbl->TransformVertices(p, a, b, c, d) +#define IDirect3DViewport2_LightElements(p, a, b) (p)->lpVtbl->LightElements(p, a, b) +#define IDirect3DViewport2_SetBackground(p, a) (p)->lpVtbl->SetBackground(p, a) +#define IDirect3DViewport2_GetBackground(p, a, b) (p)->lpVtbl->GetBackground(p, a, b) +#define IDirect3DViewport2_SetBackgroundDepth(p, a) (p)->lpVtbl->SetBackgroundDepth(p, a) +#define IDirect3DViewport2_GetBackgroundDepth(p, a, b) (p)->lpVtbl->GetBackgroundDepth(p, a, b) +#define IDirect3DViewport2_Clear(p, a, b, c) (p)->lpVtbl->Clear(p, a, b, c) +#define IDirect3DViewport2_AddLight(p, a) (p)->lpVtbl->AddLight(p, a) +#define IDirect3DViewport2_DeleteLight(p, a) (p)->lpVtbl->DeleteLight(p, a) +#define IDirect3DViewport2_NextLight(p, a, b, c) (p)->lpVtbl->NextLight(p, a, b, c) +#define IDirect3DViewport2_GetViewport2(p, a) (p)->lpVtbl->GetViewport2(p, a) +#define IDirect3DViewport2_SetViewport2(p, a) (p)->lpVtbl->SetViewport2(p, a) +#else +#define IDirect3DViewport2_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirect3DViewport2_AddRef(p) (p)->AddRef() +#define IDirect3DViewport2_Release(p) (p)->Release() +#define IDirect3DViewport2_Initialize(p, a) (p)->Initialize(a) +#define IDirect3DViewport2_GetViewport(p, a) (p)->GetViewport(a) +#define IDirect3DViewport2_SetViewport(p, a) (p)->SetViewport(a) +#define IDirect3DViewport2_TransformVertices(p, a, b, c, d) (p)->TransformVertices(a, b, c, d) +#define IDirect3DViewport2_LightElements(p, a, b) (p)->LightElements(a, b) +#define IDirect3DViewport2_SetBackground(p, a) (p)->SetBackground(a) +#define IDirect3DViewport2_GetBackground(p, a, b) (p)->GetBackground(a, b) +#define IDirect3DViewport2_SetBackgroundDepth(p, a) (p)->SetBackgroundDepth(a) +#define IDirect3DViewport2_GetBackgroundDepth(p, a, b) (p)->GetBackgroundDepth(a, b) +#define IDirect3DViewport2_Clear(p, a, b, c) (p)->Clear(a, b, c) +#define IDirect3DViewport2_AddLight(p, a) (p)->AddLight(a) +#define IDirect3DViewport2_DeleteLight(p, a) (p)->DeleteLight(a) +#define IDirect3DViewport2_NextLight(p, a, b, c) (p)->NextLight(a, b, c) +#define IDirect3DViewport2_GetViewport2(p, a) (p)->GetViewport2(a) +#define IDirect3DViewport2_SetViewport2(p, a) (p)->SetViewport2(a) +#endif + + +/**************************************************************************** + * + * Flags for IDirect3DDevice::NextViewport + * + ****************************************************************************/ + +/* + * Return the next viewport + */ +#define D3DNEXT_NEXT 0x00000001l + +/* + * Return the first viewport + */ +#define D3DNEXT_HEAD 0x00000002l + +/* + * Return the last viewport + */ +#define D3DNEXT_TAIL 0x00000004l + + +/**************************************************************************** + * + * Flags for DrawPrimitive/DrawIndexedPrimitive + * Also valid for Begin/BeginIndexed + * + ****************************************************************************/ + +/* + * Wait until the device is ready to draw the primitive + * This will cause DP to not return DDERR_WASSTILLDRAWING + */ +#define D3DDP_WAIT 0x00000001l + + +/* + * Hint that the primitives have been clipped by the application. + */ +#define D3DDP_DONOTCLIP 0x00000004l + +/* + * Hint that the extents need not be updated. + */ +#define D3DDP_DONOTUPDATEEXTENTS 0x00000008l + +/* + * Direct3D Errors + * DirectDraw error codes are used when errors not specified here. + */ +#define D3D_OK DD_OK +#define D3DERR_BADMAJORVERSION MAKE_DDHRESULT(700) +#define D3DERR_BADMINORVERSION MAKE_DDHRESULT(701) + +/* + * An invalid device was requested by the application. + */ +#define D3DERR_INVALID_DEVICE MAKE_DDHRESULT(705) +#define D3DERR_INITFAILED MAKE_DDHRESULT(706) + +/* + * SetRenderTarget attempted on a device that was + * QI'd off the render target. + */ +#define D3DERR_DEVICEAGGREGATED MAKE_DDHRESULT(707) + +#define D3DERR_EXECUTE_CREATE_FAILED MAKE_DDHRESULT(710) +#define D3DERR_EXECUTE_DESTROY_FAILED MAKE_DDHRESULT(711) +#define D3DERR_EXECUTE_LOCK_FAILED MAKE_DDHRESULT(712) +#define D3DERR_EXECUTE_UNLOCK_FAILED MAKE_DDHRESULT(713) +#define D3DERR_EXECUTE_LOCKED MAKE_DDHRESULT(714) +#define D3DERR_EXECUTE_NOT_LOCKED MAKE_DDHRESULT(715) + +#define D3DERR_EXECUTE_FAILED MAKE_DDHRESULT(716) +#define D3DERR_EXECUTE_CLIPPED_FAILED MAKE_DDHRESULT(717) + +#define D3DERR_TEXTURE_NO_SUPPORT MAKE_DDHRESULT(720) +#define D3DERR_TEXTURE_CREATE_FAILED MAKE_DDHRESULT(721) +#define D3DERR_TEXTURE_DESTROY_FAILED MAKE_DDHRESULT(722) +#define D3DERR_TEXTURE_LOCK_FAILED MAKE_DDHRESULT(723) +#define D3DERR_TEXTURE_UNLOCK_FAILED MAKE_DDHRESULT(724) +#define D3DERR_TEXTURE_LOAD_FAILED MAKE_DDHRESULT(725) +#define D3DERR_TEXTURE_SWAP_FAILED MAKE_DDHRESULT(726) +#define D3DERR_TEXTURE_LOCKED MAKE_DDHRESULT(727) +#define D3DERR_TEXTURE_NOT_LOCKED MAKE_DDHRESULT(728) +#define D3DERR_TEXTURE_GETSURF_FAILED MAKE_DDHRESULT(729) + +#define D3DERR_MATRIX_CREATE_FAILED MAKE_DDHRESULT(730) +#define D3DERR_MATRIX_DESTROY_FAILED MAKE_DDHRESULT(731) +#define D3DERR_MATRIX_SETDATA_FAILED MAKE_DDHRESULT(732) +#define D3DERR_MATRIX_GETDATA_FAILED MAKE_DDHRESULT(733) +#define D3DERR_SETVIEWPORTDATA_FAILED MAKE_DDHRESULT(734) + +#define D3DERR_INVALIDCURRENTVIEWPORT MAKE_DDHRESULT(735) +#define D3DERR_INVALIDPRIMITIVETYPE MAKE_DDHRESULT(736) +#define D3DERR_INVALIDVERTEXTYPE MAKE_DDHRESULT(737) +#define D3DERR_TEXTURE_BADSIZE MAKE_DDHRESULT(738) +#define D3DERR_INVALIDRAMPTEXTURE MAKE_DDHRESULT(739) + +#define D3DERR_MATERIAL_CREATE_FAILED MAKE_DDHRESULT(740) +#define D3DERR_MATERIAL_DESTROY_FAILED MAKE_DDHRESULT(741) +#define D3DERR_MATERIAL_SETDATA_FAILED MAKE_DDHRESULT(742) +#define D3DERR_MATERIAL_GETDATA_FAILED MAKE_DDHRESULT(743) +#define D3DERR_INVALIDPALETTE MAKE_DDHRESULT(744) + +#define D3DERR_ZBUFF_NEEDS_SYSTEMMEMORY MAKE_DDHRESULT(745) +#define D3DERR_ZBUFF_NEEDS_VIDEOMEMORY MAKE_DDHRESULT(746) +#define D3DERR_SURFACENOTINVIDMEM MAKE_DDHRESULT(747) + +#define D3DERR_LIGHT_SET_FAILED MAKE_DDHRESULT(750) +#define D3DERR_LIGHTHASVIEWPORT MAKE_DDHRESULT(751) +#define D3DERR_LIGHTNOTINTHISVIEWPORT MAKE_DDHRESULT(752) + +#define D3DERR_SCENE_IN_SCENE MAKE_DDHRESULT(760) +#define D3DERR_SCENE_NOT_IN_SCENE MAKE_DDHRESULT(761) +#define D3DERR_SCENE_BEGIN_FAILED MAKE_DDHRESULT(762) +#define D3DERR_SCENE_END_FAILED MAKE_DDHRESULT(763) + +#define D3DERR_INBEGIN MAKE_DDHRESULT(770) +#define D3DERR_NOTINBEGIN MAKE_DDHRESULT(771) +#define D3DERR_NOVIEWPORTS MAKE_DDHRESULT(772) +#define D3DERR_VIEWPORTDATANOTSET MAKE_DDHRESULT(773) +#define D3DERR_VIEWPORTHASNODEVICE MAKE_DDHRESULT(774) +#define D3DERR_NOCURRENTVIEWPORT MAKE_DDHRESULT(775) + +#ifdef __cplusplus +}; +#endif + +#endif /* _D3D_H_ */ diff --git a/3rdparty/dx5/inc/d3dcaps.h b/3rdparty/dx5/inc/d3dcaps.h new file mode 100644 index 00000000..c688eb25 --- /dev/null +++ b/3rdparty/dx5/inc/d3dcaps.h @@ -0,0 +1,313 @@ +/*==========================================================================; + * + * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. + * + * File: d3dcaps.h + * Content: Direct3D capabilities include file + * + ***************************************************************************/ + +#ifndef _D3DCAPS_H +#define _D3DCAPS_H + +/* + * Pull in DirectDraw include file automatically: + */ +#include + +#pragma pack(4) + +/* Description of capabilities of transform */ + +typedef struct _D3DTRANSFORMCAPS { + DWORD dwSize; + DWORD dwCaps; +} D3DTRANSFORMCAPS, *LPD3DTRANSFORMCAPS; + +#define D3DTRANSFORMCAPS_CLIP 0x00000001L /* Will clip whilst transforming */ + +/* Description of capabilities of lighting */ + +typedef struct _D3DLIGHTINGCAPS { + DWORD dwSize; + DWORD dwCaps; /* Lighting caps */ + DWORD dwLightingModel; /* Lighting model - RGB or mono */ + DWORD dwNumLights; /* Number of lights that can be handled */ +} D3DLIGHTINGCAPS, *LPD3DLIGHTINGCAPS; + +#define D3DLIGHTINGMODEL_RGB 0x00000001L +#define D3DLIGHTINGMODEL_MONO 0x00000002L + +#define D3DLIGHTCAPS_POINT 0x00000001L /* Point lights supported */ +#define D3DLIGHTCAPS_SPOT 0x00000002L /* Spot lights supported */ +#define D3DLIGHTCAPS_DIRECTIONAL 0x00000004L /* Directional lights supported */ +#define D3DLIGHTCAPS_PARALLELPOINT 0x00000008L /* Parallel point lights supported */ + +/* Description of capabilities for each primitive type */ + +typedef struct _D3DPrimCaps { + DWORD dwSize; + DWORD dwMiscCaps; /* Capability flags */ + DWORD dwRasterCaps; + DWORD dwZCmpCaps; + DWORD dwSrcBlendCaps; + DWORD dwDestBlendCaps; + DWORD dwAlphaCmpCaps; + DWORD dwShadeCaps; + DWORD dwTextureCaps; + DWORD dwTextureFilterCaps; + DWORD dwTextureBlendCaps; + DWORD dwTextureAddressCaps; + DWORD dwStippleWidth; /* maximum width and height of */ + DWORD dwStippleHeight; /* of supported stipple (up to 32x32) */ +} D3DPRIMCAPS, *LPD3DPRIMCAPS; + +/* D3DPRIMCAPS dwMiscCaps */ + +#define D3DPMISCCAPS_MASKPLANES 0x00000001L +#define D3DPMISCCAPS_MASKZ 0x00000002L +#define D3DPMISCCAPS_LINEPATTERNREP 0x00000004L +#define D3DPMISCCAPS_CONFORMANT 0x00000008L +#define D3DPMISCCAPS_CULLNONE 0x00000010L +#define D3DPMISCCAPS_CULLCW 0x00000020L +#define D3DPMISCCAPS_CULLCCW 0x00000040L + +/* D3DPRIMCAPS dwRasterCaps */ + +#define D3DPRASTERCAPS_DITHER 0x00000001L +#define D3DPRASTERCAPS_ROP2 0x00000002L +#define D3DPRASTERCAPS_XOR 0x00000004L +#define D3DPRASTERCAPS_PAT 0x00000008L +#define D3DPRASTERCAPS_ZTEST 0x00000010L +#define D3DPRASTERCAPS_SUBPIXEL 0x00000020L +#define D3DPRASTERCAPS_SUBPIXELX 0x00000040L +#define D3DPRASTERCAPS_FOGVERTEX 0x00000080L +#define D3DPRASTERCAPS_FOGTABLE 0x00000100L +#define D3DPRASTERCAPS_STIPPLE 0x00000200L +#define D3DPRASTERCAPS_ANTIALIASSORTDEPENDENT 0x00000400L +#define D3DPRASTERCAPS_ANTIALIASSORTINDEPENDENT 0x00000800L +#define D3DPRASTERCAPS_ANTIALIASEDGES 0x00001000L +#define D3DPRASTERCAPS_MIPMAPLODBIAS 0x00002000L +#define D3DPRASTERCAPS_ZBIAS 0x00004000L +#define D3DPRASTERCAPS_ZBUFFERLESSHSR 0x00008000L +#define D3DPRASTERCAPS_FOGRANGE 0x00010000L +#define D3DPRASTERCAPS_ANISOTROPY 0x00020000L + +/* D3DPRIMCAPS dwZCmpCaps, dwAlphaCmpCaps */ + +#define D3DPCMPCAPS_NEVER 0x00000001L +#define D3DPCMPCAPS_LESS 0x00000002L +#define D3DPCMPCAPS_EQUAL 0x00000004L +#define D3DPCMPCAPS_LESSEQUAL 0x00000008L +#define D3DPCMPCAPS_GREATER 0x00000010L +#define D3DPCMPCAPS_NOTEQUAL 0x00000020L +#define D3DPCMPCAPS_GREATEREQUAL 0x00000040L +#define D3DPCMPCAPS_ALWAYS 0x00000080L + +/* D3DPRIMCAPS dwSourceBlendCaps, dwDestBlendCaps */ + +#define D3DPBLENDCAPS_ZERO 0x00000001L +#define D3DPBLENDCAPS_ONE 0x00000002L +#define D3DPBLENDCAPS_SRCCOLOR 0x00000004L +#define D3DPBLENDCAPS_INVSRCCOLOR 0x00000008L +#define D3DPBLENDCAPS_SRCALPHA 0x00000010L +#define D3DPBLENDCAPS_INVSRCALPHA 0x00000020L +#define D3DPBLENDCAPS_DESTALPHA 0x00000040L +#define D3DPBLENDCAPS_INVDESTALPHA 0x00000080L +#define D3DPBLENDCAPS_DESTCOLOR 0x00000100L +#define D3DPBLENDCAPS_INVDESTCOLOR 0x00000200L +#define D3DPBLENDCAPS_SRCALPHASAT 0x00000400L +#define D3DPBLENDCAPS_BOTHSRCALPHA 0x00000800L +#define D3DPBLENDCAPS_BOTHINVSRCALPHA 0x00001000L + +/* D3DPRIMCAPS dwShadeCaps */ + +#define D3DPSHADECAPS_COLORFLATMONO 0x00000001L +#define D3DPSHADECAPS_COLORFLATRGB 0x00000002L +#define D3DPSHADECAPS_COLORGOURAUDMONO 0x00000004L +#define D3DPSHADECAPS_COLORGOURAUDRGB 0x00000008L +#define D3DPSHADECAPS_COLORPHONGMONO 0x00000010L +#define D3DPSHADECAPS_COLORPHONGRGB 0x00000020L + +#define D3DPSHADECAPS_SPECULARFLATMONO 0x00000040L +#define D3DPSHADECAPS_SPECULARFLATRGB 0x00000080L +#define D3DPSHADECAPS_SPECULARGOURAUDMONO 0x00000100L +#define D3DPSHADECAPS_SPECULARGOURAUDRGB 0x00000200L +#define D3DPSHADECAPS_SPECULARPHONGMONO 0x00000400L +#define D3DPSHADECAPS_SPECULARPHONGRGB 0x00000800L + +#define D3DPSHADECAPS_ALPHAFLATBLEND 0x00001000L +#define D3DPSHADECAPS_ALPHAFLATSTIPPLED 0x00002000L +#define D3DPSHADECAPS_ALPHAGOURAUDBLEND 0x00004000L +#define D3DPSHADECAPS_ALPHAGOURAUDSTIPPLED 0x00008000L +#define D3DPSHADECAPS_ALPHAPHONGBLEND 0x00010000L +#define D3DPSHADECAPS_ALPHAPHONGSTIPPLED 0x00020000L + +#define D3DPSHADECAPS_FOGFLAT 0x00040000L +#define D3DPSHADECAPS_FOGGOURAUD 0x00080000L +#define D3DPSHADECAPS_FOGPHONG 0x00100000L + +/* D3DPRIMCAPS dwTextureCaps */ + +#define D3DPTEXTURECAPS_PERSPECTIVE 0x00000001L +#define D3DPTEXTURECAPS_POW2 0x00000002L +#define D3DPTEXTURECAPS_ALPHA 0x00000004L +#define D3DPTEXTURECAPS_TRANSPARENCY 0x00000008L +#define D3DPTEXTURECAPS_BORDER 0x00000010L +#define D3DPTEXTURECAPS_SQUAREONLY 0x00000020L + +/* D3DPRIMCAPS dwTextureFilterCaps */ + +#define D3DPTFILTERCAPS_NEAREST 0x00000001L +#define D3DPTFILTERCAPS_LINEAR 0x00000002L +#define D3DPTFILTERCAPS_MIPNEAREST 0x00000004L +#define D3DPTFILTERCAPS_MIPLINEAR 0x00000008L +#define D3DPTFILTERCAPS_LINEARMIPNEAREST 0x00000010L +#define D3DPTFILTERCAPS_LINEARMIPLINEAR 0x00000020L + +/* D3DPRIMCAPS dwTextureBlendCaps */ + +#define D3DPTBLENDCAPS_DECAL 0x00000001L +#define D3DPTBLENDCAPS_MODULATE 0x00000002L +#define D3DPTBLENDCAPS_DECALALPHA 0x00000004L +#define D3DPTBLENDCAPS_MODULATEALPHA 0x00000008L +#define D3DPTBLENDCAPS_DECALMASK 0x00000010L +#define D3DPTBLENDCAPS_MODULATEMASK 0x00000020L +#define D3DPTBLENDCAPS_COPY 0x00000040L +#define D3DPTBLENDCAPS_ADD 0x00000080L + +/* D3DPRIMCAPS dwTextureAddressCaps */ +#define D3DPTADDRESSCAPS_WRAP 0x00000001L +#define D3DPTADDRESSCAPS_MIRROR 0x00000002L +#define D3DPTADDRESSCAPS_CLAMP 0x00000004L +#define D3DPTADDRESSCAPS_BORDER 0x00000008L +#define D3DPTADDRESSCAPS_INDEPENDENTUV 0x00000010L + +/* + * Description for a device. + * This is used to describe a device that is to be created or to query + * the current device. + */ +typedef struct _D3DDeviceDesc { + DWORD dwSize; /* Size of D3DDEVICEDESC structure */ + DWORD dwFlags; /* Indicates which fields have valid data */ + D3DCOLORMODEL dcmColorModel; /* Color model of device */ + DWORD dwDevCaps; /* Capabilities of device */ + D3DTRANSFORMCAPS dtcTransformCaps; /* Capabilities of transform */ + BOOL bClipping; /* Device can do 3D clipping */ + D3DLIGHTINGCAPS dlcLightingCaps; /* Capabilities of lighting */ + D3DPRIMCAPS dpcLineCaps; + D3DPRIMCAPS dpcTriCaps; + DWORD dwDeviceRenderBitDepth; /* One of DDBB_8, 16, etc.. */ + DWORD dwDeviceZBufferBitDepth;/* One of DDBD_16, 32, etc.. */ + DWORD dwMaxBufferSize; /* Maximum execute buffer size */ + DWORD dwMaxVertexCount; /* Maximum vertex count */ + // *** New fields for DX5 *** // + + // Width and height caps are 0 for legacy HALs. + DWORD dwMinTextureWidth, dwMinTextureHeight; + DWORD dwMaxTextureWidth, dwMaxTextureHeight; + DWORD dwMinStippleWidth, dwMaxStippleWidth; + DWORD dwMinStippleHeight, dwMaxStippleHeight; +} D3DDEVICEDESC, *LPD3DDEVICEDESC; + +#define D3DDEVICEDESCSIZE (sizeof(D3DDEVICEDESC)) + +typedef HRESULT (FAR PASCAL * LPD3DENUMDEVICESCALLBACK)(LPGUID lpGuid, LPSTR lpDeviceDescription, LPSTR lpDeviceName, LPD3DDEVICEDESC, LPD3DDEVICEDESC, LPVOID); + +/* D3DDEVICEDESC dwFlags indicating valid fields */ + +#define D3DDD_COLORMODEL 0x00000001L /* dcmColorModel is valid */ +#define D3DDD_DEVCAPS 0x00000002L /* dwDevCaps is valid */ +#define D3DDD_TRANSFORMCAPS 0x00000004L /* dtcTransformCaps is valid */ +#define D3DDD_LIGHTINGCAPS 0x00000008L /* dlcLightingCaps is valid */ +#define D3DDD_BCLIPPING 0x00000010L /* bClipping is valid */ +#define D3DDD_LINECAPS 0x00000020L /* dpcLineCaps is valid */ +#define D3DDD_TRICAPS 0x00000040L /* dpcTriCaps is valid */ +#define D3DDD_DEVICERENDERBITDEPTH 0x00000080L /* dwDeviceRenderBitDepth is valid */ +#define D3DDD_DEVICEZBUFFERBITDEPTH 0x00000100L /* dwDeviceZBufferBitDepth is valid */ +#define D3DDD_MAXBUFFERSIZE 0x00000200L /* dwMaxBufferSize is valid */ +#define D3DDD_MAXVERTEXCOUNT 0x00000400L /* dwMaxVertexCount is valid */ + +/* D3DDEVICEDESC dwDevCaps flags */ + +#define D3DDEVCAPS_FLOATTLVERTEX 0x00000001L /* Device accepts floating point */ + /* for post-transform vertex data */ +#define D3DDEVCAPS_SORTINCREASINGZ 0x00000002L /* Device needs data sorted for increasing Z*/ +#define D3DDEVCAPS_SORTDECREASINGZ 0X00000004L /* Device needs data sorted for decreasing Z*/ +#define D3DDEVCAPS_SORTEXACT 0x00000008L /* Device needs data sorted exactly */ + +#define D3DDEVCAPS_EXECUTESYSTEMMEMORY 0x00000010L /* Device can use execute buffers from system memory */ +#define D3DDEVCAPS_EXECUTEVIDEOMEMORY 0x00000020L /* Device can use execute buffers from video memory */ +#define D3DDEVCAPS_TLVERTEXSYSTEMMEMORY 0x00000040L /* Device can use TL buffers from system memory */ +#define D3DDEVCAPS_TLVERTEXVIDEOMEMORY 0x00000080L /* Device can use TL buffers from video memory */ +#define D3DDEVCAPS_TEXTURESYSTEMMEMORY 0x00000100L /* Device can texture from system memory */ +#define D3DDEVCAPS_TEXTUREVIDEOMEMORY 0x00000200L /* Device can texture from device memory */ +#define D3DDEVCAPS_DRAWPRIMTLVERTEX 0x00000400L /* Device can draw TLVERTEX primitives */ +#define D3DDEVCAPS_CANRENDERAFTERFLIP 0x00000800L /* Device can render without waiting for flip to complete */ +#define D3DDEVCAPS_TEXTURENONLOCALVIDMEM 0x00001000L /* Device can texture from nonlocal video memory */ + +#define D3DFDS_COLORMODEL 0x00000001L /* Match color model */ +#define D3DFDS_GUID 0x00000002L /* Match guid */ +#define D3DFDS_HARDWARE 0x00000004L /* Match hardware/software */ +#define D3DFDS_TRIANGLES 0x00000008L /* Match in triCaps */ +#define D3DFDS_LINES 0x00000010L /* Match in lineCaps */ +#define D3DFDS_MISCCAPS 0x00000020L /* Match primCaps.dwMiscCaps */ +#define D3DFDS_RASTERCAPS 0x00000040L /* Match primCaps.dwRasterCaps */ +#define D3DFDS_ZCMPCAPS 0x00000080L /* Match primCaps.dwZCmpCaps */ +#define D3DFDS_ALPHACMPCAPS 0x00000100L /* Match primCaps.dwAlphaCmpCaps */ +#define D3DFDS_SRCBLENDCAPS 0x00000200L /* Match primCaps.dwSourceBlendCaps */ +#define D3DFDS_DSTBLENDCAPS 0x00000400L /* Match primCaps.dwDestBlendCaps */ +#define D3DFDS_SHADECAPS 0x00000800L /* Match primCaps.dwShadeCaps */ +#define D3DFDS_TEXTURECAPS 0x00001000L /* Match primCaps.dwTextureCaps */ +#define D3DFDS_TEXTUREFILTERCAPS 0x00002000L /* Match primCaps.dwTextureFilterCaps */ +#define D3DFDS_TEXTUREBLENDCAPS 0x00004000L /* Match primCaps.dwTextureBlendCaps */ +#define D3DFDS_TEXTUREADDRESSCAPS 0x00008000L /* Match primCaps.dwTextureBlendCaps */ + +/* + * FindDevice arguments + */ +typedef struct _D3DFINDDEVICESEARCH { + DWORD dwSize; + DWORD dwFlags; + BOOL bHardware; + D3DCOLORMODEL dcmColorModel; + GUID guid; + DWORD dwCaps; + D3DPRIMCAPS dpcPrimCaps; +} D3DFINDDEVICESEARCH, *LPD3DFINDDEVICESEARCH; + +typedef struct _D3DFINDDEVICERESULT { + DWORD dwSize; + GUID guid; /* guid which matched */ + D3DDEVICEDESC ddHwDesc; /* hardware D3DDEVICEDESC */ + D3DDEVICEDESC ddSwDesc; /* software D3DDEVICEDESC */ +} D3DFINDDEVICERESULT, *LPD3DFINDDEVICERESULT; + + +/* + * Description of execute buffer. + */ +typedef struct _D3DExecuteBufferDesc { + DWORD dwSize; /* size of this structure */ + DWORD dwFlags; /* flags indicating which fields are valid */ + DWORD dwCaps; /* capabilities of execute buffer */ + DWORD dwBufferSize; /* size of execute buffer data */ + LPVOID lpData; /* pointer to actual data */ +} D3DEXECUTEBUFFERDESC, *LPD3DEXECUTEBUFFERDESC; + +/* D3DEXECUTEBUFFER dwFlags indicating valid fields */ + +#define D3DDEB_BUFSIZE 0x00000001l /* buffer size valid */ +#define D3DDEB_CAPS 0x00000002l /* caps valid */ +#define D3DDEB_LPDATA 0x00000004l /* lpData valid */ + +/* D3DEXECUTEBUFFER dwCaps */ + +#define D3DDEBCAPS_SYSTEMMEMORY 0x00000001l /* buffer in system memory */ +#define D3DDEBCAPS_VIDEOMEMORY 0x00000002l /* buffer in device memory */ +#define D3DDEBCAPS_MEM (D3DDEBCAPS_SYSTEMMEMORY|D3DDEBCAPS_VIDEOMEMORY) + +#pragma pack() + +#endif /* _D3DCAPS_H_ */ diff --git a/3rdparty/dx5/inc/d3drm.h b/3rdparty/dx5/inc/d3drm.h new file mode 100644 index 00000000..f653c0b9 --- /dev/null +++ b/3rdparty/dx5/inc/d3drm.h @@ -0,0 +1,229 @@ +/*==========================================================================; + * + * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. + * + * File: d3drm.h + * Content: Direct3DRM include file + * + ***************************************************************************/ + +#ifndef __D3DRM_H__ +#define __D3DRM_H__ + +#include "ddraw.h" +#include "d3drmobj.h" + +#ifdef __cplusplus +extern "C" { +struct IDirect3DRM; +#endif + + +DEFINE_GUID(IID_IDirect3DRM, 0x2bc49361, 0x8327, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRM2, 0x4516ecc8, 0x8f20, 0x11d0, 0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3); +WIN_TYPES(IDirect3DRM, DIRECT3DRM); +WIN_TYPES(IDirect3DRM2, DIRECT3DRM2); + + +/* Create a Direct3DRM API */ +STDAPI Direct3DRMCreate(LPDIRECT3DRM FAR *lplpDirect3DRM); + +#undef INTERFACE +#define INTERFACE IDirect3DRM + +DECLARE_INTERFACE_(IDirect3DRM, IUnknown) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD(CreateObject) + (THIS_ REFCLSID rclsid, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID FAR* ppv) PURE; + STDMETHOD(CreateFrame) (THIS_ LPDIRECT3DRMFRAME, LPDIRECT3DRMFRAME *) PURE; + STDMETHOD(CreateMesh) (THIS_ LPDIRECT3DRMMESH *) PURE; + STDMETHOD(CreateMeshBuilder)(THIS_ LPDIRECT3DRMMESHBUILDER *) PURE; + STDMETHOD(CreateFace) (THIS_ LPDIRECT3DRMFACE *) PURE; + STDMETHOD(CreateAnimation) (THIS_ LPDIRECT3DRMANIMATION *) PURE; + STDMETHOD(CreateAnimationSet)(THIS_ LPDIRECT3DRMANIMATIONSET *) PURE; + STDMETHOD(CreateTexture) (THIS_ LPD3DRMIMAGE, LPDIRECT3DRMTEXTURE *) PURE; + STDMETHOD(CreateLight) (THIS_ D3DRMLIGHTTYPE, D3DCOLOR, LPDIRECT3DRMLIGHT *) PURE; + STDMETHOD(CreateLightRGB) + (THIS_ D3DRMLIGHTTYPE, D3DVALUE, D3DVALUE, D3DVALUE, LPDIRECT3DRMLIGHT *) PURE; + STDMETHOD(CreateMaterial) (THIS_ D3DVALUE, LPDIRECT3DRMMATERIAL *) PURE; + STDMETHOD(CreateDevice) (THIS_ DWORD, DWORD, LPDIRECT3DRMDEVICE *) PURE; + + /* Create a Windows Device using DirectDraw surfaces */ + STDMETHOD(CreateDeviceFromSurface) + ( THIS_ LPGUID lpGUID, LPDIRECTDRAW lpDD, + LPDIRECTDRAWSURFACE lpDDSBack, LPDIRECT3DRMDEVICE * + ) PURE; + + /* Create a Windows Device using D3D objects */ + STDMETHOD(CreateDeviceFromD3D) + ( THIS_ LPDIRECT3D lpD3D, LPDIRECT3DDEVICE lpD3DDev, + LPDIRECT3DRMDEVICE * + ) PURE; + + STDMETHOD(CreateDeviceFromClipper) + ( THIS_ LPDIRECTDRAWCLIPPER lpDDClipper, LPGUID lpGUID, + int width, int height, LPDIRECT3DRMDEVICE *) PURE; + + STDMETHOD(CreateTextureFromSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDS, LPDIRECT3DRMTEXTURE *) PURE; + + STDMETHOD(CreateShadow) + ( THIS_ LPDIRECT3DRMVISUAL, LPDIRECT3DRMLIGHT, + D3DVALUE px, D3DVALUE py, D3DVALUE pz, + D3DVALUE nx, D3DVALUE ny, D3DVALUE nz, + LPDIRECT3DRMVISUAL * + ) PURE; + STDMETHOD(CreateViewport) + ( THIS_ LPDIRECT3DRMDEVICE, LPDIRECT3DRMFRAME, DWORD, DWORD, + DWORD, DWORD, LPDIRECT3DRMVIEWPORT * + ) PURE; + STDMETHOD(CreateWrap) + ( THIS_ D3DRMWRAPTYPE, LPDIRECT3DRMFRAME, + D3DVALUE ox, D3DVALUE oy, D3DVALUE oz, + D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, + D3DVALUE ux, D3DVALUE uy, D3DVALUE uz, + D3DVALUE ou, D3DVALUE ov, + D3DVALUE su, D3DVALUE sv, + LPDIRECT3DRMWRAP * + ) PURE; + STDMETHOD(CreateUserVisual) (THIS_ D3DRMUSERVISUALCALLBACK, LPVOID lPArg, LPDIRECT3DRMUSERVISUAL *) PURE; + STDMETHOD(LoadTexture) (THIS_ const char *, LPDIRECT3DRMTEXTURE *) PURE; + STDMETHOD(LoadTextureFromResource) (THIS_ HRSRC rs, LPDIRECT3DRMTEXTURE *) PURE; + + STDMETHOD(SetSearchPath) (THIS_ LPCSTR) PURE; + STDMETHOD(AddSearchPath) (THIS_ LPCSTR) PURE; + STDMETHOD(GetSearchPath) (THIS_ DWORD *size_return, LPSTR path_return) PURE; + STDMETHOD(SetDefaultTextureColors)(THIS_ DWORD) PURE; + STDMETHOD(SetDefaultTextureShades)(THIS_ DWORD) PURE; + + STDMETHOD(GetDevices) (THIS_ LPDIRECT3DRMDEVICEARRAY *) PURE; + STDMETHOD(GetNamedObject) (THIS_ const char *, LPDIRECT3DRMOBJECT *) PURE; + + STDMETHOD(EnumerateObjects) (THIS_ D3DRMOBJECTCALLBACK, LPVOID) PURE; + + STDMETHOD(Load) + ( THIS_ LPVOID, LPVOID, LPIID *, DWORD, D3DRMLOADOPTIONS, + D3DRMLOADCALLBACK, LPVOID, D3DRMLOADTEXTURECALLBACK, LPVOID, + LPDIRECT3DRMFRAME + ) PURE; + STDMETHOD(Tick) (THIS_ D3DVALUE) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRM2 + +DECLARE_INTERFACE_(IDirect3DRM2, IUnknown) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD(CreateObject) + (THIS_ REFCLSID rclsid, LPUNKNOWN pUnkOuter, REFIID riid, LPVOID FAR* ppv) PURE; + STDMETHOD(CreateFrame) (THIS_ LPDIRECT3DRMFRAME, LPDIRECT3DRMFRAME2 *) PURE; + STDMETHOD(CreateMesh) (THIS_ LPDIRECT3DRMMESH *) PURE; + STDMETHOD(CreateMeshBuilder)(THIS_ LPDIRECT3DRMMESHBUILDER2 *) PURE; + STDMETHOD(CreateFace) (THIS_ LPDIRECT3DRMFACE *) PURE; + STDMETHOD(CreateAnimation) (THIS_ LPDIRECT3DRMANIMATION *) PURE; + STDMETHOD(CreateAnimationSet)(THIS_ LPDIRECT3DRMANIMATIONSET *) PURE; + STDMETHOD(CreateTexture) (THIS_ LPD3DRMIMAGE, LPDIRECT3DRMTEXTURE2 *) PURE; + STDMETHOD(CreateLight) (THIS_ D3DRMLIGHTTYPE, D3DCOLOR, LPDIRECT3DRMLIGHT *) PURE; + STDMETHOD(CreateLightRGB) + (THIS_ D3DRMLIGHTTYPE, D3DVALUE, D3DVALUE, D3DVALUE, LPDIRECT3DRMLIGHT *) PURE; + STDMETHOD(CreateMaterial) (THIS_ D3DVALUE, LPDIRECT3DRMMATERIAL *) PURE; + STDMETHOD(CreateDevice) (THIS_ DWORD, DWORD, LPDIRECT3DRMDEVICE2 *) PURE; + + /* Create a Windows Device using DirectDraw surfaces */ + STDMETHOD(CreateDeviceFromSurface) + ( THIS_ LPGUID lpGUID, LPDIRECTDRAW lpDD, + LPDIRECTDRAWSURFACE lpDDSBack, LPDIRECT3DRMDEVICE2 * + ) PURE; + + /* Create a Windows Device using D3D objects */ + STDMETHOD(CreateDeviceFromD3D) + ( THIS_ LPDIRECT3D2 lpD3D, LPDIRECT3DDEVICE2 lpD3DDev, + LPDIRECT3DRMDEVICE2 * + ) PURE; + + STDMETHOD(CreateDeviceFromClipper) + ( THIS_ LPDIRECTDRAWCLIPPER lpDDClipper, LPGUID lpGUID, + int width, int height, LPDIRECT3DRMDEVICE2 *) PURE; + + STDMETHOD(CreateTextureFromSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDS, LPDIRECT3DRMTEXTURE2 *) PURE; + + STDMETHOD(CreateShadow) + ( THIS_ LPDIRECT3DRMVISUAL, LPDIRECT3DRMLIGHT, + D3DVALUE px, D3DVALUE py, D3DVALUE pz, + D3DVALUE nx, D3DVALUE ny, D3DVALUE nz, + LPDIRECT3DRMVISUAL * + ) PURE; + STDMETHOD(CreateViewport) + ( THIS_ LPDIRECT3DRMDEVICE, LPDIRECT3DRMFRAME, DWORD, DWORD, + DWORD, DWORD, LPDIRECT3DRMVIEWPORT * + ) PURE; + STDMETHOD(CreateWrap) + ( THIS_ D3DRMWRAPTYPE, LPDIRECT3DRMFRAME, + D3DVALUE ox, D3DVALUE oy, D3DVALUE oz, + D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, + D3DVALUE ux, D3DVALUE uy, D3DVALUE uz, + D3DVALUE ou, D3DVALUE ov, + D3DVALUE su, D3DVALUE sv, + LPDIRECT3DRMWRAP * + ) PURE; + STDMETHOD(CreateUserVisual) (THIS_ D3DRMUSERVISUALCALLBACK, LPVOID lPArg, LPDIRECT3DRMUSERVISUAL *) PURE; + STDMETHOD(LoadTexture) (THIS_ const char *, LPDIRECT3DRMTEXTURE2 *) PURE; + STDMETHOD(LoadTextureFromResource) (THIS_ HMODULE hModule, LPCTSTR strName, LPCTSTR strType, LPDIRECT3DRMTEXTURE2 *) PURE; + + STDMETHOD(SetSearchPath) (THIS_ LPCSTR) PURE; + STDMETHOD(AddSearchPath) (THIS_ LPCSTR) PURE; + STDMETHOD(GetSearchPath) (THIS_ DWORD *size_return, LPSTR path_return) PURE; + STDMETHOD(SetDefaultTextureColors)(THIS_ DWORD) PURE; + STDMETHOD(SetDefaultTextureShades)(THIS_ DWORD) PURE; + + STDMETHOD(GetDevices) (THIS_ LPDIRECT3DRMDEVICEARRAY *) PURE; + STDMETHOD(GetNamedObject) (THIS_ const char *, LPDIRECT3DRMOBJECT *) PURE; + + STDMETHOD(EnumerateObjects) (THIS_ D3DRMOBJECTCALLBACK, LPVOID) PURE; + + STDMETHOD(Load) + ( THIS_ LPVOID, LPVOID, LPIID *, DWORD, D3DRMLOADOPTIONS, + D3DRMLOADCALLBACK, LPVOID, D3DRMLOADTEXTURECALLBACK, LPVOID, + LPDIRECT3DRMFRAME + ) PURE; + STDMETHOD(Tick) (THIS_ D3DVALUE) PURE; + + STDMETHOD(CreateProgressiveMesh)(THIS_ LPDIRECT3DRMPROGRESSIVEMESH *) PURE; +}; + +#define D3DRM_OK DD_OK +#define D3DRMERR_BADOBJECT MAKE_DDHRESULT(781) +#define D3DRMERR_BADTYPE MAKE_DDHRESULT(782) +#define D3DRMERR_BADALLOC MAKE_DDHRESULT(783) +#define D3DRMERR_FACEUSED MAKE_DDHRESULT(784) +#define D3DRMERR_NOTFOUND MAKE_DDHRESULT(785) +#define D3DRMERR_NOTDONEYET MAKE_DDHRESULT(786) +#define D3DRMERR_FILENOTFOUND MAKE_DDHRESULT(787) +#define D3DRMERR_BADFILE MAKE_DDHRESULT(788) +#define D3DRMERR_BADDEVICE MAKE_DDHRESULT(789) +#define D3DRMERR_BADVALUE MAKE_DDHRESULT(790) +#define D3DRMERR_BADMAJORVERSION MAKE_DDHRESULT(791) +#define D3DRMERR_BADMINORVERSION MAKE_DDHRESULT(792) +#define D3DRMERR_UNABLETOEXECUTE MAKE_DDHRESULT(793) +#define D3DRMERR_LIBRARYNOTFOUND MAKE_DDHRESULT(794) +#define D3DRMERR_INVALIDLIBRARY MAKE_DDHRESULT(795) +#define D3DRMERR_PENDING MAKE_DDHRESULT(796) +#define D3DRMERR_NOTENOUGHDATA MAKE_DDHRESULT(797) +#define D3DRMERR_REQUESTTOOLARGE MAKE_DDHRESULT(798) +#define D3DRMERR_REQUESTTOOSMALL MAKE_DDHRESULT(799) +#define D3DRMERR_CONNECTIONLOST MAKE_DDHRESULT(800) +#define D3DRMERR_LOADABORTED MAKE_DDHRESULT(801) +#define D3DRMERR_NOINTERNET MAKE_DDHRESULT(802) +#define D3DRMERR_BADCACHEFILE MAKE_DDHRESULT(803) +#define D3DRMERR_BOXNOTSET MAKE_DDHRESULT(804) +#define D3DRMERR_BADPMDATA MAKE_DDHRESULT(805) + +#ifdef __cplusplus +}; +#endif + +#endif /* _D3DRMAPI_H_ */ + diff --git a/3rdparty/dx5/inc/d3drmdef.h b/3rdparty/dx5/inc/d3drmdef.h new file mode 100644 index 00000000..109b2674 --- /dev/null +++ b/3rdparty/dx5/inc/d3drmdef.h @@ -0,0 +1,472 @@ +/*==========================================================================; + * + * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. + * + * File: d3drm.h + * Content: Direct3DRM include file + * + ***************************************************************************/ + +#ifndef __D3DRMDEFS_H__ +#define __D3DRMDEFS_H__ + +#include +#include "d3dtypes.h" + +#ifdef WIN32 +#define D3DRMAPI __stdcall +#else +#define D3DRMAPI +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#ifndef TRUE +#define FALSE 0 +#define TRUE 1 +#endif + +typedef struct _D3DRMVECTOR4D +{ D3DVALUE x, y, z, w; +} D3DRMVECTOR4D, *LPD3DRMVECTOR4D; + +typedef D3DVALUE D3DRMMATRIX4D[4][4]; + +typedef struct _D3DRMQUATERNION +{ D3DVALUE s; + D3DVECTOR v; +} D3DRMQUATERNION, *LPD3DRMQUATERNION; + +typedef struct _D3DRMRAY +{ D3DVECTOR dvDir; + D3DVECTOR dvPos; +} D3DRMRAY, *LPD3DRMRAY; + +typedef struct _D3DRMBOX +{ D3DVECTOR min, max; +} D3DRMBOX, *LPD3DRMBOX; + +typedef void (*D3DRMWRAPCALLBACK) + (LPD3DVECTOR, int* u, int* v, LPD3DVECTOR a, LPD3DVECTOR b, LPVOID); + +typedef enum _D3DRMLIGHTTYPE +{ D3DRMLIGHT_AMBIENT, + D3DRMLIGHT_POINT, + D3DRMLIGHT_SPOT, + D3DRMLIGHT_DIRECTIONAL, + D3DRMLIGHT_PARALLELPOINT +} D3DRMLIGHTTYPE, *LPD3DRMLIGHTTYPE; + +typedef enum _D3DRMSHADEMODE { + D3DRMSHADE_FLAT = 0, + D3DRMSHADE_GOURAUD = 1, + D3DRMSHADE_PHONG = 2, + + D3DRMSHADE_MASK = 7, + D3DRMSHADE_MAX = 8 +} D3DRMSHADEMODE, *LPD3DRMSHADEMODE; + +typedef enum _D3DRMLIGHTMODE { + D3DRMLIGHT_OFF = 0 * D3DRMSHADE_MAX, + D3DRMLIGHT_ON = 1 * D3DRMSHADE_MAX, + + D3DRMLIGHT_MASK = 7 * D3DRMSHADE_MAX, + D3DRMLIGHT_MAX = 8 * D3DRMSHADE_MAX +} D3DRMLIGHTMODE, *LPD3DRMLIGHTMODE; + +typedef enum _D3DRMFILLMODE { + D3DRMFILL_POINTS = 0 * D3DRMLIGHT_MAX, + D3DRMFILL_WIREFRAME = 1 * D3DRMLIGHT_MAX, + D3DRMFILL_SOLID = 2 * D3DRMLIGHT_MAX, + + D3DRMFILL_MASK = 7 * D3DRMLIGHT_MAX, + D3DRMFILL_MAX = 8 * D3DRMLIGHT_MAX +} D3DRMFILLMODE, *LPD3DRMFILLMODE; + +typedef DWORD D3DRMRENDERQUALITY, *LPD3DRMRENDERQUALITY; + +#define D3DRMRENDER_WIREFRAME (D3DRMSHADE_FLAT+D3DRMLIGHT_OFF+D3DRMFILL_WIREFRAME) +#define D3DRMRENDER_UNLITFLAT (D3DRMSHADE_FLAT+D3DRMLIGHT_OFF+D3DRMFILL_SOLID) +#define D3DRMRENDER_FLAT (D3DRMSHADE_FLAT+D3DRMLIGHT_ON+D3DRMFILL_SOLID) +#define D3DRMRENDER_GOURAUD (D3DRMSHADE_GOURAUD+D3DRMLIGHT_ON+D3DRMFILL_SOLID) +#define D3DRMRENDER_PHONG (D3DRMSHADE_PHONG+D3DRMLIGHT_ON+D3DRMFILL_SOLID) + +#define D3DRMRENDERMODE_BLENDEDTRANSPARENCY 1 +#define D3DRMRENDERMODE_SORTEDTRANSPARENCY 2 + +typedef enum _D3DRMTEXTUREQUALITY +{ D3DRMTEXTURE_NEAREST, /* choose nearest texel */ + D3DRMTEXTURE_LINEAR, /* interpolate 4 texels */ + D3DRMTEXTURE_MIPNEAREST, /* nearest texel in nearest mipmap */ + D3DRMTEXTURE_MIPLINEAR, /* interpolate 2 texels from 2 mipmaps */ + D3DRMTEXTURE_LINEARMIPNEAREST, /* interpolate 4 texels in nearest mipmap */ + D3DRMTEXTURE_LINEARMIPLINEAR /* interpolate 8 texels from 2 mipmaps */ +} D3DRMTEXTUREQUALITY, *LPD3DRMTEXTUREQUALITY; + +typedef enum _D3DRMCOMBINETYPE +{ D3DRMCOMBINE_REPLACE, + D3DRMCOMBINE_BEFORE, + D3DRMCOMBINE_AFTER +} D3DRMCOMBINETYPE, *LPD3DRMCOMBINETYPE; + +typedef D3DCOLORMODEL D3DRMCOLORMODEL, *LPD3DRMCOLORMODEL; + +typedef enum _D3DRMPALETTEFLAGS +{ D3DRMPALETTE_FREE, /* renderer may use this entry freely */ + D3DRMPALETTE_READONLY, /* fixed but may be used by renderer */ + D3DRMPALETTE_RESERVED /* may not be used by renderer */ +} D3DRMPALETTEFLAGS, *LPD3DRMPALETTEFLAGS; + +typedef struct _D3DRMPALETTEENTRY +{ unsigned char red; /* 0 .. 255 */ + unsigned char green; /* 0 .. 255 */ + unsigned char blue; /* 0 .. 255 */ + unsigned char flags; /* one of D3DRMPALETTEFLAGS */ +} D3DRMPALETTEENTRY, *LPD3DRMPALETTEENTRY; + +typedef struct _D3DRMIMAGE +{ int width, height; /* width and height in pixels */ + int aspectx, aspecty; /* aspect ratio for non-square pixels */ + int depth; /* bits per pixel */ + int rgb; /* if false, pixels are indices into a + palette otherwise, pixels encode + RGB values. */ + int bytes_per_line; /* number of bytes of memory for a + scanline. This must be a multiple + of 4. */ + char* buffer1; /* memory to render into (first buffer). */ + char* buffer2; /* second rendering buffer for double + buffering, set to NULL for single + buffering. */ + unsigned long red_mask; + unsigned long green_mask; + unsigned long blue_mask; + unsigned long alpha_mask; /* if rgb is true, these are masks for + the red, green and blue parts of a + pixel. Otherwise, these are masks + for the significant bits of the + red, green and blue elements in the + palette. For instance, most SVGA + displays use 64 intensities of red, + green and blue, so the masks should + all be set to 0xfc. */ + int palette_size; /* number of entries in palette */ + D3DRMPALETTEENTRY* palette; /* description of the palette (only if + rgb is false). Must be (1< /* Use Windows header files */ +#define VIRTUAL + +#include "d3drmdef.h" +#include "d3d.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The methods for IUnknown + */ +#define IUNKNOWN_METHODS(kind) \ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID *ppvObj) kind; \ + STDMETHOD_(ULONG, AddRef) (THIS) kind; \ + STDMETHOD_(ULONG, Release) (THIS) kind + +/* + * The methods for IDirect3DRMObject + */ +#define IDIRECT3DRMOBJECT_METHODS(kind) \ + STDMETHOD(Clone) (THIS_ LPUNKNOWN pUnkOuter, REFIID riid, LPVOID *ppvObj) kind; \ + STDMETHOD(AddDestroyCallback) (THIS_ D3DRMOBJECTCALLBACK, LPVOID argument) kind; \ + STDMETHOD(DeleteDestroyCallback) (THIS_ D3DRMOBJECTCALLBACK, LPVOID argument) kind; \ + STDMETHOD(SetAppData) (THIS_ DWORD data) kind; \ + STDMETHOD_(DWORD, GetAppData) (THIS) kind; \ + STDMETHOD(SetName) (THIS_ LPCSTR) kind; \ + STDMETHOD(GetName) (THIS_ LPDWORD lpdwSize, LPSTR lpName) kind; \ + STDMETHOD(GetClassName) (THIS_ LPDWORD lpdwSize, LPSTR lpName) kind + + +#define WIN_TYPES(itype, ptype) \ + typedef interface itype FAR *LP##ptype, FAR **LPLP##ptype + +WIN_TYPES(IDirect3DRMObject, DIRECT3DRMOBJECT); +WIN_TYPES(IDirect3DRMDevice, DIRECT3DRMDEVICE); +WIN_TYPES(IDirect3DRMDevice2, DIRECT3DRMDEVICE2); +WIN_TYPES(IDirect3DRMViewport, DIRECT3DRMVIEWPORT); +WIN_TYPES(IDirect3DRMFrame, DIRECT3DRMFRAME); +WIN_TYPES(IDirect3DRMFrame2, DIRECT3DRMFRAME2); +WIN_TYPES(IDirect3DRMVisual, DIRECT3DRMVISUAL); +WIN_TYPES(IDirect3DRMMesh, DIRECT3DRMMESH); +WIN_TYPES(IDirect3DRMMeshBuilder, DIRECT3DRMMESHBUILDER); +WIN_TYPES(IDirect3DRMMeshBuilder2, DIRECT3DRMMESHBUILDER2); +WIN_TYPES(IDirect3DRMFace, DIRECT3DRMFACE); +WIN_TYPES(IDirect3DRMLight, DIRECT3DRMLIGHT); +WIN_TYPES(IDirect3DRMTexture, DIRECT3DRMTEXTURE); +WIN_TYPES(IDirect3DRMTexture2, DIRECT3DRMTEXTURE2); +WIN_TYPES(IDirect3DRMWrap, DIRECT3DRMWRAP); +WIN_TYPES(IDirect3DRMMaterial, DIRECT3DRMMATERIAL); +WIN_TYPES(IDirect3DRMInterpolator, DIRECT3DRMINTERPOLATOR); +WIN_TYPES(IDirect3DRMAnimation, DIRECT3DRMANIMATION); +WIN_TYPES(IDirect3DRMAnimationSet, DIRECT3DRMANIMATIONSET); +WIN_TYPES(IDirect3DRMUserVisual, DIRECT3DRMUSERVISUAL); +WIN_TYPES(IDirect3DRMShadow, DIRECT3DRMSHADOW); +WIN_TYPES(IDirect3DRMArray, DIRECT3DRMARRAY); +WIN_TYPES(IDirect3DRMObjectArray, DIRECT3DRMOBJECTARRAY); +WIN_TYPES(IDirect3DRMDeviceArray, DIRECT3DRMDEVICEARRAY); +WIN_TYPES(IDirect3DRMFaceArray, DIRECT3DRMFACEARRAY); +WIN_TYPES(IDirect3DRMViewportArray, DIRECT3DRMVIEWPORTARRAY); +WIN_TYPES(IDirect3DRMFrameArray, DIRECT3DRMFRAMEARRAY); +WIN_TYPES(IDirect3DRMVisualArray, DIRECT3DRMVISUALARRAY); +WIN_TYPES(IDirect3DRMPickedArray, DIRECT3DRMPICKEDARRAY); +WIN_TYPES(IDirect3DRMPicked2Array, DIRECT3DRMPICKED2ARRAY); +WIN_TYPES(IDirect3DRMLightArray, DIRECT3DRMLIGHTARRAY); +WIN_TYPES(IDirect3DRMProgressiveMesh, DIRECT3DRMPROGRESSIVEMESH); + +/* + * Direct3DRM Object classes + */ +DEFINE_GUID(CLSID_CDirect3DRMDevice, 0x4fa3568e, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMViewport, 0x4fa3568f, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMFrame, 0x4fa35690, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMMesh, 0x4fa35691, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMMeshBuilder, 0x4fa35692, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMFace, 0x4fa35693, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMLight, 0x4fa35694, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMTexture, 0x4fa35695, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMWrap, 0x4fa35696, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMMaterial, 0x4fa35697, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMAnimation, 0x4fa35698, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMAnimationSet, 0x4fa35699, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMUserVisual, 0x4fa3569a, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMShadow, 0x4fa3569b, 0x623f, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(CLSID_CDirect3DRMViewportInterpolator, +0xde9eaa1, 0x3b84, 0x11d0, 0x9b, 0x6d, 0x0, 0x0, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(CLSID_CDirect3DRMFrameInterpolator, +0xde9eaa2, 0x3b84, 0x11d0, 0x9b, 0x6d, 0x0, 0x0, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(CLSID_CDirect3DRMMeshInterpolator, +0xde9eaa3, 0x3b84, 0x11d0, 0x9b, 0x6d, 0x0, 0x0, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(CLSID_CDirect3DRMLightInterpolator, +0xde9eaa6, 0x3b84, 0x11d0, 0x9b, 0x6d, 0x0, 0x0, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(CLSID_CDirect3DRMMaterialInterpolator, +0xde9eaa7, 0x3b84, 0x11d0, 0x9b, 0x6d, 0x0, 0x0, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(CLSID_CDirect3DRMTextureInterpolator, +0xde9eaa8, 0x3b84, 0x11d0, 0x9b, 0x6d, 0x0, 0x0, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(CLSID_CDirect3DRMProgressiveMesh, 0x4516ec40, 0x8f20, 0x11d0, 0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3); + + +/* + * Direct3DRM Object interfaces + */ +DEFINE_GUID(IID_IDirect3DRMObject, 0xeb16cb00, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMDevice, 0xe9e19280, 0x6e05, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMDevice2, 0x4516ec78, 0x8f20, 0x11d0, 0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(IID_IDirect3DRMViewport, 0xeb16cb02, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMFrame, 0xeb16cb03, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMFrame2, 0xc3dfbd60, 0x3988, 0x11d0, 0x9e, 0xc2, 0x0, 0x0, 0xc0, 0x29, 0x1a, 0xc3); +DEFINE_GUID(IID_IDirect3DRMVisual, 0xeb16cb04, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMMesh, 0xa3a80d01, 0x6e12, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMMeshBuilder, 0xa3a80d02, 0x6e12, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMMeshBuilder2, 0x4516ec77, 0x8f20, 0x11d0, 0x9b, 0x6d, 0x0, 0x0, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(IID_IDirect3DRMFace, 0xeb16cb07, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMLight, 0xeb16cb08, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMTexture, 0xeb16cb09, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMTexture2, 0x120f30c0, 0x1629, 0x11d0, 0x94, 0x1c, 0x0, 0x80, 0xc8, 0xc, 0xfa, 0x7b); +DEFINE_GUID(IID_IDirect3DRMWrap, 0xeb16cb0a, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMMaterial, 0xeb16cb0b, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMAnimation, 0xeb16cb0d, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMAnimationSet, 0xeb16cb0e, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMObjectArray, 0x242f6bc2, 0x3849, 0x11d0, 0x9b, 0x6d, 0x0, 0x0, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(IID_IDirect3DRMDeviceArray, 0xeb16cb10, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMViewportArray, 0xeb16cb11, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMFrameArray, 0xeb16cb12, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMVisualArray, 0xeb16cb13, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMLightArray, 0xeb16cb14, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMPickedArray, 0xeb16cb16, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMFaceArray, 0xeb16cb17, 0xd271, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMUserVisual, 0x59163de0, 0x6d43, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMShadow, 0xaf359780, 0x6ba3, 0x11cf, 0xac, 0x4a, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); +DEFINE_GUID(IID_IDirect3DRMInterpolator, 0x242f6bc1, 0x3849, 0x11d0, 0x9b, 0x6d, 0x0, 0x0, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(IID_IDirect3DRMProgressiveMesh, 0x4516ec79, 0x8f20, 0x11d0, 0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3); +DEFINE_GUID(IID_IDirect3DRMPicked2Array, 0x4516ec7b, 0x8f20, 0x11d0, 0x9b, 0x6d, 0x00, 0x00, 0xc0, 0x78, 0x1b, 0xc3); + + +typedef void (CDECL *D3DRMOBJECTCALLBACK)(LPDIRECT3DRMOBJECT obj, LPVOID arg); +typedef void (CDECL *D3DRMFRAMEMOVECALLBACK)(LPDIRECT3DRMFRAME obj, LPVOID arg, D3DVALUE delta); +typedef void (CDECL *D3DRMUPDATECALLBACK)(LPDIRECT3DRMDEVICE obj, LPVOID arg, int, LPD3DRECT); +typedef int (CDECL *D3DRMUSERVISUALCALLBACK) + ( LPDIRECT3DRMUSERVISUAL obj, LPVOID arg, D3DRMUSERVISUALREASON reason, + LPDIRECT3DRMDEVICE dev, LPDIRECT3DRMVIEWPORT view + ); +typedef HRESULT (CDECL *D3DRMLOADTEXTURECALLBACK) + (char *tex_name, void *arg, LPDIRECT3DRMTEXTURE *); +typedef void (CDECL *D3DRMLOADCALLBACK) + (LPDIRECT3DRMOBJECT object, REFIID objectguid, LPVOID arg); + + +typedef struct _D3DRMPICKDESC +{ + ULONG ulFaceIdx; + LONG lGroupIdx; + D3DVECTOR vPosition; + +} D3DRMPICKDESC, *LPD3DRMPICKDESC; + +typedef struct _D3DRMPICKDESC2 +{ + ULONG ulFaceIdx; + LONG lGroupIdx; + D3DVECTOR dvPosition; + D3DVALUE tu; + D3DVALUE tv; + D3DVECTOR dvNormal; + D3DCOLOR dcColor; + +} D3DRMPICKDESC2, *LPD3DRMPICKDESC2; + +#undef INTERFACE +#define INTERFACE IDirect3DRMObject + +/* + * Base class + */ +DECLARE_INTERFACE_(IDirect3DRMObject, IUnknown) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMVisual + +DECLARE_INTERFACE_(IDirect3DRMVisual, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMDevice + +DECLARE_INTERFACE_(IDirect3DRMDevice, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMDevice methods + */ + STDMETHOD(Init)(THIS_ ULONG width, ULONG height) PURE; + STDMETHOD(InitFromD3D)(THIS_ LPDIRECT3D lpD3D, LPDIRECT3DDEVICE lpD3DDev) PURE; + STDMETHOD(InitFromClipper)(THIS_ LPDIRECTDRAWCLIPPER lpDDClipper, LPGUID lpGUID, int width, int height) PURE; + + STDMETHOD(Update)(THIS) PURE; + STDMETHOD(AddUpdateCallback)(THIS_ D3DRMUPDATECALLBACK, LPVOID arg) PURE; + STDMETHOD(DeleteUpdateCallback)(THIS_ D3DRMUPDATECALLBACK, LPVOID arg) PURE; + STDMETHOD(SetBufferCount)(THIS_ DWORD) PURE; + STDMETHOD_(DWORD, GetBufferCount)(THIS) PURE; + + STDMETHOD(SetDither)(THIS_ BOOL) PURE; + STDMETHOD(SetShades)(THIS_ DWORD) PURE; + STDMETHOD(SetQuality)(THIS_ D3DRMRENDERQUALITY) PURE; + STDMETHOD(SetTextureQuality)(THIS_ D3DRMTEXTUREQUALITY) PURE; + + STDMETHOD(GetViewports)(THIS_ LPDIRECT3DRMVIEWPORTARRAY *return_views) PURE; + + STDMETHOD_(BOOL, GetDither)(THIS) PURE; + STDMETHOD_(DWORD, GetShades)(THIS) PURE; + STDMETHOD_(DWORD, GetHeight)(THIS) PURE; + STDMETHOD_(DWORD, GetWidth)(THIS) PURE; + STDMETHOD_(DWORD, GetTrianglesDrawn)(THIS) PURE; + STDMETHOD_(DWORD, GetWireframeOptions)(THIS) PURE; + STDMETHOD_(D3DRMRENDERQUALITY, GetQuality)(THIS) PURE; + STDMETHOD_(D3DCOLORMODEL, GetColorModel)(THIS) PURE; + STDMETHOD_(D3DRMTEXTUREQUALITY, GetTextureQuality)(THIS) PURE; + STDMETHOD(GetDirect3DDevice)(THIS_ LPDIRECT3DDEVICE *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMDevice2 + +DECLARE_INTERFACE_(IDirect3DRMDevice2, IDirect3DRMDevice) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMDevice methods + */ + STDMETHOD(Init)(THIS_ ULONG width, ULONG height) PURE; + STDMETHOD(InitFromD3D)(THIS_ LPDIRECT3D lpD3D, LPDIRECT3DDEVICE lpD3DDev) PURE; + STDMETHOD(InitFromClipper)(THIS_ LPDIRECTDRAWCLIPPER lpDDClipper, LPGUID lpGUID, int width, int height) PURE; + + STDMETHOD(Update)(THIS) PURE; + STDMETHOD(AddUpdateCallback)(THIS_ D3DRMUPDATECALLBACK, LPVOID arg) PURE; + STDMETHOD(DeleteUpdateCallback)(THIS_ D3DRMUPDATECALLBACK, LPVOID arg) PURE; + STDMETHOD(SetBufferCount)(THIS_ DWORD) PURE; + STDMETHOD_(DWORD, GetBufferCount)(THIS) PURE; + + STDMETHOD(SetDither)(THIS_ BOOL) PURE; + STDMETHOD(SetShades)(THIS_ DWORD) PURE; + STDMETHOD(SetQuality)(THIS_ D3DRMRENDERQUALITY) PURE; + STDMETHOD(SetTextureQuality)(THIS_ D3DRMTEXTUREQUALITY) PURE; + + STDMETHOD(GetViewports)(THIS_ LPDIRECT3DRMVIEWPORTARRAY *return_views) PURE; + + STDMETHOD_(BOOL, GetDither)(THIS) PURE; + STDMETHOD_(DWORD, GetShades)(THIS) PURE; + STDMETHOD_(DWORD, GetHeight)(THIS) PURE; + STDMETHOD_(DWORD, GetWidth)(THIS) PURE; + STDMETHOD_(DWORD, GetTrianglesDrawn)(THIS) PURE; + STDMETHOD_(DWORD, GetWireframeOptions)(THIS) PURE; + STDMETHOD_(D3DRMRENDERQUALITY, GetQuality)(THIS) PURE; + STDMETHOD_(D3DCOLORMODEL, GetColorModel)(THIS) PURE; + STDMETHOD_(D3DRMTEXTUREQUALITY, GetTextureQuality)(THIS) PURE; + STDMETHOD(GetDirect3DDevice)(THIS_ LPDIRECT3DDEVICE *) PURE; + + /* + * IDirect3DRMDevice2 methods + */ + STDMETHOD(InitFromD3D2)(THIS_ LPDIRECT3D2 lpD3D, LPDIRECT3DDEVICE2 lpD3DDev) PURE; + STDMETHOD(InitFromSurface)(THIS_ LPGUID lpGUID, LPDIRECTDRAW lpDD, LPDIRECTDRAWSURFACE lpDDSBack) PURE; + STDMETHOD(SetRenderMode)(THIS_ DWORD dwFlags) PURE; + STDMETHOD_(DWORD, GetRenderMode)(THIS) PURE; + STDMETHOD(GetDirect3DDevice2)(THIS_ LPDIRECT3DDEVICE2 *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMViewport + +DECLARE_INTERFACE_(IDirect3DRMViewport, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMViewport methods + */ + STDMETHOD(Init) + ( THIS_ LPDIRECT3DRMDEVICE dev, LPDIRECT3DRMFRAME camera, + DWORD xpos, DWORD ypos, DWORD width, DWORD height + ) PURE; + STDMETHOD(Clear)(THIS) PURE; + STDMETHOD(Render)(THIS_ LPDIRECT3DRMFRAME) PURE; + + STDMETHOD(SetFront)(THIS_ D3DVALUE) PURE; + STDMETHOD(SetBack)(THIS_ D3DVALUE) PURE; + STDMETHOD(SetField)(THIS_ D3DVALUE) PURE; + STDMETHOD(SetUniformScaling)(THIS_ BOOL) PURE; + STDMETHOD(SetCamera)(THIS_ LPDIRECT3DRMFRAME) PURE; + STDMETHOD(SetProjection)(THIS_ D3DRMPROJECTIONTYPE) PURE; + STDMETHOD(Transform)(THIS_ D3DRMVECTOR4D *d, D3DVECTOR *s) PURE; + STDMETHOD(InverseTransform)(THIS_ D3DVECTOR *d, D3DRMVECTOR4D *s) PURE; + STDMETHOD(Configure)(THIS_ LONG x, LONG y, DWORD width, DWORD height) PURE; + STDMETHOD(ForceUpdate)(THIS_ DWORD x1, DWORD y1, DWORD x2, DWORD y2) PURE; + STDMETHOD(SetPlane)(THIS_ D3DVALUE left, D3DVALUE right, D3DVALUE bottom, D3DVALUE top) PURE; + + STDMETHOD(GetCamera)(THIS_ LPDIRECT3DRMFRAME *) PURE; + STDMETHOD(GetDevice)(THIS_ LPDIRECT3DRMDEVICE *) PURE; + STDMETHOD(GetPlane)(THIS_ D3DVALUE *left, D3DVALUE *right, D3DVALUE *bottom, D3DVALUE *top) PURE; + STDMETHOD(Pick)(THIS_ LONG x, LONG y, LPDIRECT3DRMPICKEDARRAY *return_visuals) PURE; + + STDMETHOD_(BOOL, GetUniformScaling)(THIS) PURE; + STDMETHOD_(LONG, GetX)(THIS) PURE; + STDMETHOD_(LONG, GetY)(THIS) PURE; + STDMETHOD_(DWORD, GetWidth)(THIS) PURE; + STDMETHOD_(DWORD, GetHeight)(THIS) PURE; + STDMETHOD_(D3DVALUE, GetField)(THIS) PURE; + STDMETHOD_(D3DVALUE, GetBack)(THIS) PURE; + STDMETHOD_(D3DVALUE, GetFront)(THIS) PURE; + STDMETHOD_(D3DRMPROJECTIONTYPE, GetProjection)(THIS) PURE; + STDMETHOD(GetDirect3DViewport)(THIS_ LPDIRECT3DVIEWPORT *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMFrame + +DECLARE_INTERFACE_(IDirect3DRMFrame, IDirect3DRMVisual) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMFrame methods + */ + STDMETHOD(AddChild)(THIS_ LPDIRECT3DRMFRAME child) PURE; + STDMETHOD(AddLight)(THIS_ LPDIRECT3DRMLIGHT) PURE; + STDMETHOD(AddMoveCallback)(THIS_ D3DRMFRAMEMOVECALLBACK, VOID *arg) PURE; + STDMETHOD(AddTransform)(THIS_ D3DRMCOMBINETYPE, D3DRMMATRIX4D) PURE; + STDMETHOD(AddTranslation)(THIS_ D3DRMCOMBINETYPE, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(AddScale)(THIS_ D3DRMCOMBINETYPE, D3DVALUE sx, D3DVALUE sy, D3DVALUE sz) PURE; + STDMETHOD(AddRotation)(THIS_ D3DRMCOMBINETYPE, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta) PURE; + STDMETHOD(AddVisual)(THIS_ LPDIRECT3DRMVISUAL) PURE; + STDMETHOD(GetChildren)(THIS_ LPDIRECT3DRMFRAMEARRAY *children) PURE; + STDMETHOD_(D3DCOLOR, GetColor)(THIS) PURE; + STDMETHOD(GetLights)(THIS_ LPDIRECT3DRMLIGHTARRAY *lights) PURE; + STDMETHOD_(D3DRMMATERIALMODE, GetMaterialMode)(THIS) PURE; + STDMETHOD(GetParent)(THIS_ LPDIRECT3DRMFRAME *) PURE; + STDMETHOD(GetPosition)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR return_position) PURE; + STDMETHOD(GetRotation)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR axis, LPD3DVALUE return_theta) PURE; + STDMETHOD(GetScene)(THIS_ LPDIRECT3DRMFRAME *) PURE; + STDMETHOD_(D3DRMSORTMODE, GetSortMode)(THIS) PURE; + STDMETHOD(GetTexture)(THIS_ LPDIRECT3DRMTEXTURE *) PURE; + STDMETHOD(GetTransform)(THIS_ D3DRMMATRIX4D return_matrix) PURE; + STDMETHOD(GetVelocity)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR return_velocity, BOOL with_rotation) PURE; + STDMETHOD(GetOrientation)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR dir, LPD3DVECTOR up) PURE; + STDMETHOD(GetVisuals)(THIS_ LPDIRECT3DRMVISUALARRAY *visuals) PURE; + STDMETHOD(GetTextureTopology)(THIS_ BOOL *wrap_u, BOOL *wrap_v) PURE; + STDMETHOD(InverseTransform)(THIS_ D3DVECTOR *d, D3DVECTOR *s) PURE; + STDMETHOD(Load)(THIS_ LPVOID filename, LPVOID name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURECALLBACK, LPVOID lpArg)PURE; + STDMETHOD(LookAt)(THIS_ LPDIRECT3DRMFRAME target, LPDIRECT3DRMFRAME reference, D3DRMFRAMECONSTRAINT) PURE; + STDMETHOD(Move)(THIS_ D3DVALUE delta) PURE; + STDMETHOD(DeleteChild)(THIS_ LPDIRECT3DRMFRAME) PURE; + STDMETHOD(DeleteLight)(THIS_ LPDIRECT3DRMLIGHT) PURE; + STDMETHOD(DeleteMoveCallback)(THIS_ D3DRMFRAMEMOVECALLBACK, VOID *arg) PURE; + STDMETHOD(DeleteVisual)(THIS_ LPDIRECT3DRMVISUAL) PURE; + STDMETHOD_(D3DCOLOR, GetSceneBackground)(THIS) PURE; + STDMETHOD(GetSceneBackgroundDepth)(THIS_ LPDIRECTDRAWSURFACE *) PURE; + STDMETHOD_(D3DCOLOR, GetSceneFogColor)(THIS) PURE; + STDMETHOD_(BOOL, GetSceneFogEnable)(THIS) PURE; + STDMETHOD_(D3DRMFOGMODE, GetSceneFogMode)(THIS) PURE; + STDMETHOD(GetSceneFogParams)(THIS_ D3DVALUE *return_start, D3DVALUE *return_end, D3DVALUE *return_density) PURE; + STDMETHOD(SetSceneBackground)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetSceneBackgroundRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + STDMETHOD(SetSceneBackgroundDepth)(THIS_ LPDIRECTDRAWSURFACE) PURE; + STDMETHOD(SetSceneBackgroundImage)(THIS_ LPDIRECT3DRMTEXTURE) PURE; + STDMETHOD(SetSceneFogEnable)(THIS_ BOOL) PURE; + STDMETHOD(SetSceneFogColor)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetSceneFogMode)(THIS_ D3DRMFOGMODE) PURE; + STDMETHOD(SetSceneFogParams)(THIS_ D3DVALUE start, D3DVALUE end, D3DVALUE density) PURE; + STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetColorRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + STDMETHOD_(D3DRMZBUFFERMODE, GetZbufferMode)(THIS) PURE; + STDMETHOD(SetMaterialMode)(THIS_ D3DRMMATERIALMODE) PURE; + STDMETHOD(SetOrientation) + ( THIS_ LPDIRECT3DRMFRAME reference, + D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, + D3DVALUE ux, D3DVALUE uy, D3DVALUE uz + ) PURE; + STDMETHOD(SetPosition)(THIS_ LPDIRECT3DRMFRAME reference, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(SetRotation)(THIS_ LPDIRECT3DRMFRAME reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta) PURE; + STDMETHOD(SetSortMode)(THIS_ D3DRMSORTMODE) PURE; + STDMETHOD(SetTexture)(THIS_ LPDIRECT3DRMTEXTURE) PURE; + STDMETHOD(SetTextureTopology)(THIS_ BOOL wrap_u, BOOL wrap_v) PURE; + STDMETHOD(SetVelocity)(THIS_ LPDIRECT3DRMFRAME reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, BOOL with_rotation) PURE; + STDMETHOD(SetZbufferMode)(THIS_ D3DRMZBUFFERMODE) PURE; + STDMETHOD(Transform)(THIS_ D3DVECTOR *d, D3DVECTOR *s) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMFrame2 + +DECLARE_INTERFACE_(IDirect3DRMFrame2, IDirect3DRMFrame) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMFrame methods + */ + STDMETHOD(AddChild)(THIS_ LPDIRECT3DRMFRAME child) PURE; + STDMETHOD(AddLight)(THIS_ LPDIRECT3DRMLIGHT) PURE; + STDMETHOD(AddMoveCallback)(THIS_ D3DRMFRAMEMOVECALLBACK, VOID *arg) PURE; + STDMETHOD(AddTransform)(THIS_ D3DRMCOMBINETYPE, D3DRMMATRIX4D) PURE; + STDMETHOD(AddTranslation)(THIS_ D3DRMCOMBINETYPE, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(AddScale)(THIS_ D3DRMCOMBINETYPE, D3DVALUE sx, D3DVALUE sy, D3DVALUE sz) PURE; + STDMETHOD(AddRotation)(THIS_ D3DRMCOMBINETYPE, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta) PURE; + STDMETHOD(AddVisual)(THIS_ LPDIRECT3DRMVISUAL) PURE; + STDMETHOD(GetChildren)(THIS_ LPDIRECT3DRMFRAMEARRAY *children) PURE; + STDMETHOD_(D3DCOLOR, GetColor)(THIS) PURE; + STDMETHOD(GetLights)(THIS_ LPDIRECT3DRMLIGHTARRAY *lights) PURE; + STDMETHOD_(D3DRMMATERIALMODE, GetMaterialMode)(THIS) PURE; + STDMETHOD(GetParent)(THIS_ LPDIRECT3DRMFRAME *) PURE; + STDMETHOD(GetPosition)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR return_position) PURE; + STDMETHOD(GetRotation)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR axis, LPD3DVALUE return_theta) PURE; + STDMETHOD(GetScene)(THIS_ LPDIRECT3DRMFRAME *) PURE; + STDMETHOD_(D3DRMSORTMODE, GetSortMode)(THIS) PURE; + STDMETHOD(GetTexture)(THIS_ LPDIRECT3DRMTEXTURE *) PURE; + STDMETHOD(GetTransform)(THIS_ D3DRMMATRIX4D return_matrix) PURE; + STDMETHOD(GetVelocity)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR return_velocity, BOOL with_rotation) PURE; + STDMETHOD(GetOrientation)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DVECTOR dir, LPD3DVECTOR up) PURE; + STDMETHOD(GetVisuals)(THIS_ LPDIRECT3DRMVISUALARRAY *visuals) PURE; + STDMETHOD(GetTextureTopology)(THIS_ BOOL *wrap_u, BOOL *wrap_v) PURE; + STDMETHOD(InverseTransform)(THIS_ D3DVECTOR *d, D3DVECTOR *s) PURE; + STDMETHOD(Load)(THIS_ LPVOID filename, LPVOID name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURECALLBACK, LPVOID lpArg)PURE; + STDMETHOD(LookAt)(THIS_ LPDIRECT3DRMFRAME target, LPDIRECT3DRMFRAME reference, D3DRMFRAMECONSTRAINT) PURE; + STDMETHOD(Move)(THIS_ D3DVALUE delta) PURE; + STDMETHOD(DeleteChild)(THIS_ LPDIRECT3DRMFRAME) PURE; + STDMETHOD(DeleteLight)(THIS_ LPDIRECT3DRMLIGHT) PURE; + STDMETHOD(DeleteMoveCallback)(THIS_ D3DRMFRAMEMOVECALLBACK, VOID *arg) PURE; + STDMETHOD(DeleteVisual)(THIS_ LPDIRECT3DRMVISUAL) PURE; + STDMETHOD_(D3DCOLOR, GetSceneBackground)(THIS) PURE; + STDMETHOD(GetSceneBackgroundDepth)(THIS_ LPDIRECTDRAWSURFACE *) PURE; + STDMETHOD_(D3DCOLOR, GetSceneFogColor)(THIS) PURE; + STDMETHOD_(BOOL, GetSceneFogEnable)(THIS) PURE; + STDMETHOD_(D3DRMFOGMODE, GetSceneFogMode)(THIS) PURE; + STDMETHOD(GetSceneFogParams)(THIS_ D3DVALUE *return_start, D3DVALUE *return_end, D3DVALUE *return_density) PURE; + STDMETHOD(SetSceneBackground)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetSceneBackgroundRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + STDMETHOD(SetSceneBackgroundDepth)(THIS_ LPDIRECTDRAWSURFACE) PURE; + STDMETHOD(SetSceneBackgroundImage)(THIS_ LPDIRECT3DRMTEXTURE) PURE; + STDMETHOD(SetSceneFogEnable)(THIS_ BOOL) PURE; + STDMETHOD(SetSceneFogColor)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetSceneFogMode)(THIS_ D3DRMFOGMODE) PURE; + STDMETHOD(SetSceneFogParams)(THIS_ D3DVALUE start, D3DVALUE end, D3DVALUE density) PURE; + STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetColorRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + STDMETHOD_(D3DRMZBUFFERMODE, GetZbufferMode)(THIS) PURE; + STDMETHOD(SetMaterialMode)(THIS_ D3DRMMATERIALMODE) PURE; + STDMETHOD(SetOrientation) + ( THIS_ LPDIRECT3DRMFRAME reference, + D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, + D3DVALUE ux, D3DVALUE uy, D3DVALUE uz + ) PURE; + STDMETHOD(SetPosition)(THIS_ LPDIRECT3DRMFRAME reference, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(SetRotation)(THIS_ LPDIRECT3DRMFRAME reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, D3DVALUE theta) PURE; + STDMETHOD(SetSortMode)(THIS_ D3DRMSORTMODE) PURE; + STDMETHOD(SetTexture)(THIS_ LPDIRECT3DRMTEXTURE) PURE; + STDMETHOD(SetTextureTopology)(THIS_ BOOL wrap_u, BOOL wrap_v) PURE; + STDMETHOD(SetVelocity)(THIS_ LPDIRECT3DRMFRAME reference, D3DVALUE x, D3DVALUE y, D3DVALUE z, BOOL with_rotation) PURE; + STDMETHOD(SetZbufferMode)(THIS_ D3DRMZBUFFERMODE) PURE; + STDMETHOD(Transform)(THIS_ D3DVECTOR *d, D3DVECTOR *s) PURE; + + /* + * IDirect3DRMFrame2 methods + */ + STDMETHOD(AddMoveCallback2)(THIS_ D3DRMFRAMEMOVECALLBACK, VOID *arg, DWORD dwFlags) PURE; + STDMETHOD(GetBox)(THIS_ LPD3DRMBOX) PURE; + STDMETHOD_(BOOL, GetBoxEnable)(THIS) PURE; + STDMETHOD(GetAxes)(THIS_ LPD3DVECTOR dir, LPD3DVECTOR up); + STDMETHOD(GetMaterial)(THIS_ LPDIRECT3DRMMATERIAL *) PURE; + STDMETHOD_(BOOL, GetInheritAxes)(THIS); + STDMETHOD(GetHierarchyBox)(THIS_ LPD3DRMBOX) PURE; + + STDMETHOD(SetBox)(THIS_ LPD3DRMBOX) PURE; + STDMETHOD(SetBoxEnable)(THIS_ BOOL) PURE; + STDMETHOD(SetAxes)(THIS_ D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, + D3DVALUE ux, D3DVALUE uy, D3DVALUE uz); + STDMETHOD(SetInheritAxes)(THIS_ BOOL inherit_from_parent); + STDMETHOD(SetMaterial)(THIS_ LPDIRECT3DRMMATERIAL) PURE; + STDMETHOD(SetQuaternion)(THIS_ LPDIRECT3DRMFRAME reference, D3DRMQUATERNION *q) PURE; + + STDMETHOD(RayPick)(THIS_ LPDIRECT3DRMFRAME reference, LPD3DRMRAY ray, DWORD dwFlags, LPDIRECT3DRMPICKED2ARRAY *return_visuals) PURE; + STDMETHOD(Save)(THIS_ LPCSTR filename, D3DRMXOFFORMAT d3dFormat, + D3DRMSAVEOPTIONS d3dSaveFlags); +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMMesh + +DECLARE_INTERFACE_(IDirect3DRMMesh, IDirect3DRMVisual) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMMesh methods + */ + STDMETHOD(Scale)(THIS_ D3DVALUE sx, D3DVALUE sy, D3DVALUE sz) PURE; + STDMETHOD(Translate)(THIS_ D3DVALUE tx, D3DVALUE ty, D3DVALUE tz) PURE; + STDMETHOD(GetBox)(THIS_ D3DRMBOX *) PURE; + STDMETHOD(AddGroup)(THIS_ unsigned vCount, unsigned fCount, unsigned vPerFace, unsigned *fData, D3DRMGROUPINDEX *returnId) PURE; + STDMETHOD(SetVertices)(THIS_ D3DRMGROUPINDEX id, unsigned index, unsigned count, D3DRMVERTEX *values) PURE; + STDMETHOD(SetGroupColor)(THIS_ D3DRMGROUPINDEX id, D3DCOLOR value) PURE; + STDMETHOD(SetGroupColorRGB)(THIS_ D3DRMGROUPINDEX id, D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + STDMETHOD(SetGroupMapping)(THIS_ D3DRMGROUPINDEX id, D3DRMMAPPING value) PURE; + STDMETHOD(SetGroupQuality)(THIS_ D3DRMGROUPINDEX id, D3DRMRENDERQUALITY value) PURE; + STDMETHOD(SetGroupMaterial)(THIS_ D3DRMGROUPINDEX id, LPDIRECT3DRMMATERIAL value) PURE; + STDMETHOD(SetGroupTexture)(THIS_ D3DRMGROUPINDEX id, LPDIRECT3DRMTEXTURE value) PURE; + + STDMETHOD_(unsigned, GetGroupCount)(THIS) PURE; + STDMETHOD(GetGroup)(THIS_ D3DRMGROUPINDEX id, unsigned *vCount, unsigned *fCount, unsigned *vPerFace, DWORD *fDataSize, unsigned *fData) PURE; + STDMETHOD(GetVertices)(THIS_ D3DRMGROUPINDEX id, DWORD index, DWORD count, D3DRMVERTEX *returnPtr) PURE; + STDMETHOD_(D3DCOLOR, GetGroupColor)(THIS_ D3DRMGROUPINDEX id) PURE; + STDMETHOD_(D3DRMMAPPING, GetGroupMapping)(THIS_ D3DRMGROUPINDEX id) PURE; + STDMETHOD_(D3DRMRENDERQUALITY, GetGroupQuality)(THIS_ D3DRMGROUPINDEX id) PURE; + STDMETHOD(GetGroupMaterial)(THIS_ D3DRMGROUPINDEX id, LPDIRECT3DRMMATERIAL *returnPtr) PURE; + STDMETHOD(GetGroupTexture)(THIS_ D3DRMGROUPINDEX id, LPDIRECT3DRMTEXTURE *returnPtr) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMProgressiveMesh + +DECLARE_INTERFACE_(IDirect3DRMProgressiveMesh, IDirect3DRMVisual) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMProgressiveMesh methods + */ + STDMETHOD(Load) (THIS_ LPVOID lpObjLocation, LPVOID lpObjId, + D3DRMLOADOPTIONS dloLoadflags, D3DRMLOADTEXTURECALLBACK lpCallback, + LPVOID lpArg) PURE; + STDMETHOD(GetLoadStatus) (THIS_ LPD3DRMPMESHLOADSTATUS lpStatus) PURE; + STDMETHOD(SetMinRenderDetail) (THIS_ D3DVALUE d3dVal) PURE; + STDMETHOD(Abort) (THIS_ DWORD dwFlags) PURE; + + STDMETHOD(GetFaceDetail) (THIS_ LPDWORD lpdwCount) PURE; + STDMETHOD(GetVertexDetail) (THIS_ LPDWORD lpdwCount) PURE; + STDMETHOD(SetFaceDetail) (THIS_ DWORD dwCount) PURE; + STDMETHOD(SetVertexDetail) (THIS_ DWORD dwCount) PURE; + STDMETHOD(GetFaceDetailRange) (THIS_ LPDWORD lpdwMin, LPDWORD lpdwMax) PURE; + STDMETHOD(GetVertexDetailRange) (THIS_ LPDWORD lpdwMin, LPDWORD lpdwMax) PURE; + STDMETHOD(GetDetail) (THIS_ D3DVALUE *lpdvVal) PURE; + STDMETHOD(SetDetail) (THIS_ D3DVALUE d3dVal) PURE; + + STDMETHOD(RegisterEvents) (THIS_ HANDLE hEvent, DWORD dwFlags, DWORD dwReserved) PURE; + STDMETHOD(CreateMesh) (THIS_ LPDIRECT3DRMMESH *lplpD3DRMMesh) PURE; + STDMETHOD(Duplicate) (THIS_ LPDIRECT3DRMPROGRESSIVEMESH *lplpD3DRMPMesh) PURE; + STDMETHOD(GetBox) (THIS_ LPD3DRMBOX lpBBox) PURE; + STDMETHOD(SetQuality) (THIS_ D3DRMRENDERQUALITY) PURE; + STDMETHOD(GetQuality) (THIS_ LPD3DRMRENDERQUALITY lpdwquality) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMShadow + +DECLARE_INTERFACE_(IDirect3DRMShadow, IDirect3DRMVisual) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMShadow methods + */ + STDMETHOD(Init) + ( THIS_ LPDIRECT3DRMVISUAL visual, LPDIRECT3DRMLIGHT light, + D3DVALUE px, D3DVALUE py, D3DVALUE pz, + D3DVALUE nx, D3DVALUE ny, D3DVALUE nz + ) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMFace + +DECLARE_INTERFACE_(IDirect3DRMFace, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMFace methods + */ + STDMETHOD(AddVertex)(THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(AddVertexAndNormalIndexed)(THIS_ DWORD vertex, DWORD normal) PURE; + STDMETHOD(SetColorRGB)(THIS_ D3DVALUE, D3DVALUE, D3DVALUE) PURE; + STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetTexture)(THIS_ LPDIRECT3DRMTEXTURE) PURE; + STDMETHOD(SetTextureCoordinates)(THIS_ DWORD vertex, D3DVALUE u, D3DVALUE v) PURE; + STDMETHOD(SetMaterial)(THIS_ LPDIRECT3DRMMATERIAL) PURE; + STDMETHOD(SetTextureTopology)(THIS_ BOOL wrap_u, BOOL wrap_v) PURE; + + STDMETHOD(GetVertex)(THIS_ DWORD index, D3DVECTOR *vertex, D3DVECTOR *normal) PURE; + STDMETHOD(GetVertices)(THIS_ DWORD *vertex_count, D3DVECTOR *coords, D3DVECTOR *normals); + STDMETHOD(GetTextureCoordinates)(THIS_ DWORD vertex, D3DVALUE *u, D3DVALUE *v) PURE; + STDMETHOD(GetTextureTopology)(THIS_ BOOL *wrap_u, BOOL *wrap_v) PURE; + STDMETHOD(GetNormal)(THIS_ D3DVECTOR *) PURE; + STDMETHOD(GetTexture)(THIS_ LPDIRECT3DRMTEXTURE *) PURE; + STDMETHOD(GetMaterial)(THIS_ LPDIRECT3DRMMATERIAL *) PURE; + + STDMETHOD_(int, GetVertexCount)(THIS) PURE; + STDMETHOD_(int, GetVertexIndex)(THIS_ DWORD which) PURE; + STDMETHOD_(int, GetTextureCoordinateIndex)(THIS_ DWORD which) PURE; + STDMETHOD_(D3DCOLOR, GetColor)(THIS) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMMeshBuilder + +DECLARE_INTERFACE_(IDirect3DRMMeshBuilder, IDirect3DRMVisual) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMMeshBuilder methods + */ + STDMETHOD(Load)(THIS_ LPVOID filename, LPVOID name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURECALLBACK, LPVOID lpArg) PURE; + STDMETHOD(Save)(THIS_ const char *filename, D3DRMXOFFORMAT, D3DRMSAVEOPTIONS save) PURE; + STDMETHOD(Scale)(THIS_ D3DVALUE sx, D3DVALUE sy, D3DVALUE sz) PURE; + STDMETHOD(Translate)(THIS_ D3DVALUE tx, D3DVALUE ty, D3DVALUE tz) PURE; + STDMETHOD(SetColorSource)(THIS_ D3DRMCOLORSOURCE) PURE; + STDMETHOD(GetBox)(THIS_ D3DRMBOX *) PURE; + STDMETHOD(GenerateNormals)(THIS) PURE; + STDMETHOD_(D3DRMCOLORSOURCE, GetColorSource)(THIS) PURE; + + STDMETHOD(AddMesh)(THIS_ LPDIRECT3DRMMESH) PURE; + STDMETHOD(AddMeshBuilder)(THIS_ LPDIRECT3DRMMESHBUILDER) PURE; + STDMETHOD(AddFrame)(THIS_ LPDIRECT3DRMFRAME) PURE; + STDMETHOD(AddFace)(THIS_ LPDIRECT3DRMFACE) PURE; + STDMETHOD(AddFaces) + ( THIS_ DWORD vcount, D3DVECTOR *vertices, DWORD ncount, D3DVECTOR *normals, + DWORD *data, LPDIRECT3DRMFACEARRAY* + ) PURE; + STDMETHOD(ReserveSpace)(THIS_ DWORD vertex_Count, DWORD normal_count, DWORD face_count) PURE; + STDMETHOD(SetColorRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetTexture)(THIS_ LPDIRECT3DRMTEXTURE) PURE; + STDMETHOD(SetMaterial)(THIS_ LPDIRECT3DRMMATERIAL) PURE; + STDMETHOD(SetTextureTopology)(THIS_ BOOL wrap_u, BOOL wrap_v) PURE; + STDMETHOD(SetQuality)(THIS_ D3DRMRENDERQUALITY) PURE; + STDMETHOD(SetPerspective)(THIS_ BOOL) PURE; + STDMETHOD(SetVertex)(THIS_ DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(SetNormal)(THIS_ DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(SetTextureCoordinates)(THIS_ DWORD index, D3DVALUE u, D3DVALUE v) PURE; + STDMETHOD(SetVertexColor)(THIS_ DWORD index, D3DCOLOR) PURE; + STDMETHOD(SetVertexColorRGB)(THIS_ DWORD index, D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + + STDMETHOD(GetFaces)(THIS_ LPDIRECT3DRMFACEARRAY*) PURE; + STDMETHOD(GetVertices) + ( THIS_ DWORD *vcount, D3DVECTOR *vertices, DWORD *ncount, D3DVECTOR *normals, DWORD *face_data_size, DWORD *face_data + ) PURE; + STDMETHOD(GetTextureCoordinates)(THIS_ DWORD index, D3DVALUE *u, D3DVALUE *v) PURE; + + STDMETHOD_(int, AddVertex)(THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD_(int, AddNormal)(THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(CreateFace)(THIS_ LPDIRECT3DRMFACE*) PURE; + STDMETHOD_(D3DRMRENDERQUALITY, GetQuality)(THIS) PURE; + STDMETHOD_(BOOL, GetPerspective)(THIS) PURE; + STDMETHOD_(int, GetFaceCount)(THIS) PURE; + STDMETHOD_(int, GetVertexCount)(THIS) PURE; + STDMETHOD_(D3DCOLOR, GetVertexColor)(THIS_ DWORD index) PURE; + + STDMETHOD(CreateMesh)(THIS_ LPDIRECT3DRMMESH*) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMMeshBuilder2 + +DECLARE_INTERFACE_(IDirect3DRMMeshBuilder2, IDirect3DRMMeshBuilder) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMMeshBuilder methods + */ + STDMETHOD(Load)(THIS_ LPVOID filename, LPVOID name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURECALLBACK, LPVOID lpArg) PURE; + STDMETHOD(Save)(THIS_ const char *filename, D3DRMXOFFORMAT, D3DRMSAVEOPTIONS save) PURE; + STDMETHOD(Scale)(THIS_ D3DVALUE sx, D3DVALUE sy, D3DVALUE sz) PURE; + STDMETHOD(Translate)(THIS_ D3DVALUE tx, D3DVALUE ty, D3DVALUE tz) PURE; + STDMETHOD(SetColorSource)(THIS_ D3DRMCOLORSOURCE) PURE; + STDMETHOD(GetBox)(THIS_ D3DRMBOX *) PURE; + STDMETHOD(GenerateNormals)(THIS) PURE; + STDMETHOD_(D3DRMCOLORSOURCE, GetColorSource)(THIS) PURE; + + STDMETHOD(AddMesh)(THIS_ LPDIRECT3DRMMESH) PURE; + STDMETHOD(AddMeshBuilder)(THIS_ LPDIRECT3DRMMESHBUILDER) PURE; + STDMETHOD(AddFrame)(THIS_ LPDIRECT3DRMFRAME) PURE; + STDMETHOD(AddFace)(THIS_ LPDIRECT3DRMFACE) PURE; + STDMETHOD(AddFaces) + ( THIS_ DWORD vcount, D3DVECTOR *vertices, DWORD ncount, D3DVECTOR *normals, + DWORD *data, LPDIRECT3DRMFACEARRAY* + ) PURE; + STDMETHOD(ReserveSpace)(THIS_ DWORD vertex_Count, DWORD normal_count, DWORD face_count) PURE; + STDMETHOD(SetColorRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetTexture)(THIS_ LPDIRECT3DRMTEXTURE) PURE; + STDMETHOD(SetMaterial)(THIS_ LPDIRECT3DRMMATERIAL) PURE; + STDMETHOD(SetTextureTopology)(THIS_ BOOL wrap_u, BOOL wrap_v) PURE; + STDMETHOD(SetQuality)(THIS_ D3DRMRENDERQUALITY) PURE; + STDMETHOD(SetPerspective)(THIS_ BOOL) PURE; + STDMETHOD(SetVertex)(THIS_ DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(SetNormal)(THIS_ DWORD index, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(SetTextureCoordinates)(THIS_ DWORD index, D3DVALUE u, D3DVALUE v) PURE; + STDMETHOD(SetVertexColor)(THIS_ DWORD index, D3DCOLOR) PURE; + STDMETHOD(SetVertexColorRGB)(THIS_ DWORD index, D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + + STDMETHOD(GetFaces)(THIS_ LPDIRECT3DRMFACEARRAY*) PURE; + STDMETHOD(GetVertices) + ( THIS_ DWORD *vcount, D3DVECTOR *vertices, DWORD *ncount, D3DVECTOR *normals, DWORD *face_data_size, DWORD *face_data + ) PURE; + STDMETHOD(GetTextureCoordinates)(THIS_ DWORD index, D3DVALUE *u, D3DVALUE *v) PURE; + + STDMETHOD_(int, AddVertex)(THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD_(int, AddNormal)(THIS_ D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(CreateFace)(THIS_ LPDIRECT3DRMFACE*) PURE; + STDMETHOD_(D3DRMRENDERQUALITY, GetQuality)(THIS) PURE; + STDMETHOD_(BOOL, GetPerspective)(THIS) PURE; + STDMETHOD_(int, GetFaceCount)(THIS) PURE; + STDMETHOD_(int, GetVertexCount)(THIS) PURE; + STDMETHOD_(D3DCOLOR, GetVertexColor)(THIS_ DWORD index) PURE; + + STDMETHOD(CreateMesh)(THIS_ LPDIRECT3DRMMESH*) PURE; + + /* + * IDirect3DRMMeshBuilder2 methods + */ + STDMETHOD(GenerateNormals2)(THIS_ D3DVALUE crease, DWORD dwFlags) PURE; + STDMETHOD(GetFace)(THIS_ DWORD index, LPDIRECT3DRMFACE*) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMLight + +DECLARE_INTERFACE_(IDirect3DRMLight, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMLight methods + */ + STDMETHOD(SetType)(THIS_ D3DRMLIGHTTYPE) PURE; + STDMETHOD(SetColor)(THIS_ D3DCOLOR) PURE; + STDMETHOD(SetColorRGB)(THIS_ D3DVALUE red, D3DVALUE green, D3DVALUE blue) PURE; + STDMETHOD(SetRange)(THIS_ D3DVALUE) PURE; + STDMETHOD(SetUmbra)(THIS_ D3DVALUE) PURE; + STDMETHOD(SetPenumbra)(THIS_ D3DVALUE) PURE; + STDMETHOD(SetConstantAttenuation)(THIS_ D3DVALUE) PURE; + STDMETHOD(SetLinearAttenuation)(THIS_ D3DVALUE) PURE; + STDMETHOD(SetQuadraticAttenuation)(THIS_ D3DVALUE) PURE; + + STDMETHOD_(D3DVALUE, GetRange)(THIS) PURE; + STDMETHOD_(D3DVALUE, GetUmbra)(THIS) PURE; + STDMETHOD_(D3DVALUE, GetPenumbra)(THIS) PURE; + STDMETHOD_(D3DVALUE, GetConstantAttenuation)(THIS) PURE; + STDMETHOD_(D3DVALUE, GetLinearAttenuation)(THIS) PURE; + STDMETHOD_(D3DVALUE, GetQuadraticAttenuation)(THIS) PURE; + STDMETHOD_(D3DCOLOR, GetColor)(THIS) PURE; + STDMETHOD_(D3DRMLIGHTTYPE, GetType)(THIS) PURE; + + STDMETHOD(SetEnableFrame)(THIS_ LPDIRECT3DRMFRAME) PURE; + STDMETHOD(GetEnableFrame)(THIS_ LPDIRECT3DRMFRAME*) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMTexture + +DECLARE_INTERFACE_(IDirect3DRMTexture, IDirect3DRMVisual) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMTexture methods + */ + STDMETHOD(InitFromFile)(THIS_ const char *filename) PURE; + STDMETHOD(InitFromSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDS) PURE; + STDMETHOD(InitFromResource)(THIS_ HRSRC) PURE; + STDMETHOD(Changed)(THIS_ BOOL pixels, BOOL palette) PURE; + + STDMETHOD(SetColors)(THIS_ DWORD) PURE; + STDMETHOD(SetShades)(THIS_ DWORD) PURE; + STDMETHOD(SetDecalSize)(THIS_ D3DVALUE width, D3DVALUE height) PURE; + STDMETHOD(SetDecalOrigin)(THIS_ LONG x, LONG y) PURE; + STDMETHOD(SetDecalScale)(THIS_ DWORD) PURE; + STDMETHOD(SetDecalTransparency)(THIS_ BOOL) PURE; + STDMETHOD(SetDecalTransparentColor)(THIS_ D3DCOLOR) PURE; + + STDMETHOD(GetDecalSize)(THIS_ D3DVALUE *width_return, D3DVALUE *height_return) PURE; + STDMETHOD(GetDecalOrigin)(THIS_ LONG *x_return, LONG *y_return) PURE; + + STDMETHOD_(D3DRMIMAGE *, GetImage)(THIS) PURE; + STDMETHOD_(DWORD, GetShades)(THIS) PURE; + STDMETHOD_(DWORD, GetColors)(THIS) PURE; + STDMETHOD_(DWORD, GetDecalScale)(THIS) PURE; + STDMETHOD_(BOOL, GetDecalTransparency)(THIS) PURE; + STDMETHOD_(D3DCOLOR, GetDecalTransparentColor)(THIS) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMTexture2 + +DECLARE_INTERFACE_(IDirect3DRMTexture2, IDirect3DRMTexture) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMTexture methods + */ + STDMETHOD(InitFromFile)(THIS_ const char *filename) PURE; + STDMETHOD(InitFromSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDS) PURE; + STDMETHOD(InitFromResource)(THIS_ HRSRC) PURE; + STDMETHOD(Changed)(THIS_ BOOL pixels, BOOL palette) PURE; + + STDMETHOD(SetColors)(THIS_ DWORD) PURE; + STDMETHOD(SetShades)(THIS_ DWORD) PURE; + STDMETHOD(SetDecalSize)(THIS_ D3DVALUE width, D3DVALUE height) PURE; + STDMETHOD(SetDecalOrigin)(THIS_ LONG x, LONG y) PURE; + STDMETHOD(SetDecalScale)(THIS_ DWORD) PURE; + STDMETHOD(SetDecalTransparency)(THIS_ BOOL) PURE; + STDMETHOD(SetDecalTransparentColor)(THIS_ D3DCOLOR) PURE; + + STDMETHOD(GetDecalSize)(THIS_ D3DVALUE *width_return, D3DVALUE *height_return) PURE; + STDMETHOD(GetDecalOrigin)(THIS_ LONG *x_return, LONG *y_return) PURE; + + STDMETHOD_(D3DRMIMAGE *, GetImage)(THIS) PURE; + STDMETHOD_(DWORD, GetShades)(THIS) PURE; + STDMETHOD_(DWORD, GetColors)(THIS) PURE; + STDMETHOD_(DWORD, GetDecalScale)(THIS) PURE; + STDMETHOD_(BOOL, GetDecalTransparency)(THIS) PURE; + STDMETHOD_(D3DCOLOR, GetDecalTransparentColor)(THIS) PURE; + + /* + * IDirect3DRMTexture2 methods + */ + STDMETHOD(InitFromImage)(THIS_ LPD3DRMIMAGE) PURE; + STDMETHOD(InitFromResource2)(THIS_ HMODULE hModule, LPCTSTR strName, LPCTSTR strType) PURE; + STDMETHOD(GenerateMIPMap)(THIS_ DWORD) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMWrap + +DECLARE_INTERFACE_(IDirect3DRMWrap, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMWrap methods + */ + STDMETHOD(Init) + ( THIS_ D3DRMWRAPTYPE, LPDIRECT3DRMFRAME ref, + D3DVALUE ox, D3DVALUE oy, D3DVALUE oz, + D3DVALUE dx, D3DVALUE dy, D3DVALUE dz, + D3DVALUE ux, D3DVALUE uy, D3DVALUE uz, + D3DVALUE ou, D3DVALUE ov, + D3DVALUE su, D3DVALUE sv + ) PURE; + STDMETHOD(Apply)(THIS_ LPDIRECT3DRMOBJECT) PURE; + STDMETHOD(ApplyRelative)(THIS_ LPDIRECT3DRMFRAME frame, LPDIRECT3DRMOBJECT) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMMaterial + +DECLARE_INTERFACE_(IDirect3DRMMaterial, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMMaterial methods + */ + STDMETHOD(SetPower)(THIS_ D3DVALUE power) PURE; + STDMETHOD(SetSpecular)(THIS_ D3DVALUE r, D3DVALUE g, D3DVALUE b) PURE; + STDMETHOD(SetEmissive)(THIS_ D3DVALUE r, D3DVALUE g, D3DVALUE b) PURE; + + STDMETHOD_(D3DVALUE, GetPower)(THIS) PURE; + STDMETHOD(GetSpecular)(THIS_ D3DVALUE* r, D3DVALUE* g, D3DVALUE* b) PURE; + STDMETHOD(GetEmissive)(THIS_ D3DVALUE* r, D3DVALUE* g, D3DVALUE* b) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMAnimation + +DECLARE_INTERFACE_(IDirect3DRMAnimation, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMAnimation methods + */ + STDMETHOD(SetOptions)(THIS_ D3DRMANIMATIONOPTIONS flags) PURE; + STDMETHOD(AddRotateKey)(THIS_ D3DVALUE time, D3DRMQUATERNION *q) PURE; + STDMETHOD(AddPositionKey)(THIS_ D3DVALUE time, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(AddScaleKey)(THIS_ D3DVALUE time, D3DVALUE x, D3DVALUE y, D3DVALUE z) PURE; + STDMETHOD(DeleteKey)(THIS_ D3DVALUE time) PURE; + STDMETHOD(SetFrame)(THIS_ LPDIRECT3DRMFRAME frame) PURE; + STDMETHOD(SetTime)(THIS_ D3DVALUE time) PURE; + + STDMETHOD_(D3DRMANIMATIONOPTIONS, GetOptions)(THIS) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMAnimationSet + +DECLARE_INTERFACE_(IDirect3DRMAnimationSet, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMAnimationSet methods + */ + STDMETHOD(AddAnimation)(THIS_ LPDIRECT3DRMANIMATION aid) PURE; + STDMETHOD(Load)(THIS_ LPVOID filename, LPVOID name, D3DRMLOADOPTIONS loadflags, D3DRMLOADTEXTURECALLBACK, LPVOID lpArg, LPDIRECT3DRMFRAME parent)PURE; + STDMETHOD(DeleteAnimation)(THIS_ LPDIRECT3DRMANIMATION aid) PURE; + STDMETHOD(SetTime)(THIS_ D3DVALUE time) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMUserVisual + +DECLARE_INTERFACE_(IDirect3DRMUserVisual, IDirect3DRMVisual) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMUserVisual methods + */ + STDMETHOD(Init)(THIS_ D3DRMUSERVISUALCALLBACK fn, void *arg) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMArray + +DECLARE_INTERFACE_(IDirect3DRMArray, IUnknown) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + /* No GetElement method as it would get overloaded + * in derived classes, and overloading is + * a no-no in COM + */ +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMObjectArray + +DECLARE_INTERFACE_(IDirect3DRMObjectArray, IDirect3DRMArray) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMOBJECT *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMDeviceArray + +DECLARE_INTERFACE_(IDirect3DRMDeviceArray, IDirect3DRMArray) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMDEVICE *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMFrameArray + +DECLARE_INTERFACE_(IDirect3DRMFrameArray, IDirect3DRMArray) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMFRAME *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMViewportArray + +DECLARE_INTERFACE_(IDirect3DRMViewportArray, IDirect3DRMArray) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMVIEWPORT *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMVisualArray + +DECLARE_INTERFACE_(IDirect3DRMVisualArray, IDirect3DRMArray) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMVISUAL *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMPickedArray + +DECLARE_INTERFACE_(IDirect3DRMPickedArray, IDirect3DRMArray) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + STDMETHOD(GetPick)(THIS_ DWORD index, LPDIRECT3DRMVISUAL *, LPDIRECT3DRMFRAMEARRAY *, LPD3DRMPICKDESC) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMLightArray + +DECLARE_INTERFACE_(IDirect3DRMLightArray, IDirect3DRMArray) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMLIGHT *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMFaceArray + +DECLARE_INTERFACE_(IDirect3DRMFaceArray, IDirect3DRMArray) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + STDMETHOD(GetElement)(THIS_ DWORD index, LPDIRECT3DRMFACE *) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMPicked2Array + +DECLARE_INTERFACE_(IDirect3DRMPicked2Array, IDirect3DRMArray) +{ + IUNKNOWN_METHODS(PURE); + + STDMETHOD_(DWORD, GetSize)(THIS) PURE; + STDMETHOD(GetPick)(THIS_ DWORD index, LPDIRECT3DRMVISUAL *, LPDIRECT3DRMFRAMEARRAY *, LPD3DRMPICKDESC2) PURE; +}; + +#undef INTERFACE +#define INTERFACE IDirect3DRMInterpolator + +DECLARE_INTERFACE_(IDirect3DRMInterpolator, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMInterpolator methods + */ + STDMETHOD(AttachObject)(THIS_ LPDIRECT3DRMOBJECT) PURE; + STDMETHOD(GetAttachedObjects)(THIS_ LPDIRECT3DRMOBJECTARRAY *) PURE; + STDMETHOD(DetachObject)(THIS_ LPDIRECT3DRMOBJECT) PURE; + STDMETHOD(SetIndex)(THIS_ D3DVALUE) PURE; + STDMETHOD_(D3DVALUE, GetIndex)(THIS) PURE; + STDMETHOD(Interpolate)(THIS_ D3DVALUE, LPDIRECT3DRMOBJECT, D3DRMINTERPOLATIONOPTIONS) PURE; +}; + +#ifdef __cplusplus +}; +#endif +#endif /* _D3DRMOBJ_H_ */ diff --git a/3rdparty/dx5/inc/d3drmwin.h b/3rdparty/dx5/inc/d3drmwin.h new file mode 100644 index 00000000..bf26d7a0 --- /dev/null +++ b/3rdparty/dx5/inc/d3drmwin.h @@ -0,0 +1,48 @@ +/*==========================================================================; + * + * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. + * + * File: d3drm.h + * Content: Direct3DRM include file + * + ***************************************************************************/ + +#ifndef __D3DRMWIN_H__ +#define __D3DRMWIN_H__ + +#ifndef WIN32 +#define WIN32 +#endif + +#include "d3drm.h" +#include "ddraw.h" +#include "d3d.h" + +/* + * GUIDS used by Direct3DRM Windows interface + */ +DEFINE_GUID(IID_IDirect3DRMWinDevice, 0xc5016cc0, 0xd273, 0x11ce, 0xac, 0x48, 0x0, 0x0, 0xc0, 0x38, 0x25, 0xa1); + +WIN_TYPES(IDirect3DRMWinDevice, DIRECT3DRMWINDEVICE); + +#undef INTERFACE +#define INTERFACE IDirect3DRMWinDevice + +DECLARE_INTERFACE_(IDirect3DRMWinDevice, IDirect3DRMObject) +{ + IUNKNOWN_METHODS(PURE); + IDIRECT3DRMOBJECT_METHODS(PURE); + + /* + * IDirect3DRMWinDevice methods + */ + + /* Repaint the window with the last frame which was rendered. */ + STDMETHOD(HandlePaint)(THIS_ HDC hdc) PURE; + + /* Respond to a WM_ACTIVATE message. */ + STDMETHOD(HandleActivate)(THIS_ WORD wparam) PURE; +}; + + +#endif diff --git a/3rdparty/dx5/inc/d3dtypes.h b/3rdparty/dx5/inc/d3dtypes.h new file mode 100644 index 00000000..c1046639 --- /dev/null +++ b/3rdparty/dx5/inc/d3dtypes.h @@ -0,0 +1,1201 @@ +/*==========================================================================; + * + * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. + * + * File: d3dtypes.h + * Content: Direct3D types include file + * + ***************************************************************************/ + +#ifndef _D3DTYPES_H_ +#define _D3DTYPES_H_ + +#if (! defined WIN32) && (! defined WIN95) +#include "subwtype.h" +#else +#include +#endif + +#include +#include + +#pragma pack(4) + +/* D3DVALUE is the fundamental Direct3D fractional data type */ + +#define D3DVALP(val, prec) ((float)(val)) +#define D3DVAL(val) ((float)(val)) +typedef float D3DVALUE, *LPD3DVALUE; +#define D3DDivide(a, b) (float)((double) (a) / (double) (b)) +#define D3DMultiply(a, b) ((a) * (b)) + +typedef LONG D3DFIXED; + +#ifndef RGB_MAKE +/* + * Format of CI colors is + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | alpha | color index | fraction | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +#define CI_GETALPHA(ci) ((ci) >> 24) +#define CI_GETINDEX(ci) (((ci) >> 8) & 0xffff) +#define CI_GETFRACTION(ci) ((ci) & 0xff) +#define CI_ROUNDINDEX(ci) CI_GETINDEX((ci) + 0x80) +#define CI_MASKALPHA(ci) ((ci) & 0xffffff) +#define CI_MAKE(a, i, f) (((a) << 24) | ((i) << 8) | (f)) + +/* + * Format of RGBA colors is + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | alpha | red | green | blue | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +#define RGBA_GETALPHA(rgb) ((rgb) >> 24) +#define RGBA_GETRED(rgb) (((rgb) >> 16) & 0xff) +#define RGBA_GETGREEN(rgb) (((rgb) >> 8) & 0xff) +#define RGBA_GETBLUE(rgb) ((rgb) & 0xff) +#define RGBA_MAKE(r, g, b, a) ((D3DCOLOR) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))) + +/* D3DRGB and D3DRGBA may be used as initialisers for D3DCOLORs + * The float values must be in the range 0..1 + */ +#define D3DRGB(r, g, b) \ + (0xff000000L | ( ((long)((r) * 255)) << 16) | (((long)((g) * 255)) << 8) | (long)((b) * 255)) +#define D3DRGBA(r, g, b, a) \ + ( (((long)((a) * 255)) << 24) | (((long)((r) * 255)) << 16) \ + | (((long)((g) * 255)) << 8) | (long)((b) * 255) \ + ) + +/* + * Format of RGB colors is + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | ignored | red | green | blue | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +#define RGB_GETRED(rgb) (((rgb) >> 16) & 0xff) +#define RGB_GETGREEN(rgb) (((rgb) >> 8) & 0xff) +#define RGB_GETBLUE(rgb) ((rgb) & 0xff) +#define RGBA_SETALPHA(rgba, x) (((x) << 24) | ((rgba) & 0x00ffffff)) +#define RGB_MAKE(r, g, b) ((D3DCOLOR) (((r) << 16) | ((g) << 8) | (b))) +#define RGBA_TORGB(rgba) ((D3DCOLOR) ((rgba) & 0xffffff)) +#define RGB_TORGBA(rgb) ((D3DCOLOR) ((rgb) | 0xff000000)) + +#endif + +/* + * Flags for Enumerate functions + */ + +/* + * Stop the enumeration + */ +#define D3DENUMRET_CANCEL DDENUMRET_CANCEL + +/* + * Continue the enumeration + */ +#define D3DENUMRET_OK DDENUMRET_OK + +typedef HRESULT (WINAPI* LPD3DVALIDATECALLBACK)(LPVOID lpUserArg, DWORD dwOffset); +typedef HRESULT (WINAPI* LPD3DENUMTEXTUREFORMATSCALLBACK)(LPDDSURFACEDESC lpDdsd, LPVOID lpContext); + +typedef DWORD D3DCOLOR, *LPD3DCOLOR; + +typedef DWORD D3DMATERIALHANDLE, *LPD3DMATERIALHANDLE; +typedef DWORD D3DTEXTUREHANDLE, *LPD3DTEXTUREHANDLE; +typedef DWORD D3DMATRIXHANDLE, *LPD3DMATRIXHANDLE; + +typedef struct _D3DCOLORVALUE { + union { + D3DVALUE r; + D3DVALUE dvR; + }; + union { + D3DVALUE g; + D3DVALUE dvG; + }; + union { + D3DVALUE b; + D3DVALUE dvB; + }; + union { + D3DVALUE a; + D3DVALUE dvA; + }; +} D3DCOLORVALUE, *LPD3DCOLORVALUE; + +typedef struct _D3DRECT { + union { + LONG x1; + LONG lX1; + }; + union { + LONG y1; + LONG lY1; + }; + union { + LONG x2; + LONG lX2; + }; + union { + LONG y2; + LONG lY2; + }; +} D3DRECT, *LPD3DRECT; + +typedef struct _D3DVECTOR { + union { + D3DVALUE x; + D3DVALUE dvX; + }; + union { + D3DVALUE y; + D3DVALUE dvY; + }; + union { + D3DVALUE z; + D3DVALUE dvZ; + }; +#if (defined __cplusplus) && (defined D3D_OVERLOADS) + +public: + + // ===================================== + // Constructors + // ===================================== + + _D3DVECTOR() { } + _D3DVECTOR(D3DVALUE f); + _D3DVECTOR(D3DVALUE _x, D3DVALUE _y, D3DVALUE _z); + _D3DVECTOR(const D3DVALUE f[3]); + + // ===================================== + // Access grants + // ===================================== + + const D3DVALUE&operator[](int i) const; + D3DVALUE&operator[](int i); + + // ===================================== + // Assignment operators + // ===================================== + + _D3DVECTOR& operator += (const _D3DVECTOR& v); + _D3DVECTOR& operator -= (const _D3DVECTOR& v); + _D3DVECTOR& operator *= (const _D3DVECTOR& v); + _D3DVECTOR& operator /= (const _D3DVECTOR& v); + _D3DVECTOR& operator *= (D3DVALUE s); + _D3DVECTOR& operator /= (D3DVALUE s); + + // ===================================== + // Unary operators + // ===================================== + + friend _D3DVECTOR operator + (const _D3DVECTOR& v); + friend _D3DVECTOR operator - (const _D3DVECTOR& v); + + + // ===================================== + // Binary operators + // ===================================== + + // Addition and subtraction + friend _D3DVECTOR operator + (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + friend _D3DVECTOR operator - (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + // Scalar multiplication and division + friend _D3DVECTOR operator * (const _D3DVECTOR& v, D3DVALUE s); + friend _D3DVECTOR operator * (D3DVALUE s, const _D3DVECTOR& v); + friend _D3DVECTOR operator / (const _D3DVECTOR& v, D3DVALUE s); + // Memberwise multiplication and division + friend _D3DVECTOR operator * (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + friend _D3DVECTOR operator / (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + + // Vector dominance + friend int operator < (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + friend int operator <= (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + + // Bitwise equality + friend int operator == (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + + // Length-related functions + friend D3DVALUE SquareMagnitude (const _D3DVECTOR& v); + friend D3DVALUE Magnitude (const _D3DVECTOR& v); + + // Returns vector with same direction and unit length + friend _D3DVECTOR Normalize (const _D3DVECTOR& v); + + // Return min/max component of the input vector + friend D3DVALUE Min (const _D3DVECTOR& v); + friend D3DVALUE Max (const _D3DVECTOR& v); + + // Return memberwise min/max of input vectors + friend _D3DVECTOR Minimize (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + friend _D3DVECTOR Maximize (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + + // Dot and cross product + friend D3DVALUE DotProduct (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + friend _D3DVECTOR CrossProduct (const _D3DVECTOR& v1, const _D3DVECTOR& v2); + +#endif + +} D3DVECTOR, *LPD3DVECTOR; + +#if (defined __cplusplus) && (defined D3D_OVERLOADS) +#include "d3dvec.inl" +#endif + +/* + * Vertex data types supported in an ExecuteBuffer. + */ + +/* + * Homogeneous vertices + */ + +typedef struct _D3DHVERTEX { + DWORD dwFlags; /* Homogeneous clipping flags */ + union { + D3DVALUE hx; + D3DVALUE dvHX; + }; + union { + D3DVALUE hy; + D3DVALUE dvHY; + }; + union { + D3DVALUE hz; + D3DVALUE dvHZ; + }; +} D3DHVERTEX, *LPD3DHVERTEX; + +/* + * Transformed/lit vertices + */ +typedef struct _D3DTLVERTEX { + union { + D3DVALUE sx; /* Screen coordinates */ + D3DVALUE dvSX; + }; + union { + D3DVALUE sy; + D3DVALUE dvSY; + }; + union { + D3DVALUE sz; + D3DVALUE dvSZ; + }; + union { + D3DVALUE rhw; /* Reciprocal of homogeneous w */ + D3DVALUE dvRHW; + }; + union { + D3DCOLOR color; /* Vertex color */ + D3DCOLOR dcColor; + }; + union { + D3DCOLOR specular; /* Specular component of vertex */ + D3DCOLOR dcSpecular; + }; + union { + D3DVALUE tu; /* Texture coordinates */ + D3DVALUE dvTU; + }; + union { + D3DVALUE tv; + D3DVALUE dvTV; + }; +#if (defined __cplusplus) && (defined D3D_OVERLOADS) + _D3DTLVERTEX() { } + _D3DTLVERTEX(const D3DVECTOR& v, float _rhw, + D3DCOLOR _color, D3DCOLOR _specular, + float _tu, float _tv) + { sx = v.x; sy = v.y; sz = v.z; rhw = _rhw; + color = _color; specular = _specular; + tu = _tu; tv = _tv; + } +#endif +} D3DTLVERTEX, *LPD3DTLVERTEX; + +/* + * Untransformed/lit vertices + */ +typedef struct _D3DLVERTEX { + union { + D3DVALUE x; /* Homogeneous coordinates */ + D3DVALUE dvX; + }; + union { + D3DVALUE y; + D3DVALUE dvY; + }; + union { + D3DVALUE z; + D3DVALUE dvZ; + }; + DWORD dwReserved; + union { + D3DCOLOR color; /* Vertex color */ + D3DCOLOR dcColor; + }; + union { + D3DCOLOR specular; /* Specular component of vertex */ + D3DCOLOR dcSpecular; + }; + union { + D3DVALUE tu; /* Texture coordinates */ + D3DVALUE dvTU; + }; + union { + D3DVALUE tv; + D3DVALUE dvTV; + }; +#if (defined __cplusplus) && (defined D3D_OVERLOADS) + _D3DLVERTEX() { } + _D3DLVERTEX(const D3DVECTOR& v, + D3DCOLOR _color, D3DCOLOR _specular, + float _tu, float _tv) + { x = v.x; y = v.y; z = v.z; dwReserved = 0; + color = _color; specular = _specular; + tu = _tu; tv = _tv; + } +#endif +} D3DLVERTEX, *LPD3DLVERTEX; + +/* + * Untransformed/unlit vertices + */ + +typedef struct _D3DVERTEX { + union { + D3DVALUE x; /* Homogeneous coordinates */ + D3DVALUE dvX; + }; + union { + D3DVALUE y; + D3DVALUE dvY; + }; + union { + D3DVALUE z; + D3DVALUE dvZ; + }; + union { + D3DVALUE nx; /* Normal */ + D3DVALUE dvNX; + }; + union { + D3DVALUE ny; + D3DVALUE dvNY; + }; + union { + D3DVALUE nz; + D3DVALUE dvNZ; + }; + union { + D3DVALUE tu; /* Texture coordinates */ + D3DVALUE dvTU; + }; + union { + D3DVALUE tv; + D3DVALUE dvTV; + }; +#if (defined __cplusplus) && (defined D3D_OVERLOADS) + _D3DVERTEX() { } + _D3DVERTEX(const D3DVECTOR& v, const D3DVECTOR& n, float _tu, float _tv) + { x = v.x; y = v.y; z = v.z; + nx = n.x; ny = n.y; nz = n.z; + tu = _tu; tv = _tv; + } +#endif +} D3DVERTEX, *LPD3DVERTEX; + +/* + * Matrix, viewport, and tranformation structures and definitions. + */ + +typedef struct _D3DMATRIX { +#if (defined __cplusplus) && (defined D3D_OVERLOADS) + union { + struct { +#endif + + D3DVALUE _11, _12, _13, _14; + D3DVALUE _21, _22, _23, _24; + D3DVALUE _31, _32, _33, _34; + D3DVALUE _41, _42, _43, _44; + +#if (defined __cplusplus) && (defined D3D_OVERLOADS) + }; + D3DVALUE m[4][4]; + }; + _D3DMATRIX() { } + _D3DMATRIX( D3DVALUE _m00, D3DVALUE _m01, D3DVALUE _m02, D3DVALUE _m03, + D3DVALUE _m10, D3DVALUE _m11, D3DVALUE _m12, D3DVALUE _m13, + D3DVALUE _m20, D3DVALUE _m21, D3DVALUE _m22, D3DVALUE _m23, + D3DVALUE _m30, D3DVALUE _m31, D3DVALUE _m32, D3DVALUE _m33 + ) + { + m[0][0] = _m00; m[0][1] = _m01; m[0][2] = _m02; m[0][3] = _m03; + m[1][0] = _m10; m[1][1] = _m11; m[1][2] = _m12; m[1][3] = _m13; + m[2][0] = _m20; m[2][1] = _m21; m[2][2] = _m22; m[2][3] = _m23; + m[3][0] = _m30; m[3][1] = _m31; m[3][2] = _m32; m[3][3] = _m33; + } + + D3DVALUE& operator()(int iRow, int iColumn) { return m[iRow][iColumn]; } + const D3DVALUE& operator()(int iRow, int iColumn) const { return m[iRow][iColumn]; } +#endif +} D3DMATRIX, *LPD3DMATRIX; + +typedef struct _D3DVIEWPORT { + DWORD dwSize; + DWORD dwX; + DWORD dwY; /* Top left */ + DWORD dwWidth; + DWORD dwHeight; /* Dimensions */ + D3DVALUE dvScaleX; /* Scale homogeneous to screen */ + D3DVALUE dvScaleY; /* Scale homogeneous to screen */ + D3DVALUE dvMaxX; /* Min/max homogeneous x coord */ + D3DVALUE dvMaxY; /* Min/max homogeneous y coord */ + D3DVALUE dvMinZ; + D3DVALUE dvMaxZ; /* Min/max homogeneous z coord */ +} D3DVIEWPORT, *LPD3DVIEWPORT; + +typedef struct _D3DVIEWPORT2 { + DWORD dwSize; + DWORD dwX; + DWORD dwY; /* Viewport Top left */ + DWORD dwWidth; + DWORD dwHeight; /* Viewport Dimensions */ + D3DVALUE dvClipX; /* Top left of clip volume */ + D3DVALUE dvClipY; + D3DVALUE dvClipWidth; /* Clip Volume Dimensions */ + D3DVALUE dvClipHeight; + D3DVALUE dvMinZ; /* Min/max of clip Volume */ + D3DVALUE dvMaxZ; +} D3DVIEWPORT2, *LPD3DVIEWPORT2; + +/* + * Values for clip fields. + */ +#define D3DCLIP_LEFT 0x00000001L +#define D3DCLIP_RIGHT 0x00000002L +#define D3DCLIP_TOP 0x00000004L +#define D3DCLIP_BOTTOM 0x00000008L +#define D3DCLIP_FRONT 0x00000010L +#define D3DCLIP_BACK 0x00000020L +#define D3DCLIP_GEN0 0x00000040L +#define D3DCLIP_GEN1 0x00000080L +#define D3DCLIP_GEN2 0x00000100L +#define D3DCLIP_GEN3 0x00000200L +#define D3DCLIP_GEN4 0x00000400L +#define D3DCLIP_GEN5 0x00000800L + +/* + * Values for d3d status. + */ +#define D3DSTATUS_CLIPUNIONLEFT D3DCLIP_LEFT +#define D3DSTATUS_CLIPUNIONRIGHT D3DCLIP_RIGHT +#define D3DSTATUS_CLIPUNIONTOP D3DCLIP_TOP +#define D3DSTATUS_CLIPUNIONBOTTOM D3DCLIP_BOTTOM +#define D3DSTATUS_CLIPUNIONFRONT D3DCLIP_FRONT +#define D3DSTATUS_CLIPUNIONBACK D3DCLIP_BACK +#define D3DSTATUS_CLIPUNIONGEN0 D3DCLIP_GEN0 +#define D3DSTATUS_CLIPUNIONGEN1 D3DCLIP_GEN1 +#define D3DSTATUS_CLIPUNIONGEN2 D3DCLIP_GEN2 +#define D3DSTATUS_CLIPUNIONGEN3 D3DCLIP_GEN3 +#define D3DSTATUS_CLIPUNIONGEN4 D3DCLIP_GEN4 +#define D3DSTATUS_CLIPUNIONGEN5 D3DCLIP_GEN5 + +#define D3DSTATUS_CLIPINTERSECTIONLEFT 0x00001000L +#define D3DSTATUS_CLIPINTERSECTIONRIGHT 0x00002000L +#define D3DSTATUS_CLIPINTERSECTIONTOP 0x00004000L +#define D3DSTATUS_CLIPINTERSECTIONBOTTOM 0x00008000L +#define D3DSTATUS_CLIPINTERSECTIONFRONT 0x00010000L +#define D3DSTATUS_CLIPINTERSECTIONBACK 0x00020000L +#define D3DSTATUS_CLIPINTERSECTIONGEN0 0x00040000L +#define D3DSTATUS_CLIPINTERSECTIONGEN1 0x00080000L +#define D3DSTATUS_CLIPINTERSECTIONGEN2 0x00100000L +#define D3DSTATUS_CLIPINTERSECTIONGEN3 0x00200000L +#define D3DSTATUS_CLIPINTERSECTIONGEN4 0x00400000L +#define D3DSTATUS_CLIPINTERSECTIONGEN5 0x00800000L +#define D3DSTATUS_ZNOTVISIBLE 0x01000000L +/* Do not use 0x80000000 for any status flags in future as it is reserved */ + +#define D3DSTATUS_CLIPUNIONALL ( \ + D3DSTATUS_CLIPUNIONLEFT | \ + D3DSTATUS_CLIPUNIONRIGHT | \ + D3DSTATUS_CLIPUNIONTOP | \ + D3DSTATUS_CLIPUNIONBOTTOM | \ + D3DSTATUS_CLIPUNIONFRONT | \ + D3DSTATUS_CLIPUNIONBACK | \ + D3DSTATUS_CLIPUNIONGEN0 | \ + D3DSTATUS_CLIPUNIONGEN1 | \ + D3DSTATUS_CLIPUNIONGEN2 | \ + D3DSTATUS_CLIPUNIONGEN3 | \ + D3DSTATUS_CLIPUNIONGEN4 | \ + D3DSTATUS_CLIPUNIONGEN5 \ + ) + +#define D3DSTATUS_CLIPINTERSECTIONALL ( \ + D3DSTATUS_CLIPINTERSECTIONLEFT | \ + D3DSTATUS_CLIPINTERSECTIONRIGHT | \ + D3DSTATUS_CLIPINTERSECTIONTOP | \ + D3DSTATUS_CLIPINTERSECTIONBOTTOM | \ + D3DSTATUS_CLIPINTERSECTIONFRONT | \ + D3DSTATUS_CLIPINTERSECTIONBACK | \ + D3DSTATUS_CLIPINTERSECTIONGEN0 | \ + D3DSTATUS_CLIPINTERSECTIONGEN1 | \ + D3DSTATUS_CLIPINTERSECTIONGEN2 | \ + D3DSTATUS_CLIPINTERSECTIONGEN3 | \ + D3DSTATUS_CLIPINTERSECTIONGEN4 | \ + D3DSTATUS_CLIPINTERSECTIONGEN5 \ + ) + +#define D3DSTATUS_DEFAULT ( \ + D3DSTATUS_CLIPINTERSECTIONALL | \ + D3DSTATUS_ZNOTVISIBLE) + + +/* + * Options for direct transform calls + */ +#define D3DTRANSFORM_CLIPPED 0x00000001l +#define D3DTRANSFORM_UNCLIPPED 0x00000002l + +typedef struct _D3DTRANSFORMDATA { + DWORD dwSize; + LPVOID lpIn; /* Input vertices */ + DWORD dwInSize; /* Stride of input vertices */ + LPVOID lpOut; /* Output vertices */ + DWORD dwOutSize; /* Stride of output vertices */ + LPD3DHVERTEX lpHOut; /* Output homogeneous vertices */ + DWORD dwClip; /* Clipping hint */ + DWORD dwClipIntersection; + DWORD dwClipUnion; /* Union of all clip flags */ + D3DRECT drExtent; /* Extent of transformed vertices */ +} D3DTRANSFORMDATA, *LPD3DTRANSFORMDATA; + +/* + * Structure defining position and direction properties for lighting. + */ +typedef struct _D3DLIGHTINGELEMENT { + D3DVECTOR dvPosition; /* Lightable point in model space */ + D3DVECTOR dvNormal; /* Normalised unit vector */ +} D3DLIGHTINGELEMENT, *LPD3DLIGHTINGELEMENT; + +/* + * Structure defining material properties for lighting. + */ +typedef struct _D3DMATERIAL { + DWORD dwSize; + union { + D3DCOLORVALUE diffuse; /* Diffuse color RGBA */ + D3DCOLORVALUE dcvDiffuse; + }; + union { + D3DCOLORVALUE ambient; /* Ambient color RGB */ + D3DCOLORVALUE dcvAmbient; + }; + union { + D3DCOLORVALUE specular; /* Specular 'shininess' */ + D3DCOLORVALUE dcvSpecular; + }; + union { + D3DCOLORVALUE emissive; /* Emissive color RGB */ + D3DCOLORVALUE dcvEmissive; + }; + union { + D3DVALUE power; /* Sharpness if specular highlight */ + D3DVALUE dvPower; + }; + D3DTEXTUREHANDLE hTexture; /* Handle to texture map */ + DWORD dwRampSize; +} D3DMATERIAL, *LPD3DMATERIAL; + +typedef enum _D3DLIGHTTYPE { + D3DLIGHT_POINT = 1, + D3DLIGHT_SPOT = 2, + D3DLIGHT_DIRECTIONAL = 3, + D3DLIGHT_PARALLELPOINT = 4, + D3DLIGHT_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DLIGHTTYPE; + +/* + * Structure defining a light source and its properties. + */ +typedef struct _D3DLIGHT { + DWORD dwSize; + D3DLIGHTTYPE dltType; /* Type of light source */ + D3DCOLORVALUE dcvColor; /* Color of light */ + D3DVECTOR dvPosition; /* Position in world space */ + D3DVECTOR dvDirection; /* Direction in world space */ + D3DVALUE dvRange; /* Cutoff range */ + D3DVALUE dvFalloff; /* Falloff */ + D3DVALUE dvAttenuation0; /* Constant attenuation */ + D3DVALUE dvAttenuation1; /* Linear attenuation */ + D3DVALUE dvAttenuation2; /* Quadratic attenuation */ + D3DVALUE dvTheta; /* Inner angle of spotlight cone */ + D3DVALUE dvPhi; /* Outer angle of spotlight cone */ +} D3DLIGHT, *LPD3DLIGHT; + +/* + * Structure defining a light source and its properties. + */ + +/* flags bits */ +#define D3DLIGHT_ACTIVE 0x00000001 +#define D3DLIGHT_NO_SPECULAR 0x00000002 + +/* maximum valid light range */ +#define D3DLIGHT_RANGE_MAX ((float)sqrt(FLT_MAX)) + +typedef struct _D3DLIGHT2 { + DWORD dwSize; + D3DLIGHTTYPE dltType; /* Type of light source */ + D3DCOLORVALUE dcvColor; /* Color of light */ + D3DVECTOR dvPosition; /* Position in world space */ + D3DVECTOR dvDirection; /* Direction in world space */ + D3DVALUE dvRange; /* Cutoff range */ + D3DVALUE dvFalloff; /* Falloff */ + D3DVALUE dvAttenuation0; /* Constant attenuation */ + D3DVALUE dvAttenuation1; /* Linear attenuation */ + D3DVALUE dvAttenuation2; /* Quadratic attenuation */ + D3DVALUE dvTheta; /* Inner angle of spotlight cone */ + D3DVALUE dvPhi; /* Outer angle of spotlight cone */ + DWORD dwFlags; +} D3DLIGHT2, *LPD3DLIGHT2; + +typedef struct _D3DLIGHTDATA { + DWORD dwSize; + LPD3DLIGHTINGELEMENT lpIn; /* Input positions and normals */ + DWORD dwInSize; /* Stride of input elements */ + LPD3DTLVERTEX lpOut; /* Output colors */ + DWORD dwOutSize; /* Stride of output colors */ +} D3DLIGHTDATA, *LPD3DLIGHTDATA; + +/* + * Before DX5, these values were in an enum called + * D3DCOLORMODEL. This was not correct, since they are + * bit flags. A driver can surface either or both flags + * in the dcmColorModel member of D3DDEVICEDESC. + */ +#define D3DCOLOR_MONO 1 +#define D3DCOLOR_RGB 2 + +typedef DWORD D3DCOLORMODEL; + +/* + * Options for clearing + */ +#define D3DCLEAR_TARGET 0x00000001l /* Clear target surface */ +#define D3DCLEAR_ZBUFFER 0x00000002l /* Clear target z buffer */ + +/* + * Execute buffers are allocated via Direct3D. These buffers may then + * be filled by the application with instructions to execute along with + * vertex data. + */ + +/* + * Supported op codes for execute instructions. + */ +typedef enum _D3DOPCODE { + D3DOP_POINT = 1, + D3DOP_LINE = 2, + D3DOP_TRIANGLE = 3, + D3DOP_MATRIXLOAD = 4, + D3DOP_MATRIXMULTIPLY = 5, + D3DOP_STATETRANSFORM = 6, + D3DOP_STATELIGHT = 7, + D3DOP_STATERENDER = 8, + D3DOP_PROCESSVERTICES = 9, + D3DOP_TEXTURELOAD = 10, + D3DOP_EXIT = 11, + D3DOP_BRANCHFORWARD = 12, + D3DOP_SPAN = 13, + D3DOP_SETSTATUS = 14, + D3DOP_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DOPCODE; + +typedef struct _D3DINSTRUCTION { + BYTE bOpcode; /* Instruction opcode */ + BYTE bSize; /* Size of each instruction data unit */ + WORD wCount; /* Count of instruction data units to follow */ +} D3DINSTRUCTION, *LPD3DINSTRUCTION; + +/* + * Structure for texture loads + */ +typedef struct _D3DTEXTURELOAD { + D3DTEXTUREHANDLE hDestTexture; + D3DTEXTUREHANDLE hSrcTexture; +} D3DTEXTURELOAD, *LPD3DTEXTURELOAD; + +/* + * Structure for picking + */ +typedef struct _D3DPICKRECORD { + BYTE bOpcode; + BYTE bPad; + DWORD dwOffset; + D3DVALUE dvZ; +} D3DPICKRECORD, *LPD3DPICKRECORD; + +/* + * The following defines the rendering states which can be set in the + * execute buffer. + */ + +typedef enum _D3DSHADEMODE { + D3DSHADE_FLAT = 1, + D3DSHADE_GOURAUD = 2, + D3DSHADE_PHONG = 3, + D3DSHADE_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DSHADEMODE; + +typedef enum _D3DFILLMODE { + D3DFILL_POINT = 1, + D3DFILL_WIREFRAME = 2, + D3DFILL_SOLID = 3, + D3DFILL_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DFILLMODE; + +typedef struct _D3DLINEPATTERN { + WORD wRepeatFactor; + WORD wLinePattern; +} D3DLINEPATTERN; + +typedef enum _D3DTEXTUREFILTER { + D3DFILTER_NEAREST = 1, + D3DFILTER_LINEAR = 2, + D3DFILTER_MIPNEAREST = 3, + D3DFILTER_MIPLINEAR = 4, + D3DFILTER_LINEARMIPNEAREST = 5, + D3DFILTER_LINEARMIPLINEAR = 6, + D3DFILTER_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DTEXTUREFILTER; + +typedef enum _D3DBLEND { + D3DBLEND_ZERO = 1, + D3DBLEND_ONE = 2, + D3DBLEND_SRCCOLOR = 3, + D3DBLEND_INVSRCCOLOR = 4, + D3DBLEND_SRCALPHA = 5, + D3DBLEND_INVSRCALPHA = 6, + D3DBLEND_DESTALPHA = 7, + D3DBLEND_INVDESTALPHA = 8, + D3DBLEND_DESTCOLOR = 9, + D3DBLEND_INVDESTCOLOR = 10, + D3DBLEND_SRCALPHASAT = 11, + D3DBLEND_BOTHSRCALPHA = 12, + D3DBLEND_BOTHINVSRCALPHA = 13, + D3DBLEND_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DBLEND; + +typedef enum _D3DTEXTUREBLEND { + D3DTBLEND_DECAL = 1, + D3DTBLEND_MODULATE = 2, + D3DTBLEND_DECALALPHA = 3, + D3DTBLEND_MODULATEALPHA = 4, + D3DTBLEND_DECALMASK = 5, + D3DTBLEND_MODULATEMASK = 6, + D3DTBLEND_COPY = 7, + D3DTBLEND_ADD = 8, + D3DTBLEND_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DTEXTUREBLEND; + +typedef enum _D3DTEXTUREADDRESS { + D3DTADDRESS_WRAP = 1, + D3DTADDRESS_MIRROR = 2, + D3DTADDRESS_CLAMP = 3, + D3DTADDRESS_BORDER = 4, + D3DTADDRESS_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DTEXTUREADDRESS; + +typedef enum _D3DCULL { + D3DCULL_NONE = 1, + D3DCULL_CW = 2, + D3DCULL_CCW = 3, + D3DCULL_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DCULL; + +typedef enum _D3DCMPFUNC { + D3DCMP_NEVER = 1, + D3DCMP_LESS = 2, + D3DCMP_EQUAL = 3, + D3DCMP_LESSEQUAL = 4, + D3DCMP_GREATER = 5, + D3DCMP_NOTEQUAL = 6, + D3DCMP_GREATEREQUAL = 7, + D3DCMP_ALWAYS = 8, + D3DCMP_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DCMPFUNC; + +typedef enum _D3DFOGMODE { + D3DFOG_NONE = 0, + D3DFOG_EXP = 1, + D3DFOG_EXP2 = 2, + D3DFOG_LINEAR = 3, + D3DFOG_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DFOGMODE; + +typedef enum _D3DANTIALIASMODE { + D3DANTIALIAS_NONE = 0, + D3DANTIALIAS_SORTDEPENDENT = 1, + D3DANTIALIAS_SORTINDEPENDENT = 2, + D3DANTIALIAS_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DANTIALIASMODE; + +// Vertex types supported by Direct3D +typedef enum _D3DVERTEXTYPE { + D3DVT_VERTEX = 1, + D3DVT_LVERTEX = 2, + D3DVT_TLVERTEX = 3, + D3DVT_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DVERTEXTYPE; + +// Primitives supported by draw-primitive API +typedef enum _D3DPRIMITIVETYPE { + D3DPT_POINTLIST = 1, + D3DPT_LINELIST = 2, + D3DPT_LINESTRIP = 3, + D3DPT_TRIANGLELIST = 4, + D3DPT_TRIANGLESTRIP = 5, + D3DPT_TRIANGLEFAN = 6, + D3DPT_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DPRIMITIVETYPE; + +/* + * Amount to add to a state to generate the override for that state. + */ +#define D3DSTATE_OVERRIDE_BIAS 256 + +/* + * A state which sets the override flag for the specified state type. + */ +#define D3DSTATE_OVERRIDE(type) ((DWORD) (type) + D3DSTATE_OVERRIDE_BIAS) + +typedef enum _D3DTRANSFORMSTATETYPE { + D3DTRANSFORMSTATE_WORLD = 1, + D3DTRANSFORMSTATE_VIEW = 2, + D3DTRANSFORMSTATE_PROJECTION = 3, + D3DTRANSFORMSTATE_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DTRANSFORMSTATETYPE; + +typedef enum _D3DLIGHTSTATETYPE { + D3DLIGHTSTATE_MATERIAL = 1, + D3DLIGHTSTATE_AMBIENT = 2, + D3DLIGHTSTATE_COLORMODEL = 3, + D3DLIGHTSTATE_FOGMODE = 4, + D3DLIGHTSTATE_FOGSTART = 5, + D3DLIGHTSTATE_FOGEND = 6, + D3DLIGHTSTATE_FOGDENSITY = 7, + D3DLIGHTSTATE_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DLIGHTSTATETYPE; + +typedef enum _D3DRENDERSTATETYPE { + D3DRENDERSTATE_TEXTUREHANDLE = 1, /* Texture handle */ + D3DRENDERSTATE_ANTIALIAS = 2, /* D3DANTIALIASMODE */ + D3DRENDERSTATE_TEXTUREADDRESS = 3, /* D3DTEXTUREADDRESS */ + D3DRENDERSTATE_TEXTUREPERSPECTIVE = 4, /* TRUE for perspective correction */ + D3DRENDERSTATE_WRAPU = 5, /* TRUE for wrapping in u */ + D3DRENDERSTATE_WRAPV = 6, /* TRUE for wrapping in v */ + D3DRENDERSTATE_ZENABLE = 7, /* TRUE to enable z test */ + D3DRENDERSTATE_FILLMODE = 8, /* D3DFILL_MODE */ + D3DRENDERSTATE_SHADEMODE = 9, /* D3DSHADEMODE */ + D3DRENDERSTATE_LINEPATTERN = 10, /* D3DLINEPATTERN */ + D3DRENDERSTATE_MONOENABLE = 11, /* TRUE to enable mono rasterization */ + D3DRENDERSTATE_ROP2 = 12, /* ROP2 */ + D3DRENDERSTATE_PLANEMASK = 13, /* DWORD physical plane mask */ + D3DRENDERSTATE_ZWRITEENABLE = 14, /* TRUE to enable z writes */ + D3DRENDERSTATE_ALPHATESTENABLE = 15, /* TRUE to enable alpha tests */ + D3DRENDERSTATE_LASTPIXEL = 16, /* TRUE for last-pixel on lines */ + D3DRENDERSTATE_TEXTUREMAG = 17, /* D3DTEXTUREFILTER */ + D3DRENDERSTATE_TEXTUREMIN = 18, /* D3DTEXTUREFILTER */ + D3DRENDERSTATE_SRCBLEND = 19, /* D3DBLEND */ + D3DRENDERSTATE_DESTBLEND = 20, /* D3DBLEND */ + D3DRENDERSTATE_TEXTUREMAPBLEND = 21, /* D3DTEXTUREBLEND */ + D3DRENDERSTATE_CULLMODE = 22, /* D3DCULL */ + D3DRENDERSTATE_ZFUNC = 23, /* D3DCMPFUNC */ + D3DRENDERSTATE_ALPHAREF = 24, /* D3DFIXED */ + D3DRENDERSTATE_ALPHAFUNC = 25, /* D3DCMPFUNC */ + D3DRENDERSTATE_DITHERENABLE = 26, /* TRUE to enable dithering */ + D3DRENDERSTATE_ALPHABLENDENABLE = 27, /* TRUE to enable alpha blending */ + D3DRENDERSTATE_FOGENABLE = 28, /* TRUE to enable fog */ + D3DRENDERSTATE_SPECULARENABLE = 29, /* TRUE to enable specular */ + D3DRENDERSTATE_ZVISIBLE = 30, /* TRUE to enable z checking */ + D3DRENDERSTATE_SUBPIXEL = 31, /* TRUE to enable subpixel correction */ + D3DRENDERSTATE_SUBPIXELX = 32, /* TRUE to enable correction in X only */ + D3DRENDERSTATE_STIPPLEDALPHA = 33, /* TRUE to enable stippled alpha */ + D3DRENDERSTATE_FOGCOLOR = 34, /* D3DCOLOR */ + D3DRENDERSTATE_FOGTABLEMODE = 35, /* D3DFOGMODE */ + D3DRENDERSTATE_FOGTABLESTART = 36, /* Fog table start */ + D3DRENDERSTATE_FOGTABLEEND = 37, /* Fog table end */ + D3DRENDERSTATE_FOGTABLEDENSITY = 38, /* Fog table density */ + D3DRENDERSTATE_STIPPLEENABLE = 39, /* TRUE to enable stippling */ + D3DRENDERSTATE_EDGEANTIALIAS = 40, /* TRUE to enable edge antialiasing */ + D3DRENDERSTATE_COLORKEYENABLE = 41, /* TRUE to enable source colorkeyed textures */ + D3DRENDERSTATE_BORDERCOLOR = 43, /* Border color for texturing w/border */ + D3DRENDERSTATE_TEXTUREADDRESSU = 44, /* Texture addressing mode for U coordinate */ + D3DRENDERSTATE_TEXTUREADDRESSV = 45, /* Texture addressing mode for V coordinate */ + D3DRENDERSTATE_MIPMAPLODBIAS = 46, /* D3DVALUE Mipmap LOD bias */ + D3DRENDERSTATE_ZBIAS = 47, /* LONG Z bias */ + D3DRENDERSTATE_RANGEFOGENABLE = 48, /* Enables range-based fog */ + D3DRENDERSTATE_ANISOTROPY = 49, /* Max. anisotropy. 1 = no anisotropy */ + D3DRENDERSTATE_FLUSHBATCH = 50, /* Explicit flush for DP batching (DX5 Only) */ + D3DRENDERSTATE_STIPPLEPATTERN00 = 64, /* Stipple pattern 01... */ + D3DRENDERSTATE_STIPPLEPATTERN01 = 65, + D3DRENDERSTATE_STIPPLEPATTERN02 = 66, + D3DRENDERSTATE_STIPPLEPATTERN03 = 67, + D3DRENDERSTATE_STIPPLEPATTERN04 = 68, + D3DRENDERSTATE_STIPPLEPATTERN05 = 69, + D3DRENDERSTATE_STIPPLEPATTERN06 = 70, + D3DRENDERSTATE_STIPPLEPATTERN07 = 71, + D3DRENDERSTATE_STIPPLEPATTERN08 = 72, + D3DRENDERSTATE_STIPPLEPATTERN09 = 73, + D3DRENDERSTATE_STIPPLEPATTERN10 = 74, + D3DRENDERSTATE_STIPPLEPATTERN11 = 75, + D3DRENDERSTATE_STIPPLEPATTERN12 = 76, + D3DRENDERSTATE_STIPPLEPATTERN13 = 77, + D3DRENDERSTATE_STIPPLEPATTERN14 = 78, + D3DRENDERSTATE_STIPPLEPATTERN15 = 79, + D3DRENDERSTATE_STIPPLEPATTERN16 = 80, + D3DRENDERSTATE_STIPPLEPATTERN17 = 81, + D3DRENDERSTATE_STIPPLEPATTERN18 = 82, + D3DRENDERSTATE_STIPPLEPATTERN19 = 83, + D3DRENDERSTATE_STIPPLEPATTERN20 = 84, + D3DRENDERSTATE_STIPPLEPATTERN21 = 85, + D3DRENDERSTATE_STIPPLEPATTERN22 = 86, + D3DRENDERSTATE_STIPPLEPATTERN23 = 87, + D3DRENDERSTATE_STIPPLEPATTERN24 = 88, + D3DRENDERSTATE_STIPPLEPATTERN25 = 89, + D3DRENDERSTATE_STIPPLEPATTERN26 = 90, + D3DRENDERSTATE_STIPPLEPATTERN27 = 91, + D3DRENDERSTATE_STIPPLEPATTERN28 = 92, + D3DRENDERSTATE_STIPPLEPATTERN29 = 93, + D3DRENDERSTATE_STIPPLEPATTERN30 = 94, + D3DRENDERSTATE_STIPPLEPATTERN31 = 95, + D3DRENDERSTATE_FORCE_DWORD = 0x7fffffff, /* force 32-bit size enum */ +} D3DRENDERSTATETYPE; + +// For back-compatibility with legacy compilations +#define D3DRENDERSTATE_BLENDENABLE D3DRENDERSTATE_ALPHABLENDENABLE + +#define D3DRENDERSTATE_STIPPLEPATTERN(y) (D3DRENDERSTATE_STIPPLEPATTERN00 + (y)) + +typedef struct _D3DSTATE { + union { + D3DTRANSFORMSTATETYPE dtstTransformStateType; + D3DLIGHTSTATETYPE dlstLightStateType; + D3DRENDERSTATETYPE drstRenderStateType; + }; + union { + DWORD dwArg[1]; + D3DVALUE dvArg[1]; + }; +} D3DSTATE, *LPD3DSTATE; + +/* + * Operation used to load matrices + * hDstMat = hSrcMat + */ +typedef struct _D3DMATRIXLOAD { + D3DMATRIXHANDLE hDestMatrix; /* Destination matrix */ + D3DMATRIXHANDLE hSrcMatrix; /* Source matrix */ +} D3DMATRIXLOAD, *LPD3DMATRIXLOAD; + +/* + * Operation used to multiply matrices + * hDstMat = hSrcMat1 * hSrcMat2 + */ +typedef struct _D3DMATRIXMULTIPLY { + D3DMATRIXHANDLE hDestMatrix; /* Destination matrix */ + D3DMATRIXHANDLE hSrcMatrix1; /* First source matrix */ + D3DMATRIXHANDLE hSrcMatrix2; /* Second source matrix */ +} D3DMATRIXMULTIPLY, *LPD3DMATRIXMULTIPLY; + +/* + * Operation used to transform and light vertices. + */ +typedef struct _D3DPROCESSVERTICES { + DWORD dwFlags; /* Do we transform or light or just copy? */ + WORD wStart; /* Index to first vertex in source */ + WORD wDest; /* Index to first vertex in local buffer */ + DWORD dwCount; /* Number of vertices to be processed */ + DWORD dwReserved; /* Must be zero */ +} D3DPROCESSVERTICES, *LPD3DPROCESSVERTICES; + +#define D3DPROCESSVERTICES_TRANSFORMLIGHT 0x00000000L +#define D3DPROCESSVERTICES_TRANSFORM 0x00000001L +#define D3DPROCESSVERTICES_COPY 0x00000002L +#define D3DPROCESSVERTICES_OPMASK 0x00000007L + +#define D3DPROCESSVERTICES_UPDATEEXTENTS 0x00000008L +#define D3DPROCESSVERTICES_NOCOLOR 0x00000010L + + +/* + * Triangle flags + */ + +/* + * Tri strip and fan flags. + * START loads all three vertices + * EVEN and ODD load just v3 with even or odd culling + * START_FLAT contains a count from 0 to 29 that allows the + * whole strip or fan to be culled in one hit. + * e.g. for a quad len = 1 + */ +#define D3DTRIFLAG_START 0x00000000L +#define D3DTRIFLAG_STARTFLAT(len) (len) /* 0 < len < 30 */ +#define D3DTRIFLAG_ODD 0x0000001eL +#define D3DTRIFLAG_EVEN 0x0000001fL + +/* + * Triangle edge flags + * enable edges for wireframe or antialiasing + */ +#define D3DTRIFLAG_EDGEENABLE1 0x00000100L /* v0-v1 edge */ +#define D3DTRIFLAG_EDGEENABLE2 0x00000200L /* v1-v2 edge */ +#define D3DTRIFLAG_EDGEENABLE3 0x00000400L /* v2-v0 edge */ +#define D3DTRIFLAG_EDGEENABLETRIANGLE \ + (D3DTRIFLAG_EDGEENABLE1 | D3DTRIFLAG_EDGEENABLE2 | D3DTRIFLAG_EDGEENABLE3) + +/* + * Primitive structures and related defines. Vertex offsets are to types + * D3DVERTEX, D3DLVERTEX, or D3DTLVERTEX. + */ + +/* + * Triangle list primitive structure + */ +typedef struct _D3DTRIANGLE { + union { + WORD v1; /* Vertex indices */ + WORD wV1; + }; + union { + WORD v2; + WORD wV2; + }; + union { + WORD v3; + WORD wV3; + }; + WORD wFlags; /* Edge (and other) flags */ +} D3DTRIANGLE, *LPD3DTRIANGLE; + +/* + * Line list structure. + * The instruction count defines the number of line segments. + */ +typedef struct _D3DLINE { + union { + WORD v1; /* Vertex indices */ + WORD wV1; + }; + union { + WORD v2; + WORD wV2; + }; +} D3DLINE, *LPD3DLINE; + +/* + * Span structure + * Spans join a list of points with the same y value. + * If the y value changes, a new span is started. + */ +typedef struct _D3DSPAN { + WORD wCount; /* Number of spans */ + WORD wFirst; /* Index to first vertex */ +} D3DSPAN, *LPD3DSPAN; + +/* + * Point structure + */ +typedef struct _D3DPOINT { + WORD wCount; /* number of points */ + WORD wFirst; /* index to first vertex */ +} D3DPOINT, *LPD3DPOINT; + + +/* + * Forward branch structure. + * Mask is logically anded with the driver status mask + * if the result equals 'value', the branch is taken. + */ +typedef struct _D3DBRANCH { + DWORD dwMask; /* Bitmask against D3D status */ + DWORD dwValue; + BOOL bNegate; /* TRUE to negate comparison */ + DWORD dwOffset; /* How far to branch forward (0 for exit)*/ +} D3DBRANCH, *LPD3DBRANCH; + +/* + * Status used for set status instruction. + * The D3D status is initialised on device creation + * and is modified by all execute calls. + */ +typedef struct _D3DSTATUS { + DWORD dwFlags; /* Do we set extents or status */ + DWORD dwStatus; /* D3D status */ + D3DRECT drExtent; +} D3DSTATUS, *LPD3DSTATUS; + +#define D3DSETSTATUS_STATUS 0x00000001L +#define D3DSETSTATUS_EXTENTS 0x00000002L +#define D3DSETSTATUS_ALL (D3DSETSTATUS_STATUS | D3DSETSTATUS_EXTENTS) + +typedef struct _D3DCLIPSTATUS { + DWORD dwFlags; /* Do we set 2d extents, 3D extents or status */ + DWORD dwStatus; /* Clip status */ + float minx, maxx; /* X extents */ + float miny, maxy; /* Y extents */ + float minz, maxz; /* Z extents */ +} D3DCLIPSTATUS, *LPD3DCLIPSTATUS; + +#define D3DCLIPSTATUS_STATUS 0x00000001L +#define D3DCLIPSTATUS_EXTENTS2 0x00000002L +#define D3DCLIPSTATUS_EXTENTS3 0x00000004L + +/* + * Statistics structure + */ +typedef struct _D3DSTATS { + DWORD dwSize; + DWORD dwTrianglesDrawn; + DWORD dwLinesDrawn; + DWORD dwPointsDrawn; + DWORD dwSpansDrawn; + DWORD dwVerticesProcessed; +} D3DSTATS, *LPD3DSTATS; + +/* + * Execute options. + * When calling using D3DEXECUTE_UNCLIPPED all the primitives + * inside the buffer must be contained within the viewport. + */ +#define D3DEXECUTE_CLIPPED 0x00000001l +#define D3DEXECUTE_UNCLIPPED 0x00000002l + +typedef struct _D3DEXECUTEDATA { + DWORD dwSize; + DWORD dwVertexOffset; + DWORD dwVertexCount; + DWORD dwInstructionOffset; + DWORD dwInstructionLength; + DWORD dwHVertexOffset; + D3DSTATUS dsStatus; /* Status after execute */ +} D3DEXECUTEDATA, *LPD3DEXECUTEDATA; + +/* + * Palette flags. + * This are or'ed with the peFlags in the PALETTEENTRYs passed to DirectDraw. + */ +#define D3DPAL_FREE 0x00 /* Renderer may use this entry freely */ +#define D3DPAL_READONLY 0x40 /* Renderer may not set this entry */ +#define D3DPAL_RESERVED 0x80 /* Renderer may not use this entry */ + +#pragma pack() + +#endif /* _D3DTYPES_H_ */ diff --git a/3rdparty/dx5/inc/d3dvec.inl b/3rdparty/dx5/inc/d3dvec.inl new file mode 100644 index 00000000..6e711f2f --- /dev/null +++ b/3rdparty/dx5/inc/d3dvec.inl @@ -0,0 +1,240 @@ + +/****************************************************************** + * * + * D3DVec.inl * + * * + * Float-valued 3D vector class for Direct3D. * + * * + * Copyright (c) 1996-1997 Microsoft Corp. All rights reserved. * + * * + ******************************************************************/ + +#include + +// ===================================== +// Constructors +// ===================================== + +inline +_D3DVECTOR::_D3DVECTOR(D3DVALUE f) +{ + x = y = z = f; +} + +inline +_D3DVECTOR::_D3DVECTOR(D3DVALUE _x, D3DVALUE _y, D3DVALUE _z) +{ + x = _x; y = _y; z = _z; +} + +inline +_D3DVECTOR::_D3DVECTOR(const D3DVALUE f[3]) +{ + x = f[0]; y = f[1]; z = f[2]; +} + +// ===================================== +// Access grants +// ===================================== + +inline const D3DVALUE& +_D3DVECTOR::operator[](int i) const +{ + return (&x)[i]; +} + +inline D3DVALUE& +_D3DVECTOR::operator[](int i) +{ + return (&x)[i]; +} + + +// ===================================== +// Assignment operators +// ===================================== + +inline _D3DVECTOR& +_D3DVECTOR::operator += (const _D3DVECTOR& v) +{ + x += v.x; y += v.y; z += v.z; + return *this; +} + +inline _D3DVECTOR& +_D3DVECTOR::operator -= (const _D3DVECTOR& v) +{ + x -= v.x; y -= v.y; z -= v.z; + return *this; +} + +inline _D3DVECTOR& +_D3DVECTOR::operator *= (const _D3DVECTOR& v) +{ + x *= v.x; y *= v.y; z *= v.z; + return *this; +} + +inline _D3DVECTOR& +_D3DVECTOR::operator /= (const _D3DVECTOR& v) +{ + x /= v.x; y /= v.y; z /= v.z; + return *this; +} + +inline _D3DVECTOR& +_D3DVECTOR::operator *= (D3DVALUE s) +{ + x *= s; y *= s; z *= s; + return *this; +} + +inline _D3DVECTOR& +_D3DVECTOR::operator /= (D3DVALUE s) +{ + x /= s; y /= s; z /= s; + return *this; +} + +inline _D3DVECTOR +operator + (const _D3DVECTOR& v) +{ + return v; +} + +inline _D3DVECTOR +operator - (const _D3DVECTOR& v) +{ + return _D3DVECTOR(-v.x, -v.y, -v.z); +} + +inline _D3DVECTOR +operator + (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return _D3DVECTOR(v1.x+v2.x, v1.y+v2.y, v1.z+v2.z); +} + +inline _D3DVECTOR +operator - (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return _D3DVECTOR(v1.x-v2.x, v1.y-v2.y, v1.z-v2.z); +} + +inline _D3DVECTOR +operator * (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return _D3DVECTOR(v1.x*v2.x, v1.y*v2.y, v1.z*v2.z); +} + +inline _D3DVECTOR +operator / (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return _D3DVECTOR(v1.x/v2.x, v1.y/v2.y, v1.z/v2.z); +} + +inline int +operator < (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return v1[0] < v2[0] && v1[1] < v2[1] && v1[2] < v2[2]; +} + +inline int +operator <= (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return v1[0] <= v2[0] && v1[1] <= v2[1] && v1[2] <= v2[2]; +} + +inline _D3DVECTOR +operator * (const _D3DVECTOR& v, D3DVALUE s) +{ + return _D3DVECTOR(s*v.x, s*v.y, s*v.z); +} + +inline _D3DVECTOR +operator * (D3DVALUE s, const _D3DVECTOR& v) +{ + return _D3DVECTOR(s*v.x, s*v.y, s*v.z); +} + +inline _D3DVECTOR +operator / (const _D3DVECTOR& v, D3DVALUE s) +{ + return _D3DVECTOR(v.x/s, v.y/s, v.z/s); +} + +inline int +operator == (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return v1.x==v2.x && v1.y==v2.y && v1.z == v2.z; +} + +inline D3DVALUE +Magnitude (const _D3DVECTOR& v) +{ + return (D3DVALUE) sqrt(SquareMagnitude(v)); +} + +inline D3DVALUE +SquareMagnitude (const _D3DVECTOR& v) +{ + return v.x*v.x + v.y*v.y + v.z*v.z; +} + +inline _D3DVECTOR +Normalize (const _D3DVECTOR& v) +{ + return v / Magnitude(v); +} + +inline D3DVALUE +Min (const _D3DVECTOR& v) +{ + D3DVALUE ret = v.x; + if (v.y < ret) ret = v.y; + if (v.z < ret) ret = v.z; + return ret; +} + +inline D3DVALUE +Max (const _D3DVECTOR& v) +{ + D3DVALUE ret = v.x; + if (ret < v.y) ret = v.y; + if (ret < v.z) ret = v.z; + return ret; +} + +inline _D3DVECTOR +Minimize (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return _D3DVECTOR( v1[0] < v2[0] ? v1[0] : v2[0], + v1[1] < v2[1] ? v1[1] : v2[1], + v1[2] < v2[2] ? v1[2] : v2[2]); +} + +inline _D3DVECTOR +Maximize (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return _D3DVECTOR( v1[0] > v2[0] ? v1[0] : v2[0], + v1[1] > v2[1] ? v1[1] : v2[1], + v1[2] > v2[2] ? v1[2] : v2[2]); +} + +inline D3DVALUE +DotProduct (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + return v1.x*v2.x + v1.y * v2.y + v1.z*v2.z; +} + +inline _D3DVECTOR +CrossProduct (const _D3DVECTOR& v1, const _D3DVECTOR& v2) +{ + _D3DVECTOR result; + + result[0] = v1[1] * v2[2] - v1[2] * v2[1]; + result[1] = v1[2] * v2[0] - v1[0] * v2[2]; + result[2] = v1[0] * v2[1] - v1[1] * v2[0]; + + return result; +} + diff --git a/3rdparty/dx5/inc/ddraw.h b/3rdparty/dx5/inc/ddraw.h new file mode 100644 index 00000000..7923059c --- /dev/null +++ b/3rdparty/dx5/inc/ddraw.h @@ -0,0 +1,3791 @@ +/*==========================================================================; + * + * Copyright (C) 1994-1997 Microsoft Corporation. All Rights Reserved. + * + * File: ddraw.h + * Content: DirectDraw include file + * + ***************************************************************************/ + +#ifndef __DDRAW_INCLUDED__ +#define __DDRAW_INCLUDED__ + +/* + * If you wish an application built against the newest version of DirectDraw + * to run against an older DirectDraw run time then define DIRECTDRAW_VERSION + * to be the earlies version of DirectDraw you wish to run against. For, + * example if you wish an application to run against a DX 3 runtime define + * DIRECTDRAW_VERSION to be 0x0300. + */ +#ifndef DIRECTDRAW_VERSION +#define DIRECTDRAW_VERSION 0x0500 +#endif /* DIRECTDRAW_VERSION */ + +#if defined( _WIN32 ) && !defined( _NO_COM ) +#define COM_NO_WINDOWS_H +#include +#else +#define IUnknown void +#if !defined( NT_BUILD_ENVIRONMENT ) && !defined(WINNT) + #define CO_E_NOTINITIALIZED 0x800401F0L +#endif +#endif + +#define _FACDD 0x876 +#define MAKE_DDHRESULT( code ) MAKE_HRESULT( 1, _FACDD, code ) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * GUIDS used by DirectDraw objects + */ +#if defined( _WIN32 ) && !defined( _NO_COM ) +DEFINE_GUID( CLSID_DirectDraw, 0xD7B70EE0,0x4340,0x11CF,0xB0,0x63,0x00,0x20,0xAF,0xC2,0xCD,0x35 ); +DEFINE_GUID( CLSID_DirectDrawClipper, 0x593817A0,0x7DB3,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xb9,0x33,0x56 ); +DEFINE_GUID( IID_IDirectDraw, 0x6C14DB80,0xA733,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60 ); +DEFINE_GUID( IID_IDirectDraw2, 0xB3A6F3E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 ); +DEFINE_GUID( IID_IDirectDrawSurface, 0x6C14DB81,0xA733,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60 ); +DEFINE_GUID( IID_IDirectDrawSurface2, 0x57805885,0x6eec,0x11cf,0x94,0x41,0xa8,0x23,0x03,0xc1,0x0e,0x27 ); +DEFINE_GUID( IID_IDirectDrawSurface3, 0xDA044E00,0x69B2,0x11D0,0xA1,0xD5,0x00,0xAA,0x00,0xB8,0xDF,0xBB ); + +DEFINE_GUID( IID_IDirectDrawPalette, 0x6C14DB84,0xA733,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60 ); +DEFINE_GUID( IID_IDirectDrawClipper, 0x6C14DB85,0xA733,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60 ); +DEFINE_GUID( IID_IDirectDrawColorControl, 0x4B9F0EE0,0x0D7E,0x11D0,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8 ); + +#endif + +/*============================================================================ + * + * DirectDraw Structures + * + * Various structures used to invoke DirectDraw. + * + *==========================================================================*/ + +struct IDirectDraw; +struct IDirectDrawSurface; +struct IDirectDrawPalette; +struct IDirectDrawClipper; + +typedef struct IDirectDraw FAR *LPDIRECTDRAW; +typedef struct IDirectDraw2 FAR *LPDIRECTDRAW2; +typedef struct IDirectDrawSurface FAR *LPDIRECTDRAWSURFACE; +typedef struct IDirectDrawSurface2 FAR *LPDIRECTDRAWSURFACE2; +typedef struct IDirectDrawSurface3 FAR *LPDIRECTDRAWSURFACE3; + +typedef struct IDirectDrawPalette FAR *LPDIRECTDRAWPALETTE; +typedef struct IDirectDrawClipper FAR *LPDIRECTDRAWCLIPPER; +typedef struct IDirectDrawColorControl FAR *LPDIRECTDRAWCOLORCONTROL; + +typedef struct _DDFXROP FAR *LPDDFXROP; +typedef struct _DDSURFACEDESC FAR *LPDDSURFACEDESC; +typedef struct _DDCOLORCONTROL FAR *LPDDCOLORCONTROL; + +/* + * API's + */ +#if (defined (WIN32) || defined( _WIN32 ) ) && !defined( _NO_COM ) +//#if defined( _WIN32 ) && !defined( _NO_ENUM ) + typedef BOOL (FAR PASCAL * LPDDENUMCALLBACKA)(GUID FAR *, LPSTR, LPSTR, LPVOID); + typedef BOOL (FAR PASCAL * LPDDENUMCALLBACKW)(GUID FAR *, LPWSTR, LPWSTR, LPVOID); + extern HRESULT WINAPI DirectDrawEnumerateW( LPDDENUMCALLBACKW lpCallback, LPVOID lpContext ); + extern HRESULT WINAPI DirectDrawEnumerateA( LPDDENUMCALLBACKA lpCallback, LPVOID lpContext ); + #ifdef UNICODE + typedef LPDDENUMCALLBACKW LPDDENUMCALLBACK; + #define DirectDrawEnumerate DirectDrawEnumerateW + #else + typedef LPDDENUMCALLBACKA LPDDENUMCALLBACK; + #define DirectDrawEnumerate DirectDrawEnumerateA + #endif + extern HRESULT WINAPI DirectDrawCreate( GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter ); + extern HRESULT WINAPI DirectDrawCreateClipper( DWORD dwFlags, LPDIRECTDRAWCLIPPER FAR *lplpDDClipper, IUnknown FAR *pUnkOuter ); +#endif + + +#define REGSTR_KEY_DDHW_DESCRIPTION "Description" +#define REGSTR_KEY_DDHW_DRIVERNAME "DriverName" +#define REGSTR_PATH_DDHW "Hardware\\DirectDrawDrivers" + +#define DDCREATE_HARDWAREONLY 0x00000001l +#define DDCREATE_EMULATIONONLY 0x00000002l + +#if defined(WINNT) || !defined(WIN32) +typedef long HRESULT; +#endif + +//#ifndef WINNT +typedef HRESULT (FAR PASCAL * LPDDENUMMODESCALLBACK)(LPDDSURFACEDESC, LPVOID); +typedef HRESULT (FAR PASCAL * LPDDENUMSURFACESCALLBACK)(LPDIRECTDRAWSURFACE, LPDDSURFACEDESC, LPVOID); +//#endif +/* + * DDCOLORKEY + */ +typedef struct _DDCOLORKEY +{ + DWORD dwColorSpaceLowValue; // low boundary of color space that is to + // be treated as Color Key, inclusive + DWORD dwColorSpaceHighValue; // high boundary of color space that is + // to be treated as Color Key, inclusive +} DDCOLORKEY; + +typedef DDCOLORKEY FAR* LPDDCOLORKEY; + +/* + * DDBLTFX + * Used to pass override information to the DIRECTDRAWSURFACE callback Blt. + */ +typedef struct _DDBLTFX +{ + DWORD dwSize; // size of structure + DWORD dwDDFX; // FX operations + DWORD dwROP; // Win32 raster operations + DWORD dwDDROP; // Raster operations new for DirectDraw + DWORD dwRotationAngle; // Rotation angle for blt + DWORD dwZBufferOpCode; // ZBuffer compares + DWORD dwZBufferLow; // Low limit of Z buffer + DWORD dwZBufferHigh; // High limit of Z buffer + DWORD dwZBufferBaseDest; // Destination base value + DWORD dwZDestConstBitDepth; // Bit depth used to specify Z constant for destination + union + { + DWORD dwZDestConst; // Constant to use as Z buffer for dest + LPDIRECTDRAWSURFACE lpDDSZBufferDest; // Surface to use as Z buffer for dest + }; + DWORD dwZSrcConstBitDepth; // Bit depth used to specify Z constant for source + union + { + DWORD dwZSrcConst; // Constant to use as Z buffer for src + LPDIRECTDRAWSURFACE lpDDSZBufferSrc; // Surface to use as Z buffer for src + }; + DWORD dwAlphaEdgeBlendBitDepth; // Bit depth used to specify constant for alpha edge blend + DWORD dwAlphaEdgeBlend; // Alpha for edge blending + DWORD dwReserved; + DWORD dwAlphaDestConstBitDepth; // Bit depth used to specify alpha constant for destination + union + { + DWORD dwAlphaDestConst; // Constant to use as Alpha Channel + LPDIRECTDRAWSURFACE lpDDSAlphaDest; // Surface to use as Alpha Channel + }; + DWORD dwAlphaSrcConstBitDepth; // Bit depth used to specify alpha constant for source + union + { + DWORD dwAlphaSrcConst; // Constant to use as Alpha Channel + LPDIRECTDRAWSURFACE lpDDSAlphaSrc; // Surface to use as Alpha Channel + }; + union + { + DWORD dwFillColor; // color in RGB or Palettized + DWORD dwFillDepth; // depth value for z-buffer + DWORD dwFillPixel; // pixel value for RGBA or RGBZ + LPDIRECTDRAWSURFACE lpDDSPattern; // Surface to use as pattern + }; + DDCOLORKEY ddckDestColorkey; // DestColorkey override + DDCOLORKEY ddckSrcColorkey; // SrcColorkey override +} DDBLTFX; + +typedef DDBLTFX FAR* LPDDBLTFX; + + +/* + * DDSCAPS + */ +typedef struct _DDSCAPS +{ + DWORD dwCaps; // capabilities of surface wanted +} DDSCAPS; + +typedef DDSCAPS FAR* LPDDSCAPS; + +/* + * DDCAPS + */ +#define DD_ROP_SPACE (256/32) // space required to store ROP array + +#if DIRECTDRAW_VERSION >= 0x0500 +/* + * This structure is the DDCAPS structure as it was in version 2 and 3 of Direct X. + * It is present for back compatability. + */ +typedef struct _DDCAPS_DX3 +{ + DWORD dwSize; // size of the DDDRIVERCAPS structure + DWORD dwCaps; // driver specific capabilities + DWORD dwCaps2; // more driver specific capabilites + DWORD dwCKeyCaps; // color key capabilities of the surface + DWORD dwFXCaps; // driver specific stretching and effects capabilites + DWORD dwFXAlphaCaps; // alpha driver specific capabilities + DWORD dwPalCaps; // palette capabilities + DWORD dwSVCaps; // stereo vision capabilities + DWORD dwAlphaBltConstBitDepths; // DDBD_2,4,8 + DWORD dwAlphaBltPixelBitDepths; // DDBD_1,2,4,8 + DWORD dwAlphaBltSurfaceBitDepths; // DDBD_1,2,4,8 + DWORD dwAlphaOverlayConstBitDepths; // DDBD_2,4,8 + DWORD dwAlphaOverlayPixelBitDepths; // DDBD_1,2,4,8 + DWORD dwAlphaOverlaySurfaceBitDepths; // DDBD_1,2,4,8 + DWORD dwZBufferBitDepths; // DDBD_8,16,24,32 + DWORD dwVidMemTotal; // total amount of video memory + DWORD dwVidMemFree; // amount of free video memory + DWORD dwMaxVisibleOverlays; // maximum number of visible overlays + DWORD dwCurrVisibleOverlays; // current number of visible overlays + DWORD dwNumFourCCCodes; // number of four cc codes + DWORD dwAlignBoundarySrc; // source rectangle alignment + DWORD dwAlignSizeSrc; // source rectangle byte size + DWORD dwAlignBoundaryDest; // dest rectangle alignment + DWORD dwAlignSizeDest; // dest rectangle byte size + DWORD dwAlignStrideAlign; // stride alignment + DWORD dwRops[DD_ROP_SPACE]; // ROPS supported + DDSCAPS ddsCaps; // DDSCAPS structure has all the general capabilities + DWORD dwMinOverlayStretch; // minimum overlay stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 + DWORD dwMaxOverlayStretch; // maximum overlay stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 + DWORD dwMinLiveVideoStretch; // minimum live video stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 + DWORD dwMaxLiveVideoStretch; // maximum live video stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 + DWORD dwMinHwCodecStretch; // minimum hardware codec stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 + DWORD dwMaxHwCodecStretch; // maximum hardware codec stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 + DWORD dwReserved1; // reserved + DWORD dwReserved2; // reserved + DWORD dwReserved3; // reserved + DWORD dwSVBCaps; // driver specific capabilities for System->Vmem blts + DWORD dwSVBCKeyCaps; // driver color key capabilities for System->Vmem blts + DWORD dwSVBFXCaps; // driver FX capabilities for System->Vmem blts + DWORD dwSVBRops[DD_ROP_SPACE];// ROPS supported for System->Vmem blts + DWORD dwVSBCaps; // driver specific capabilities for Vmem->System blts + DWORD dwVSBCKeyCaps; // driver color key capabilities for Vmem->System blts + DWORD dwVSBFXCaps; // driver FX capabilities for Vmem->System blts + DWORD dwVSBRops[DD_ROP_SPACE];// ROPS supported for Vmem->System blts + DWORD dwSSBCaps; // driver specific capabilities for System->System blts + DWORD dwSSBCKeyCaps; // driver color key capabilities for System->System blts + DWORD dwSSBFXCaps; // driver FX capabilities for System->System blts + DWORD dwSSBRops[DD_ROP_SPACE];// ROPS supported for System->System blts + DWORD dwReserved4; // reserved + DWORD dwReserved5; // reserved + DWORD dwReserved6; // reserved +} DDCAPS_DX3; +typedef DDCAPS_DX3 FAR* LPDDCAPS_DX3; +#endif /* DIRECTDRAW_VERSION >= 0x0500 */ + +typedef struct _DDCAPS +{ +/* 0*/ DWORD dwSize; // size of the DDDRIVERCAPS structure +/* 4*/ DWORD dwCaps; // driver specific capabilities +/* 8*/ DWORD dwCaps2; // more driver specific capabilites +/* c*/ DWORD dwCKeyCaps; // color key capabilities of the surface +/* 10*/ DWORD dwFXCaps; // driver specific stretching and effects capabilites +/* 14*/ DWORD dwFXAlphaCaps; // alpha driver specific capabilities +/* 18*/ DWORD dwPalCaps; // palette capabilities +/* 1c*/ DWORD dwSVCaps; // stereo vision capabilities +/* 20*/ DWORD dwAlphaBltConstBitDepths; // DDBD_2,4,8 +/* 24*/ DWORD dwAlphaBltPixelBitDepths; // DDBD_1,2,4,8 +/* 28*/ DWORD dwAlphaBltSurfaceBitDepths; // DDBD_1,2,4,8 +/* 2c*/ DWORD dwAlphaOverlayConstBitDepths; // DDBD_2,4,8 +/* 30*/ DWORD dwAlphaOverlayPixelBitDepths; // DDBD_1,2,4,8 +/* 34*/ DWORD dwAlphaOverlaySurfaceBitDepths; // DDBD_1,2,4,8 +/* 38*/ DWORD dwZBufferBitDepths; // DDBD_8,16,24,32 +/* 3c*/ DWORD dwVidMemTotal; // total amount of video memory +/* 40*/ DWORD dwVidMemFree; // amount of free video memory +/* 44*/ DWORD dwMaxVisibleOverlays; // maximum number of visible overlays +/* 48*/ DWORD dwCurrVisibleOverlays; // current number of visible overlays +/* 4c*/ DWORD dwNumFourCCCodes; // number of four cc codes +/* 50*/ DWORD dwAlignBoundarySrc; // source rectangle alignment +/* 54*/ DWORD dwAlignSizeSrc; // source rectangle byte size +/* 58*/ DWORD dwAlignBoundaryDest; // dest rectangle alignment +/* 5c*/ DWORD dwAlignSizeDest; // dest rectangle byte size +/* 60*/ DWORD dwAlignStrideAlign; // stride alignment +/* 64*/ DWORD dwRops[DD_ROP_SPACE]; // ROPS supported +/* 84*/ DDSCAPS ddsCaps; // DDSCAPS structure has all the general capabilities +/* 88*/ DWORD dwMinOverlayStretch; // minimum overlay stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 +/* 8c*/ DWORD dwMaxOverlayStretch; // maximum overlay stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 +/* 90*/ DWORD dwMinLiveVideoStretch; // minimum live video stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 +/* 94*/ DWORD dwMaxLiveVideoStretch; // maximum live video stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 +/* 98*/ DWORD dwMinHwCodecStretch; // minimum hardware codec stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 +/* 9c*/ DWORD dwMaxHwCodecStretch; // maximum hardware codec stretch factor multiplied by 1000, eg 1000 == 1.0, 1300 == 1.3 +/* a0*/ DWORD dwReserved1; // reserved +/* a4*/ DWORD dwReserved2; // reserved +/* a8*/ DWORD dwReserved3; // reserved +/* ac*/ DWORD dwSVBCaps; // driver specific capabilities for System->Vmem blts +/* b0*/ DWORD dwSVBCKeyCaps; // driver color key capabilities for System->Vmem blts +/* b4*/ DWORD dwSVBFXCaps; // driver FX capabilities for System->Vmem blts +/* b8*/ DWORD dwSVBRops[DD_ROP_SPACE];// ROPS supported for System->Vmem blts +/* d8*/ DWORD dwVSBCaps; // driver specific capabilities for Vmem->System blts +/* dc*/ DWORD dwVSBCKeyCaps; // driver color key capabilities for Vmem->System blts +/* e0*/ DWORD dwVSBFXCaps; // driver FX capabilities for Vmem->System blts +/* e4*/ DWORD dwVSBRops[DD_ROP_SPACE];// ROPS supported for Vmem->System blts +/*104*/ DWORD dwSSBCaps; // driver specific capabilities for System->System blts +/*108*/ DWORD dwSSBCKeyCaps; // driver color key capabilities for System->System blts +/*10c*/ DWORD dwSSBFXCaps; // driver FX capabilities for System->System blts +/*110*/ DWORD dwSSBRops[DD_ROP_SPACE];// ROPS supported for System->System blts +#if DIRECTDRAW_VERSION >= 0x0500 +/*130*/ DWORD dwMaxVideoPorts; // maximum number of usable video ports +/*134*/ DWORD dwCurrVideoPorts; // current number of video ports used +/*138*/ DWORD dwSVBCaps2; // more driver specific capabilities for System->Vmem blts +/*13c*/ DWORD dwNLVBCaps; // driver specific capabilities for non-local->local vidmem blts +/*140*/ DWORD dwNLVBCaps2; // more driver specific capabilities non-local->local vidmem blts +/*144*/ DWORD dwNLVBCKeyCaps; // driver color key capabilities for non-local->local vidmem blts +/*148*/ DWORD dwNLVBFXCaps; // driver FX capabilities for non-local->local blts +/*14c*/ DWORD dwNLVBRops[DD_ROP_SPACE]; // ROPS supported for non-local->local blts +#else /* DIRECTDRAW_VERSION >= 0x0500 */ +/*130*/ DWORD dwReserved4; // reserved +/*134*/ DWORD dwReserved5; // reserved +/*138*/ DWORD dwReserved6; // reserved +#endif /* DIRECTDRAW_VERSION >= 0x0500 */ +} DDCAPS; + +typedef DDCAPS FAR* LPDDCAPS; + + + +/* + * DDPIXELFORMAT + */ +typedef struct _DDPIXELFORMAT +{ + DWORD dwSize; // size of structure + DWORD dwFlags; // pixel format flags + DWORD dwFourCC; // (FOURCC code) + union + { + DWORD dwRGBBitCount; // how many bits per pixel + DWORD dwYUVBitCount; // how many bits per pixel + DWORD dwZBufferBitDepth; // how many bits for z buffers + DWORD dwAlphaBitDepth; // how many bits for alpha channels + }; + union + { + DWORD dwRBitMask; // mask for red bit + DWORD dwYBitMask; // mask for Y bits + }; + union + { + DWORD dwGBitMask; // mask for green bits + DWORD dwUBitMask; // mask for U bits + }; + union + { + DWORD dwBBitMask; // mask for blue bits + DWORD dwVBitMask; // mask for V bits + }; + union + { + DWORD dwRGBAlphaBitMask; // mask for alpha channel + DWORD dwYUVAlphaBitMask; // mask for alpha channel + DWORD dwRGBZBitMask; // mask for Z channel + DWORD dwYUVZBitMask; // mask for Z channel + }; +} DDPIXELFORMAT; + +typedef DDPIXELFORMAT FAR* LPDDPIXELFORMAT; + +/* + * DDOVERLAYFX + */ +typedef struct _DDOVERLAYFX +{ + DWORD dwSize; // size of structure + DWORD dwAlphaEdgeBlendBitDepth; // Bit depth used to specify constant for alpha edge blend + DWORD dwAlphaEdgeBlend; // Constant to use as alpha for edge blend + DWORD dwReserved; + DWORD dwAlphaDestConstBitDepth; // Bit depth used to specify alpha constant for destination + union + { + DWORD dwAlphaDestConst; // Constant to use as alpha channel for dest + LPDIRECTDRAWSURFACE lpDDSAlphaDest; // Surface to use as alpha channel for dest + }; + DWORD dwAlphaSrcConstBitDepth; // Bit depth used to specify alpha constant for source + union + { + DWORD dwAlphaSrcConst; // Constant to use as alpha channel for src + LPDIRECTDRAWSURFACE lpDDSAlphaSrc; // Surface to use as alpha channel for src + }; + DDCOLORKEY dckDestColorkey; // DestColorkey override + DDCOLORKEY dckSrcColorkey; // DestColorkey override + DWORD dwDDFX; // Overlay FX + DWORD dwFlags; // flags +} DDOVERLAYFX; + +typedef DDOVERLAYFX FAR *LPDDOVERLAYFX; + +/* + * DDBLTBATCH: BltBatch entry structure + */ +typedef struct _DDBLTBATCH +{ + LPRECT lprDest; + LPDIRECTDRAWSURFACE lpDDSSrc; + LPRECT lprSrc; + DWORD dwFlags; + LPDDBLTFX lpDDBltFx; +} DDBLTBATCH; + +typedef DDBLTBATCH FAR * LPDDBLTBATCH; + +/* + * callbacks + */ +typedef DWORD (FAR PASCAL *LPCLIPPERCALLBACK)(LPDIRECTDRAWCLIPPER lpDDClipper, HWND hWnd, DWORD code, LPVOID lpContext ); +#ifdef STREAMING +typedef DWORD (FAR PASCAL *LPSURFACESTREAMINGCALLBACK)(DWORD); +#endif + + +/* + * INTERACES FOLLOW: + * IDirectDraw + * IDirectDrawClipper + * IDirectDrawPalette + * IDirectDrawSurface + */ + +/* + * IDirectDraw + */ +#if defined( _WIN32 ) && !defined( _NO_COM ) +#undef INTERFACE +#define INTERFACE IDirectDraw +DECLARE_INTERFACE_( IDirectDraw, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectDraw methods ***/ + STDMETHOD(Compact)(THIS) PURE; + STDMETHOD(CreateClipper)(THIS_ DWORD, LPDIRECTDRAWCLIPPER FAR*, IUnknown FAR * ) PURE; + STDMETHOD(CreatePalette)(THIS_ DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE FAR*, IUnknown FAR * ) PURE; + STDMETHOD(CreateSurface)(THIS_ LPDDSURFACEDESC, LPDIRECTDRAWSURFACE FAR *, IUnknown FAR *) PURE; + STDMETHOD(DuplicateSurface)( THIS_ LPDIRECTDRAWSURFACE, LPDIRECTDRAWSURFACE FAR * ) PURE; + STDMETHOD(EnumDisplayModes)( THIS_ DWORD, LPDDSURFACEDESC, LPVOID, LPDDENUMMODESCALLBACK ) PURE; + STDMETHOD(EnumSurfaces)(THIS_ DWORD, LPDDSURFACEDESC, LPVOID,LPDDENUMSURFACESCALLBACK ) PURE; + STDMETHOD(FlipToGDISurface)(THIS) PURE; + STDMETHOD(GetCaps)( THIS_ LPDDCAPS, LPDDCAPS) PURE; + STDMETHOD(GetDisplayMode)( THIS_ LPDDSURFACEDESC) PURE; + STDMETHOD(GetFourCCCodes)(THIS_ LPDWORD, LPDWORD ) PURE; + STDMETHOD(GetGDISurface)(THIS_ LPDIRECTDRAWSURFACE FAR *) PURE; + STDMETHOD(GetMonitorFrequency)(THIS_ LPDWORD) PURE; + STDMETHOD(GetScanLine)(THIS_ LPDWORD) PURE; + STDMETHOD(GetVerticalBlankStatus)(THIS_ LPBOOL ) PURE; + STDMETHOD(Initialize)(THIS_ GUID FAR *) PURE; + STDMETHOD(RestoreDisplayMode)(THIS) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND, DWORD) PURE; + STDMETHOD(SetDisplayMode)(THIS_ DWORD, DWORD,DWORD) PURE; + STDMETHOD(WaitForVerticalBlank)(THIS_ DWORD, HANDLE ) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectDraw_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirectDraw_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectDraw_Release(p) (p)->lpVtbl->Release(p) +#define IDirectDraw_Compact(p) (p)->lpVtbl->Compact(p) +#define IDirectDraw_CreateClipper(p, a, b, c) (p)->lpVtbl->CreateClipper(p, a, b, c) +#define IDirectDraw_CreatePalette(p, a, b, c, d) (p)->lpVtbl->CreatePalette(p, a, b, c, d) +#define IDirectDraw_CreateSurface(p, a, b, c) (p)->lpVtbl->CreateSurface(p, a, b, c) +#define IDirectDraw_DuplicateSurface(p, a, b) (p)->lpVtbl->DuplicateSurface(p, a, b) +#define IDirectDraw_EnumDisplayModes(p, a, b, c, d) (p)->lpVtbl->EnumDisplayModes(p, a, b, c, d) +#define IDirectDraw_EnumSurfaces(p, a, b, c, d) (p)->lpVtbl->EnumSurfaces(p, a, b, c, d) +#define IDirectDraw_FlipToGDISurface(p) (p)->lpVtbl->FlipToGDISurface(p) +#define IDirectDraw_GetCaps(p, a, b) (p)->lpVtbl->GetCaps(p, a, b) +#define IDirectDraw_GetDisplayMode(p, a) (p)->lpVtbl->GetDisplayMode(p, a) +#define IDirectDraw_GetFourCCCodes(p, a, b) (p)->lpVtbl->GetFourCCCodes(p, a, b) +#define IDirectDraw_GetGDISurface(p, a) (p)->lpVtbl->GetGDISurface(p, a) +#define IDirectDraw_GetMonitorFrequency(p, a) (p)->lpVtbl->GetMonitorFrequency(p, a) +#define IDirectDraw_GetScanLine(p, a) (p)->lpVtbl->GetScanLine(p, a) +#define IDirectDraw_GetVerticalBlankStatus(p, a) (p)->lpVtbl->GetVerticalBlankStatus(p, a) +#define IDirectDraw_Initialize(p, a) (p)->lpVtbl->Initialize(p, a) +#define IDirectDraw_RestoreDisplayMode(p) (p)->lpVtbl->RestoreDisplayMode(p) +#define IDirectDraw_SetCooperativeLevel(p, a, b) (p)->lpVtbl->SetCooperativeLevel(p, a, b) +#define IDirectDraw_SetDisplayMode(p, a, b, c) (p)->lpVtbl->SetDisplayMode(p, a, b, c) +#define IDirectDraw_WaitForVerticalBlank(p, a, b) (p)->lpVtbl->WaitForVerticalBlank(p, a, b) +#else +#define IDirectDraw_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirectDraw_AddRef(p) (p)->AddRef() +#define IDirectDraw_Release(p) (p)->Release() +#define IDirectDraw_Compact(p) (p)->Compact() +#define IDirectDraw_CreateClipper(p, a, b, c) (p)->CreateClipper(a, b, c) +#define IDirectDraw_CreatePalette(p, a, b, c, d) (p)->CreatePalette(a, b, c, d) +#define IDirectDraw_CreateSurface(p, a, b, c) (p)->CreateSurface(a, b, c) +#define IDirectDraw_DuplicateSurface(p, a, b) (p)->DuplicateSurface(a, b) +#define IDirectDraw_EnumDisplayModes(p, a, b, c, d) (p)->EnumDisplayModes(a, b, c, d) +#define IDirectDraw_EnumSurfaces(p, a, b, c, d) (p)->EnumSurfaces(a, b, c, d) +#define IDirectDraw_FlipToGDISurface(p) (p)->FlipToGDISurface() +#define IDirectDraw_GetCaps(p, a, b) (p)->GetCaps(a, b) +#define IDirectDraw_GetDisplayMode(p, a) (p)->GetDisplayMode(a) +#define IDirectDraw_GetFourCCCodes(p, a, b) (p)->GetFourCCCodes(a, b) +#define IDirectDraw_GetGDISurface(p, a) (p)->GetGDISurface(a) +#define IDirectDraw_GetMonitorFrequency(p, a) (p)->GetMonitorFrequency(a) +#define IDirectDraw_GetScanLine(p, a) (p)->GetScanLine(a) +#define IDirectDraw_GetVerticalBlankStatus(p, a) (p)->GetVerticalBlankStatus(a) +#define IDirectDraw_Initialize(p, a) (p)->Initialize(a) +#define IDirectDraw_RestoreDisplayMode(p) (p)->RestoreDisplayMode() +#define IDirectDraw_SetCooperativeLevel(p, a, b) (p)->SetCooperativeLevel(a, b) +#define IDirectDraw_SetDisplayMode(p, a, b, c) (p)->SetDisplayMode(a, b, c) +#define IDirectDraw_WaitForVerticalBlank(p, a, b) (p)->WaitForVerticalBlank(a, b) +#endif + +#endif + +#if defined( _WIN32 ) && !defined( _NO_COM ) +#undef INTERFACE +#define INTERFACE IDirectDraw2 +DECLARE_INTERFACE_( IDirectDraw2, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectDraw methods ***/ + STDMETHOD(Compact)(THIS) PURE; + STDMETHOD(CreateClipper)(THIS_ DWORD, LPDIRECTDRAWCLIPPER FAR*, IUnknown FAR * ) PURE; + STDMETHOD(CreatePalette)(THIS_ DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE FAR*, IUnknown FAR * ) PURE; + STDMETHOD(CreateSurface)(THIS_ LPDDSURFACEDESC, LPDIRECTDRAWSURFACE FAR *, IUnknown FAR *) PURE; + STDMETHOD(DuplicateSurface)( THIS_ LPDIRECTDRAWSURFACE, LPDIRECTDRAWSURFACE FAR * ) PURE; + STDMETHOD(EnumDisplayModes)( THIS_ DWORD, LPDDSURFACEDESC, LPVOID, LPDDENUMMODESCALLBACK ) PURE; + STDMETHOD(EnumSurfaces)(THIS_ DWORD, LPDDSURFACEDESC, LPVOID,LPDDENUMSURFACESCALLBACK ) PURE; + STDMETHOD(FlipToGDISurface)(THIS) PURE; + STDMETHOD(GetCaps)( THIS_ LPDDCAPS, LPDDCAPS) PURE; + STDMETHOD(GetDisplayMode)( THIS_ LPDDSURFACEDESC) PURE; + STDMETHOD(GetFourCCCodes)(THIS_ LPDWORD, LPDWORD ) PURE; + STDMETHOD(GetGDISurface)(THIS_ LPDIRECTDRAWSURFACE FAR *) PURE; + STDMETHOD(GetMonitorFrequency)(THIS_ LPDWORD) PURE; + STDMETHOD(GetScanLine)(THIS_ LPDWORD) PURE; + STDMETHOD(GetVerticalBlankStatus)(THIS_ LPBOOL ) PURE; + STDMETHOD(Initialize)(THIS_ GUID FAR *) PURE; + STDMETHOD(RestoreDisplayMode)(THIS) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND, DWORD) PURE; + STDMETHOD(SetDisplayMode)(THIS_ DWORD, DWORD,DWORD, DWORD, DWORD) PURE; + STDMETHOD(WaitForVerticalBlank)(THIS_ DWORD, HANDLE ) PURE; + /*** Added in the v2 interface ***/ + STDMETHOD(GetAvailableVidMem)(THIS_ LPDDSCAPS, LPDWORD, LPDWORD) PURE; +}; +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectDraw2_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirectDraw2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectDraw2_Release(p) (p)->lpVtbl->Release(p) +#define IDirectDraw2_Compact(p) (p)->lpVtbl->Compact(p) +#define IDirectDraw2_CreateClipper(p, a, b, c) (p)->lpVtbl->CreateClipper(p, a, b, c) +#define IDirectDraw2_CreatePalette(p, a, b, c, d) (p)->lpVtbl->CreatePalette(p, a, b, c, d) +#define IDirectDraw2_CreateSurface(p, a, b, c) (p)->lpVtbl->CreateSurface(p, a, b, c) +#define IDirectDraw2_DuplicateSurface(p, a, b) (p)->lpVtbl->DuplicateSurface(p, a, b) +#define IDirectDraw2_EnumDisplayModes(p, a, b, c, d) (p)->lpVtbl->EnumDisplayModes(p, a, b, c, d) +#define IDirectDraw2_EnumSurfaces(p, a, b, c, d) (p)->lpVtbl->EnumSurfaces(p, a, b, c, d) +#define IDirectDraw2_FlipToGDISurface(p) (p)->lpVtbl->FlipToGDISurface(p) +#define IDirectDraw2_GetCaps(p, a, b) (p)->lpVtbl->GetCaps(p, a, b) +#define IDirectDraw2_GetDisplayMode(p, a) (p)->lpVtbl->GetDisplayMode(p, a) +#define IDirectDraw2_GetFourCCCodes(p, a, b) (p)->lpVtbl->GetFourCCCodes(p, a, b) +#define IDirectDraw2_GetGDISurface(p, a) (p)->lpVtbl->GetGDISurface(p, a) +#define IDirectDraw2_GetMonitorFrequency(p, a) (p)->lpVtbl->GetMonitorFrequency(p, a) +#define IDirectDraw2_GetScanLine(p, a) (p)->lpVtbl->GetScanLine(p, a) +#define IDirectDraw2_GetVerticalBlankStatus(p, a) (p)->lpVtbl->GetVerticalBlankStatus(p, a) +#define IDirectDraw2_Initialize(p, a) (p)->lpVtbl->Initialize(p, a) +#define IDirectDraw2_RestoreDisplayMode(p) (p)->lpVtbl->RestoreDisplayMode(p) +#define IDirectDraw2_SetCooperativeLevel(p, a, b) (p)->lpVtbl->SetCooperativeLevel(p, a, b) +#define IDirectDraw2_SetDisplayMode(p, a, b, c, d, e) (p)->lpVtbl->SetDisplayMode(p, a, b, c, d, e) +#define IDirectDraw2_WaitForVerticalBlank(p, a, b) (p)->lpVtbl->WaitForVerticalBlank(p, a, b) +#define IDirectDraw2_GetAvailableVidMem(p, a, b, c) (p)->lpVtbl->GetAvailableVidMem(p, a, b, c) +#else +#define IDirectDraw2_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirectDraw2_AddRef(p) (p)->AddRef() +#define IDirectDraw2_Release(p) (p)->Release() +#define IDirectDraw2_Compact(p) (p)->Compact() +#define IDirectDraw2_CreateClipper(p, a, b, c) (p)->CreateClipper(a, b, c) +#define IDirectDraw2_CreatePalette(p, a, b, c, d) (p)->CreatePalette(a, b, c, d) +#define IDirectDraw2_CreateSurface(p, a, b, c) (p)->CreateSurface(a, b, c) +#define IDirectDraw2_DuplicateSurface(p, a, b) (p)->DuplicateSurface(a, b) +#define IDirectDraw2_EnumDisplayModes(p, a, b, c, d) (p)->EnumDisplayModes(a, b, c, d) +#define IDirectDraw2_EnumSurfaces(p, a, b, c, d) (p)->EnumSurfaces(a, b, c, d) +#define IDirectDraw2_FlipToGDISurface(p) (p)->FlipToGDISurface() +#define IDirectDraw2_GetCaps(p, a, b) (p)->GetCaps(a, b) +#define IDirectDraw2_GetDisplayMode(p, a) (p)->GetDisplayMode(a) +#define IDirectDraw2_GetFourCCCodes(p, a, b) (p)->GetFourCCCodes(a, b) +#define IDirectDraw2_GetGDISurface(p, a) (p)->GetGDISurface(a) +#define IDirectDraw2_GetMonitorFrequency(p, a) (p)->GetMonitorFrequency(a) +#define IDirectDraw2_GetScanLine(p, a) (p)->GetScanLine(a) +#define IDirectDraw2_GetVerticalBlankStatus(p, a) (p)->GetVerticalBlankStatus(a) +#define IDirectDraw2_Initialize(p, a) (p)->Initialize(a) +#define IDirectDraw2_RestoreDisplayMode(p) (p)->RestoreDisplayMode() +#define IDirectDraw2_SetCooperativeLevel(p, a, b) (p)->SetCooperativeLevel(a, b) +#define IDirectDraw2_SetDisplayMode(p, a, b, c, d, e) (p)->SetDisplayMode(a, b, c, d, e) +#define IDirectDraw2_WaitForVerticalBlank(p, a, b) (p)->WaitForVerticalBlank(a, b) +#define IDirectDraw2_GetAvailableVidMem(p, a, b, c) (p)->GetAvailableVidMem(a, b, c) +#endif + +#endif + +/* + * IDirectDrawPalette + */ +#if defined( _WIN32 ) && !defined( _NO_COM ) +#undef INTERFACE +#define INTERFACE IDirectDrawPalette +DECLARE_INTERFACE_( IDirectDrawPalette, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectDrawPalette methods ***/ + STDMETHOD(GetCaps)(THIS_ LPDWORD) PURE; + STDMETHOD(GetEntries)(THIS_ DWORD,DWORD,DWORD,LPPALETTEENTRY) PURE; + STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW, DWORD, LPPALETTEENTRY) PURE; + STDMETHOD(SetEntries)(THIS_ DWORD,DWORD,DWORD,LPPALETTEENTRY) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectDrawPalette_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirectDrawPalette_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectDrawPalette_Release(p) (p)->lpVtbl->Release(p) +#define IDirectDrawPalette_GetCaps(p, a) (p)->lpVtbl->GetCaps(p, a) +#define IDirectDrawPalette_GetEntries(p, a, b, c, d) (p)->lpVtbl->GetEntries(p, a, b, c, d) +#define IDirectDrawPalette_Initialize(p, a, b, c) (p)->lpVtbl->Initialize(p, a, b, c) +#define IDirectDrawPalette_SetEntries(p, a, b, c, d) (p)->lpVtbl->SetEntries(p, a, b, c, d) +#else +#define IDirectDrawPalette_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirectDrawPalette_AddRef(p) (p)->AddRef() +#define IDirectDrawPalette_Release(p) (p)->Release() +#define IDirectDrawPalette_GetCaps(p, a) (p)->GetCaps(a) +#define IDirectDrawPalette_GetEntries(p, a, b, c, d) (p)->GetEntries(a, b, c, d) +#define IDirectDrawPalette_Initialize(p, a, b, c) (p)->Initialize(a, b, c) +#define IDirectDrawPalette_SetEntries(p, a, b, c, d) (p)->SetEntries(a, b, c, d) +#endif + +#endif + +/* + * IDirectDrawClipper + */ +#if defined( _WIN32 ) && !defined( _NO_COM ) +#undef INTERFACE +#define INTERFACE IDirectDrawClipper +DECLARE_INTERFACE_( IDirectDrawClipper, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectDrawClipper methods ***/ + STDMETHOD(GetClipList)(THIS_ LPRECT, LPRGNDATA, LPDWORD) PURE; + STDMETHOD(GetHWnd)(THIS_ HWND FAR *) PURE; + STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW, DWORD) PURE; + STDMETHOD(IsClipListChanged)(THIS_ BOOL FAR *) PURE; + STDMETHOD(SetClipList)(THIS_ LPRGNDATA,DWORD) PURE; + STDMETHOD(SetHWnd)(THIS_ DWORD, HWND ) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectDrawClipper_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirectDrawClipper_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectDrawClipper_Release(p) (p)->lpVtbl->Release(p) +#define IDirectDrawClipper_GetClipList(p, a, b, c) (p)->lpVtbl->GetClipList(p, a, b, c) +#define IDirectDrawClipper_GetHWnd(p, a) (p)->lpVtbl->GetHWnd(p, a) +#define IDirectDrawClipper_Initialize(p, a, b) (p)->lpVtbl->Initialize(p, a, b) +#define IDirectDrawClipper_IsClipListChanged(p, a) (p)->lpVtbl->IsClipListChanged(p, a) +#define IDirectDrawClipper_SetClipList(p, a, b) (p)->lpVtbl->SetClipList(p, a, b) +#define IDirectDrawClipper_SetHWnd(p, a, b) (p)->lpVtbl->SetHWnd(p, a, b) +#else +#define IDirectDrawClipper_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirectDrawClipper_AddRef(p) (p)->AddRef() +#define IDirectDrawClipper_Release(p) (p)->Release() +#define IDirectDrawClipper_GetClipList(p, a, b, c) (p)->GetClipList(a, b, c) +#define IDirectDrawClipper_GetHWnd(p, a) (p)->GetHWnd(a) +#define IDirectDrawClipper_Initialize(p, a, b) (p)->Initialize(a, b) +#define IDirectDrawClipper_IsClipListChanged(p, a) (p)->IsClipListChanged(a) +#define IDirectDrawClipper_SetClipList(p, a, b) (p)->SetClipList(a, b) +#define IDirectDrawClipper_SetHWnd(p, a, b) (p)->SetHWnd(a, b) +#endif + +#endif + +/* + * IDirectDrawSurface and related interfaces + */ +#if defined( _WIN32 ) && !defined( _NO_COM ) +#undef INTERFACE +#define INTERFACE IDirectDrawSurface +DECLARE_INTERFACE_( IDirectDrawSurface, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectDrawSurface methods ***/ + STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE) PURE; + STDMETHOD(AddOverlayDirtyRect)(THIS_ LPRECT) PURE; + STDMETHOD(Blt)(THIS_ LPRECT,LPDIRECTDRAWSURFACE, LPRECT,DWORD, LPDDBLTFX) PURE; + STDMETHOD(BltBatch)(THIS_ LPDDBLTBATCH, DWORD, DWORD ) PURE; + STDMETHOD(BltFast)(THIS_ DWORD,DWORD,LPDIRECTDRAWSURFACE, LPRECT,DWORD) PURE; + STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD,LPDIRECTDRAWSURFACE) PURE; + STDMETHOD(EnumAttachedSurfaces)(THIS_ LPVOID,LPDDENUMSURFACESCALLBACK) PURE; + STDMETHOD(EnumOverlayZOrders)(THIS_ DWORD,LPVOID,LPDDENUMSURFACESCALLBACK) PURE; + STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE, DWORD) PURE; + STDMETHOD(GetAttachedSurface)(THIS_ LPDDSCAPS, LPDIRECTDRAWSURFACE FAR *) PURE; + STDMETHOD(GetBltStatus)(THIS_ DWORD) PURE; + STDMETHOD(GetCaps)(THIS_ LPDDSCAPS) PURE; + STDMETHOD(GetClipper)(THIS_ LPDIRECTDRAWCLIPPER FAR*) PURE; + STDMETHOD(GetColorKey)(THIS_ DWORD, LPDDCOLORKEY) PURE; + STDMETHOD(GetDC)(THIS_ HDC FAR *) PURE; + STDMETHOD(GetFlipStatus)(THIS_ DWORD) PURE; + STDMETHOD(GetOverlayPosition)(THIS_ LPLONG, LPLONG ) PURE; + STDMETHOD(GetPalette)(THIS_ LPDIRECTDRAWPALETTE FAR*) PURE; + STDMETHOD(GetPixelFormat)(THIS_ LPDDPIXELFORMAT) PURE; + STDMETHOD(GetSurfaceDesc)(THIS_ LPDDSURFACEDESC) PURE; + STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW, LPDDSURFACEDESC) PURE; + STDMETHOD(IsLost)(THIS) PURE; + STDMETHOD(Lock)(THIS_ LPRECT,LPDDSURFACEDESC,DWORD,HANDLE) PURE; + STDMETHOD(ReleaseDC)(THIS_ HDC) PURE; + STDMETHOD(Restore)(THIS) PURE; + STDMETHOD(SetClipper)(THIS_ LPDIRECTDRAWCLIPPER) PURE; + STDMETHOD(SetColorKey)(THIS_ DWORD, LPDDCOLORKEY) PURE; + STDMETHOD(SetOverlayPosition)(THIS_ LONG, LONG ) PURE; + STDMETHOD(SetPalette)(THIS_ LPDIRECTDRAWPALETTE) PURE; + STDMETHOD(Unlock)(THIS_ LPVOID) PURE; + STDMETHOD(UpdateOverlay)(THIS_ LPRECT, LPDIRECTDRAWSURFACE,LPRECT,DWORD, LPDDOVERLAYFX) PURE; + STDMETHOD(UpdateOverlayDisplay)(THIS_ DWORD) PURE; + STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD, LPDIRECTDRAWSURFACE) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectDrawSurface_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectDrawSurface_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectDrawSurface_Release(p) (p)->lpVtbl->Release(p) +#define IDirectDrawSurface_AddAttachedSurface(p,a) (p)->lpVtbl->AddAttachedSurface(p,a) +#define IDirectDrawSurface_AddOverlayDirtyRect(p,a) (p)->lpVtbl->AddOverlayDirtyRect(p,a) +#define IDirectDrawSurface_Blt(p,a,b,c,d,e) (p)->lpVtbl->Blt(p,a,b,c,d,e) +#define IDirectDrawSurface_BltBatch(p,a,b,c) (p)->lpVtbl->BltBatch(p,a,b,c) +#define IDirectDrawSurface_BltFast(p,a,b,c,d,e) (p)->lpVtbl->BltFast(p,a,b,c,d,e) +#define IDirectDrawSurface_DeleteAttachedSurface(p,a,b) (p)->lpVtbl->DeleteAttachedSurface(p,a,b) +#define IDirectDrawSurface_EnumAttachedSurfaces(p,a,b) (p)->lpVtbl->EnumAttachedSurfaces(p,a,b) +#define IDirectDrawSurface_EnumOverlayZOrders(p,a,b,c) (p)->lpVtbl->EnumOverlayZOrders(p,a,b,c) +#define IDirectDrawSurface_Flip(p,a,b) (p)->lpVtbl->Flip(p,a,b) +#define IDirectDrawSurface_GetAttachedSurface(p,a,b) (p)->lpVtbl->GetAttachedSurface(p,a,b) +#define IDirectDrawSurface_GetBltStatus(p,a) (p)->lpVtbl->GetBltStatus(p,a) +#define IDirectDrawSurface_GetCaps(p,b) (p)->lpVtbl->GetCaps(p,b) +#define IDirectDrawSurface_GetClipper(p,a) (p)->lpVtbl->GetClipper(p,a) +#define IDirectDrawSurface_GetColorKey(p,a,b) (p)->lpVtbl->GetColorKey(p,a,b) +#define IDirectDrawSurface_GetDC(p,a) (p)->lpVtbl->GetDC(p,a) +#define IDirectDrawSurface_GetFlipStatus(p,a) (p)->lpVtbl->GetFlipStatus(p,a) +#define IDirectDrawSurface_GetOverlayPosition(p,a,b) (p)->lpVtbl->GetOverlayPosition(p,a,b) +#define IDirectDrawSurface_GetPalette(p,a) (p)->lpVtbl->GetPalette(p,a) +#define IDirectDrawSurface_GetPixelFormat(p,a) (p)->lpVtbl->GetPixelFormat(p,a) +#define IDirectDrawSurface_GetSurfaceDesc(p,a) (p)->lpVtbl->GetSurfaceDesc(p,a) +#define IDirectDrawSurface_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectDrawSurface_IsLost(p) (p)->lpVtbl->IsLost(p) +#define IDirectDrawSurface_Lock(p,a,b,c,d) (p)->lpVtbl->Lock(p,a,b,c,d) +#define IDirectDrawSurface_ReleaseDC(p,a) (p)->lpVtbl->ReleaseDC(p,a) +#define IDirectDrawSurface_Restore(p) (p)->lpVtbl->Restore(p) +#define IDirectDrawSurface_SetClipper(p,a) (p)->lpVtbl->SetClipper(p,a) +#define IDirectDrawSurface_SetColorKey(p,a,b) (p)->lpVtbl->SetColorKey(p,a,b) +#define IDirectDrawSurface_SetOverlayPosition(p,a,b) (p)->lpVtbl->SetOverlayPosition(p,a,b) +#define IDirectDrawSurface_SetPalette(p,a) (p)->lpVtbl->SetPalette(p,a) +#define IDirectDrawSurface_Unlock(p,b) (p)->lpVtbl->Unlock(p,b) +#define IDirectDrawSurface_UpdateOverlay(p,a,b,c,d,e) (p)->lpVtbl->UpdateOverlay(p,a,b,c,d,e) +#define IDirectDrawSurface_UpdateOverlayDisplay(p,a) (p)->lpVtbl->UpdateOverlayDisplay(p,a) +#define IDirectDrawSurface_UpdateOverlayZOrder(p,a,b) (p)->lpVtbl->UpdateOverlayZOrder(p,a,b) +#else +#define IDirectDrawSurface_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectDrawSurface_AddRef(p) (p)->AddRef() +#define IDirectDrawSurface_Release(p) (p)->Release() +#define IDirectDrawSurface_AddAttachedSurface(p,a) (p)->AddAttachedSurface(a) +#define IDirectDrawSurface_AddOverlayDirtyRect(p,a) (p)->AddOverlayDirtyRect(a) +#define IDirectDrawSurface_Blt(p,a,b,c,d,e) (p)->Blt(a,b,c,d,e) +#define IDirectDrawSurface_BltBatch(p,a,b,c) (p)->BltBatch(a,b,c) +#define IDirectDrawSurface_BltFast(p,a,b,c,d,e) (p)->BltFast(a,b,c,d,e) +#define IDirectDrawSurface_DeleteAttachedSurface(p,a,b) (p)->DeleteAttachedSurface(a,b) +#define IDirectDrawSurface_EnumAttachedSurfaces(p,a,b) (p)->EnumAttachedSurfaces(a,b) +#define IDirectDrawSurface_EnumOverlayZOrders(p,a,b,c) (p)->EnumOverlayZOrders(a,b,c) +#define IDirectDrawSurface_Flip(p,a,b) (p)->Flip(a,b) +#define IDirectDrawSurface_GetAttachedSurface(p,a,b) (p)->GetAttachedSurface(a,b) +#define IDirectDrawSurface_GetBltStatus(p,a) (p)->GetBltStatus(a) +#define IDirectDrawSurface_GetCaps(p,b) (p)->GetCaps(b) +#define IDirectDrawSurface_GetClipper(p,a) (p)->GetClipper(a) +#define IDirectDrawSurface_GetColorKey(p,a,b) (p)->GetColorKey(a,b) +#define IDirectDrawSurface_GetDC(p,a) (p)->GetDC(a) +#define IDirectDrawSurface_GetFlipStatus(p,a) (p)->GetFlipStatus(a) +#define IDirectDrawSurface_GetOverlayPosition(p,a,b) (p)->GetOverlayPosition(a,b) +#define IDirectDrawSurface_GetPalette(p,a) (p)->GetPalette(a) +#define IDirectDrawSurface_GetPixelFormat(p,a) (p)->GetPixelFormat(a) +#define IDirectDrawSurface_GetSurfaceDesc(p,a) (p)->GetSurfaceDesc(a) +#define IDirectDrawSurface_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectDrawSurface_IsLost(p) (p)->IsLost() +#define IDirectDrawSurface_Lock(p,a,b,c,d) (p)->Lock(a,b,c,d) +#define IDirectDrawSurface_ReleaseDC(p,a) (p)->ReleaseDC(a) +#define IDirectDrawSurface_Restore(p) (p)->Restore() +#define IDirectDrawSurface_SetClipper(p,a) (p)->SetClipper(a) +#define IDirectDrawSurface_SetColorKey(p,a,b) (p)->SetColorKey(a,b) +#define IDirectDrawSurface_SetOverlayPosition(p,a,b) (p)->SetOverlayPosition(a,b) +#define IDirectDrawSurface_SetPalette(p,a) (p)->SetPalette(a) +#define IDirectDrawSurface_Unlock(p,b) (p)->Unlock(b) +#define IDirectDrawSurface_UpdateOverlay(p,a,b,c,d,e) (p)->UpdateOverlay(a,b,c,d,e) +#define IDirectDrawSurface_UpdateOverlayDisplay(p,a) (p)->UpdateOverlayDisplay(a) +#define IDirectDrawSurface_UpdateOverlayZOrder(p,a,b) (p)->UpdateOverlayZOrder(a,b) +#endif + +/* + * IDirectDrawSurface2 and related interfaces + */ +#undef INTERFACE +#define INTERFACE IDirectDrawSurface2 +DECLARE_INTERFACE_( IDirectDrawSurface2, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectDrawSurface methods ***/ + STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE2) PURE; + STDMETHOD(AddOverlayDirtyRect)(THIS_ LPRECT) PURE; + STDMETHOD(Blt)(THIS_ LPRECT,LPDIRECTDRAWSURFACE2, LPRECT,DWORD, LPDDBLTFX) PURE; + STDMETHOD(BltBatch)(THIS_ LPDDBLTBATCH, DWORD, DWORD ) PURE; + STDMETHOD(BltFast)(THIS_ DWORD,DWORD,LPDIRECTDRAWSURFACE2, LPRECT,DWORD) PURE; + STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD,LPDIRECTDRAWSURFACE2) PURE; + STDMETHOD(EnumAttachedSurfaces)(THIS_ LPVOID,LPDDENUMSURFACESCALLBACK) PURE; + STDMETHOD(EnumOverlayZOrders)(THIS_ DWORD,LPVOID,LPDDENUMSURFACESCALLBACK) PURE; + STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE2, DWORD) PURE; + STDMETHOD(GetAttachedSurface)(THIS_ LPDDSCAPS, LPDIRECTDRAWSURFACE2 FAR *) PURE; + STDMETHOD(GetBltStatus)(THIS_ DWORD) PURE; + STDMETHOD(GetCaps)(THIS_ LPDDSCAPS) PURE; + STDMETHOD(GetClipper)(THIS_ LPDIRECTDRAWCLIPPER FAR*) PURE; + STDMETHOD(GetColorKey)(THIS_ DWORD, LPDDCOLORKEY) PURE; + STDMETHOD(GetDC)(THIS_ HDC FAR *) PURE; + STDMETHOD(GetFlipStatus)(THIS_ DWORD) PURE; + STDMETHOD(GetOverlayPosition)(THIS_ LPLONG, LPLONG ) PURE; + STDMETHOD(GetPalette)(THIS_ LPDIRECTDRAWPALETTE FAR*) PURE; + STDMETHOD(GetPixelFormat)(THIS_ LPDDPIXELFORMAT) PURE; + STDMETHOD(GetSurfaceDesc)(THIS_ LPDDSURFACEDESC) PURE; + STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW, LPDDSURFACEDESC) PURE; + STDMETHOD(IsLost)(THIS) PURE; + STDMETHOD(Lock)(THIS_ LPRECT,LPDDSURFACEDESC,DWORD,HANDLE) PURE; + STDMETHOD(ReleaseDC)(THIS_ HDC) PURE; + STDMETHOD(Restore)(THIS) PURE; + STDMETHOD(SetClipper)(THIS_ LPDIRECTDRAWCLIPPER) PURE; + STDMETHOD(SetColorKey)(THIS_ DWORD, LPDDCOLORKEY) PURE; + STDMETHOD(SetOverlayPosition)(THIS_ LONG, LONG ) PURE; + STDMETHOD(SetPalette)(THIS_ LPDIRECTDRAWPALETTE) PURE; + STDMETHOD(Unlock)(THIS_ LPVOID) PURE; + STDMETHOD(UpdateOverlay)(THIS_ LPRECT, LPDIRECTDRAWSURFACE2,LPRECT,DWORD, LPDDOVERLAYFX) PURE; + STDMETHOD(UpdateOverlayDisplay)(THIS_ DWORD) PURE; + STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD, LPDIRECTDRAWSURFACE2) PURE; + /*** Added in the v2 interface ***/ + STDMETHOD(GetDDInterface)(THIS_ LPVOID FAR *) PURE; + STDMETHOD(PageLock)(THIS_ DWORD) PURE; + STDMETHOD(PageUnlock)(THIS_ DWORD) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectDrawSurface2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectDrawSurface2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectDrawSurface2_Release(p) (p)->lpVtbl->Release(p) +#define IDirectDrawSurface2_AddAttachedSurface(p,a) (p)->lpVtbl->AddAttachedSurface(p,a) +#define IDirectDrawSurface2_AddOverlayDirtyRect(p,a) (p)->lpVtbl->AddOverlayDirtyRect(p,a) +#define IDirectDrawSurface2_Blt(p,a,b,c,d,e) (p)->lpVtbl->Blt(p,a,b,c,d,e) +#define IDirectDrawSurface2_BltBatch(p,a,b,c) (p)->lpVtbl->BltBatch(p,a,b,c) +#define IDirectDrawSurface2_BltFast(p,a,b,c,d,e) (p)->lpVtbl->BltFast(p,a,b,c,d,e) +#define IDirectDrawSurface2_DeleteAttachedSurface(p,a,b) (p)->lpVtbl->DeleteAttachedSurface(p,a,b) +#define IDirectDrawSurface2_EnumAttachedSurfaces(p,a,b) (p)->lpVtbl->EnumAttachedSurfaces(p,a,b) +#define IDirectDrawSurface2_EnumOverlayZOrders(p,a,b,c) (p)->lpVtbl->EnumOverlayZOrders(p,a,b,c) +#define IDirectDrawSurface2_Flip(p,a,b) (p)->lpVtbl->Flip(p,a,b) +#define IDirectDrawSurface2_GetAttachedSurface(p,a,b) (p)->lpVtbl->GetAttachedSurface(p,a,b) +#define IDirectDrawSurface2_GetBltStatus(p,a) (p)->lpVtbl->GetBltStatus(p,a) +#define IDirectDrawSurface2_GetCaps(p,b) (p)->lpVtbl->GetCaps(p,b) +#define IDirectDrawSurface2_GetClipper(p,a) (p)->lpVtbl->GetClipper(p,a) +#define IDirectDrawSurface2_GetColorKey(p,a,b) (p)->lpVtbl->GetColorKey(p,a,b) +#define IDirectDrawSurface2_GetDC(p,a) (p)->lpVtbl->GetDC(p,a) +#define IDirectDrawSurface2_GetFlipStatus(p,a) (p)->lpVtbl->GetFlipStatus(p,a) +#define IDirectDrawSurface2_GetOverlayPosition(p,a,b) (p)->lpVtbl->GetOverlayPosition(p,a,b) +#define IDirectDrawSurface2_GetPalette(p,a) (p)->lpVtbl->GetPalette(p,a) +#define IDirectDrawSurface2_GetPixelFormat(p,a) (p)->lpVtbl->GetPixelFormat(p,a) +#define IDirectDrawSurface2_GetSurfaceDesc(p,a) (p)->lpVtbl->GetSurfaceDesc(p,a) +#define IDirectDrawSurface2_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectDrawSurface2_IsLost(p) (p)->lpVtbl->IsLost(p) +#define IDirectDrawSurface2_Lock(p,a,b,c,d) (p)->lpVtbl->Lock(p,a,b,c,d) +#define IDirectDrawSurface2_ReleaseDC(p,a) (p)->lpVtbl->ReleaseDC(p,a) +#define IDirectDrawSurface2_Restore(p) (p)->lpVtbl->Restore(p) +#define IDirectDrawSurface2_SetClipper(p,a) (p)->lpVtbl->SetClipper(p,a) +#define IDirectDrawSurface2_SetColorKey(p,a,b) (p)->lpVtbl->SetColorKey(p,a,b) +#define IDirectDrawSurface2_SetOverlayPosition(p,a,b) (p)->lpVtbl->SetOverlayPosition(p,a,b) +#define IDirectDrawSurface2_SetPalette(p,a) (p)->lpVtbl->SetPalette(p,a) +#define IDirectDrawSurface2_Unlock(p,b) (p)->lpVtbl->Unlock(p,b) +#define IDirectDrawSurface2_UpdateOverlay(p,a,b,c,d,e) (p)->lpVtbl->UpdateOverlay(p,a,b,c,d,e) +#define IDirectDrawSurface2_UpdateOverlayDisplay(p,a) (p)->lpVtbl->UpdateOverlayDisplay(p,a) +#define IDirectDrawSurface2_UpdateOverlayZOrder(p,a,b) (p)->lpVtbl->UpdateOverlayZOrder(p,a,b) +#define IDirectDrawSurface2_GetDDInterface(p,a) (p)->lpVtbl->GetDDInterface(p,a) +#define IDirectDrawSurface2_PageLock(p,a) (p)->lpVtbl->PageLock(p,a) +#define IDirectDrawSurface2_PageUnlock(p,a) (p)->lpVtbl->PageUnlock(p,a) +#else +#define IDirectDrawSurface2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectDrawSurface2_AddRef(p) (p)->AddRef() +#define IDirectDrawSurface2_Release(p) (p)->Release() +#define IDirectDrawSurface2_AddAttachedSurface(p,a) (p)->AddAttachedSurface(a) +#define IDirectDrawSurface2_AddOverlayDirtyRect(p,a) (p)->AddOverlayDirtyRect(a) +#define IDirectDrawSurface2_Blt(p,a,b,c,d,e) (p)->Blt(a,b,c,d,e) +#define IDirectDrawSurface2_BltBatch(p,a,b,c) (p)->BltBatch(a,b,c) +#define IDirectDrawSurface2_BltFast(p,a,b,c,d,e) (p)->BltFast(a,b,c,d,e) +#define IDirectDrawSurface2_DeleteAttachedSurface(p,a,b) (p)->DeleteAttachedSurface(a,b) +#define IDirectDrawSurface2_EnumAttachedSurfaces(p,a,b) (p)->EnumAttachedSurfaces(a,b) +#define IDirectDrawSurface2_EnumOverlayZOrders(p,a,b,c) (p)->EnumOverlayZOrders(a,b,c) +#define IDirectDrawSurface2_Flip(p,a,b) (p)->Flip(a,b) +#define IDirectDrawSurface2_GetAttachedSurface(p,a,b) (p)->GetAttachedSurface(a,b) +#define IDirectDrawSurface2_GetBltStatus(p,a) (p)->GetBltStatus(a) +#define IDirectDrawSurface2_GetCaps(p,b) (p)->GetCaps(b) +#define IDirectDrawSurface2_GetClipper(p,a) (p)->GetClipper(a) +#define IDirectDrawSurface2_GetColorKey(p,a,b) (p)->GetColorKey(a,b) +#define IDirectDrawSurface2_GetDC(p,a) (p)->GetDC(a) +#define IDirectDrawSurface2_GetFlipStatus(p,a) (p)->GetFlipStatus(a) +#define IDirectDrawSurface2_GetOverlayPosition(p,a,b) (p)->GetOverlayPosition(a,b) +#define IDirectDrawSurface2_GetPalette(p,a) (p)->GetPalette(a) +#define IDirectDrawSurface2_GetPixelFormat(p,a) (p)->GetPixelFormat(a) +#define IDirectDrawSurface2_GetSurfaceDesc(p,a) (p)->GetSurfaceDesc(a) +#define IDirectDrawSurface2_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectDrawSurface2_IsLost(p) (p)->IsLost() +#define IDirectDrawSurface2_Lock(p,a,b,c,d) (p)->Lock(a,b,c,d) +#define IDirectDrawSurface2_ReleaseDC(p,a) (p)->ReleaseDC(a) +#define IDirectDrawSurface2_Restore(p) (p)->Restore() +#define IDirectDrawSurface2_SetClipper(p,a) (p)->SetClipper(a) +#define IDirectDrawSurface2_SetColorKey(p,a,b) (p)->SetColorKey(a,b) +#define IDirectDrawSurface2_SetOverlayPosition(p,a,b) (p)->SetOverlayPosition(a,b) +#define IDirectDrawSurface2_SetPalette(p,a) (p)->SetPalette(a) +#define IDirectDrawSurface2_Unlock(p,b) (p)->Unlock(b) +#define IDirectDrawSurface2_UpdateOverlay(p,a,b,c,d,e) (p)->UpdateOverlay(a,b,c,d,e) +#define IDirectDrawSurface2_UpdateOverlayDisplay(p,a) (p)->UpdateOverlayDisplay(a) +#define IDirectDrawSurface2_UpdateOverlayZOrder(p,a,b) (p)->UpdateOverlayZOrder(a,b) +#define IDirectDrawSurface2_GetDDInterface(p,a) (p)->GetDDInterface(a) +#define IDirectDrawSurface2_PageLock(p,a) (p)->PageLock(a) +#define IDirectDrawSurface2_PageUnlock(p,a) (p)->PageUnlock(a) +#endif + +/* + * IDirectDrawSurface3 and related interfaces + */ +#undef INTERFACE +#define INTERFACE IDirectDrawSurface3 +DECLARE_INTERFACE_( IDirectDrawSurface3, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectDrawSurface methods ***/ + STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE3) PURE; + STDMETHOD(AddOverlayDirtyRect)(THIS_ LPRECT) PURE; + STDMETHOD(Blt)(THIS_ LPRECT,LPDIRECTDRAWSURFACE3, LPRECT,DWORD, LPDDBLTFX) PURE; + STDMETHOD(BltBatch)(THIS_ LPDDBLTBATCH, DWORD, DWORD ) PURE; + STDMETHOD(BltFast)(THIS_ DWORD,DWORD,LPDIRECTDRAWSURFACE3, LPRECT,DWORD) PURE; + STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD,LPDIRECTDRAWSURFACE3) PURE; + STDMETHOD(EnumAttachedSurfaces)(THIS_ LPVOID,LPDDENUMSURFACESCALLBACK) PURE; + STDMETHOD(EnumOverlayZOrders)(THIS_ DWORD,LPVOID,LPDDENUMSURFACESCALLBACK) PURE; + STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE3, DWORD) PURE; + STDMETHOD(GetAttachedSurface)(THIS_ LPDDSCAPS, LPDIRECTDRAWSURFACE3 FAR *) PURE; + STDMETHOD(GetBltStatus)(THIS_ DWORD) PURE; + STDMETHOD(GetCaps)(THIS_ LPDDSCAPS) PURE; + STDMETHOD(GetClipper)(THIS_ LPDIRECTDRAWCLIPPER FAR*) PURE; + STDMETHOD(GetColorKey)(THIS_ DWORD, LPDDCOLORKEY) PURE; + STDMETHOD(GetDC)(THIS_ HDC FAR *) PURE; + STDMETHOD(GetFlipStatus)(THIS_ DWORD) PURE; + STDMETHOD(GetOverlayPosition)(THIS_ LPLONG, LPLONG ) PURE; + STDMETHOD(GetPalette)(THIS_ LPDIRECTDRAWPALETTE FAR*) PURE; + STDMETHOD(GetPixelFormat)(THIS_ LPDDPIXELFORMAT) PURE; + STDMETHOD(GetSurfaceDesc)(THIS_ LPDDSURFACEDESC) PURE; + STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW, LPDDSURFACEDESC) PURE; + STDMETHOD(IsLost)(THIS) PURE; + STDMETHOD(Lock)(THIS_ LPRECT,LPDDSURFACEDESC,DWORD,HANDLE) PURE; + STDMETHOD(ReleaseDC)(THIS_ HDC) PURE; + STDMETHOD(Restore)(THIS) PURE; + STDMETHOD(SetClipper)(THIS_ LPDIRECTDRAWCLIPPER) PURE; + STDMETHOD(SetColorKey)(THIS_ DWORD, LPDDCOLORKEY) PURE; + STDMETHOD(SetOverlayPosition)(THIS_ LONG, LONG ) PURE; + STDMETHOD(SetPalette)(THIS_ LPDIRECTDRAWPALETTE) PURE; + STDMETHOD(Unlock)(THIS_ LPVOID) PURE; + STDMETHOD(UpdateOverlay)(THIS_ LPRECT, LPDIRECTDRAWSURFACE3,LPRECT,DWORD, LPDDOVERLAYFX) PURE; + STDMETHOD(UpdateOverlayDisplay)(THIS_ DWORD) PURE; + STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD, LPDIRECTDRAWSURFACE3) PURE; + /*** Added in the v2 interface ***/ + STDMETHOD(GetDDInterface)(THIS_ LPVOID FAR *) PURE; + STDMETHOD(PageLock)(THIS_ DWORD) PURE; + STDMETHOD(PageUnlock)(THIS_ DWORD) PURE; + /*** Added in the V3 interface ***/ + STDMETHOD(SetSurfaceDesc)(THIS_ LPDDSURFACEDESC, DWORD) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectDrawSurface3_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectDrawSurface3_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectDrawSurface3_Release(p) (p)->lpVtbl->Release(p) +#define IDirectDrawSurface3_AddAttachedSurface(p,a) (p)->lpVtbl->AddAttachedSurface(p,a) +#define IDirectDrawSurface3_AddOverlayDirtyRect(p,a) (p)->lpVtbl->AddOverlayDirtyRect(p,a) +#define IDirectDrawSurface3_Blt(p,a,b,c,d,e) (p)->lpVtbl->Blt(p,a,b,c,d,e) +#define IDirectDrawSurface3_BltBatch(p,a,b,c) (p)->lpVtbl->BltBatch(p,a,b,c) +#define IDirectDrawSurface3_BltFast(p,a,b,c,d,e) (p)->lpVtbl->BltFast(p,a,b,c,d,e) +#define IDirectDrawSurface3_DeleteAttachedSurface(p,a,b) (p)->lpVtbl->DeleteAttachedSurface(p,a,b) +#define IDirectDrawSurface3_EnumAttachedSurfaces(p,a,b) (p)->lpVtbl->EnumAttachedSurfaces(p,a,b) +#define IDirectDrawSurface3_EnumOverlayZOrders(p,a,b,c) (p)->lpVtbl->EnumOverlayZOrders(p,a,b,c) +#define IDirectDrawSurface3_Flip(p,a,b) (p)->lpVtbl->Flip(p,a,b) +#define IDirectDrawSurface3_GetAttachedSurface(p,a,b) (p)->lpVtbl->GetAttachedSurface(p,a,b) +#define IDirectDrawSurface3_GetBltStatus(p,a) (p)->lpVtbl->GetBltStatus(p,a) +#define IDirectDrawSurface3_GetCaps(p,b) (p)->lpVtbl->GetCaps(p,b) +#define IDirectDrawSurface3_GetClipper(p,a) (p)->lpVtbl->GetClipper(p,a) +#define IDirectDrawSurface3_GetColorKey(p,a,b) (p)->lpVtbl->GetColorKey(p,a,b) +#define IDirectDrawSurface3_GetDC(p,a) (p)->lpVtbl->GetDC(p,a) +#define IDirectDrawSurface3_GetFlipStatus(p,a) (p)->lpVtbl->GetFlipStatus(p,a) +#define IDirectDrawSurface3_GetOverlayPosition(p,a,b) (p)->lpVtbl->GetOverlayPosition(p,a,b) +#define IDirectDrawSurface3_GetPalette(p,a) (p)->lpVtbl->GetPalette(p,a) +#define IDirectDrawSurface3_GetPixelFormat(p,a) (p)->lpVtbl->GetPixelFormat(p,a) +#define IDirectDrawSurface3_GetSurfaceDesc(p,a) (p)->lpVtbl->GetSurfaceDesc(p,a) +#define IDirectDrawSurface3_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectDrawSurface3_IsLost(p) (p)->lpVtbl->IsLost(p) +#define IDirectDrawSurface3_Lock(p,a,b,c,d) (p)->lpVtbl->Lock(p,a,b,c,d) +#define IDirectDrawSurface3_ReleaseDC(p,a) (p)->lpVtbl->ReleaseDC(p,a) +#define IDirectDrawSurface3_Restore(p) (p)->lpVtbl->Restore(p) +#define IDirectDrawSurface3_SetClipper(p,a) (p)->lpVtbl->SetClipper(p,a) +#define IDirectDrawSurface3_SetColorKey(p,a,b) (p)->lpVtbl->SetColorKey(p,a,b) +#define IDirectDrawSurface3_SetOverlayPosition(p,a,b) (p)->lpVtbl->SetOverlayPosition(p,a,b) +#define IDirectDrawSurface3_SetPalette(p,a) (p)->lpVtbl->SetPalette(p,a) +#define IDirectDrawSurface3_Unlock(p,b) (p)->lpVtbl->Unlock(p,b) +#define IDirectDrawSurface3_UpdateOverlay(p,a,b,c,d,e) (p)->lpVtbl->UpdateOverlay(p,a,b,c,d,e) +#define IDirectDrawSurface3_UpdateOverlayDisplay(p,a) (p)->lpVtbl->UpdateOverlayDisplay(p,a) +#define IDirectDrawSurface3_UpdateOverlayZOrder(p,a,b) (p)->lpVtbl->UpdateOverlayZOrder(p,a,b) +#define IDirectDrawSurface3_GetDDInterface(p,a) (p)->lpVtbl->GetDDInterface(p,a) +#define IDirectDrawSurface3_PageLock(p,a) (p)->lpVtbl->PageLock(p,a) +#define IDirectDrawSurface3_PageUnlock(p,a) (p)->lpVtbl->PageUnlock(p,a) +#define IDirectDrawSurface3_SetSurfaceDesc(p,a,b) (p)->lpVtbl->SetSurfaceDesc(p,a,b) +#else +#define IDirectDrawSurface3_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectDrawSurface3_AddRef(p) (p)->AddRef() +#define IDirectDrawSurface3_Release(p) (p)->Release() +#define IDirectDrawSurface3_AddAttachedSurface(p,a) (p)->AddAttachedSurface(a) +#define IDirectDrawSurface3_AddOverlayDirtyRect(p,a) (p)->AddOverlayDirtyRect(a) +#define IDirectDrawSurface3_Blt(p,a,b,c,d,e) (p)->Blt(a,b,c,d,e) +#define IDirectDrawSurface3_BltBatch(p,a,b,c) (p)->BltBatch(a,b,c) +#define IDirectDrawSurface3_BltFast(p,a,b,c,d,e) (p)->BltFast(a,b,c,d,e) +#define IDirectDrawSurface3_DeleteAttachedSurface(p,a,b) (p)->DeleteAttachedSurface(a,b) +#define IDirectDrawSurface3_EnumAttachedSurfaces(p,a,b) (p)->EnumAttachedSurfaces(a,b) +#define IDirectDrawSurface3_EnumOverlayZOrders(p,a,b,c) (p)->EnumOverlayZOrders(a,b,c) +#define IDirectDrawSurface3_Flip(p,a,b) (p)->Flip(a,b) +#define IDirectDrawSurface3_GetAttachedSurface(p,a,b) (p)->GetAttachedSurface(a,b) +#define IDirectDrawSurface3_GetBltStatus(p,a) (p)->GetBltStatus(a) +#define IDirectDrawSurface3_GetCaps(p,b) (p)->GetCaps(b) +#define IDirectDrawSurface3_GetClipper(p,a) (p)->GetClipper(a) +#define IDirectDrawSurface3_GetColorKey(p,a,b) (p)->GetColorKey(a,b) +#define IDirectDrawSurface3_GetDC(p,a) (p)->GetDC(a) +#define IDirectDrawSurface3_GetFlipStatus(p,a) (p)->GetFlipStatus(a) +#define IDirectDrawSurface3_GetOverlayPosition(p,a,b) (p)->GetOverlayPosition(a,b) +#define IDirectDrawSurface3_GetPalette(p,a) (p)->GetPalette(a) +#define IDirectDrawSurface3_GetPixelFormat(p,a) (p)->GetPixelFormat(a) +#define IDirectDrawSurface3_GetSurfaceDesc(p,a) (p)->GetSurfaceDesc(a) +#define IDirectDrawSurface3_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectDrawSurface3_IsLost(p) (p)->IsLost() +#define IDirectDrawSurface3_Lock(p,a,b,c,d) (p)->Lock(a,b,c,d) +#define IDirectDrawSurface3_ReleaseDC(p,a) (p)->ReleaseDC(a) +#define IDirectDrawSurface3_Restore(p) (p)->Restore() +#define IDirectDrawSurface3_SetClipper(p,a) (p)->SetClipper(a) +#define IDirectDrawSurface3_SetColorKey(p,a,b) (p)->SetColorKey(a,b) +#define IDirectDrawSurface3_SetOverlayPosition(p,a,b) (p)->SetOverlayPosition(a,b) +#define IDirectDrawSurface3_SetPalette(p,a) (p)->SetPalette(a) +#define IDirectDrawSurface3_Unlock(p,b) (p)->Unlock(b) +#define IDirectDrawSurface3_UpdateOverlay(p,a,b,c,d,e) (p)->UpdateOverlay(a,b,c,d,e) +#define IDirectDrawSurface3_UpdateOverlayDisplay(p,a) (p)->UpdateOverlayDisplay(a) +#define IDirectDrawSurface3_UpdateOverlayZOrder(p,a,b) (p)->UpdateOverlayZOrder(a,b) +#define IDirectDrawSurface3_GetDDInterface(p,a) (p)->GetDDInterface(a) +#define IDirectDrawSurface3_PageLock(p,a) (p)->PageLock(a) +#define IDirectDrawSurface3_PageUnlock(p,a) (p)->PageUnlock(a) +#define IDirectDrawSurface3_SetSurfaceDesc(p,a,b) (p)->SetSurfaceDesc(a,b) +#endif + +/* + * IDirectDrawColorControl + */ +#if defined( _WIN32 ) && !defined( _NO_COM ) +#undef INTERFACE +#define INTERFACE IDirectDrawColorControl +DECLARE_INTERFACE_( IDirectDrawColorControl, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectDrawColorControl methods ***/ + STDMETHOD(GetColorControls)(THIS_ LPDDCOLORCONTROL) PURE; + STDMETHOD(SetColorControls)(THIS_ LPDDCOLORCONTROL) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectDrawColorControl_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IDirectDrawColorControl_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectDrawColorControl_Release(p) (p)->lpVtbl->Release(p) +#define IDirectDrawColorControl_GetColorControls(p, a) (p)->lpVtbl->GetColorControls(p, a) +#define IDirectDrawColorControl_SetColorControls(p, a) (p)->lpVtbl->SetColorControls(p, a) +#else +#define IDirectDrawColorControl_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IDirectDrawColorControl_AddRef(p) (p)->AddRef() +#define IDirectDrawColorControl_Release(p) (p)->Release() +#define IDirectDrawColorControl_GetColorControls(p, a) (p)->GetColorControls(a) +#define IDirectDrawColorControl_SetColorControls(p, a) (p)->SetColorControls(a) +#endif + +#endif + + + +#endif + + +/* + * DDSURFACEDESC + */ +typedef struct _DDSURFACEDESC +{ + DWORD dwSize; // size of the DDSURFACEDESC structure + DWORD dwFlags; // determines what fields are valid + DWORD dwHeight; // height of surface to be created + DWORD dwWidth; // width of input surface + union + { + LONG lPitch; // distance to start of next line (return value only) + DWORD dwLinearSize; // Formless late-allocated optimized surface size + }; + DWORD dwBackBufferCount; // number of back buffers requested + union + { + DWORD dwMipMapCount; // number of mip-map levels requested + DWORD dwZBufferBitDepth; // depth of Z buffer requested + DWORD dwRefreshRate; // refresh rate (used when display mode is described) + }; + DWORD dwAlphaBitDepth; // depth of alpha buffer requested + DWORD dwReserved; // reserved + LPVOID lpSurface; // pointer to the associated surface memory + DDCOLORKEY ddckCKDestOverlay; // color key for destination overlay use + DDCOLORKEY ddckCKDestBlt; // color key for destination blt use + DDCOLORKEY ddckCKSrcOverlay; // color key for source overlay use + DDCOLORKEY ddckCKSrcBlt; // color key for source blt use + DDPIXELFORMAT ddpfPixelFormat; // pixel format description of the surface + DDSCAPS ddsCaps; // direct draw surface capabilities +} DDSURFACEDESC; + +/* + * ddsCaps field is valid. + */ +#define DDSD_CAPS 0x00000001l // default + +/* + * dwHeight field is valid. + */ +#define DDSD_HEIGHT 0x00000002l + +/* + * dwWidth field is valid. + */ +#define DDSD_WIDTH 0x00000004l + +/* + * lPitch is valid. + */ +#define DDSD_PITCH 0x00000008l + +/* + * dwBackBufferCount is valid. + */ +#define DDSD_BACKBUFFERCOUNT 0x00000020l + +/* + * dwZBufferBitDepth is valid. + */ +#define DDSD_ZBUFFERBITDEPTH 0x00000040l + +/* + * dwAlphaBitDepth is valid. + */ +#define DDSD_ALPHABITDEPTH 0x00000080l + + +/* + * lpSurface is valid. + */ +#define DDSD_LPSURFACE 0x00000800l + +/* + * ddpfPixelFormat is valid. + */ +#define DDSD_PIXELFORMAT 0x00001000l + +/* + * ddckCKDestOverlay is valid. + */ +#define DDSD_CKDESTOVERLAY 0x00002000l + +/* + * ddckCKDestBlt is valid. + */ +#define DDSD_CKDESTBLT 0x00004000l + +/* + * ddckCKSrcOverlay is valid. + */ +#define DDSD_CKSRCOVERLAY 0x00008000l + +/* + * ddckCKSrcBlt is valid. + */ +#define DDSD_CKSRCBLT 0x00010000l + +/* + * dwMipMapCount is valid. + */ +#define DDSD_MIPMAPCOUNT 0x00020000l + + /* + * dwRefreshRate is valid + */ +#define DDSD_REFRESHRATE 0x00040000l + +/* + * dwLinearSize is valid + */ +#define DDSD_LINEARSIZE 0x00080000l + +/* + * All input fields are valid. + */ +#define DDSD_ALL 0x000ff9eel + + +/* + * DDCOLORCONTROL + */ +typedef struct _DDCOLORCONTROL +{ + DWORD dwSize; + DWORD dwFlags; + LONG lBrightness; + LONG lContrast; + LONG lHue; + LONG lSaturation; + LONG lSharpness; + LONG lGamma; + LONG lColorEnable; + DWORD dwReserved1; +} DDCOLORCONTROL; + + +/* + * lBrightness field is valid. + */ +#define DDCOLOR_BRIGHTNESS 0x00000001l + +/* + * lContrast field is valid. + */ +#define DDCOLOR_CONTRAST 0x00000002l + +/* + * lHue field is valid. + */ +#define DDCOLOR_HUE 0x00000004l + +/* + * lSaturation field is valid. + */ +#define DDCOLOR_SATURATION 0x00000008l + +/* + * lSharpness field is valid. + */ +#define DDCOLOR_SHARPNESS 0x00000010l + +/* + * lGamma field is valid. + */ +#define DDCOLOR_GAMMA 0x00000020l + +/* + * lColorEnable field is valid. + */ +#define DDCOLOR_COLORENABLE 0x00000040l + + + +/*============================================================================ + * + * Direct Draw Capability Flags + * + * These flags are used to describe the capabilities of a given Surface. + * All flags are bit flags. + * + *==========================================================================*/ + +/**************************************************************************** + * + * DIRECTDRAWSURFACE CAPABILITY FLAGS + * + ****************************************************************************/ + +/* + * This bit is reserved. It should not be specified. + */ +#define DDSCAPS_RESERVED1 0x00000001l + +/* + * Indicates that this surface contains alpha-only information. + * (To determine if a surface is RGBA/YUVA, the pixel format must be + * interrogated.) + */ +#define DDSCAPS_ALPHA 0x00000002l + +/* + * Indicates that this surface is a backbuffer. It is generally + * set by CreateSurface when the DDSCAPS_FLIP capability bit is set. + * It indicates that this surface is THE back buffer of a surface + * flipping structure. DirectDraw supports N surfaces in a + * surface flipping structure. Only the surface that immediately + * precedeces the DDSCAPS_FRONTBUFFER has this capability bit set. + * The other surfaces are identified as back buffers by the presence + * of the DDSCAPS_FLIP capability, their attachment order, and the + * absence of the DDSCAPS_FRONTBUFFER and DDSCAPS_BACKBUFFER + * capabilities. The bit is sent to CreateSurface when a standalone + * back buffer is being created. This surface could be attached to + * a front buffer and/or back buffers to form a flipping surface + * structure after the CreateSurface call. See AddAttachments for + * a detailed description of the behaviors in this case. + */ +#define DDSCAPS_BACKBUFFER 0x00000004l + +/* + * Indicates a complex surface structure is being described. A + * complex surface structure results in the creation of more than + * one surface. The additional surfaces are attached to the root + * surface. The complex structure can only be destroyed by + * destroying the root. + */ +#define DDSCAPS_COMPLEX 0x00000008l + +/* + * Indicates that this surface is a part of a surface flipping structure. + * When it is passed to CreateSurface the DDSCAPS_FRONTBUFFER and + * DDSCAP_BACKBUFFER bits are not set. They are set by CreateSurface + * on the resulting creations. The dwBackBufferCount field in the + * DDSURFACEDESC structure must be set to at least 1 in order for + * the CreateSurface call to succeed. The DDSCAPS_COMPLEX capability + * must always be set with creating multiple surfaces through CreateSurface. + */ +#define DDSCAPS_FLIP 0x00000010l + +/* + * Indicates that this surface is THE front buffer of a surface flipping + * structure. It is generally set by CreateSurface when the DDSCAPS_FLIP + * capability bit is set. + * If this capability is sent to CreateSurface then a standalonw front buffer + * is created. This surface will not have the DDSCAPS_FLIP capability. + * It can be attached to other back buffers to form a flipping structure. + * See AddAttachments for a detailed description of the behaviors in this + * case. + */ +#define DDSCAPS_FRONTBUFFER 0x00000020l + +/* + * Indicates that this surface is any offscreen surface that is not an overlay, + * texture, zbuffer, front buffer, back buffer, or alpha surface. It is used + * to identify plain vanilla surfaces. + */ +#define DDSCAPS_OFFSCREENPLAIN 0x00000040l + +/* + * Indicates that this surface is an overlay. It may or may not be directly visible + * depending on whether or not it is currently being overlayed onto the primary + * surface. DDSCAPS_VISIBLE can be used to determine whether or not it is being + * overlayed at the moment. + */ +#define DDSCAPS_OVERLAY 0x00000080l + +/* + * Indicates that unique DirectDrawPalette objects can be created and + * attached to this surface. + */ +#define DDSCAPS_PALETTE 0x00000100l + +/* + * Indicates that this surface is the primary surface. The primary + * surface represents what the user is seeing at the moment. + */ +#define DDSCAPS_PRIMARYSURFACE 0x00000200l + +/* + * Indicates that this surface is the primary surface for the left eye. + * The primary surface for the left eye represents what the user is seeing + * at the moment with the users left eye. When this surface is created the + * DDSCAPS_PRIMARYSURFACE represents what the user is seeing with the users + * right eye. + */ +#define DDSCAPS_PRIMARYSURFACELEFT 0x00000400l + +/* + * Indicates that this surface memory was allocated in system memory + */ +#define DDSCAPS_SYSTEMMEMORY 0x00000800l + +/* + * Indicates that this surface can be used as a 3D texture. It does not + * indicate whether or not the surface is being used for that purpose. + */ +#define DDSCAPS_TEXTURE 0x00001000l + +/* + * Indicates that a surface may be a destination for 3D rendering. This + * bit must be set in order to query for a Direct3D Device Interface + * from this surface. + */ +#define DDSCAPS_3DDEVICE 0x00002000l + +/* + * Indicates that this surface exists in video memory. + */ +#define DDSCAPS_VIDEOMEMORY 0x00004000l + +/* + * Indicates that changes made to this surface are immediately visible. + * It is always set for the primary surface and is set for overlays while + * they are being overlayed and texture maps while they are being textured. + */ +#define DDSCAPS_VISIBLE 0x00008000l + +/* + * Indicates that only writes are permitted to the surface. Read accesses + * from the surface may or may not generate a protection fault, but the + * results of a read from this surface will not be meaningful. READ ONLY. + */ +#define DDSCAPS_WRITEONLY 0x00010000l + +/* + * Indicates that this surface is a z buffer. A z buffer does not contain + * displayable information. Instead it contains bit depth information that is + * used to determine which pixels are visible and which are obscured. + */ +#define DDSCAPS_ZBUFFER 0x00020000l + +/* + * Indicates surface will have a DC associated long term + */ +#define DDSCAPS_OWNDC 0x00040000l + +/* + * Indicates surface should be able to receive live video + */ +#define DDSCAPS_LIVEVIDEO 0x00080000l + +/* + * Indicates surface should be able to have a stream decompressed + * to it by the hardware. + */ +#define DDSCAPS_HWCODEC 0x00100000l + +/* + * Surface is a ModeX surface. + * + */ +#define DDSCAPS_MODEX 0x00200000l + +/* + * Indicates surface is one level of a mip-map. This surface will + * be attached to other DDSCAPS_MIPMAP surfaces to form the mip-map. + * This can be done explicitly, by creating a number of surfaces and + * attaching them with AddAttachedSurface or by implicitly by CreateSurface. + * If this bit is set then DDSCAPS_TEXTURE must also be set. + */ +#define DDSCAPS_MIPMAP 0x00400000l + +/* + * This bit is reserved. It should not be specified. + */ +#define DDSCAPS_RESERVED2 0x00800000l + + +/* + * Indicates that memory for the surface is not allocated until the surface + * is loaded (via the Direct3D texture Load() function). + */ +#define DDSCAPS_ALLOCONLOAD 0x04000000l + +/* + * Indicates that the surface will recieve data from a video port. + */ +#define DDSCAPS_VIDEOPORT 0x08000000l + +/* + * Indicates that a video memory surface is resident in true, local video + * memory rather than non-local video memory. If this flag is specified then + * so must DDSCAPS_VIDEOMEMORY. This flag is mutually exclusive with + * DDSCAPS_NONLOCALVIDMEM. + */ +#define DDSCAPS_LOCALVIDMEM 0x10000000l + +/* + * Indicates that a video memory surface is resident in non-local video + * memory rather than true, local video memory. If this flag is specified + * then so must DDSCAPS_VIDEOMEMORY. This flag is mutually exclusive with + * DDSCAPS_LOCALVIDMEM. + */ +#define DDSCAPS_NONLOCALVIDMEM 0x20000000l + +/* + * Indicates that this surface is a standard VGA mode surface, and not a + * ModeX surface. (This flag will never be set in combination with the + * DDSCAPS_MODEX flag). + */ +#define DDSCAPS_STANDARDVGAMODE 0x40000000l + +/* + * Indicates that this surface will be an optimized surface. This flag is + * currently only valid in conjunction with the DDSCAPS_TEXTURE flag. The surface + * will be created without any underlying video memory until loaded. + */ +#define DDSCAPS_OPTIMIZED 0x80000000l + + + + /**************************************************************************** + * + * DIRECTDRAW DRIVER CAPABILITY FLAGS + * + ****************************************************************************/ + +/* + * Display hardware has 3D acceleration. + */ +#define DDCAPS_3D 0x00000001l + +/* + * Indicates that DirectDraw will support only dest rectangles that are aligned + * on DIRECTDRAWCAPS.dwAlignBoundaryDest boundaries of the surface, respectively. + * READ ONLY. + */ +#define DDCAPS_ALIGNBOUNDARYDEST 0x00000002l + +/* + * Indicates that DirectDraw will support only source rectangles whose sizes in + * BYTEs are DIRECTDRAWCAPS.dwAlignSizeDest multiples, respectively. READ ONLY. + */ +#define DDCAPS_ALIGNSIZEDEST 0x00000004l +/* + * Indicates that DirectDraw will support only source rectangles that are aligned + * on DIRECTDRAWCAPS.dwAlignBoundarySrc boundaries of the surface, respectively. + * READ ONLY. + */ +#define DDCAPS_ALIGNBOUNDARYSRC 0x00000008l + +/* + * Indicates that DirectDraw will support only source rectangles whose sizes in + * BYTEs are DIRECTDRAWCAPS.dwAlignSizeSrc multiples, respectively. READ ONLY. + */ +#define DDCAPS_ALIGNSIZESRC 0x00000010l + +/* + * Indicates that DirectDraw will create video memory surfaces that have a stride + * alignment equal to DIRECTDRAWCAPS.dwAlignStride. READ ONLY. + */ +#define DDCAPS_ALIGNSTRIDE 0x00000020l + +/* + * Display hardware is capable of blt operations. + */ +#define DDCAPS_BLT 0x00000040l + +/* + * Display hardware is capable of asynchronous blt operations. + */ +#define DDCAPS_BLTQUEUE 0x00000080l + +/* + * Display hardware is capable of color space conversions during the blt operation. + */ +#define DDCAPS_BLTFOURCC 0x00000100l + +/* + * Display hardware is capable of stretching during blt operations. + */ +#define DDCAPS_BLTSTRETCH 0x00000200l + +/* + * Display hardware is shared with GDI. + */ +#define DDCAPS_GDI 0x00000400l + +/* + * Display hardware can overlay. + */ +#define DDCAPS_OVERLAY 0x00000800l + +/* + * Set if display hardware supports overlays but can not clip them. + */ +#define DDCAPS_OVERLAYCANTCLIP 0x00001000l + +/* + * Indicates that overlay hardware is capable of color space conversions during + * the overlay operation. + */ +#define DDCAPS_OVERLAYFOURCC 0x00002000l + +/* + * Indicates that stretching can be done by the overlay hardware. + */ +#define DDCAPS_OVERLAYSTRETCH 0x00004000l + +/* + * Indicates that unique DirectDrawPalettes can be created for DirectDrawSurfaces + * other than the primary surface. + */ +#define DDCAPS_PALETTE 0x00008000l + +/* + * Indicates that palette changes can be syncd with the veritcal refresh. + */ +#define DDCAPS_PALETTEVSYNC 0x00010000l + +/* + * Display hardware can return the current scan line. + */ +#define DDCAPS_READSCANLINE 0x00020000l + +/* + * Display hardware has stereo vision capabilities. DDSCAPS_PRIMARYSURFACELEFT + * can be created. + */ +#define DDCAPS_STEREOVIEW 0x00040000l + +/* + * Display hardware is capable of generating a vertical blank interrupt. + */ +#define DDCAPS_VBI 0x00080000l + +/* + * Supports the use of z buffers with blt operations. + */ +#define DDCAPS_ZBLTS 0x00100000l + +/* + * Supports Z Ordering of overlays. + */ +#define DDCAPS_ZOVERLAYS 0x00200000l + +/* + * Supports color key + */ +#define DDCAPS_COLORKEY 0x00400000l + +/* + * Supports alpha surfaces + */ +#define DDCAPS_ALPHA 0x00800000l + +/* + * colorkey is hardware assisted(DDCAPS_COLORKEY will also be set) + */ +#define DDCAPS_COLORKEYHWASSIST 0x01000000l + +/* + * no hardware support at all + */ +#define DDCAPS_NOHARDWARE 0x02000000l + +/* + * Display hardware is capable of color fill with bltter + */ +#define DDCAPS_BLTCOLORFILL 0x04000000l + +/* + * Display hardware is bank switched, and potentially very slow at + * random access to VRAM. + */ +#define DDCAPS_BANKSWITCHED 0x08000000l + +/* + * Display hardware is capable of depth filling Z-buffers with bltter + */ +#define DDCAPS_BLTDEPTHFILL 0x10000000l + +/* + * Display hardware is capable of clipping while bltting. + */ +#define DDCAPS_CANCLIP 0x20000000l + +/* + * Display hardware is capable of clipping while stretch bltting. + */ +#define DDCAPS_CANCLIPSTRETCHED 0x40000000l + +/* + * Display hardware is capable of bltting to or from system memory + */ +#define DDCAPS_CANBLTSYSMEM 0x80000000l + + + /**************************************************************************** + * + * MORE DIRECTDRAW DRIVER CAPABILITY FLAGS (dwCaps2) + * + ****************************************************************************/ + +/* + * Display hardware is certified + */ +#define DDCAPS2_CERTIFIED 0x00000001l + +/* + * Driver cannot interleave 2D operations (lock and blt) to surfaces with + * Direct3D rendering operations between calls to BeginScene() and EndScene() + */ +#define DDCAPS2_NO2DDURING3DSCENE 0x00000002l + +/* + * Display hardware contains a video port + */ +#define DDCAPS2_VIDEOPORT 0x00000004l + +/* + * The overlay can be automatically flipped according to the video port + * VSYNCs, providing automatic doubled buffered display of video port + * data using an overlay + */ +#define DDCAPS2_AUTOFLIPOVERLAY 0x00000008l + +/* + * Overlay can display each field of interlaced data individually while + * it is interleaved in memory without causing jittery artifacts. + */ +#define DDCAPS2_CANBOBINTERLEAVED 0x00000010l + +/* + * Overlay can display each field of interlaced data individually while + * it is not interleaved in memory without causing jittery artifacts. + */ +#define DDCAPS2_CANBOBNONINTERLEAVED 0x00000020l + +/* + * The overlay surface contains color controls (brightness, sharpness, etc.) + */ +#define DDCAPS2_COLORCONTROLOVERLAY 0x00000040l + +/* + * The primary surface contains color controls (gamma, etc.) + */ +#define DDCAPS2_COLORCONTROLPRIMARY 0x00000080l + +/* + * RGBZ -> RGB supported for 16:16 RGB:Z + */ +#define DDCAPS2_CANDROPZ16BIT 0x00000100l + +/* + * Driver supports non-local video memory. + */ +#define DDCAPS2_NONLOCALVIDMEM 0x00000200l + +/* + * Dirver supports non-local video memory but has different capabilities for + * non-local video memory surfaces. If this bit is set then so must + * DDCAPS2_NONLOCALVIDMEM. + */ +#define DDCAPS2_NONLOCALVIDMEMCAPS 0x00000400l + +/* + * Driver neither requires nor prefers surfaces to be pagelocked when performing + * blts involving system memory surfaces + */ +#define DDCAPS2_NOPAGELOCKREQUIRED 0x00000800l + +/* + * Driver can create surfaces which are wider than the primary surface + */ +#define DDCAPS2_WIDESURFACES 0x00001000l + +/* + * Driver supports bob using software without using a video port + */ +#define DDCAPS2_CANFLIPODDEVEN 0x00002000l + +/**************************************************************************** + * + * DIRECTDRAW FX ALPHA CAPABILITY FLAGS + * + ****************************************************************************/ + +/* + * Supports alpha blending around the edge of a source color keyed surface. + * For Blt. + */ +#define DDFXALPHACAPS_BLTALPHAEDGEBLEND 0x00000001l + +/* + * Supports alpha information in the pixel format. The bit depth of alpha + * information in the pixel format can be 1,2,4, or 8. The alpha value becomes + * more opaque as the alpha value increases. (0 is transparent.) + * For Blt. + */ +#define DDFXALPHACAPS_BLTALPHAPIXELS 0x00000002l + +/* + * Supports alpha information in the pixel format. The bit depth of alpha + * information in the pixel format can be 1,2,4, or 8. The alpha value + * becomes more transparent as the alpha value increases. (0 is opaque.) + * This flag can only be set if DDCAPS_ALPHA is set. + * For Blt. + */ +#define DDFXALPHACAPS_BLTALPHAPIXELSNEG 0x00000004l + +/* + * Supports alpha only surfaces. The bit depth of an alpha only surface can be + * 1,2,4, or 8. The alpha value becomes more opaque as the alpha value increases. + * (0 is transparent.) + * For Blt. + */ +#define DDFXALPHACAPS_BLTALPHASURFACES 0x00000008l + +/* + * The depth of the alpha channel data can range can be 1,2,4, or 8. + * The NEG suffix indicates that this alpha channel becomes more transparent + * as the alpha value increases. (0 is opaque.) This flag can only be set if + * DDCAPS_ALPHA is set. + * For Blt. + */ +#define DDFXALPHACAPS_BLTALPHASURFACESNEG 0x00000010l + +/* + * Supports alpha blending around the edge of a source color keyed surface. + * For Overlays. + */ +#define DDFXALPHACAPS_OVERLAYALPHAEDGEBLEND 0x00000020l + +/* + * Supports alpha information in the pixel format. The bit depth of alpha + * information in the pixel format can be 1,2,4, or 8. The alpha value becomes + * more opaque as the alpha value increases. (0 is transparent.) + * For Overlays. + */ +#define DDFXALPHACAPS_OVERLAYALPHAPIXELS 0x00000040l + +/* + * Supports alpha information in the pixel format. The bit depth of alpha + * information in the pixel format can be 1,2,4, or 8. The alpha value + * becomes more transparent as the alpha value increases. (0 is opaque.) + * This flag can only be set if DDCAPS_ALPHA is set. + * For Overlays. + */ +#define DDFXALPHACAPS_OVERLAYALPHAPIXELSNEG 0x00000080l + +/* + * Supports alpha only surfaces. The bit depth of an alpha only surface can be + * 1,2,4, or 8. The alpha value becomes more opaque as the alpha value increases. + * (0 is transparent.) + * For Overlays. + */ +#define DDFXALPHACAPS_OVERLAYALPHASURFACES 0x00000100l + +/* + * The depth of the alpha channel data can range can be 1,2,4, or 8. + * The NEG suffix indicates that this alpha channel becomes more transparent + * as the alpha value increases. (0 is opaque.) This flag can only be set if + * DDCAPS_ALPHA is set. + * For Overlays. + */ +#define DDFXALPHACAPS_OVERLAYALPHASURFACESNEG 0x00000200l + +/**************************************************************************** + * + * DIRECTDRAW FX CAPABILITY FLAGS + * + ****************************************************************************/ + +/* + * Uses arithmetic operations to stretch and shrink surfaces during blt + * rather than pixel doubling techniques. Along the Y axis. + */ +#define DDFXCAPS_BLTARITHSTRETCHY 0x00000020l + +/* + * Uses arithmetic operations to stretch during blt + * rather than pixel doubling techniques. Along the Y axis. Only + * works for x1, x2, etc. + */ +#define DDFXCAPS_BLTARITHSTRETCHYN 0x00000010l + +/* + * Supports mirroring left to right in blt. + */ +#define DDFXCAPS_BLTMIRRORLEFTRIGHT 0x00000040l + +/* + * Supports mirroring top to bottom in blt. + */ +#define DDFXCAPS_BLTMIRRORUPDOWN 0x00000080l + +/* + * Supports arbitrary rotation for blts. + */ +#define DDFXCAPS_BLTROTATION 0x00000100l + +/* + * Supports 90 degree rotations for blts. + */ +#define DDFXCAPS_BLTROTATION90 0x00000200l + +/* + * DirectDraw supports arbitrary shrinking of a surface along the + * x axis (horizontal direction) for blts. + */ +#define DDFXCAPS_BLTSHRINKX 0x00000400l + +/* + * DirectDraw supports integer shrinking (1x,2x,) of a surface + * along the x axis (horizontal direction) for blts. + */ +#define DDFXCAPS_BLTSHRINKXN 0x00000800l + +/* + * DirectDraw supports arbitrary shrinking of a surface along the + * y axis (horizontal direction) for blts. + */ +#define DDFXCAPS_BLTSHRINKY 0x00001000l + +/* + * DirectDraw supports integer shrinking (1x,2x,) of a surface + * along the y axis (vertical direction) for blts. + */ +#define DDFXCAPS_BLTSHRINKYN 0x00002000l + +/* + * DirectDraw supports arbitrary stretching of a surface along the + * x axis (horizontal direction) for blts. + */ +#define DDFXCAPS_BLTSTRETCHX 0x00004000l + +/* + * DirectDraw supports integer stretching (1x,2x,) of a surface + * along the x axis (horizontal direction) for blts. + */ +#define DDFXCAPS_BLTSTRETCHXN 0x00008000l + +/* + * DirectDraw supports arbitrary stretching of a surface along the + * y axis (horizontal direction) for blts. + */ +#define DDFXCAPS_BLTSTRETCHY 0x00010000l + +/* + * DirectDraw supports integer stretching (1x,2x,) of a surface + * along the y axis (vertical direction) for blts. + */ +#define DDFXCAPS_BLTSTRETCHYN 0x00020000l + +/* + * Uses arithmetic operations to stretch and shrink surfaces during + * overlay rather than pixel doubling techniques. Along the Y axis + * for overlays. + */ +#define DDFXCAPS_OVERLAYARITHSTRETCHY 0x00040000l + +/* + * Uses arithmetic operations to stretch surfaces during + * overlay rather than pixel doubling techniques. Along the Y axis + * for overlays. Only works for x1, x2, etc. + */ +#define DDFXCAPS_OVERLAYARITHSTRETCHYN 0x00000008l + +/* + * DirectDraw supports arbitrary shrinking of a surface along the + * x axis (horizontal direction) for overlays. + */ +#define DDFXCAPS_OVERLAYSHRINKX 0x00080000l + +/* + * DirectDraw supports integer shrinking (1x,2x,) of a surface + * along the x axis (horizontal direction) for overlays. + */ +#define DDFXCAPS_OVERLAYSHRINKXN 0x00100000l + +/* + * DirectDraw supports arbitrary shrinking of a surface along the + * y axis (horizontal direction) for overlays. + */ +#define DDFXCAPS_OVERLAYSHRINKY 0x00200000l + +/* + * DirectDraw supports integer shrinking (1x,2x,) of a surface + * along the y axis (vertical direction) for overlays. + */ +#define DDFXCAPS_OVERLAYSHRINKYN 0x00400000l + +/* + * DirectDraw supports arbitrary stretching of a surface along the + * x axis (horizontal direction) for overlays. + */ +#define DDFXCAPS_OVERLAYSTRETCHX 0x00800000l + +/* + * DirectDraw supports integer stretching (1x,2x,) of a surface + * along the x axis (horizontal direction) for overlays. + */ +#define DDFXCAPS_OVERLAYSTRETCHXN 0x01000000l + +/* + * DirectDraw supports arbitrary stretching of a surface along the + * y axis (horizontal direction) for overlays. + */ +#define DDFXCAPS_OVERLAYSTRETCHY 0x02000000l + +/* + * DirectDraw supports integer stretching (1x,2x,) of a surface + * along the y axis (vertical direction) for overlays. + */ +#define DDFXCAPS_OVERLAYSTRETCHYN 0x04000000l + +/* + * DirectDraw supports mirroring of overlays across the vertical axis + */ +#define DDFXCAPS_OVERLAYMIRRORLEFTRIGHT 0x08000000l + +/* + * DirectDraw supports mirroring of overlays across the horizontal axis + */ +#define DDFXCAPS_OVERLAYMIRRORUPDOWN 0x10000000l + +/**************************************************************************** + * + * DIRECTDRAW STEREO VIEW CAPABILITIES + * + ****************************************************************************/ + +/* + * The stereo view is accomplished via enigma encoding. + */ +#define DDSVCAPS_ENIGMA 0x00000001l + +/* + * The stereo view is accomplished via high frequency flickering. + */ +#define DDSVCAPS_FLICKER 0x00000002l + +/* + * The stereo view is accomplished via red and blue filters applied + * to the left and right eyes. All images must adapt their colorspaces + * for this process. + */ +#define DDSVCAPS_REDBLUE 0x00000004l + +/* + * The stereo view is accomplished with split screen technology. + */ +#define DDSVCAPS_SPLIT 0x00000008l + +/**************************************************************************** + * + * DIRECTDRAWPALETTE CAPABILITIES + * + ****************************************************************************/ + +/* + * Index is 4 bits. There are sixteen color entries in the palette table. + */ +#define DDPCAPS_4BIT 0x00000001l + +/* + * Index is onto a 8 bit color index. This field is only valid with the + * DDPCAPS_1BIT, DDPCAPS_2BIT or DDPCAPS_4BIT capability and the target + * surface is in 8bpp. Each color entry is one byte long and is an index + * into destination surface's 8bpp palette. + */ +#define DDPCAPS_8BITENTRIES 0x00000002l + +/* + * Index is 8 bits. There are 256 color entries in the palette table. + */ +#define DDPCAPS_8BIT 0x00000004l + +/* + * Indicates that this DIRECTDRAWPALETTE should use the palette color array + * passed into the lpDDColorArray parameter to initialize the DIRECTDRAWPALETTE + * object. + */ +#define DDPCAPS_INITIALIZE 0x00000008l + +/* + * This palette is the one attached to the primary surface. Changing this + * table has immediate effect on the display unless DDPSETPAL_VSYNC is specified + * and supported. + */ +#define DDPCAPS_PRIMARYSURFACE 0x00000010l + +/* + * This palette is the one attached to the primary surface left. Changing + * this table has immediate effect on the display for the left eye unless + * DDPSETPAL_VSYNC is specified and supported. + */ +#define DDPCAPS_PRIMARYSURFACELEFT 0x00000020l + +/* + * This palette can have all 256 entries defined + */ +#define DDPCAPS_ALLOW256 0x00000040l + +/* + * This palette can have modifications to it synced with the monitors + * refresh rate. + */ +#define DDPCAPS_VSYNC 0x00000080l + +/* + * Index is 1 bit. There are two color entries in the palette table. + */ +#define DDPCAPS_1BIT 0x00000100l + +/* + * Index is 2 bit. There are four color entries in the palette table. + */ +#define DDPCAPS_2BIT 0x00000200l + + +/**************************************************************************** + * + * DIRECTDRAWPALETTE SETENTRY CONSTANTS + * + ****************************************************************************/ + + +/**************************************************************************** + * + * DIRECTDRAWPALETTE GETENTRY CONSTANTS + * + ****************************************************************************/ + +/* 0 is the only legal value */ + +/**************************************************************************** + * + * DIRECTDRAWSURFACE SETPALETTE CONSTANTS + * + ****************************************************************************/ + + +/**************************************************************************** + * + * DIRECTDRAW BITDEPTH CONSTANTS + * + * NOTE: These are only used to indicate supported bit depths. These + * are flags only, they are not to be used as an actual bit depth. The + * absolute numbers 1, 2, 4, 8, 16, 24 and 32 are used to indicate actual + * bit depths in a surface or for changing the display mode. + * + ****************************************************************************/ + +/* + * 1 bit per pixel. + */ +#define DDBD_1 0x00004000l + +/* + * 2 bits per pixel. + */ +#define DDBD_2 0x00002000l + +/* + * 4 bits per pixel. + */ +#define DDBD_4 0x00001000l + +/* + * 8 bits per pixel. + */ +#define DDBD_8 0x00000800l + +/* + * 16 bits per pixel. + */ +#define DDBD_16 0x00000400l + +/* + * 24 bits per pixel. + */ +#define DDBD_24 0X00000200l + +/* + * 32 bits per pixel. + */ +#define DDBD_32 0x00000100l + +/**************************************************************************** + * + * DIRECTDRAWSURFACE SET/GET COLOR KEY FLAGS + * + ****************************************************************************/ + +/* + * Set if the structure contains a color space. Not set if the structure + * contains a single color key. + */ +#define DDCKEY_COLORSPACE 0x00000001l + +/* + * Set if the structure specifies a color key or color space which is to be + * used as a destination color key for blt operations. + */ +#define DDCKEY_DESTBLT 0x00000002l + +/* + * Set if the structure specifies a color key or color space which is to be + * used as a destination color key for overlay operations. + */ +#define DDCKEY_DESTOVERLAY 0x00000004l + +/* + * Set if the structure specifies a color key or color space which is to be + * used as a source color key for blt operations. + */ +#define DDCKEY_SRCBLT 0x00000008l + +/* + * Set if the structure specifies a color key or color space which is to be + * used as a source color key for overlay operations. + */ +#define DDCKEY_SRCOVERLAY 0x00000010l + + +/**************************************************************************** + * + * DIRECTDRAW COLOR KEY CAPABILITY FLAGS + * + ****************************************************************************/ + +/* + * Supports transparent blting using a color key to identify the replaceable + * bits of the destination surface for RGB colors. + */ +#define DDCKEYCAPS_DESTBLT 0x00000001l + +/* + * Supports transparent blting using a color space to identify the replaceable + * bits of the destination surface for RGB colors. + */ +#define DDCKEYCAPS_DESTBLTCLRSPACE 0x00000002l + +/* + * Supports transparent blting using a color space to identify the replaceable + * bits of the destination surface for YUV colors. + */ +#define DDCKEYCAPS_DESTBLTCLRSPACEYUV 0x00000004l + +/* + * Supports transparent blting using a color key to identify the replaceable + * bits of the destination surface for YUV colors. + */ +#define DDCKEYCAPS_DESTBLTYUV 0x00000008l + +/* + * Supports overlaying using colorkeying of the replaceable bits of the surface + * being overlayed for RGB colors. + */ +#define DDCKEYCAPS_DESTOVERLAY 0x00000010l + +/* + * Supports a color space as the color key for the destination for RGB colors. + */ +#define DDCKEYCAPS_DESTOVERLAYCLRSPACE 0x00000020l + +/* + * Supports a color space as the color key for the destination for YUV colors. + */ +#define DDCKEYCAPS_DESTOVERLAYCLRSPACEYUV 0x00000040l + +/* + * Supports only one active destination color key value for visible overlay + * surfaces. + */ +#define DDCKEYCAPS_DESTOVERLAYONEACTIVE 0x00000080l + +/* + * Supports overlaying using colorkeying of the replaceable bits of the + * surface being overlayed for YUV colors. + */ +#define DDCKEYCAPS_DESTOVERLAYYUV 0x00000100l + +/* + * Supports transparent blting using the color key for the source with + * this surface for RGB colors. + */ +#define DDCKEYCAPS_SRCBLT 0x00000200l + +/* + * Supports transparent blting using a color space for the source with + * this surface for RGB colors. + */ +#define DDCKEYCAPS_SRCBLTCLRSPACE 0x00000400l + +/* + * Supports transparent blting using a color space for the source with + * this surface for YUV colors. + */ +#define DDCKEYCAPS_SRCBLTCLRSPACEYUV 0x00000800l + +/* + * Supports transparent blting using the color key for the source with + * this surface for YUV colors. + */ +#define DDCKEYCAPS_SRCBLTYUV 0x00001000l + +/* + * Supports overlays using the color key for the source with this + * overlay surface for RGB colors. + */ +#define DDCKEYCAPS_SRCOVERLAY 0x00002000l + +/* + * Supports overlays using a color space as the source color key for + * the overlay surface for RGB colors. + */ +#define DDCKEYCAPS_SRCOVERLAYCLRSPACE 0x00004000l + +/* + * Supports overlays using a color space as the source color key for + * the overlay surface for YUV colors. + */ +#define DDCKEYCAPS_SRCOVERLAYCLRSPACEYUV 0x00008000l + +/* + * Supports only one active source color key value for visible + * overlay surfaces. + */ +#define DDCKEYCAPS_SRCOVERLAYONEACTIVE 0x00010000l + +/* + * Supports overlays using the color key for the source with this + * overlay surface for YUV colors. + */ +#define DDCKEYCAPS_SRCOVERLAYYUV 0x00020000l + +/* + * there are no bandwidth trade-offs for using colorkey with an overlay + */ +#define DDCKEYCAPS_NOCOSTOVERLAY 0x00040000l + + +/**************************************************************************** + * + * DIRECTDRAW PIXELFORMAT FLAGS + * + ****************************************************************************/ + +/* + * The surface has alpha channel information in the pixel format. + */ +#define DDPF_ALPHAPIXELS 0x00000001l + +/* + * The pixel format contains alpha only information + */ +#define DDPF_ALPHA 0x00000002l + +/* + * The FourCC code is valid. + */ +#define DDPF_FOURCC 0x00000004l + +/* + * The surface is 4-bit color indexed. + */ +#define DDPF_PALETTEINDEXED4 0x00000008l + +/* + * The surface is indexed into a palette which stores indices + * into the destination surface's 8-bit palette. + */ +#define DDPF_PALETTEINDEXEDTO8 0x00000010l + +/* + * The surface is 8-bit color indexed. + */ +#define DDPF_PALETTEINDEXED8 0x00000020l + +/* + * The RGB data in the pixel format structure is valid. + */ +#define DDPF_RGB 0x00000040l + +/* + * The surface will accept pixel data in the format specified + * and compress it during the write. + */ +#define DDPF_COMPRESSED 0x00000080l + +/* + * The surface will accept RGB data and translate it during + * the write to YUV data. The format of the data to be written + * will be contained in the pixel format structure. The DDPF_RGB + * flag will be set. + */ +#define DDPF_RGBTOYUV 0x00000100l + +/* + * pixel format is YUV - YUV data in pixel format struct is valid + */ +#define DDPF_YUV 0x00000200l + +/* + * pixel format is a z buffer only surface + */ +#define DDPF_ZBUFFER 0x00000400l + +/* + * The surface is 1-bit color indexed. + */ +#define DDPF_PALETTEINDEXED1 0x00000800l + +/* + * The surface is 2-bit color indexed. + */ +#define DDPF_PALETTEINDEXED2 0x00001000l + +/* + * The surface contains Z information in the pixels + */ +#define DDPF_ZPIXELS 0x00002000l + +/*=========================================================================== + * + * + * DIRECTDRAW CALLBACK FLAGS + * + * + *==========================================================================*/ + +/**************************************************************************** + * + * DIRECTDRAW ENUMSURFACES FLAGS + * + ****************************************************************************/ + +/* + * Enumerate all of the surfaces that meet the search criterion. + */ +#define DDENUMSURFACES_ALL 0x00000001l + +/* + * A search hit is a surface that matches the surface description. + */ +#define DDENUMSURFACES_MATCH 0x00000002l + +/* + * A search hit is a surface that does not match the surface description. + */ +#define DDENUMSURFACES_NOMATCH 0x00000004l + +/* + * Enumerate the first surface that can be created which meets the search criterion. + */ +#define DDENUMSURFACES_CANBECREATED 0x00000008l + +/* + * Enumerate the surfaces that already exist that meet the search criterion. + */ +#define DDENUMSURFACES_DOESEXIST 0x00000010l + + +/**************************************************************************** + * + * DIRECTDRAW SETDISPLAYMODE FLAGS + * + ****************************************************************************/ + +/* + * The desired mode is a standard VGA mode + */ +#define DDSDM_STANDARDVGAMODE 0x00000001l + + + +/**************************************************************************** + * + * DIRECTDRAW ENUMDISPLAYMODES FLAGS + * + ****************************************************************************/ + +/* + * Enumerate Modes with different refresh rates. EnumDisplayModes guarantees + * that a particular mode will be enumerated only once. This flag specifies whether + * the refresh rate is taken into account when determining if a mode is unique. + */ +#define DDEDM_REFRESHRATES 0x00000001l + +/* + * Enumerate VGA modes. Specify this flag if you wish to enumerate supported VGA + * modes such as mode 0x13 in addition to the usual ModeX modes (which are always + * enumerated if the application has previously called SetCooperativeLevel with the + * DDSCL_ALLOWMODEX flag set). + */ +#define DDEDM_STANDARDVGAMODES 0x00000002L + + +/**************************************************************************** + * + * DIRECTDRAW SETCOOPERATIVELEVEL FLAGS + * + ****************************************************************************/ + +/* + * Exclusive mode owner will be responsible for the entire primary surface. + * GDI can be ignored. used with DD + */ +#define DDSCL_FULLSCREEN 0x00000001l + +/* + * allow CTRL_ALT_DEL to work while in fullscreen exclusive mode + */ +#define DDSCL_ALLOWREBOOT 0x00000002l + +/* + * prevents DDRAW from modifying the application window. + * prevents DDRAW from minimize/restore the application window on activation. + */ +#define DDSCL_NOWINDOWCHANGES 0x00000004l + +/* + * app wants to work as a regular Windows application + */ +#define DDSCL_NORMAL 0x00000008l + +/* + * app wants exclusive access + */ +#define DDSCL_EXCLUSIVE 0x00000010l + + +/* + * app can deal with non-windows display modes + */ +#define DDSCL_ALLOWMODEX 0x00000040l + + +/**************************************************************************** + * + * DIRECTDRAW BLT FLAGS + * + ****************************************************************************/ + +/* + * Use the alpha information in the pixel format or the alpha channel surface + * attached to the destination surface as the alpha channel for this blt. + */ +#define DDBLT_ALPHADEST 0x00000001l + +/* + * Use the dwConstAlphaDest field in the DDBLTFX structure as the alpha channel + * for the destination surface for this blt. + */ +#define DDBLT_ALPHADESTCONSTOVERRIDE 0x00000002l + +/* + * The NEG suffix indicates that the destination surface becomes more + * transparent as the alpha value increases. (0 is opaque) + */ +#define DDBLT_ALPHADESTNEG 0x00000004l + +/* + * Use the lpDDSAlphaDest field in the DDBLTFX structure as the alpha + * channel for the destination for this blt. + */ +#define DDBLT_ALPHADESTSURFACEOVERRIDE 0x00000008l + +/* + * Use the dwAlphaEdgeBlend field in the DDBLTFX structure as the alpha channel + * for the edges of the image that border the color key colors. + */ +#define DDBLT_ALPHAEDGEBLEND 0x00000010l + +/* + * Use the alpha information in the pixel format or the alpha channel surface + * attached to the source surface as the alpha channel for this blt. + */ +#define DDBLT_ALPHASRC 0x00000020l + +/* + * Use the dwConstAlphaSrc field in the DDBLTFX structure as the alpha channel + * for the source for this blt. + */ +#define DDBLT_ALPHASRCCONSTOVERRIDE 0x00000040l + +/* + * The NEG suffix indicates that the source surface becomes more transparent + * as the alpha value increases. (0 is opaque) + */ +#define DDBLT_ALPHASRCNEG 0x00000080l + +/* + * Use the lpDDSAlphaSrc field in the DDBLTFX structure as the alpha channel + * for the source for this blt. + */ +#define DDBLT_ALPHASRCSURFACEOVERRIDE 0x00000100l + +/* + * Do this blt asynchronously through the FIFO in the order received. If + * there is no room in the hardware FIFO fail the call. + */ +#define DDBLT_ASYNC 0x00000200l + +/* + * Uses the dwFillColor field in the DDBLTFX structure as the RGB color + * to fill the destination rectangle on the destination surface with. + */ +#define DDBLT_COLORFILL 0x00000400l + +/* + * Uses the dwDDFX field in the DDBLTFX structure to specify the effects + * to use for the blt. + */ +#define DDBLT_DDFX 0x00000800l + +/* + * Uses the dwDDROPS field in the DDBLTFX structure to specify the ROPS + * that are not part of the Win32 API. + */ +#define DDBLT_DDROPS 0x00001000l + +/* + * Use the color key associated with the destination surface. + */ +#define DDBLT_KEYDEST 0x00002000l + +/* + * Use the dckDestColorkey field in the DDBLTFX structure as the color key + * for the destination surface. + */ +#define DDBLT_KEYDESTOVERRIDE 0x00004000l + +/* + * Use the color key associated with the source surface. + */ +#define DDBLT_KEYSRC 0x00008000l + +/* + * Use the dckSrcColorkey field in the DDBLTFX structure as the color key + * for the source surface. + */ +#define DDBLT_KEYSRCOVERRIDE 0x00010000l + +/* + * Use the dwROP field in the DDBLTFX structure for the raster operation + * for this blt. These ROPs are the same as the ones defined in the Win32 API. + */ +#define DDBLT_ROP 0x00020000l + +/* + * Use the dwRotationAngle field in the DDBLTFX structure as the angle + * (specified in 1/100th of a degree) to rotate the surface. + */ +#define DDBLT_ROTATIONANGLE 0x00040000l + +/* + * Z-buffered blt using the z-buffers attached to the source and destination + * surfaces and the dwZBufferOpCode field in the DDBLTFX structure as the + * z-buffer opcode. + */ +#define DDBLT_ZBUFFER 0x00080000l + +/* + * Z-buffered blt using the dwConstDest Zfield and the dwZBufferOpCode field + * in the DDBLTFX structure as the z-buffer and z-buffer opcode respectively + * for the destination. + */ +#define DDBLT_ZBUFFERDESTCONSTOVERRIDE 0x00100000l + +/* + * Z-buffered blt using the lpDDSDestZBuffer field and the dwZBufferOpCode + * field in the DDBLTFX structure as the z-buffer and z-buffer opcode + * respectively for the destination. + */ +#define DDBLT_ZBUFFERDESTOVERRIDE 0x00200000l + +/* + * Z-buffered blt using the dwConstSrcZ field and the dwZBufferOpCode field + * in the DDBLTFX structure as the z-buffer and z-buffer opcode respectively + * for the source. + */ +#define DDBLT_ZBUFFERSRCCONSTOVERRIDE 0x00400000l + +/* + * Z-buffered blt using the lpDDSSrcZBuffer field and the dwZBufferOpCode + * field in the DDBLTFX structure as the z-buffer and z-buffer opcode + * respectively for the source. + */ +#define DDBLT_ZBUFFERSRCOVERRIDE 0x00800000l + +/* + * wait until the device is ready to handle the blt + * this will cause blt to not return DDERR_WASSTILLDRAWING + */ +#define DDBLT_WAIT 0x01000000l + +/* + * Uses the dwFillDepth field in the DDBLTFX structure as the depth value + * to fill the destination rectangle on the destination Z-buffer surface + * with. + */ +#define DDBLT_DEPTHFILL 0x02000000l + + + +/**************************************************************************** + * + * BLTFAST FLAGS + * + ****************************************************************************/ + +#define DDBLTFAST_NOCOLORKEY 0x00000000 +#define DDBLTFAST_SRCCOLORKEY 0x00000001 +#define DDBLTFAST_DESTCOLORKEY 0x00000002 +#define DDBLTFAST_WAIT 0x00000010 + +/**************************************************************************** + * + * FLIP FLAGS + * + ****************************************************************************/ + +#define DDFLIP_WAIT 0x00000001l + +/* + * Indicates that the target surface contains the even field of video data. + * This flag is only valid with an overlay surface. + */ +#define DDFLIP_EVEN 0x00000002l + +/* + * Indicates that the target surface contains the odd field of video data. + * This flag is only valid with an overlay surface. + */ +#define DDFLIP_ODD 0x00000004l + + + +/**************************************************************************** + * + * DIRECTDRAW SURFACE OVERLAY FLAGS + * + ****************************************************************************/ + +/* + * Use the alpha information in the pixel format or the alpha channel surface + * attached to the destination surface as the alpha channel for the + * destination overlay. + */ +#define DDOVER_ALPHADEST 0x00000001l + +/* + * Use the dwConstAlphaDest field in the DDOVERLAYFX structure as the + * destination alpha channel for this overlay. + */ +#define DDOVER_ALPHADESTCONSTOVERRIDE 0x00000002l + +/* + * The NEG suffix indicates that the destination surface becomes more + * transparent as the alpha value increases. + */ +#define DDOVER_ALPHADESTNEG 0x00000004l + +/* + * Use the lpDDSAlphaDest field in the DDOVERLAYFX structure as the alpha + * channel destination for this overlay. + */ +#define DDOVER_ALPHADESTSURFACEOVERRIDE 0x00000008l + +/* + * Use the dwAlphaEdgeBlend field in the DDOVERLAYFX structure as the alpha + * channel for the edges of the image that border the color key colors. + */ +#define DDOVER_ALPHAEDGEBLEND 0x00000010l + +/* + * Use the alpha information in the pixel format or the alpha channel surface + * attached to the source surface as the source alpha channel for this overlay. + */ +#define DDOVER_ALPHASRC 0x00000020l + +/* + * Use the dwConstAlphaSrc field in the DDOVERLAYFX structure as the source + * alpha channel for this overlay. + */ +#define DDOVER_ALPHASRCCONSTOVERRIDE 0x00000040l + +/* + * The NEG suffix indicates that the source surface becomes more transparent + * as the alpha value increases. + */ +#define DDOVER_ALPHASRCNEG 0x00000080l + +/* + * Use the lpDDSAlphaSrc field in the DDOVERLAYFX structure as the alpha channel + * source for this overlay. + */ +#define DDOVER_ALPHASRCSURFACEOVERRIDE 0x00000100l + +/* + * Turn this overlay off. + */ +#define DDOVER_HIDE 0x00000200l + +/* + * Use the color key associated with the destination surface. + */ +#define DDOVER_KEYDEST 0x00000400l + +/* + * Use the dckDestColorkey field in the DDOVERLAYFX structure as the color key + * for the destination surface + */ +#define DDOVER_KEYDESTOVERRIDE 0x00000800l + +/* + * Use the color key associated with the source surface. + */ +#define DDOVER_KEYSRC 0x00001000l + +/* + * Use the dckSrcColorkey field in the DDOVERLAYFX structure as the color key + * for the source surface. + */ +#define DDOVER_KEYSRCOVERRIDE 0x00002000l + +/* + * Turn this overlay on. + */ +#define DDOVER_SHOW 0x00004000l + +/* + * Add a dirty rect to an emulated overlayed surface. + */ +#define DDOVER_ADDDIRTYRECT 0x00008000l + +/* + * Redraw all dirty rects on an emulated overlayed surface. + */ +#define DDOVER_REFRESHDIRTYRECTS 0x00010000l + +/* + * Redraw the entire surface on an emulated overlayed surface. + */ +#define DDOVER_REFRESHALL 0x00020000l + + +/* + * Use the overlay FX flags to define special overlay FX + */ +#define DDOVER_DDFX 0x00080000l + +/* + * Autoflip the overlay when ever the video port autoflips + */ +#define DDOVER_AUTOFLIP 0x00100000l + +/* + * Display each field of video port data individually without + * causing any jittery artifacts + */ +#define DDOVER_BOB 0x00200000l + +/* + * Indicates that bob/weave decisions should not be overridden by other + * interfaces. + */ +#define DDOVER_OVERRIDEBOBWEAVE 0x00400000l + +/* + * Indicates that the surface memory is composed of interleaved fields. + */ +#define DDOVER_INTERLEAVED 0x00800000l + + +/**************************************************************************** + * + * DIRECTDRAWSURFACE LOCK FLAGS + * + ****************************************************************************/ + +/* + * The default. Set to indicate that Lock should return a valid memory pointer + * to the top of the specified rectangle. If no rectangle is specified then a + * pointer to the top of the surface is returned. + */ +#define DDLOCK_SURFACEMEMORYPTR 0x00000000L // default + +/* + * Set to indicate that Lock should wait until it can obtain a valid memory + * pointer before returning. If this bit is set, Lock will never return + * DDERR_WASSTILLDRAWING. + */ +#define DDLOCK_WAIT 0x00000001L + +/* + * Set if an event handle is being passed to Lock. Lock will trigger the event + * when it can return the surface memory pointer requested. + */ +#define DDLOCK_EVENT 0x00000002L + +/* + * Indicates that the surface being locked will only be read from. + */ +#define DDLOCK_READONLY 0x00000010L + +/* + * Indicates that the surface being locked will only be written to + */ +#define DDLOCK_WRITEONLY 0x00000020L + + +/* + * Indicates that a system wide lock should not be taken when this surface + * is locked. This has several advantages (cursor responsiveness, ability + * to call more Windows functions, easier debugging) when locking video + * memory surfaces. However, an application specifying this flag must + * comply with a number of conditions documented in the help file. + * Furthermore, this flag cannot be specified when locking the primary. + */ +#define DDLOCK_NOSYSLOCK 0x00000800L + + +/**************************************************************************** + * + * DIRECTDRAWSURFACE PAGELOCK FLAGS + * + ****************************************************************************/ + +/* + * No flags defined at present + */ + + +/**************************************************************************** + * + * DIRECTDRAWSURFACE PAGEUNLOCK FLAGS + * + ****************************************************************************/ + +/* + * No flags defined at present + */ + + +/**************************************************************************** + * + * DIRECTDRAWSURFACE BLT FX FLAGS + * + ****************************************************************************/ + +/* + * If stretching, use arithmetic stretching along the Y axis for this blt. + */ +#define DDBLTFX_ARITHSTRETCHY 0x00000001l + +/* + * Do this blt mirroring the surface left to right. Spin the + * surface around its y-axis. + */ +#define DDBLTFX_MIRRORLEFTRIGHT 0x00000002l + +/* + * Do this blt mirroring the surface up and down. Spin the surface + * around its x-axis. + */ +#define DDBLTFX_MIRRORUPDOWN 0x00000004l + +/* + * Schedule this blt to avoid tearing. + */ +#define DDBLTFX_NOTEARING 0x00000008l + +/* + * Do this blt rotating the surface one hundred and eighty degrees. + */ +#define DDBLTFX_ROTATE180 0x00000010l + +/* + * Do this blt rotating the surface two hundred and seventy degrees. + */ +#define DDBLTFX_ROTATE270 0x00000020l + +/* + * Do this blt rotating the surface ninety degrees. + */ +#define DDBLTFX_ROTATE90 0x00000040l + +/* + * Do this z blt using dwZBufferLow and dwZBufferHigh as range values + * specified to limit the bits copied from the source surface. + */ +#define DDBLTFX_ZBUFFERRANGE 0x00000080l + +/* + * Do this z blt adding the dwZBufferBaseDest to each of the sources z values + * before comparing it with the desting z values. + */ +#define DDBLTFX_ZBUFFERBASEDEST 0x00000100l + +/**************************************************************************** + * + * DIRECTDRAWSURFACE OVERLAY FX FLAGS + * + ****************************************************************************/ + +/* + * If stretching, use arithmetic stretching along the Y axis for this overlay. + */ +#define DDOVERFX_ARITHSTRETCHY 0x00000001l + +/* + * Mirror the overlay across the vertical axis + */ +#define DDOVERFX_MIRRORLEFTRIGHT 0x00000002l + +/* + * Mirror the overlay across the horizontal axis + */ +#define DDOVERFX_MIRRORUPDOWN 0x00000004l + +/**************************************************************************** + * + * DIRECTDRAW WAITFORVERTICALBLANK FLAGS + * + ****************************************************************************/ + +/* + * return when the vertical blank interval begins + */ +#define DDWAITVB_BLOCKBEGIN 0x00000001l + +/* + * set up an event to trigger when the vertical blank begins + */ +#define DDWAITVB_BLOCKBEGINEVENT 0x00000002l + +/* + * return when the vertical blank interval ends and display begins + */ +#define DDWAITVB_BLOCKEND 0x00000004l + +/**************************************************************************** + * + * DIRECTDRAW GETFLIPSTATUS FLAGS + * + ****************************************************************************/ + +/* + * is it OK to flip now? + */ +#define DDGFS_CANFLIP 0x00000001l + +/* + * is the last flip finished? + */ +#define DDGFS_ISFLIPDONE 0x00000002l + +/**************************************************************************** + * + * DIRECTDRAW GETBLTSTATUS FLAGS + * + ****************************************************************************/ + +/* + * is it OK to blt now? + */ +#define DDGBS_CANBLT 0x00000001l + +/* + * is the blt to the surface finished? + */ +#define DDGBS_ISBLTDONE 0x00000002l + + +/**************************************************************************** + * + * DIRECTDRAW ENUMOVERLAYZORDER FLAGS + * + ****************************************************************************/ + +/* + * Enumerate overlays back to front. + */ +#define DDENUMOVERLAYZ_BACKTOFRONT 0x00000000l + +/* + * Enumerate overlays front to back + */ +#define DDENUMOVERLAYZ_FRONTTOBACK 0x00000001l + +/**************************************************************************** + * + * DIRECTDRAW UPDATEOVERLAYZORDER FLAGS + * + ****************************************************************************/ + +/* + * Send overlay to front + */ +#define DDOVERZ_SENDTOFRONT 0x00000000l + +/* + * Send overlay to back + */ +#define DDOVERZ_SENDTOBACK 0x00000001l + +/* + * Move Overlay forward + */ +#define DDOVERZ_MOVEFORWARD 0x00000002l + +/* + * Move Overlay backward + */ +#define DDOVERZ_MOVEBACKWARD 0x00000003l + +/* + * Move Overlay in front of relative surface + */ +#define DDOVERZ_INSERTINFRONTOF 0x00000004l + +/* + * Move Overlay in back of relative surface + */ +#define DDOVERZ_INSERTINBACKOF 0x00000005l + +/*=========================================================================== + * + * + * DIRECTDRAW RETURN CODES + * + * The return values from DirectDraw Commands and Surface that return an HRESULT + * are codes from DirectDraw concerning the results of the action + * requested by DirectDraw. + * + *==========================================================================*/ + +/* + * Status is OK + * + * Issued by: DirectDraw Commands and all callbacks + */ +#define DD_OK 0 + +/**************************************************************************** + * + * DIRECTDRAW ENUMCALLBACK RETURN VALUES + * + * EnumCallback returns are used to control the flow of the DIRECTDRAW and + * DIRECTDRAWSURFACE object enumerations. They can only be returned by + * enumeration callback routines. + * + ****************************************************************************/ + +/* + * stop the enumeration + */ +#define DDENUMRET_CANCEL 0 + +/* + * continue the enumeration + */ +#define DDENUMRET_OK 1 + +/**************************************************************************** + * + * DIRECTDRAW ERRORS + * + * Errors are represented by negative values and cannot be combined. + * + ****************************************************************************/ + +/* + * This object is already initialized + */ +#define DDERR_ALREADYINITIALIZED MAKE_DDHRESULT( 5 ) + +/* + * This surface can not be attached to the requested surface. + */ +#define DDERR_CANNOTATTACHSURFACE MAKE_DDHRESULT( 10 ) + +/* + * This surface can not be detached from the requested surface. + */ +#define DDERR_CANNOTDETACHSURFACE MAKE_DDHRESULT( 20 ) + +/* + * Support is currently not available. + */ +#define DDERR_CURRENTLYNOTAVAIL MAKE_DDHRESULT( 40 ) + +/* + * An exception was encountered while performing the requested operation + */ +#define DDERR_EXCEPTION MAKE_DDHRESULT( 55 ) + +/* + * Generic failure. + */ +#define DDERR_GENERIC E_FAIL + +/* + * Height of rectangle provided is not a multiple of reqd alignment + */ +#define DDERR_HEIGHTALIGN MAKE_DDHRESULT( 90 ) + +/* + * Unable to match primary surface creation request with existing + * primary surface. + */ +#define DDERR_INCOMPATIBLEPRIMARY MAKE_DDHRESULT( 95 ) + +/* + * One or more of the caps bits passed to the callback are incorrect. + */ +#define DDERR_INVALIDCAPS MAKE_DDHRESULT( 100 ) + +/* + * DirectDraw does not support provided Cliplist. + */ +#define DDERR_INVALIDCLIPLIST MAKE_DDHRESULT( 110 ) + +/* + * DirectDraw does not support the requested mode + */ +#define DDERR_INVALIDMODE MAKE_DDHRESULT( 120 ) + +/* + * DirectDraw received a pointer that was an invalid DIRECTDRAW object. + */ +#define DDERR_INVALIDOBJECT MAKE_DDHRESULT( 130 ) + +/* + * One or more of the parameters passed to the callback function are + * incorrect. + */ +#define DDERR_INVALIDPARAMS E_INVALIDARG + +/* + * pixel format was invalid as specified + */ +#define DDERR_INVALIDPIXELFORMAT MAKE_DDHRESULT( 145 ) + +/* + * Rectangle provided was invalid. + */ +#define DDERR_INVALIDRECT MAKE_DDHRESULT( 150 ) + +/* + * Operation could not be carried out because one or more surfaces are locked + */ +#define DDERR_LOCKEDSURFACES MAKE_DDHRESULT( 160 ) + +/* + * There is no 3D present. + */ +#define DDERR_NO3D MAKE_DDHRESULT( 170 ) + +/* + * Operation could not be carried out because there is no alpha accleration + * hardware present or available. + */ +#define DDERR_NOALPHAHW MAKE_DDHRESULT( 180 ) + + +/* + * no clip list available + */ +#define DDERR_NOCLIPLIST MAKE_DDHRESULT( 205 ) + +/* + * Operation could not be carried out because there is no color conversion + * hardware present or available. + */ +#define DDERR_NOCOLORCONVHW MAKE_DDHRESULT( 210 ) + +/* + * Create function called without DirectDraw object method SetCooperativeLevel + * being called. + */ +#define DDERR_NOCOOPERATIVELEVELSET MAKE_DDHRESULT( 212 ) + +/* + * Surface doesn't currently have a color key + */ +#define DDERR_NOCOLORKEY MAKE_DDHRESULT( 215 ) + +/* + * Operation could not be carried out because there is no hardware support + * of the dest color key. + */ +#define DDERR_NOCOLORKEYHW MAKE_DDHRESULT( 220 ) + +/* + * No DirectDraw support possible with current display driver + */ +#define DDERR_NODIRECTDRAWSUPPORT MAKE_DDHRESULT( 222 ) + +/* + * Operation requires the application to have exclusive mode but the + * application does not have exclusive mode. + */ +#define DDERR_NOEXCLUSIVEMODE MAKE_DDHRESULT( 225 ) + +/* + * Flipping visible surfaces is not supported. + */ +#define DDERR_NOFLIPHW MAKE_DDHRESULT( 230 ) + +/* + * There is no GDI present. + */ +#define DDERR_NOGDI MAKE_DDHRESULT( 240 ) + +/* + * Operation could not be carried out because there is no hardware present + * or available. + */ +#define DDERR_NOMIRRORHW MAKE_DDHRESULT( 250 ) + +/* + * Requested item was not found + */ +#define DDERR_NOTFOUND MAKE_DDHRESULT( 255 ) + +/* + * Operation could not be carried out because there is no overlay hardware + * present or available. + */ +#define DDERR_NOOVERLAYHW MAKE_DDHRESULT( 260 ) + +/* + * Operation could not be carried out because there is no appropriate raster + * op hardware present or available. + */ +#define DDERR_NORASTEROPHW MAKE_DDHRESULT( 280 ) + +/* + * Operation could not be carried out because there is no rotation hardware + * present or available. + */ +#define DDERR_NOROTATIONHW MAKE_DDHRESULT( 290 ) + +/* + * Operation could not be carried out because there is no hardware support + * for stretching + */ +#define DDERR_NOSTRETCHHW MAKE_DDHRESULT( 310 ) + +/* + * DirectDrawSurface is not in 4 bit color palette and the requested operation + * requires 4 bit color palette. + */ +#define DDERR_NOT4BITCOLOR MAKE_DDHRESULT( 316 ) + +/* + * DirectDrawSurface is not in 4 bit color index palette and the requested + * operation requires 4 bit color index palette. + */ +#define DDERR_NOT4BITCOLORINDEX MAKE_DDHRESULT( 317 ) + +/* + * DirectDraw Surface is not in 8 bit color mode and the requested operation + * requires 8 bit color. + */ +#define DDERR_NOT8BITCOLOR MAKE_DDHRESULT( 320 ) + +/* + * Operation could not be carried out because there is no texture mapping + * hardware present or available. + */ +#define DDERR_NOTEXTUREHW MAKE_DDHRESULT( 330 ) + +/* + * Operation could not be carried out because there is no hardware support + * for vertical blank synchronized operations. + */ +#define DDERR_NOVSYNCHW MAKE_DDHRESULT( 335 ) + +/* + * Operation could not be carried out because there is no hardware support + * for zbuffer blting. + */ +#define DDERR_NOZBUFFERHW MAKE_DDHRESULT( 340 ) + +/* + * Overlay surfaces could not be z layered based on their BltOrder because + * the hardware does not support z layering of overlays. + */ +#define DDERR_NOZOVERLAYHW MAKE_DDHRESULT( 350 ) + +/* + * The hardware needed for the requested operation has already been + * allocated. + */ +#define DDERR_OUTOFCAPS MAKE_DDHRESULT( 360 ) + +/* + * DirectDraw does not have enough memory to perform the operation. + */ +#define DDERR_OUTOFMEMORY E_OUTOFMEMORY + +/* + * DirectDraw does not have enough memory to perform the operation. + */ +#define DDERR_OUTOFVIDEOMEMORY MAKE_DDHRESULT( 380 ) + +/* + * hardware does not support clipped overlays + */ +#define DDERR_OVERLAYCANTCLIP MAKE_DDHRESULT( 382 ) + +/* + * Can only have ony color key active at one time for overlays + */ +#define DDERR_OVERLAYCOLORKEYONLYONEACTIVE MAKE_DDHRESULT( 384 ) + +/* + * Access to this palette is being refused because the palette is already + * locked by another thread. + */ +#define DDERR_PALETTEBUSY MAKE_DDHRESULT( 387 ) + +/* + * No src color key specified for this operation. + */ +#define DDERR_COLORKEYNOTSET MAKE_DDHRESULT( 400 ) + +/* + * This surface is already attached to the surface it is being attached to. + */ +#define DDERR_SURFACEALREADYATTACHED MAKE_DDHRESULT( 410 ) + +/* + * This surface is already a dependency of the surface it is being made a + * dependency of. + */ +#define DDERR_SURFACEALREADYDEPENDENT MAKE_DDHRESULT( 420 ) + +/* + * Access to this surface is being refused because the surface is already + * locked by another thread. + */ +#define DDERR_SURFACEBUSY MAKE_DDHRESULT( 430 ) + +/* + * Access to this surface is being refused because no driver exists + * which can supply a pointer to the surface. + * This is most likely to happen when attempting to lock the primary + * surface when no DCI provider is present. + * Will also happen on attempts to lock an optimized surface. + */ +#define DDERR_CANTLOCKSURFACE MAKE_DDHRESULT( 435 ) + +/* + * Access to Surface refused because Surface is obscured. + */ +#define DDERR_SURFACEISOBSCURED MAKE_DDHRESULT( 440 ) + +/* + * Access to this surface is being refused because the surface is gone. + * The DIRECTDRAWSURFACE object representing this surface should + * have Restore called on it. + */ +#define DDERR_SURFACELOST MAKE_DDHRESULT( 450 ) + +/* + * The requested surface is not attached. + */ +#define DDERR_SURFACENOTATTACHED MAKE_DDHRESULT( 460 ) + +/* + * Height requested by DirectDraw is too large. + */ +#define DDERR_TOOBIGHEIGHT MAKE_DDHRESULT( 470 ) + +/* + * Size requested by DirectDraw is too large -- The individual height and + * width are OK. + */ +#define DDERR_TOOBIGSIZE MAKE_DDHRESULT( 480 ) + +/* + * Width requested by DirectDraw is too large. + */ +#define DDERR_TOOBIGWIDTH MAKE_DDHRESULT( 490 ) + +/* + * Action not supported. + */ +#define DDERR_UNSUPPORTED E_NOTIMPL + +/* + * FOURCC format requested is unsupported by DirectDraw + */ +#define DDERR_UNSUPPORTEDFORMAT MAKE_DDHRESULT( 510 ) + +/* + * Bitmask in the pixel format requested is unsupported by DirectDraw + */ +#define DDERR_UNSUPPORTEDMASK MAKE_DDHRESULT( 520 ) + +/* + * vertical blank is in progress + */ +#define DDERR_VERTICALBLANKINPROGRESS MAKE_DDHRESULT( 537 ) + +/* + * Informs DirectDraw that the previous Blt which is transfering information + * to or from this Surface is incomplete. + */ +#define DDERR_WASSTILLDRAWING MAKE_DDHRESULT( 540 ) + + +/* + * Rectangle provided was not horizontally aligned on reqd. boundary + */ +#define DDERR_XALIGN MAKE_DDHRESULT( 560 ) + +/* + * The GUID passed to DirectDrawCreate is not a valid DirectDraw driver + * identifier. + */ +#define DDERR_INVALIDDIRECTDRAWGUID MAKE_DDHRESULT( 561 ) + +/* + * A DirectDraw object representing this driver has already been created + * for this process. + */ +#define DDERR_DIRECTDRAWALREADYCREATED MAKE_DDHRESULT( 562 ) + +/* + * A hardware only DirectDraw object creation was attempted but the driver + * did not support any hardware. + */ +#define DDERR_NODIRECTDRAWHW MAKE_DDHRESULT( 563 ) + +/* + * this process already has created a primary surface + */ +#define DDERR_PRIMARYSURFACEALREADYEXISTS MAKE_DDHRESULT( 564 ) + +/* + * software emulation not available. + */ +#define DDERR_NOEMULATION MAKE_DDHRESULT( 565 ) + +/* + * region passed to Clipper::GetClipList is too small. + */ +#define DDERR_REGIONTOOSMALL MAKE_DDHRESULT( 566 ) + +/* + * an attempt was made to set a clip list for a clipper objec that + * is already monitoring an hwnd. + */ +#define DDERR_CLIPPERISUSINGHWND MAKE_DDHRESULT( 567 ) + +/* + * No clipper object attached to surface object + */ +#define DDERR_NOCLIPPERATTACHED MAKE_DDHRESULT( 568 ) + +/* + * Clipper notification requires an HWND or + * no HWND has previously been set as the CooperativeLevel HWND. + */ +#define DDERR_NOHWND MAKE_DDHRESULT( 569 ) + +/* + * HWND used by DirectDraw CooperativeLevel has been subclassed, + * this prevents DirectDraw from restoring state. + */ +#define DDERR_HWNDSUBCLASSED MAKE_DDHRESULT( 570 ) + +/* + * The CooperativeLevel HWND has already been set. + * It can not be reset while the process has surfaces or palettes created. + */ +#define DDERR_HWNDALREADYSET MAKE_DDHRESULT( 571 ) + +/* + * No palette object attached to this surface. + */ +#define DDERR_NOPALETTEATTACHED MAKE_DDHRESULT( 572 ) + +/* + * No hardware support for 16 or 256 color palettes. + */ +#define DDERR_NOPALETTEHW MAKE_DDHRESULT( 573 ) + +/* + * If a clipper object is attached to the source surface passed into a + * BltFast call. + */ +#define DDERR_BLTFASTCANTCLIP MAKE_DDHRESULT( 574 ) + +/* + * No blter. + */ +#define DDERR_NOBLTHW MAKE_DDHRESULT( 575 ) + +/* + * No DirectDraw ROP hardware. + */ +#define DDERR_NODDROPSHW MAKE_DDHRESULT( 576 ) + +/* + * returned when GetOverlayPosition is called on a hidden overlay + */ +#define DDERR_OVERLAYNOTVISIBLE MAKE_DDHRESULT( 577 ) + +/* + * returned when GetOverlayPosition is called on a overlay that UpdateOverlay + * has never been called on to establish a destionation. + */ +#define DDERR_NOOVERLAYDEST MAKE_DDHRESULT( 578 ) + +/* + * returned when the position of the overlay on the destionation is no longer + * legal for that destionation. + */ +#define DDERR_INVALIDPOSITION MAKE_DDHRESULT( 579 ) + +/* + * returned when an overlay member is called for a non-overlay surface + */ +#define DDERR_NOTAOVERLAYSURFACE MAKE_DDHRESULT( 580 ) + +/* + * An attempt was made to set the cooperative level when it was already + * set to exclusive. + */ +#define DDERR_EXCLUSIVEMODEALREADYSET MAKE_DDHRESULT( 581 ) + +/* + * An attempt has been made to flip a surface that is not flippable. + */ +#define DDERR_NOTFLIPPABLE MAKE_DDHRESULT( 582 ) + +/* + * Can't duplicate primary & 3D surfaces, or surfaces that are implicitly + * created. + */ +#define DDERR_CANTDUPLICATE MAKE_DDHRESULT( 583 ) + +/* + * Surface was not locked. An attempt to unlock a surface that was not + * locked at all, or by this process, has been attempted. + */ +#define DDERR_NOTLOCKED MAKE_DDHRESULT( 584 ) + +/* + * Windows can not create any more DCs + */ +#define DDERR_CANTCREATEDC MAKE_DDHRESULT( 585 ) + +/* + * No DC was ever created for this surface. + */ +#define DDERR_NODC MAKE_DDHRESULT( 586 ) + +/* + * This surface can not be restored because it was created in a different + * mode. + */ +#define DDERR_WRONGMODE MAKE_DDHRESULT( 587 ) + +/* + * This surface can not be restored because it is an implicitly created + * surface. + */ +#define DDERR_IMPLICITLYCREATED MAKE_DDHRESULT( 588 ) + +/* + * The surface being used is not a palette-based surface + */ +#define DDERR_NOTPALETTIZED MAKE_DDHRESULT( 589 ) + + +/* + * The display is currently in an unsupported mode + */ +#define DDERR_UNSUPPORTEDMODE MAKE_DDHRESULT( 590 ) + +/* + * Operation could not be carried out because there is no mip-map + * texture mapping hardware present or available. + */ +#define DDERR_NOMIPMAPHW MAKE_DDHRESULT( 591 ) + +/* + * The requested action could not be performed because the surface was of + * the wrong type. + */ +#define DDERR_INVALIDSURFACETYPE MAKE_DDHRESULT( 592 ) + + + +/* + * Device does not support optimized surfaces, therefore no video memory optimized surfaces + */ +#define DDERR_NOOPTIMIZEHW MAKE_DDHRESULT( 600 ) + +/* + * Surface is an optimized surface, but has not yet been allocated any memory + */ +#define DDERR_NOTLOADED MAKE_DDHRESULT( 601 ) + +/* + * A DC has already been returned for this surface. Only one DC can be + * retrieved per surface. + */ +#define DDERR_DCALREADYCREATED MAKE_DDHRESULT( 620 ) + +/* + * An attempt was made to allocate non-local video memory from a device + * that does not support non-local video memory. + */ +#define DDERR_NONONLOCALVIDMEM MAKE_DDHRESULT( 630 ) + +/* + * The attempt to page lock a surface failed. + */ +#define DDERR_CANTPAGELOCK MAKE_DDHRESULT( 640 ) + +/* + * The attempt to page unlock a surface failed. + */ +#define DDERR_CANTPAGEUNLOCK MAKE_DDHRESULT( 660 ) + +/* + * An attempt was made to page unlock a surface with no outstanding page locks. + */ +#define DDERR_NOTPAGELOCKED MAKE_DDHRESULT( 680 ) + +/* + * There is more data available than the specified buffer size could hold + */ +#define DDERR_MOREDATA MAKE_DDHRESULT( 690 ) + +/* + * The video port is not active + */ +#define DDERR_VIDEONOTACTIVE MAKE_DDHRESULT( 695 ) + +/* + * Surfaces created by one direct draw device cannot be used directly by + * another direct draw device. + */ +#define DDERR_DEVICEDOESNTOWNSURFACE MAKE_DDHRESULT( 699 ) + + +/* + * An attempt was made to invoke an interface member of a DirectDraw object + * created by CoCreateInstance() before it was initialized. + */ +#define DDERR_NOTINITIALIZED CO_E_NOTINITIALIZED + +/* Alpha bit depth constants */ + + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/3rdparty/dx5/inc/dinput.h b/3rdparty/dx5/inc/dinput.h new file mode 100644 index 00000000..5bf9f5ae --- /dev/null +++ b/3rdparty/dx5/inc/dinput.h @@ -0,0 +1,1849 @@ +/**************************************************************************** + * + * Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved. + * + * File: dinput.h + * Content: DirectInput include file + * + ****************************************************************************/ + +#ifndef __DINPUT_INCLUDED__ +#define __DINPUT_INCLUDED__ + +#ifndef DIJ_RINGZERO + +#ifdef _WIN32 +#define COM_NO_WINDOWS_H +#include +#endif + +#endif /* DIJ_RINGZERO */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef DIRECTINPUT_VERSION +#define DIRECTINPUT_VERSION 0x0500 +#endif + +#ifndef DIJ_RINGZERO +/**************************************************************************** + * + * Class IDs + * + ****************************************************************************/ + +DEFINE_GUID(CLSID_DirectInput, 0x25E609E0,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(CLSID_DirectInputDevice,0x25E609E1,0xB259,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/**************************************************************************** + * + * Interfaces + * + ****************************************************************************/ + +DEFINE_GUID(IID_IDirectInputA, 0x89521360,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputW, 0x89521361,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput2A, 0x5944E662,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInput2W, 0x5944E663,0xAA8A,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +DEFINE_GUID(IID_IDirectInputDeviceA, 0x5944E680,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDeviceW, 0x5944E681,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice2A,0x5944E682,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(IID_IDirectInputDevice2W,0x5944E683,0xC92E,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +DEFINE_GUID(IID_IDirectInputEffect, 0xE7E1F7C0,0x88D2,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); + +/**************************************************************************** + * + * Predefined object types + * + ****************************************************************************/ + +DEFINE_GUID(GUID_XAxis, 0xA36D02E0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_YAxis, 0xA36D02E1,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_ZAxis, 0xA36D02E2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RxAxis, 0xA36D02F4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RyAxis, 0xA36D02F5,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_RzAxis, 0xA36D02E3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Slider, 0xA36D02E4,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +DEFINE_GUID(GUID_Button, 0xA36D02F0,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Key, 0x55728220,0xD33C,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +DEFINE_GUID(GUID_POV, 0xA36D02F2,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +DEFINE_GUID(GUID_Unknown, 0xA36D02F3,0xC9F3,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/**************************************************************************** + * + * Predefined product GUIDs + * + ****************************************************************************/ + +DEFINE_GUID(GUID_SysMouse, 0x6F1D2B60,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_SysKeyboard,0x6F1D2B61,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); +DEFINE_GUID(GUID_Joystick ,0x6F1D2B70,0xD5A0,0x11CF,0xBF,0xC7,0x44,0x45,0x53,0x54,0x00,0x00); + +/**************************************************************************** + * + * Predefined force feedback effects + * + ****************************************************************************/ + +DEFINE_GUID(GUID_ConstantForce,0x13541C20,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_RampForce, 0x13541C21,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Square, 0x13541C22,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Sine, 0x13541C23,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Triangle, 0x13541C24,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_SawtoothUp, 0x13541C25,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_SawtoothDown, 0x13541C26,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Spring, 0x13541C27,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Damper, 0x13541C28,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Inertia, 0x13541C29,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_Friction, 0x13541C2A,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); +DEFINE_GUID(GUID_CustomForce, 0x13541C2B,0x8E33,0x11D0,0x9A,0xD0,0x00,0xA0,0xC9,0xA0,0x6E,0x35); + + +#endif /* DIJ_RINGZERO */ + +/**************************************************************************** + * + * Interfaces and Structures... + * + ****************************************************************************/ + +#if(DIRECTINPUT_VERSION >= 0x0500) + +/**************************************************************************** + * + * IDirectInputEffect + * + ****************************************************************************/ + +#define DIEFT_ALL 0x00000000 + +#define DIEFT_CONSTANTFORCE 0x00000001 +#define DIEFT_RAMPFORCE 0x00000002 +#define DIEFT_PERIODIC 0x00000003 +#define DIEFT_CONDITION 0x00000004 +#define DIEFT_CUSTOMFORCE 0x00000005 +#define DIEFT_HARDWARE 0x000000FF + +#define DIEFT_FFATTACK 0x00000200 +#define DIEFT_FFFADE 0x00000400 +#define DIEFT_SATURATION 0x00000800 +#define DIEFT_POSNEGCOEFFICIENTS 0x00001000 +#define DIEFT_POSNEGSATURATION 0x00002000 +#define DIEFT_DEADBAND 0x00004000 + +#define DIEFT_GETTYPE(n) LOBYTE(n) + +#define DI_DEGREES 100 +#define DI_FFNOMINALMAX 10000 +#define DI_SECONDS 1000000 + +typedef struct DICONSTANTFORCE { + LONG lMagnitude; +} DICONSTANTFORCE, *LPDICONSTANTFORCE; +typedef const DICONSTANTFORCE *LPCDICONSTANTFORCE; + +typedef struct DIRAMPFORCE { + LONG lStart; + LONG lEnd; +} DIRAMPFORCE, *LPDIRAMPFORCE; +typedef const DIRAMPFORCE *LPCDIRAMPFORCE; + +typedef struct DIPERIODIC { + DWORD dwMagnitude; + LONG lOffset; + DWORD dwPhase; + DWORD dwPeriod; +} DIPERIODIC, *LPDIPERIODIC; +typedef const DIPERIODIC *LPCDIPERIODIC; + +typedef struct DICONDITION { + LONG lOffset; + LONG lPositiveCoefficient; + LONG lNegativeCoefficient; + DWORD dwPositiveSaturation; + DWORD dwNegativeSaturation; + LONG lDeadBand; +} DICONDITION, *LPDICONDITION; +typedef const DICONDITION *LPCDICONDITION; + +typedef struct DICUSTOMFORCE { + DWORD cChannels; + DWORD dwSamplePeriod; + DWORD cSamples; + LPLONG rglForceData; +} DICUSTOMFORCE, *LPDICUSTOMFORCE; +typedef const DICUSTOMFORCE *LPCDICUSTOMFORCE; + +typedef struct DIENVELOPE { + DWORD dwSize; /* sizeof(DIENVELOPE) */ + DWORD dwAttackLevel; + DWORD dwAttackTime; /* Microseconds */ + DWORD dwFadeLevel; + DWORD dwFadeTime; /* Microseconds */ +} DIENVELOPE, *LPDIENVELOPE; +typedef const DIENVELOPE *LPCDIENVELOPE; + +typedef struct DIEFFECT { + DWORD dwSize; /* sizeof(DIEFFECT) */ + DWORD dwFlags; /* DIEFF_* */ + DWORD dwDuration; /* Microseconds */ + DWORD dwSamplePeriod; /* Microseconds */ + DWORD dwGain; + DWORD dwTriggerButton; /* or DIEB_NOTRIGGER */ + DWORD dwTriggerRepeatInterval; /* Microseconds */ + DWORD cAxes; /* Number of axes */ + LPDWORD rgdwAxes; /* Array of axes */ + LPLONG rglDirection; /* Array of directions */ + LPDIENVELOPE lpEnvelope; /* Optional */ + DWORD cbTypeSpecificParams; /* Size of params */ + LPVOID lpvTypeSpecificParams; /* Pointer to params */ +} DIEFFECT, *LPDIEFFECT; +typedef const DIEFFECT *LPCDIEFFECT; + +#define DIEFF_OBJECTIDS 0x00000001 +#define DIEFF_OBJECTOFFSETS 0x00000002 +#define DIEFF_CARTESIAN 0x00000010 +#define DIEFF_POLAR 0x00000020 +#define DIEFF_SPHERICAL 0x00000040 + +#define DIEP_DURATION 0x00000001 +#define DIEP_SAMPLEPERIOD 0x00000002 +#define DIEP_GAIN 0x00000004 +#define DIEP_TRIGGERBUTTON 0x00000008 +#define DIEP_TRIGGERREPEATINTERVAL 0x00000010 +#define DIEP_AXES 0x00000020 +#define DIEP_DIRECTION 0x00000040 +#define DIEP_ENVELOPE 0x00000080 +#define DIEP_TYPESPECIFICPARAMS 0x00000100 +#define DIEP_ALLPARAMS 0x000001FF +#define DIEP_START 0x20000000 +#define DIEP_NORESTART 0x40000000 +#define DIEP_NODOWNLOAD 0x80000000 +#define DIEB_NOTRIGGER 0xFFFFFFFF + +#define DIES_SOLO 0x00000001 +#define DIES_NODOWNLOAD 0x80000000 + +#define DIEGES_PLAYING 0x00000001 +#define DIEGES_EMULATED 0x00000002 + +typedef struct DIEFFESCAPE { + DWORD dwSize; + DWORD dwCommand; + LPVOID lpvInBuffer; + DWORD cbInBuffer; + LPVOID lpvOutBuffer; + DWORD cbOutBuffer; +} DIEFFESCAPE, *LPDIEFFESCAPE; + +#ifndef DIJ_RINGZERO + +#undef INTERFACE +#define INTERFACE IDirectInputEffect + +DECLARE_INTERFACE_(IDirectInputEffect, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IDirectInputEffect methods ***/ + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD,REFGUID) PURE; + STDMETHOD(GetEffectGuid)(THIS_ LPGUID) PURE; + STDMETHOD(GetParameters)(THIS_ LPDIEFFECT,DWORD) PURE; + STDMETHOD(SetParameters)(THIS_ LPCDIEFFECT,DWORD) PURE; + STDMETHOD(Start)(THIS_ DWORD,DWORD) PURE; + STDMETHOD(Stop)(THIS) PURE; + STDMETHOD(GetEffectStatus)(THIS_ LPDWORD) PURE; + STDMETHOD(Download)(THIS) PURE; + STDMETHOD(Unload)(THIS) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE) PURE; +}; + +typedef struct IDirectInputEffect *LPDIRECTINPUTEFFECT; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectInputEffect_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputEffect_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputEffect_Release(p) (p)->lpVtbl->Release(p) +#define IDirectInputEffect_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#define IDirectInputEffect_GetEffectGuid(p,a) (p)->lpVtbl->GetEffectGuid(p,a) +#define IDirectInputEffect_GetParameters(p,a,b) (p)->lpVtbl->GetParameters(p,a,b) +#define IDirectInputEffect_SetParameters(p,a,b) (p)->lpVtbl->SetParameters(p,a,b) +#define IDirectInputEffect_Start(p,a,b) (p)->lpVtbl->Start(p,a,b) +#define IDirectInputEffect_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectInputEffect_GetEffectStatus(p,a) (p)->lpVtbl->GetEffectStatus(p,a) +#define IDirectInputEffect_Download(p) (p)->lpVtbl->Download(p) +#define IDirectInputEffect_Unload(p) (p)->lpVtbl->Unload(p) +#define IDirectInputEffect_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#else +#define IDirectInputEffect_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputEffect_AddRef(p) (p)->AddRef() +#define IDirectInputEffect_Release(p) (p)->Release() +#define IDirectInputEffect_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +#define IDirectInputEffect_GetEffectGuid(p,a) (p)->GetEffectGuid(a) +#define IDirectInputEffect_GetParameters(p,a,b) (p)->GetParameters(a,b) +#define IDirectInputEffect_SetParameters(p,a,b) (p)->SetParameters(a,b) +#define IDirectInputEffect_Start(p,a,b) (p)->Start(a,b) +#define IDirectInputEffect_Stop(p) (p)->Stop() +#define IDirectInputEffect_GetEffectStatus(p,a) (p)->GetEffectStatus(a) +#define IDirectInputEffect_Download(p) (p)->Download() +#define IDirectInputEffect_Unload(p) (p)->Unload() +#define IDirectInputEffect_Escape(p,a) (p)->Escape(a) +#endif + +#endif /* DIJ_RINGZERO */ + +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +/**************************************************************************** + * + * IDirectInputDevice + * + ****************************************************************************/ + +#define DIDEVTYPE_DEVICE 1 +#define DIDEVTYPE_MOUSE 2 +#define DIDEVTYPE_KEYBOARD 3 +#define DIDEVTYPE_JOYSTICK 4 +#define DIDEVTYPE_HID 0x00010000 + +#define DIDEVTYPEMOUSE_UNKNOWN 1 +#define DIDEVTYPEMOUSE_TRADITIONAL 2 +#define DIDEVTYPEMOUSE_FINGERSTICK 3 +#define DIDEVTYPEMOUSE_TOUCHPAD 4 +#define DIDEVTYPEMOUSE_TRACKBALL 5 + +#define DIDEVTYPEKEYBOARD_UNKNOWN 0 +#define DIDEVTYPEKEYBOARD_PCXT 1 +#define DIDEVTYPEKEYBOARD_OLIVETTI 2 +#define DIDEVTYPEKEYBOARD_PCAT 3 +#define DIDEVTYPEKEYBOARD_PCENH 4 +#define DIDEVTYPEKEYBOARD_NOKIA1050 5 +#define DIDEVTYPEKEYBOARD_NOKIA9140 6 +#define DIDEVTYPEKEYBOARD_NEC98 7 +#define DIDEVTYPEKEYBOARD_NEC98LAPTOP 8 +#define DIDEVTYPEKEYBOARD_NEC98106 9 +#define DIDEVTYPEKEYBOARD_JAPAN106 10 +#define DIDEVTYPEKEYBOARD_JAPANAX 11 +#define DIDEVTYPEKEYBOARD_J3100 12 + +#define DIDEVTYPEJOYSTICK_UNKNOWN 1 +#define DIDEVTYPEJOYSTICK_TRADITIONAL 2 +#define DIDEVTYPEJOYSTICK_FLIGHTSTICK 3 +#define DIDEVTYPEJOYSTICK_GAMEPAD 4 +#define DIDEVTYPEJOYSTICK_RUDDER 5 +#define DIDEVTYPEJOYSTICK_WHEEL 6 +#define DIDEVTYPEJOYSTICK_HEADTRACKER 7 + +#define GET_DIDEVICE_TYPE(dwDevType) LOBYTE(dwDevType) +#define GET_DIDEVICE_SUBTYPE(dwDevType) HIBYTE(dwDevType) + +#if(DIRECTINPUT_VERSION >= 0x0500) +/* This structure is defined for DirectX 3.0 compatibility */ + +typedef struct DIDEVCAPS_DX3 { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; +} DIDEVCAPS_DX3, *LPDIDEVCAPS_DX3; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +typedef struct DIDEVCAPS { + DWORD dwSize; + DWORD dwFlags; + DWORD dwDevType; + DWORD dwAxes; + DWORD dwButtons; + DWORD dwPOVs; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFSamplePeriod; + DWORD dwFFMinTimeResolution; + DWORD dwFirmwareRevision; + DWORD dwHardwareRevision; + DWORD dwFFDriverVersion; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVCAPS, *LPDIDEVCAPS; + +#define DIDC_ATTACHED 0x00000001 +#define DIDC_POLLEDDEVICE 0x00000002 +#define DIDC_EMULATED 0x00000004 +#define DIDC_POLLEDDATAFORMAT 0x00000008 +#if(DIRECTINPUT_VERSION >= 0x0500) +#define DIDC_FORCEFEEDBACK 0x00000100 +#define DIDC_FFATTACK 0x00000200 +#define DIDC_FFFADE 0x00000400 +#define DIDC_SATURATION 0x00000800 +#define DIDC_POSNEGCOEFFICIENTS 0x00001000 +#define DIDC_POSNEGSATURATION 0x00002000 +#define DIDC_DEADBAND 0x00004000 +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +#define DIDFT_ALL 0x00000000 + +#define DIDFT_RELAXIS 0x00000001 +#define DIDFT_ABSAXIS 0x00000002 +#define DIDFT_AXIS 0x00000003 + +#define DIDFT_PSHBUTTON 0x00000004 +#define DIDFT_TGLBUTTON 0x00000008 +#define DIDFT_BUTTON 0x0000000C + +#define DIDFT_POV 0x00000010 + +#define DIDFT_COLLECTION 0x00000040 +#define DIDFT_NODATA 0x00000080 + +#define DIDFT_ANYINSTANCE 0x00FFFF00 +#define DIDFT_INSTANCEMASK DIDFT_ANYINSTANCE +#define DIDFT_MAKEINSTANCE(n) ((WORD)(n) << 8) +#define DIDFT_GETTYPE(n) LOBYTE(n) +#define DIDFT_GETINSTANCE(n) LOWORD((n) >> 8) +#define DIDFT_FFACTUATOR 0x01000000 +#define DIDFT_FFEFFECTTRIGGER 0x02000000 + +#define DIDFT_ENUMCOLLECTION(n) ((WORD)(n) << 8) +#define DIDFT_NOCOLLECTION 0x00FFFF00 + + +#ifndef DIJ_RINGZERO + +typedef struct _DIOBJECTDATAFORMAT { + const GUID *pguid; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; +} DIOBJECTDATAFORMAT, *LPDIOBJECTDATAFORMAT; +typedef const DIOBJECTDATAFORMAT *LPCDIOBJECTDATAFORMAT; + +typedef struct _DIDATAFORMAT { + DWORD dwSize; + DWORD dwObjSize; + DWORD dwFlags; + DWORD dwDataSize; + DWORD dwNumObjs; + LPDIOBJECTDATAFORMAT rgodf; +} DIDATAFORMAT, *LPDIDATAFORMAT; +typedef const DIDATAFORMAT *LPCDIDATAFORMAT; + +#define DIDF_ABSAXIS 0x00000001 +#define DIDF_RELAXIS 0x00000002 + +extern const DIDATAFORMAT c_dfDIMouse; +extern const DIDATAFORMAT c_dfDIKeyboard; +extern const DIDATAFORMAT c_dfDIJoystick; +extern const DIDATAFORMAT c_dfDIJoystick2; + +#if(DIRECTINPUT_VERSION >= 0x0500) +/* These structures are defined for DirectX 3.0 compatibility */ + +typedef struct DIDEVICEOBJECTINSTANCE_DX3A { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + CHAR tszName[MAX_PATH]; +} DIDEVICEOBJECTINSTANCE_DX3A, *LPDIDEVICEOBJECTINSTANCE_DX3A; +typedef struct DIDEVICEOBJECTINSTANCE_DX3W { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + WCHAR tszName[MAX_PATH]; +} DIDEVICEOBJECTINSTANCE_DX3W, *LPDIDEVICEOBJECTINSTANCE_DX3W; +#ifdef UNICODE +typedef DIDEVICEOBJECTINSTANCE_DX3W DIDEVICEOBJECTINSTANCE_DX3; +typedef LPDIDEVICEOBJECTINSTANCE_DX3W LPDIDEVICEOBJECTINSTANCE_DX3; +#else +typedef DIDEVICEOBJECTINSTANCE_DX3A DIDEVICEOBJECTINSTANCE_DX3; +typedef LPDIDEVICEOBJECTINSTANCE_DX3A LPDIDEVICEOBJECTINSTANCE_DX3; +#endif // UNICODE +typedef const DIDEVICEOBJECTINSTANCE_DX3A *LPCDIDEVICEOBJECTINSTANCE_DX3A; +typedef const DIDEVICEOBJECTINSTANCE_DX3W *LPCDIDEVICEOBJECTINSTANCE_DX3W; +typedef const DIDEVICEOBJECTINSTANCE_DX3 *LPCDIDEVICEOBJECTINSTANCE_DX3; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +typedef struct DIDEVICEOBJECTINSTANCEA { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + CHAR tszName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFMaxForce; + DWORD dwFFForceResolution; + WORD wCollectionNumber; + WORD wDesignatorIndex; + WORD wUsagePage; + WORD wUsage; + DWORD dwDimension; + WORD wExponent; + WORD wReserved; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEOBJECTINSTANCEA, *LPDIDEVICEOBJECTINSTANCEA; +typedef struct DIDEVICEOBJECTINSTANCEW { + DWORD dwSize; + GUID guidType; + DWORD dwOfs; + DWORD dwType; + DWORD dwFlags; + WCHAR tszName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + DWORD dwFFMaxForce; + DWORD dwFFForceResolution; + WORD wCollectionNumber; + WORD wDesignatorIndex; + WORD wUsagePage; + WORD wUsage; + DWORD dwDimension; + WORD wExponent; + WORD wReserved; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEOBJECTINSTANCEW, *LPDIDEVICEOBJECTINSTANCEW; +#ifdef UNICODE +typedef DIDEVICEOBJECTINSTANCEW DIDEVICEOBJECTINSTANCE; +typedef LPDIDEVICEOBJECTINSTANCEW LPDIDEVICEOBJECTINSTANCE; +#else +typedef DIDEVICEOBJECTINSTANCEA DIDEVICEOBJECTINSTANCE; +typedef LPDIDEVICEOBJECTINSTANCEA LPDIDEVICEOBJECTINSTANCE; +#endif // UNICODE +typedef const DIDEVICEOBJECTINSTANCEA *LPCDIDEVICEOBJECTINSTANCEA; +typedef const DIDEVICEOBJECTINSTANCEW *LPCDIDEVICEOBJECTINSTANCEW; +typedef const DIDEVICEOBJECTINSTANCE *LPCDIDEVICEOBJECTINSTANCE; + +typedef BOOL (FAR PASCAL * LPDIENUMDEVICEOBJECTSCALLBACKA)(LPCDIDEVICEOBJECTINSTANCEA, LPVOID); +typedef BOOL (FAR PASCAL * LPDIENUMDEVICEOBJECTSCALLBACKW)(LPCDIDEVICEOBJECTINSTANCEW, LPVOID); +#ifdef UNICODE +#define LPDIENUMDEVICEOBJECTSCALLBACK LPDIENUMDEVICEOBJECTSCALLBACKW +#else +#define LPDIENUMDEVICEOBJECTSCALLBACK LPDIENUMDEVICEOBJECTSCALLBACKA +#endif // !UNICODE + +#if(DIRECTINPUT_VERSION >= 0x0500) +#define DIDOI_FFACTUATOR 0x00000001 +#define DIDOI_FFEFFECTTRIGGER 0x00000002 +#define DIDOI_POLLED 0x00008000 +#define DIDOI_ASPECTPOSITION 0x00000100 +#define DIDOI_ASPECTVELOCITY 0x00000200 +#define DIDOI_ASPECTACCEL 0x00000300 +#define DIDOI_ASPECTFORCE 0x00000400 +#define DIDOI_ASPECTMASK 0x00000F00 +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +typedef struct DIPROPHEADER { + DWORD dwSize; + DWORD dwHeaderSize; + DWORD dwObj; + DWORD dwHow; +} DIPROPHEADER, *LPDIPROPHEADER; +typedef const DIPROPHEADER *LPCDIPROPHEADER; + +#define DIPH_DEVICE 0 +#define DIPH_BYOFFSET 1 +#define DIPH_BYID 2 + +typedef struct DIPROPDWORD { + DIPROPHEADER diph; + DWORD dwData; +} DIPROPDWORD, *LPDIPROPDWORD; +typedef const DIPROPDWORD *LPCDIPROPDWORD; + +typedef struct DIPROPRANGE { + DIPROPHEADER diph; + LONG lMin; + LONG lMax; +} DIPROPRANGE, *LPDIPROPRANGE; +typedef const DIPROPRANGE *LPCDIPROPRANGE; + +#define DIPROPRANGE_NOMIN ((LONG)0x80000000) +#define DIPROPRANGE_NOMAX ((LONG)0x7FFFFFFF) + +#ifdef __cplusplus +#define MAKEDIPROP(prop) (*(const GUID *)(prop)) +#else +#define MAKEDIPROP(prop) ((REFGUID)(prop)) +#endif + +#define DIPROP_BUFFERSIZE MAKEDIPROP(1) + +#define DIPROP_AXISMODE MAKEDIPROP(2) + +#define DIPROPAXISMODE_ABS 0 +#define DIPROPAXISMODE_REL 1 + +#define DIPROP_GRANULARITY MAKEDIPROP(3) + +#define DIPROP_RANGE MAKEDIPROP(4) + +#define DIPROP_DEADZONE MAKEDIPROP(5) + +#define DIPROP_SATURATION MAKEDIPROP(6) + +#define DIPROP_FFGAIN MAKEDIPROP(7) + +#define DIPROP_FFLOAD MAKEDIPROP(8) + +#define DIPROP_AUTOCENTER MAKEDIPROP(9) + +#define DIPROPAUTOCENTER_OFF 0 +#define DIPROPAUTOCENTER_ON 1 + +#define DIPROP_CALIBRATIONMODE MAKEDIPROP(10) + +#define DIPROPCALIBRATIONMODE_COOKED 0 +#define DIPROPCALIBRATIONMODE_RAW 1 + +typedef struct DIDEVICEOBJECTDATA { + DWORD dwOfs; + DWORD dwData; + DWORD dwTimeStamp; + DWORD dwSequence; +} DIDEVICEOBJECTDATA, *LPDIDEVICEOBJECTDATA; +typedef const DIDEVICEOBJECTDATA *LPCDIDEVICEOBJECTDATA; + +#define DIGDD_PEEK 0x00000001 + +#define DISEQUENCE_COMPARE(dwSequence1, cmp, dwSequence2) \ + ((int)((dwSequence1) - (dwSequence2)) cmp 0) +#define DISCL_EXCLUSIVE 0x00000001 +#define DISCL_NONEXCLUSIVE 0x00000002 +#define DISCL_FOREGROUND 0x00000004 +#define DISCL_BACKGROUND 0x00000008 + +#if(DIRECTINPUT_VERSION >= 0x0500) +/* These structures are defined for DirectX 3.0 compatibility */ + +typedef struct DIDEVICEINSTANCE_DX3A { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + CHAR tszInstanceName[MAX_PATH]; + CHAR tszProductName[MAX_PATH]; +} DIDEVICEINSTANCE_DX3A, *LPDIDEVICEINSTANCE_DX3A; +typedef struct DIDEVICEINSTANCE_DX3W { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + WCHAR tszInstanceName[MAX_PATH]; + WCHAR tszProductName[MAX_PATH]; +} DIDEVICEINSTANCE_DX3W, *LPDIDEVICEINSTANCE_DX3W; +#ifdef UNICODE +typedef DIDEVICEINSTANCE_DX3W DIDEVICEINSTANCE_DX3; +typedef LPDIDEVICEINSTANCE_DX3W LPDIDEVICEINSTANCE_DX3; +#else +typedef DIDEVICEINSTANCE_DX3A DIDEVICEINSTANCE_DX3; +typedef LPDIDEVICEINSTANCE_DX3A LPDIDEVICEINSTANCE_DX3; +#endif // UNICODE +typedef const DIDEVICEINSTANCE_DX3A *LPCDIDEVICEINSTANCE_DX3A; +typedef const DIDEVICEINSTANCE_DX3W *LPCDIDEVICEINSTANCE_DX3W; +typedef const DIDEVICEINSTANCE_DX3 *LPCDIDEVICEINSTANCE_DX3; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +typedef struct DIDEVICEINSTANCEA { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + CHAR tszInstanceName[MAX_PATH]; + CHAR tszProductName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + GUID guidFFDriver; + WORD wUsagePage; + WORD wUsage; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEINSTANCEA, *LPDIDEVICEINSTANCEA; +typedef struct DIDEVICEINSTANCEW { + DWORD dwSize; + GUID guidInstance; + GUID guidProduct; + DWORD dwDevType; + WCHAR tszInstanceName[MAX_PATH]; + WCHAR tszProductName[MAX_PATH]; +#if(DIRECTINPUT_VERSION >= 0x0500) + GUID guidFFDriver; + WORD wUsagePage; + WORD wUsage; +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ +} DIDEVICEINSTANCEW, *LPDIDEVICEINSTANCEW; +#ifdef UNICODE +typedef DIDEVICEINSTANCEW DIDEVICEINSTANCE; +typedef LPDIDEVICEINSTANCEW LPDIDEVICEINSTANCE; +#else +typedef DIDEVICEINSTANCEA DIDEVICEINSTANCE; +typedef LPDIDEVICEINSTANCEA LPDIDEVICEINSTANCE; +#endif // UNICODE +typedef const DIDEVICEINSTANCEA *LPCDIDEVICEINSTANCEA; +typedef const DIDEVICEINSTANCEW *LPCDIDEVICEINSTANCEW; +typedef const DIDEVICEINSTANCE *LPCDIDEVICEINSTANCE; + +#undef INTERFACE +#define INTERFACE IDirectInputDeviceW + +DECLARE_INTERFACE_(IDirectInputDeviceW, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW,LPVOID,DWORD) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID,LPDIPROPHEADER) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID,LPCDIPROPHEADER) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD,LPVOID) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD,LPDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW,DWORD,DWORD) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD,REFGUID) PURE; +}; + +typedef struct IDirectInputDeviceW *LPDIRECTINPUTDEVICEW; + +#undef INTERFACE +#define INTERFACE IDirectInputDeviceA + +DECLARE_INTERFACE_(IDirectInputDeviceA, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA,LPVOID,DWORD) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID,LPDIPROPHEADER) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID,LPCDIPROPHEADER) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD,LPVOID) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD,LPDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA,DWORD,DWORD) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD,REFGUID) PURE; +}; + +typedef struct IDirectInputDeviceA *LPDIRECTINPUTDEVICEA; + +#ifdef UNICODE +#define IID_IDirectInputDevice IID_IDirectInputDeviceW +#define IDirectInputDevice IDirectInputDeviceW +#define IDirectInputDeviceVtbl IDirectInputDeviceWVtbl +#else +#define IID_IDirectInputDevice IID_IDirectInputDeviceA +#define IDirectInputDevice IDirectInputDeviceA +#define IDirectInputDeviceVtbl IDirectInputDeviceAVtbl +#endif +typedef struct IDirectInputDevice *LPDIRECTINPUTDEVICE; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectInputDevice_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice_Release(p) (p)->lpVtbl->Release(p) +#define IDirectInputDevice_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#else +#define IDirectInputDevice_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice_AddRef(p) (p)->AddRef() +#define IDirectInputDevice_Release(p) (p)->Release() +#define IDirectInputDevice_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice_Acquire(p) (p)->Acquire() +#define IDirectInputDevice_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +#endif + +#endif /* DIJ_RINGZERO */ + + +#if(DIRECTINPUT_VERSION >= 0x0500) + +#define DISFFC_RESET 0x00000001 +#define DISFFC_STOPALL 0x00000002 +#define DISFFC_PAUSE 0x00000004 +#define DISFFC_CONTINUE 0x00000008 +#define DISFFC_SETACTUATORSON 0x00000010 +#define DISFFC_SETACTUATORSOFF 0x00000020 + +#define DIGFFS_EMPTY 0x00000001 +#define DIGFFS_STOPPED 0x00000002 +#define DIGFFS_PAUSED 0x00000004 +#define DIGFFS_ACTUATORSON 0x00000010 +#define DIGFFS_ACTUATORSOFF 0x00000020 +#define DIGFFS_POWERON 0x00000040 +#define DIGFFS_POWEROFF 0x00000080 +#define DIGFFS_SAFETYSWITCHON 0x00000100 +#define DIGFFS_SAFETYSWITCHOFF 0x00000200 +#define DIGFFS_USERFFSWITCHON 0x00000400 +#define DIGFFS_USERFFSWITCHOFF 0x00000800 +#define DIGFFS_DEVICELOST 0x80000000 + +#ifndef DIJ_RINGZERO + +typedef struct DIEFFECTINFOA { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + CHAR tszName[MAX_PATH]; +} DIEFFECTINFOA, *LPDIEFFECTINFOA; +typedef struct DIEFFECTINFOW { + DWORD dwSize; + GUID guid; + DWORD dwEffType; + DWORD dwStaticParams; + DWORD dwDynamicParams; + WCHAR tszName[MAX_PATH]; +} DIEFFECTINFOW, *LPDIEFFECTINFOW; +#ifdef UNICODE +typedef DIEFFECTINFOW DIEFFECTINFO; +typedef LPDIEFFECTINFOW LPDIEFFECTINFO; +#else +typedef DIEFFECTINFOA DIEFFECTINFO; +typedef LPDIEFFECTINFOA LPDIEFFECTINFO; +#endif // UNICODE +typedef const DIEFFECTINFOA *LPCDIEFFECTINFOA; +typedef const DIEFFECTINFOW *LPCDIEFFECTINFOW; +typedef const DIEFFECTINFO *LPCDIEFFECTINFO; + +typedef BOOL (FAR PASCAL * LPDIENUMEFFECTSCALLBACKA)(LPCDIEFFECTINFOA, LPVOID); +typedef BOOL (FAR PASCAL * LPDIENUMEFFECTSCALLBACKW)(LPCDIEFFECTINFOW, LPVOID); +#ifdef UNICODE +#define LPDIENUMEFFECTSCALLBACK LPDIENUMEFFECTSCALLBACKW +#else +#define LPDIENUMEFFECTSCALLBACK LPDIENUMEFFECTSCALLBACKA +#endif // !UNICODE +typedef BOOL (FAR PASCAL * LPDIENUMCREATEDEFFECTOBJECTSCALLBACK)(LPDIRECTINPUTEFFECT, LPVOID); + +#undef INTERFACE +#define INTERFACE IDirectInputDevice2W + +DECLARE_INTERFACE_(IDirectInputDevice2W, IDirectInputDeviceW) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IDirectInputDeviceW methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKW,LPVOID,DWORD) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID,LPDIPROPHEADER) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID,LPCDIPROPHEADER) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD,LPVOID) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD,LPDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEW,DWORD,DWORD) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEW) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD,REFGUID) PURE; + + /*** IDirectInputDevice2W methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID,LPCDIEFFECT,LPDIRECTINPUTEFFECT *,LPUNKNOWN) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKW,LPVOID,DWORD) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOW,REFGUID) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD,LPDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE; +}; + +typedef struct IDirectInputDevice2W *LPDIRECTINPUTDEVICE2W; + +#undef INTERFACE +#define INTERFACE IDirectInputDevice2A + +DECLARE_INTERFACE_(IDirectInputDevice2A, IDirectInputDeviceA) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IDirectInputDeviceA methods ***/ + STDMETHOD(GetCapabilities)(THIS_ LPDIDEVCAPS) PURE; + STDMETHOD(EnumObjects)(THIS_ LPDIENUMDEVICEOBJECTSCALLBACKA,LPVOID,DWORD) PURE; + STDMETHOD(GetProperty)(THIS_ REFGUID,LPDIPROPHEADER) PURE; + STDMETHOD(SetProperty)(THIS_ REFGUID,LPCDIPROPHEADER) PURE; + STDMETHOD(Acquire)(THIS) PURE; + STDMETHOD(Unacquire)(THIS) PURE; + STDMETHOD(GetDeviceState)(THIS_ DWORD,LPVOID) PURE; + STDMETHOD(GetDeviceData)(THIS_ DWORD,LPDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE; + STDMETHOD(SetDataFormat)(THIS_ LPCDIDATAFORMAT) PURE; + STDMETHOD(SetEventNotification)(THIS_ HANDLE) PURE; + STDMETHOD(SetCooperativeLevel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(GetObjectInfo)(THIS_ LPDIDEVICEOBJECTINSTANCEA,DWORD,DWORD) PURE; + STDMETHOD(GetDeviceInfo)(THIS_ LPDIDEVICEINSTANCEA) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD,REFGUID) PURE; + + /*** IDirectInputDevice2A methods ***/ + STDMETHOD(CreateEffect)(THIS_ REFGUID,LPCDIEFFECT,LPDIRECTINPUTEFFECT *,LPUNKNOWN) PURE; + STDMETHOD(EnumEffects)(THIS_ LPDIENUMEFFECTSCALLBACKA,LPVOID,DWORD) PURE; + STDMETHOD(GetEffectInfo)(THIS_ LPDIEFFECTINFOA,REFGUID) PURE; + STDMETHOD(GetForceFeedbackState)(THIS_ LPDWORD) PURE; + STDMETHOD(SendForceFeedbackCommand)(THIS_ DWORD) PURE; + STDMETHOD(EnumCreatedEffectObjects)(THIS_ LPDIENUMCREATEDEFFECTOBJECTSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(Escape)(THIS_ LPDIEFFESCAPE) PURE; + STDMETHOD(Poll)(THIS) PURE; + STDMETHOD(SendDeviceData)(THIS_ DWORD,LPDIDEVICEOBJECTDATA,LPDWORD,DWORD) PURE; +}; + +typedef struct IDirectInputDevice2A *LPDIRECTINPUTDEVICE2A; + +#ifdef UNICODE +#define IID_IDirectInputDevice2 IID_IDirectInputDevice2W +#define IDirectInputDevice2 IDirectInputDevice2W +#define IDirectInputDevice2Vtbl IDirectInputDevice2WVtbl +#else +#define IID_IDirectInputDevice2 IID_IDirectInputDevice2A +#define IDirectInputDevice2 IDirectInputDevice2A +#define IDirectInputDevice2Vtbl IDirectInputDevice2AVtbl +#endif +typedef struct IDirectInputDevice2 *LPDIRECTINPUTDEVICE2; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInputDevice2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInputDevice2_Release(p) (p)->lpVtbl->Release(p) +#define IDirectInputDevice2_GetCapabilities(p,a) (p)->lpVtbl->GetCapabilities(p,a) +#define IDirectInputDevice2_EnumObjects(p,a,b,c) (p)->lpVtbl->EnumObjects(p,a,b,c) +#define IDirectInputDevice2_GetProperty(p,a,b) (p)->lpVtbl->GetProperty(p,a,b) +#define IDirectInputDevice2_SetProperty(p,a,b) (p)->lpVtbl->SetProperty(p,a,b) +#define IDirectInputDevice2_Acquire(p) (p)->lpVtbl->Acquire(p) +#define IDirectInputDevice2_Unacquire(p) (p)->lpVtbl->Unacquire(p) +#define IDirectInputDevice2_GetDeviceState(p,a,b) (p)->lpVtbl->GetDeviceState(p,a,b) +#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d) (p)->lpVtbl->GetDeviceData(p,a,b,c,d) +#define IDirectInputDevice2_SetDataFormat(p,a) (p)->lpVtbl->SetDataFormat(p,a) +#define IDirectInputDevice2_SetEventNotification(p,a) (p)->lpVtbl->SetEventNotification(p,a) +#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectInputDevice2_GetObjectInfo(p,a,b,c) (p)->lpVtbl->GetObjectInfo(p,a,b,c) +#define IDirectInputDevice2_GetDeviceInfo(p,a) (p)->lpVtbl->GetDeviceInfo(p,a) +#define IDirectInputDevice2_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInputDevice2_Initialize(p,a,b,c) (p)->lpVtbl->Initialize(p,a,b,c) +#define IDirectInputDevice2_CreateEffect(p,a,b,c,d) (p)->lpVtbl->CreateEffect(p,a,b,c,d) +#define IDirectInputDevice2_EnumEffects(p,a,b,c) (p)->lpVtbl->EnumEffects(p,a,b,c) +#define IDirectInputDevice2_GetEffectInfo(p,a,b) (p)->lpVtbl->GetEffectInfo(p,a,b) +#define IDirectInputDevice2_GetForceFeedbackState(p,a) (p)->lpVtbl->GetForceFeedbackState(p,a) +#define IDirectInputDevice2_SendForceFeedbackCommand(p,a) (p)->lpVtbl->SendForceFeedbackCommand(p,a) +#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->lpVtbl->EnumCreatedEffectObjects(p,a,b,c) +#define IDirectInputDevice2_Escape(p,a) (p)->lpVtbl->Escape(p,a) +#define IDirectInputDevice2_Poll(p) (p)->lpVtbl->Poll(p) +#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d) (p)->lpVtbl->SendDeviceData(p,a,b,c,d) +#else +#define IDirectInputDevice2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInputDevice2_AddRef(p) (p)->AddRef() +#define IDirectInputDevice2_Release(p) (p)->Release() +#define IDirectInputDevice2_GetCapabilities(p,a) (p)->GetCapabilities(a) +#define IDirectInputDevice2_EnumObjects(p,a,b,c) (p)->EnumObjects(a,b,c) +#define IDirectInputDevice2_GetProperty(p,a,b) (p)->GetProperty(a,b) +#define IDirectInputDevice2_SetProperty(p,a,b) (p)->SetProperty(a,b) +#define IDirectInputDevice2_Acquire(p) (p)->Acquire() +#define IDirectInputDevice2_Unacquire(p) (p)->Unacquire() +#define IDirectInputDevice2_GetDeviceState(p,a,b) (p)->GetDeviceState(a,b) +#define IDirectInputDevice2_GetDeviceData(p,a,b,c,d) (p)->GetDeviceData(a,b,c,d) +#define IDirectInputDevice2_SetDataFormat(p,a) (p)->SetDataFormat(a) +#define IDirectInputDevice2_SetEventNotification(p,a) (p)->SetEventNotification(a) +#define IDirectInputDevice2_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectInputDevice2_GetObjectInfo(p,a,b,c) (p)->GetObjectInfo(a,b,c) +#define IDirectInputDevice2_GetDeviceInfo(p,a) (p)->GetDeviceInfo(a) +#define IDirectInputDevice2_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInputDevice2_Initialize(p,a,b,c) (p)->Initialize(a,b,c) +#define IDirectInputDevice2_CreateEffect(p,a,b,c,d) (p)->CreateEffect(a,b,c,d) +#define IDirectInputDevice2_EnumEffects(p,a,b,c) (p)->EnumEffects(a,b,c) +#define IDirectInputDevice2_GetEffectInfo(p,a,b) (p)->GetEffectInfo(a,b) +#define IDirectInputDevice2_GetForceFeedbackState(p,a) (p)->GetForceFeedbackState(a) +#define IDirectInputDevice2_SendForceFeedbackCommand(p,a) (p)->SendForceFeedbackCommand(a) +#define IDirectInputDevice2_EnumCreatedEffectObjects(p,a,b,c) (p)->EnumCreatedEffectObjects(a,b,c) +#define IDirectInputDevice2_Escape(p,a) (p)->Escape(a) +#define IDirectInputDevice2_Poll(p) (p)->Poll() +#define IDirectInputDevice2_SendDeviceData(p,a,b,c,d) (p)->SendDeviceData(a,b,c,d) +#endif + +#endif /* DIJ_RINGZERO */ + +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +/**************************************************************************** + * + * Mouse + * + ****************************************************************************/ + +#ifndef DIJ_RINGZERO + +typedef struct _DIMOUSESTATE { + LONG lX; + LONG lY; + LONG lZ; + BYTE rgbButtons[4]; +} DIMOUSESTATE, *LPDIMOUSESTATE; + +#define DIMOFS_X FIELD_OFFSET(DIMOUSESTATE, lX) +#define DIMOFS_Y FIELD_OFFSET(DIMOUSESTATE, lY) +#define DIMOFS_Z FIELD_OFFSET(DIMOUSESTATE, lZ) +#define DIMOFS_BUTTON0 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 0) +#define DIMOFS_BUTTON1 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 1) +#define DIMOFS_BUTTON2 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 2) +#define DIMOFS_BUTTON3 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 3) + +#endif /* DIJ_RINGZERO */ + +/**************************************************************************** + * + * Keyboard + * + ****************************************************************************/ + +#ifndef DIJ_RINGZERO + +/**************************************************************************** + * + * DirectInput keyboard scan codes + * + ****************************************************************************/ + +#define DIK_ESCAPE 0x01 +#define DIK_1 0x02 +#define DIK_2 0x03 +#define DIK_3 0x04 +#define DIK_4 0x05 +#define DIK_5 0x06 +#define DIK_6 0x07 +#define DIK_7 0x08 +#define DIK_8 0x09 +#define DIK_9 0x0A +#define DIK_0 0x0B +#define DIK_MINUS 0x0C /* - on main keyboard */ +#define DIK_EQUALS 0x0D +#define DIK_BACK 0x0E /* backspace */ +#define DIK_TAB 0x0F +#define DIK_Q 0x10 +#define DIK_W 0x11 +#define DIK_E 0x12 +#define DIK_R 0x13 +#define DIK_T 0x14 +#define DIK_Y 0x15 +#define DIK_U 0x16 +#define DIK_I 0x17 +#define DIK_O 0x18 +#define DIK_P 0x19 +#define DIK_LBRACKET 0x1A +#define DIK_RBRACKET 0x1B +#define DIK_RETURN 0x1C /* Enter on main keyboard */ +#define DIK_LCONTROL 0x1D +#define DIK_A 0x1E +#define DIK_S 0x1F +#define DIK_D 0x20 +#define DIK_F 0x21 +#define DIK_G 0x22 +#define DIK_H 0x23 +#define DIK_J 0x24 +#define DIK_K 0x25 +#define DIK_L 0x26 +#define DIK_SEMICOLON 0x27 +#define DIK_APOSTROPHE 0x28 +#define DIK_GRAVE 0x29 /* accent grave */ +#define DIK_LSHIFT 0x2A +#define DIK_BACKSLASH 0x2B +#define DIK_Z 0x2C +#define DIK_X 0x2D +#define DIK_C 0x2E +#define DIK_V 0x2F +#define DIK_B 0x30 +#define DIK_N 0x31 +#define DIK_M 0x32 +#define DIK_COMMA 0x33 +#define DIK_PERIOD 0x34 /* . on main keyboard */ +#define DIK_SLASH 0x35 /* / on main keyboard */ +#define DIK_RSHIFT 0x36 +#define DIK_MULTIPLY 0x37 /* * on numeric keypad */ +#define DIK_LMENU 0x38 /* left Alt */ +#define DIK_SPACE 0x39 +#define DIK_CAPITAL 0x3A +#define DIK_F1 0x3B +#define DIK_F2 0x3C +#define DIK_F3 0x3D +#define DIK_F4 0x3E +#define DIK_F5 0x3F +#define DIK_F6 0x40 +#define DIK_F7 0x41 +#define DIK_F8 0x42 +#define DIK_F9 0x43 +#define DIK_F10 0x44 +#define DIK_NUMLOCK 0x45 +#define DIK_SCROLL 0x46 /* Scroll Lock */ +#define DIK_NUMPAD7 0x47 +#define DIK_NUMPAD8 0x48 +#define DIK_NUMPAD9 0x49 +#define DIK_SUBTRACT 0x4A /* - on numeric keypad */ +#define DIK_NUMPAD4 0x4B +#define DIK_NUMPAD5 0x4C +#define DIK_NUMPAD6 0x4D +#define DIK_ADD 0x4E /* + on numeric keypad */ +#define DIK_NUMPAD1 0x4F +#define DIK_NUMPAD2 0x50 +#define DIK_NUMPAD3 0x51 +#define DIK_NUMPAD0 0x52 +#define DIK_DECIMAL 0x53 /* . on numeric keypad */ +#define DIK_F11 0x57 +#define DIK_F12 0x58 + +#define DIK_F13 0x64 /* (NEC PC98) */ +#define DIK_F14 0x65 /* (NEC PC98) */ +#define DIK_F15 0x66 /* (NEC PC98) */ + +#define DIK_KANA 0x70 /* (Japanese keyboard) */ +#define DIK_CONVERT 0x79 /* (Japanese keyboard) */ +#define DIK_NOCONVERT 0x7B /* (Japanese keyboard) */ +#define DIK_YEN 0x7D /* (Japanese keyboard) */ +#define DIK_NUMPADEQUALS 0x8D /* = on numeric keypad (NEC PC98) */ +#define DIK_CIRCUMFLEX 0x90 /* (Japanese keyboard) */ +#define DIK_AT 0x91 /* (NEC PC98) */ +#define DIK_COLON 0x92 /* (NEC PC98) */ +#define DIK_UNDERLINE 0x93 /* (NEC PC98) */ +#define DIK_KANJI 0x94 /* (Japanese keyboard) */ +#define DIK_STOP 0x95 /* (NEC PC98) */ +#define DIK_AX 0x96 /* (Japan AX) */ +#define DIK_UNLABELED 0x97 /* (J3100) */ +#define DIK_NUMPADENTER 0x9C /* Enter on numeric keypad */ +#define DIK_RCONTROL 0x9D +#define DIK_NUMPADCOMMA 0xB3 /* , on numeric keypad (NEC PC98) */ +#define DIK_DIVIDE 0xB5 /* / on numeric keypad */ +#define DIK_SYSRQ 0xB7 +#define DIK_RMENU 0xB8 /* right Alt */ +#define DIK_HOME 0xC7 /* Home on arrow keypad */ +#define DIK_UP 0xC8 /* UpArrow on arrow keypad */ +#define DIK_PRIOR 0xC9 /* PgUp on arrow keypad */ +#define DIK_LEFT 0xCB /* LeftArrow on arrow keypad */ +#define DIK_RIGHT 0xCD /* RightArrow on arrow keypad */ +#define DIK_END 0xCF /* End on arrow keypad */ +#define DIK_DOWN 0xD0 /* DownArrow on arrow keypad */ +#define DIK_NEXT 0xD1 /* PgDn on arrow keypad */ +#define DIK_INSERT 0xD2 /* Insert on arrow keypad */ +#define DIK_DELETE 0xD3 /* Delete on arrow keypad */ +#define DIK_LWIN 0xDB /* Left Windows key */ +#define DIK_RWIN 0xDC /* Right Windows key */ +#define DIK_APPS 0xDD /* AppMenu key */ + +/* + * Alternate names for keys, to facilitate transition from DOS. + */ +#define DIK_BACKSPACE DIK_BACK /* backspace */ +#define DIK_NUMPADSTAR DIK_MULTIPLY /* * on numeric keypad */ +#define DIK_LALT DIK_LMENU /* left Alt */ +#define DIK_CAPSLOCK DIK_CAPITAL /* CapsLock */ +#define DIK_NUMPADMINUS DIK_SUBTRACT /* - on numeric keypad */ +#define DIK_NUMPADPLUS DIK_ADD /* + on numeric keypad */ +#define DIK_NUMPADPERIOD DIK_DECIMAL /* . on numeric keypad */ +#define DIK_NUMPADSLASH DIK_DIVIDE /* / on numeric keypad */ +#define DIK_RALT DIK_RMENU /* right Alt */ +#define DIK_UPARROW DIK_UP /* UpArrow on arrow keypad */ +#define DIK_PGUP DIK_PRIOR /* PgUp on arrow keypad */ +#define DIK_LEFTARROW DIK_LEFT /* LeftArrow on arrow keypad */ +#define DIK_RIGHTARROW DIK_RIGHT /* RightArrow on arrow keypad */ +#define DIK_DOWNARROW DIK_DOWN /* DownArrow on arrow keypad */ +#define DIK_PGDN DIK_NEXT /* PgDn on arrow keypad */ + +#endif /* DIJ_RINGZERO */ + +/**************************************************************************** + * + * Joystick + * + ****************************************************************************/ + +#ifndef DIJ_RINGZERO + +typedef struct DIJOYSTATE { + LONG lX; /* x-axis position */ + LONG lY; /* y-axis position */ + LONG lZ; /* z-axis position */ + LONG lRx; /* x-axis rotation */ + LONG lRy; /* y-axis rotation */ + LONG lRz; /* z-axis rotation */ + LONG rglSlider[2]; /* extra axes positions */ + DWORD rgdwPOV[4]; /* POV directions */ + BYTE rgbButtons[32]; /* 32 buttons */ +} DIJOYSTATE, *LPDIJOYSTATE; + +typedef struct DIJOYSTATE2 { + LONG lX; /* x-axis position */ + LONG lY; /* y-axis position */ + LONG lZ; /* z-axis position */ + LONG lRx; /* x-axis rotation */ + LONG lRy; /* y-axis rotation */ + LONG lRz; /* z-axis rotation */ + LONG rglSlider[2]; /* extra axes positions */ + DWORD rgdwPOV[4]; /* POV directions */ + BYTE rgbButtons[128]; /* 128 buttons */ + LONG lVX; /* x-axis velocity */ + LONG lVY; /* y-axis velocity */ + LONG lVZ; /* z-axis velocity */ + LONG lVRx; /* x-axis angular velocity */ + LONG lVRy; /* y-axis angular velocity */ + LONG lVRz; /* z-axis angular velocity */ + LONG rglVSlider[2]; /* extra axes velocities */ + LONG lAX; /* x-axis acceleration */ + LONG lAY; /* y-axis acceleration */ + LONG lAZ; /* z-axis acceleration */ + LONG lARx; /* x-axis angular acceleration */ + LONG lARy; /* y-axis angular acceleration */ + LONG lARz; /* z-axis angular acceleration */ + LONG rglASlider[2]; /* extra axes accelerations */ + LONG lFX; /* x-axis force */ + LONG lFY; /* y-axis force */ + LONG lFZ; /* z-axis force */ + LONG lFRx; /* x-axis torque */ + LONG lFRy; /* y-axis torque */ + LONG lFRz; /* z-axis torque */ + LONG rglFSlider[2]; /* extra axes forces */ +} DIJOYSTATE2, *LPDIJOYSTATE2; + +#define DIJOFS_X FIELD_OFFSET(DIJOYSTATE, lX) +#define DIJOFS_Y FIELD_OFFSET(DIJOYSTATE, lY) +#define DIJOFS_Z FIELD_OFFSET(DIJOYSTATE, lZ) +#define DIJOFS_RX FIELD_OFFSET(DIJOYSTATE, lRx) +#define DIJOFS_RY FIELD_OFFSET(DIJOYSTATE, lRy) +#define DIJOFS_RZ FIELD_OFFSET(DIJOYSTATE, lRz) +#define DIJOFS_SLIDER(n) (FIELD_OFFSET(DIJOYSTATE, rglSlider) + \ + (n) * sizeof(LONG)) +#define DIJOFS_POV(n) (FIELD_OFFSET(DIJOYSTATE, rgdwPOV) + \ + (n) * sizeof(DWORD)) +#define DIJOFS_BUTTON(n) (FIELD_OFFSET(DIJOYSTATE, rgbButtons) + (n)) +#define DIJOFS_BUTTON0 DIJOFS_BUTTON(0) +#define DIJOFS_BUTTON1 DIJOFS_BUTTON(1) +#define DIJOFS_BUTTON2 DIJOFS_BUTTON(2) +#define DIJOFS_BUTTON3 DIJOFS_BUTTON(3) +#define DIJOFS_BUTTON4 DIJOFS_BUTTON(4) +#define DIJOFS_BUTTON5 DIJOFS_BUTTON(5) +#define DIJOFS_BUTTON6 DIJOFS_BUTTON(6) +#define DIJOFS_BUTTON7 DIJOFS_BUTTON(7) +#define DIJOFS_BUTTON8 DIJOFS_BUTTON(8) +#define DIJOFS_BUTTON9 DIJOFS_BUTTON(9) +#define DIJOFS_BUTTON10 DIJOFS_BUTTON(10) +#define DIJOFS_BUTTON11 DIJOFS_BUTTON(11) +#define DIJOFS_BUTTON12 DIJOFS_BUTTON(12) +#define DIJOFS_BUTTON13 DIJOFS_BUTTON(13) +#define DIJOFS_BUTTON14 DIJOFS_BUTTON(14) +#define DIJOFS_BUTTON15 DIJOFS_BUTTON(15) +#define DIJOFS_BUTTON16 DIJOFS_BUTTON(16) +#define DIJOFS_BUTTON17 DIJOFS_BUTTON(17) +#define DIJOFS_BUTTON18 DIJOFS_BUTTON(18) +#define DIJOFS_BUTTON19 DIJOFS_BUTTON(19) +#define DIJOFS_BUTTON20 DIJOFS_BUTTON(20) +#define DIJOFS_BUTTON21 DIJOFS_BUTTON(21) +#define DIJOFS_BUTTON22 DIJOFS_BUTTON(22) +#define DIJOFS_BUTTON23 DIJOFS_BUTTON(23) +#define DIJOFS_BUTTON24 DIJOFS_BUTTON(24) +#define DIJOFS_BUTTON25 DIJOFS_BUTTON(25) +#define DIJOFS_BUTTON26 DIJOFS_BUTTON(26) +#define DIJOFS_BUTTON27 DIJOFS_BUTTON(27) +#define DIJOFS_BUTTON28 DIJOFS_BUTTON(28) +#define DIJOFS_BUTTON29 DIJOFS_BUTTON(29) +#define DIJOFS_BUTTON30 DIJOFS_BUTTON(30) +#define DIJOFS_BUTTON31 DIJOFS_BUTTON(31) + + +#endif /* DIJ_RINGZERO */ + +/**************************************************************************** + * + * IDirectInput + * + ****************************************************************************/ + +#ifndef DIJ_RINGZERO + +#define DIENUM_STOP 0 +#define DIENUM_CONTINUE 1 + +typedef BOOL (FAR PASCAL * LPDIENUMDEVICESCALLBACKA)(LPCDIDEVICEINSTANCEA, LPVOID); +typedef BOOL (FAR PASCAL * LPDIENUMDEVICESCALLBACKW)(LPCDIDEVICEINSTANCEW, LPVOID); +#ifdef UNICODE +#define LPDIENUMDEVICESCALLBACK LPDIENUMDEVICESCALLBACKW +#else +#define LPDIENUMDEVICESCALLBACK LPDIENUMDEVICESCALLBACKA +#endif // !UNICODE + +#define DIEDFL_ALLDEVICES 0x00000000 +#define DIEDFL_ATTACHEDONLY 0x00000001 +#if(DIRECTINPUT_VERSION >= 0x0500) +#define DIEDFL_FORCEFEEDBACK 0x00000100 +#endif /* DIRECTINPUT_VERSION >= 0x0500 */ + +#undef INTERFACE +#define INTERFACE IDirectInputW + +DECLARE_INTERFACE_(IDirectInputW, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID,LPDIRECTINPUTDEVICEW *,LPUNKNOWN) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD,LPDIENUMDEVICESCALLBACKW,LPVOID,DWORD) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD) PURE; +}; + +typedef struct IDirectInputW *LPDIRECTINPUTW; + +#undef INTERFACE +#define INTERFACE IDirectInputA + +DECLARE_INTERFACE_(IDirectInputA, IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID,LPDIRECTINPUTDEVICEA *,LPUNKNOWN) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD,LPDIENUMDEVICESCALLBACKA,LPVOID,DWORD) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD) PURE; +}; + +typedef struct IDirectInputA *LPDIRECTINPUTA; + +#ifdef UNICODE +#define IID_IDirectInput IID_IDirectInputW +#define IDirectInput IDirectInputW +#define IDirectInputVtbl IDirectInputWVtbl +#else +#define IID_IDirectInput IID_IDirectInputA +#define IDirectInput IDirectInputA +#define IDirectInputVtbl IDirectInputAVtbl +#endif +typedef struct IDirectInput *LPDIRECTINPUT; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectInput_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput_Release(p) (p)->lpVtbl->Release(p) +#define IDirectInput_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#else +#define IDirectInput_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput_AddRef(p) (p)->AddRef() +#define IDirectInput_Release(p) (p)->Release() +#define IDirectInput_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput_Initialize(p,a,b) (p)->Initialize(a,b) +#endif + +#undef INTERFACE +#define INTERFACE IDirectInput2W + +DECLARE_INTERFACE_(IDirectInput2W, IDirectInputW) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IDirectInputW methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID,LPDIRECTINPUTDEVICEW *,LPUNKNOWN) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD,LPDIENUMDEVICESCALLBACKW,LPVOID,DWORD) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD) PURE; + + /*** IDirectInput2W methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID,LPCWSTR,LPGUID) PURE; +}; + +typedef struct IDirectInput2W *LPDIRECTINPUT2W; + +#undef INTERFACE +#define INTERFACE IDirectInput2A + +DECLARE_INTERFACE_(IDirectInput2A, IDirectInputA) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + + /*** IDirectInputA methods ***/ + STDMETHOD(CreateDevice)(THIS_ REFGUID,LPDIRECTINPUTDEVICEA *,LPUNKNOWN) PURE; + STDMETHOD(EnumDevices)(THIS_ DWORD,LPDIENUMDEVICESCALLBACKA,LPVOID,DWORD) PURE; + STDMETHOD(GetDeviceStatus)(THIS_ REFGUID) PURE; + STDMETHOD(RunControlPanel)(THIS_ HWND,DWORD) PURE; + STDMETHOD(Initialize)(THIS_ HINSTANCE,DWORD) PURE; + + /*** IDirectInput2A methods ***/ + STDMETHOD(FindDevice)(THIS_ REFGUID,LPCSTR,LPGUID) PURE; +}; + +typedef struct IDirectInput2A *LPDIRECTINPUT2A; + +#ifdef UNICODE +#define IID_IDirectInput2 IID_IDirectInput2W +#define IDirectInput2 IDirectInput2W +#define IDirectInput2Vtbl IDirectInput2WVtbl +#else +#define IID_IDirectInput2 IID_IDirectInput2A +#define IDirectInput2 IDirectInput2A +#define IDirectInput2Vtbl IDirectInput2AVtbl +#endif +typedef struct IDirectInput2 *LPDIRECTINPUT2; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectInput2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectInput2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectInput2_Release(p) (p)->lpVtbl->Release(p) +#define IDirectInput2_CreateDevice(p,a,b,c) (p)->lpVtbl->CreateDevice(p,a,b,c) +#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->lpVtbl->EnumDevices(p,a,b,c,d) +#define IDirectInput2_GetDeviceStatus(p,a) (p)->lpVtbl->GetDeviceStatus(p,a) +#define IDirectInput2_RunControlPanel(p,a,b) (p)->lpVtbl->RunControlPanel(p,a,b) +#define IDirectInput2_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectInput2_FindDevice(p,a,b,c) (p)->lpVtbl->FindDevice(p,a,b,c) +#else +#define IDirectInput2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectInput2_AddRef(p) (p)->AddRef() +#define IDirectInput2_Release(p) (p)->Release() +#define IDirectInput2_CreateDevice(p,a,b,c) (p)->CreateDevice(a,b,c) +#define IDirectInput2_EnumDevices(p,a,b,c,d) (p)->EnumDevices(a,b,c,d) +#define IDirectInput2_GetDeviceStatus(p,a) (p)->GetDeviceStatus(a) +#define IDirectInput2_RunControlPanel(p,a,b) (p)->RunControlPanel(a,b) +#define IDirectInput2_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectInput2_FindDevice(p,a,b,c) (p)->FindDevice(a,b,c) +#endif + +extern HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter); +extern HRESULT WINAPI DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter); +#ifdef UNICODE +#define DirectInputCreate DirectInputCreateW +#else +#define DirectInputCreate DirectInputCreateA +#endif // !UNICODE + +#endif /* DIJ_RINGZERO */ + + +/**************************************************************************** + * + * Return Codes + * + ****************************************************************************/ + +/* + * The operation completed successfully. + */ +#define DI_OK S_OK + +/* + * The device exists but is not currently attached. + */ +#define DI_NOTATTACHED S_FALSE + +/* + * The device buffer overflowed. Some input was lost. + */ +#define DI_BUFFEROVERFLOW S_FALSE + +/* + * The change in device properties had no effect. + */ +#define DI_PROPNOEFFECT S_FALSE + +/* + * The operation had no effect. + */ +#define DI_NOEFFECT S_FALSE + +/* + * The device is a polled device. As a result, device buffering + * will not collect any data and event notifications will not be + * signalled until GetDeviceState is called. + */ +#define DI_POLLEDDEVICE ((HRESULT)0x00000002L) + +/* + * The parameters of the effect were successfully updated by + * IDirectInputEffect::SetParameters, but the effect was not + * downloaded because the device is not exclusively acquired + * or because the DIEP_NODOWNLOAD flag was passed. + */ +#define DI_DOWNLOADSKIPPED ((HRESULT)0x00000003L) + +/* + * The parameters of the effect were successfully updated by + * IDirectInputEffect::SetParameters, but in order to change + * the parameters, the effect needed to be restarted. + */ +#define DI_EFFECTRESTARTED ((HRESULT)0x00000004L) + +/* + * The parameters of the effect were successfully updated by + * IDirectInputEffect::SetParameters, but some of them were + * beyond the capabilities of the device and were truncated. + */ +#define DI_TRUNCATED ((HRESULT)0x00000008L) + +/* + * Equal to DI_EFFECTRESTARTED | DI_TRUNCATED. + */ +#define DI_TRUNCATEDANDRESTARTED ((HRESULT)0x0000000CL) + +/* + * The application requires a newer version of DirectInput. + */ +#define DIERR_OLDDIRECTINPUTVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_OLD_WIN_VERSION) + +/* + * The application was written for an unsupported prerelease version + * of DirectInput. + */ +#define DIERR_BETADIRECTINPUTVERSION \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_RMODE_APP) + +/* + * The object could not be created due to an incompatible driver version + * or mismatched or incomplete driver components. + */ +#define DIERR_BADDRIVERVER \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BAD_DRIVER_LEVEL) + +/* + * The device or device instance or effect is not registered with DirectInput. + */ +#define DIERR_DEVICENOTREG REGDB_E_CLASSNOTREG + +/* + * The requested object does not exist. + */ +#define DIERR_NOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) + +/* + * The requested object does not exist. + */ +#define DIERR_OBJECTNOTFOUND \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND) + +/* + * An invalid parameter was passed to the returning function, + * or the object was not in a state that admitted the function + * to be called. + */ +#define DIERR_INVALIDPARAM E_INVALIDARG + +/* + * The specified interface is not supported by the object + */ +#define DIERR_NOINTERFACE E_NOINTERFACE + +/* + * An undetermined error occured inside the DInput subsystem + */ +#define DIERR_GENERIC E_FAIL + +/* + * The DInput subsystem couldn't allocate sufficient memory to complete the + * caller's request. + */ +#define DIERR_OUTOFMEMORY E_OUTOFMEMORY + +/* + * The function called is not supported at this time + */ +#define DIERR_UNSUPPORTED E_NOTIMPL + +/* + * This object has not been initialized + */ +#define DIERR_NOTINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_READY) + +/* + * This object is already initialized + */ +#define DIERR_ALREADYINITIALIZED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_ALREADY_INITIALIZED) + +/* + * This object does not support aggregation + */ +#define DIERR_NOAGGREGATION CLASS_E_NOAGGREGATION + +/* + * Another app has a higher priority level, preventing this call from + * succeeding. + */ +#define DIERR_OTHERAPPHASPRIO E_ACCESSDENIED + +/* + * Access to the device has been lost. It must be re-acquired. + */ +#define DIERR_INPUTLOST \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_READ_FAULT) + +/* + * The operation cannot be performed while the device is acquired. + */ +#define DIERR_ACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_BUSY) + +/* + * The operation cannot be performed unless the device is acquired. + */ +#define DIERR_NOTACQUIRED \ + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_ACCESS) + +/* + * The specified property cannot be changed. + */ +#define DIERR_READONLY E_ACCESSDENIED + +/* + * The device already has an event notification associated with it. + */ +#define DIERR_HANDLEEXISTS E_ACCESSDENIED + +/* + * Data is not yet available. + */ +#ifndef E_PENDING +#define E_PENDING 0x80070007L +#endif + +/* + * Unable to IDirectInputJoyConfig_Acquire because the user + * does not have sufficient privileges to change the joystick + * configuration. + */ +#define DIERR_INSUFFICIENTPRIVS 0x80040200L + +/* + * The device is full. + */ +#define DIERR_DEVICEFULL 0x80040201L + +/* + * Not all the requested information fit into the buffer. + */ +#define DIERR_MOREDATA 0x80040202L + +/* + * The effect is not downloaded. + */ +#define DIERR_NOTDOWNLOADED 0x80040203L + +/* + * The device cannot be reinitialized because there are still effects + * attached to it. + */ +#define DIERR_HASEFFECTS 0x80040204L + +/* + * The operation cannot be performed unless the device is acquired + * in DISCL_EXCLUSIVE mode. + */ +#define DIERR_NOTEXCLUSIVEACQUIRED 0x80040205L + +/* + * The effect could not be downloaded because essential information + * is missing. For example, no axes have been associated with the + * effect, or no type-specific information has been created. + */ +#define DIERR_INCOMPLETEEFFECT 0x80040206L + +/* + * Attempted to read buffered device data from a device that is + * not buffered. + */ +#define DIERR_NOTBUFFERED 0x80040207L + +/* + * An attempt was made to modify parameters of an effect while it is + * playing. Not all hardware devices support altering the parameters + * of an effect while it is playing. + */ +#define DIERR_EFFECTPLAYING 0x80040208L + +#ifdef __cplusplus +}; +#endif + +#endif /* __DINPUT_INCLUDED__ */ + +/**************************************************************************** + * + * Definitions for non-IDirectInput (VJoyD) features defined more recently + * than the current sdk files + * + ****************************************************************************/ + +#ifdef _INC_MMSYSTEM +#ifndef MMNOJOY + +#ifndef __VJOYDX_INCLUDED__ +#define __VJOYDX_INCLUDED__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Flag to indicate that the dwReserved2 field of the JOYINFOEX structure + * contains mini-driver specific data to be passed by VJoyD to the mini- + * driver instead of doing a poll. + */ +#define JOY_PASSDRIVERDATA 0x10000000l + +/* + * Informs the joystick driver that the configuration has been changed + * and should be reloaded from the registery. + * dwFlags is reserved and should be set to zero + */ +WINMMAPI MMRESULT WINAPI joyConfigChanged( DWORD dwFlags ); + +/* + * Hardware Setting indicating that the device is a headtracker + */ +#define JOY_HWS_ISHEADTRACKER 0x02000000l + +/* + * Hardware Setting indicating that the VxD is used to replace + * the standard analog polling + */ +#define JOY_HWS_ISGAMEPORTDRIVER 0x04000000l + +/* + * Hardware Setting indicating that the driver needs a standard + * gameport in order to communicate with the device. + */ +#define JOY_HWS_ISANALOGPORTDRIVER 0x08000000l + +/* + * Hardware Setting indicating that VJoyD should not load this + * driver, it will be loaded externally and will register with + * VJoyD of it's own accord. + */ +#define JOY_HWS_AUTOLOAD 0x10000000l + +/* + * Hardware Setting indicating that the driver acquires any + * resources needed without needing a devnode through VJoyD. + */ +#define JOY_HWS_NODEVNODE 0x20000000l + +/* + * Hardware Setting indicating that the VxD can be used as + * a port 201h emulator. + */ +#define JOY_HWS_ISGAMEPORTEMULATOR 0x40000000l + + +/* + * Usage Setting indicating that the settings are volatile and + * should be removed if still present on a reboot. + */ +#define JOY_US_VOLATILE 0x00000008L + +#ifdef __cplusplus +}; +#endif + +#endif /* __VJOYDX_INCLUDED__ */ + +#endif /* not MMNOJOY */ +#endif /* _INC_MMSYSTEM */ + +/**************************************************************************** + * + * Definitions for non-IDirectInput (VJoyD) features defined more recently + * than the current ddk files + * + ****************************************************************************/ + +#ifndef DIJ_RINGZERO + +#ifdef _INC_MMDDK +#ifndef MMNOJOYDEV + +#ifndef __VJOYDXD_INCLUDED__ +#define __VJOYDXD_INCLUDED__ +/* + * Poll type in which the do_other field of the JOYOEMPOLLDATA + * structure contains mini-driver specific data passed from an app. + */ +#define JOY_OEMPOLL_PASSDRIVERDATA 7 + +#endif /* __VJOYDXD_INCLUDED__ */ + +#endif /* not MMNOJOYDEV */ +#endif /* _INC_MMDDK */ + +#endif /* DIJ_RINGZERO */ diff --git a/3rdparty/dx5/inc/dplay.h b/3rdparty/dx5/inc/dplay.h new file mode 100644 index 00000000..f5b6bb5c --- /dev/null +++ b/3rdparty/dx5/inc/dplay.h @@ -0,0 +1,1710 @@ +/*==========================================================================; + * + * Copyright (C) 1994-1997 Microsoft Corporation. All Rights Reserved. + * + * File: dplay.h + * Content: DirectPlay include file + * + ***************************************************************************/ + +#ifndef __DPLAY_INCLUDED__ +#define __DPLAY_INCLUDED__ + +#include // for DECLARE_INTERFACE and HRESULT + +#define _FACDP 0x877 +#define MAKE_DPHRESULT( code ) MAKE_HRESULT( 1, _FACDP, code ) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * GUIDS used by DirectPlay objects + */ +DEFINE_GUID(IID_IDirectPlay2, 0x2b74f7c0, 0x9154, 0x11cf, 0xa9, 0xcd, 0x0, 0xaa, 0x0, 0x68, 0x86, 0xe3); +DEFINE_GUID(IID_IDirectPlay2A,0x9d460580, 0xa822, 0x11cf, 0x96, 0xc, 0x0, 0x80, 0xc7, 0x53, 0x4e, 0x82); + +DEFINE_GUID(IID_IDirectPlay3, 0x133efe40, 0x32dc, 0x11d0, 0x9c, 0xfb, 0x0, 0xa0, 0xc9, 0xa, 0x43, 0xcb); +DEFINE_GUID(IID_IDirectPlay3A,0x133efe41, 0x32dc, 0x11d0, 0x9c, 0xfb, 0x0, 0xa0, 0xc9, 0xa, 0x43, 0xcb); + +// {D1EB6D20-8923-11d0-9D97-00A0C90A43CB} +DEFINE_GUID(CLSID_DirectPlay,0xd1eb6d20, 0x8923, 0x11d0, 0x9d, 0x97, 0x0, 0xa0, 0xc9, 0xa, 0x43, 0xcb); + +/* + * GUIDS used by Service Providers shipped with DirectPlay + * Use these to identify Service Provider returned by EnumConnections + */ + +// GUID for IPX service provider +// {685BC400-9D2C-11cf-A9CD-00AA006886E3} +DEFINE_GUID(DPSPGUID_IPX, +0x685bc400, 0x9d2c, 0x11cf, 0xa9, 0xcd, 0x0, 0xaa, 0x0, 0x68, 0x86, 0xe3); + +// GUID for TCP/IP service provider +// 36E95EE0-8577-11cf-960C-0080C7534E82 +DEFINE_GUID(DPSPGUID_TCPIP, +0x36E95EE0, 0x8577, 0x11cf, 0x96, 0xc, 0x0, 0x80, 0xc7, 0x53, 0x4e, 0x82); + +// GUID for Serial service provider +// {0F1D6860-88D9-11cf-9C4E-00A0C905425E} +DEFINE_GUID(DPSPGUID_SERIAL, +0xf1d6860, 0x88d9, 0x11cf, 0x9c, 0x4e, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +// GUID for Modem service provider +// {44EAA760-CB68-11cf-9C4E-00A0C905425E} +DEFINE_GUID(DPSPGUID_MODEM, +0x44eaa760, 0xcb68, 0x11cf, 0x9c, 0x4e, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +/**************************************************************************** + * + * DirectPlay Structures + * + * Various structures used to invoke DirectPlay. + * + ****************************************************************************/ + +#ifndef IDIRECTPLAY2_OR_GREATER +typedef struct IDirectPlay FAR *LPDIRECTPLAY; +#else +typedef struct IUnknown FAR *LPDIRECTPLAY; +#endif + +typedef struct IDirectPlay2 FAR *LPDIRECTPLAY2; +typedef struct IDirectPlay2 FAR *LPDIRECTPLAY2A; +typedef struct IDirectPlay2 IDirectPlay2A; + +typedef struct IDirectPlay3 FAR *LPDIRECTPLAY3; +typedef struct IDirectPlay3 FAR *LPDIRECTPLAY3A; +typedef struct IDirectPlay3 IDirectPlay3A; + +/* + * DPID + * DirectPlay player and group ID + */ +typedef DWORD DPID, FAR *LPDPID; + +/* + * DPID that system messages come from + */ +#define DPID_SYSMSG 0 + +/* + * DPID representing all players in the session + */ +#define DPID_ALLPLAYERS 0 + +/* + * DPID representing the server player + */ +#define DPID_SERVERPLAYER 1 + +/* + * The player ID is unknown (used with e.g. DPSESSION_NOMESSAGEID) + */ +#define DPID_UNKNOWN 0xFFFFFFFF + +/* + * DPCAPS + * Used to obtain the capabilities of a DirectPlay object + */ +typedef struct +{ + DWORD dwSize; // Size of structure, in bytes + DWORD dwFlags; // DPCAPS_xxx flags + DWORD dwMaxBufferSize; // Maximum message size, in bytes, for this service provider + DWORD dwMaxQueueSize; // Obsolete. + DWORD dwMaxPlayers; // Maximum players/groups (local + remote) + DWORD dwHundredBaud; // Bandwidth in 100 bits per second units; + // i.e. 24 is 2400, 96 is 9600, etc. + DWORD dwLatency; // Estimated latency; 0 = unknown + DWORD dwMaxLocalPlayers; // Maximum # of locally created players allowed + DWORD dwHeaderLength; // Maximum header length, in bytes, on messages + // added by the service provider + DWORD dwTimeout; // Service provider's suggested timeout value + // This is how long DirectPlay will wait for + // responses to system messages +} DPCAPS, FAR *LPDPCAPS; + +/* + * This DirectPlay object is the session host. If the host exits the + * session, another application will become the host and receive a + * DPSYS_HOST system message. + */ +#define DPCAPS_ISHOST 0x00000002 + +/* + * The service provider bound to this DirectPlay object can optimize + * group messaging. + */ +#define DPCAPS_GROUPOPTIMIZED 0x00000008 + +/* + * The service provider bound to this DirectPlay object can optimize + * keep alives (see DPSESSION_KEEPALIVE) + */ +#define DPCAPS_KEEPALIVEOPTIMIZED 0x00000010 + +/* + * The service provider bound to this DirectPlay object can optimize + * guaranteed message delivery. + */ +#define DPCAPS_GUARANTEEDOPTIMIZED 0x00000020 + +/* + * This DirectPlay object supports guaranteed message delivery. + */ +#define DPCAPS_GUARANTEEDSUPPORTED 0x00000040 + +/* + * This DirectPlay object supports digital signing of messages. + */ +#define DPCAPS_SIGNINGSUPPORTED 0x00000080 + +/* + * This DirectPlay object supports encryption of messages. + */ +#define DPCAPS_ENCRYPTIONSUPPORTED 0x00000100 + + +/* + * DPSESSIONDESC2 + * Used to describe the properties of a DirectPlay + * session instance + */ +typedef struct +{ + DWORD dwSize; // Size of structure + DWORD dwFlags; // DPSESSION_xxx flags + GUID guidInstance; // ID for the session instance + GUID guidApplication; // GUID of the DirectPlay application. + // GUID_NULL for all applications. + DWORD dwMaxPlayers; // Maximum # players allowed in session + DWORD dwCurrentPlayers; // Current # players in session (read only) + union + { // Name of the session + LPWSTR lpszSessionName; // Unicode + LPSTR lpszSessionNameA; // ANSI + }; + union + { // Password of the session (optional) + LPWSTR lpszPassword; // Unicode + LPSTR lpszPasswordA; // ANSI + }; + DWORD dwReserved1; // Reserved for future MS use. + DWORD dwReserved2; + DWORD dwUser1; // For use by the application + DWORD dwUser2; + DWORD dwUser3; + DWORD dwUser4; +} DPSESSIONDESC2, FAR *LPDPSESSIONDESC2; + +/* + * LPCDPSESSIONDESC2 + * A constant pointer to DPSESSIONDESC2 + */ +typedef const DPSESSIONDESC2 FAR *LPCDPSESSIONDESC2; + +/* + * Applications cannot create new players in this session. + */ +#define DPSESSION_NEWPLAYERSDISABLED 0x00000001 + +/* + * If the DirectPlay object that created the session, the host, + * quits, then the host will attempt to migrate to another + * DirectPlay object so that new players can continue to be created + * and new applications can join the session. + */ +#define DPSESSION_MIGRATEHOST 0x00000004 + +/* + * This flag tells DirectPlay not to set the idPlayerTo and idPlayerFrom + * fields in player messages. This cuts two DWORD's off the message + * overhead. + */ +#define DPSESSION_NOMESSAGEID 0x00000008 + + +/* + * This flag tells DirectPlay to not allow any new applications to + * join the session. Applications already in the session can still + * create new players. + */ +#define DPSESSION_JOINDISABLED 0x00000020 + +/* + * This flag tells DirectPlay to detect when remote players + * exit abnormally (e.g. their computer or modem gets unplugged) + */ +#define DPSESSION_KEEPALIVE 0x00000040 + +/* + * This flag tells DirectPlay not to send a message to all players + * when a players remote data changes + */ +#define DPSESSION_NODATAMESSAGES 0x00000080 + +/* + * This flag indicates that the session belongs to a secure server + * and needs user authentication + */ +#define DPSESSION_SECURESERVER 0x00000100 + +/* + * This flag indicates that the session is private and requirs a password + * for EnumSessions as well as Open. + */ +#define DPSESSION_PRIVATE 0x00000200 + +/* + * This flag indicates that the session requires a password for joining. + */ +#define DPSESSION_PASSWORDREQUIRED 0x00000400 + +/* + * This flag tells DirectPlay to route all messages through the server + */ +#define DPSESSION_MULTICASTSERVER 0x00000800 + +/* + * This flag tells DirectPlay to only download information about the + * DPPLAYER_SERVERPLAYER. + */ +#define DPSESSION_CLIENTSERVER 0x00001000 + +/* + * DPNAME + * Used to hold the name of a DirectPlay entity + * like a player or a group + */ +typedef struct +{ + DWORD dwSize; // Size of structure + DWORD dwFlags; // Not used. Must be zero. + union + { // The short or friendly name + LPWSTR lpszShortName; // Unicode + LPSTR lpszShortNameA; // ANSI + }; + union + { // The long or formal name + LPWSTR lpszLongName; // Unicode + LPSTR lpszLongNameA; // ANSI + }; + +} DPNAME, FAR *LPDPNAME; + +/* + * LPCDPNAME + * A constant pointer to DPNAME + */ +typedef const DPNAME FAR *LPCDPNAME; + +/* + * DPCREDENTIALS + * Used to hold the user name and password of a DirectPlay user + */ +typedef struct +{ + DWORD dwSize; // Size of structure + DWORD dwFlags; // Not used. Must be zero. + union + { // User name of the account + LPWSTR lpszUsername; // Unicode + LPSTR lpszUsernameA; // ANSI + }; + union + { // Password of the account + LPWSTR lpszPassword; // Unicode + LPSTR lpszPasswordA; // ANSI + }; + union + { // Domain name of the account + LPWSTR lpszDomain; // Unicode + LPSTR lpszDomainA; // ANSI + }; +} DPCREDENTIALS, FAR *LPDPCREDENTIALS; + +typedef const DPCREDENTIALS FAR *LPCDPCREDENTIALS; + +/* + * DPSECURITYDESC + * Used to describe the security properties of a DirectPlay + * session instance + */ +typedef struct +{ + DWORD dwSize; // Size of structure + DWORD dwFlags; // Not used. Must be zero. + union + { // SSPI provider name + LPWSTR lpszSSPIProvider; // Unicode + LPSTR lpszSSPIProviderA; // ANSI + }; + union + { // CAPI provider name + LPWSTR lpszCAPIProvider; // Unicode + LPSTR lpszCAPIProviderA; // ANSI + }; + DWORD dwCAPIProviderType; // Crypto Service Provider type + DWORD dwEncryptionAlgorithm; // Encryption Algorithm type +} DPSECURITYDESC, FAR *LPDPSECURITYDESC; + +typedef const DPSECURITYDESC FAR *LPCDPSECURITYDESC; + +/* + * DPACCOUNTDESC + * Used to describe a user membership account + */ +typedef struct +{ + DWORD dwSize; // Size of structure + DWORD dwFlags; // Not used. Must be zero. + union + { // Account identifier + LPWSTR lpszAccountID; // Unicode + LPSTR lpszAccountIDA; // ANSI + }; +} DPACCOUNTDESC, FAR *LPDPACCOUNTDESC; + +typedef const DPACCOUNTDESC FAR *LPCDPACCOUNTDESC; + +/* + * LPCGUID + * A constant pointer to a guid + */ +typedef const GUID FAR *LPCGUID; + +/* + * DPLCONNECTION + * Used to hold all in the informaion needed to connect + * an application to a session or create a session + */ +typedef struct +{ + DWORD dwSize; // Size of this structure + DWORD dwFlags; // Flags specific to this structure + LPDPSESSIONDESC2 lpSessionDesc; // Pointer to session desc to use on connect + LPDPNAME lpPlayerName; // Pointer to Player name structure + GUID guidSP; // GUID of the DPlay SP to use + LPVOID lpAddress; // Address for service provider + DWORD dwAddressSize; // Size of address data +} DPLCONNECTION, FAR *LPDPLCONNECTION; + +/* + * LPCDPLCONNECTION + * A constant pointer to DPLCONNECTION + */ +typedef const DPLCONNECTION FAR *LPCDPLCONNECTION; + +/* + * DPCHAT + * Used to hold the a DirectPlay chat message + */ +typedef struct +{ + DWORD dwSize; + DWORD dwFlags; + union + { // Message string + LPWSTR lpszMessage; // Unicode + LPSTR lpszMessageA; // ANSI + }; +} DPCHAT, FAR * LPDPCHAT; + +/**************************************************************************** + * + * Prototypes for DirectPlay callback functions + * + ****************************************************************************/ + +/* + * Callback for IDirectPlay2::EnumSessions + */ +typedef BOOL (FAR PASCAL * LPDPENUMSESSIONSCALLBACK2)( + LPCDPSESSIONDESC2 lpThisSD, + LPDWORD lpdwTimeOut, + DWORD dwFlags, + LPVOID lpContext ); + +/* + * This flag is set on the EnumSessions callback dwFlags parameter when + * the time out has occurred. There will be no session data for this + * callback. If *lpdwTimeOut is set to a non-zero value and the + * EnumSessionsCallback function returns TRUE then EnumSessions will + * continue waiting until the next timeout occurs. Timeouts are in + * milliseconds. + */ +#define DPESC_TIMEDOUT 0x00000001 + + +/* + * Callback for IDirectPlay2::EnumPlayers + * IDirectPlay2::EnumGroups + * IDirectPlay2::EnumGroupPlayers + */ +typedef BOOL (FAR PASCAL *LPDPENUMPLAYERSCALLBACK2)( + DPID dpId, + DWORD dwPlayerType, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext ); + + +/* + * Unicode callback for DirectPlayEnumerate + * This callback prototype will be used if compiling + * for Unicode strings + */ +typedef BOOL (FAR PASCAL * LPDPENUMDPCALLBACK)( + LPGUID lpguidSP, + LPWSTR lpSPName, + DWORD dwMajorVersion, + DWORD dwMinorVersion, + LPVOID lpContext); + +/* + * ANSI callback for DirectPlayEnumerate + * This callback prototype will be used if compiling + * for ANSI strings + */ +typedef BOOL (FAR PASCAL * LPDPENUMDPCALLBACKA)( + LPGUID lpguidSP, + LPSTR lpSPName, + DWORD dwMajorVersion, + DWORD dwMinorVersion, + LPVOID lpContext); + +/* + * Callback for IDirectPlay3(A)::EnumConnections + */ +typedef BOOL (FAR PASCAL * LPDPENUMCONNECTIONSCALLBACK)( + LPCGUID lpguidSP, + LPVOID lpConnection, + DWORD dwConnectionSize, + LPCDPNAME lpName, + DWORD dwFlags, + LPVOID lpContext); + + +/* + * API's + */ + +#ifdef UNICODE +#define DirectPlayEnumerate DirectPlayEnumerateW +#else +#define DirectPlayEnumerate DirectPlayEnumerateA +#endif // UNICODE + +extern HRESULT WINAPI DirectPlayEnumerateA( LPDPENUMDPCALLBACKA, LPVOID ); +extern HRESULT WINAPI DirectPlayEnumerateW( LPDPENUMDPCALLBACK, LPVOID ); +extern HRESULT WINAPI DirectPlayCreate( LPGUID lpGUID, LPDIRECTPLAY *lplpDP, IUnknown *pUnk); + +/**************************************************************************** + * + * IDirectPlay2 (and IDirectPlay2A) Interface + * + ****************************************************************************/ + +#undef INTERFACE +#define INTERFACE IDirectPlay2 +DECLARE_INTERFACE_( IDirectPlay2, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectPlay2 methods ***/ + STDMETHOD(AddPlayerToGroup) (THIS_ DPID, DPID) PURE; + STDMETHOD(Close) (THIS) PURE; + STDMETHOD(CreateGroup) (THIS_ LPDPID,LPDPNAME,LPVOID,DWORD,DWORD) PURE; + STDMETHOD(CreatePlayer) (THIS_ LPDPID,LPDPNAME,HANDLE,LPVOID,DWORD,DWORD) PURE; + STDMETHOD(DeletePlayerFromGroup)(THIS_ DPID,DPID) PURE; + STDMETHOD(DestroyGroup) (THIS_ DPID) PURE; + STDMETHOD(DestroyPlayer) (THIS_ DPID) PURE; + STDMETHOD(EnumGroupPlayers) (THIS_ DPID,LPGUID,LPDPENUMPLAYERSCALLBACK2,LPVOID,DWORD) PURE; + STDMETHOD(EnumGroups) (THIS_ LPGUID,LPDPENUMPLAYERSCALLBACK2,LPVOID,DWORD) PURE; + STDMETHOD(EnumPlayers) (THIS_ LPGUID,LPDPENUMPLAYERSCALLBACK2,LPVOID,DWORD) PURE; + STDMETHOD(EnumSessions) (THIS_ LPDPSESSIONDESC2,DWORD,LPDPENUMSESSIONSCALLBACK2,LPVOID,DWORD) PURE; + STDMETHOD(GetCaps) (THIS_ LPDPCAPS,DWORD) PURE; + STDMETHOD(GetGroupData) (THIS_ DPID,LPVOID,LPDWORD,DWORD) PURE; + STDMETHOD(GetGroupName) (THIS_ DPID,LPVOID,LPDWORD) PURE; + STDMETHOD(GetMessageCount) (THIS_ DPID, LPDWORD) PURE; + STDMETHOD(GetPlayerAddress) (THIS_ DPID,LPVOID,LPDWORD) PURE; + STDMETHOD(GetPlayerCaps) (THIS_ DPID,LPDPCAPS,DWORD) PURE; + STDMETHOD(GetPlayerData) (THIS_ DPID,LPVOID,LPDWORD,DWORD) PURE; + STDMETHOD(GetPlayerName) (THIS_ DPID,LPVOID,LPDWORD) PURE; + STDMETHOD(GetSessionDesc) (THIS_ LPVOID,LPDWORD) PURE; + STDMETHOD(Initialize) (THIS_ LPGUID) PURE; + STDMETHOD(Open) (THIS_ LPDPSESSIONDESC2,DWORD) PURE; + STDMETHOD(Receive) (THIS_ LPDPID,LPDPID,DWORD,LPVOID,LPDWORD) PURE; + STDMETHOD(Send) (THIS_ DPID, DPID, DWORD, LPVOID, DWORD) PURE; + STDMETHOD(SetGroupData) (THIS_ DPID,LPVOID,DWORD,DWORD) PURE; + STDMETHOD(SetGroupName) (THIS_ DPID,LPDPNAME,DWORD) PURE; + STDMETHOD(SetPlayerData) (THIS_ DPID,LPVOID,DWORD,DWORD) PURE; + STDMETHOD(SetPlayerName) (THIS_ DPID,LPDPNAME,DWORD) PURE; + STDMETHOD(SetSessionDesc) (THIS_ LPDPSESSIONDESC2,DWORD) PURE; +}; + +/**************************************************************************** + * + * IDirectPlay2 interface macros + * + ****************************************************************************/ + +#if !defined(__cplusplus) || defined(CINTERFACE) + +#define IDirectPlay2_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectPlay2_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectPlay2_Release(p) (p)->lpVtbl->Release(p) +#define IDirectPlay2_AddPlayerToGroup(p,a,b) (p)->lpVtbl->AddPlayerToGroup(p,a,b) +#define IDirectPlay2_Close(p) (p)->lpVtbl->Close(p) +#define IDirectPlay2_CreateGroup(p,a,b,c,d,e) (p)->lpVtbl->CreateGroup(p,a,b,c,d,e) +#define IDirectPlay2_CreatePlayer(p,a,b,c,d,e,f) (p)->lpVtbl->CreatePlayer(p,a,b,c,d,e,f) +#define IDirectPlay2_DeletePlayerFromGroup(p,a,b) (p)->lpVtbl->DeletePlayerFromGroup(p,a,b) +#define IDirectPlay2_DestroyGroup(p,a) (p)->lpVtbl->DestroyGroup(p,a) +#define IDirectPlay2_DestroyPlayer(p,a) (p)->lpVtbl->DestroyPlayer(p,a) +#define IDirectPlay2_EnumGroupPlayers(p,a,b,c,d,e) (p)->lpVtbl->EnumGroupPlayers(p,a,b,c,d,e) +#define IDirectPlay2_EnumGroups(p,a,b,c,d) (p)->lpVtbl->EnumGroups(p,a,b,c,d) +#define IDirectPlay2_EnumPlayers(p,a,b,c,d) (p)->lpVtbl->EnumPlayers(p,a,b,c,d) +#define IDirectPlay2_EnumSessions(p,a,b,c,d,e) (p)->lpVtbl->EnumSessions(p,a,b,c,d,e) +#define IDirectPlay2_GetCaps(p,a,b) (p)->lpVtbl->GetCaps(p,a,b) +#define IDirectPlay2_GetMessageCount(p,a,b) (p)->lpVtbl->GetMessageCount(p,a,b) +#define IDirectPlay2_GetGroupData(p,a,b,c,d) (p)->lpVtbl->GetGroupData(p,a,b,c,d) +#define IDirectPlay2_GetGroupName(p,a,b,c) (p)->lpVtbl->GetGroupName(p,a,b,c) +#define IDirectPlay2_GetPlayerAddress(p,a,b,c) (p)->lpVtbl->GetPlayerAddress(p,a,b,c) +#define IDirectPlay2_GetPlayerCaps(p,a,b,c) (p)->lpVtbl->GetPlayerCaps(p,a,b,c) +#define IDirectPlay2_GetPlayerData(p,a,b,c,d) (p)->lpVtbl->GetPlayerData(p,a,b,c,d) +#define IDirectPlay2_GetPlayerName(p,a,b,c) (p)->lpVtbl->GetPlayerName(p,a,b,c) +#define IDirectPlay2_GetSessionDesc(p,a,b) (p)->lpVtbl->GetSessionDesc(p,a,b) +#define IDirectPlay2_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) +#define IDirectPlay2_Open(p,a,b) (p)->lpVtbl->Open(p,a,b) +#define IDirectPlay2_Receive(p,a,b,c,d,e) (p)->lpVtbl->Receive(p,a,b,c,d,e) +#define IDirectPlay2_Send(p,a,b,c,d,e) (p)->lpVtbl->Send(p,a,b,c,d,e) +#define IDirectPlay2_SetGroupData(p,a,b,c,d) (p)->lpVtbl->SetGroupData(p,a,b,c,d) +#define IDirectPlay2_SetGroupName(p,a,b,c) (p)->lpVtbl->SetGroupName(p,a,b,c) +#define IDirectPlay2_SetPlayerData(p,a,b,c,d) (p)->lpVtbl->SetPlayerData(p,a,b,c,d) +#define IDirectPlay2_SetPlayerName(p,a,b,c) (p)->lpVtbl->SetPlayerName(p,a,b,c) +#define IDirectPlay2_SetSessionDesc(p,a,b) (p)->lpVtbl->SetSessionDesc(p,a,b) + +#else /* C++ */ + +#define IDirectPlay2_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectPlay2_AddRef(p) (p)->AddRef() +#define IDirectPlay2_Release(p) (p)->Release() +#define IDirectPlay2_AddPlayerToGroup(p,a,b) (p)->AddPlayerToGroup(a,b) +#define IDirectPlay2_Close(p) (p)->Close() +#define IDirectPlay2_CreateGroup(p,a,b,c,d,e) (p)->CreateGroup(a,b,c,d,e) +#define IDirectPlay2_CreatePlayer(p,a,b,c,d,e,f) (p)->CreatePlayer(a,b,c,d,e,f) +#define IDirectPlay2_DeletePlayerFromGroup(p,a,b) (p)->DeletePlayerFromGroup(a,b) +#define IDirectPlay2_DestroyGroup(p,a) (p)->DestroyGroup(a) +#define IDirectPlay2_DestroyPlayer(p,a) (p)->DestroyPlayer(a) +#define IDirectPlay2_EnumGroupPlayers(p,a,b,c,d,e) (p)->EnumGroupPlayers(a,b,c,d,e) +#define IDirectPlay2_EnumGroups(p,a,b,c,d) (p)->EnumGroups(a,b,c,d) +#define IDirectPlay2_EnumPlayers(p,a,b,c,d) (p)->EnumPlayers(a,b,c,d) +#define IDirectPlay2_EnumSessions(p,a,b,c,d,e) (p)->EnumSessions(a,b,c,d,e) +#define IDirectPlay2_GetCaps(p,a,b) (p)->GetCaps(a,b) +#define IDirectPlay2_GetMessageCount(p,a,b) (p)->GetMessageCount(a,b) +#define IDirectPlay2_GetGroupData(p,a,b,c,d) (p)->GetGroupData(a,b,c,d) +#define IDirectPlay2_GetGroupName(p,a,b,c) (p)->GetGroupName(a,b,c) +#define IDirectPlay2_GetPlayerAddress(p,a,b,c) (p)->GetPlayerAddress(a,b,c) +#define IDirectPlay2_GetPlayerCaps(p,a,b,c) (p)->GetPlayerCaps(a,b,c) +#define IDirectPlay2_GetPlayerData(p,a,b,c,d) (p)->GetPlayerData(a,b,c,d) +#define IDirectPlay2_GetPlayerName(p,a,b,c) (p)->GetPlayerName(a,b,c) +#define IDirectPlay2_GetSessionDesc(p,a,b) (p)->GetSessionDesc(a,b) +#define IDirectPlay2_Initialize(p,a) (p)->Initialize(a) +#define IDirectPlay2_Open(p,a,b) (p)->Open(a,b) +#define IDirectPlay2_Receive(p,a,b,c,d,e) (p)->Receive(a,b,c,d,e) +#define IDirectPlay2_Send(p,a,b,c,d,e) (p)->Send(a,b,c,d,e) +#define IDirectPlay2_SetGroupData(p,a,b,c,d) (p)->SetGroupData(a,b,c,d) +#define IDirectPlay2_SetGroupName(p,a,b,c) (p)->SetGroupName(a,b,c) +#define IDirectPlay2_SetPlayerData(p,a,b,c,d) (p)->SetPlayerData(a,b,c,d) +#define IDirectPlay2_SetPlayerName(p,a,b,c) (p)->SetPlayerName(a,b,c) +#define IDirectPlay2_SetSessionDesc(p,a,b) (p)->SetSessionDesc(a,b) + +#endif + +/**************************************************************************** + * + * IDirectPlay3 (and IDirectPlay3A) Interface + * + ****************************************************************************/ + +#undef INTERFACE +#define INTERFACE IDirectPlay3 +DECLARE_INTERFACE_( IDirectPlay3, IDirectPlay2 ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectPlay2 methods ***/ + STDMETHOD(AddPlayerToGroup) (THIS_ DPID, DPID) PURE; + STDMETHOD(Close) (THIS) PURE; + STDMETHOD(CreateGroup) (THIS_ LPDPID,LPDPNAME,LPVOID,DWORD,DWORD) PURE; + STDMETHOD(CreatePlayer) (THIS_ LPDPID,LPDPNAME,HANDLE,LPVOID,DWORD,DWORD) PURE; + STDMETHOD(DeletePlayerFromGroup)(THIS_ DPID,DPID) PURE; + STDMETHOD(DestroyGroup) (THIS_ DPID) PURE; + STDMETHOD(DestroyPlayer) (THIS_ DPID) PURE; + STDMETHOD(EnumGroupPlayers) (THIS_ DPID,LPGUID,LPDPENUMPLAYERSCALLBACK2,LPVOID,DWORD) PURE; + STDMETHOD(EnumGroups) (THIS_ LPGUID,LPDPENUMPLAYERSCALLBACK2,LPVOID,DWORD) PURE; + STDMETHOD(EnumPlayers) (THIS_ LPGUID,LPDPENUMPLAYERSCALLBACK2,LPVOID,DWORD) PURE; + STDMETHOD(EnumSessions) (THIS_ LPDPSESSIONDESC2,DWORD,LPDPENUMSESSIONSCALLBACK2,LPVOID,DWORD) PURE; + STDMETHOD(GetCaps) (THIS_ LPDPCAPS,DWORD) PURE; + STDMETHOD(GetGroupData) (THIS_ DPID,LPVOID,LPDWORD,DWORD) PURE; + STDMETHOD(GetGroupName) (THIS_ DPID,LPVOID,LPDWORD) PURE; + STDMETHOD(GetMessageCount) (THIS_ DPID, LPDWORD) PURE; + STDMETHOD(GetPlayerAddress) (THIS_ DPID,LPVOID,LPDWORD) PURE; + STDMETHOD(GetPlayerCaps) (THIS_ DPID,LPDPCAPS,DWORD) PURE; + STDMETHOD(GetPlayerData) (THIS_ DPID,LPVOID,LPDWORD,DWORD) PURE; + STDMETHOD(GetPlayerName) (THIS_ DPID,LPVOID,LPDWORD) PURE; + STDMETHOD(GetSessionDesc) (THIS_ LPVOID,LPDWORD) PURE; + STDMETHOD(Initialize) (THIS_ LPGUID) PURE; + STDMETHOD(Open) (THIS_ LPDPSESSIONDESC2,DWORD) PURE; + STDMETHOD(Receive) (THIS_ LPDPID,LPDPID,DWORD,LPVOID,LPDWORD) PURE; + STDMETHOD(Send) (THIS_ DPID, DPID, DWORD, LPVOID, DWORD) PURE; + STDMETHOD(SetGroupData) (THIS_ DPID,LPVOID,DWORD,DWORD) PURE; + STDMETHOD(SetGroupName) (THIS_ DPID,LPDPNAME,DWORD) PURE; + STDMETHOD(SetPlayerData) (THIS_ DPID,LPVOID,DWORD,DWORD) PURE; + STDMETHOD(SetPlayerName) (THIS_ DPID,LPDPNAME,DWORD) PURE; + STDMETHOD(SetSessionDesc) (THIS_ LPDPSESSIONDESC2,DWORD) PURE; + /*** IDirectPlay3 methods ***/ + STDMETHOD(AddGroupToGroup) (THIS_ DPID, DPID) PURE; + STDMETHOD(CreateGroupInGroup) (THIS_ DPID,LPDPID,LPDPNAME,LPVOID,DWORD,DWORD) PURE; + STDMETHOD(DeleteGroupFromGroup) (THIS_ DPID,DPID) PURE; + STDMETHOD(EnumConnections) (THIS_ LPCGUID,LPDPENUMCONNECTIONSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(EnumGroupsInGroup) (THIS_ DPID,LPGUID,LPDPENUMPLAYERSCALLBACK2,LPVOID,DWORD) PURE; + STDMETHOD(GetGroupConnectionSettings)(THIS_ DWORD, DPID, LPVOID, LPDWORD) PURE; + STDMETHOD(InitializeConnection) (THIS_ LPVOID,DWORD) PURE; + STDMETHOD(SecureOpen) (THIS_ LPCDPSESSIONDESC2,DWORD,LPCDPSECURITYDESC,LPCDPCREDENTIALS) PURE; + STDMETHOD(SendChatMessage) (THIS_ DPID,DPID,DWORD,LPDPCHAT); + STDMETHOD(SetGroupConnectionSettings)(THIS_ DWORD,DPID,LPDPLCONNECTION) PURE; + STDMETHOD(StartSession) (THIS_ DWORD,DPID); + STDMETHOD(GetGroupFlags) (THIS_ DPID,LPDWORD); + STDMETHOD(GetGroupParent) (THIS_ DPID,LPDPID); + STDMETHOD(GetPlayerAccount) (THIS_ DPID, DWORD, LPVOID, LPDWORD) PURE; + STDMETHOD(GetPlayerFlags) (THIS_ DPID,LPDWORD); +}; + +/**************************************************************************** + * + * IDirectPlay3 interface macros + * + ****************************************************************************/ + +#if !defined(__cplusplus) || defined(CINTERFACE) + +#define IDirectPlay3_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectPlay3_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectPlay3_Release(p) (p)->lpVtbl->Release(p) +#define IDirectPlay3_AddPlayerToGroup(p,a,b) (p)->lpVtbl->AddPlayerToGroup(p,a,b) +#define IDirectPlay3_Close(p) (p)->lpVtbl->Close(p) +#define IDirectPlay3_CreateGroup(p,a,b,c,d,e) (p)->lpVtbl->CreateGroup(p,a,b,c,d,e) +#define IDirectPlay3_CreatePlayer(p,a,b,c,d,e,f) (p)->lpVtbl->CreatePlayer(p,a,b,c,d,e,f) +#define IDirectPlay3_DeletePlayerFromGroup(p,a,b) (p)->lpVtbl->DeletePlayerFromGroup(p,a,b) +#define IDirectPlay3_DestroyGroup(p,a) (p)->lpVtbl->DestroyGroup(p,a) +#define IDirectPlay3_DestroyPlayer(p,a) (p)->lpVtbl->DestroyPlayer(p,a) +#define IDirectPlay3_EnumGroupPlayers(p,a,b,c,d,e) (p)->lpVtbl->EnumGroupPlayers(p,a,b,c,d,e) +#define IDirectPlay3_EnumGroups(p,a,b,c,d) (p)->lpVtbl->EnumGroups(p,a,b,c,d) +#define IDirectPlay3_EnumPlayers(p,a,b,c,d) (p)->lpVtbl->EnumPlayers(p,a,b,c,d) +#define IDirectPlay3_EnumSessions(p,a,b,c,d,e) (p)->lpVtbl->EnumSessions(p,a,b,c,d,e) +#define IDirectPlay3_GetCaps(p,a,b) (p)->lpVtbl->GetCaps(p,a,b) +#define IDirectPlay3_GetMessageCount(p,a,b) (p)->lpVtbl->GetMessageCount(p,a,b) +#define IDirectPlay3_GetGroupData(p,a,b,c,d) (p)->lpVtbl->GetGroupData(p,a,b,c,d) +#define IDirectPlay3_GetGroupName(p,a,b,c) (p)->lpVtbl->GetGroupName(p,a,b,c) +#define IDirectPlay3_GetPlayerAddress(p,a,b,c) (p)->lpVtbl->GetPlayerAddress(p,a,b,c) +#define IDirectPlay3_GetPlayerCaps(p,a,b,c) (p)->lpVtbl->GetPlayerCaps(p,a,b,c) +#define IDirectPlay3_GetPlayerData(p,a,b,c,d) (p)->lpVtbl->GetPlayerData(p,a,b,c,d) +#define IDirectPlay3_GetPlayerName(p,a,b,c) (p)->lpVtbl->GetPlayerName(p,a,b,c) +#define IDirectPlay3_GetSessionDesc(p,a,b) (p)->lpVtbl->GetSessionDesc(p,a,b) +#define IDirectPlay3_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) +#define IDirectPlay3_Open(p,a,b) (p)->lpVtbl->Open(p,a,b) +#define IDirectPlay3_Receive(p,a,b,c,d,e) (p)->lpVtbl->Receive(p,a,b,c,d,e) +#define IDirectPlay3_Send(p,a,b,c,d,e) (p)->lpVtbl->Send(p,a,b,c,d,e) +#define IDirectPlay3_SetGroupData(p,a,b,c,d) (p)->lpVtbl->SetGroupData(p,a,b,c,d) +#define IDirectPlay3_SetGroupName(p,a,b,c) (p)->lpVtbl->SetGroupName(p,a,b,c) +#define IDirectPlay3_SetPlayerData(p,a,b,c,d) (p)->lpVtbl->SetPlayerData(p,a,b,c,d) +#define IDirectPlay3_SetPlayerName(p,a,b,c) (p)->lpVtbl->SetPlayerName(p,a,b,c) +#define IDirectPlay3_SetSessionDesc(p,a,b) (p)->lpVtbl->SetSessionDesc(p,a,b) +#define IDirectPlay3_AddGroupToGroup(p,a,b) (p)->lpVtbl->AddGroupToGroup(p,a,b) +#define IDirectPlay3_CreateGroupInGroup(p,a,b,c,d,e,f) (p)->lpVtbl->CreateGroupInGroup(p,a,b,c,d,e,f) +#define IDirectPlay3_DeleteGroupFromGroup(p,a,b) (p)->lpVtbl->DeleteGroupFromGroup(p,a,b) +#define IDirectPlay3_EnumConnections(p,a,b,c,d) (p)->lpVtbl->EnumConnections(p,a,b,c,d) +#define IDirectPlay3_EnumGroupsInGroup(p,a,b,c,d,e) (p)->lpVtbl->EnumGroupsInGroup(p,a,b,c,d,e) +#define IDirectPlay3_GetGroupConnectionSettings(p,a,b,c,d) (p)->lpVtbl->GetGroupConnectionSettings(p,a,b,c,d) +#define IDirectPlay3_InitializeConnection(p,a,b) (p)->lpVtbl->InitializeConnection(p,a,b) +#define IDirectPlay3_SecureOpen(p,a,b,c,d) (p)->lpVtbl->SecureOpen(p,a,b,c,d) +#define IDirectPlay3_SendChatMessage(p,a,b,c,d) (p)->lpVtbl->SendChatMessage(p,a,b,c,d) +#define IDirectPlay3_SetGroupConnectionSettings(p,a,b,c) (p)->lpVtbl->SetGroupConnectionSettings(p,a,b,c) +#define IDirectPlay3_StartSession(p,a,b) (p)->lpVtbl->StartSession(p,a,b) +#define IDirectPlay3_GetGroupFlags(p,a,b) (p)->lpVtbl->GetGroupFlags(p,a,b) +#define IDirectPlay3_GetGroupParent(p,a,b) (p)->lpVtbl->GetGroupParent(p,a,b) +#define IDirectPlay3_GetPlayerAccount(p,a,b,c,d) (p)->lpVtbl->GetPlayerAccount(p,a,b,c,d) +#define IDirectPlay3_GetPlayerFlags(p,a,b) (p)->lpVtbl->GetPlayerFlags(p,a,b) + +#else /* C++ */ + +#define IDirectPlay3_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectPlay3_AddRef(p) (p)->AddRef() +#define IDirectPlay3_Release(p) (p)->Release() +#define IDirectPlay3_AddPlayerToGroup(p,a,b) (p)->AddPlayerToGroup(a,b) +#define IDirectPlay3_Close(p) (p)->Close() +#define IDirectPlay3_CreateGroup(p,a,b,c,d,e) (p)->CreateGroup(a,b,c,d,e) +#define IDirectPlay3_CreatePlayer(p,a,b,c,d,e,f) (p)->CreatePlayer(a,b,c,d,e,f) +#define IDirectPlay3_DeletePlayerFromGroup(p,a,b) (p)->DeletePlayerFromGroup(a,b) +#define IDirectPlay3_DestroyGroup(p,a) (p)->DestroyGroup(a) +#define IDirectPlay3_DestroyPlayer(p,a) (p)->DestroyPlayer(a) +#define IDirectPlay3_EnumGroupPlayers(p,a,b,c,d,e) (p)->EnumGroupPlayers(a,b,c,d,e) +#define IDirectPlay3_EnumGroups(p,a,b,c,d) (p)->EnumGroups(a,b,c,d) +#define IDirectPlay3_EnumPlayers(p,a,b,c,d) (p)->EnumPlayers(a,b,c,d) +#define IDirectPlay3_EnumSessions(p,a,b,c,d,e) (p)->EnumSessions(a,b,c,d,e) +#define IDirectPlay3_GetCaps(p,a,b) (p)->GetCaps(a,b) +#define IDirectPlay3_GetMessageCount(p,a,b) (p)->GetMessageCount(a,b) +#define IDirectPlay3_GetGroupData(p,a,b,c,d) (p)->GetGroupData(a,b,c,d) +#define IDirectPlay3_GetGroupName(p,a,b,c) (p)->GetGroupName(a,b,c) +#define IDirectPlay3_GetPlayerAddress(p,a,b,c) (p)->GetPlayerAddress(a,b,c) +#define IDirectPlay3_GetPlayerCaps(p,a,b,c) (p)->GetPlayerCaps(a,b,c) +#define IDirectPlay3_GetPlayerData(p,a,b,c,d) (p)->GetPlayerData(a,b,c,d) +#define IDirectPlay3_GetPlayerName(p,a,b,c) (p)->GetPlayerName(a,b,c) +#define IDirectPlay3_GetSessionDesc(p,a,b) (p)->GetSessionDesc(a,b) +#define IDirectPlay3_Initialize(p,a) (p)->Initialize(a) +#define IDirectPlay3_Open(p,a,b) (p)->Open(a,b) +#define IDirectPlay3_Receive(p,a,b,c,d,e) (p)->Receive(a,b,c,d,e) +#define IDirectPlay3_Send(p,a,b,c,d,e) (p)->Send(a,b,c,d,e) +#define IDirectPlay3_SetGroupData(p,a,b,c,d) (p)->SetGroupData(a,b,c,d) +#define IDirectPlay3_SetGroupName(p,a,b,c) (p)->SetGroupName(a,b,c) +#define IDirectPlay3_SetPlayerData(p,a,b,c,d) (p)->SetPlayerData(a,b,c,d) +#define IDirectPlay3_SetPlayerName(p,a,b,c) (p)->SetPlayerName(a,b,c) +#define IDirectPlay3_SetSessionDesc(p,a,b) (p)->SetSessionDesc(a,b) +#define IDirectPlay3_AddGroupToGroup(p,a,b) (p)->AddGroupToGroup(a,b) +#define IDirectPlay3_CreateGroupInGroup(p,a,b,c,d,e,f) (p)->CreateGroupInGroup(a,b,c,d,e,f) +#define IDirectPlay3_DeleteGroupFromGroup(p,a,b) (p)->DeleteGroupFromGroup(a,b) +#define IDirectPlay3_EnumConnections(p,a,b,c,d) (p)->EnumConnections(a,b,c,d) +#define IDirectPlay3_EnumGroupsInGroup(p,a,b,c,d,e) (p)->EnumGroupsInGroup(a,b,c,d,e) +#define IDirectPlay3_GetGroupConnectionSettings(p,a,b,c,d) (p)->GetGroupConnectionSettings(a,b,c,d) +#define IDirectPlay3_InitializeConnection(p,a,b) (p)->InitializeConnection(a,b) +#define IDirectPlay3_SecureOpen(p,a,b,c,d) (p)->SecureOpen(a,b,c,d) +#define IDirectPlay3_SendChatMessage(p,a,b,c,d) (p)->SendChatMessage(a,b,c,d) +#define IDirectPlay3_SetGroupConnectionSettings(p,a,b,c) (p)->SetGroupConnectionSettings(a,b,c) +#define IDirectPlay3_StartSession(p,a,b) (p)->StartSession(a,b) +#define IDirectPlay3_GetGroupFlags(p,a,b) (p)->GetGroupFlags(a,b) +#define IDirectPlay3_GetGroupParent(p,a,b) (p)->GetGroupParent(a,b) +#define IDirectPlay3_GetPlayerAccount(p,a,b,c,d) (p)->GetPlayerAccount(a,b,c,d) +#define IDirectPlay3_GetPlayerFlags(p,a,b) (p)->GetPlayerFlags(a,b) + +#endif + +/**************************************************************************** + * + * EnumConnections API flags + * + ****************************************************************************/ + +/* + * Enumerate Service Providers + */ +#define DPCONNECTION_DIRECTPLAY 0x00000001 + +/* + * Enumerate Lobby Providers + */ +#define DPCONNECTION_DIRECTPLAYLOBBY 0x00000002 + + +/**************************************************************************** + * + * EnumPlayers API flags + * + ****************************************************************************/ + +/* + * Enumerate all players in the current session + */ +#define DPENUMPLAYERS_ALL 0x00000000 +#define DPENUMGROUPS_ALL DPENUMPLAYERS_ALL + + +/* + * Enumerate only local (created by this application) players + * or groups + */ +#define DPENUMPLAYERS_LOCAL 0x00000008 +#define DPENUMGROUPS_LOCAL DPENUMPLAYERS_LOCAL + +/* + * Enumerate only remote (non-local) players + * or groups + */ +#define DPENUMPLAYERS_REMOTE 0x00000010 +#define DPENUMGROUPS_REMOTE DPENUMPLAYERS_REMOTE + +/* + * Enumerate groups along with the players + */ +#define DPENUMPLAYERS_GROUP 0x00000020 + +/* + * Enumerate players or groups in another session + * (must supply lpguidInstance) + */ +#define DPENUMPLAYERS_SESSION 0x00000080 +#define DPENUMGROUPS_SESSION DPENUMPLAYERS_SESSION + +/* + * Enumerate server players + */ +#define DPENUMPLAYERS_SERVERPLAYER 0x00000100 + +/* + * Enumerate spectator players + */ +#define DPENUMPLAYERS_SPECTATOR 0x00000200 + +/* + * Enumerate shortcut groups + */ +#define DPENUMGROUPS_SHORTCUT 0x00000400 + +/* + * Enumerate staging area groups + */ +#define DPENUMGROUPS_STAGINGAREA 0x00000800 + +/**************************************************************************** + * + * CreatePlayer API flags + * + ****************************************************************************/ + +/* + * This flag indicates that this player should be designated + * the server player. The app should specify this at CreatePlayer. + */ +#define DPPLAYER_SERVERPLAYER DPENUMPLAYERS_SERVERPLAYER + +/* + * This flag indicates that this player should be designated + * a spectator. The app should specify this at CreatePlayer. + */ +#define DPPLAYER_SPECTATOR DPENUMPLAYERS_SPECTATOR + +/* + * This flag indicates that this player was created locally. + * (returned from GetPlayerFlags) + */ +#define DPPLAYER_LOCAL DPENUMPLAYERS_LOCAL + +/**************************************************************************** + * + * CreateGroup API flags + * + ****************************************************************************/ + + +/* + * This flag indicates that the StartSession can be called on the group. + * The app should specify this at CreateGroup, or CreateGroupInGroup. + */ +#define DPGROUP_STAGINGAREA DPENUMGROUPS_STAGINGAREA + +/* + * This flag indicates that this group was created locally. + * (returned from GetGroupFlags) + */ +#define DPGROUP_LOCAL DPENUMGROUPS_LOCAL + +/**************************************************************************** + * + * EnumSessions API flags + * + ****************************************************************************/ + +/* + * Enumerate sessions which can be joined + */ +#define DPENUMSESSIONS_AVAILABLE 0x00000001 + +/* + * Enumerate all sessions even if they can't be joined. + */ +#define DPENUMSESSIONS_ALL 0x00000002 + + + + +/* + * Start an asynchronous enum sessions + */ + #define DPENUMSESSIONS_ASYNC 0x00000010 + +/* + * Stop an asynchronous enum sessions + */ + #define DPENUMSESSIONS_STOPASYNC 0x00000020 + +/* + * Enumerate sessions even if they require a password + */ + #define DPENUMSESSIONS_PASSWORDREQUIRED 0x00000040 + +/* + * Return status about progress of enumeration instead of + * showing any status dialogs. + */ + #define DPENUMSESSIONS_RETURNSTATUS 0x00000080 + +/**************************************************************************** + * + * GetCaps and GetPlayerCaps API flags + * + ****************************************************************************/ + +/* + * The latency returned should be for guaranteed message sending. + * Default is non-guaranteed messaging. + */ +#define DPGETCAPS_GUARANTEED 0x00000001 + + +/**************************************************************************** + * + * GetGroupData, GetPlayerData API flags + * Remote and local Group/Player data is maintained separately. + * Default is DPGET_REMOTE. + * + ****************************************************************************/ + +/* + * Get the remote data (set by any DirectPlay object in + * the session using DPSET_REMOTE) + */ +#define DPGET_REMOTE 0x00000000 + +/* + * Get the local data (set by this DirectPlay object + * using DPSET_LOCAL) + */ +#define DPGET_LOCAL 0x00000001 + + +/**************************************************************************** + * + * Open API flags + * + ****************************************************************************/ + +/* + * Join the session that is described by the DPSESSIONDESC2 structure + */ +#define DPOPEN_JOIN 0x00000001 + +/* + * Create a new session as described by the DPSESSIONDESC2 structure + */ +#define DPOPEN_CREATE 0x00000002 + +/* + * Return status about progress of open instead of showing + * any status dialogs. + */ + #define DPOPEN_RETURNSTATUS DPENUMSESSIONS_RETURNSTATUS + +/**************************************************************************** + * + * DPLCONNECTION flags + * + ****************************************************************************/ + +/* + * This application should create a new session as + * described by the DPSESIONDESC structure + */ +#define DPLCONNECTION_CREATESESSION DPOPEN_CREATE + +/* + * This application should join the session described by + * the DPSESIONDESC structure with the lpAddress data + */ +#define DPLCONNECTION_JOINSESSION DPOPEN_JOIN + +/**************************************************************************** + * + * Receive API flags + * Default is DPRECEIVE_ALL + * + ****************************************************************************/ + +/* + * Get the first message in the queue + */ +#define DPRECEIVE_ALL 0x00000001 + +/* + * Get the first message in the queue directed to a specific player + */ +#define DPRECEIVE_TOPLAYER 0x00000002 + +/* + * Get the first message in the queue from a specific player + */ +#define DPRECEIVE_FROMPLAYER 0x00000004 + +/* + * Get the message but don't remove it from the queue + */ +#define DPRECEIVE_PEEK 0x00000008 + + +/**************************************************************************** + * + * Send API flags + * + ****************************************************************************/ + +/* + * Send the message using a guaranteed send method. + * Default is non-guaranteed. + */ +#define DPSEND_GUARANTEED 0x00000001 + + +/* + * This flag is obsolete. It is ignored by DirectPlay + */ +#define DPSEND_HIGHPRIORITY 0x00000002 + +/* + * This flag is obsolete. It is ignored by DirectPlay + */ +#define DPSEND_OPENSTREAM 0x00000008 + +/* + * This flag is obsolete. It is ignored by DirectPlay + */ +#define DPSEND_CLOSESTREAM 0x00000010 + +/* + * Send the message digitally signed to ensure authenticity. + */ +#define DPSEND_SIGNED 0x00000020 + +/* + * Send the message with encryption to ensure privacy. + */ +#define DPSEND_ENCRYPTED 0x00000040 + + +/**************************************************************************** + * + * SetGroupData, SetGroupName, SetPlayerData, SetPlayerName, + * SetSessionDesc API flags. + * Default is DPSET_REMOTE. + * + ****************************************************************************/ + +/* + * Propagate the data to all players in the session + */ +#define DPSET_REMOTE 0x00000000 + +/* + * Do not propagate the data to other players + */ +#define DPSET_LOCAL 0x00000001 + +/* + * Used with DPSET_REMOTE, use guaranteed message send to + * propagate the data + */ +#define DPSET_GUARANTEED 0x00000002 + + +/**************************************************************************** + * + * DirectPlay system messages and message data structures + * + * All system message come 'From' player DPID_SYSMSG. To determine what type + * of message it is, cast the lpData from Receive to DPMSG_GENERIC and check + * the dwType member against one of the following DPSYS_xxx constants. Once + * a match is found, cast the lpData to the corresponding of the DPMSG_xxx + * structures to access the data of the message. + * + ****************************************************************************/ + +/* + * A new player or group has been created in the session + * Use DPMSG_CREATEPLAYERORGROUP. Check dwPlayerType to see if it + * is a player or a group. + */ +#define DPSYS_CREATEPLAYERORGROUP 0x0003 + +/* + * A player has been deleted from the session + * Use DPMSG_DESTROYPLAYERORGROUP + */ +#define DPSYS_DESTROYPLAYERORGROUP 0x0005 + +/* + * A player has been added to a group + * Use DPMSG_ADDPLAYERTOGROUP + */ +#define DPSYS_ADDPLAYERTOGROUP 0x0007 + +/* + * A player has been removed from a group + * Use DPMSG_DELETEPLAYERFROMGROUP + */ +#define DPSYS_DELETEPLAYERFROMGROUP 0x0021 + +/* + * This DirectPlay object lost its connection with all the + * other players in the session. + * Use DPMSG_SESSIONLOST. + */ +#define DPSYS_SESSIONLOST 0x0031 + +/* + * The current host has left the session. + * This DirectPlay object is now the host. + * Use DPMSG_HOST. + */ +#define DPSYS_HOST 0x0101 + +/* + * The remote data associated with a player or + * group has changed. Check dwPlayerType to see + * if it is a player or a group + * Use DPMSG_SETPLAYERORGROUPDATA + */ +#define DPSYS_SETPLAYERORGROUPDATA 0x0102 + +/* + * The name of a player or group has changed. + * Check dwPlayerType to see if it is a player + * or a group. + * Use DPMSG_SETPLAYERORGROUPNAME + */ +#define DPSYS_SETPLAYERORGROUPNAME 0x0103 + +/* + * The session description has changed. + * Use DPMSG_SETSESSIONDESC + */ +#define DPSYS_SETSESSIONDESC 0x0104 + +/* + * A group has been added to a group + * Use DPMSG_ADDGROUPTOGROUP + */ +#define DPSYS_ADDGROUPTOGROUP 0x0105 + +/* + * A group has been removed from a group + * Use DPMSG_DELETEGROUPFROMGROUP + */ +#define DPSYS_DELETEGROUPFROMGROUP 0x0106 + +/* + * A secure player-player message has arrived. + * Use DPMSG_SECUREMESSAGE + */ +#define DPSYS_SECUREMESSAGE 0x0107 + +/* + * Start a new session. + * Use DPMSG_STARTSESSION + */ +#define DPSYS_STARTSESSION 0x0108 + +/* + * A chat message has arrived + * Use DPMSG_CHAT + */ +#define DPSYS_CHAT 0x0109 + +/* + * Used in the dwPlayerType field to indicate if it applies to a group + * or a player + */ +#define DPPLAYERTYPE_GROUP 0x00000000 +#define DPPLAYERTYPE_PLAYER 0x00000001 + + +/* + * DPMSG_GENERIC + * Generic message structure used to identify the message type. + */ +typedef struct +{ + DWORD dwType; // Message type +} DPMSG_GENERIC, FAR *LPDPMSG_GENERIC; + +/* + * DPMSG_CREATEPLAYERORGROUP + * System message generated when a new player or group + * created in the session with information about it. + */ +typedef struct +{ + DWORD dwType; // Message type + DWORD dwPlayerType; // Is it a player or group + DPID dpId; // ID of the player or group + DWORD dwCurrentPlayers; // current # players & groups in session + LPVOID lpData; // pointer to remote data + DWORD dwDataSize; // size of remote data + DPNAME dpnName; // structure with name info + // the following fields are only available when using + // the IDirectPlay3 interface or greater + DPID dpIdParent; // id of parent group + DWORD dwFlags; // player or group flags +} DPMSG_CREATEPLAYERORGROUP, FAR *LPDPMSG_CREATEPLAYERORGROUP; + +/* + * DPMSG_DESTROYPLAYERORGROUP + * System message generated when a player or group is being + * destroyed in the session with information about it. + */ +typedef struct +{ + DWORD dwType; // Message type + DWORD dwPlayerType; // Is it a player or group + DPID dpId; // player ID being deleted + LPVOID lpLocalData; // copy of players local data + DWORD dwLocalDataSize; // sizeof local data + LPVOID lpRemoteData; // copy of players remote data + DWORD dwRemoteDataSize; // sizeof remote data + // the following fields are only available when using + // the IDirectPlay3 interface or greater + DPNAME dpnName; // structure with name info + DPID dpIdParent; // id of parent group + DWORD dwFlags; // player or group flags +} DPMSG_DESTROYPLAYERORGROUP, FAR *LPDPMSG_DESTROYPLAYERORGROUP; + +/* + * DPMSG_ADDPLAYERTOGROUP + * System message generated when a player is being added + * to a group. + */ +typedef struct +{ + DWORD dwType; // Message type + DPID dpIdGroup; // group ID being added to + DPID dpIdPlayer; // player ID being added +} DPMSG_ADDPLAYERTOGROUP, FAR *LPDPMSG_ADDPLAYERTOGROUP; + +/* + * DPMSG_DELETEPLAYERFROMGROUP + * System message generated when a player is being + * removed from a group + */ +typedef DPMSG_ADDPLAYERTOGROUP DPMSG_DELETEPLAYERFROMGROUP; +typedef DPMSG_DELETEPLAYERFROMGROUP FAR *LPDPMSG_DELETEPLAYERFROMGROUP; + +/* + * DPMSG_ADDGROUPTOGROUP + * System message generated when a group is being added + * to a group. + */ +typedef struct +{ + DWORD dwType; // Message type + DPID dpIdParentGroup; // group ID being added to + DPID dpIdGroup; // group ID being added +} DPMSG_ADDGROUPTOGROUP, FAR *LPDPMSG_ADDGROUPTOGROUP; + +/* + * DPMSG_DELETEGROUPFROMGROUP + * System message generated when a GROUP is being + * removed from a group + */ +typedef DPMSG_ADDGROUPTOGROUP DPMSG_DELETEGROUPFROMGROUP; +typedef DPMSG_DELETEGROUPFROMGROUP FAR *LPDPMSG_DELETEGROUPFROMGROUP; + +/* + * DPMSG_SETPLAYERORGROUPDATA + * System message generated when remote data for a player or + * group has changed. + */ +typedef struct +{ + DWORD dwType; // Message type + DWORD dwPlayerType; // Is it a player or group + DPID dpId; // ID of player or group + LPVOID lpData; // pointer to remote data + DWORD dwDataSize; // size of remote data +} DPMSG_SETPLAYERORGROUPDATA, FAR *LPDPMSG_SETPLAYERORGROUPDATA; + +/* + * DPMSG_SETPLAYERORGROUPNAME + * System message generated when the name of a player or + * group has changed. + */ +typedef struct +{ + DWORD dwType; // Message type + DWORD dwPlayerType; // Is it a player or group + DPID dpId; // ID of player or group + DPNAME dpnName; // structure with new name info +} DPMSG_SETPLAYERORGROUPNAME, FAR *LPDPMSG_SETPLAYERORGROUPNAME; + +/* + * DPMSG_SETSESSIONDESC + * System message generated when session desc has changed + */ +typedef struct +{ + DWORD dwType; // Message type + DPSESSIONDESC2 dpDesc; // Session desc +} DPMSG_SETSESSIONDESC, FAR *LPDPMSG_SETSESSIONDESC; + +/* + * DPMSG_HOST + * System message generated when the host has migrated to this + * DirectPlay object. + * + */ +typedef DPMSG_GENERIC DPMSG_HOST; +typedef DPMSG_HOST FAR *LPDPMSG_HOST; + +/* + * DPMSG_SESSIONLOST + * System message generated when the connection to the session is lost. + * + */ +typedef DPMSG_GENERIC DPMSG_SESSIONLOST; +typedef DPMSG_SESSIONLOST FAR *LPDPMSG_SESSIONLOST; + +/* + * DPMSG_SECUREMESSAGE + * System message generated when a player requests a secure send + */ +typedef struct +{ + DWORD dwType; // Message Type + DWORD dwFlags; // Signed/Encrypted + DPID dpIdFrom; // ID of Sending Player + LPVOID lpData; // Player message + DWORD dwDataSize; // Size of player message +} DPMSG_SECUREMESSAGE, FAR *LPDPMSG_SECUREMESSAGE; + +/* + * DPMSG_STARTSESSION + * System message containing all information required to + * start a new session + */ +typedef struct +{ + DWORD dwType; // Message type + LPDPLCONNECTION lpConn; // DPLCONNECTION structure +} DPMSG_STARTSESSION, FAR *LPDPMSG_STARTSESSION; + +/* + * DPMSG_CHAT + * System message containing a chat message + */ +typedef struct +{ + DWORD dwType; // Message type + DWORD dwFlags; // Message flags + DPID idFromPlayer; // ID of the Sending Player + DPID idToPlayer; // ID of the To Player + DPID idToGroup; // ID of the To Group + LPDPCHAT lpChat; // Pointer to a structure containing the chat message +} DPMSG_CHAT, FAR *LPDPMSG_CHAT; + +/**************************************************************************** + * + * DIRECTPLAY ERRORS + * + * Errors are represented by negative values and cannot be combined. + * + ****************************************************************************/ +#define DP_OK S_OK +#define DPERR_ALREADYINITIALIZED MAKE_DPHRESULT( 5 ) +#define DPERR_ACCESSDENIED MAKE_DPHRESULT( 10 ) +#define DPERR_ACTIVEPLAYERS MAKE_DPHRESULT( 20 ) +#define DPERR_BUFFERTOOSMALL MAKE_DPHRESULT( 30 ) +#define DPERR_CANTADDPLAYER MAKE_DPHRESULT( 40 ) +#define DPERR_CANTCREATEGROUP MAKE_DPHRESULT( 50 ) +#define DPERR_CANTCREATEPLAYER MAKE_DPHRESULT( 60 ) +#define DPERR_CANTCREATESESSION MAKE_DPHRESULT( 70 ) +#define DPERR_CAPSNOTAVAILABLEYET MAKE_DPHRESULT( 80 ) +#define DPERR_EXCEPTION MAKE_DPHRESULT( 90 ) +#define DPERR_GENERIC E_FAIL +#define DPERR_INVALIDFLAGS MAKE_DPHRESULT( 120 ) +#define DPERR_INVALIDOBJECT MAKE_DPHRESULT( 130 ) +#define DPERR_INVALIDPARAM E_INVALIDARG +#define DPERR_INVALIDPARAMS DPERR_INVALIDPARAM +#define DPERR_INVALIDPLAYER MAKE_DPHRESULT( 150 ) +#define DPERR_INVALIDGROUP MAKE_DPHRESULT( 155 ) +#define DPERR_NOCAPS MAKE_DPHRESULT( 160 ) +#define DPERR_NOCONNECTION MAKE_DPHRESULT( 170 ) +#define DPERR_NOMEMORY E_OUTOFMEMORY +#define DPERR_OUTOFMEMORY DPERR_NOMEMORY +#define DPERR_NOMESSAGES MAKE_DPHRESULT( 190 ) +#define DPERR_NONAMESERVERFOUND MAKE_DPHRESULT( 200 ) +#define DPERR_NOPLAYERS MAKE_DPHRESULT( 210 ) +#define DPERR_NOSESSIONS MAKE_DPHRESULT( 220 ) +#define DPERR_PENDING E_PENDING +#define DPERR_SENDTOOBIG MAKE_DPHRESULT( 230 ) +#define DPERR_TIMEOUT MAKE_DPHRESULT( 240 ) +#define DPERR_UNAVAILABLE MAKE_DPHRESULT( 250 ) +#define DPERR_UNSUPPORTED E_NOTIMPL +#define DPERR_BUSY MAKE_DPHRESULT( 270 ) +#define DPERR_USERCANCEL MAKE_DPHRESULT( 280 ) +#define DPERR_NOINTERFACE E_NOINTERFACE +#define DPERR_CANNOTCREATESERVER MAKE_DPHRESULT( 290 ) +#define DPERR_PLAYERLOST MAKE_DPHRESULT( 300 ) +#define DPERR_SESSIONLOST MAKE_DPHRESULT( 310 ) +#define DPERR_UNINITIALIZED MAKE_DPHRESULT( 320 ) +#define DPERR_NONEWPLAYERS MAKE_DPHRESULT( 330 ) +#define DPERR_INVALIDPASSWORD MAKE_DPHRESULT( 340 ) +#define DPERR_CONNECTING MAKE_DPHRESULT( 350 ) + + +#define DPERR_BUFFERTOOLARGE MAKE_DPHRESULT( 1000 ) +#define DPERR_CANTCREATEPROCESS MAKE_DPHRESULT( 1010 ) +#define DPERR_APPNOTSTARTED MAKE_DPHRESULT( 1020 ) +#define DPERR_INVALIDINTERFACE MAKE_DPHRESULT( 1030 ) +#define DPERR_NOSERVICEPROVIDER MAKE_DPHRESULT( 1040 ) +#define DPERR_UNKNOWNAPPLICATION MAKE_DPHRESULT( 1050 ) +#define DPERR_NOTLOBBIED MAKE_DPHRESULT( 1070 ) +#define DPERR_SERVICEPROVIDERLOADED MAKE_DPHRESULT( 1080 ) +#define DPERR_ALREADYREGISTERED MAKE_DPHRESULT( 1090 ) +#define DPERR_NOTREGISTERED MAKE_DPHRESULT( 1100 ) + +// +// Security related errors +// +#define DPERR_AUTHENTICATIONFAILED MAKE_DPHRESULT( 2000 ) +#define DPERR_CANTLOADSSPI MAKE_DPHRESULT( 2010 ) +#define DPERR_ENCRYPTIONFAILED MAKE_DPHRESULT( 2020 ) +#define DPERR_SIGNFAILED MAKE_DPHRESULT( 2030 ) +#define DPERR_CANTLOADSECURITYPACKAGE MAKE_DPHRESULT( 2040 ) +#define DPERR_ENCRYPTIONNOTSUPPORTED MAKE_DPHRESULT( 2050 ) +#define DPERR_CANTLOADCAPI MAKE_DPHRESULT( 2060 ) +#define DPERR_NOTLOGGEDIN MAKE_DPHRESULT( 2070 ) +#define DPERR_LOGONDENIED MAKE_DPHRESULT( 2080 ) + + +/**************************************************************************** + * + * dplay 1.0 obsolete structures + interfaces + * Included for compatibility only. New apps should + * use IDirectPlay2 + * + ****************************************************************************/ + +// define this to ignore obsolete interfaces and constants +#ifndef IDIRECTPLAY2_OR_GREATER + +#define DPOPEN_OPENSESSION DPOPEN_JOIN +#define DPOPEN_CREATESESSION DPOPEN_CREATE + +#define DPENUMSESSIONS_PREVIOUS 0x00000004 + +#define DPENUMPLAYERS_PREVIOUS 0x00000004 + +#define DPSEND_GUARANTEE DPSEND_GUARANTEED +#define DPSEND_TRYONCE 0x00000004 + +#define DPCAPS_NAMESERVICE 0x00000001 +#define DPCAPS_NAMESERVER DPCAPS_ISHOST +#define DPCAPS_GUARANTEED 0x00000004 + +#define DPLONGNAMELEN 52 +#define DPSHORTNAMELEN 20 +#define DPSESSIONNAMELEN 32 +#define DPPASSWORDLEN 16 +#define DPUSERRESERVED 16 + +#define DPSYS_ADDPLAYER 0x0003 +#define DPSYS_DELETEPLAYER 0x0005 + +#define DPSYS_DELETEGROUP 0x0020 +#define DPSYS_DELETEPLAYERFROMGRP 0x0021 +#define DPSYS_CONNECT 0x484b + +typedef struct +{ + DWORD dwType; + DWORD dwPlayerType; + DPID dpId; + char szLongName[DPLONGNAMELEN]; + char szShortName[DPSHORTNAMELEN]; + DWORD dwCurrentPlayers; +} DPMSG_ADDPLAYER; + +typedef DPMSG_ADDPLAYER DPMSG_ADDGROUP; + +typedef struct +{ + DWORD dwType; + DPID dpIdGroup; + DPID dpIdPlayer; +} DPMSG_GROUPADD; + +typedef DPMSG_GROUPADD DPMSG_GROUPDELETE; +typedef struct +{ + DWORD dwType; + DPID dpId; +} DPMSG_DELETEPLAYER; + +typedef BOOL (PASCAL *LPDPENUMPLAYERSCALLBACK)( + DPID dpId, + LPSTR lpFriendlyName, + LPSTR lpFormalName, + DWORD dwFlags, + LPVOID lpContext ); + +typedef struct +{ + DWORD dwSize; + GUID guidSession; + DWORD dwSession; + DWORD dwMaxPlayers; + DWORD dwCurrentPlayers; + DWORD dwFlags; + char szSessionName[DPSESSIONNAMELEN]; + char szUserField[DPUSERRESERVED]; + DWORD dwReserved1; + char szPassword[DPPASSWORDLEN]; + DWORD dwReserved2; + DWORD dwUser1; + DWORD dwUser2; + DWORD dwUser3; + DWORD dwUser4; +} DPSESSIONDESC,*LPDPSESSIONDESC; + +typedef BOOL (PASCAL * LPDPENUMSESSIONSCALLBACK)( + LPDPSESSIONDESC lpDPSessionDesc, + LPVOID lpContext, + LPDWORD lpdwTimeOut, + DWORD dwFlags); + +/* + * IDirectPlay + */ +#undef INTERFACE +#define INTERFACE IDirectPlay +DECLARE_INTERFACE_( IDirectPlay, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectPlay methods ***/ + STDMETHOD(AddPlayerToGroup) (THIS_ DPID, DPID) PURE; + STDMETHOD(Close) (THIS) PURE; + STDMETHOD(CreatePlayer) (THIS_ LPDPID,LPSTR,LPSTR,LPHANDLE) PURE; + STDMETHOD(CreateGroup) (THIS_ LPDPID,LPSTR,LPSTR) PURE; + STDMETHOD(DeletePlayerFromGroup)(THIS_ DPID,DPID) PURE; + STDMETHOD(DestroyPlayer) (THIS_ DPID) PURE; + STDMETHOD(DestroyGroup) (THIS_ DPID) PURE; + STDMETHOD(EnableNewPlayers) (THIS_ BOOL) PURE; + STDMETHOD(EnumGroupPlayers) (THIS_ DPID, LPDPENUMPLAYERSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(EnumGroups) (THIS_ DWORD, LPDPENUMPLAYERSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(EnumPlayers) (THIS_ DWORD, LPDPENUMPLAYERSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(EnumSessions) (THIS_ LPDPSESSIONDESC,DWORD,LPDPENUMSESSIONSCALLBACK,LPVOID,DWORD) PURE; + STDMETHOD(GetCaps) (THIS_ LPDPCAPS) PURE; + STDMETHOD(GetMessageCount) (THIS_ DPID, LPDWORD) PURE; + STDMETHOD(GetPlayerCaps) (THIS_ DPID, LPDPCAPS) PURE; + STDMETHOD(GetPlayerName) (THIS_ DPID,LPSTR,LPDWORD,LPSTR,LPDWORD) PURE; + STDMETHOD(Initialize) (THIS_ LPGUID) PURE; + STDMETHOD(Open) (THIS_ LPDPSESSIONDESC) PURE; + STDMETHOD(Receive) (THIS_ LPDPID,LPDPID,DWORD,LPVOID,LPDWORD) PURE; + STDMETHOD(SaveSession) (THIS_ LPSTR) PURE; + STDMETHOD(Send) (THIS_ DPID, DPID, DWORD, LPVOID, DWORD) PURE; + STDMETHOD(SetPlayerName) (THIS_ DPID,LPSTR,LPSTR) PURE; +}; + +/**************************************************************************** + * + * IDirectPlay interface macros + * + ****************************************************************************/ + +#if !defined(__cplusplus) || defined(CINTERFACE) + +#define IDirectPlay_AddPlayerToGroup(p,a,b) (p)->lpVtbl->AddPlayerToGroup(p,a,b) +#define IDirectPlay_Close(p) (p)->lpVtbl->Close(p) +#define IDirectPlay_CreateGroup(p,a,b,c) (p)->lpVtbl->CreateGroup(p,a,b,c) +#define IDirectPlay_CreatePlayer(p,a,b,c,d) (p)->lpVtbl->CreatePlayer(p,a,b,c,d) +#define IDirectPlay_DeletePlayerFromGroup(p,a,b) (p)->lpVtbl->DeletePlayerFromGroup(p,a,b) +#define IDirectPlay_DestroyGroup(p,a) (p)->lpVtbl->DestroyGroup(p,a) +#define IDirectPlay_DestroyPlayer(p,a) (p)->lpVtbl->DestroyPlayer(p,a) +#define IDirectPlay_EnableNewPlayers(p,a) (p)->lpVtbl->EnableNewPlayers(p,a) +#define IDirectPlay_EnumGroupPlayers(p,a,b,c,d) (p)->lpVtbl->EnumGroupPlayers(p,a,b,c,d) +#define IDirectPlay_EnumGroups(p,a,b,c,d) (p)->lpVtbl->EnumGroups(p,a,b,c,d) +#define IDirectPlay_EnumPlayers(p,a,b,c,d) (p)->lpVtbl->EnumPlayers(p,a,b,c,d) +#define IDirectPlay_EnumSessions(p,a,b,c,d,e) (p)->lpVtbl->EnumSessions(p,a,b,c,d,e) +#define IDirectPlay_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectPlay_GetMessageCount(p,a,b) (p)->lpVtbl->GetMessageCount(p,a,b) +#define IDirectPlay_GetPlayerCaps(p,a,b) (p)->lpVtbl->GetPlayerCaps(p,a,b) +#define IDirectPlay_GetPlayerName(p,a,b,c,d,e) (p)->lpVtbl->GetPlayerName(p,a,b,c,d,e) +#define IDirectPlay_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) +#define IDirectPlay_Open(p,a) (p)->lpVtbl->Open(p,a) +#define IDirectPlay_Receive(p,a,b,c,d,e) (p)->lpVtbl->Receive(p,a,b,c,d,e) +#define IDirectPlay_SaveSession(p,a) (p)->lpVtbl->SaveSession(p,a) +#define IDirectPlay_Send(p,a,b,c,d,e) (p)->lpVtbl->Send(p,a,b,c,d,e) +#define IDirectPlay_SetPlayerName(p,a,b,c) (p)->lpVtbl->SetPlayerName(p,a,b,c) + +#else /* C++ */ + +#define IDirectPlay_AddPlayerToGroup(p,a,b) (p)->AddPlayerToGroup(a,b) +#define IDirectPlay_Close(p) (p)->Close() +#define IDirectPlay_CreateGroup(p,a,b,c) (p)->CreateGroup(a,b,c) +#define IDirectPlay_CreatePlayer(p,a,b,c,d) (p)->CreatePlayer(a,b,c,d) +#define IDirectPlay_DeletePlayerFromGroup(p,a,b) (p)->DeletePlayerFromGroup(a,b) +#define IDirectPlay_DestroyGroup(p,a) (p)->DestroyGroup(a) +#define IDirectPlay_DestroyPlayer(p,a) (p)->DestroyPlayer(a) +#define IDirectPlay_EnableNewPlayers(p,a) (p)->EnableNewPlayers(a) +#define IDirectPlay_EnumGroupPlayers(p,a,b,c,d) (p)->EnumGroupPlayers(a,b,c,d) +#define IDirectPlay_EnumGroups(p,a,b,c,d) (p)->EnumGroups(a,b,c,d) +#define IDirectPlay_EnumPlayers(p,a,b,c,d) (p)->EnumPlayers(a,b,c,d) +#define IDirectPlay_EnumSessions(p,a,b,c,d,e) (p)->EnumSessions(a,b,c,d,e) +#define IDirectPlay_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectPlay_GetMessageCount(p,a,b) (p)->GetMessageCount(a,b) +#define IDirectPlay_GetPlayerCaps(p,a,b) (p)->GetPlayerCaps(a,b) +#define IDirectPlay_GetPlayerName(p,a,b,c,d,e) (p)->GetPlayerName(a,b,c,d,e) +#define IDirectPlay_Initialize(p,a) (p)->Initialize(a) +#define IDirectPlay_Open(p,a) (p)->Open(a) +#define IDirectPlay_Receive(p,a,b,c,d,e) (p)->Receive(a,b,c,d,e) +#define IDirectPlay_SaveSession(p,a) (p)->SaveSession(a) +#define IDirectPlay_Send(p,a,b,c,d,e) (p)->Send(a,b,c,d,e) +#define IDirectPlay_SetPlayerName(p,a,b,c) (p)->SetPlayerName(a,b,c) + +#endif + +DEFINE_GUID(IID_IDirectPlay, 0x5454e9a0, 0xdb65, 0x11ce, 0x92, 0x1c, 0x00, 0xaa, 0x00, 0x6c, 0x49, 0x72); + +#endif // IDIRECTPLAY2_OR_GREATER + +/**************************************************************************** + * + * IDirectPlay macros (included regardless of IDIRECTPLAY2_OR_GREATER flag) + * + ****************************************************************************/ + +#if !defined(__cplusplus) || defined(CINTERFACE) + +#define IDirectPlay_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectPlay_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectPlay_Release(p) (p)->lpVtbl->Release(p) + +#else + +#define IDirectPlay_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectPlay_AddRef(p) (p)->AddRef() +#define IDirectPlay_Release(p) (p)->Release() + +#endif // IDirectPlay interface macros + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/3rdparty/dx5/inc/dplobby.h b/3rdparty/dx5/inc/dplobby.h new file mode 100644 index 00000000..a1d58963 --- /dev/null +++ b/3rdparty/dx5/inc/dplobby.h @@ -0,0 +1,627 @@ +/*==========================================================================; + * + * Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved. + * + * File: dplobby.h + * Content: DirectPlayLobby include file + ***************************************************************************/ +#ifndef __DPLOBBY_INCLUDED__ +#define __DPLOBBY_INCLUDED__ + +#include "dplay.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + * GUIDS used by DirectPlay objects + */ + +/* {AF465C71-9588-11cf-A020-00AA006157AC} */ +DEFINE_GUID(IID_IDirectPlayLobby, 0xaf465c71, 0x9588, 0x11cf, 0xa0, 0x20, 0x0, 0xaa, 0x0, 0x61, 0x57, 0xac); +/* {26C66A70-B367-11cf-A024-00AA006157AC} */ +DEFINE_GUID(IID_IDirectPlayLobbyA, 0x26c66a70, 0xb367, 0x11cf, 0xa0, 0x24, 0x0, 0xaa, 0x0, 0x61, 0x57, 0xac); +/* {0194C220-A303-11d0-9C4F-00A0C905425E} */ +DEFINE_GUID(IID_IDirectPlayLobby2, 0x194c220, 0xa303, 0x11d0, 0x9c, 0x4f, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); +/* {1BB4AF80-A303-11d0-9C4F-00A0C905425E} */ +DEFINE_GUID(IID_IDirectPlayLobby2A, 0x1bb4af80, 0xa303, 0x11d0, 0x9c, 0x4f, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); +/* {2FE8F810-B2A5-11d0-A787-0000F803ABFC} */ +DEFINE_GUID(CLSID_DirectPlayLobby, 0x2fe8f810, 0xb2a5, 0x11d0, 0xa7, 0x87, 0x0, 0x0, 0xf8, 0x3, 0xab, 0xfc); + + +/**************************************************************************** + * + * IDirectPlayLobby Structures + * + * Various structures used to invoke DirectPlayLobby. + * + ****************************************************************************/ + +typedef struct IDirectPlayLobby FAR *LPDIRECTPLAYLOBBY; +typedef struct IDirectPlayLobby FAR *LPDIRECTPLAYLOBBYA; +typedef struct IDirectPlayLobby IDirectPlayLobbyA; + +typedef struct IDirectPlayLobby2 FAR *LPDIRECTPLAYLOBBY2; +typedef struct IDirectPlayLobby2 FAR *LPDIRECTPLAYLOBBY2A; +typedef struct IDirectPlayLobby2 IDirectPlayLobby2A; + + +/* + * DPLAPPINFO + * Used to hold information about a registered DirectPlay + * application + */ +typedef struct DPLAPPINFO +{ + DWORD dwSize; // Size of this structure + GUID guidApplication; // GUID of the Application + union + { + LPSTR lpszAppNameA; // Pointer to the Application Name + LPWSTR lpszAppName; + }; + +} DPLAPPINFO, FAR *LPDPLAPPINFO; + +/* + * LPCDPLAPPINFO + * A constant pointer to DPLAPPINFO + */ +typedef const DPLAPPINFO FAR *LPCDPLAPPINFO; + +/* + * DPCOMPOUNDADDRESSELEMENT + * + * An array of these is passed to CreateCompoundAddresses() + */ +typedef struct DPCOMPOUNDADDRESSELEMENT +{ + GUID guidDataType; + DWORD dwDataSize; + LPVOID lpData; +} DPCOMPOUNDADDRESSELEMENT, FAR *LPDPCOMPOUNDADDRESSELEMENT; + +/* + * LPCDPCOMPOUNDADDRESSELEMENT + * A constant pointer to DPCOMPOUNDADDRESSELEMENT + */ +typedef const DPCOMPOUNDADDRESSELEMENT FAR *LPCDPCOMPOUNDADDRESSELEMENT; + + +/**************************************************************************** + * + * Enumeration Method Callback Prototypes + * + ****************************************************************************/ + +/* + * Callback for EnumAddress() + */ +typedef BOOL (FAR PASCAL *LPDPENUMADDRESSCALLBACK)( + REFGUID guidDataType, + DWORD dwDataSize, + LPCVOID lpData, + LPVOID lpContext); + +/* + * Callback for EnumAddressTypes() + */ +typedef BOOL (FAR PASCAL *LPDPLENUMADDRESSTYPESCALLBACK)( + REFGUID guidDataType, + LPVOID lpContext, + DWORD dwFlags); + +/* + * Callback for EnumLocalApplications() + */ +typedef BOOL (FAR PASCAL * LPDPLENUMLOCALAPPLICATIONSCALLBACK)( + LPCDPLAPPINFO lpAppInfo, + LPVOID lpContext, + DWORD dwFlags); + + +/**************************************************************************** + * + * DirectPlayLobby API Prototypes + * + ****************************************************************************/ +#ifdef UNICODE +#define DirectPlayLobbyCreate DirectPlayLobbyCreateW +#else +#define DirectPlayLobbyCreate DirectPlayLobbyCreateA +#endif /* UNICODE */ + +extern HRESULT WINAPI DirectPlayLobbyCreateW(LPGUID, LPDIRECTPLAYLOBBY *, IUnknown *, LPVOID, DWORD ); +extern HRESULT WINAPI DirectPlayLobbyCreateA(LPGUID, LPDIRECTPLAYLOBBYA *, IUnknown *, LPVOID, DWORD ); + + +/**************************************************************************** + * + * IDirectPlayLobby (and IDirectPlayLobbyA) Interface + * + ****************************************************************************/ +#undef INTERFACE +#define INTERFACE IDirectPlayLobby +DECLARE_INTERFACE_( IDirectPlayLobby, IUnknown ) +{ + /* IUnknown Methods */ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + /* IDirectPlayLobby Methods */ + STDMETHOD(Connect) (THIS_ DWORD, LPDIRECTPLAY2 *, IUnknown FAR *) PURE; + STDMETHOD(CreateAddress) (THIS_ REFGUID, REFGUID, LPCVOID, DWORD, LPVOID, LPDWORD) PURE; + STDMETHOD(EnumAddress) (THIS_ LPDPENUMADDRESSCALLBACK, LPCVOID, DWORD, LPVOID) PURE; + STDMETHOD(EnumAddressTypes) (THIS_ LPDPLENUMADDRESSTYPESCALLBACK, REFGUID, LPVOID, DWORD) PURE; + STDMETHOD(EnumLocalApplications)(THIS_ LPDPLENUMLOCALAPPLICATIONSCALLBACK, LPVOID, DWORD) PURE; + STDMETHOD(GetConnectionSettings)(THIS_ DWORD, LPVOID, LPDWORD) PURE; + STDMETHOD(ReceiveLobbyMessage) (THIS_ DWORD, DWORD, LPDWORD, LPVOID, LPDWORD) PURE; + STDMETHOD(RunApplication) (THIS_ DWORD, LPDWORD, LPDPLCONNECTION, HANDLE) PURE; + STDMETHOD(SendLobbyMessage) (THIS_ DWORD, DWORD, LPVOID, DWORD) PURE; + STDMETHOD(SetConnectionSettings)(THIS_ DWORD, DWORD, LPDPLCONNECTION) PURE; + STDMETHOD(SetLobbyMessageEvent) (THIS_ DWORD, DWORD, HANDLE) PURE; + +}; + +/**************************************************************************** + * + * IDirectPlayLobby2 (and IDirectPlayLobby2A) Interface + * + ****************************************************************************/ +#undef INTERFACE +#define INTERFACE IDirectPlayLobby2 +DECLARE_INTERFACE_( IDirectPlayLobby2, IDirectPlayLobby ) +{ + /* IUnknown Methods */ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + /* IDirectPlayLobby Methods */ + STDMETHOD(Connect) (THIS_ DWORD, LPDIRECTPLAY2 *, IUnknown FAR *) PURE; + STDMETHOD(CreateAddress) (THIS_ REFGUID, REFGUID, LPCVOID, DWORD, LPVOID, LPDWORD) PURE; + STDMETHOD(EnumAddress) (THIS_ LPDPENUMADDRESSCALLBACK, LPCVOID, DWORD, LPVOID) PURE; + STDMETHOD(EnumAddressTypes) (THIS_ LPDPLENUMADDRESSTYPESCALLBACK, REFGUID, LPVOID, DWORD) PURE; + STDMETHOD(EnumLocalApplications)(THIS_ LPDPLENUMLOCALAPPLICATIONSCALLBACK, LPVOID, DWORD) PURE; + STDMETHOD(GetConnectionSettings)(THIS_ DWORD, LPVOID, LPDWORD) PURE; + STDMETHOD(ReceiveLobbyMessage) (THIS_ DWORD, DWORD, LPDWORD, LPVOID, LPDWORD) PURE; + STDMETHOD(RunApplication) (THIS_ DWORD, LPDWORD, LPDPLCONNECTION, HANDLE) PURE; + STDMETHOD(SendLobbyMessage) (THIS_ DWORD, DWORD, LPVOID, DWORD) PURE; + STDMETHOD(SetConnectionSettings)(THIS_ DWORD, DWORD, LPDPLCONNECTION) PURE; + STDMETHOD(SetLobbyMessageEvent) (THIS_ DWORD, DWORD, HANDLE) PURE; + + /* IDirectPlayLobby2 Methods */ + STDMETHOD(CreateCompoundAddress)(THIS_ LPCDPCOMPOUNDADDRESSELEMENT,DWORD,LPVOID,LPDWORD) PURE; +}; + +/**************************************************************************** + * + * IDirectPlayLobby interface macros + * + ****************************************************************************/ + +#if !defined(__cplusplus) || defined(CINTERFACE) + +#define IDirectPlayLobby_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectPlayLobby_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectPlayLobby_Release(p) (p)->lpVtbl->Release(p) +#define IDirectPlayLobby_Connect(p,a,b,c) (p)->lpVtbl->Connect(p,a,b,c) +#define IDirectPlayLobby_CreateAddress(p,a,b,c,d,e,f) (p)->lpVtbl->CreateAddress(p,a,b,c,d,e,f) +#define IDirectPlayLobby_CreateCompoundAddress(p,a,b,c,d) (p)->lpVtbl->CreateCompoundAddress(p,a,b,c,d) +#define IDirectPlayLobby_EnumAddress(p,a,b,c,d) (p)->lpVtbl->EnumAddress(p,a,b,c,d) +#define IDirectPlayLobby_EnumAddressTypes(p,a,b,c,d) (p)->lpVtbl->EnumAddressTypes(p,a,b,c,d) +#define IDirectPlayLobby_EnumLocalApplications(p,a,b,c) (p)->lpVtbl->EnumLocalApplications(p,a,b,c) +#define IDirectPlayLobby_GetConnectionSettings(p,a,b,c) (p)->lpVtbl->GetConnectionSettings(p,a,b,c) +#define IDirectPlayLobby_ReceiveLobbyMessage(p,a,b,c,d,e) (p)->lpVtbl->ReceiveLobbyMessage(p,a,b,c,d,e) +#define IDirectPlayLobby_RunApplication(p,a,b,c,d) (p)->lpVtbl->RunApplication(p,a,b,c,d) +#define IDirectPlayLobby_SendLobbyMessage(p,a,b,c,d) (p)->lpVtbl->SendLobbyMessage(p,a,b,c,d) +#define IDirectPlayLobby_SetConnectionSettings(p,a,b,c) (p)->lpVtbl->SetConnectionSettings(p,a,b,c) +#define IDirectPlayLobby_SetLobbyMessageEvent(p,a,b,c) (p)->lpVtbl->SetLobbyMessageEvent(p,a,b,c) + +#else /* C++ */ + +#define IDirectPlayLobby_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectPlayLobby_AddRef(p) (p)->AddRef() +#define IDirectPlayLobby_Release(p) (p)->Release() +#define IDirectPlayLobby_Connect(p,a,b,c) (p)->Connect(a,b,c) +#define IDirectPlayLobby_CreateAddress(p,a,b,c,d,e,f) (p)->CreateAddress(a,b,c,d,e,f) +#define IDirectPlayLobby_CreateCompoundAddress(p,a,b,c,d) (p)->lpVtbl->CreateCompoundAddress(a,b,c,d) +#define IDirectPlayLobby_EnumAddress(p,a,b,c,d) (p)->EnumAddress(a,b,c,d) +#define IDirectPlayLobby_EnumAddressTypes(p,a,b,c,d) (p)->EnumAddressTypes(a,b,c,d) +#define IDirectPlayLobby_EnumLocalApplications(p,a,b,c) (p)->EnumLocalApplications(a,b,c) +#define IDirectPlayLobby_GetConnectionSettings(p,a,b,c) (p)->GetConnectionSettings(a,b,c) +#define IDirectPlayLobby_ReceiveLobbyMessage(p,a,b,c,d,e) (p)->ReceiveLobbyMessage(a,b,c,d,e) +#define IDirectPlayLobby_RunApplication(p,a,b,c,d) (p)->RunApplication(a,b,c,d) +#define IDirectPlayLobby_SendLobbyMessage(p,a,b,c,d) (p)->SendLobbyMessage(a,b,c,d) +#define IDirectPlayLobby_SetConnectionSettings(p,a,b,c) (p)->SetConnectionSettings(a,b,c) +#define IDirectPlayLobby_SetLobbyMessageEvent(p,a,b,c) (p)->SetLobbyMessageEvent(a,b,c) + +#endif + +/**************************************************************************** + * + * DirectPlayLobby Flags + * + ****************************************************************************/ + +/* + * This is a message flag used by ReceiveLobbyMessage. It can be + * returned in the dwMessageFlags parameter to indicate a message from + * the system. + */ +#define DPLMSG_SYSTEM 0x00000001 + +/* + * This is a message flag used by ReceiveLobbyMessage and SendLobbyMessage. + * It is used to indicate that the message is a standard lobby message. + * DPLMSG_SETPROPERTY, DPLMSG_SETPROPERTYRESPONSE, DPLMSG_GETPROPERTY, + * DPLMSG_GETPROPERTYRESPONSE + */ +#define DPLMSG_STANDARD 0x00000002 + + +/**************************************************************************** + * + * DirectPlayLobby messages and message data structures + * + * All system messages have a dwMessageFlags value of DPLMSG_SYSTEM returned + * from a call to ReceiveLobbyMessage. + * + * All standard messages have a dwMessageFlags value of DPLMSG_STANDARD returned + * from a call to ReceiveLobbyMessage. + * + ****************************************************************************/ + +/* + * DPLMSG_GENERIC + * Generic message structure used to identify the message type. + */ +typedef struct _DPLMSG_GENERIC +{ + DWORD dwType; // Message type +} DPLMSG_GENERIC, FAR *LPDPLMSG_GENERIC; + +/* + * DPLMSG_SETPROPERTY + * Standard message sent by an application to a lobby to set a + * property + */ +typedef struct _DPLMSG_SETPROPERTY +{ + DWORD dwType; // Message type + DWORD dwRequestID; // Request ID (DPL_NOCONFIRMATION if no confirmation desired) + GUID guidPlayer; // Player GUID + GUID guidPropertyTag; // Property GUID + DWORD dwDataSize; // Size of data + DWORD dwPropertyData[1]; // Buffer containing data +} DPLMSG_SETPROPERTY, FAR *LPDPLMSG_SETPROPERTY; + +#define DPL_NOCONFIRMATION 0 + +/* + * DPLMSG_SETPROPERTYRESPONSE + * Standard message returned by a lobby to confirm a + * DPLMSG_SETPROPERTY message. + */ +typedef struct _DPLMSG_SETPROPERTYRESPONSE +{ + DWORD dwType; // Message type + DWORD dwRequestID; // Request ID + GUID guidPlayer; // Player GUID + GUID guidPropertyTag; // Property GUID + HRESULT hr; // Return Code +} DPLMSG_SETPROPERTYRESPONSE, FAR *LPDPLMSG_SETPROPERTYRESPONSE; + +/* + * DPLMSG_GETPROPERTY + * Standard message sent by an application to a lobby to request + * the current value of a property + */ +typedef struct _DPLMSG_GETPROPERTY +{ + DWORD dwType; // Message type + DWORD dwRequestID; // Request ID + GUID guidPlayer; // Player GUID + GUID guidPropertyTag; // Property GUID +} DPLMSG_GETPROPERTY, FAR *LPDPLMSG_GETPROPERTY; + +/* + * DPLMSG_GETPROPERTYRESPONSE + * Standard message returned by a lobby in response to a + * DPLMSG_GETPROPERTY message. + */ +typedef struct _DPLMSG_GETPROPERTYRESPONSE +{ + DWORD dwType; // Message type + DWORD dwRequestID; // Request ID + GUID guidPlayer; // Player GUID + GUID guidPropertyTag; // Property GUID + HRESULT hr; // Return Code + DWORD dwDataSize; // Size of data + DWORD dwPropertyData[1]; // Buffer containing data +} DPLMSG_GETPROPERTYRESPONSE, FAR *LPDPLMSG_GETPROPERTYRESPONSE; + + +/****************************************** + * + * DirectPlay Lobby message dwType values + * + *****************************************/ + +/* + * The application has read the connection settings. + * It is now O.K. for the lobby client to release + * its IDirectPlayLobby interface. + */ +#define DPLSYS_CONNECTIONSETTINGSREAD 0x00000001 + +/* + * The application's call to DirectPlayConnect failed + */ +#define DPLSYS_DPLAYCONNECTFAILED 0x00000002 + +/* + * The application has created a DirectPlay session. + */ +#define DPLSYS_DPLAYCONNECTSUCCEEDED 0x00000003 + +/* + * The application has terminated. + */ +#define DPLSYS_APPTERMINATED 0x00000004 + +/* + * The message is a DPLMSG_SETPROPERTY message. + */ +#define DPLSYS_SETPROPERTY 0x00000005 + +/* + * The message is a DPLMSG_SETPROPERTYRESPONSE message. + */ +#define DPLSYS_SETPROPERTYRESPONSE 0x00000006 + +/* + * The message is a DPLMSG_GETPROPERTY message. + */ +#define DPLSYS_GETPROPERTY 0x00000007 + +/* + * The message is a DPLMSG_GETPROPERTYRESPONSE message. + */ +#define DPLSYS_GETPROPERTYRESPONSE 0x00000008 + + +/**************************************************************************** + * + * DirectPlay defined property GUIDs and associated data structures + * + ****************************************************************************/ + +/* + * DPLPROPERTY_MessagesSupported + * + * Request whether the lobby supports standard. Lobby with respond with either + * TRUE or FALSE or may not respond at all. + * + * Property data is a single BOOL with TRUE or FALSE + */ +// {762CCDA1-D916-11d0-BA39-00C04FD7ED67} +DEFINE_GUID(DPLPROPERTY_MessagesSupported, +0x762ccda1, 0xd916, 0x11d0, 0xba, 0x39, 0x0, 0xc0, 0x4f, 0xd7, 0xed, 0x67); + +/* + * DPLPROPERTY_LobbyGuid + * + * Request the GUID that identifies the lobby software that the application + * is communicating with. + * + * Property data is a single GUID. + */ +// {F56920A0-D218-11d0-BA39-00C04FD7ED67} +DEFINE_GUID(DPLPROPERTY_LobbyGuid, +0xf56920a0, 0xd218, 0x11d0, 0xba, 0x39, 0x0, 0xc0, 0x4f, 0xd7, 0xed, 0x67); + +/* + * DPLPROPERTY_PlayerGuid + * + * Request the GUID that identifies the player on this machine for sending + * property data back to the lobby. + * + * Property data is the DPLDATA_PLAYERDATA structure + */ +// {B4319322-D20D-11d0-BA39-00C04FD7ED67} +DEFINE_GUID(DPLPROPERTY_PlayerGuid, +0xb4319322, 0xd20d, 0x11d0, 0xba, 0x39, 0x0, 0xc0, 0x4f, 0xd7, 0xed, 0x67); + +/* + * DPLDATA_PLAYERGUID + * + * Data structure to hold the GUID of the player and player creation flags + * from the lobby. + */ +typedef struct _DPLDATA_PLAYERGUID +{ + GUID guidPlayer; + DWORD dwPlayerFlags; +} DPLDATA_PLAYERGUID, FAR *LPDPLDATA_PLAYERGUID; + +/* + * DPLPROPERTY_PlayerScore + * + * Used to send an array of long integers to the lobby indicating the + * score of a player. + * + * Property data is the DPLDATA_PLAYERSCORE structure. + */ +// {48784000-D219-11d0-BA39-00C04FD7ED67} +DEFINE_GUID(DPLPROPERTY_PlayerScore, +0x48784000, 0xd219, 0x11d0, 0xba, 0x39, 0x0, 0xc0, 0x4f, 0xd7, 0xed, 0x67); + +/* + * DPLDATA_PLAYERSCORE + * + * Data structure to hold an array of long integers representing a player score. + * Application must allocate enough memory to hold all the scores. + */ +typedef struct _DPLDATA_PLAYERSCORE +{ + DWORD dwScoreCount; + LONG Score[1]; +} DPLDATA_PLAYERSCORE, FAR *LPDPLDATA_PLAYERSCORE; + +/**************************************************************************** + * + * DirectPlay Address ID's + * + ****************************************************************************/ + +/* DirectPlay Address + * + * A DirectPlay address consists of multiple chunks of data, each tagged + * with a GUID signifying the type of data in the chunk. The chunk also + * has a length so that unknown chunk types can be skipped. + * + * The EnumAddress() function is used to parse these address data chunks. + */ + +/* + * DPADDRESS + * + * Header for block of address data elements + */ +typedef struct _DPADDRESS +{ + GUID guidDataType; + DWORD dwDataSize; +} DPADDRESS; + +typedef DPADDRESS FAR *LPDPADDRESS; + +/* + * DPAID_TotalSize + * + * Chunk is a DWORD containing size of entire DPADDRESS structure + */ + +// {1318F560-912C-11d0-9DAA-00A0C90A43CB} +DEFINE_GUID(DPAID_TotalSize, +0x1318f560, 0x912c, 0x11d0, 0x9d, 0xaa, 0x0, 0xa0, 0xc9, 0xa, 0x43, 0xcb); + +/* + * DPAID_ServiceProvider + * + * Chunk is a GUID describing the service provider that created the chunk. + * All addresses must contain this chunk. + */ + +// {07D916C0-E0AF-11cf-9C4E-00A0C905425E} +DEFINE_GUID(DPAID_ServiceProvider, +0x7d916c0, 0xe0af, 0x11cf, 0x9c, 0x4e, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +/* + * DPAID_LobbyProvider + * + * Chunk is a GUID describing the lobby provider that created the chunk. + * All addresses must contain this chunk. + */ + +// {59B95640-9667-11d0-A77D-0000F803ABFC} +DEFINE_GUID(DPAID_LobbyProvider, +0x59b95640, 0x9667, 0x11d0, 0xa7, 0x7d, 0x0, 0x0, 0xf8, 0x3, 0xab, 0xfc); + +/* + * DPAID_Phone and DPAID_PhoneW + * + * Chunk is a string containing a phone number (i.e. "1-800-555-1212") + * in ANSI or UNICODE format + */ + +// {78EC89A0-E0AF-11cf-9C4E-00A0C905425E} +DEFINE_GUID(DPAID_Phone, +0x78ec89a0, 0xe0af, 0x11cf, 0x9c, 0x4e, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +// {BA5A7A70-9DBF-11d0-9CC1-00A0C905425E} +DEFINE_GUID(DPAID_PhoneW, +0xba5a7a70, 0x9dbf, 0x11d0, 0x9c, 0xc1, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +/* + * DPAID_Modem and DPAID_ModemW + * + * Chunk is a string containing a modem name registered with TAPI + * in ANSI or UNICODE format + */ + +// {F6DCC200-A2FE-11d0-9C4F-00A0C905425E} +DEFINE_GUID(DPAID_Modem, +0xf6dcc200, 0xa2fe, 0x11d0, 0x9c, 0x4f, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +// {01FD92E0-A2FF-11d0-9C4F-00A0C905425E} +DEFINE_GUID(DPAID_ModemW, +0x1fd92e0, 0xa2ff, 0x11d0, 0x9c, 0x4f, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +/* + * DPAID_Inet and DPAID_InetW + * + * Chunk is a string containing a TCP/IP host name or an IP address + * (i.e. "dplay.microsoft.com" or "137.55.100.173") in ANSI or UNICODE format + */ + +// {C4A54DA0-E0AF-11cf-9C4E-00A0C905425E} +DEFINE_GUID(DPAID_INet, +0xc4a54da0, 0xe0af, 0x11cf, 0x9c, 0x4e, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +// {E63232A0-9DBF-11d0-9CC1-00A0C905425E} +DEFINE_GUID(DPAID_INetW, +0xe63232a0, 0x9dbf, 0x11d0, 0x9c, 0xc1, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +/* + * DPCOMPORTADDRESS + * + * Used to specify com port settings. The constants that define baud rate, + * stop bits and parity are defined in WINBASE.H. The constants for flow + * control are given below. + */ + +#define DPCPA_NOFLOW 0 // no flow control +#define DPCPA_XONXOFFFLOW 1 // software flow control +#define DPCPA_RTSFLOW 2 // hardware flow control with RTS +#define DPCPA_DTRFLOW 3 // hardware flow control with DTR +#define DPCPA_RTSDTRFLOW 4 // hardware flow control with RTS and DTR + +typedef struct _DPCOMPORTADDRESS +{ + DWORD dwComPort; // COM port to use (1-4) + DWORD dwBaudRate; // baud rate (100-256k) + DWORD dwStopBits; // no. stop bits (1-2) + DWORD dwParity; // parity (none, odd, even, mark) + DWORD dwFlowControl; // flow control (none, xon/xoff, rts, dtr) +} DPCOMPORTADDRESS; + +typedef DPCOMPORTADDRESS FAR *LPDPCOMPORTADDRESS; + +/* + * DPAID_ComPort + * + * Chunk contains a DPCOMPORTADDRESS structure defining the serial port. + */ + +// {F2F0CE00-E0AF-11cf-9C4E-00A0C905425E} +DEFINE_GUID(DPAID_ComPort, +0xf2f0ce00, 0xe0af, 0x11cf, 0x9c, 0x4e, 0x0, 0xa0, 0xc9, 0x5, 0x42, 0x5e); + +/**************************************************************************** + * + * dplobby 1.0 obsolete definitions + * Included for compatibility only. + * + ****************************************************************************/ +#define DPLAD_SYSTEM DPLMSG_SYSTEM + + +#ifdef __cplusplus +}; +#endif /* __cplusplus */ + +#endif /* __DPLOBBY_INCLUDED__ */ diff --git a/3rdparty/dx5/inc/dsetup.h b/3rdparty/dx5/inc/dsetup.h new file mode 100644 index 00000000..ea5936a5 --- /dev/null +++ b/3rdparty/dx5/inc/dsetup.h @@ -0,0 +1,267 @@ +/*========================================================================== + * + * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. + * + * File: dsetup.h + * Content: DirectXSetup, error codes and flags + ***************************************************************************/ + +#ifndef __DSETUP_H__ +#define __DSETUP_H__ + +#include // windows stuff + +#ifdef _WIN32 +#define COM_NO_WINDOWS_H +#include +#else +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +// DSETUP Error Codes, must remain compatible with previous setup. +#define DSETUPERR_SUCCESS_RESTART 1 +#define DSETUPERR_SUCCESS 0 +#define DSETUPERR_BADWINDOWSVERSION -1 +#define DSETUPERR_SOURCEFILENOTFOUND -2 +#define DSETUPERR_BADSOURCESIZE -3 +#define DSETUPERR_BADSOURCETIME -4 +#define DSETUPERR_NOCOPY -5 +#define DSETUPERR_OUTOFDISKSPACE -6 +#define DSETUPERR_CANTFINDINF -7 +#define DSETUPERR_CANTFINDDIR -8 +#define DSETUPERR_INTERNAL -9 +#define DSETUPERR_NTWITHNO3D -10 /* REM: obsolete, you'll never see this */ +#define DSETUPERR_UNKNOWNOS -11 +#define DSETUPERR_USERHITCANCEL -12 +#define DSETUPERR_NOTPREINSTALLEDONNT -13 + +// DSETUP flags. DirectX 5.0 apps should use these flags only. +#define DSETUP_DDRAWDRV 0x00000008 /* install DirectDraw Drivers */ +#define DSETUP_DSOUNDDRV 0x00000010 /* install DirectSound Drivers */ +#define DSETUP_DXCORE 0x00010000 /* install DirectX runtime */ +#define DSETUP_DIRECTX (DSETUP_DXCORE|DSETUP_DDRAWDRV|DSETUP_DSOUNDDRV) +#define DSETUP_TESTINSTALL 0x00020000 /* just test install, don't do anything */ + +// These OBSOLETE flags are here for compatibility with pre-DX5 apps only. +// They are present to allow DX3 apps to be recompiled with DX5 and still work. +// DO NOT USE THEM for DX5. They will go away in future DX releases. +#define DSETUP_DDRAW 0x00000001 /* OBSOLETE. install DirectDraw */ +#define DSETUP_DSOUND 0x00000002 /* OBSOLETE. install DirectSound */ +#define DSETUP_DPLAY 0x00000004 /* OBSOLETE. install DirectPlay */ +#define DSETUP_DPLAYSP 0x00000020 /* OBSOLETE. install DirectPlay Providers */ +#define DSETUP_DVIDEO 0x00000040 /* OBSOLETE. install DirectVideo */ +#define DSETUP_D3D 0x00000200 /* OBSOLETE. install Direct3D */ +#define DSETUP_DINPUT 0x00000800 /* OBSOLETE. install DirectInput */ +#define DSETUP_DIRECTXSETUP 0x00001000 /* OBSOLETE. install DirectXSetup DLL's */ +#define DSETUP_NOUI 0x00002000 /* OBSOLETE. install DirectX with NO UI */ +#define DSETUP_PROMPTFORDRIVERS 0x10000000 /* OBSOLETE. prompt when replacing display/audio drivers */ +#define DSETUP_RESTOREDRIVERS 0x20000000 /* OBSOLETE. restore display/audio drivers */ + + + +//****************************************************************** +// DirectX Setup Callback mechanism +//****************************************************************** + +// DSETUP Message Info Codes, passed to callback as Reason parameter. +#define DSETUP_CB_MSG_NOMESSAGE 0 +#define DSETUP_CB_MSG_CANTINSTALL_UNKNOWNOS 1 +#define DSETUP_CB_MSG_CANTINSTALL_NT 2 +#define DSETUP_CB_MSG_CANTINSTALL_BETA 3 +#define DSETUP_CB_MSG_CANTINSTALL_NOTWIN32 4 +#define DSETUP_CB_MSG_CANTINSTALL_WRONGLANGUAGE 5 +#define DSETUP_CB_MSG_CANTINSTALL_WRONGPLATFORM 6 +#define DSETUP_CB_MSG_PREINSTALL_NT 7 +#define DSETUP_CB_MSG_NOTPREINSTALLEDONNT 8 +#define DSETUP_CB_MSG_SETUP_INIT_FAILED 9 +#define DSETUP_CB_MSG_INTERNAL_ERROR 10 +#define DSETUP_CB_MSG_CHECK_DRIVER_UPGRADE 11 +#define DSETUP_CB_MSG_OUTOFDISKSPACE 12 +#define DSETUP_CB_MSG_BEGIN_INSTALL 13 +#define DSETUP_CB_MSG_BEGIN_INSTALL_RUNTIME 14 +#define DSETUP_CB_MSG_BEGIN_INSTALL_DRIVERS 15 +#define DSETUP_CB_MSG_BEGIN_RESTORE_DRIVERS 16 +#define DSETUP_CB_MSG_FILECOPYERROR 17 + + +#define DSETUP_CB_UPGRADE_TYPE_MASK 0x000F +#define DSETUP_CB_UPGRADE_KEEP 0x0001 +#define DSETUP_CB_UPGRADE_SAFE 0x0002 +#define DSETUP_CB_UPGRADE_FORCE 0x0004 +#define DSETUP_CB_UPGRADE_UNKNOWN 0x0008 + +#define DSETUP_CB_UPGRADE_HASWARNINGS 0x0100 +#define DSETUP_CB_UPGRADE_CANTBACKUP 0x0200 + +#define DSETUP_CB_UPGRADE_DEVICE_ACTIVE 0x0800 + +#define DSETUP_CB_UPGRADE_DEVICE_DISPLAY 0x1000 +#define DSETUP_CB_UPGRADE_DEVICE_MEDIA 0x2000 + + +typedef struct _DSETUP_CB_UPGRADEINFO +{ + DWORD UpgradeFlags; +} DSETUP_CB_UPGRADEINFO; + +typedef struct _DSETUP_CB_FILECOPYERROR +{ + DWORD dwError; +} DSETUP_CB_FILECOPYERROR; + + +#ifdef _WIN32 +// +// Data Structures +// +#ifndef UNICODE_ONLY +typedef struct _DIRECTXREGISTERAPPA { + DWORD dwSize; + DWORD dwFlags; + LPSTR lpszApplicationName; + LPGUID lpGUID; + LPSTR lpszFilename; + LPSTR lpszCommandLine; + LPSTR lpszPath; + LPSTR lpszCurrentDirectory; +} DIRECTXREGISTERAPPA, *PDIRECTXREGISTERAPPA, *LPDIRECTXREGISTERAPPA; +#endif //!UNICODE_ONLY +#ifndef ANSI_ONLY +typedef struct _DIRECTXREGISTERAPPW { + DWORD dwSize; + DWORD dwFlags; + LPWSTR lpszApplicationName; + LPGUID lpGUID; + LPWSTR lpszFilename; + LPWSTR lpszCommandLine; + LPWSTR lpszPath; + LPWSTR lpszCurrentDirectory; +} DIRECTXREGISTERAPPW, *PDIRECTXREGISTERAPPW, *LPDIRECTXREGISTERAPPW; +#endif //!ANSI_ONLY +#ifdef UNICODE +typedef DIRECTXREGISTERAPPW DIRECTXREGISTERAPP; +typedef PDIRECTXREGISTERAPPW PDIRECTXREGISTERAPP; +typedef LPDIRECTXREGISTERAPPW LPDIRECTXREGISTERAPP; +#else +typedef DIRECTXREGISTERAPPA DIRECTXREGISTERAPP; +typedef PDIRECTXREGISTERAPPA PDIRECTXREGISTERAPP; +typedef LPDIRECTXREGISTERAPPA LPDIRECTXREGISTERAPP; +#endif // UNICODE + + +// +// API +// +#ifndef UNICODE_ONLY +INT +WINAPI +DirectXSetupA( + HWND hWnd, + LPSTR lpszRootPath, + DWORD dwFlags + ); +#endif //!UNICODE_ONLY +#ifndef ANSI_ONLY +INT +WINAPI +DirectXSetupW( + HWND hWnd, + LPWSTR lpszRootPath, + DWORD dwFlags + ); +#endif //!ANSI_ONLY +#ifdef UNICODE +#define DirectXSetup DirectXSetupW +#else +#define DirectXSetup DirectXSetupA +#endif // !UNICODE + +#ifndef UNICODE_ONLY +INT +WINAPI +DirectXDeviceDriverSetupA( + HWND hWnd, + LPSTR lpszDriverClass, + LPSTR lpszDriverPath, + DWORD dwFlags + ); +#endif //!UNICODE_ONLY +#ifndef ANSI_ONLY +INT +WINAPI +DirectXDeviceDriverSetupW( + HWND hWnd, + LPWSTR lpszDriverClass, + LPWSTR lpszDriverPath, + DWORD dwFlags + ); +#endif //!ANSI_ONLY +#ifdef UNICODE +#define DirectXDeviceDriverSetup DirectXDeviceDriverSetupW +#else +#define DirectXDeviceDriverSetup DirectXDeviceDriverSetupA +#endif // !UNICODE + +#ifndef UNICODE_ONLY +INT +WINAPI +DirectXRegisterApplicationA( + HWND hWnd, + LPDIRECTXREGISTERAPPA lpDXRegApp + ); +#endif //!UNICODE_ONLY +#ifndef ANSI_ONLY +INT +WINAPI +DirectXRegisterApplicationW( + HWND hWnd, + LPDIRECTXREGISTERAPPW lpDXRegApp + ); +#endif //!ANSI_ONLY +#ifdef UNICODE +#define DirectXRegisterApplication DirectXRegisterApplicationW +#else +#define DirectXRegisterApplication DirectXRegisterApplicationA +#endif // !UNICODE + +INT +WINAPI +DirectXUnRegisterApplication( + HWND hWnd, + LPGUID lpGUID + ); + +// +// Function Pointers +// +#ifdef UNICODE +typedef INT (WINAPI * LPDIRECTXSETUP)(HWND, LPWSTR, DWORD); +typedef INT (WINAPI * LPDIRECTXDEVICEDRIVERSETUP)(HWND, LPWSTR, LPSTR, DWORD); +typedef INT (WINAPI * LPDIRECTXREGISTERAPPLICATION)(HWND, LPDIRECTXREGISTERAPPW); +#else +typedef INT (WINAPI * LPDIRECTXSETUP)(HWND, LPSTR, DWORD); +typedef INT (WINAPI * LPDIRECTXDEVICEDRIVERSETUP)(HWND, LPSTR, LPSTR, DWORD); +typedef INT (WINAPI * LPDIRECTXREGISTERAPPLICATION)(HWND, LPDIRECTXREGISTERAPPA); +#endif // UNICODE + +typedef DWORD (FAR PASCAL * DSETUP_CALLBACK)(DWORD Reason, + DWORD MsgType, /* Same as flags to MessageBox */ + LPSTR szMessage, + LPSTR szName, + void *pInfo); + +INT WINAPI DirectXSetupSetCallback(DSETUP_CALLBACK Callback); +INT WINAPI DirectXSetupGetVersion(DWORD *lpdwVersion, DWORD *lpdwMinorVersion); + +#endif // WIN32 + + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/3rdparty/dx5/inc/dsound.h b/3rdparty/dx5/inc/dsound.h new file mode 100644 index 00000000..0f4b2d3f --- /dev/null +++ b/3rdparty/dx5/inc/dsound.h @@ -0,0 +1,863 @@ +/*==========================================================================; + * + * Copyright (C) 1995,1996 Microsoft Corporation. All Rights Reserved. + * + * File: dsound.h + * Content: DirectSound include file + * + **************************************************************************/ + +#ifndef __DSOUND_INCLUDED__ +#define __DSOUND_INCLUDED__ + +#include + +#define COM_NO_WINDOWS_H +#include + +#define _FACDS 0x878 +#define MAKE_DSHRESULT(code) MAKE_HRESULT(1, _FACDS, code) + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Direct Sound Component GUID {47D4D946-62E8-11cf-93BC-444553540000} +DEFINE_GUID(CLSID_DirectSound, 0x47d4d946, 0x62e8, 0x11cf, 0x93, 0xbc, 0x44, 0x45, 0x53, 0x54, 0x0, 0x0); + +// DirectSound Capture Component GUID {B0210780-89CD-11d0-AF08-00A0C925CD16} +DEFINE_GUID(CLSID_DirectSoundCapture, 0xb0210780, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +// +// Structures +// + +#ifdef __cplusplus +// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined +struct IDirectSound; +struct IDirectSoundBuffer; +struct IDirectSound3DListener; +struct IDirectSound3DBuffer; +struct IDirectSoundCapture; +struct IDirectSoundCaptureBuffer; +struct IDirectSoundNotify; +#endif // __cplusplus + +typedef struct IDirectSound *LPDIRECTSOUND; +typedef struct IDirectSoundBuffer *LPDIRECTSOUNDBUFFER; +typedef struct IDirectSound3DListener *LPDIRECTSOUND3DLISTENER; +typedef struct IDirectSound3DBuffer *LPDIRECTSOUND3DBUFFER; +typedef struct IDirectSoundCapture *LPDIRECTSOUNDCAPTURE; +typedef struct IDirectSoundCaptureBuffer *LPDIRECTSOUNDCAPTUREBUFFER; +typedef struct IDirectSoundNotify *LPDIRECTSOUNDNOTIFY; + +typedef struct _DSCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwMinSecondarySampleRate; + DWORD dwMaxSecondarySampleRate; + DWORD dwPrimaryBuffers; + DWORD dwMaxHwMixingAllBuffers; + DWORD dwMaxHwMixingStaticBuffers; + DWORD dwMaxHwMixingStreamingBuffers; + DWORD dwFreeHwMixingAllBuffers; + DWORD dwFreeHwMixingStaticBuffers; + DWORD dwFreeHwMixingStreamingBuffers; + DWORD dwMaxHw3DAllBuffers; + DWORD dwMaxHw3DStaticBuffers; + DWORD dwMaxHw3DStreamingBuffers; + DWORD dwFreeHw3DAllBuffers; + DWORD dwFreeHw3DStaticBuffers; + DWORD dwFreeHw3DStreamingBuffers; + DWORD dwTotalHwMemBytes; + DWORD dwFreeHwMemBytes; + DWORD dwMaxContigFreeHwMemBytes; + DWORD dwUnlockTransferRateHwBuffers; + DWORD dwPlayCpuOverheadSwBuffers; + DWORD dwReserved1; + DWORD dwReserved2; +} DSCAPS, *LPDSCAPS; + +typedef const DSCAPS *LPCDSCAPS; + +typedef struct _DSBCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwUnlockTransferRate; + DWORD dwPlayCpuOverhead; +} DSBCAPS, *LPDSBCAPS; + +typedef const DSBCAPS *LPCDSBCAPS; + +typedef struct _DSBUFFERDESC +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +} DSBUFFERDESC, *LPDSBUFFERDESC; + +typedef const DSBUFFERDESC *LPCDSBUFFERDESC; + +typedef struct _DS3DBUFFER +{ + DWORD dwSize; + D3DVECTOR vPosition; + D3DVECTOR vVelocity; + DWORD dwInsideConeAngle; + DWORD dwOutsideConeAngle; + D3DVECTOR vConeOrientation; + LONG lConeOutsideVolume; + D3DVALUE flMinDistance; + D3DVALUE flMaxDistance; + DWORD dwMode; +} DS3DBUFFER, *LPDS3DBUFFER; + +typedef const DS3DBUFFER *LPCDS3DBUFFER; + +typedef struct _DS3DLISTENER +{ + DWORD dwSize; + D3DVECTOR vPosition; + D3DVECTOR vVelocity; + D3DVECTOR vOrientFront; + D3DVECTOR vOrientTop; + D3DVALUE flDistanceFactor; + D3DVALUE flRolloffFactor; + D3DVALUE flDopplerFactor; +} DS3DLISTENER, *LPDS3DLISTENER; + +typedef const DS3DLISTENER *LPCDS3DLISTENER; + +typedef struct _DSCCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwFormats; + DWORD dwChannels; +} DSCCAPS, *LPDSCCAPS; + +typedef const DSCCAPS *LPCDSCCAPS; + +typedef struct _DSCBUFFERDESC +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; + LPWAVEFORMATEX lpwfxFormat; +} DSCBUFFERDESC, *LPDSCBUFFERDESC; + +typedef const DSCBUFFERDESC *LPCDSCBUFFERDESC; + +typedef struct _DSCBCAPS +{ + DWORD dwSize; + DWORD dwFlags; + DWORD dwBufferBytes; + DWORD dwReserved; +} DSCBCAPS, *LPDSCBCAPS; + +typedef const DSCBCAPS *LPCDSCBCAPS; + +typedef struct _DSBPOSITIONNOTIFY +{ + DWORD dwOffset; + HANDLE hEventNotify; +} DSBPOSITIONNOTIFY, *LPDSBPOSITIONNOTIFY; + +typedef const DSBPOSITIONNOTIFY *LPCDSBPOSITIONNOTIFY; + +// +// Compatibility typedefs +// + +typedef LPDIRECTSOUND *LPLPDIRECTSOUND; +typedef LPDIRECTSOUNDBUFFER *LPLPDIRECTSOUNDBUFFER; +typedef LPDIRECTSOUND3DLISTENER *LPLPDIRECTSOUND3DLISTENER; +typedef LPDIRECTSOUND3DBUFFER *LPLPDIRECTSOUND3DBUFFER; +typedef LPDIRECTSOUNDCAPTURE *LPLPDIRECTSOUNDCAPTURE; +typedef LPDIRECTSOUNDCAPTUREBUFFER *LPLPDIRECTSOUNDCAPTUREBUFFER; +typedef LPDIRECTSOUNDNOTIFY *LPLPDIRECTSOUNDNOTIFY; +typedef LPVOID *LPLPVOID; +typedef const WAVEFORMATEX *LPCWAVEFORMATEX; + +// +// DirectSound API +// + +typedef BOOL (CALLBACK *LPDSENUMCALLBACKW)(LPGUID, LPCWSTR, LPCWSTR, LPVOID); +typedef BOOL (CALLBACK *LPDSENUMCALLBACKA)(LPGUID, LPCSTR, LPCSTR, LPVOID); + +extern HRESULT WINAPI DirectSoundCreate(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); +extern HRESULT WINAPI DirectSoundEnumerateW(LPDSENUMCALLBACKW, LPVOID); +extern HRESULT WINAPI DirectSoundEnumerateA(LPDSENUMCALLBACKA, LPVOID); + +extern HRESULT WINAPI DirectSoundCaptureCreate(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN); +extern HRESULT WINAPI DirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW, LPVOID); +extern HRESULT WINAPI DirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA, LPVOID); + +#ifdef UNICODE +#define LPDSENUMCALLBACK LPDSENUMCALLBACKW +#define DirectSoundEnumerate DirectSoundEnumerateW +#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateW +#else // UNICODE +#define LPDSENUMCALLBACK LPDSENUMCALLBACKA +#define DirectSoundEnumerate DirectSoundEnumerateA +#define DirectSoundCaptureEnumerate DirectSoundCaptureEnumerateA +#endif // UNICODE + +// +// IDirectSound +// + +DEFINE_GUID(IID_IDirectSound, 0x279AFA83, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSound + +DECLARE_INTERFACE_(IDirectSound, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound methods + STDMETHOD(CreateSoundBuffer) (THIS_ LPCDSBUFFERDESC, LPDIRECTSOUNDBUFFER *, LPUNKNOWN) PURE; + STDMETHOD(GetCaps) (THIS_ LPDSCAPS) PURE; + STDMETHOD(DuplicateSoundBuffer) (THIS_ LPDIRECTSOUNDBUFFER, LPDIRECTSOUNDBUFFER *) PURE; + STDMETHOD(SetCooperativeLevel) (THIS_ HWND, DWORD) PURE; + STDMETHOD(Compact) (THIS) PURE; + STDMETHOD(GetSpeakerConfig) (THIS_ LPDWORD) PURE; + STDMETHOD(SetSpeakerConfig) (THIS_ DWORD) PURE; + STDMETHOD(Initialize) (THIS_ LPGUID) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectSound_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectSound_Release(p) (p)->lpVtbl->Release(p) +#define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->lpVtbl->CreateSoundBuffer(p,a,b,c) +#define IDirectSound_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->lpVtbl->DuplicateSoundBuffer(p,a,b) +#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->lpVtbl->SetCooperativeLevel(p,a,b) +#define IDirectSound_Compact(p) (p)->lpVtbl->Compact(p) +#define IDirectSound_GetSpeakerConfig(p,a) (p)->lpVtbl->GetSpeakerConfig(p,a) +#define IDirectSound_SetSpeakerConfig(p,b) (p)->lpVtbl->SetSpeakerConfig(p,b) +#define IDirectSound_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectSound_AddRef(p) (p)->AddRef() +#define IDirectSound_Release(p) (p)->Release() +#define IDirectSound_CreateSoundBuffer(p,a,b,c) (p)->CreateSoundBuffer(a,b,c) +#define IDirectSound_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSound_DuplicateSoundBuffer(p,a,b) (p)->DuplicateSoundBuffer(a,b) +#define IDirectSound_SetCooperativeLevel(p,a,b) (p)->SetCooperativeLevel(a,b) +#define IDirectSound_Compact(p) (p)->Compact() +#define IDirectSound_GetSpeakerConfig(p,a) (p)->GetSpeakerConfig(a) +#define IDirectSound_SetSpeakerConfig(p,b) (p)->SetSpeakerConfig(b) +#define IDirectSound_Initialize(p,a) (p)->Initialize(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundBuffer +// + +DEFINE_GUID(IID_IDirectSoundBuffer, 0x279AFA85, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSoundBuffer + +DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSBCAPS) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD, LPDWORD) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX, DWORD, LPDWORD) PURE; + STDMETHOD(GetVolume) (THIS_ LPLONG) PURE; + STDMETHOD(GetPan) (THIS_ LPLONG) PURE; + STDMETHOD(GetFrequency) (THIS_ LPDWORD) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUND, LPCDSBUFFERDESC) PURE; + STDMETHOD(Lock) (THIS_ DWORD, DWORD, LPVOID *, LPDWORD, LPVOID *, LPDWORD, DWORD) PURE; + STDMETHOD(Play) (THIS_ DWORD, DWORD, DWORD) PURE; + STDMETHOD(SetCurrentPosition) (THIS_ DWORD) PURE; + STDMETHOD(SetFormat) (THIS_ LPCWAVEFORMATEX) PURE; + STDMETHOD(SetVolume) (THIS_ LONG) PURE; + STDMETHOD(SetPan) (THIS_ LONG) PURE; + STDMETHOD(SetFrequency) (THIS_ DWORD) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID, DWORD, LPVOID, DWORD) PURE; + STDMETHOD(Restore) (THIS) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectSoundBuffer_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectSoundBuffer_Release(p) (p)->lpVtbl->Release(p) +#define IDirectSoundBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) +#define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) +#define IDirectSoundBuffer_GetVolume(p,a) (p)->lpVtbl->GetVolume(p,a) +#define IDirectSoundBuffer_GetPan(p,a) (p)->lpVtbl->GetPan(p,a) +#define IDirectSoundBuffer_GetFrequency(p,a) (p)->lpVtbl->GetFrequency(p,a) +#define IDirectSoundBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) +#define IDirectSoundBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundBuffer_Play(p,a,b,c) (p)->lpVtbl->Play(p,a,b,c) +#define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->lpVtbl->SetCurrentPosition(p,a) +#define IDirectSoundBuffer_SetFormat(p,a) (p)->lpVtbl->SetFormat(p,a) +#define IDirectSoundBuffer_SetVolume(p,a) (p)->lpVtbl->SetVolume(p,a) +#define IDirectSoundBuffer_SetPan(p,a) (p)->lpVtbl->SetPan(p,a) +#define IDirectSoundBuffer_SetFrequency(p,a) (p)->lpVtbl->SetFrequency(p,a) +#define IDirectSoundBuffer_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) +#define IDirectSoundBuffer_Restore(p) (p)->lpVtbl->Restore(p) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundBuffer_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectSoundBuffer_AddRef(p) (p)->AddRef() +#define IDirectSoundBuffer_Release(p) (p)->Release() +#define IDirectSoundBuffer_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSoundBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) +#define IDirectSoundBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) +#define IDirectSoundBuffer_GetVolume(p,a) (p)->GetVolume(a) +#define IDirectSoundBuffer_GetPan(p,a) (p)->GetPan(a) +#define IDirectSoundBuffer_GetFrequency(p,a) (p)->GetFrequency(a) +#define IDirectSoundBuffer_GetStatus(p,a) (p)->GetStatus(a) +#define IDirectSoundBuffer_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectSoundBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) +#define IDirectSoundBuffer_Play(p,a,b,c) (p)->Play(a,b,c) +#define IDirectSoundBuffer_SetCurrentPosition(p,a) (p)->SetCurrentPosition(a) +#define IDirectSoundBuffer_SetFormat(p,a) (p)->SetFormat(a) +#define IDirectSoundBuffer_SetVolume(p,a) (p)->SetVolume(a) +#define IDirectSoundBuffer_SetPan(p,a) (p)->SetPan(a) +#define IDirectSoundBuffer_SetFrequency(p,a) (p)->SetFrequency(a) +#define IDirectSoundBuffer_Stop(p) (p)->Stop() +#define IDirectSoundBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) +#define IDirectSoundBuffer_Restore(p) (p)->Restore() +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSound3DListener +// + +DEFINE_GUID(IID_IDirectSound3DListener, 0x279AFA84, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSound3DListener + +DECLARE_INTERFACE_(IDirectSound3DListener, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSound3D methods + STDMETHOD(GetAllParameters) (THIS_ LPDS3DLISTENER) PURE; + STDMETHOD(GetDistanceFactor) (THIS_ LPD3DVALUE) PURE; + STDMETHOD(GetDopplerFactor) (THIS_ LPD3DVALUE) PURE; + STDMETHOD(GetOrientation) (THIS_ LPD3DVECTOR, LPD3DVECTOR) PURE; + STDMETHOD(GetPosition) (THIS_ LPD3DVECTOR) PURE; + STDMETHOD(GetRolloffFactor) (THIS_ LPD3DVALUE) PURE; + STDMETHOD(GetVelocity) (THIS_ LPD3DVECTOR) PURE; + STDMETHOD(SetAllParameters) (THIS_ LPCDS3DLISTENER, DWORD) PURE; + STDMETHOD(SetDistanceFactor) (THIS_ D3DVALUE, DWORD) PURE; + STDMETHOD(SetDopplerFactor) (THIS_ D3DVALUE, DWORD) PURE; + STDMETHOD(SetOrientation) (THIS_ D3DVALUE, D3DVALUE, D3DVALUE, D3DVALUE, D3DVALUE, D3DVALUE, DWORD) PURE; + STDMETHOD(SetPosition) (THIS_ D3DVALUE, D3DVALUE, D3DVALUE, DWORD) PURE; + STDMETHOD(SetRolloffFactor) (THIS_ D3DVALUE, DWORD) PURE; + STDMETHOD(SetVelocity) (THIS_ D3DVALUE, D3DVALUE, D3DVALUE, DWORD) PURE; + STDMETHOD(CommitDeferredSettings) (THIS) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DListener_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectSound3DListener_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectSound3DListener_Release(p) (p)->lpVtbl->Release(p) +#define IDirectSound3DListener_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->lpVtbl->GetDistanceFactor(p,a) +#define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->lpVtbl->GetDopplerFactor(p,a) +#define IDirectSound3DListener_GetOrientation(p,a,b) (p)->lpVtbl->GetOrientation(p,a,b) +#define IDirectSound3DListener_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) +#define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->lpVtbl->GetRolloffFactor(p,a) +#define IDirectSound3DListener_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) +#define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) +#define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->lpVtbl->SetDistanceFactor(p,a,b) +#define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->lpVtbl->SetDopplerFactor(p,a,b) +#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->lpVtbl->SetOrientation(p,a,b,c,d,e,f,g) +#define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) +#define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->lpVtbl->SetRolloffFactor(p,a,b) +#define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) +#define IDirectSound3DListener_CommitDeferredSettings(p) (p)->lpVtbl->CommitDeferredSettings(p) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DListener_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectSound3DListener_AddRef(p) (p)->AddRef() +#define IDirectSound3DListener_Release(p) (p)->Release() +#define IDirectSound3DListener_GetAllParameters(p,a) (p)->GetAllParameters(a) +#define IDirectSound3DListener_GetDistanceFactor(p,a) (p)->GetDistanceFactor(a) +#define IDirectSound3DListener_GetDopplerFactor(p,a) (p)->GetDopplerFactor(a) +#define IDirectSound3DListener_GetOrientation(p,a,b) (p)->GetOrientation(a,b) +#define IDirectSound3DListener_GetPosition(p,a) (p)->GetPosition(a) +#define IDirectSound3DListener_GetRolloffFactor(p,a) (p)->GetRolloffFactor(a) +#define IDirectSound3DListener_GetVelocity(p,a) (p)->GetVelocity(a) +#define IDirectSound3DListener_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) +#define IDirectSound3DListener_SetDistanceFactor(p,a,b) (p)->SetDistanceFactor(a,b) +#define IDirectSound3DListener_SetDopplerFactor(p,a,b) (p)->SetDopplerFactor(a,b) +#define IDirectSound3DListener_SetOrientation(p,a,b,c,d,e,f,g) (p)->SetOrientation(a,b,c,d,e,f,g) +#define IDirectSound3DListener_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) +#define IDirectSound3DListener_SetRolloffFactor(p,a,b) (p)->SetRolloffFactor(a,b) +#define IDirectSound3DListener_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) +#define IDirectSound3DListener_CommitDeferredSettings(p) (p)->CommitDeferredSettings() +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSound3DBuffer +// + +DEFINE_GUID(IID_IDirectSound3DBuffer, 0x279AFA86, 0x4981, 0x11CE, 0xA5, 0x21, 0x00, 0x20, 0xAF, 0x0B, 0xE5, 0x60); + +#undef INTERFACE +#define INTERFACE IDirectSound3DBuffer + +DECLARE_INTERFACE_(IDirectSound3DBuffer, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundBuffer3D methods + STDMETHOD(GetAllParameters) (THIS_ LPDS3DBUFFER) PURE; + STDMETHOD(GetConeAngles) (THIS_ LPDWORD, LPDWORD) PURE; + STDMETHOD(GetConeOrientation) (THIS_ LPD3DVECTOR) PURE; + STDMETHOD(GetConeOutsideVolume) (THIS_ LPLONG) PURE; + STDMETHOD(GetMaxDistance) (THIS_ LPD3DVALUE) PURE; + STDMETHOD(GetMinDistance) (THIS_ LPD3DVALUE) PURE; + STDMETHOD(GetMode) (THIS_ LPDWORD) PURE; + STDMETHOD(GetPosition) (THIS_ LPD3DVECTOR) PURE; + STDMETHOD(GetVelocity) (THIS_ LPD3DVECTOR) PURE; + STDMETHOD(SetAllParameters) (THIS_ LPCDS3DBUFFER, DWORD) PURE; + STDMETHOD(SetConeAngles) (THIS_ DWORD, DWORD, DWORD) PURE; + STDMETHOD(SetConeOrientation) (THIS_ D3DVALUE, D3DVALUE, D3DVALUE, DWORD) PURE; + STDMETHOD(SetConeOutsideVolume) (THIS_ LONG, DWORD) PURE; + STDMETHOD(SetMaxDistance) (THIS_ D3DVALUE, DWORD) PURE; + STDMETHOD(SetMinDistance) (THIS_ D3DVALUE, DWORD) PURE; + STDMETHOD(SetMode) (THIS_ DWORD, DWORD) PURE; + STDMETHOD(SetPosition) (THIS_ D3DVALUE, D3DVALUE, D3DVALUE, DWORD) PURE; + STDMETHOD(SetVelocity) (THIS_ D3DVALUE, D3DVALUE, D3DVALUE, DWORD) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DBuffer_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectSound3DBuffer_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectSound3DBuffer_Release(p) (p)->lpVtbl->Release(p) +#define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->lpVtbl->GetAllParameters(p,a) +#define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->lpVtbl->GetConeAngles(p,a,b) +#define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->lpVtbl->GetConeOrientation(p,a) +#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->lpVtbl->GetConeOutsideVolume(p,a) +#define IDirectSound3DBuffer_GetPosition(p,a) (p)->lpVtbl->GetPosition(p,a) +#define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->lpVtbl->GetMinDistance(p,a) +#define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->lpVtbl->GetMaxDistance(p,a) +#define IDirectSound3DBuffer_GetMode(p,a) (p)->lpVtbl->GetMode(p,a) +#define IDirectSound3DBuffer_GetVelocity(p,a) (p)->lpVtbl->GetVelocity(p,a) +#define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->lpVtbl->SetAllParameters(p,a,b) +#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->lpVtbl->SetConeAngles(p,a,b,c) +#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->lpVtbl->SetConeOrientation(p,a,b,c,d) +#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b)(p)->lpVtbl->SetConeOutsideVolume(p,a,b) +#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->lpVtbl->SetPosition(p,a,b,c,d) +#define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->lpVtbl->SetMinDistance(p,a,b) +#define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->lpVtbl->SetMaxDistance(p,a,b) +#define IDirectSound3DBuffer_SetMode(p,a,b) (p)->lpVtbl->SetMode(p,a,b) +#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->lpVtbl->SetVelocity(p,a,b,c,d) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSound3DBuffer_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectSound3DBuffer_AddRef(p) (p)->AddRef() +#define IDirectSound3DBuffer_Release(p) (p)->Release() +#define IDirectSound3DBuffer_GetAllParameters(p,a) (p)->GetAllParameters(a) +#define IDirectSound3DBuffer_GetConeAngles(p,a,b) (p)->GetConeAngles(a,b) +#define IDirectSound3DBuffer_GetConeOrientation(p,a) (p)->GetConeOrientation(a) +#define IDirectSound3DBuffer_GetConeOutsideVolume(p,a) (p)->GetConeOutsideVolume(a) +#define IDirectSound3DBuffer_GetPosition(p,a) (p)->GetPosition(a) +#define IDirectSound3DBuffer_GetMinDistance(p,a) (p)->GetMinDistance(a) +#define IDirectSound3DBuffer_GetMaxDistance(p,a) (p)->GetMaxDistance(a) +#define IDirectSound3DBuffer_GetMode(p,a) (p)->GetMode(a) +#define IDirectSound3DBuffer_GetVelocity(p,a) (p)->GetVelocity(a) +#define IDirectSound3DBuffer_SetAllParameters(p,a,b) (p)->SetAllParameters(a,b) +#define IDirectSound3DBuffer_SetConeAngles(p,a,b,c) (p)->SetConeAngles(a,b,c) +#define IDirectSound3DBuffer_SetConeOrientation(p,a,b,c,d) (p)->SetConeOrientation(a,b,c,d) +#define IDirectSound3DBuffer_SetConeOutsideVolume(p,a,b)(p)->SetConeOutsideVolume(a,b) +#define IDirectSound3DBuffer_SetPosition(p,a,b,c,d) (p)->SetPosition(a,b,c,d) +#define IDirectSound3DBuffer_SetMinDistance(p,a,b) (p)->SetMinDistance(a,b) +#define IDirectSound3DBuffer_SetMaxDistance(p,a,b) (p)->SetMaxDistance(a,b) +#define IDirectSound3DBuffer_SetMode(p,a,b) (p)->SetMode(a,b) +#define IDirectSound3DBuffer_SetVelocity(p,a,b,c,d) (p)->SetVelocity(a,b,c,d) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundCapture +// + +DEFINE_GUID(IID_IDirectSoundCapture, 0xb0210781, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +#undef INTERFACE +#define INTERFACE IDirectSoundCapture + +DECLARE_INTERFACE_(IDirectSoundCapture, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCapture methods + STDMETHOD(CreateCaptureBuffer) (THIS_ LPCDSCBUFFERDESC, LPDIRECTSOUNDCAPTUREBUFFER *, LPUNKNOWN) PURE; + STDMETHOD(GetCaps) (THIS_ LPDSCCAPS ) PURE; + STDMETHOD(Initialize) (THIS_ LPGUID) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCapture_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectSoundCapture_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectSoundCapture_Release(p) (p)->lpVtbl->Release(p) +#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->lpVtbl->CreateCaptureBuffer(p,a,b,c) +#define IDirectSoundCapture_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSoundCapture_Initialize(p,a) (p)->lpVtbl->Initialize(p,a) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCapture_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectSoundCapture_AddRef(p) (p)->AddRef() +#define IDirectSoundCapture_Release(p) (p)->Release() +#define IDirectSoundCapture_CreateCaptureBuffer(p,a,b,c) (p)->CreateCaptureBuffer(a,b,c) +#define IDirectSoundCapture_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSoundCapture_Initialize(p,a) (p)->Initialize(a) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundCaptureBuffer +// + +DEFINE_GUID(IID_IDirectSoundCaptureBuffer, 0xb0210782, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +#undef INTERFACE +#define INTERFACE IDirectSoundCaptureBuffer + +DECLARE_INTERFACE_(IDirectSoundCaptureBuffer, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundCaptureBuffer methods + STDMETHOD(GetCaps) (THIS_ LPDSCBCAPS ) PURE; + STDMETHOD(GetCurrentPosition) (THIS_ LPDWORD, LPDWORD ) PURE; + STDMETHOD(GetFormat) (THIS_ LPWAVEFORMATEX, DWORD, LPDWORD ) PURE; + STDMETHOD(GetStatus) (THIS_ LPDWORD ) PURE; + STDMETHOD(Initialize) (THIS_ LPDIRECTSOUNDCAPTURE, LPCDSCBUFFERDESC) PURE; + STDMETHOD(Lock) (THIS_ DWORD, DWORD, LPVOID *, LPDWORD, LPVOID *, LPDWORD, DWORD) PURE; + STDMETHOD(Start) (THIS_ DWORD) PURE; + STDMETHOD(Stop) (THIS) PURE; + STDMETHOD(Unlock) (THIS_ LPVOID, DWORD, LPVOID, DWORD) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectSoundCaptureBuffer_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectSoundCaptureBuffer_Release(p) (p)->lpVtbl->Release(p) +#define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->lpVtbl->GetCaps(p,a) +#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->lpVtbl->GetCurrentPosition(p,a,b) +#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->lpVtbl->GetFormat(p,a,b,c) +#define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->lpVtbl->GetStatus(p,a) +#define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->lpVtbl->Initialize(p,a,b) +#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->lpVtbl->Lock(p,a,b,c,d,e,f,g) +#define IDirectSoundCaptureBuffer_Start(p,a) (p)->lpVtbl->Start(p,a) +#define IDirectSoundCaptureBuffer_Stop(p) (p)->lpVtbl->Stop(p) +#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->lpVtbl->Unlock(p,a,b,c,d) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundCaptureBuffer_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectSoundCaptureBuffer_AddRef(p) (p)->AddRef() +#define IDirectSoundCaptureBuffer_Release(p) (p)->Release() +#define IDirectSoundCaptureBuffer_GetCaps(p,a) (p)->GetCaps(a) +#define IDirectSoundCaptureBuffer_GetCurrentPosition(p,a,b) (p)->GetCurrentPosition(a,b) +#define IDirectSoundCaptureBuffer_GetFormat(p,a,b,c) (p)->GetFormat(a,b,c) +#define IDirectSoundCaptureBuffer_GetStatus(p,a) (p)->GetStatus(a) +#define IDirectSoundCaptureBuffer_Initialize(p,a,b) (p)->Initialize(a,b) +#define IDirectSoundCaptureBuffer_Lock(p,a,b,c,d,e,f,g) (p)->Lock(a,b,c,d,e,f,g) +#define IDirectSoundCaptureBuffer_Start(p,a) (p)->Start(a) +#define IDirectSoundCaptureBuffer_Stop(p) (p)->Stop() +#define IDirectSoundCaptureBuffer_Unlock(p,a,b,c,d) (p)->Unlock(a,b,c,d) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IDirectSoundNotify +// + +DEFINE_GUID(IID_IDirectSoundNotify, 0xb0210783, 0x89cd, 0x11d0, 0xaf, 0x8, 0x0, 0xa0, 0xc9, 0x25, 0xcd, 0x16); + +#undef INTERFACE +#define INTERFACE IDirectSoundNotify + +DECLARE_INTERFACE_(IDirectSoundNotify, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IDirectSoundNotify methods + STDMETHOD(SetNotificationPositions) (THIS_ DWORD, LPCDSBPOSITIONNOTIFY) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundNotify_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IDirectSoundNotify_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IDirectSoundNotify_Release(p) (p)->lpVtbl->Release(p) +#define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->lpVtbl->SetNotificationPositions(p,a,b) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IDirectSoundNotify_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IDirectSoundNotify_AddRef(p) (p)->AddRef() +#define IDirectSoundNotify_Release(p) (p)->Release() +#define IDirectSoundNotify_SetNotificationPositions(p,a,b) (p)->SetNotificationPositions(a,b) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +// +// IKsPropertySet +// + +#ifndef _IKsPropertySet_ +#define _IKsPropertySet_ + +#ifdef __cplusplus +// 'struct' not 'class' per the way DECLARE_INTERFACE_ is defined +struct IKsPropertySet; +#endif // __cplusplus + +typedef struct IKsPropertySet *LPKSPROPERTYSET; + +#define KSPROPERTY_SUPPORT_GET 0x00000001 +#define KSPROPERTY_SUPPORT_SET 0x00000002 + +DEFINE_GUID(IID_IKsPropertySet, 0x31efac30, 0x515c, 0x11d0, 0xa9, 0xaa, 0x00, 0xaa, 0x00, 0x61, 0xbe, 0x93); + +#undef INTERFACE +#define INTERFACE IKsPropertySet + +DECLARE_INTERFACE_(IKsPropertySet, IUnknown) +{ + // IUnknown methods + STDMETHOD(QueryInterface) (THIS_ REFIID, LPVOID *) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + + // IKsPropertySet methods + STDMETHOD(Get) (THIS_ REFGUID, ULONG, LPVOID, ULONG, LPVOID, ULONG, PULONG) PURE; + STDMETHOD(Set) (THIS_ REFGUID, ULONG, LPVOID, ULONG, LPVOID, ULONG) PURE; + STDMETHOD(QuerySupport) (THIS_ REFGUID, ULONG, PULONG) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IKsPropertySet_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IKsPropertySet_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IKsPropertySet_Release(p) (p)->lpVtbl->Release(p) +#define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->lpVtbl->Get(p,a,b,c,d,e,f,g) +#define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->lpVtbl->Set(p,a,b,c,d,e,f) +#define IKsPropertySet_QuerySupport(p,a,b,c) (p)->lpVtbl->QuerySupport(p,a,b,c) +#else // !defined(__cplusplus) || defined(CINTERFACE) +#define IKsPropertySet_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IKsPropertySet_AddRef(p) (p)->AddRef() +#define IKsPropertySet_Release(p) (p)->Release() +#define IKsPropertySet_Get(p,a,b,c,d,e,f,g) (p)->Get(a,b,c,d,e,f,g) +#define IKsPropertySet_Set(p,a,b,c,d,e,f) (p)->Set(a,b,c,d,e,f) +#define IKsPropertySet_QuerySupport(p,a,b,c) (p)->QuerySupport(a,b,c) +#endif // !defined(__cplusplus) || defined(CINTERFACE) + +#endif // _IKsPropertySet_ + +// +// Return Codes +// + +#define DS_OK 0 + +// The call failed because resources (such as a priority level) +// were already being used by another caller. +#define DSERR_ALLOCATED MAKE_DSHRESULT(10) + +// The control (vol,pan,etc.) requested by the caller is not available. +#define DSERR_CONTROLUNAVAIL MAKE_DSHRESULT(30) + +// An invalid parameter was passed to the returning function +#define DSERR_INVALIDPARAM E_INVALIDARG + +// This call is not valid for the current state of this object +#define DSERR_INVALIDCALL MAKE_DSHRESULT(50) + +// An undetermined error occured inside the DirectSound subsystem +#define DSERR_GENERIC E_FAIL + +// The caller does not have the priority level required for the function to +// succeed. +#define DSERR_PRIOLEVELNEEDED MAKE_DSHRESULT(70) + +// Not enough free memory is available to complete the operation +#define DSERR_OUTOFMEMORY E_OUTOFMEMORY + +// The specified WAVE format is not supported +#define DSERR_BADFORMAT MAKE_DSHRESULT(100) + +// The function called is not supported at this time +#define DSERR_UNSUPPORTED E_NOTIMPL + +// No sound driver is available for use +#define DSERR_NODRIVER MAKE_DSHRESULT(120) + +// This object is already initialized +#define DSERR_ALREADYINITIALIZED MAKE_DSHRESULT(130) + +// This object does not support aggregation +#define DSERR_NOAGGREGATION CLASS_E_NOAGGREGATION + +// The buffer memory has been lost, and must be restored. +#define DSERR_BUFFERLOST MAKE_DSHRESULT(150) + +// Another app has a higher priority level, preventing this call from +// succeeding. +#define DSERR_OTHERAPPHASPRIO MAKE_DSHRESULT(160) + +// This object has not been initialized +#define DSERR_UNINITIALIZED MAKE_DSHRESULT(170) + +// The requested COM interface is not available +#define DSERR_NOINTERFACE E_NOINTERFACE + +// +// Flags +// + +#define DSCAPS_PRIMARYMONO 0x00000001 +#define DSCAPS_PRIMARYSTEREO 0x00000002 +#define DSCAPS_PRIMARY8BIT 0x00000004 +#define DSCAPS_PRIMARY16BIT 0x00000008 +#define DSCAPS_CONTINUOUSRATE 0x00000010 +#define DSCAPS_EMULDRIVER 0x00000020 +#define DSCAPS_CERTIFIED 0x00000040 +#define DSCAPS_SECONDARYMONO 0x00000100 +#define DSCAPS_SECONDARYSTEREO 0x00000200 +#define DSCAPS_SECONDARY8BIT 0x00000400 +#define DSCAPS_SECONDARY16BIT 0x00000800 + +#define DSBPLAY_LOOPING 0x00000001 + +#define DSBSTATUS_PLAYING 0x00000001 +#define DSBSTATUS_BUFFERLOST 0x00000002 +#define DSBSTATUS_LOOPING 0x00000004 + +#define DSBLOCK_FROMWRITECURSOR 0x00000001 +#define DSBLOCK_ENTIREBUFFER 0x00000002 + +#define DSSCL_NORMAL 0x00000001 +#define DSSCL_PRIORITY 0x00000002 +#define DSSCL_EXCLUSIVE 0x00000003 +#define DSSCL_WRITEPRIMARY 0x00000004 + +#define DS3DMODE_NORMAL 0x00000000 +#define DS3DMODE_HEADRELATIVE 0x00000001 +#define DS3DMODE_DISABLE 0x00000002 + +#define DS3D_IMMEDIATE 0x00000000 +#define DS3D_DEFERRED 0x00000001 + +#define DS3D_MINDISTANCEFACTOR 0.0f +#define DS3D_MAXDISTANCEFACTOR 10.0f +#define DS3D_DEFAULTDISTANCEFACTOR 1.0f + +#define DS3D_MINROLLOFFFACTOR 0.0f +#define DS3D_MAXROLLOFFFACTOR 10.0f +#define DS3D_DEFAULTROLLOFFFACTOR 1.0f + +#define DS3D_MINDOPPLERFACTOR 0.0f +#define DS3D_MAXDOPPLERFACTOR 10.0f +#define DS3D_DEFAULTDOPPLERFACTOR 1.0f + +#define DS3D_DEFAULTMINDISTANCE 1.0f +#define DS3D_DEFAULTMAXDISTANCE 1000000000.0f + +#define DS3D_MINCONEANGLE 0 +#define DS3D_MAXCONEANGLE 360 +#define DS3D_DEFAULTCONEANGLE 360 + +#define DS3D_DEFAULTCONEOUTSIDEVOLUME 0 + +#define DSBCAPS_PRIMARYBUFFER 0x00000001 +#define DSBCAPS_STATIC 0x00000002 +#define DSBCAPS_LOCHARDWARE 0x00000004 +#define DSBCAPS_LOCSOFTWARE 0x00000008 +#define DSBCAPS_CTRL3D 0x00000010 +#define DSBCAPS_CTRLFREQUENCY 0x00000020 +#define DSBCAPS_CTRLPAN 0x00000040 +#define DSBCAPS_CTRLVOLUME 0x00000080 +#define DSBCAPS_CTRLPOSITIONNOTIFY 0x00000100 +#define DSBCAPS_CTRLDEFAULT 0x000000E0 +#define DSBCAPS_CTRLALL 0x000001F0 +#define DSBCAPS_STICKYFOCUS 0x00004000 +#define DSBCAPS_GLOBALFOCUS 0x00008000 +#define DSBCAPS_GETCURRENTPOSITION2 0x00010000 +#define DSBCAPS_MUTE3DATMAXDISTANCE 0x00020000 + +#define DSCBCAPS_WAVEMAPPED 0x80000000 + +#define DSSPEAKER_HEADPHONE 0x00000001 +#define DSSPEAKER_MONO 0x00000002 +#define DSSPEAKER_QUAD 0x00000003 +#define DSSPEAKER_STEREO 0x00000004 +#define DSSPEAKER_SURROUND 0x00000005 + +#define DSSPEAKER_GEOMETRY_MIN 0x00000005 // 5 degrees +#define DSSPEAKER_GEOMETRY_NARROW 0x0000000A // 10 degrees +#define DSSPEAKER_GEOMETRY_WIDE 0x00000014 // 20 degrees +#define DSSPEAKER_GEOMETRY_MAX 0x000000B4 // 180 degrees + +#define DSSPEAKER_COMBINED(c, g) ((DWORD)(((BYTE)(c)) | ((DWORD)((BYTE)(g))) << 16)) +#define DSSPEAKER_CONFIG(a) ((BYTE)(a)) +#define DSSPEAKER_GEOMETRY(a) ((BYTE)(((DWORD)(a) >> 16) & 0x00FF)) + +#define DSCCAPS_EMULDRIVER 0x00000020 + +#define DSCBLOCK_ENTIREBUFFER 0x00000001 + +#define DSCBSTATUS_CAPTURING 0x00000001 +#define DSCBSTATUS_LOOPING 0x00000002 + +#define DSCBSTART_LOOPING 0x00000001 + +#define DSBFREQUENCY_MIN 100 +#define DSBFREQUENCY_MAX 100000 +#define DSBFREQUENCY_ORIGINAL 0 + +#define DSBPAN_LEFT -10000 +#define DSBPAN_CENTER 0 +#define DSBPAN_RIGHT 10000 + +#define DSBVOLUME_MIN -10000 +#define DSBVOLUME_MAX 0 + +#define DSBSIZE_MIN 4 +#define DSBSIZE_MAX 0x0FFFFFFF + +#define DSBPN_OFFSETSTOP 0xFFFFFFFF + +#ifdef __cplusplus +}; +#endif // __cplusplus + +#endif // __DSOUND_INCLUDED__ diff --git a/3rdparty/dx5/inc/dvp.h b/3rdparty/dx5/inc/dvp.h new file mode 100644 index 00000000..9554de55 --- /dev/null +++ b/3rdparty/dx5/inc/dvp.h @@ -0,0 +1,831 @@ +/*==========================================================================; + * + * Copyright (C) 1996-1997 Microsoft Corporation. All Rights Reserved. + * + * File: dvp.h + * Content: DirectDrawVideoPort include file + * + ***************************************************************************/ + +#ifndef __DVP_INCLUDED__ +#define __DVP_INCLUDED__ +#if defined( _WIN32 ) && !defined( _NO_COM ) +#define COM_NO_WINDOWS_H +#include +#else +#define IUnknown void +#undef CO_E_NOTINITIALIZED +#define CO_E_NOTINITIALIZED 0x800401F0L +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * GUIDS used by DirectDrawVideoPort objects + */ +#if defined( _WIN32 ) && !defined( _NO_COM ) +DEFINE_GUID( IID_IDDVideoPortContainer, 0x6C142760,0xA733,0x11CE,0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60 ); +DEFINE_GUID( IID_IDirectDrawVideoPort, 0xB36D93E0,0x2B43,0x11CF,0xA2,0xDE,0x00,0xAA,0x00,0xB9,0x33,0x56 ); + +DEFINE_GUID( DDVPTYPE_E_HREFH_VREFH, 0x54F39980L,0xDA60,0x11CF,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8); +DEFINE_GUID( DDVPTYPE_E_HREFH_VREFL, 0x92783220L,0xDA60,0x11CF,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8); +DEFINE_GUID( DDVPTYPE_E_HREFL_VREFH, 0xA07A02E0L,0xDA60,0x11CF,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8); +DEFINE_GUID( DDVPTYPE_E_HREFL_VREFL, 0xE09C77E0L,0xDA60,0x11CF,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8); +DEFINE_GUID( DDVPTYPE_CCIR656, 0xFCA326A0L,0xDA60,0x11CF,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8); +DEFINE_GUID( DDVPTYPE_BROOKTREE, 0x1352A560L,0xDA61,0x11CF,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8); +DEFINE_GUID( DDVPTYPE_PHILIPS, 0x332CF160L,0xDA61,0x11CF,0x9B,0x06,0x00,0xA0,0xC9,0x03,0xA3,0xB8); + +/* + * GUIDS used to describe connections + */ + +#endif + +/*============================================================================ + * + * DirectDraw Structures + * + * Various structures used to invoke DirectDraw. + * + *==========================================================================*/ + +struct IDirectDraw; +struct IDirectDrawSurface; +struct IDirectDrawPalette; +struct IDirectDrawClipper; + +typedef struct IDDVideoPortContainer FAR *LPDDVIDEOPORTCONTAINER; +typedef struct IDirectDrawVideoPort FAR *LPDIRECTDRAWVIDEOPORT; + +typedef struct _DDVIDEOPORTCONNECT FAR *LPDDVIDEOPORTCONNECT; +typedef struct _DDVIDEOPORTCAPS FAR *LPDDVIDEOPORTCAPS; +typedef struct _DDVIDEOPORTDESC FAR *LPDDVIDEOPORTDESC; +typedef struct _DDVIDEOPORTINFO FAR *LPDDVIDEOPORTINFO; +typedef struct _DDVIDEOPORTBANDWIDTH FAR *LPDDVIDEOPORTBANDWIDTH; +typedef struct _DDVIDEOPORTSTATUS FAR *LPDDVIDEOPORTSTATUS; + +typedef struct IDDVideoPortContainerVtbl DDVIDEOPORTCONTAINERCALLBACKS; +typedef struct IDirectDrawVideoPortVtbl DIRECTDRAWVIDEOPORTCALLBACKS; + + +/* + * API's + */ +typedef HRESULT (FAR PASCAL * LPDDENUMVIDEOCALLBACK)(LPDDVIDEOPORTCAPS, LPVOID); + + +/* + * INTERACES FOLLOW: + * IDirectDrawVideoPort + * IVideoPort + */ + +/* + * IDirectDrawVideoPortContainer + */ +#if defined( _WIN32 ) && !defined( _NO_COM ) +#undef INTERFACE +#define INTERFACE IDDVideoPortContainer +DECLARE_INTERFACE_( IDDVideoPortContainer, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IDirectDrawVideoPort methods ***/ + STDMETHOD(CreateVideoPort)(THIS_ DWORD, LPDDVIDEOPORTDESC, LPDIRECTDRAWVIDEOPORT FAR *, IUnknown FAR *) PURE; + STDMETHOD(EnumVideoPorts)(THIS_ DWORD, LPDDVIDEOPORTCAPS, LPVOID,LPDDENUMVIDEOCALLBACK ) PURE; + STDMETHOD(GetVideoPortConnectInfo)(THIS_ DWORD, LPDWORD, LPDDVIDEOPORTCONNECT ) PURE; + STDMETHOD(QueryVideoPortStatus)(THIS_ DWORD, LPDDVIDEOPORTSTATUS ) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IVideoPortContainer_QueryInterface(p, a, b) (p)->lpVtbl->QueryInterface(p, a, b) +#define IVideoPortContainer_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IVideoPortContainer_Release(p) (p)->lpVtbl->Release(p) +#define IVideoPortContainer_CreateVideoPort(p, a, b, c, d) (p)->lpVtbl->CreateVideoPort(p, a, b, c, d) +#define IVideoPortContainer_EnumVideoPorts(p, a, b, c, d) (p)->lpVtbl->EnumVideoPorts(p, a, b, c, d) +#define IVideoPortContainer_GetVideoPortConnectInfo(p, a, b, c) (p)->lpVtbl->GetVideoPortConnectInfo(p, a, b, c) +#define IVideoPortContainer_QueryVideoPortStatus(p, a, b) (p)->lpVtbl->QueryVideoPortStatus(p, a, b) +#else +#define IVideoPortContainer_QueryInterface(p, a, b) (p)->QueryInterface(a, b) +#define IVideoPortContainer_AddRef(p) (p)->AddRef() +#define IVideoPortContainer_Release(p) (p)->Release() +#define IVideoPortContainer_CreateVideoPort(p, a, b, c, d) (p)->CreateVideoPort(a, b, c, d) +#define IVideoPortContainer_EnumVideoPorts(p, a, b, c, d) (p)->EnumVideoPorts(a, b, c, d) +#define IVideoPortContainer_GetVideoPortConnectInfo(p, a, b, c) (p)->GetVideoPortConnectInfo(a, b, c) +#define IVideoPortContainer_QueryVideoPortStatus(p, a, b) (p)->QueryVideoPortStatus(a, b) +#endif + +#endif + + +/* + * IDirectDrawVideoPort + */ +#if defined( _WIN32 ) && !defined( _NO_COM ) +#undef INTERFACE +#define INTERFACE IDirectDrawVideoPort +DECLARE_INTERFACE_( IDirectDrawVideoPort, IUnknown ) +{ + /*** IUnknown methods ***/ + STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID FAR * ppvObj) PURE; + STDMETHOD_(ULONG,AddRef) (THIS) PURE; + STDMETHOD_(ULONG,Release) (THIS) PURE; + /*** IVideoPort methods ***/ + STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE, DWORD) PURE; + STDMETHOD(GetBandwidthInfo)(THIS_ LPDDPIXELFORMAT, DWORD, DWORD, DWORD, LPDDVIDEOPORTBANDWIDTH) PURE; + STDMETHOD(GetColorControls)(THIS_ LPDDCOLORCONTROL) PURE; + STDMETHOD(GetInputFormats)(THIS_ LPDWORD, LPDDPIXELFORMAT, DWORD) PURE; + STDMETHOD(GetOutputFormats)(THIS_ LPDDPIXELFORMAT, LPDWORD, LPDDPIXELFORMAT, DWORD) PURE; + STDMETHOD(GetFieldPolarity)(THIS_ LPBOOL) PURE; + STDMETHOD(GetVideoLine)(THIS_ LPDWORD) PURE; + STDMETHOD(GetVideoSignalStatus)(THIS_ LPDWORD) PURE; + STDMETHOD(SetColorControls)(THIS_ LPDDCOLORCONTROL) PURE; + STDMETHOD(SetTargetSurface)(THIS_ LPDIRECTDRAWSURFACE, DWORD) PURE; + STDMETHOD(StartVideo)(THIS_ LPDDVIDEOPORTINFO) PURE; + STDMETHOD(StopVideo)(THIS) PURE; + STDMETHOD(UpdateVideo)(THIS_ LPDDVIDEOPORTINFO) PURE; + STDMETHOD(WaitForSync)(THIS_ DWORD, DWORD, DWORD) PURE; +}; + +#if !defined(__cplusplus) || defined(CINTERFACE) +#define IVideoPort_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IVideoPort_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IVideoPort_Release(p) (p)->lpVtbl->Release(p) +#define IVideoPort_SetTargetSurface(p,a,b) (p)->lpVtbl->SetTargetSurface(p,a,b) +#define IVideoPort_Flip(p,a,b) (p)->lpVtbl->Flip(p,a,b) +#define IVideoPort_GetBandwidthInfo(p,a,b,c,d,e) (p)->lpVtbl->GetBandwidthInfo(p,a,b,c,d,e) +#define IVideoPort_GetColorControls(p,a) (p)->lpVtbl->GetColorControls(p,a) +#define IVideoPort_GetInputFormats(p,a,b,c) (p)->lpVtbl->GetInputFormats(p,a,b,c) +#define IVideoPort_GetOutputFormats(p,a,b,c,d) (p)->lpVtbl->GetOutputFormats(p,a,b,c,d) +#define IVideoPort_GetFieldPolarity(p,a) (p)->lpVtbl->GetFieldPolarity(p,a) +#define IVideoPort_GetVideoLine(p,a) (p)->lpVtbl->GetVideoLine(p,a) +#define IVideoPort_GetVideoSignalStatus(p,a) (p)->lpVtbl->GetVideoSignalStatus(p,a) +#define IVideoPort_SetColorControls(p,a) (p)->lpVtbl->SetColorControls(p,a) +#define IVideoPort_StartVideo(p,a) (p)->lpVtbl->StartVideo(p,a) +#define IVideoPort_StopVideo(p) (p)->lpVtbl->StopVideo(p) +#define IVideoPort_UpdateVideo(p,a) (p)->lpVtbl->UpdateVideo(p,a) +#define IVideoPort_WaitForSync(p,a,b,c) (p)->lpVtbl->WaitForSync(p,a,b,c) +#else +#define IVideoPort_QueryInterface(p,a,b) (p)->QueryInterface(a,b) +#define IVideoPort_AddRef(p) (p)->AddRef() +#define IVideoPort_Release(p) (p)->Release() +#define IVideoPort_SetTargetSurface(p,a,b) (p)->SetTargetSurface(a,b) +#define IVideoPort_Flip(p,a,b) (p)->Flip(a,b) +#define IVideoPort_GetBandwidthInfo(p,a,b,c,d,e) (p)->GetBandwidthInfo(a,b,c,d,e) +#define IVideoPort_GetColorControls(p,a) (p)->GetColorControls(a) +#define IVideoPort_GetInputFormats(p,a,b,c) (p)->GetInputFormats(a,b,c) +#define IVideoPort_GetOutputFormats(p,a,b,c,d) (p)->GetOutputFormats(a,b,c,d) +#define IVideoPort_GetFieldPolarity(p,a) (p)->GetFieldPolarity(a) +#define IVideoPort_GetVideoLine(p,a) (p)->GetVideoLine(a) +#define IVideoPort_GetVideoSignalStatus(p,a) (p)->GetVideoSignalStatus(a) +#define IVideoPort_SetColorControls(p,a) (p)->SetColorControls(a) +#define IVideoPort_StartVideo(p,a) (p)->StartVideo(a) +#define IVideoPort_StopVideo(p) (p)->StopVideo() +#define IVideoPort_UpdateVideo(p,a) (p)->UpdateVideo(a) +#define IVideoPort_WaitForSync(p,a,b,c) (p)->WaitForSync(a,b,c) +#endif + +#endif + + +/* + * DDVIDEOPORTCONNECT + */ +typedef struct _DDVIDEOPORTCONNECT +{ + DWORD dwSize; // size of the DDVIDEOPORTCONNECT structure + DWORD dwPortWidth; // Width of the video port + GUID guidTypeID; // Description of video port connection + DWORD dwFlags; // Connection flags + DWORD dwReserved1; // Reserved, set to zero. +} DDVIDEOPORTCONNECT; + + +/* + * DDVIDEOPORTCAPS + */ +typedef struct _DDVIDEOPORTCAPS +{ + DWORD dwSize; // size of the DDVIDEOPORTCAPS structure + DWORD dwFlags; // indicates which fields contain data + DWORD dwMaxWidth; // max width of the video port field + DWORD dwMaxVBIWidth; // max width of the VBI data + DWORD dwMaxHeight; // max height of the video port field + DWORD dwVideoPortID; // Video port ID (0 - (dwMaxVideoPorts -1)) + DWORD dwCaps; // Video port capabilities + DWORD dwFX; // More video port capabilities + DWORD dwNumAutoFlipSurfaces; // Number of autoflippable surfaces + DWORD dwAlignVideoPortBoundary; // Byte restriction of placement within the surface + DWORD dwAlignVideoPortPrescaleWidth;// Byte restriction of width after prescaling + DWORD dwAlignVideoPortCropBoundary; // Byte restriction of left cropping + DWORD dwAlignVideoPortCropWidth; // Byte restriction of cropping width + DWORD dwPreshrinkXStep; // Width can be shrunk in steps of 1/x + DWORD dwPreshrinkYStep; // Height can be shrunk in steps of 1/x + DWORD dwNumVBIAutoFlipSurfaces; // Number of VBI autoflippable surfaces + DWORD dwReserved1; // Reserved for future use + DWORD dwReserved2; // Reserved for future use +} DDVIDEOPORTCAPS; + +/* + * The dwMaxWidth and dwMaxVBIWidth members are valid + */ +#define DDVPD_WIDTH 0x00000001l + +/* + * The dwMaxHeight member is valid + */ +#define DDVPD_HEIGHT 0x00000002l + +/* + * The dwVideoPortID member is valid + */ +#define DDVPD_ID 0x00000004l + +/* + * The dwCaps member is valid + */ +#define DDVPD_CAPS 0x00000008l + +/* + * The dwFX member is valid + */ +#define DDVPD_FX 0x00000010l + +/* + * The dwNumAutoFlipSurfaces member is valid + */ +#define DDVPD_AUTOFLIP 0x00000020l + +/* + * All of the alignment members are valid + */ +#define DDVPD_ALIGN 0x00000040l + + +/* + * DDVIDEOPORTDESC + */ +typedef struct _DDVIDEOPORTDESC +{ + DWORD dwSize; // size of the DDVIDEOPORTDESC structure + DWORD dwFieldWidth; // width of the video port field + DWORD dwVBIWidth; // width of the VBI data + DWORD dwFieldHeight; // height of the video port field + DWORD dwMicrosecondsPerField; // Microseconds per video field + DWORD dwMaxPixelsPerSecond; // Maximum pixel rate per second + DWORD dwVideoPortID; // Video port ID (0 - (dwMaxVideoPorts -1)) + DWORD dwReserved1; // Reserved for future use - set to zero + DDVIDEOPORTCONNECT VideoPortType; // Description of video port connection + DWORD dwReserved2; // Reserved for future use - set to zero + DWORD dwReserved3; // Reserved for future use - set to zero +} DDVIDEOPORTDESC; + + +/* + * DDVIDEOPORTINFO + */ +typedef struct _DDVIDEOPORTINFO +{ + DWORD dwSize; // Size of the structure + DWORD dwOriginX; // Placement of the video data within the surface. + DWORD dwOriginY; // Placement of the video data within the surface. + DWORD dwVPFlags; // Video port options + RECT rCrop; // Cropping rectangle (optional). + DWORD dwPrescaleWidth; // Determines pre-scaling/zooming in the X direction (optional). + DWORD dwPrescaleHeight; // Determines pre-scaling/zooming in the Y direction (optional). + LPDDPIXELFORMAT lpddpfInputFormat; // Video format written to the video port + LPDDPIXELFORMAT lpddpfVBIInputFormat; // Input format of the VBI data + LPDDPIXELFORMAT lpddpfVBIOutputFormat;// Output format of the data + DWORD dwVBIHeight; // Specifies the number of lines of data within the vertical blanking interval. + DWORD dwReserved1; // Reserved for future use - set to zero + DWORD dwReserved2; // Reserved for future use - set to zero +} DDVIDEOPORTINFO; + + +/* + * DDVIDEOPORTBANDWIDTH + */ +typedef struct _DDVIDEOPORTBANDWIDTH +{ + DWORD dwSize; // Size of the structure + DWORD dwCaps; + DWORD dwOverlay; // Zoom factor at which overlay is supported + DWORD dwColorkey; // Zoom factor at which overlay w/ colorkey is supported + DWORD dwYInterpolate; // Zoom factor at which overlay w/ Y interpolation is supported + DWORD dwYInterpAndColorkey; // Zoom factor at which ovelray w/ Y interpolation and colorkeying is supported + DWORD dwReserved1; // Reserved for future use - set to zero + DWORD dwReserved2; // Reserved for future use - set to zero +} DDVIDEOPORTBANDWIDTH; + + +/* + * DDVIDEOPORTSTATUS + */ +typedef struct _DDVIDEOPORTSTATUS +{ + DWORD dwSize; // Size of the structure + BOOL bInUse; // TRUE if video port is currently being used + DWORD dwFlags; // Currently not used + DWORD dwReserved1; // Reserved for future use + DDVIDEOPORTCONNECT VideoPortType; // Information about the connection + DWORD dwReserved2; // Reserved for future use + DWORD dwReserved3; // Reserved for future use +} DDVIDEOPORTSTATUS; + +/*============================================================================ + * + * Video Port Flags + * + * All flags are bit flags. + * + *==========================================================================*/ + +/**************************************************************************** + * + * VIDEOPORT DDVIDEOPORTCONNECT FLAGS + * + ****************************************************************************/ + +/* + * When this is set by the driver and passed to the client, this + * indicates that the video port is capable of double clocking the data. + * When this is set by the client, this indicates that the video port + * should enable double clocking. This flag is only valid with external + * syncs. + */ +#define DDVPCONNECT_DOUBLECLOCK 0x00000001l + +/* + * When this is set by the driver and passed to the client, this + * indicates that the video port is capable of using an external VACT + * signal. When this is set by the client, this indicates that the + * video port should use the external VACT signal. + */ +#define DDVPCONNECT_VACT 0x00000002l + +/* + * When this is set by the driver and passed to the client, this + * indicates that the video port is capable of treating even fields + * like odd fields and visa versa. When this is set by the client, + * this indicates that the video port should treat even fields like odd + * fields. + */ +#define DDVPCONNECT_INVERTPOLARITY 0x00000004l + +/* + * Indicates that any data written to the video port during the VREF + * period will not be written into the frame buffer. This flag is read only. + */ +#define DDVPCONNECT_DISCARDSVREFDATA 0x00000008l + +/* + * Device will write half lines into the frame buffer, sometimes causing + * the data to not be displayed correctly. + */ +#define DDVPCONNECT_HALFLINE 0x00000010l + +/* + * Indicates that the signal is interlaced. This flag is only + * set by the client. + */ +#define DDVPCONNECT_INTERLACED 0x00000020l + +/* + * Indicates that video port is shareable and that this video port + * will use the even fields. This flag is only set by the client. + */ +#define DDVPCONNECT_SHAREEVEN 0x00000040l + +/* + * Indicates that video port is shareable and that this video port + * will use the odd fields. This flag is only set by the client. + */ +#define DDVPCONNECT_SHAREODD 0x00000080l + +/**************************************************************************** + * + * VIDEOPORT DDVIDEOPORTDESC CAPS + * + ****************************************************************************/ + +/* + * Flip can be performed automatically to avoid tearing. + */ +#define DDVPCAPS_AUTOFLIP 0x00000001l + +/* + * Supports interlaced video + */ +#define DDVPCAPS_INTERLACED 0x00000002l + +/* + * Supports non-interlaced video + */ +#define DDVPCAPS_NONINTERLACED 0x00000004l + +/* + * Indicates that the device can return whether the current field + * of an interlaced signal is even or odd. + */ +#define DDVPCAPS_READBACKFIELD 0x00000008l + +/* + * Indicates that the device can return the current line of video + * being written into the frame buffer. + */ +#define DDVPCAPS_READBACKLINE 0x00000010l + +/* + * Allows two gen-locked video streams to share a single video port, + * where one stream uses the even fields and the other uses the odd + * fields. Separate parameters (including address, scaling, + * cropping, etc.) are maintained for both fields.) + */ +#define DDVPCAPS_SHAREABLE 0x00000020l + +/* + * Even fields of video can be automatically discarded. + */ +#define DDVPCAPS_SKIPEVENFIELDS 0x00000040l + +/* + * Odd fields of video can be automatically discarded. + */ +#define DDVPCAPS_SKIPODDFIELDS 0x00000080l + +/* + * Indicates that the device is capable of driving the graphics + * VSYNC with the video port VSYNC. + */ +#define DDVPCAPS_SYNCMASTER 0x00000100l + +/* + * Indicates that data within the vertical blanking interval can + * be written to a different surface. + */ +#define DDVPCAPS_VBISURFACE 0x00000200l + +/* + * Indicates that the video port can perform color operations + * on the incoming data before it is written to the frame buffer. + */ +#define DDVPCAPS_COLORCONTROL 0x00000400l + +/* + * Indicates that the video port can accept VBI data in a different + * width or format than the regular video data. + */ +#define DDVPCAPS_OVERSAMPLEDVBI 0x00000800l + +/* + * Indicates that the video port can write data directly to system memory + */ +#define DDVPCAPS_SYSTEMMEMORY 0x00001000l + + +/**************************************************************************** + * + * VIDEOPORT DDVIDEOPORTDESC FX + * + ****************************************************************************/ + +/* + * Limited cropping is available to crop out the vertical interval data. + */ +#define DDVPFX_CROPTOPDATA 0x00000001l + +/* + * Incoming data can be cropped in the X direction before it is written + * to the surface. + */ +#define DDVPFX_CROPX 0x00000002l + +/* + * Incoming data can be cropped in the Y direction before it is written + * to the surface. + */ +#define DDVPFX_CROPY 0x00000004l + +/* + * Supports interleaving interlaced fields in memory. + */ +#define DDVPFX_INTERLEAVE 0x00000008l + +/* + * Supports mirroring left to right as the video data is written + * into the frame buffer. + */ +#define DDVPFX_MIRRORLEFTRIGHT 0x00000010l + +/* + * Supports mirroring top to bottom as the video data is written + * into the frame buffer. + */ +#define DDVPFX_MIRRORUPDOWN 0x00000020l + +/* + * Data can be arbitrarily shrunk in the X direction before it + * is written to the surface. + */ +#define DDVPFX_PRESHRINKX 0x00000040l + +/* + * Data can be arbitrarily shrunk in the Y direction before it + * is written to the surface. + */ +#define DDVPFX_PRESHRINKY 0x00000080l + +/* + * Data can be binary shrunk (1/2, 1/4, 1/8, etc.) in the X + * direction before it is written to the surface. + */ +#define DDVPFX_PRESHRINKXB 0x00000100l + +/* + * Data can be binary shrunk (1/2, 1/4, 1/8, etc.) in the Y + * direction before it is written to the surface. + */ +#define DDVPFX_PRESHRINKYB 0x00000200l + +/* + * Data can be shrunk in increments of 1/x in the X direction + * (where X is specified in the DDVIDEOPORTCAPS.dwPreshrinkXStep) + * before it is written to the surface. + */ +#define DDVPFX_PRESHRINKXS 0x00000400l + +/* + * Data can be shrunk in increments of 1/x in the Y direction + * (where X is specified in the DDVIDEOPORTCAPS.dwPreshrinkYStep) + * before it is written to the surface. + */ +#define DDVPFX_PRESHRINKYS 0x00000800l + +/* + * Data can be arbitrarily stretched in the X direction before + * it is written to the surface. + */ +#define DDVPFX_PRESTRETCHX 0x00001000l + +/* + * Data can be arbitrarily stretched in the Y direction before + * it is written to the surface. + */ +#define DDVPFX_PRESTRETCHY 0x00002000l + +/* + * Data can be integer stretched in the X direction before it is + * written to the surface. + */ +#define DDVPFX_PRESTRETCHXN 0x00004000l + +/* + * Data can be integer stretched in the Y direction before it is + * written to the surface. + */ +#define DDVPFX_PRESTRETCHYN 0x00008000l + +/* + * Indicates that data within the vertical blanking interval can + * be converted independently of the remaining video data. + */ +#define DDVPFX_VBICONVERT 0x00010000l + +/* + * Indicates that scaling can be disabled for data within the + * vertical blanking interval. + */ +#define DDVPFX_VBINOSCALE 0x00020000l + +/* + * Indicates that the video data can ignore the left and right + * cropping coordinates when cropping oversampled VBI data. + */ +#define DDVPFX_IGNOREVBIXCROP 0x00040000l + + +/**************************************************************************** + * + * VIDEOPORT DDVIDEOPORTINFO FLAGS + * + ****************************************************************************/ + +/* + * Perform automatic flipping. Auto-flipping is performed between + * the overlay surface that was attached to the video port using + * IDirectDrawVideoPort::AttachSurface and the overlay surfaces that + * are attached to the surface via the IDirectDrawSurface::AttachSurface + * method. The flip order is the order in which the overlay surfaces + * were. attached. + */ +#define DDVP_AUTOFLIP 0x00000001l + +/* + * Perform conversion using the ddpfOutputFormat information. + */ +#define DDVP_CONVERT 0x00000002l + +/* + * Perform cropping using the specified rectangle. + */ +#define DDVP_CROP 0x00000004l + +/* + * Indicates that interlaced fields should be interleaved in memory. + */ +#define DDVP_INTERLEAVE 0x00000008l + +/* + * Indicates that the data should be mirrored left to right as it's + * written into the frame buffer. + */ +#define DDVP_MIRRORLEFTRIGHT 0x00000010l + +/* + * Indicates that the data should be mirrored top to bottom as it's + * written into the frame buffer. + */ +#define DDVP_MIRRORUPDOWN 0x00000020l + +/* + * Perform pre-scaling/zooming based on the pre-scale parameters. + */ +#define DDVP_PRESCALE 0x00000040l + +/* + * Ignore input of even fields. + */ +#define DDVP_SKIPEVENFIELDS 0x00000080l + +/* + * Ignore input of odd fields. + */ +#define DDVP_SKIPODDFIELDS 0x00000100l + +/* + * Drive the graphics VSYNCs using the video port VYSNCs. + */ +#define DDVP_SYNCMASTER 0x00000200l + +/* + * The ddpfVBIOutputFormatFormat member contains data that should be used + * to convert the data within the vertical blanking interval. + */ +#define DDVP_VBICONVERT 0x00000400l + +/* + * Indicates that data within the vertical blanking interval + * should not be scaled. + */ +#define DDVP_VBINOSCALE 0x00000800l + +/* + * Indicates that these bob/weave decisions should not be + * overriden by other interfaces. + */ +#define DDVP_OVERRIDEBOBWEAVE 0x00001000l + +/* + * Indicates that the video data should ignore the left and right + * cropping coordinates when cropping the VBI data. + */ +#define DDVP_IGNOREVBIXCROP 0x00002000l + + +/**************************************************************************** + * + * DIRIRECTDRAWVIDEOPORT GETINPUTFORMAT/GETOUTPUTFORMAT FLAGS + * + ****************************************************************************/ + +/* + * Return formats for the video data + */ +#define DDVPFORMAT_VIDEO 0x00000001l + +/* + * Return formats for the VBI data + */ +#define DDVPFORMAT_VBI 0x00000002l + + +/**************************************************************************** + * + * DIRIRECTDRAWVIDEOPORT SETTARGETSURFACE FLAGS + * + ****************************************************************************/ + +/* + * Surface should receive video data (and VBI data if a surface + * is not explicitly attached for that purpose) + */ +#define DDVPTARGET_VIDEO 0x00000001l + +/* + * Surface should receive VBI data + */ +#define DDVPTARGET_VBI 0x00000002l + + +/**************************************************************************** + * + * DIRIRECTDRAWVIDEOPORT WAITFORSYNC FLAGS + * + ****************************************************************************/ + +/* + * Waits until the beginning of the next VSYNC + */ +#define DDVPWAIT_BEGIN 0x00000001l + +/* + * Waits until the end of the next/current VSYNC + */ +#define DDVPWAIT_END 0x00000002l + +/* + * Waits until the beginning of the specified line + */ +#define DDVPWAIT_LINE 0x00000003l + +/**************************************************************************** + * + * DIRECTDRAWVIDEOPORT FLIP FLAGS + * + ****************************************************************************/ + +/* + * Flips the normal video surface + */ +#define DDVPFLIP_VIDEO 0x00000001l + +/* + * Flips the VBI surface + */ +#define DDVPFLIP_VBI 0x00000002l + +/**************************************************************************** + * + * DIRIRECTDRAWVIDEOPORT GETVIDEOSIGNALSTATUS VALUES + * + ****************************************************************************/ + +/* + * No video signal is present at the video port + */ +#define DDVPSQ_NOSIGNAL 0x00000001l + +/* + * A valid video signal is present at the video port + */ +#define DDVPSQ_SIGNALOK 0x00000002l + +/**************************************************************************** + * + * VIDEOPORTBANDWIDTH Flags + * + ****************************************************************************/ + +/* + * The specified height/width refer to the size of the video port data + * written into memory, after prescaling has occured. + */ +#define DDVPB_VIDEOPORT 0x00000001l + +/* + * The specified height/width refer to the source size of the overlay. + */ +#define DDVPB_OVERLAY 0x00000002l + +/* + * This is a query for the device to return which caps this device requires. + */ +#define DDVPB_TYPE 0x00000004l + +/**************************************************************************** + * + * VIDEOPORTBANDWIDTH Caps + * + ****************************************************************************/ + +/* + * The bandwidth for this device is dependant on the overlay source size. + */ +#define DDVPBCAPS_SOURCE 0x00000001l + +/* + * The bandwidth for this device is dependant on the overlay destination + * size. + */ +#define DDVPBCAPS_DESTINATION 0x00000002l + + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/3rdparty/dx5/inc/fastfile.h b/3rdparty/dx5/inc/fastfile.h new file mode 100644 index 00000000..92b37b16 --- /dev/null +++ b/3rdparty/dx5/inc/fastfile.h @@ -0,0 +1,24 @@ +/*========================================================================== + * + * Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved. + * + * File: fastfile.h + * Content: Definitions for fastfile access. + * + * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, + * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED + * WARRANTIES OF MERCHANTBILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + * + ***************************************************************************/ + +typedef LPVOID HFASTFILE; + +extern BOOL FastFileInit( LPSTR fname, int max_handles ); +extern void FastFileFini( void ); +extern HFASTFILE FastFileOpen( LPSTR name ); +extern BOOL FastFileClose( HFASTFILE pfe ); +extern BOOL FastFileRead( HFASTFILE pfh, LPVOID ptr, int size ); +extern BOOL FastFileSeek( HFASTFILE pfe, int off, int how ); +extern long FastFileTell( HFASTFILE pfe ); +extern LPVOID FastFileLock( HFASTFILE pfe, int off, int len ); +extern BOOL FastFileUnlock( HFASTFILE pfe, int off, int len ); diff --git a/3rdparty/dx5/lib/d3drm.lib b/3rdparty/dx5/lib/d3drm.lib new file mode 100644 index 00000000..03af2525 Binary files /dev/null and b/3rdparty/dx5/lib/d3drm.lib differ diff --git a/3rdparty/dx5/lib/ddraw.lbw b/3rdparty/dx5/lib/ddraw.lbw new file mode 100644 index 00000000..21a3eddf Binary files /dev/null and b/3rdparty/dx5/lib/ddraw.lbw differ diff --git a/3rdparty/dx5/lib/ddraw.lib b/3rdparty/dx5/lib/ddraw.lib new file mode 100644 index 00000000..d46efa22 Binary files /dev/null and b/3rdparty/dx5/lib/ddraw.lib differ diff --git a/3rdparty/dx5/lib/dinput.lib b/3rdparty/dx5/lib/dinput.lib new file mode 100644 index 00000000..d105311a Binary files /dev/null and b/3rdparty/dx5/lib/dinput.lib differ diff --git a/3rdparty/dx5/lib/dplayx.lib b/3rdparty/dx5/lib/dplayx.lib new file mode 100644 index 00000000..21a5f06a Binary files /dev/null and b/3rdparty/dx5/lib/dplayx.lib differ diff --git a/3rdparty/dx5/lib/dsetup.lib b/3rdparty/dx5/lib/dsetup.lib new file mode 100644 index 00000000..07305452 Binary files /dev/null and b/3rdparty/dx5/lib/dsetup.lib differ diff --git a/3rdparty/dx5/lib/dsound.lbw b/3rdparty/dx5/lib/dsound.lbw new file mode 100644 index 00000000..2f8071f2 Binary files /dev/null and b/3rdparty/dx5/lib/dsound.lbw differ diff --git a/3rdparty/dx5/lib/dsound.lib b/3rdparty/dx5/lib/dsound.lib new file mode 100644 index 00000000..fb4d5598 Binary files /dev/null and b/3rdparty/dx5/lib/dsound.lib differ diff --git a/3rdparty/dx5/lib/dxguid.lib b/3rdparty/dx5/lib/dxguid.lib new file mode 100644 index 00000000..0a314063 Binary files /dev/null and b/3rdparty/dx5/lib/dxguid.lib differ diff --git a/3rdparty/dx5/lib/fastfile.lbw b/3rdparty/dx5/lib/fastfile.lbw new file mode 100644 index 00000000..467ebf88 Binary files /dev/null and b/3rdparty/dx5/lib/fastfile.lbw differ diff --git a/3rdparty/dx5/lib/fastfile.lib b/3rdparty/dx5/lib/fastfile.lib new file mode 100644 index 00000000..8587c24d Binary files /dev/null and b/3rdparty/dx5/lib/fastfile.lib differ diff --git a/3rdparty/smacker/rad.h b/3rdparty/smacker/rad.h new file mode 100644 index 00000000..610bd794 --- /dev/null +++ b/3rdparty/smacker/rad.h @@ -0,0 +1,401 @@ +#ifndef __RAD__ +#define __RAD__ + +#define RADCOPYRIGHT "Copyright (c) RAD Software, 1994-95." + + +// __RADDOS__ means DOS code (16 or 32 bit) +// __RAD16__ means 16 bit code (Win16) +// __RAD32__ means 32 bit code (DOS, Win386, Win32s, Mac) +// __RADWIN__ means Windows code (Win16, Win386, Win32s) +// __RADWINEXT__ means Windows 386 extender (Win386) +// __RADNT__ means Win32s code +// __RADMAC__ means Macintosh +// __RAD68K__ means 68K Macintosh +// __RADPPC__ means PowerMac + + +#if defined(__MWERKS__) || defined(THINK_C) || defined(powerc) || defined(macintosh) || defined(__powerc) + + #define __RADMAC__ + #if defined(powerc) || defined(__powerc) + #define __RADPPC__ + #else + #define __RAD68K__ + #endif + + #define __RAD32__ + +#else + + #ifdef __DOS__ + #define __RADDOS__ + #endif + + #ifdef __386__ + #define __RAD32__ + #endif + + #ifdef _Windows //For Borland + #ifdef __WIN32__ + #define WIN32 + #else + #define __WINDOWS__ + #endif + #endif + + #ifdef _WINDOWS //For MS + #ifndef _WIN32 + #define __WINDOWS__ + #endif + #endif + + #ifdef _WIN32 + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #else + #ifdef __NT__ + #define __RADNT__ + #define __RAD32__ + #define __RADWIN__ + #else + #ifdef __WINDOWS_386__ + #define __RADWIN__ + #define __RADWINEXT__ + #define __RAD32__ + #else + #ifdef __WINDOWS__ + #define __RADWIN__ + #define __RAD16__ + #else + #ifdef WIN32 + #define __RADWIN__ + #define __RADNT__ + #define __RAD32__ + #endif + #endif + #endif + #endif + #endif + +#endif + +#if !defined(__RADDOS__) && !defined(__RADWIN__) && !defined(__RADMAC__) + #error "RAD.H didn'y detect your platform. Define __DOS__, __WINDOWS__, WIN32, macintosh, or powerc." +#endif + +#ifdef __RADMAC__ + #define RADLINK + #define RADEXPLINK + #define RADASMLINK +#else + + #ifdef __RADNT__ + #ifndef _WIN32 + #define _WIN32 + #endif + #endif + + #define RADDLLIMP + + #ifdef __RADWIN__ + #ifdef __RAD32__ + #ifdef __RADNT__ + #define RADEXPLINK __cdecl + #ifndef __RADINDLL_ + #undef RADDLLIMP + #define RADDLLIMP __declspec(dllimport) + #endif + #ifdef __WATCOMC__ + #define RADLINK __pascal + #else + #define RADLINK + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __far __pascal + #endif + #else + #define RADLINK __far __pascal + #define RADEXPLINK __export __far __pascal + #endif + #else + #define RADLINK __pascal + #define RADEXPLINK __pascal + #endif + + #define RADASMLINK __cdecl + +#endif + +#ifdef __cplusplus + #define RCFUNC extern "C" + #define RCSTART extern "C" { + #define RCEND } +#else + #define RCFUNC + #define RCSTART + #define RCEND +#endif + + +RCSTART + +#define s8 signed char +#define u8 unsigned char +#define u32 unsigned long +#define s32 signed long + +#ifdef __RAD32__ + #define PTR4 + + #define u16 unsigned short + #define s16 signed short + + #ifdef __RADMAC__ + + #include + #include + #include + + #define radstrlen strlen + + #define radmemset memset + + #define radmemcpy(dest,source,size) BlockMoveData((Ptr)(source),(Ptr)(dest),size) + + #define radmemcpydb(dest,source,size) BlockMoveData((Ptr)(source),(Ptr)(dest),size) + + #define radstrcpy strcpy + + #ifdef __RAD68K__ + + #pragma parameter __D0 mult64anddiv(__D0,__D1,__D2) + u32 mult64anddiv(u32 m1,u32 m2,u32 d) FOURWORDINLINE(0x4C01,0x0C01,0x4C42,0x0C01); + // muls.l d1,d1:d0 divs.l d2,d1:d0 + + #pragma parameter radconv32a(__A0,__D0) + void radconv32a(void* p,u32 n) NINEWORDINLINE(0x4A80,0x600C,0x2210,0xE059,0x4841,0xE059,0x20C1,0x5380,0x6EF2); + // tst.l d0 bra.s @loope @loop: move.l (a0),d1 ror.w #8,d1 swap d1 ror.w #8,d1 move.l d1,(a0)+ sub.l #1,d0 bgt.s @loop @loope: + + #else + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + + void radconv32a(void* p,u32 n); + + #endif + + #else + + #ifdef __WATCOMC__ + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + #pragma aux mult64anddiv = "mul ecx" "div ebx" parm [eax] [ecx] [ebx] modify [EDX eax]; + + s32 radabs(s32 ab); + #pragma aux radabs = "test eax,eax" "jge skip" "neg eax" "skip:" parm [eax]; + + #define radabs32 radabs + + u32 DOSOut(char* str); + #pragma aux DOSOut = "cld" "mov ecx,0xffffffff" "xor eax,eax" "mov edx,edi" "repne scasb" "not ecx" "dec ecx" "mov ebx,1" "mov ah,0x40" "int 0x21" parm [EDI] modify [EAX EBX ECX EDX EDI] value [ecx]; + + void DOSOutNum(char* str,u32 len); + #pragma aux DOSOutNum = "mov ah,0x40" "mov ebx,1" "int 0x21" parm [edx] [ecx] modify [eax ebx]; + + u32 ErrOut(char* str); + #pragma aux ErrOut = "cld" "mov ecx,0xffffffff" "xor eax,eax" "mov edx,edi" "repne scasb" "not ecx" "dec ecx" "xor ebx,ebx" "mov ah,0x40" "int 0x21" parm [EDI] modify [EAX EBX ECX EDX EDI] value [ecx]; + + void ErrOutNum(char* str,u32 len); + #pragma aux ErrOutNum = "mov ah,0x40" "xor ebx,ebx" "int 0x21" parm [edx] [ecx] modify [eax ebx]; + + void radmemset16(void* dest,u16 value,u32 size); + #pragma aux radmemset16 = "cld" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,1" "rep stosd" "mov cl,bl" "and cl,1" "rep stosb" parm [EDI] [EAX] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemset(void* dest,u8 value,u32 size); + #pragma aux radmemset = "cld" "mov ah,al" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,2" "rep stosd" "mov cl,bl" "and cl,3" "rep stosb" parm [EDI] [AL] [ECX] modify [EAX EDX EBX ECX EDI]; + + void radmemcpy(void* dest,void* source,u32 size); + #pragma aux radmemcpy = "cld" "mov bl,cl" "shr ecx,2" "rep movsd" "mov cl,bl" "and cl,3" "rep movsb" parm [EDI] [ESI] [ECX] modify [EBX ECX EDI ESI]; + + void __far *radfmemcpy(void __far* dest,void __far* source,u32 size); + #pragma aux radfmemcpy = "cld" "push es" "push ds" "mov es,cx" "mov ds,dx" "mov ecx,eax" "shr ecx,2" "rep movsd" "mov cl,al" "and cl,3" "rep movsb" "pop ds" "pop es" parm [CX EDI] [DX ESI] [EAX] modify [ECX EDI ESI] value [CX EDI]; + + void radmemcpydb(void* dest,void* source,u32 size); //Destination bigger + #pragma aux radmemcpydb = "std" "mov bl,cl" "lea esi,[esi+ecx-4]" "lea edi,[edi+ecx-4]" "shr ecx,2" "rep movsd" "and bl,3" "jz dne" "add esi,3" "add edi,3" "mov cl,bl" "rep movsb" "dne:" "cld" parm [EDI] [ESI] [ECX] modify [EBX ECX EDI ESI]; + + char* radstrcpy(void* dest,void* source); + #pragma aux radstrcpy = "cld" "mov edx,edi" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" parm [EDI] [ESI] modify [EAX EDX EDI ESI] value [EDX]; + + char __far* radfstrcpy(void __far* dest,void __far* source); + #pragma aux radfstrcpy = "cld" "push es" "push ds" "mov es,cx" "mov ds,dx" "mov edx,edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" "pop es" parm [CX EDI] [DX ESI] modify [EAX EDX EDI ESI] value [CX EDX]; + + char* radstpcpy(void* dest,void* source); + #pragma aux radstpcpy = "cld" "lp:" "mov al,[esi]" "inc esi" "mov [edi],al" "inc edi" "cmp al,0" "jne lp" "dec edi" parm [EDI] [ESI] modify [EAX EDI ESI] value [EDI]; + + char* radstpcpyrs(void* dest,void* source); + #pragma aux radstpcpyrs = "cld" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "dec edi" parm [EDI] [ESI] modify [EAX EDI ESI] value [ESI]; + + u32 radstrlen(void* dest); + #pragma aux radstrlen = "cld" "mov ecx,0xffffffff" "xor eax,eax" "repne scasb" "not ecx" "dec ecx" parm [EDI] modify [EAX ECX EDI] value [ECX]; + + char* radstrcat(void* dest,void* source); + #pragma aux radstrcat = "cld" "mov ecx,0xffffffff" "mov edx,edi" "xor eax,eax" "repne scasb" "dec edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" \ + parm [EDI] [ESI] modify [EAX ECX EDI ESI] value [EDX]; + + char* radstrchr(void* dest,char chr); + #pragma aux radstrchr = "cld" "lp:" "lodsb" "cmp al,dl" "je fnd" "cmp al,0" "jnz lp" "mov esi,1" "fnd:" "dec esi" parm [ESI] [DL] modify [EAX ESI] value [esi]; + + s8 radmemcmp(void* s1,void* s2,u32 len); + #pragma aux radmemcmp = "cld" "rep cmpsb" "setne al" "jbe end" "neg al" "end:" parm [EDI] [ESI] [ECX] modify [ECX EDI ESI]; + + s8 radstrcmp(void* s1,void* s2); + #pragma aux radstrcmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,ah" "jne set" "cmp al,0" "je set" "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] modify [EAX EDI ESI]; + + s8 radstricmp(void* s1,void* s2); + #pragma aux radstricmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] modify [EAX EDI ESI]; + + s8 radstrnicmp(void* s1,void* s2,u32 len); + #pragma aux radstrnicmp = "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "dec ecx" "jz set" "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" \ + parm [EDI] [ESI] [ECX] modify [EAX ECX EDI ESI]; + + char* radstrupr(void* s1); + #pragma aux radstrupr = "mov ecx,edi" "lp:" "mov al,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub [edi],32" "c1:" "inc edi" "cmp al,0" "jne lp" parm [EDI] modify [EAX EDI] value [ecx]; + + char* radstrlwr(void* s1); + #pragma aux radstrlwr = "mov ecx,edi" "lp:" "mov al,[edi]" "cmp al,'A'" "jb c1" "cmp al,'Z'" "ja c1" "add [edi],32" "c1:" "inc edi" "cmp al,0" "jne lp" parm [EDI] modify [EAX EDI] value [ecx]; + + u32 radstru32(void* dest); + #pragma aux radstru32 = "cld" "xor ecx,ecx" "xor ebx,ebx" "xor edi,edi" "lodsb" "cmp al,45" "jne skip2" "mov edi,1" "jmp skip" "lp:" "mov eax,10" "mul ecx" "lea ecx,[eax+ebx]" \ + "skip:" "lodsb" "skip2:" "cmp al,0x39" "ja dne" "cmp al,0x30" "jb dne" "mov bl,al" "sub bl,0x30" "jmp lp" "dne:" "test edi,1" "jz pos" "neg ecx" "pos:" \ + parm [ESI] modify [EAX EBX EDX EDI ESI] value [ecx]; + + u16 GetDS(); + #pragma aux GetDS = "mov ax,ds" value [ax]; + + #ifdef __RADWINEXT__ + + u32 GetBase(u16 sel); + #pragma aux GetBase = "mov bx,ax" "mov ax,6" "int 0x31" "shrd eax,ecx,16" "mov ax,dx" parm [ax] modify [ax bx cx dx] value [eax]; + + #define _16To32(ptr16) ((void*)(((GetBase((u16)(((u32)(ptr16))>>16))+((u16)(u32)(ptr16)))-GetBase(GetDS())))) + + #endif + + #ifndef __RADWIN__ + #define int86 int386 + #define int86x int386x + #endif + + #define u32regs x + #define u16regs w + + #endif + + #endif + +#else + + #define PTR4 __far + + #define u16 unsigned int + #define s16 signed int + + #ifdef __WATCOMC__ + + s16 radabs(s16 ab); + #pragma aux radabs = "test ax,ax" "jge skip" "neg ax" "skip:" parm [ax] value [ax]; + + s32 radabs32(s32 ab); + #pragma aux radabs32 = "test dx,dx" "jge skip" "neg dx" "neg ax" "sbb dx,0" "skip:" parm [dx ax] value [dx ax]; + + u32 DOSOut(char far* dest); + #pragma aux DOSOut = "cld" "and edi,0xffff" "mov dx,di" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "mov bx,1" "push ds" "push es" "pop ds" "mov ah,0x40" "int 0x21" "pop ds" "movzx eax,cx" "shr ecx,16" \ + parm [ES DI] modify [AX BX CX DX DI ES] value [CX AX]; + + void DOSOutNum(char far* str,u16 len); + #pragma aux DOSOutNum = "push ds" "mov ds,cx" "mov cx,bx" "mov ah,0x40" "mov bx,1" "int 0x21" "pop ds" parm [cx dx] [bx] modify [ax bx cx]; + + u32 ErrOut(char far* dest); + #pragma aux ErrOut = "cld" "and edi,0xffff" "mov dx,di" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "xor bx,bx" "push ds" "push es" "pop ds" "mov ah,0x40" "int 0x21" "pop ds" "movzx eax,cx" "shr ecx,16" \ + parm [ES DI] modify [AX BX CX DX DI ES] value [CX AX]; + + void ErrOutNum(char far* str,u16 len); + #pragma aux ErrOutNum = "push ds" "mov ds,cx" "mov cx,bx" "mov ah,0x40" "xor bx,bx" "int 0x21" "pop ds" parm [cx dx] [bx] modify [ax bx cx]; + + void radmemset(void far *dest,u8 value,u32 size); + #pragma aux radmemset = "cld" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "mov ah,al" "mov bx,ax" "shl eax,16" "mov ax,bx" "mov bl,cl" "shr ecx,2" 0x67 "rep stosd" "mov cl,bl" "and cl,3" "rep stosb" parm [ES DI] [AL] [CX BX]; + + void radmemcpy(void far* dest,void far* source,u32 size); + #pragma aux radmemcpy = "cld" "push ds" "mov ds,dx" "and esi,0ffffh" "and edi,0ffffh" "shl ecx,16" "mov cx,bx" "shr ecx,2" 0x67 "rep movsd" "mov cl,bl" "and cl,3" "rep movsb" "pop ds" parm [ES DI] [DX SI] [CX BX] modify [CX SI DI ES]; + + char far* radstrcpy(void far* dest,void far* source); + #pragma aux radstrcpy = "cld" "push ds" "mov ds,dx" "and esi,0xffff" "and edi,0xffff" "mov dx,di" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" parm [ES DI] [DX SI] modify [AX DX DI SI ES] value [es dx]; + + char far* radstpcpy(void far* dest,void far* source); + #pragma aux radstpcpy = "cld" "push ds" "mov ds,dx" "and esi,0xffff" "and edi,0xffff" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "dec di" "pop ds" parm [ES DI] [DX SI] modify [DI SI ES] value [es di]; + + u32 radstrlen(void far* dest); + #pragma aux radstrlen = "cld" "and edi,0xffff" "mov ecx,0xffffffff" "xor eax,eax" 0x67 "repne scasb" "not ecx" "dec ecx" "movzx eax,cx" "shr ecx,16" parm [ES DI] modify [AX CX DI ES] value [CX AX]; + + char far* radstrcat(void far* dest,void far* source); + #pragma aux radstrcat = "cld" "and edi,0xffff" "mov ecx,0xffffffff" "and esi,0xffff" "push ds" "mov ds,dx" "mov dx,di" "xor eax,eax" 0x67 "repne scasb" "dec edi" "lp:" "lodsb" "stosb" "test al,0xff" "jnz lp" "pop ds" \ + parm [ES DI] [DX SI] modify [AX CX DI SI ES] value [es dx]; + + char far* radstrchr(void far* dest,char chr); + #pragma aux radstrchr = "cld" "lp:" 0x26 "lodsb" "cmp al,dl" "je fnd" "cmp al,0" "jnz lp" "xor ax,ax" "mov es,ax" "mov si,1" "fnd:" "dec si" parm [ES SI] [DL] modify [AX SI ES] value [es si]; + + s8 radstricmp(void far* s1,void far* s2); + #pragma aux radstricmp = "and edi,0xffff" "push ds" "mov ds,dx" "and esi,0xffff" "lp:" "mov al,[esi]" "mov ah,[edi]" "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" \ + "cmp ah,'a'" "jb c2" "cmp ah,'z'" "ja c2" "sub ah,32" "c2:" "cmp al,ah" "jne set" "cmp al,0" "je set" \ + "inc esi" "inc edi" "jmp lp" "set:" "setne al" "jbe end" "neg al" "end:" "pop ds" \ + parm [ES DI] [DX SI] modify [AX DI SI]; + + u32 radstru32(void far* dest); + #pragma aux radstru32 = "cld" "xor ecx,ecx" "xor ebx,ebx" "xor edi,edi" "lodsb" "cmp al,45" "jne skip2" "mov edi,1" "jmp skip" "lp:" "mov eax,10" "mul ecx" "lea ecx,[eax+ebx]" \ + "skip:" 0x26 "lodsb" "skip2:" "cmp al,0x39" "ja dne" "cmp al,0x30" "jb dne" "mov bl,al" "sub bl,0x30" "jmp lp" "dne:" "test edi,1" "jz pos" "neg ecx" "pos:" \ + "movzx eax,cx" "shr ecx,16" parm [ES SI] modify [AX BX DX DI SI] value [cx ax]; + + u32 mult64anddiv(u32 m1,u32 m2,u32 d); + #pragma aux mult64anddiv = "shl ecx,16" "mov cx,ax" "shrd eax,edx,16" "mov ax,si" "mul ecx" "shl edi,16" "mov di,bx" "div edi" "shld edx,eax,16" "and edx,0xffff" "and eax,0xffff" parm [cx ax] [dx si] [di bx] \ + modify [ax bx cx dx si di] value [dx ax]; + + #endif + +#endif + +RCEND + +RCFUNC void PTR4* RADLINK radmalloc(u32 numbytes); +RCFUNC void RADLINK radfree(void PTR4* ptr); + +#ifdef __WATCOMC__ + + char bkbhit(); + #pragma aux bkbhit = "mov ah,1" "int 0x16" "lahf" "shr eax,14" "and eax,1" "xor al,1" ; + + char bgetch(); + #pragma aux bgetch = "xor ah,ah" "int 0x16" "test al,0xff" "jnz done" "mov al,ah" "or al,0x80" "done:" modify [AX]; + + void BreakPoint(); + #pragma aux BreakPoint = "int 3"; + + u8 radinp(u16 p); + #pragma aux radinp = "in al,dx" parm [DX]; + + u8 radtoupper(u8 p); + #pragma aux radtoupper = "cmp al,'a'" "jb c1" "cmp al,'z'" "ja c1" "sub al,32" "c1:" parm [al] value [al]; + + void radoutp(u16 p,u8 v); + #pragma aux radoutp = "out dx,al" parm [DX] [AL]; + +#endif + +#endif + diff --git a/3rdparty/smacker/smack.h b/3rdparty/smacker/smack.h new file mode 100644 index 00000000..091c0439 --- /dev/null +++ b/3rdparty/smacker/smack.h @@ -0,0 +1,307 @@ +#ifndef SMACKH +#define SMACKH + +#include "rad.h" + +RCSTART + +#define SMACKVERSION "2.0y" + +typedef struct SmackSumTag { + u32 TotalTime; // total time + u32 MS100PerFrame; // MS*100 per frame (100000/MS100PerFrame=Frames/Sec) + u32 TotalOpenTime; // Time to open and prepare for decompression + u32 TotalFrames; // Total Frames displayed + u32 SkippedFrames; // Total number of skipped frames + u32 TotalBlitTime; // Total time spent blitting + u32 TotalReadTime; // Total time spent reading + u32 TotalDecompTime; // Total time spent decompressing + u32 TotalBackReadTime; // Total time spent reading in background + u32 TotalReadSpeed; // Total io speed (bytes/second) + u32 SlowestFrameTime; // Slowest single frame time + u32 Slowest2FrameTime; // Second slowest single frame time + u32 SlowestFrameNum; // Slowest single frame number + u32 Slowest2FrameNum; // Second slowest single frame number + u32 AverageFrameSize; // Average size of the frame + u32 Highest1SecRate; // Highest 1 sec data rate + u32 Highest1SecFrame; // Highest 1 sec data rate starting frame + u32 HighestMemAmount; // Highest amount of memory allocated + u32 TotalExtraMemory; // Total extra memory allocated + u32 HighestExtraUsed; // Highest extra memory actually used +} SmackSum; + +typedef struct SmackTag { + u32 Version; // SMK2 only right now + u32 Width; // Width (1 based, 640 for example) + u32 Height; // Height (1 based, 480 for example) + u32 Frames; // Number of frames (1 based, 100 = 100 frames) + u32 MSPerFrame; // Frame Rate + u32 SmackerType; // bit 0 set=ring frame + u32 LargestInTrack[7]; // Largest single size for each track + u32 tablesize; // Size of the init tables + u32 codesize; // Compression info + u32 absize; // ditto + u32 detailsize; // ditto + u32 typesize; // ditto + u32 TrackType[7]; // high byte=0x80-Comp,0x40-PCM data,0x20-16 bit,0x10-stereo + u32 extra; // extra value (should be zero) + u32 NewPalette; // set to one if the palette changed + u8 Palette[772]; // palette data + u32 FrameNum; // Frame Number to be displayed + u32 LastRectx; // Rect set in from SmackToBufferRect (X coord) + u32 LastRecty; // Rect set in from SmackToBufferRect (Y coord) + u32 LastRectw; // Rect set in from SmackToBufferRect (Width) + u32 LastRecth; // Rect set in from SmackToBufferRect (Height) + u32 OpenFlags; // flags used on open + u32 LeftOfs; // Left Offset used in SmackTo + u32 TopOfs; // Top Offset used in SmackTo +} Smack; + +#define SmackHeaderSize(smk) ((((u8*)&((smk)->extra))-((u8*)(smk)))+4) + +//======================================================================= +#define SMACKNEEDPAN 0x00020L // Will be setting the pan +#define SMACKNEEDVOLUME 0x00040L // Will be setting the volume +#define SMACKFRAMERATE 0x00080L // Override fr (call SmackFrameRate first) +#define SMACKLOADEXTRA 0x00100L // Load the extra buffer during SmackOpen +#define SMACKPRELOADALL 0x00200L // Preload the entire animation +#define SMACKNOSKIP 0x00400L // Don't skip frames if falling behind +#define SMACKSIMULATE 0x00800L // Simulate the speed (call SmackSim first) +#define SMACKFILEHANDLE 0x01000L // Use when passing in a file handle +#define SMACKTRACK1 0x02000L // Play audio track 1 +#define SMACKTRACK2 0x04000L // Play audio track 2 +#define SMACKTRACK3 0x08000L // Play audio track 3 +#define SMACKTRACK4 0x10000L // Play audio track 4 +#define SMACKTRACK5 0x20000L // Play audio track 5 +#define SMACKTRACK6 0x40000L // Play audio track 6 +#define SMACKTRACK7 0x80000L // Play audio track 7 +#define SMACKTRACKS (SMACKTRACK1|SMACKTRACK2|SMACKTRACK3|SMACKTRACK4|SMACKTRACK5|SMACKTRACK6|SMACKTRACK7) + +#define SMACKAUTOEXTRA 0xffffffffL // NOT A FLAG! - Use as extrabuf param +//======================================================================= + +#define SMACKSURFACEFAST 0 +#define SMACKSURFACESLOW 1 +#define SMACKSURFACEDIRECT 2 + + +Smack PTR4* RADEXPLINK SmackOpen(char PTR4* name,u32 flags,u32 extrabuf); + +#ifdef __RADMAC__ + #include + + Smack PTR4* RADEXPLINK SmackMacOpen(FSSpec* fsp,u32 flags,u32 extrabuf); +#endif + +u32 RADEXPLINK SmackDoFrame(Smack PTR4* smk); +void RADEXPLINK SmackNextFrame(Smack PTR4* smk); +u32 RADEXPLINK SmackWait(Smack PTR4* smk); +void RADEXPLINK SmackClose(Smack PTR4* smk); + +void RADEXPLINK SmackVolumePan(Smack PTR4* smk, u32 trackflag,u32 volume,u32 pan); + +void RADEXPLINK SmackSummary(Smack PTR4* smk,SmackSum PTR4* sum); + +u32 RADEXPLINK SmackSoundInTrack(Smack PTR4* smk,u32 trackflags); +u32 RADEXPLINK SmackSoundOnOff(Smack PTR4* smk,u32 on); + +#ifdef __RADMAC__ + void RADEXPLINK SmackToScreen(Smack PTR4* smk,u32 left,u32 top); +#else + void RADEXPLINK SmackToScreen(Smack PTR4* smk,u32 left,u32 top,u32 BytesPS,u16 PTR4* WinTbl,u32 SetBank); +#endif + +void RADEXPLINK SmackToBuffer(Smack PTR4* smk,u32 left,u32 top,u32 Pitch,u32 destheight,void PTR4* buf,u32 Reversed); +u32 RADEXPLINK SmackToBufferRect(Smack PTR4* smk, u32 SmackSurface); + +void RADEXPLINK SmackGoto(Smack PTR4* smk,u32 frame); +void RADEXPLINK SmackColorRemap(Smack PTR4* smk,void PTR4* remappal,u32 numcolors,u32 paltype); +void RADEXPLINK SmackColorTrans(Smack PTR4* smk,void PTR4* trans); +void RADEXPLINK SmackFrameRate(u32 forcerate); +void RADEXPLINK SmackSimulate(u32 sim); + +u32 RADEXPLINK SmackGetTrackData(Smack PTR4* smk,void PTR4* dest,u32 trackflag); + +void RADEXPLINK SmackSoundCheck(); + +//====================================================================== +#ifdef __RADDOS__ + + #define SMACKSOUNDNONE -1 + + extern void* cdecl SmackTimerSetupAddr; + extern void* cdecl SmackTimerReadAddr; + extern void* cdecl SmackTimerDoneAddr; + + typedef void RADLINK (*SmackTimerSetupType)(); + typedef u32 RADLINK (*SmackTimerReadType)(); + typedef void RADLINK (*SmackTimerDoneType)(); + + #define SmackTimerSetup() ((SmackTimerSetupType)(SmackTimerSetupAddr))() + #define SmackTimerRead() ((SmackTimerReadType)(SmackTimerReadAddr))() + #define SmackTimerDone() ((SmackTimerDoneType)(SmackTimerDoneAddr))() + + u8 RADEXPLINK SmackSoundUseMSS(void* DigDriver,u32 MaxTimerSpeed); + void RADEXPLINK SmackSoundMSSLiteInit(); + void RADEXPLINK SmackSoundMSSLiteDone(); + + u8 RADEXPLINK SmackSoundUseSOS3r(u32 SOSDriver,u32 MaxTimerSpeed); + u8 RADEXPLINK SmackSoundUseSOS3s(u32 SOSDriver,u32 MaxTimerSpeed); + u8 RADEXPLINK SmackSoundUseSOS4r(u32 SOSDriver,u32 MaxTimerSpeed); + u8 RADEXPLINK SmackSoundUseSOS4s(u32 SOSDriver,u32 MaxTimerSpeed); + + #ifdef __SW_3R + #define SmackSoundUseSOS3 SmackSoundUseSOS3r + #define SmackSoundUseSOS4 SmackSoundUseSOS4r + #else + #define SmackSoundUseSOS3 SmackSoundUseSOS3s + #define SmackSoundUseSOS4 SmackSoundUseSOS4s + #endif + +#else + + #define SMACKRESRESET 0 + #define SMACKRES640X400 1 + #define SMACKRES640X480 2 + #define SMACKRES800X600 3 + #define SMACKRES1024X768 4 + + u32 RADEXPLINK SmackSetSystemRes(u32 mode); // use SMACKRES* values + + #ifdef __RADMAC__ + + #include + #include + #include + #include + + typedef struct SmkTMInfoTag { + TMTask smTask; + u32 milli; + } SmkTMInfo; + + extern SmkTMInfo __SmackTimeInfo; + + void RADEXPLINK SmackTimerSetup(); + void RADEXPLINK SmackTimerDone(); + #define SmackTimerRead() (__SmackTimeInfo.milli) + + #define SMACKAUTOBLIT 0 + #define SMACKDIRECTBLIT 1 + #define SMACKGWORLDBLIT 2 + + typedef struct SmackBufTag { + u32 Reversed; + u32 SurfaceType; // SMACKSURFACExxxxxx + u32 BlitType; // SMACKxxxxxBLIT + u32 Width; + u32 Height; + u32 Pitch; + u32 Zoomed; + u32 ZWidth; + u32 ZHeight; + u32 DispColors; // colors on screen + u32 MaxPalColors; + u32 PalColorsInUse; + u32 StartPalColor; + u32 EndPalColor; + void* Buffer; + void* Palette; + u32 PalType; + + WindowPtr wp; + GWorldPtr gwp; + CTabHandle cth; + PaletteHandle palh; + } SmackBuf; + + #else + + #ifdef __RADWIN__ + + #define INCLUDE_MMSYSTEM_H + #include "windows.h" + #include "windowsx.h" + + #define SMACKAUTOBLIT 0 + #define SMACKFULL320X240BLIT 1 + #define SMACKFULL320X200BLIT 2 + #define SMACKSTANDARDBLIT 3 + #define SMACKWINGBLIT 4 + + #define WM_SMACKACTIVATE WM_USER+0x5678 + + typedef struct SmackBufTag { + u32 Reversed; // 1 if the buffer is upside down + u32 SurfaceType; // SMACKSURFACExxxx defines + u32 BlitType; // SMACKxxxxBLIT defines + u32 FullScreen; // 1 if full-screen + u32 Width; + u32 Height; + u32 Zoomed; + u32 ZWidth; + u32 ZHeight; + u32 DispColors; // colors on the screen + u32 MaxPalColors; // total possible colors in palette (usually 256) + u32 PalColorsInUse; // Used colors in palette (usually 236) + u32 StartPalColor; // first usable color index (usually 10) + u32 EndPalColor; // last usable color index (usually 246) + RGBQUAD Palette[256]; + u32 PalType; + + void PTR4* Buffer; + void PTR4* DIBRestore; + u32 OurBitmap; + u32 OrigBitmap; + u32 OurPalette; + u32 WinGDC; + u32 FullFocused; + u32 ParentHwnd; + u32 OldParWndProc; + u32 OldDispWndProc; + u32 DispHwnd; + u32 WinGBufHandle; + } SmackBuf; + + void RADEXPLINK SmackGet(Smack PTR4* smk,void PTR4* dest); + void RADEXPLINK SmackBufferGet( SmackBuf PTR4* sbuf, void PTR4* dest); + + u8 RADEXPLINK SmackSoundUseMSS(void PTR4* dd); + u8 RADEXPLINK SmackSoundUseDirectSound(HWND hw); + + #define SmackTimerSetup() + #define SmackTimerDone() + #define SmackTimerRead timeGetTime + + #endif + + #endif + + #ifdef __RADMAC__ + SmackBuf PTR4* RADEXPLINK SmackBufferOpen( WindowPtr wp, u16 BlitType, u16 width, u16 height, u16 ZoomW, u16 ZoomH ); + u16 RADEXPLINK SmackBufferBlit( SmackBuf PTR4* sbuf, u16 hwndx, u16 hwndy, u16 subx, u16 suby, u16 subw, u16 subh ); + void RADEXPLINK SmackBufferFromScreen( SmackBuf PTR4* destbuf, u16 x, u16 y); + #else + SmackBuf PTR4* RADEXPLINK SmackBufferOpen( HWND wnd, u16 BlitType, u16 width, u16 height, u16 ZoomW, u16 ZoomH ); + u16 RADEXPLINK SmackBufferBlit( SmackBuf PTR4* sbuf, HDC dc, u16 hwndx, u16 hwndy, u16 subx, u16 suby, u16 subw, u16 subh ); + void RADEXPLINK SmackBufferFromScreen( SmackBuf PTR4* destbuf, HWND hw, u16 x, u16 y); + #endif + + char PTR4* RADEXPLINK SmackBufferString(char PTR4* dest,u16 BlitType); + + void RADEXPLINK SmackBufferNewPalette( SmackBuf PTR4* sbuf, void PTR4* pal, u16 paltype ); + u16 RADEXPLINK SmackBufferSetPalette( SmackBuf PTR4* sbuf ); + void RADEXPLINK SmackBufferClose( SmackBuf PTR4* sbuf ); + + void RADEXPLINK SmackBufferClear( SmackBuf PTR4* destbuf, u16 color); + void RADEXPLINK SmackBufferToBuffer( SmackBuf PTR4* destbuf, u16 destx, u16 desty, SmackBuf PTR4* sourcebuf,u16 sourcex,u16 sourcey,u16 sourcew,u16 sourceh); + void RADEXPLINK SmackBufferToBufferTrans( SmackBuf PTR4* destbuf, u16 destx, u16 desty, SmackBuf PTR4* sourcebuf,u16 sourcex,u16 sourcey,u16 sourcew,u16 sourceh,u16 TransColor); + void RADEXPLINK SmackBufferCopyPalette( SmackBuf PTR4* destbuf, SmackBuf PTR4* sourcebuf, u16 remap); + + u16 RADEXPLINK SmackBufferFocused( SmackBuf PTR4* sbuf); + +#endif + +RCEND + +#endif diff --git a/3rdparty/smacker/smack.lib b/3rdparty/smacker/smack.lib new file mode 100644 index 00000000..a3a9dcfc Binary files /dev/null and b/3rdparty/smacker/smack.lib differ diff --git a/3rdparty/smartheap/SHLW32MT.LIB b/3rdparty/smartheap/SHLW32MT.LIB new file mode 100644 index 00000000..732aedf8 Binary files /dev/null and b/3rdparty/smartheap/SHLW32MT.LIB differ diff --git a/3rdparty/smartheap/SHMALLOC.H b/3rdparty/smartheap/SHMALLOC.H new file mode 100644 index 00000000..709c19b8 --- /dev/null +++ b/3rdparty/smartheap/SHMALLOC.H @@ -0,0 +1,63 @@ +/* shmalloc.h -- SmartHeap ANSI Standard C memory API + * Professional Memory Management Library + * + * Copyright (C) 1991-1996 by Arthur D. Applegate. All Rights Reserved. + * All Rights Reserved. + * + * No part of this source code may be copied, modified or reproduced + * in any form without retaining the above copyright notice. + * This source code, or source code derived from it, may not be redistributed + * without express written permission of the author. + */ + +#if !(defined(_SHMALLOC_H)) +#define _SHMALLOC_H + +#include "smrtheap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ANSI Standard Memory Management API */ + +#if (!defined(MEM_DEBUG) && !defined(NO_MALLOC_MACRO)) || defined(MALLOC_MACRO) +#ifdef malloc +#undef malloc +#endif +#define malloc(s) MEM_malloc(s) +#ifdef calloc +#undef calloc +#endif +#define calloc(s,c) MEM_calloc(s,c) +#ifdef realloc +#undef realloc +#endif +#define realloc(p,s) MEM_realloc(p,s) +#ifdef free +#undef free +#endif +#define free(p) MEM_free(p) + +#endif /* NO_MALLOC_MACRO */ + +#ifndef MEM_malloc +void MEM_FAR * MEM_ENTRY_ANSI MEM_malloc(size_t size); +void MEM_FAR * MEM_ENTRY_ANSI MEM_calloc(size_t nobj, size_t size); +void MEM_FAR * MEM_ENTRY_ANSI MEM_realloc(void MEM_FAR *p, size_t size); +void MEM_ENTRY_ANSI MEM_free(void MEM_FAR *p); +#endif /* MEM_malloc */ + +#if defined(__WATCOMC__) && defined(__SW_3S) +/* Watcom stack calling convention */ + #pragma aux (syscall) MEM_malloc + #pragma aux (syscall) MEM_realloc + #pragma aux (syscall) MEM_calloc + #pragma aux (syscall) MEM_free +#endif /* __WATCOMC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(_SHMALLOC_H) */ diff --git a/3rdparty/smartheap/SHMFC4M.LIB b/3rdparty/smartheap/SHMFC4M.LIB new file mode 100644 index 00000000..a8f04163 Binary files /dev/null and b/3rdparty/smartheap/SHMFC4M.LIB differ diff --git a/3rdparty/smartheap/SMRTHEAP.H b/3rdparty/smartheap/SMRTHEAP.H new file mode 100644 index 00000000..b4f17a74 --- /dev/null +++ b/3rdparty/smartheap/SMRTHEAP.H @@ -0,0 +1,656 @@ +/* smrtheap.h -- SmartHeap (tm) public C header file + * Professional Memory Management Library + * + * Copyright (C) 1991-1997 by Arthur D. Applegate. All Rights Reserved. + * All Rights Reserved. + * + * No part of this source code may be copied, modified or reproduced + * in any form without retaining the above copyright notice. + * This source code, or source code derived from it, may not be redistributed + * without express written permission of the author. + * + */ + +#if !defined(_SMARTHEAP_H) +#define _SMARTHEAP_H + +#include +#include + +#if !defined(macintosh) && !defined(THINK_C) && !defined(__MWERKS__) \ + && !defined(SHANSI) && UINT_MAX == 0xFFFFu \ + && (defined(_Windows) || defined(_WINDOWS) || defined(__WINDOWS__)) + #define MEM_WIN16 +#endif + +#if (UINT_MAX == 0xFFFFu) && (defined(MEM_WIN16) \ + || defined(MSDOS) || defined(__MSDOS__) || defined(__DOS__)) + /* 16-bit X86 */ + #if defined(SYS_DLL) + #if defined(_MSC_VER) && _MSC_VER <= 600 + #define MEM_ENTRY _export _loadds far pascal + #else + #define MEM_ENTRY _export far pascal + #endif + #else + #define MEM_ENTRY far pascal + #endif + #ifdef __WATCOMC__ + #define MEM_ENTRY_ANSI __far + #else + #define MEM_ENTRY_ANSI far cdecl + #endif + #define MEM_FAR far + #if defined(MEM_WIN16) + #define MEM_ENTRY2 _export far pascal + #elif defined(DOS16M) || defined(DOSX286) + #define MEM_ENTRY2 _export _loadds far pascal + #endif + +#else /* not 16-bit X86 */ + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) \ + || defined(__WIN32__) || defined(__NT__) + #define MEM_WIN32 + #if defined(_MSC_VER) + #if defined(_SHI_Pool) && defined(SYS_DLL) + #define MEM_ENTRY1 __declspec(dllexport) + #define MEM_ENTRY4 __declspec(dllexport) extern + #elif !defined(_SHI_Pool) && (defined(MEM_DEBUG) || defined(MEM_DLL)) + #define MEM_ENTRY1 __declspec(dllimport) + #if defined(_M_IX86) || defined(_X86_) + #define MemDefaultPool shi_MemDefaultPool + #define MEM_ENTRY4 __declspec(dllimport) + #endif + #endif + #endif + #if !defined(_MSC_VER) || defined(_M_IX86) || defined(_X86_) + #define MEM_ENTRY __stdcall + #else + #define MEM_ENTRY __cdecl /* for NT/RISC */ + #endif + #ifndef __WATCOMC__ + #define MEM_ENTRY_ANSI __cdecl + #endif + +#elif defined(__OS2__) + #if defined(__BORLANDC__) || defined(__WATCOMC__) + #if defined(SYS_DLL) + #define MEM_ENTRY __export __syscall + #else + #define MEM_ENTRY __syscall + #endif /* SYS_DLL */ + #ifdef __BORLANDC__ + #define MEM_ENTRY_ANSI __stdcall + #endif + #elif defined(__IBMC__) || defined(__IBMCPP__) + #if defined(SYS_DLL) && 0 + #define MEM_ENTRY _Export _System + #else + #define MEM_ENTRY _System + #endif + #define MEM_ENTRY_ANSI _Optlink + #define MEM_ENTRY3 MEM_ENTRY + #define MEM_CALLBACK MEM_ENTRY3 + #define MEM_ENTRY2 + #endif +#endif /* __OS2__ */ + +#if defined(__WATCOMC__) && defined(__SW_3S) + /* Watcom stack calling convention */ +#ifndef __OS2__ +#ifdef __WINDOWS_386__ + #pragma aux syscall "*_" parm routine [eax ebx ecx edx fs gs] modify [eax]; +#else + #pragma aux syscall "*_" parm routine [eax ebx ecx edx] modify [eax]; +#endif +#ifndef MEM_ENTRY + #define MEM_ENTRY __syscall +#endif /* MEM_ENTRY */ +#endif +#endif /* Watcom stack calling convention */ + +#endif /* end of system-specific declarations */ + +#ifndef MEM_ENTRY + #define MEM_ENTRY +#endif +#ifndef MEM_ENTRY1 + #define MEM_ENTRY1 +#endif +#ifndef MEM_ENTRY2 + #define MEM_ENTRY2 MEM_ENTRY +#endif +#ifndef MEM_ENTRY3 + #define MEM_ENTRY3 +#endif +#ifndef MEM_ENTRY4 + #define MEM_ENTRY4 extern +#endif +#ifndef MEM_CALLBACK +#define MEM_CALLBACK MEM_ENTRY2 +#endif +#ifndef MEM_ENTRY_ANSI + #define MEM_ENTRY_ANSI +#endif +#ifndef MEM_FAR + #define MEM_FAR +#endif + +#ifdef applec +/* Macintosh: Apple MPW C/C++ passes char/short parms as longs (4 bytes), + * whereas Symantec C/C++ for MPW passes these as words (2 bytes); + * therefore, canonicalize all integer parms as 'int' for this platform. + */ + #define MEM_USHORT unsigned + #define MEM_UCHAR unsigned +#else + #define MEM_USHORT unsigned short + #define MEM_UCHAR unsigned char +#endif /* applec */ + +#ifdef MEM_DEBUG +#include "heapagnt.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*** Types ***/ + +#ifndef MEM_BOOL_DEFINED +#define MEM_BOOL_DEFINED +typedef int MEM_BOOL; +#endif + +/* Version Masks */ +typedef unsigned MEM_VERSION; +#define MEM_MAJOR_VERSION(v) (((v) & 0xF000u) >> 12) +#define MEM_MINOR_VERSION(v) (((v) & 0x0F00u) >> 8) +#define MEM_UPDATE_VERSION(v) ((v) & 0x00FFu) + +/* Note: these types are struct's rather than integral types to facilitate + * compile-time type-checking. MEM_POOL and MEM_HANDLE should be regarded + * as black boxes, and treated just like handles. + * You should not have any type casts to or from MEM_POOL or MEM_HANDLE; + * nor should you dereference variables of type MEM_POOL or MEM_HANDLE + * (unless you are using SmartHeap to replace NewHandle on the Mac, and + * you have existing code that dereferences handles). + */ +#ifndef MEM_POOL_DEFINED +#define MEM_POOL_DEFINED +#ifdef _SHI_Pool + typedef struct _SHI_Pool MEM_FAR *MEM_POOL; + typedef struct _SHI_MovHandle MEM_FAR *MEM_HANDLE; +#else + #ifdef THINK_C + typedef void *MEM_POOL; + typedef void **MEM_HANDLE; + #else + typedef struct _SHI_Pool { int reserved; } MEM_FAR *MEM_POOL; + typedef struct _SHI_MovHandle { int reserved; } MEM_FAR *MEM_HANDLE; + #endif +#endif +#endif /* MEM_POOL_DEFINED */ + + +#if !defined(MEM_DEBUG) || !(defined(MEM_WIN16) || defined(MEM_WIN32)) +#define SHI_MAJOR_VERSION 3 +#define SHI_MINOR_VERSION 3 +#define SHI_UPDATE_LEVEL 0 +#endif /* !WINDOWS */ + +#ifndef MEM_DEBUG + +/* Error codes: errorCode field of MEM_ERROR_INFO */ +#ifndef MEM_ERROR_CODE_DEFINED +#define MEM_ERROR_CODE_DEFINED +typedef enum +{ + MEM_NO_ERROR=0, + MEM_INTERNAL_ERROR, + MEM_OUT_OF_MEMORY, + MEM_BLOCK_TOO_BIG, + MEM_ALLOC_ZERO, + MEM_RESIZE_FAILED, + MEM_LOCK_ERROR, + MEM_EXCEEDED_CEILING, + MEM_TOO_MANY_PAGES, + MEM_TOO_MANY_TASKS, + MEM_BAD_MEM_POOL, + MEM_BAD_BLOCK, + MEM_BAD_FREE_BLOCK, + MEM_BAD_HANDLE, + MEM_BAD_POINTER, + MEM_WRONG_TASK, + MEM_NOT_FIXED_SIZE, + MEM_BAD_FLAGS, + MEM_ERROR_CODE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_ERROR_CODE; +#endif /* MEM_ERROR_CODE_DEFINED */ + + +/* ### we should have packing pragma around these structure decls in case + * ### user is compiling with non-default packing directive (only needed + * ### if user is packing more strictly than native int size *and* if + * ### native int size is != native long and ptr sizes) + */ + +/* Error info, passed to error-handling callback routine */ +#ifndef MEM_ERROR_INFO_DEFINED +#define MEM_ERROR_INFO_DEFINED +typedef struct _MEM_ERROR_INFO +{ + MEM_ERROR_CODE errorCode; /* error code identifying type of error */ + MEM_POOL pool; /* pool in which error occurred, if known */ +} MEM_ERROR_INFO; + +/* Error handling callback function */ +typedef MEM_BOOL (MEM_ENTRY2 * MEM_ENTRY3 MEM_ERROR_FN) + (MEM_ERROR_INFO MEM_FAR *); + +#endif /* MEM_ERROR_INFO_DEFINED */ + +#endif /* MEM_DEBUG */ + + +#ifndef MEM_BLOCK_TYPE_DEFINED +#define MEM_BLOCK_TYPE_DEFINED +/* Block Type: field of MEM_POOL_ENTRY, field of MEM_POOL_INFO, + * parameter to MemPoolPreAllocate + */ +typedef enum +{ + MEM_FS_BLOCK = 0x0001u, + MEM_VAR_MOVEABLE_BLOCK = 0x0002u, + MEM_VAR_FIXED_BLOCK = 0x0004u, + MEM_EXTERNAL_BLOCK = 0x0008u, + MEM_BLOCK_TYPE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_BLOCK_TYPE; +#endif /* MEM_BLOCK_TYPE_DEFINED */ + +#ifndef MEM_POOL_ENTRY_DEFINED +#define MEM_POOL_ENTRY_DEFINED +/* Pool Entry: parameter to MemPoolWalk */ +typedef struct +{ + void MEM_FAR *entry; + MEM_POOL pool; + MEM_BLOCK_TYPE type; + MEM_BOOL isInUse; + unsigned long size; + MEM_HANDLE handle; + unsigned lockCount; + void MEM_FAR *reserved_ptr; +} MEM_POOL_ENTRY; +#endif /* MEM_POOL_ENTRY_DEFINED */ + +#ifndef MEM_POOL_STATUS_DEFINED +#define MEM_POOL_STATUS_DEFINED +/* Pool Status: returned by MemPoolWalk, MemPoolFirst, MemPoolNext */ +typedef enum +{ + MEM_POOL_OK = 1, + MEM_POOL_CORRUPT = -1, + MEM_POOL_CORRUPT_FATAL = -2, + MEM_POOL_END = 0, + MEM_POOL_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_POOL_STATUS; +#endif /* MEM_POOL_STATUS_DEFINED */ + +#ifndef MEM_POINTER_STATUS_DEFINED +#define MEM_POINTER_STATUS_DEFINED +/* Pointer Status: returned by MemCheckPtr */ +typedef enum +{ + MEM_POINTER_OK = 1, + MEM_POINTER_WILD = 0, + MEM_POINTER_FREE = -1, + MEM_POINTER_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_POINTER_STATUS; +#endif /* MEM_POINTER_STATUS_DEFINED */ + +/* Pool Info: parameter to MemPoolInfo, MemPoolFirst, MemPoolNext */ +typedef struct +{ + MEM_POOL pool; + MEM_BLOCK_TYPE type; /* disjunctive combination of block type flags */ + unsigned short blockSizeFS; + unsigned short smallBlockSize; + unsigned pageSize; + unsigned long floor; + unsigned long ceiling; + unsigned flags; + MEM_ERROR_FN errorFn; +} MEM_POOL_INFO; + +/* Flags passed to MemAlloc, MemAllocPtr, MemReAlloc, MemReAllocPtr */ +#define MEM_FIXED 0x0000u /* fixed handle-based block */ +#define MEM_ZEROINIT 0x0001u /* == TRUE for SH 1.5 compatibility */ +#define MEM_MOVEABLE 0x0002u /* moveable handle-based block */ +#define MEM_RESIZEABLE 0x0004u /* reserve space above block */ +#define MEM_RESIZE_IN_PLACE 0x0008u /* do not move block (realloc) */ +#define MEM_NOGROW 0x0010u /* do not grow heap to satisfy request */ +#define MEM_NOEXTERNAL 0x0020u /* reserved for internal use */ +#define MEM_NOCOMPACT 0x0040u /* do not compact to satisfy request */ +#define MEM_NO_SERIALIZE 0x0080u /* do not serialize this request */ +#define MEM_HANDLEBASED 0x4000u /* for internal use */ +#define MEM_RESERVED 0x8000u /* for internal use */ + +#define MEM_UNLOCK_FAILED USHRT_MAX + +/* Flags passed to MemPoolInit, MemPoolInitFS */ +#ifndef MEM_POOL_SHARED +#define MEM_POOL_SHARED 0x0001u /* == TRUE for SH 1.5 compatibility */ +#define MEM_POOL_SERIALIZE 0x0002u /* pool used in more than one thread */ +#define MEM_POOL_VIRTUAL_LOCK 0x0004u /* pool is locked in physical memory */ +#define MEM_POOL_ZEROINIT 0x0008u /* malloc/new from pool zero-inits */ +#define MEM_POOL_REGION 0x0010u /* store pool in user-supplied region*/ +#define MEM_POOL_DEFAULT 0x8000u /* pool with default characteristics */ +#endif /* MEM_POOL_SHARED */ + +MEM_ENTRY4 MEM_POOL MemDefaultPool; + +/* Default memory pool for C malloc, C++ new (for backwards compatibility) */ +#define MEM_DEFAULT_POOL MemDefaultPool + +/* define and initialize these variables at file scope to change defaults */ +extern unsigned short MemDefaultPoolBlockSizeFS; +extern unsigned MemDefaultPoolPageSize; +extern unsigned MemDefaultPoolFlags; + +/* define SmartHeap_malloc at file scope if you + * are intentionally _NOT_ linking in the SmartHeap malloc definition + * ditto for SmartHeap operator new, and fmalloc et al. + */ +extern int SmartHeap_malloc; +extern int SmartHeap_far_malloc; +extern int SmartHeap_new; + +#define MEM_ERROR_RET ULONG_MAX + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !defined(_SMARTHEAP_H) */ + + +/*** Function Prototypes ***/ + +#ifndef _SMARTHEAP_PROT +#define _SMARTHEAP_PROT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _shAPI + #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) + #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY _dbg ## name + #else + #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY name + #endif +#endif + +#ifndef _dbgARGS + #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) + #define _dbgARGS1 const char MEM_FAR *, int + #define _dbgARGS , _dbgARGS1 + #else + #define _dbgARGS1 void + #define _dbgARGS + #endif +#endif + + +/**** HOW TO READ SmartHeap PROTOTYPES **** + * prototypes below have the follow syntax in order to support both debug + * and non-debug APIs with single-source: + * + * _shiAPI(, )([] _dbgARGS); + * + * the above translates to a C prototype as follows: + * + * ([]); + */ + +/* Library Version */ +MEM_ENTRY1 MEM_VERSION MEM_ENTRY MemVersion(void); + +/* Library Registration */ +_shAPI(MEM_BOOL, MemRegisterTask)(_dbgARGS1); +_shAPI(MEM_BOOL, MemUnregisterTask)(_dbgARGS1); + +/* Memory Pool Functions */ +_shAPI(MEM_POOL, MemPoolInit)(unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitFS)(MEM_USHORT, unsigned long, + unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitRegion)(void MEM_FAR *, + unsigned long size, unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitNamedShared)(const char MEM_FAR *, + unsigned long size,unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitNamedSharedEx)(void MEM_FAR *addr, + unsigned pidCount, unsigned long MEM_FAR *pids, void MEM_FAR *security, + const char MEM_FAR *name, unsigned long size, unsigned flags _dbgARGS); +_shAPI(MEM_POOL, MemPoolAttachShared)(MEM_POOL, const char MEM_FAR * _dbgARGS); +_shAPI(MEM_BOOL, MemPoolFree)(MEM_POOL _dbgARGS); +MEM_POOL MEM_ENTRY MemInitDefaultPool(void); +MEM_BOOL MEM_ENTRY MemFreeDefaultPool(void); +_shAPI(unsigned, MemPoolSetPageSize)(MEM_POOL, unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemPoolSetBlockSizeFS)(MEM_POOL, MEM_USHORT _dbgARGS); +_shAPI(MEM_BOOL, MemPoolSetSmallBlockSize)(MEM_POOL, MEM_USHORT _dbgARGS); +_shAPI(unsigned long, MemPoolSetFloor)(MEM_POOL, unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolSetCeiling)(MEM_POOL, unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolPreAllocate)(MEM_POOL, unsigned long, + MEM_BLOCK_TYPE _dbgARGS); +_shAPI(unsigned long, MemPoolPreAllocateHandles)(MEM_POOL, + unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolShrink)(MEM_POOL _dbgARGS); +_shAPI(unsigned long, MemPoolSize)(MEM_POOL _dbgARGS); +_shAPI(unsigned long, MemPoolCount)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolInfo)(MEM_POOL, void MEM_FAR *, + MEM_POOL_INFO MEM_FAR* _dbgARGS); +_shAPI(MEM_POOL_STATUS, MemPoolFirst)(MEM_POOL_INFO MEM_FAR *, + MEM_BOOL _dbgARGS); +_shAPI(MEM_POOL_STATUS,MemPoolNext)(MEM_POOL_INFO MEM_FAR*,MEM_BOOL _dbgARGS); +_shAPI(MEM_POOL_STATUS,MemPoolWalk)(MEM_POOL,MEM_POOL_ENTRY MEM_FAR*_dbgARGS); +_shAPI(MEM_BOOL, MemPoolCheck)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolLock)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolUnlock)(MEM_POOL _dbgARGS); + +/* Handle-based API for moveable memory within heap. */ +_shAPI(MEM_HANDLE, MemAlloc)(MEM_POOL, unsigned, unsigned long _dbgARGS); +_shAPI(MEM_HANDLE, MemReAlloc)(MEM_HANDLE,unsigned long,unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemFree)(MEM_HANDLE _dbgARGS); +_shAPI(void MEM_FAR *, MemLock)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemUnlock)(MEM_HANDLE _dbgARGS); +_shAPI(void MEM_FAR *, MemFix)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemUnfix)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemLockCount)(MEM_HANDLE _dbgARGS); +#ifndef MemFlags +#define MemFlags(mem) MemLockCount(mem) +#endif +_shAPI(MEM_BOOL, MemIsMoveable)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned long, MemSize)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned long, MemSizeRequested)(MEM_HANDLE _dbgARGS); +_shAPI(MEM_HANDLE, MemHandle)(void MEM_FAR * _dbgARGS); +#ifndef MEM_REFERENCE + #ifdef MEM_DEBUG + MEM_ENTRY1 void MEM_FAR * MEM_ENTRY _dbgMemReference(MEM_HANDLE, + const char MEM_FAR *, int); + #define MEM_REFERENCE(handle) \ + _dbgMemReference(handle, __FILE__, __LINE__) + #else + #define MEM_REFERENCE(handle) (*(void MEM_FAR * MEM_FAR *)handle) + #endif +#endif + +/* General Heap Allocator (returns direct pointer to memory) */ +_shAPI(void MEM_FAR*,MemAllocPtr)(MEM_POOL,unsigned long,unsigned _dbgARGS); +_shAPI(void MEM_FAR *, MemReAllocPtr)(void MEM_FAR *, unsigned long, + unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemFreePtr)(void MEM_FAR * _dbgARGS); +_shAPI(unsigned long, MemSizePtr)(void MEM_FAR * _dbgARGS); +_shAPI(MEM_POINTER_STATUS, MemCheckPtr)(MEM_POOL, void MEM_FAR * _dbgARGS); + +/* Fixed-Size Allocator */ +_shAPI(void MEM_FAR *, MemAllocFS)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemFreeFS)(void MEM_FAR * _dbgARGS); + +/* Error Handling Functions */ +MEM_ENTRY1 MEM_ERROR_FN MEM_ENTRY MemSetErrorHandler(MEM_ERROR_FN); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY MemDefaultErrorHandler(MEM_ERROR_INFO MEM_FAR*); +MEM_ENTRY1 void MEM_ENTRY MemErrorUnwind(void); + +#ifdef MEM_WIN32 +/* patching control */ + +#ifndef MEM_PATCHING_DEFINED +#define MEM_PATCHING_DEFINED +typedef enum +{ + MEM_PATCH_ALL = 0, + MEM_SKIP_PATCHING_THIS_DLL = 1, + MEM_DISABLE_SYSTEM_HEAP_PATCHING = 2, + MEM_DISABLE_ALL_PATCHING = 4|2|1, + MEM_PATCHING_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_PATCHING; +#endif /* MEM_PATCHING_DEFINED */ + +#ifdef _MSC_VER +__declspec(dllexport) +#endif +MEM_PATCHING MEM_ENTRY MemSetPatching(const char ***skipDLLs); + +#endif /* MEM_WIN32 */ + +/* internal routines */ +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _shi_enterCriticalSection(void); +MEM_ENTRY1 void MEM_ENTRY _shi_leaveCriticalSection(void); +MEM_BOOL shi_call_new_handler_msc(size_t, MEM_BOOL); + + +/* Wrapper macros for debugging API */ +#ifndef _SHI_dbgMacros +#ifdef MEM_DEBUG +#define MemRegisterTask() _dbgMemRegisterTask(__FILE__, __LINE__) +#define MemUnregisterTask() _dbgMemUnregisterTask(__FILE__, __LINE__) +#define MemPoolInit(flags) _dbgMemPoolInit(flags, __FILE__, __LINE__) +#define MemPoolInitFS(bs, bc, f) _dbgMemPoolInitFS(bs,bc,f,__FILE__,__LINE__) +#define MemPoolInitRegion(addr, sz, f) \ + _dbgMemPoolInitRegion(addr, sz, f, __FILE__, __LINE__) +#define MemPoolInitNamedShared(nm, sz, f) \ + _dbgMemPoolInitNamedShared(nm, sz, f, __FILE__, __LINE__) +#define MemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f) \ + _dbgMemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f, __FILE__, __LINE__) +#define MemPoolAttachShared(p, n) \ + _dbgMemPoolAttachShared(p, n, __FILE__, __LINE__) +#define MemPoolFree(pool) _dbgMemPoolFree(pool, __FILE__, __LINE__) +#define MemPoolSetPageSize(p, s) _dbgMemPoolSetPageSize(p,s,__FILE__,__LINE__) +#define MemPoolSetBlockSizeFS(p, s) \ + _dbgMemPoolSetBlockSizeFS(p, s, __FILE__, __LINE__) +#define MemPoolSetSmallBlockSize(p, s) \ + _dbgMemPoolSetSmallBlockSize(p, s, __FILE__, __LINE__) +#define MemPoolSetFloor(p, f) _dbgMemPoolSetFloor(p, f, __FILE__, __LINE__) +#define MemPoolSetCeiling(p, c) _dbgMemPoolSetCeiling(p,c,__FILE__, __LINE__) +#define MemPoolPreAllocate(p,s,t) \ + _dbgMemPoolPreAllocate(p,s,t,__FILE__, __LINE__) +#define MemPoolPreAllocateHandles(p,h) \ + _dbgMemPoolPreAllocateHandles(p,h,__FILE__, __LINE__) +#define MemPoolShrink(p) _dbgMemPoolShrink(p, __FILE__, __LINE__) +#define MemPoolCheck(p) _dbgMemPoolCheck(p, __FILE__, __LINE__) +#define MemPoolWalk(p, e) _dbgMemPoolWalk(p, e, __FILE__, __LINE__) +#define MemPoolSize(p) _dbgMemPoolSize(p, __FILE__, __LINE__) +#define MemPoolCount(p) _dbgMemPoolCount(p, __FILE__, __LINE__) +#define MemPoolInfo(p,x,i) _dbgMemPoolInfo(p,x,i, __FILE__, __LINE__) +#define MemPoolFirst(i, b) _dbgMemPoolFirst(i, b, __FILE__, __LINE__) +#define MemPoolNext(i, b) _dbgMemPoolNext(i, b, __FILE__, __LINE__) +#define MemPoolLock(p) _dbgMemPoolLock(p, __FILE__, __LINE__) +#define MemPoolUnlock(p) _dbgMemPoolUnlock(p, __FILE__, __LINE__) +#define MemAlloc(p, f, s) _dbgMemAlloc(p, f, s, __FILE__, __LINE__) +#define MemReAlloc(h, s, f) _dbgMemReAlloc(h, s, f, __FILE__, __LINE__) +#define MemFree(h) _dbgMemFree(h, __FILE__, __LINE__) +#define MemLock(h) _dbgMemLock(h, __FILE__, __LINE__) +#define MemUnlock(h) _dbgMemUnlock(h, __FILE__, __LINE__) +#define MemFix(h) _dbgMemFix(h, __FILE__, __LINE__) +#define MemUnfix(h) _dbgMemUnfix(h, __FILE__, __LINE__) +#define MemSize(h) _dbgMemSize(h, __FILE__, __LINE__) +#define MemSizeRequested(h) _dbgMemSizeRequested(h, __FILE__, __LINE__) +#define MemLockCount(h) _dbgMemLockCount(h, __FILE__, __LINE__) +#define MemIsMoveable(h) _dbgMemIsMoveable(h, __FILE__, __LINE__) +#define MemHandle(p) _dbgMemHandle(p, __FILE__, __LINE__) +#define MemAllocPtr(p, s, f) _dbgMemAllocPtr(p, s, f, __FILE__, __LINE__) +#define MemReAllocPtr(p, s, f) _dbgMemReAllocPtr(p, s, f, __FILE__,__LINE__) +#define MemFreePtr(p) _dbgMemFreePtr(p, __FILE__, __LINE__) +#define MemSizePtr(p) _dbgMemSizePtr(p, __FILE__, __LINE__) +#define MemCheckPtr(p, x) _dbgMemCheckPtr(p, x, __FILE__, __LINE__) +#define MemAllocFS(p) _dbgMemAllocFS(p, __FILE__, __LINE__) +#define MemFreeFS(p) _dbgMemFreeFS(p, __FILE__, __LINE__) + +#else /* MEM_DEBUG */ + +/* MEM_DEBUG not defined: define dbgMemXXX as no-op macros + * each macro returns "success" value when MEM_DEBUG not defined + */ +#ifndef dbgMemBreakpoint +#define dbgMemBreakpoint() ((void)0) +#define dbgMemCheckAll() 1 +#define dbgMemCheckPtr(p, f, s) 1 +#define dbgMemDeferFreeing(b) 1 +#define dbgMemFormatCall(i, b, s) 0 +#define dbgMemFormatErrorInfo(i, b, s) 0 +#define dbgMemPoolDeferFreeing(p, b) 1 +#define dbgMemFreeDeferred() 1 +#define dbgMemPoolFreeDeferred(p) 1 +#define dbgMemPoolInfo(p, b) 1 +#define dbgMemPoolSetCheckFrequency(p, f) 1 +#define dbgMemPoolSetDeferQueueLen(p, b) 1 +#define dbgMemPoolSetName(p, n) 1 +#define dbgMemProtectPtr(p, f) 1 +#define dbgMemPtrInfo(p, b) 1 +#define dbgMemReallocMoves(b) 1 +#define dbgMemReportLeakage(p, c1, c2) 1 +#define dbgMemReportWrongTaskRef(b) 1 +#define dbgMemScheduleChecking(b, p, i) 1 +#define dbgMemSetCheckFrequency(f) 1 +#define dbgMemSetCheckpoint(c) 1 +#define dbgMemSetDefaultErrorOutput(x, f) 1 +#define dbgMemSetDeferQueueLen(l) 1 +#define dbgMemSetDeferSizeThreshold(s) 1 +#define dbgMemSetEntryHandler(f) 0 +#define dbgMemSetExitHandler(f) 0 +#define dbgMemSetFreeFill(c) 1 +#define dbgMemSetGuardFill(c) 1 +#define dbgMemSetGuardSize(s) 1 +#define dbgMemSetInUseFill(c) 1 +#define dbgMemSetCallstackChains(s) 1 +#define dbgMemSetStackChecking(s) 1 +#define dbgMemSetSafetyLevel(s) 1 +#define dbgMemSettingsInfo(b) 1 +#define dbgMemSuppressFreeFill(b) 1 +#define dbgMemTotalCount() 1 +#define dbgMemTotalSize() 1 +#define dbgMemWalkHeap(b) MEM_POOL_OK +#endif /* dbgMemBreakpoint */ + +#endif /* MEM_DEBUG */ +#endif /* _SHI_dbgMacros */ + +#if defined(__WATCOMC__) && defined(__SW_3S) +/* Watcom stack calling convention */ + #pragma aux MemDefaultPool "_*"; + #pragma aux MemDefaultPoolBlockSizeFS "_*"; + #pragma aux MemDefaultPoolPageSize "_*"; + #pragma aux MemDefaultPoolFlags "_*"; + #pragma aux SmartHeap_malloc "_*"; + #pragma aux SmartHeap_far_malloc "_*"; + #pragma aux SmartHeap_new "_*"; +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !defined(_SMARTHEAP_PROT) */ diff --git a/3rdparty/smartheap/SMRTHEAP.HPP b/3rdparty/smartheap/SMRTHEAP.HPP new file mode 100644 index 00000000..f263f72e --- /dev/null +++ b/3rdparty/smartheap/SMRTHEAP.HPP @@ -0,0 +1,159 @@ +// smrtheap.hpp -- SmartHeap public C++ header file +// Professional Memory Management Library +// +// Copyright (C) 1991-1996 by Arthur D. Applegate +// All Rights Reserved. +// +// No part of this source code may be copied, modified or reproduced +// in any form without retaining the above copyright notice. +// This source code, or source code derived from it, may not be redistributed +// without express written permission of the author. +// +// COMMENTS: +// - Include this header file to call the SmartHeap-specific versions of +// operators new (i.e. with placement syntax), to: +// o allocate from a specific memory pool; +// o specify allocation flags, such as zero-initialization; +// o resize an allocation. +// +// - If you include this header file, you must compile and link shnew.cpp, or +// link with one of the SmartHeap static operator new libraries: +// sh[l|d]XXXX.lib +// +// - Can be used in both EXEs and DLLs. +// +// - For 16-bit x86 platforms, use only in large or compact memory model. +// +// - If you do not want to use SmartHeap's global operator new but you do +// want to use SmartHeap's other facilities in a C++ application, then +// include the smrtheap.h header file but do not include this header file, +// and do not link with shnew.cpp. The two ".Xpp" files are present +// ONLY for the purpose of defining operator new and operator delete. +// +// - Use the MemDefaultPool global variable to refer to a memory pool to pass +// to SmartHeap functions that accept a pool as a parameter, +// e.g. MemPoolCount, MemPoolSize, MemPoolWalk, etc. +// + +#if !defined(_SMARTHEAP_HPP) +#define _SMARTHEAP_HPP + +#if defined(_MSC_VER) \ + && (defined(M_I86LM) || defined(M_I86CM) || defined(M_I86HM)) \ + && !defined(MEM_HUGE) +#define MEM_HUGE 0x8000u +#endif + +#ifndef __BORLANDC__ +/* Borland C++ does not treat extern "C++" correctly */ +extern "C++" +{ +#endif /* __BORLANDC__ */ + +#if defined(_MSC_VER) && _MSC_VER >= 900 +#pragma warning(disable : 4507) +#endif + +#if defined(new) +#if defined(MEM_DEBUG) +#undef new +#endif +#endif + +#include + +#include "smrtheap.h" + +#if defined(new) +#if defined(MEM_DEBUG) +#undef new +#endif +#endif + +#if ((defined(__BORLANDC__) && (__BORLANDC__ >= 0x450)) \ + || (defined(__WATCOMC__) && __WATCOMC__ >= 1000) \ + || (defined(__IBMCPP__) && __IBMCPP__ >= 250)) +#define SHI_ARRAY_NEW 1 +#endif + +void MEM_FAR * MEM_ENTRY_ANSI shi_New(unsigned long sz, unsigned flags=0, MEM_POOL pool=0); + +// operator new variants: + + +// version of new that passes memory allocation flags +// (e.g. MEM_ZEROINIT to zero-initialize memory) +// call with syntax 'ptr = new (flags) ' +inline void MEM_FAR *operator new(size_t sz, unsigned flags) + { return shi_New(sz, flags); } + +// version of new that allocates from a specified memory pool with alloc flags +// call with the syntax 'ptr = new (pool, [flags=0]) ' +inline void MEM_FAR *operator new(size_t sz, MEM_POOL pool, unsigned flags=0) + { return shi_New(sz, flags, pool); } +#ifdef SHI_ARRAY_NEW +inline void MEM_FAR *operator new[](size_t sz, MEM_POOL pool, unsigned flags=0) + { return shi_New(sz, flags, pool); } +#endif + +// version of new that changes the size of a memory block previously allocated +// from an SmartHeap memory pool +// call with the syntax 'ptr = new (ptr, flags) ' +#if !defined(MEM_DEBUG) || !defined(__HIGHC__) +/* bug in MetaWare High C++ parser confuses this with new(file,line) */ +inline void MEM_FAR *operator new(size_t new_sz, void MEM_FAR *lpMem, + unsigned flags) + { return MemReAllocPtr(lpMem, new_sz, flags); } +#ifdef SHI_ARRAY_NEW +inline void MEM_FAR *operator new[](size_t new_sz, void MEM_FAR *lpMem, + unsigned flags) + { return MemReAllocPtr(lpMem, new_sz, flags); } +#endif // SHI_ARRAY_NEW +#endif + + +// new_handler prototypes: note that MSC/C++ prototype differs from the +// protosed ANSI standard prototype for set_new_handler +#ifdef __MWERKS__ +#define MEM_CPP_THROW throw() +#else +#define MEM_CPP_THROW +#endif // __MWERKS__ +#ifndef _CRTIMP +#define _CRTIMP +#endif // _CRTIMP +#ifdef _MSC_VER +_CRTIMP _PNH MEM_ENTRY_ANSI _set_new_handler(_PNH); +#if UINT_MAX == 0xFFFFu +_PNH MEM_ENTRY_ANSI _set_fnew_handler(_PNH); +_PNHH MEM_ENTRY_ANSI _set_hnew_handler(_PNHH); +#endif // UINT_MAX +#endif // _MSC_VER +typedef void (MEM_ENTRY_ANSI * pnh)(); +_CRTIMP pnh MEM_ENTRY_ANSI set_new_handler(pnh) MEM_CPP_THROW; + +#ifndef DBG_FORMAL +#define DBG_FORMAL +#define DBG_ACTUAL +#ifndef DEBUG_NEW +#define DEBUG_NEW new +#endif // DEBUG_NEW +#define DEBUG_NEW1(x_) new(x_) +#define DEBUG_NEW2(x_, y_) new(x_, y_) +#define DEBUG_NEW3(x_, y_, z_) new(x_, y_, z_) +#define DEBUG_DELETE delete +#endif + +#ifdef DEFINE_NEW_MACRO +#define new DEBUG_NEW +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 900 +#pragma warning(default : 4507) +#endif + +#ifndef __BORLANDC__ +} +#endif /* __BORLANDC__ */ + +#endif /* !defined(_SMARTHEAP_HPP) */ diff --git a/3rdparty/vec/vec.h b/3rdparty/vec/vec.h new file mode 100644 index 00000000..b6ad4b0c --- /dev/null +++ b/3rdparty/vec/vec.h @@ -0,0 +1,1085 @@ +/* + * vec.h -- Vector macros for 2,3, and 4 dimensions, + * for any combination of C scalar types. + * + * Author: Don Hatch (hatch@sgi.com) + * Last modified: Fri Dec 15 01:57:07 PST 1995 + * + * General description: + * + * The macro name describes its arguments; e.g. + * MXS3 is "matrix times scalar in 3 dimensions"; + * VMV2 is "vector minus vector in 2 dimensions". + * + * If the result of an operation is a scalar, then the macro "returns" + * the value; e.g. + * result = DOT3(v,w); + * result = DET4(m); + * + * If the result of an operation is a vector or matrix, then + * the first argument is the destination; e.g. + * SET2(tovec, fromvec); + * MXM3(result, m1, m2); + * + * WARNING: For the operations that are not done "componentwise" + * (e.g. vector cross products and matrix multiplies) + * the destination should not be either of the arguments, + * for obvious reasons. For example, the following is wrong: + * VXM2(v,v,m); + * For such "unsafe" macros, there are safe versions provided, + * but you have to specify a type for the temporary + * result vector or matrix. For example, the safe versions + * of VXM2 are: + * VXM2d(v,v,m) if v's scalar type is double or float + * VXM2i(v,v,m) if v's scalar type is int or char + * VXM2l(v,v,m) if v's scalar type is long + * VXM2r(v,v,m) if v's scalar type is real + * VXM2safe(type,v,v,m) for other scalar types. + * + * These "safe" macros and INVERTMAT do not evaluate to C expressions + * (so, for example, they can't be used inside the parentheses of + * a for(...)). + * + * Specific descriptions: + * + * The "?"'s in the following can be 2, 3, or 4. + * + * EXPAND?(v) comma-separated list of elements of v + * + * SET?(to,from) to = from + * SETMAT?(to,from) to = from + * ROUNDVEC?(to,from) to = from with entries rounded + * to nearest integer + * ROUNDMAT?(to,from) to = from with entries rounded + * to nearest integer + * FILLVEC?(v,s) set each entry of vector v to be s + * FILLMAT?(m,s) set each entry of matrix m to be s + * ZEROVEC?(v) v = 0 + * ISZEROVEC?(v) v == 0 + * EQVEC?(v,w) v == w + * EQMAT?(m1,m2) m1 == m2 + * ZEROMAT?(m) m = 0 + * IDENTMAT?(m) m = 1 + * TRANSPOSE?(to,from) (matrix to) = (transpose of matrix from) + * ADJOINT?(to,from) (matrix to) = (adjoint of matrix from) + * i.e. its determinant times its inverse + * INVERTMAT?{d,i,l,r}(to,from) (matrix to) = (inverse of matrix from) + * with temp adjoint and determinant type + * double, int, long, or real respectively + * + * V{P,M}V?(to,v,w) to = v {+,-} w + * M{P,M}M?(to,m1,m2) to = m1 {+,-} m2 + * SX{V,M}?(to,s,from) to = s * from + * VPSXV?(to,v,s,w) to = v + s*w + * VPVXS?(to,v,w,s) to = v + w*s + * M{V,M}?(to,from) to = -from + * {V,M}{X,D}S?(to,from,s) to = from {*,/} s + * MXM?(to,m1,m2) to = m1 * m2 + * VXM?(to,v,m) (row vec to) = (row vec v) * m + * MXV?(to,m,v) (column vec to) = m * (column vec v) + * VMODS?(to,v,s) to = v mod s (always >= 0) + * VMODV?(to,v0,v1) to = v0 mod v1 componentwise + * VDIVS?(to,v,s) to = (v-(v mod s))/s + * VDIVV?(to,v0,v1) to = (v0-(v0 mod v1))/v1 componentwise + * V{MIN,MAX}S?(to,v,s) to = {MIN,MAX}(v, s) + * V{MIN,MAX}V?(to,v0,v1) to = {MIN,MAX}(v0, v1) + * LERP?(to,v0,v1,t) to = v0 + t*(v1-v0) + * + * DET?(m) determinant of m + * TRACE?(m) trace (sum of diagonal entries) of m + * DOT?(v,w) dot (scalar) product of v and w + * NORMSQRD?(v) square of |v| + * DISTSQRD?(v,w) square of |v-w| + * + * XV2(to,v) to = v rotated by 90 degrees + * VXV3(to,v1,v2) to = cross (vector) product of v1 and v2 + * VXVXV4(to,v1,v2,v3) to = 4-dimensional vector cross product + * of v1,v2,v3 (a vector orthogonal to + * v1,v2,v3 whose length equals the + * volume of the spanned parallelotope) + * VXV2(v0,v1) determinant of matrix with rows v0,v1 + * VXVXV3(v0,v1,v2) determinant of matrix with rows v0,v1,v2 + * VXVXVXV4(v0,v1,v2,v3) determinant of matrix with rows v0,..,v3 + * + * The following macros mix objects from different dimensions. + * For example, V3XM4 would be used to apply a composite + * 4x4 rotation-and-translation matrix to a 3d vector. + * + * SET3from2(to,from,pad) (3d vec to) = (2d vec from) with pad + * SET4from3(to,from,pad) (4d vec to) = (3d vec from) with pad + * SETMAT3from2(to,from,pad0,pad1) (3x3 mat to) = (2x2 mat from) + * padded with pad0 on the sides + * and pad1 in the corner + * SETMAT4from3(to,from,pad0,pad1) (4x4 mat to) = (3x3 mat from) + * padded with pad0 on the sides + * and pad1 in the corner + * V2XM3(to2,v2,m3) (2d row vec to2) = (2d row vec v2) * (3x3 mat m3) + * V3XM4(to3,v3,m4) (3d row vec to3) = (3d row vec v2) * (4x4 mat m4) + * M3XV2(to2,m3,v2) (2d col vec to2) = (3x3 mat m3) * (2d col vec v2) + * M4XV3(to3,m4,v3) (3d col vec to3) = (4x4 mat m4) * (3d col vec v3) + * M2XM3(to3,m2,m3) (3x3 mat to3) = (2x2 mat m2) * (3x3 mat m3) + * M3XM4(to4,m3,m4) (4x4 mat to4) = (3x3 mat m3) * (4x4 mat m4) + * M3XM2(to3,m3,m2) (3x3 mat to3) = (3x3 mat m3) * (2x2 mat m2) + * M4XM3(to4,m4,m3) (4x4 mat to4) = (4x4 mat m4) * (3x3 mat m3) + * + * + * This file is machine-generated and can be regenerated + * for any number of dimensions. + * The program that generated it is available upon request. + */ + +#ifndef VEC_H +#define VEC_H 4 +#include /* for definition of floor() */ +#define EXPAND2(v) (v)[0], (v)[1] +#define EXPAND3(v) (v)[0], (v)[1], (v)[2] +#define EXPAND4(v) (v)[0], (v)[1], (v)[2], (v)[3] +#define SET2(to,from) \ + ((to)[0] = (from)[0], \ + (to)[1] = (from)[1]) +#define SETMAT2(to,from) \ + (SET2((to)[0], (from)[0]), \ + SET2((to)[1], (from)[1])) +#define ROUNDVEC2(to,from) \ + ((to)[0] = floor((from)[0]+.5), \ + (to)[1] = floor((from)[1]+.5)) +#define ROUNDMAT2(to,from) \ + (ROUNDVEC2((to)[0], (from)[0]), \ + ROUNDVEC2((to)[1], (from)[1])) +#define FILLVEC2(v,s) \ + ((v)[0] = (s), \ + (v)[1] = (s)) +#define FILLMAT2(m,s) \ + (FILLVEC2((m)[0], s), \ + FILLVEC2((m)[1], s)) +#define ZEROVEC2(v) \ + ((v)[0] = 0, \ + (v)[1] = 0) +#define ISZEROVEC2(v) \ + ((v)[0] == 0 && \ + (v)[1] == 0) +#define EQVEC2(v,w) \ + ((v)[0] == (w)[0] && \ + (v)[1] == (w)[1]) +#define EQMAT2(m1,m2) \ + (EQVEC2((m1)[0], (m2)[0]) && \ + EQVEC2((m1)[1], (m2)[1])) +#define ZEROMAT2(m) \ + (ZEROVEC2((m)[0]), \ + ZEROVEC2((m)[1])) +#define IDENTMAT2(m) \ + (ZEROVEC2((m)[0]), (m)[0][0]=1, \ + ZEROVEC2((m)[1]), (m)[1][1]=1) +#define TRANSPOSE2(to,from) \ + (_SETcol2((to)[0], from, 0), \ + _SETcol2((to)[1], from, 1)) +#define VPSXV2(to,v,s,w) \ + ((to)[0] = (v)[0] + (s) * (w)[0], \ + (to)[1] = (v)[1] + (s) * (w)[1]) +#define VPVXS2(to,v,w,s) \ + ((to)[0] = (v)[0] + (w)[0] * (s), \ + (to)[1] = (v)[1] + (w)[1] * (s)) +#define VPV2(to,v,w) \ + ((to)[0] = (v)[0] + (w)[0], \ + (to)[1] = (v)[1] + (w)[1]) +#define VMV2(to,v,w) \ + ((to)[0] = (v)[0] - (w)[0], \ + (to)[1] = (v)[1] - (w)[1]) +#define MPM2(to,m1,m2) \ + (VPV2((to)[0], (m1)[0], (m2)[0]), \ + VPV2((to)[1], (m1)[1], (m2)[1])) +#define MMM2(to,m1,m2) \ + (VMV2((to)[0], (m1)[0], (m2)[0]), \ + VMV2((to)[1], (m1)[1], (m2)[1])) +#define SXV2(to,s,from) \ + ((to)[0] = (s) * (from)[0], \ + (to)[1] = (s) * (from)[1]) +#define SXM2(to,s,from) \ + (SXV2((to)[0], s, (from)[0]), \ + SXV2((to)[1], s, (from)[1])) +#define MV2(to,from) \ + ((to)[0] = -(from)[0], \ + (to)[1] = -(from)[1]) +#define MM2(to,from) \ + (MV2((to)[0], (from)[0]), \ + MV2((to)[1], (from)[1])) +#define VXS2(to,from,s) \ + ((to)[0] = (from)[0] * (s), \ + (to)[1] = (from)[1] * (s)) +#define VDS2(to,from,s) \ + ((to)[0] = (from)[0] / (s), \ + (to)[1] = (from)[1] / (s)) +#define MXS2(to,from,s) \ + (VXS2((to)[0], (from)[0], s), \ + VXS2((to)[1], (from)[1], s)) +#define MDS2(to,from,s) \ + (VDS2((to)[0], (from)[0], s), \ + VDS2((to)[1], (from)[1], s)) +#define MXM2(to,m1,m2) \ + (VXM2((to)[0], (m1)[0], m2), \ + VXM2((to)[1], (m1)[1], m2)) +#define VXM2(to,v,m) \ + ((to)[0] = _DOTcol2(v, m, 0), \ + (to)[1] = _DOTcol2(v, m, 1)) +#define MXV2(to,m,v) \ + ((to)[0] = DOT2((m)[0], v), \ + (to)[1] = DOT2((m)[1], v)) +#define VMODS2(to,v,s) \ + ((to)[0] = SMODS1((v)[0], s), \ + (to)[1] = SMODS1((v)[1], s)) +#define VMODV2(to,v0,v1) \ + ((to)[0] = SMODS1((v0)[0], (v1)[0]), \ + (to)[1] = SMODS1((v0)[1], (v1)[1])) +#define VDIVS2(to,v,s) \ + ((to)[0] = SDIVS1((v)[0], s), \ + (to)[1] = SDIVS1((v)[1], s)) +#define VDIVV2(to,v0,v1) \ + ((to)[0] = SDIVS1((v0)[0], (v1)[0]), \ + (to)[1] = SDIVS1((v0)[1], (v1)[1])) +#define VMINS2(to,v,s) \ + ((to)[0] = SMINS1((v)[0], s), \ + (to)[1] = SMINS1((v)[1], s)) +#define VMINV2(to,v0,v1) \ + ((to)[0] = SMINS1((v0)[0], (v1)[0]), \ + (to)[1] = SMINS1((v0)[1], (v1)[1])) +#define VMAXS2(to,v,s) \ + ((to)[0] = SMAXS1((v)[0], s), \ + (to)[1] = SMAXS1((v)[1], s)) +#define VMAXV2(to,v0,v1) \ + ((to)[0] = SMAXS1((v0)[0], (v1)[0]), \ + (to)[1] = SMAXS1((v0)[1], (v1)[1])) +#define LERP2(to,v0,v1,t) \ + ((to)[0]=(v0)[0]+(t)*((v1)[0]-(v0)[0]), \ + (to)[1]=(v0)[1]+(t)*((v1)[1]-(v0)[1])) +#define TRACE2(m) \ + ((m)[0][0] + \ + (m)[1][1]) +#define DOT2(v,w) \ + ((v)[0] * (w)[0] + \ + (v)[1] * (w)[1]) +#define NORMSQRD2(v) \ + ((v)[0] * (v)[0] + \ + (v)[1] * (v)[1]) +#define DISTSQRD2(v,w) \ + (((v)[0]-(w)[0])*((v)[0]-(w)[0]) + \ + ((v)[1]-(w)[1])*((v)[1]-(w)[1])) +#define _DOTcol2(v,m,j) \ + ((v)[0] * (m)[0][j] + \ + (v)[1] * (m)[1][j]) +#define _SETcol2(v,m,j) \ + ((v)[0] = (m)[0][j], \ + (v)[1] = (m)[1][j]) +#define _MXVcol2(to,m,M,j) \ + ((to)[0][j] = _DOTcol2((m)[0],M,j), \ + (to)[1][j] = _DOTcol2((m)[1],M,j)) +#define _DET2(v0,v1,i0,i1) \ + ((v0)[i0]* _DET1(v1,i1) + \ + (v0)[i1]*-_DET1(v1,i0)) +#define XV2(to,v1) \ + ((to)[0] = -_DET1(v1, 1), \ + (to)[1] = _DET1(v1, 0)) +#define V2XM3(to2,v2,m3) \ + ((to2)[0] = _DOTcol2(v2,m3,0) + (m3)[2][0], \ + (to2)[1] = _DOTcol2(v2,m3,1) + (m3)[2][1]) +#define M3XV2(to2,m3,v2) \ + ((to2)[0] = DOT2((m3)[0],v2) + (m3)[0][2], \ + (to2)[1] = DOT2((m3)[1],v2) + (m3)[1][2]) +#define _DET1(v0,i0) \ + ((v0)[i0]) +#define VXV2(v0,v1) \ + (_DET2(v0,v1,0,1)) +#define DET2(m) \ + (VXV2((m)[0],(m)[1])) +#define SMODS1(a,b) \ + ((((a)%(b)+(b))%(b))) +#define SDIVS1(a,b) \ + ((((a)-SMODS1(a,b))/(b))) +#define SMINS1(a,b) \ + (((a) < (b) ? (a) : (b))) +#define SMAXS1(a,b) \ + (((a) > (b) ? (a) : (b))) +#define ADJOINT2(to,m) \ + ( _ADJOINTcol2(to,0,m,1), \ + __ADJOINTcol2(to,1,m,0)) +#define _ADJOINTcol2(to,col,m,i1) \ + ((to)[0][col] = _DET1(m[i1], 1), \ + (to)[1][col] = -_DET1(m[i1], 0)) +#define __ADJOINTcol2(to,col,m,i1) \ + ((to)[0][col] = -_DET1(m[i1], 1), \ + (to)[1][col] = _DET1(m[i1], 0)) +#define SET3(to,from) \ + ((to)[0] = (from)[0], \ + (to)[1] = (from)[1], \ + (to)[2] = (from)[2]) +#define SETMAT3(to,from) \ + (SET3((to)[0], (from)[0]), \ + SET3((to)[1], (from)[1]), \ + SET3((to)[2], (from)[2])) +#define ROUNDVEC3(to,from) \ + ((to)[0] = floor((from)[0]+.5), \ + (to)[1] = floor((from)[1]+.5), \ + (to)[2] = floor((from)[2]+.5)) +#define ROUNDMAT3(to,from) \ + (ROUNDVEC3((to)[0], (from)[0]), \ + ROUNDVEC3((to)[1], (from)[1]), \ + ROUNDVEC3((to)[2], (from)[2])) +#define FILLVEC3(v,s) \ + ((v)[0] = (s), \ + (v)[1] = (s), \ + (v)[2] = (s)) +#define FILLMAT3(m,s) \ + (FILLVEC3((m)[0], s), \ + FILLVEC3((m)[1], s), \ + FILLVEC3((m)[2], s)) +#define ZEROVEC3(v) \ + ((v)[0] = 0, \ + (v)[1] = 0, \ + (v)[2] = 0) +#define ISZEROVEC3(v) \ + ((v)[0] == 0 && \ + (v)[1] == 0 && \ + (v)[2] == 0) +#define EQVEC3(v,w) \ + ((v)[0] == (w)[0] && \ + (v)[1] == (w)[1] && \ + (v)[2] == (w)[2]) +#define EQMAT3(m1,m2) \ + (EQVEC3((m1)[0], (m2)[0]) && \ + EQVEC3((m1)[1], (m2)[1]) && \ + EQVEC3((m1)[2], (m2)[2])) +#define ZEROMAT3(m) \ + (ZEROVEC3((m)[0]), \ + ZEROVEC3((m)[1]), \ + ZEROVEC3((m)[2])) +#define IDENTMAT3(m) \ + (ZEROVEC3((m)[0]), (m)[0][0]=1, \ + ZEROVEC3((m)[1]), (m)[1][1]=1, \ + ZEROVEC3((m)[2]), (m)[2][2]=1) +#define TRANSPOSE3(to,from) \ + (_SETcol3((to)[0], from, 0), \ + _SETcol3((to)[1], from, 1), \ + _SETcol3((to)[2], from, 2)) +#define VPSXV3(to,v,s,w) \ + ((to)[0] = (v)[0] + (s) * (w)[0], \ + (to)[1] = (v)[1] + (s) * (w)[1], \ + (to)[2] = (v)[2] + (s) * (w)[2]) +#define VPVXS3(to,v,w,s) \ + ((to)[0] = (v)[0] + (w)[0] * (s), \ + (to)[1] = (v)[1] + (w)[1] * (s), \ + (to)[2] = (v)[2] + (w)[2] * (s)) +#define VPV3(to,v,w) \ + ((to)[0] = (v)[0] + (w)[0], \ + (to)[1] = (v)[1] + (w)[1], \ + (to)[2] = (v)[2] + (w)[2]) +#define VMV3(to,v,w) \ + ((to)[0] = (v)[0] - (w)[0], \ + (to)[1] = (v)[1] - (w)[1], \ + (to)[2] = (v)[2] - (w)[2]) +#define MPM3(to,m1,m2) \ + (VPV3((to)[0], (m1)[0], (m2)[0]), \ + VPV3((to)[1], (m1)[1], (m2)[1]), \ + VPV3((to)[2], (m1)[2], (m2)[2])) +#define MMM3(to,m1,m2) \ + (VMV3((to)[0], (m1)[0], (m2)[0]), \ + VMV3((to)[1], (m1)[1], (m2)[1]), \ + VMV3((to)[2], (m1)[2], (m2)[2])) +#define SXV3(to,s,from) \ + ((to)[0] = (s) * (from)[0], \ + (to)[1] = (s) * (from)[1], \ + (to)[2] = (s) * (from)[2]) +#define SXM3(to,s,from) \ + (SXV3((to)[0], s, (from)[0]), \ + SXV3((to)[1], s, (from)[1]), \ + SXV3((to)[2], s, (from)[2])) +#define MV3(to,from) \ + ((to)[0] = -(from)[0], \ + (to)[1] = -(from)[1], \ + (to)[2] = -(from)[2]) +#define MM3(to,from) \ + (MV3((to)[0], (from)[0]), \ + MV3((to)[1], (from)[1]), \ + MV3((to)[2], (from)[2])) +#define VXS3(to,from,s) \ + ((to)[0] = (from)[0] * (s), \ + (to)[1] = (from)[1] * (s), \ + (to)[2] = (from)[2] * (s)) +#define VDS3(to,from,s) \ + ((to)[0] = (from)[0] / (s), \ + (to)[1] = (from)[1] / (s), \ + (to)[2] = (from)[2] / (s)) +#define MXS3(to,from,s) \ + (VXS3((to)[0], (from)[0], s), \ + VXS3((to)[1], (from)[1], s), \ + VXS3((to)[2], (from)[2], s)) +#define MDS3(to,from,s) \ + (VDS3((to)[0], (from)[0], s), \ + VDS3((to)[1], (from)[1], s), \ + VDS3((to)[2], (from)[2], s)) +#define MXM3(to,m1,m2) \ + (VXM3((to)[0], (m1)[0], m2), \ + VXM3((to)[1], (m1)[1], m2), \ + VXM3((to)[2], (m1)[2], m2)) +#define VXM3(to,v,m) \ + ((to)[0] = _DOTcol3(v, m, 0), \ + (to)[1] = _DOTcol3(v, m, 1), \ + (to)[2] = _DOTcol3(v, m, 2)) +#define MXV3(to,m,v) \ + ((to)[0] = DOT3((m)[0], v), \ + (to)[1] = DOT3((m)[1], v), \ + (to)[2] = DOT3((m)[2], v)) +#define VMODS3(to,v,s) \ + ((to)[0] = SMODS1((v)[0], s), \ + (to)[1] = SMODS1((v)[1], s), \ + (to)[2] = SMODS1((v)[2], s)) +#define VMODV3(to,v0,v1) \ + ((to)[0] = SMODS1((v0)[0], (v1)[0]), \ + (to)[1] = SMODS1((v0)[1], (v1)[1]), \ + (to)[2] = SMODS1((v0)[2], (v1)[2])) +#define VDIVS3(to,v,s) \ + ((to)[0] = SDIVS1((v)[0], s), \ + (to)[1] = SDIVS1((v)[1], s), \ + (to)[2] = SDIVS1((v)[2], s)) +#define VDIVV3(to,v0,v1) \ + ((to)[0] = SDIVS1((v0)[0], (v1)[0]), \ + (to)[1] = SDIVS1((v0)[1], (v1)[1]), \ + (to)[2] = SDIVS1((v0)[2], (v1)[2])) +#define VMINS3(to,v,s) \ + ((to)[0] = SMINS1((v)[0], s), \ + (to)[1] = SMINS1((v)[1], s), \ + (to)[2] = SMINS1((v)[2], s)) +#define VMINV3(to,v0,v1) \ + ((to)[0] = SMINS1((v0)[0], (v1)[0]), \ + (to)[1] = SMINS1((v0)[1], (v1)[1]), \ + (to)[2] = SMINS1((v0)[2], (v1)[2])) +#define VMAXS3(to,v,s) \ + ((to)[0] = SMAXS1((v)[0], s), \ + (to)[1] = SMAXS1((v)[1], s), \ + (to)[2] = SMAXS1((v)[2], s)) +#define VMAXV3(to,v0,v1) \ + ((to)[0] = SMAXS1((v0)[0], (v1)[0]), \ + (to)[1] = SMAXS1((v0)[1], (v1)[1]), \ + (to)[2] = SMAXS1((v0)[2], (v1)[2])) +#define LERP3(to,v0,v1,t) \ + ((to)[0]=(v0)[0]+(t)*((v1)[0]-(v0)[0]), \ + (to)[1]=(v0)[1]+(t)*((v1)[1]-(v0)[1]), \ + (to)[2]=(v0)[2]+(t)*((v1)[2]-(v0)[2])) +#define TRACE3(m) \ + ((m)[0][0] + \ + (m)[1][1] + \ + (m)[2][2]) +#define DOT3(v,w) \ + ((v)[0] * (w)[0] + \ + (v)[1] * (w)[1] + \ + (v)[2] * (w)[2]) +#define NORMSQRD3(v) \ + ((v)[0] * (v)[0] + \ + (v)[1] * (v)[1] + \ + (v)[2] * (v)[2]) +#define DISTSQRD3(v,w) \ + (((v)[0]-(w)[0])*((v)[0]-(w)[0]) + \ + ((v)[1]-(w)[1])*((v)[1]-(w)[1]) + \ + ((v)[2]-(w)[2])*((v)[2]-(w)[2])) +#define _DOTcol3(v,m,j) \ + ((v)[0] * (m)[0][j] + \ + (v)[1] * (m)[1][j] + \ + (v)[2] * (m)[2][j]) +#define _SETcol3(v,m,j) \ + ((v)[0] = (m)[0][j], \ + (v)[1] = (m)[1][j], \ + (v)[2] = (m)[2][j]) +#define _MXVcol3(to,m,M,j) \ + ((to)[0][j] = _DOTcol3((m)[0],M,j), \ + (to)[1][j] = _DOTcol3((m)[1],M,j), \ + (to)[2][j] = _DOTcol3((m)[2],M,j)) +#define _DET3(v0,v1,v2,i0,i1,i2) \ + ((v0)[i0]* _DET2(v1,v2,i1,i2) + \ + (v0)[i1]*-_DET2(v1,v2,i0,i2) + \ + (v0)[i2]* _DET2(v1,v2,i0,i1)) +#define VXV3(to,v1,v2) \ + ((to)[0] = _DET2(v1,v2, 1,2), \ + (to)[1] = -_DET2(v1,v2, 0,2), \ + (to)[2] = _DET2(v1,v2, 0,1)) +#define SET3from2(to,from,pad) \ + ((to)[0] = (from)[0], \ + (to)[1] = (from)[1], \ + (to)[2] = (pad)) +#define SETMAT3from2(to,from,pad0,pad1) \ + (SET3from2((to)[0], (from)[0], pad0), \ + SET3from2((to)[1], (from)[1], pad0), \ + FILLVEC2((to)[2], (pad0)), (to)[2][2] = (pad1)) +#define M2XM3(to3,m2,m3) \ + (_MXVcol2(to3,m2,m3,0), (to3)[2][0]=(m3)[2][0], \ + _MXVcol2(to3,m2,m3,1), (to3)[2][1]=(m3)[2][1], \ + _MXVcol2(to3,m2,m3,2), (to3)[2][2]=(m3)[2][2]) +#define M3XM2(to3,m3,m2) \ + (VXM2((to3)[0],(m3)[0],m2), (to3)[0][2]=(m3)[0][2], \ + VXM2((to3)[1],(m3)[1],m2), (to3)[1][2]=(m3)[1][2], \ + VXM2((to3)[2],(m3)[2],m2), (to3)[2][2]=(m3)[2][2]) +#define V3XM4(to3,v3,m4) \ + ((to3)[0] = _DOTcol3(v3,m4,0) + (m4)[3][0], \ + (to3)[1] = _DOTcol3(v3,m4,1) + (m4)[3][1], \ + (to3)[2] = _DOTcol3(v3,m4,2) + (m4)[3][2]) +#define M4XV3(to3,m4,v3) \ + ((to3)[0] = DOT3((m4)[0],v3) + (m4)[0][3], \ + (to3)[1] = DOT3((m4)[1],v3) + (m4)[1][3], \ + (to3)[2] = DOT3((m4)[2],v3) + (m4)[2][3]) +#define VXVXV3(v0,v1,v2) \ + (_DET3(v0,v1,v2,0,1,2)) +#define DET3(m) \ + (VXVXV3((m)[0],(m)[1],(m)[2])) +#define ADJOINT3(to,m) \ + ( _ADJOINTcol3(to,0,m,1,2), \ + __ADJOINTcol3(to,1,m,0,2), \ + _ADJOINTcol3(to,2,m,0,1)) +#define _ADJOINTcol3(to,col,m,i1,i2) \ + ((to)[0][col] = _DET2(m[i1],m[i2], 1,2), \ + (to)[1][col] = -_DET2(m[i1],m[i2], 0,2), \ + (to)[2][col] = _DET2(m[i1],m[i2], 0,1)) +#define __ADJOINTcol3(to,col,m,i1,i2) \ + ((to)[0][col] = -_DET2(m[i1],m[i2], 1,2), \ + (to)[1][col] = _DET2(m[i1],m[i2], 0,2), \ + (to)[2][col] = -_DET2(m[i1],m[i2], 0,1)) +#define SET4(to,from) \ + ((to)[0] = (from)[0], \ + (to)[1] = (from)[1], \ + (to)[2] = (from)[2], \ + (to)[3] = (from)[3]) +#define SETMAT4(to,from) \ + (SET4((to)[0], (from)[0]), \ + SET4((to)[1], (from)[1]), \ + SET4((to)[2], (from)[2]), \ + SET4((to)[3], (from)[3])) +#define ROUNDVEC4(to,from) \ + ((to)[0] = floor((from)[0]+.5), \ + (to)[1] = floor((from)[1]+.5), \ + (to)[2] = floor((from)[2]+.5), \ + (to)[3] = floor((from)[3]+.5)) +#define ROUNDMAT4(to,from) \ + (ROUNDVEC4((to)[0], (from)[0]), \ + ROUNDVEC4((to)[1], (from)[1]), \ + ROUNDVEC4((to)[2], (from)[2]), \ + ROUNDVEC4((to)[3], (from)[3])) +#define FILLVEC4(v,s) \ + ((v)[0] = (s), \ + (v)[1] = (s), \ + (v)[2] = (s), \ + (v)[3] = (s)) +#define FILLMAT4(m,s) \ + (FILLVEC4((m)[0], s), \ + FILLVEC4((m)[1], s), \ + FILLVEC4((m)[2], s), \ + FILLVEC4((m)[3], s)) +#define ZEROVEC4(v) \ + ((v)[0] = 0, \ + (v)[1] = 0, \ + (v)[2] = 0, \ + (v)[3] = 0) +#define ISZEROVEC4(v) \ + ((v)[0] == 0 && \ + (v)[1] == 0 && \ + (v)[2] == 0 && \ + (v)[3] == 0) +#define EQVEC4(v,w) \ + ((v)[0] == (w)[0] && \ + (v)[1] == (w)[1] && \ + (v)[2] == (w)[2] && \ + (v)[3] == (w)[3]) +#define EQMAT4(m1,m2) \ + (EQVEC4((m1)[0], (m2)[0]) && \ + EQVEC4((m1)[1], (m2)[1]) && \ + EQVEC4((m1)[2], (m2)[2]) && \ + EQVEC4((m1)[3], (m2)[3])) +#define ZEROMAT4(m) \ + (ZEROVEC4((m)[0]), \ + ZEROVEC4((m)[1]), \ + ZEROVEC4((m)[2]), \ + ZEROVEC4((m)[3])) +#define IDENTMAT4(m) \ + (ZEROVEC4((m)[0]), (m)[0][0]=1, \ + ZEROVEC4((m)[1]), (m)[1][1]=1, \ + ZEROVEC4((m)[2]), (m)[2][2]=1, \ + ZEROVEC4((m)[3]), (m)[3][3]=1) +#define TRANSPOSE4(to,from) \ + (_SETcol4((to)[0], from, 0), \ + _SETcol4((to)[1], from, 1), \ + _SETcol4((to)[2], from, 2), \ + _SETcol4((to)[3], from, 3)) +#define VPSXV4(to,v,s,w) \ + ((to)[0] = (v)[0] + (s) * (w)[0], \ + (to)[1] = (v)[1] + (s) * (w)[1], \ + (to)[2] = (v)[2] + (s) * (w)[2], \ + (to)[3] = (v)[3] + (s) * (w)[3]) +#define VPVXS4(to,v,w,s) \ + ((to)[0] = (v)[0] + (w)[0] * (s), \ + (to)[1] = (v)[1] + (w)[1] * (s), \ + (to)[2] = (v)[2] + (w)[2] * (s), \ + (to)[3] = (v)[3] + (w)[3] * (s)) +#define VPV4(to,v,w) \ + ((to)[0] = (v)[0] + (w)[0], \ + (to)[1] = (v)[1] + (w)[1], \ + (to)[2] = (v)[2] + (w)[2], \ + (to)[3] = (v)[3] + (w)[3]) +#define VMV4(to,v,w) \ + ((to)[0] = (v)[0] - (w)[0], \ + (to)[1] = (v)[1] - (w)[1], \ + (to)[2] = (v)[2] - (w)[2], \ + (to)[3] = (v)[3] - (w)[3]) +#define MPM4(to,m1,m2) \ + (VPV4((to)[0], (m1)[0], (m2)[0]), \ + VPV4((to)[1], (m1)[1], (m2)[1]), \ + VPV4((to)[2], (m1)[2], (m2)[2]), \ + VPV4((to)[3], (m1)[3], (m2)[3])) +#define MMM4(to,m1,m2) \ + (VMV4((to)[0], (m1)[0], (m2)[0]), \ + VMV4((to)[1], (m1)[1], (m2)[1]), \ + VMV4((to)[2], (m1)[2], (m2)[2]), \ + VMV4((to)[3], (m1)[3], (m2)[3])) +#define SXV4(to,s,from) \ + ((to)[0] = (s) * (from)[0], \ + (to)[1] = (s) * (from)[1], \ + (to)[2] = (s) * (from)[2], \ + (to)[3] = (s) * (from)[3]) +#define SXM4(to,s,from) \ + (SXV4((to)[0], s, (from)[0]), \ + SXV4((to)[1], s, (from)[1]), \ + SXV4((to)[2], s, (from)[2]), \ + SXV4((to)[3], s, (from)[3])) +#define MV4(to,from) \ + ((to)[0] = -(from)[0], \ + (to)[1] = -(from)[1], \ + (to)[2] = -(from)[2], \ + (to)[3] = -(from)[3]) +#define MM4(to,from) \ + (MV4((to)[0], (from)[0]), \ + MV4((to)[1], (from)[1]), \ + MV4((to)[2], (from)[2]), \ + MV4((to)[3], (from)[3])) +#define VXS4(to,from,s) \ + ((to)[0] = (from)[0] * (s), \ + (to)[1] = (from)[1] * (s), \ + (to)[2] = (from)[2] * (s), \ + (to)[3] = (from)[3] * (s)) +#define VDS4(to,from,s) \ + ((to)[0] = (from)[0] / (s), \ + (to)[1] = (from)[1] / (s), \ + (to)[2] = (from)[2] / (s), \ + (to)[3] = (from)[3] / (s)) +#define MXS4(to,from,s) \ + (VXS4((to)[0], (from)[0], s), \ + VXS4((to)[1], (from)[1], s), \ + VXS4((to)[2], (from)[2], s), \ + VXS4((to)[3], (from)[3], s)) +#define MDS4(to,from,s) \ + (VDS4((to)[0], (from)[0], s), \ + VDS4((to)[1], (from)[1], s), \ + VDS4((to)[2], (from)[2], s), \ + VDS4((to)[3], (from)[3], s)) +#define MXM4(to,m1,m2) \ + (VXM4((to)[0], (m1)[0], m2), \ + VXM4((to)[1], (m1)[1], m2), \ + VXM4((to)[2], (m1)[2], m2), \ + VXM4((to)[3], (m1)[3], m2)) +#define VXM4(to,v,m) \ + ((to)[0] = _DOTcol4(v, m, 0), \ + (to)[1] = _DOTcol4(v, m, 1), \ + (to)[2] = _DOTcol4(v, m, 2), \ + (to)[3] = _DOTcol4(v, m, 3)) +#define MXV4(to,m,v) \ + ((to)[0] = DOT4((m)[0], v), \ + (to)[1] = DOT4((m)[1], v), \ + (to)[2] = DOT4((m)[2], v), \ + (to)[3] = DOT4((m)[3], v)) +#define VMODS4(to,v,s) \ + ((to)[0] = SMODS1((v)[0], s), \ + (to)[1] = SMODS1((v)[1], s), \ + (to)[2] = SMODS1((v)[2], s), \ + (to)[3] = SMODS1((v)[3], s)) +#define VMODV4(to,v0,v1) \ + ((to)[0] = SMODS1((v0)[0], (v1)[0]), \ + (to)[1] = SMODS1((v0)[1], (v1)[1]), \ + (to)[2] = SMODS1((v0)[2], (v1)[2]), \ + (to)[3] = SMODS1((v0)[3], (v1)[3])) +#define VDIVS4(to,v,s) \ + ((to)[0] = SDIVS1((v)[0], s), \ + (to)[1] = SDIVS1((v)[1], s), \ + (to)[2] = SDIVS1((v)[2], s), \ + (to)[3] = SDIVS1((v)[3], s)) +#define VDIVV4(to,v0,v1) \ + ((to)[0] = SDIVS1((v0)[0], (v1)[0]), \ + (to)[1] = SDIVS1((v0)[1], (v1)[1]), \ + (to)[2] = SDIVS1((v0)[2], (v1)[2]), \ + (to)[3] = SDIVS1((v0)[3], (v1)[3])) +#define VMINS4(to,v,s) \ + ((to)[0] = SMINS1((v)[0], s), \ + (to)[1] = SMINS1((v)[1], s), \ + (to)[2] = SMINS1((v)[2], s), \ + (to)[3] = SMINS1((v)[3], s)) +#define VMINV4(to,v0,v1) \ + ((to)[0] = SMINS1((v0)[0], (v1)[0]), \ + (to)[1] = SMINS1((v0)[1], (v1)[1]), \ + (to)[2] = SMINS1((v0)[2], (v1)[2]), \ + (to)[3] = SMINS1((v0)[3], (v1)[3])) +#define VMAXS4(to,v,s) \ + ((to)[0] = SMAXS1((v)[0], s), \ + (to)[1] = SMAXS1((v)[1], s), \ + (to)[2] = SMAXS1((v)[2], s), \ + (to)[3] = SMAXS1((v)[3], s)) +#define VMAXV4(to,v0,v1) \ + ((to)[0] = SMAXS1((v0)[0], (v1)[0]), \ + (to)[1] = SMAXS1((v0)[1], (v1)[1]), \ + (to)[2] = SMAXS1((v0)[2], (v1)[2]), \ + (to)[3] = SMAXS1((v0)[3], (v1)[3])) +#define LERP4(to,v0,v1,t) \ + ((to)[0]=(v0)[0]+(t)*((v1)[0]-(v0)[0]), \ + (to)[1]=(v0)[1]+(t)*((v1)[1]-(v0)[1]), \ + (to)[2]=(v0)[2]+(t)*((v1)[2]-(v0)[2]), \ + (to)[3]=(v0)[3]+(t)*((v1)[3]-(v0)[3])) +#define TRACE4(m) \ + ((m)[0][0] + \ + (m)[1][1] + \ + (m)[2][2] + \ + (m)[3][3]) +#define DOT4(v,w) \ + ((v)[0] * (w)[0] + \ + (v)[1] * (w)[1] + \ + (v)[2] * (w)[2] + \ + (v)[3] * (w)[3]) +#define NORMSQRD4(v) \ + ((v)[0] * (v)[0] + \ + (v)[1] * (v)[1] + \ + (v)[2] * (v)[2] + \ + (v)[3] * (v)[3]) +#define DISTSQRD4(v,w) \ + (((v)[0]-(w)[0])*((v)[0]-(w)[0]) + \ + ((v)[1]-(w)[1])*((v)[1]-(w)[1]) + \ + ((v)[2]-(w)[2])*((v)[2]-(w)[2]) + \ + ((v)[3]-(w)[3])*((v)[3]-(w)[3])) +#define _DOTcol4(v,m,j) \ + ((v)[0] * (m)[0][j] + \ + (v)[1] * (m)[1][j] + \ + (v)[2] * (m)[2][j] + \ + (v)[3] * (m)[3][j]) +#define _SETcol4(v,m,j) \ + ((v)[0] = (m)[0][j], \ + (v)[1] = (m)[1][j], \ + (v)[2] = (m)[2][j], \ + (v)[3] = (m)[3][j]) +#define _MXVcol4(to,m,M,j) \ + ((to)[0][j] = _DOTcol4((m)[0],M,j), \ + (to)[1][j] = _DOTcol4((m)[1],M,j), \ + (to)[2][j] = _DOTcol4((m)[2],M,j), \ + (to)[3][j] = _DOTcol4((m)[3],M,j)) +#define _DET4(v0,v1,v2,v3,i0,i1,i2,i3) \ + ((v0)[i0]* _DET3(v1,v2,v3,i1,i2,i3) + \ + (v0)[i1]*-_DET3(v1,v2,v3,i0,i2,i3) + \ + (v0)[i2]* _DET3(v1,v2,v3,i0,i1,i3) + \ + (v0)[i3]*-_DET3(v1,v2,v3,i0,i1,i2)) +#define VXVXV4(to,v1,v2,v3) \ + ((to)[0] = -_DET3(v1,v2,v3, 1,2,3), \ + (to)[1] = _DET3(v1,v2,v3, 0,2,3), \ + (to)[2] = -_DET3(v1,v2,v3, 0,1,3), \ + (to)[3] = _DET3(v1,v2,v3, 0,1,2)) +#define SET4from3(to,from,pad) \ + ((to)[0] = (from)[0], \ + (to)[1] = (from)[1], \ + (to)[2] = (from)[2], \ + (to)[3] = (pad)) +#define SETMAT4from3(to,from,pad0,pad1) \ + (SET4from3((to)[0], (from)[0], pad0), \ + SET4from3((to)[1], (from)[1], pad0), \ + SET4from3((to)[2], (from)[2], pad0), \ + FILLVEC3((to)[3], (pad0)), (to)[3][3] = (pad1)) +#define M3XM4(to4,m3,m4) \ + (_MXVcol3(to4,m3,m4,0), (to4)[3][0]=(m4)[3][0], \ + _MXVcol3(to4,m3,m4,1), (to4)[3][1]=(m4)[3][1], \ + _MXVcol3(to4,m3,m4,2), (to4)[3][2]=(m4)[3][2], \ + _MXVcol3(to4,m3,m4,3), (to4)[3][3]=(m4)[3][3]) +#define M4XM3(to4,m4,m3) \ + (VXM3((to4)[0],(m4)[0],m3), (to4)[0][3]=(m4)[0][3], \ + VXM3((to4)[1],(m4)[1],m3), (to4)[1][3]=(m4)[1][3], \ + VXM3((to4)[2],(m4)[2],m3), (to4)[2][3]=(m4)[2][3], \ + VXM3((to4)[3],(m4)[3],m3), (to4)[3][3]=(m4)[3][3]) +#define VXVXVXV4(v0,v1,v2,v3) \ + (_DET4(v0,v1,v2,v3,0,1,2,3)) +#define DET4(m) \ + (VXVXVXV4((m)[0],(m)[1],(m)[2],(m)[3])) +#define ADJOINT4(to,m) \ + ( _ADJOINTcol4(to,0,m,1,2,3), \ + __ADJOINTcol4(to,1,m,0,2,3), \ + _ADJOINTcol4(to,2,m,0,1,3), \ + __ADJOINTcol4(to,3,m,0,1,2)) +#define _ADJOINTcol4(to,col,m,i1,i2,i3) \ + ((to)[0][col] = _DET3(m[i1],m[i2],m[i3], 1,2,3), \ + (to)[1][col] = -_DET3(m[i1],m[i2],m[i3], 0,2,3), \ + (to)[2][col] = _DET3(m[i1],m[i2],m[i3], 0,1,3), \ + (to)[3][col] = -_DET3(m[i1],m[i2],m[i3], 0,1,2)) +#define __ADJOINTcol4(to,col,m,i1,i2,i3) \ + ((to)[0][col] = -_DET3(m[i1],m[i2],m[i3], 1,2,3), \ + (to)[1][col] = _DET3(m[i1],m[i2],m[i3], 0,2,3), \ + (to)[2][col] = -_DET3(m[i1],m[i2],m[i3], 0,1,3), \ + (to)[3][col] = _DET3(m[i1],m[i2],m[i3], 0,1,2)) +#define TRANSPOSE2safe(type,to,from) \ + do {type _vec_h_temp_[2][2]; \ + TRANSPOSE2(_vec_h_temp_,from); \ + SETMAT2(to, _vec_h_temp_); \ + } while (0) +#define TRANSPOSE2d(to,from) TRANSPOSE2safe(double,to,from) +#define TRANSPOSE2i(to,from) TRANSPOSE2safe(int,to,from) +#define TRANSPOSE2l(to,from) TRANSPOSE2safe(long,to,from) +#define TRANSPOSE2r(to,from) TRANSPOSE2safe(real,to,from) +#define MXM2safe(type,to,m1,m2) \ + do {type _vec_h_temp_[2][2]; \ + MXM2(_vec_h_temp_,m1,m2); \ + SETMAT2(to, _vec_h_temp_); \ + } while (0) +#define MXM2d(to,m1,m2) MXM2safe(double,to,m1,m2) +#define MXM2i(to,m1,m2) MXM2safe(int,to,m1,m2) +#define MXM2l(to,m1,m2) MXM2safe(long,to,m1,m2) +#define MXM2r(to,m1,m2) MXM2safe(real,to,m1,m2) +#define VXM2safe(type,to,v,m) \ + do {type _vec_h_temp_[2]; \ + VXM2(_vec_h_temp_,v,m); \ + SET2(to, _vec_h_temp_); \ + } while (0) +#define VXM2d(to,v,m) VXM2safe(double,to,v,m) +#define VXM2i(to,v,m) VXM2safe(int,to,v,m) +#define VXM2l(to,v,m) VXM2safe(long,to,v,m) +#define VXM2r(to,v,m) VXM2safe(real,to,v,m) +#define MXV2safe(type,to,m,v) \ + do {type _vec_h_temp_[2]; \ + MXV2(_vec_h_temp_,m,v); \ + SET2(to, _vec_h_temp_); \ + } while (0) +#define MXV2d(to,m,v) MXV2safe(double,to,m,v) +#define MXV2i(to,m,v) MXV2safe(int,to,m,v) +#define MXV2l(to,m,v) MXV2safe(long,to,m,v) +#define MXV2r(to,m,v) MXV2safe(real,to,m,v) +#define XV2safe(type,to,v1) \ + do {type _vec_h_temp_[2]; \ + XV2(_vec_h_temp_,v1); \ + SET2(to, _vec_h_temp_); \ + } while (0) +#define XV2d(to,v1) XV2safe(double,to,v1) +#define XV2i(to,v1) XV2safe(int,to,v1) +#define XV2l(to,v1) XV2safe(long,to,v1) +#define XV2r(to,v1) XV2safe(real,to,v1) +#define V2XM3safe(type,to2,v2,m3) \ + do {type _vec_h_temp_[2]; \ + V2XM3(_vec_h_temp_,v2,m3); \ + SET2(to2, _vec_h_temp_); \ + } while (0) +#define V2XM3d(to2,v2,m3) V2XM3safe(double,to2,v2,m3) +#define V2XM3i(to2,v2,m3) V2XM3safe(int,to2,v2,m3) +#define V2XM3l(to2,v2,m3) V2XM3safe(long,to2,v2,m3) +#define V2XM3r(to2,v2,m3) V2XM3safe(real,to2,v2,m3) +#define M3XV2safe(type,to2,m3,v2) \ + do {type _vec_h_temp_[2]; \ + M3XV2(_vec_h_temp_,m3,v2); \ + SET2(to2, _vec_h_temp_); \ + } while (0) +#define M3XV2d(to2,m3,v2) M3XV2safe(double,to2,m3,v2) +#define M3XV2i(to2,m3,v2) M3XV2safe(int,to2,m3,v2) +#define M3XV2l(to2,m3,v2) M3XV2safe(long,to2,m3,v2) +#define M3XV2r(to2,m3,v2) M3XV2safe(real,to2,m3,v2) +#define ADJOINT2safe(type,to,m) \ + do {type _vec_h_temp_[2][2]; \ + ADJOINT2(_vec_h_temp_,m); \ + SETMAT2(to, _vec_h_temp_); \ + } while (0) +#define ADJOINT2d(to,m) ADJOINT2safe(double,to,m) +#define ADJOINT2i(to,m) ADJOINT2safe(int,to,m) +#define ADJOINT2l(to,m) ADJOINT2safe(long,to,m) +#define ADJOINT2r(to,m) ADJOINT2safe(real,to,m) +#define INVERTMAT2safe(type,to,from) \ + do {type _vec_h_temp_[2][2]; \ + ADJOINT2(_vec_h_temp_, from); \ + type _vec_h_temp_invdet_ = (type)1/(type)DET2(from); \ + SXM2(to, _vec_h_temp_invdet_, _vec_h_temp_); \ + } while (0) +#define INVERTMAT2d(to,from) INVERTMAT2safe(double,to,from) +#define INVERTMAT2i(to,from) INVERTMAT2safe(int,to,from) +#define INVERTMAT2l(to,from) INVERTMAT2safe(long,to,from) +#define INVERTMAT2r(to,from) INVERTMAT2safe(real,to,from) +#define TRANSPOSE3safe(type,to,from) \ + do {type _vec_h_temp_[3][3]; \ + TRANSPOSE3(_vec_h_temp_,from); \ + SETMAT3(to, _vec_h_temp_); \ + } while (0) +#define TRANSPOSE3d(to,from) TRANSPOSE3safe(double,to,from) +#define TRANSPOSE3i(to,from) TRANSPOSE3safe(int,to,from) +#define TRANSPOSE3l(to,from) TRANSPOSE3safe(long,to,from) +#define TRANSPOSE3r(to,from) TRANSPOSE3safe(real,to,from) +#define MXM3safe(type,to,m1,m2) \ + do {type _vec_h_temp_[3][3]; \ + MXM3(_vec_h_temp_,m1,m2); \ + SETMAT3(to, _vec_h_temp_); \ + } while (0) +#define MXM3d(to,m1,m2) MXM3safe(double,to,m1,m2) +#define MXM3i(to,m1,m2) MXM3safe(int,to,m1,m2) +#define MXM3l(to,m1,m2) MXM3safe(long,to,m1,m2) +#define MXM3r(to,m1,m2) MXM3safe(real,to,m1,m2) +#define VXM3safe(type,to,v,m) \ + do {type _vec_h_temp_[3]; \ + VXM3(_vec_h_temp_,v,m); \ + SET3(to, _vec_h_temp_); \ + } while (0) +#define VXM3d(to,v,m) VXM3safe(double,to,v,m) +#define VXM3i(to,v,m) VXM3safe(int,to,v,m) +#define VXM3l(to,v,m) VXM3safe(long,to,v,m) +#define VXM3r(to,v,m) VXM3safe(real,to,v,m) +#define MXV3safe(type,to,m,v) \ + do {type _vec_h_temp_[3]; \ + MXV3(_vec_h_temp_,m,v); \ + SET3(to, _vec_h_temp_); \ + } while (0) +#define MXV3d(to,m,v) MXV3safe(double,to,m,v) +#define MXV3i(to,m,v) MXV3safe(int,to,m,v) +#define MXV3l(to,m,v) MXV3safe(long,to,m,v) +#define MXV3r(to,m,v) MXV3safe(real,to,m,v) +#define VXV3safe(type,to,v1,v2) \ + do {type _vec_h_temp_[3]; \ + VXV3(_vec_h_temp_,v1,v2); \ + SET3(to, _vec_h_temp_); \ + } while (0) +#define VXV3d(to,v1,v2) VXV3safe(double,to,v1,v2) +#define VXV3i(to,v1,v2) VXV3safe(int,to,v1,v2) +#define VXV3l(to,v1,v2) VXV3safe(long,to,v1,v2) +#define VXV3r(to,v1,v2) VXV3safe(real,to,v1,v2) +#define M2XM3safe(type,to3,m2,m3) \ + do {type _vec_h_temp_[3][3]; \ + M2XM3(_vec_h_temp_,m2,m3); \ + SETMAT3(to3, _vec_h_temp_); \ + } while (0) +#define M2XM3d(to3,m2,m3) M2XM3safe(double,to3,m2,m3) +#define M2XM3i(to3,m2,m3) M2XM3safe(int,to3,m2,m3) +#define M2XM3l(to3,m2,m3) M2XM3safe(long,to3,m2,m3) +#define M2XM3r(to3,m2,m3) M2XM3safe(real,to3,m2,m3) +#define M3XM2safe(type,to3,m3,m2) \ + do {type _vec_h_temp_[3][3]; \ + M3XM2(_vec_h_temp_,m3,m2); \ + SETMAT3(to3, _vec_h_temp_); \ + } while (0) +#define M3XM2d(to3,m3,m2) M3XM2safe(double,to3,m3,m2) +#define M3XM2i(to3,m3,m2) M3XM2safe(int,to3,m3,m2) +#define M3XM2l(to3,m3,m2) M3XM2safe(long,to3,m3,m2) +#define M3XM2r(to3,m3,m2) M3XM2safe(real,to3,m3,m2) +#define V3XM4safe(type,to3,v3,m4) \ + do {type _vec_h_temp_[3]; \ + V3XM4(_vec_h_temp_,v3,m4); \ + SET3(to3, _vec_h_temp_); \ + } while (0) +#define V3XM4d(to3,v3,m4) V3XM4safe(double,to3,v3,m4) +#define V3XM4i(to3,v3,m4) V3XM4safe(int,to3,v3,m4) +#define V3XM4l(to3,v3,m4) V3XM4safe(long,to3,v3,m4) +#define V3XM4r(to3,v3,m4) V3XM4safe(real,to3,v3,m4) +#define M4XV3safe(type,to3,m4,v3) \ + do {type _vec_h_temp_[3]; \ + M4XV3(_vec_h_temp_,m4,v3); \ + SET3(to3, _vec_h_temp_); \ + } while (0) +#define M4XV3d(to3,m4,v3) M4XV3safe(double,to3,m4,v3) +#define M4XV3i(to3,m4,v3) M4XV3safe(int,to3,m4,v3) +#define M4XV3l(to3,m4,v3) M4XV3safe(long,to3,m4,v3) +#define M4XV3r(to3,m4,v3) M4XV3safe(real,to3,m4,v3) +#define ADJOINT3safe(type,to,m) \ + do {type _vec_h_temp_[3][3]; \ + ADJOINT3(_vec_h_temp_,m); \ + SETMAT3(to, _vec_h_temp_); \ + } while (0) +#define ADJOINT3d(to,m) ADJOINT3safe(double,to,m) +#define ADJOINT3i(to,m) ADJOINT3safe(int,to,m) +#define ADJOINT3l(to,m) ADJOINT3safe(long,to,m) +#define ADJOINT3r(to,m) ADJOINT3safe(real,to,m) +#define INVERTMAT3safe(type,to,from) \ + do {type _vec_h_temp_[3][3]; \ + ADJOINT3(_vec_h_temp_, from); \ + type _vec_h_temp_invdet_ = (type)1/(type)DET3(from); \ + SXM3(to, _vec_h_temp_invdet_, _vec_h_temp_); \ + } while (0) +#define INVERTMAT3d(to,from) INVERTMAT3safe(double,to,from) +#define INVERTMAT3i(to,from) INVERTMAT3safe(int,to,from) +#define INVERTMAT3l(to,from) INVERTMAT3safe(long,to,from) +#define INVERTMAT3r(to,from) INVERTMAT3safe(real,to,from) +#define TRANSPOSE4safe(type,to,from) \ + do {type _vec_h_temp_[4][4]; \ + TRANSPOSE4(_vec_h_temp_,from); \ + SETMAT4(to, _vec_h_temp_); \ + } while (0) +#define TRANSPOSE4d(to,from) TRANSPOSE4safe(double,to,from) +#define TRANSPOSE4i(to,from) TRANSPOSE4safe(int,to,from) +#define TRANSPOSE4l(to,from) TRANSPOSE4safe(long,to,from) +#define TRANSPOSE4r(to,from) TRANSPOSE4safe(real,to,from) +#define MXM4safe(type,to,m1,m2) \ + do {type _vec_h_temp_[4][4]; \ + MXM4(_vec_h_temp_,m1,m2); \ + SETMAT4(to, _vec_h_temp_); \ + } while (0) +#define MXM4d(to,m1,m2) MXM4safe(double,to,m1,m2) +#define MXM4i(to,m1,m2) MXM4safe(int,to,m1,m2) +#define MXM4l(to,m1,m2) MXM4safe(long,to,m1,m2) +#define MXM4r(to,m1,m2) MXM4safe(real,to,m1,m2) +#define VXM4safe(type,to,v,m) \ + do {type _vec_h_temp_[4]; \ + VXM4(_vec_h_temp_,v,m); \ + SET4(to, _vec_h_temp_); \ + } while (0) +#define VXM4d(to,v,m) VXM4safe(double,to,v,m) +#define VXM4i(to,v,m) VXM4safe(int,to,v,m) +#define VXM4l(to,v,m) VXM4safe(long,to,v,m) +#define VXM4r(to,v,m) VXM4safe(real,to,v,m) +#define MXV4safe(type,to,m,v) \ + do {type _vec_h_temp_[4]; \ + MXV4(_vec_h_temp_,m,v); \ + SET4(to, _vec_h_temp_); \ + } while (0) +#define MXV4d(to,m,v) MXV4safe(double,to,m,v) +#define MXV4i(to,m,v) MXV4safe(int,to,m,v) +#define MXV4l(to,m,v) MXV4safe(long,to,m,v) +#define MXV4r(to,m,v) MXV4safe(real,to,m,v) +#define VXVXV4safe(type,to,v1,v2,v3) \ + do {type _vec_h_temp_[4]; \ + VXVXV4(_vec_h_temp_,v1,v2,v3); \ + SET4(to, _vec_h_temp_); \ + } while (0) +#define VXVXV4d(to,v1,v2,v3) VXVXV4safe(double,to,v1,v2,v3) +#define VXVXV4i(to,v1,v2,v3) VXVXV4safe(int,to,v1,v2,v3) +#define VXVXV4l(to,v1,v2,v3) VXVXV4safe(long,to,v1,v2,v3) +#define VXVXV4r(to,v1,v2,v3) VXVXV4safe(real,to,v1,v2,v3) +#define M3XM4safe(type,to4,m3,m4) \ + do {type _vec_h_temp_[4][4]; \ + M3XM4(_vec_h_temp_,m3,m4); \ + SETMAT4(to4, _vec_h_temp_); \ + } while (0) +#define M3XM4d(to4,m3,m4) M3XM4safe(double,to4,m3,m4) +#define M3XM4i(to4,m3,m4) M3XM4safe(int,to4,m3,m4) +#define M3XM4l(to4,m3,m4) M3XM4safe(long,to4,m3,m4) +#define M3XM4r(to4,m3,m4) M3XM4safe(real,to4,m3,m4) +#define M4XM3safe(type,to4,m4,m3) \ + do {type _vec_h_temp_[4][4]; \ + M4XM3(_vec_h_temp_,m4,m3); \ + SETMAT4(to4, _vec_h_temp_); \ + } while (0) +#define M4XM3d(to4,m4,m3) M4XM3safe(double,to4,m4,m3) +#define M4XM3i(to4,m4,m3) M4XM3safe(int,to4,m4,m3) +#define M4XM3l(to4,m4,m3) M4XM3safe(long,to4,m4,m3) +#define M4XM3r(to4,m4,m3) M4XM3safe(real,to4,m4,m3) +#define ADJOINT4safe(type,to,m) \ + do {type _vec_h_temp_[4][4]; \ + ADJOINT4(_vec_h_temp_,m); \ + SETMAT4(to, _vec_h_temp_); \ + } while (0) +#define ADJOINT4d(to,m) ADJOINT4safe(double,to,m) +#define ADJOINT4i(to,m) ADJOINT4safe(int,to,m) +#define ADJOINT4l(to,m) ADJOINT4safe(long,to,m) +#define ADJOINT4r(to,m) ADJOINT4safe(real,to,m) +#define INVERTMAT4safe(type,to,from) \ + do {type _vec_h_temp_[4][4]; \ + ADJOINT4(_vec_h_temp_, from); \ + type _vec_h_temp_invdet_ = (type)1/(type)DET4(from); \ + SXM4(to, _vec_h_temp_invdet_, _vec_h_temp_); \ + } while (0) +#define INVERTMAT4d(to,from) INVERTMAT4safe(double,to,from) +#define INVERTMAT4i(to,from) INVERTMAT4safe(int,to,from) +#define INVERTMAT4l(to,from) INVERTMAT4safe(long,to,from) +#define INVERTMAT4r(to,from) INVERTMAT4safe(real,to,from) +#endif /* VEC_H */ diff --git a/CONFIG/AboutDlg.cpp b/CONFIG/AboutDlg.cpp new file mode 100644 index 00000000..9585d1c1 --- /dev/null +++ b/CONFIG/AboutDlg.cpp @@ -0,0 +1,19 @@ +#include "AboutDlg.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(CDialog, 0x60) +DECOMP_SIZE_ASSERT(CAboutDialog, 0x60) + +// FUNCTION: CONFIG 0x00403c20 +CAboutDialog::CAboutDialog() : CDialog(IDD) +{ +} + +// FUNCTION: CONFIG 0x00403d20 +void CAboutDialog::DoDataExchange(CDataExchange* pDX) +{ +} + +BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) +END_MESSAGE_MAP() diff --git a/CONFIG/AboutDlg.h b/CONFIG/AboutDlg.h new file mode 100644 index 00000000..dc648d63 --- /dev/null +++ b/CONFIG/AboutDlg.h @@ -0,0 +1,39 @@ +#if !defined(AFX_ABOUTDLG_H) +#define AFX_ABOUTDLG_H + +#include "StdAfx.h" +#include "compat.h" +#include "res/resource.h" + +// VTABLE: CONFIG 0x00406308 +// SIZE 0x60 +class CAboutDialog : public CDialog { +public: + CAboutDialog(); + enum { + IDD = IDD_ABOUT + }; + +protected: + void DoDataExchange(CDataExchange* pDX) override; + +protected: + DECLARE_MESSAGE_MAP() +}; + +// SYNTHETIC: CONFIG 0x00403cb0 +// CAboutDialog::`scalar deleting destructor' + +// FUNCTION: CONFIG 0x00403d30 +// CAboutDialog::_GetBaseMessageMap + +// FUNCTION: CONFIG 0x00403d40 +// CAboutDialog::GetMessageMap + +// GLOBAL: CONFIG 0x00406100 +// CAboutDialog::messageMap + +// GLOBAL: CONFIG 0x00406108 +// CAboutDialog::_messageEntries + +#endif // !defined(AFX_ABOUTDLG_H) diff --git a/CONFIG/ConfigCommandLineInfo.cpp b/CONFIG/ConfigCommandLineInfo.cpp new file mode 100644 index 00000000..0e376e6d --- /dev/null +++ b/CONFIG/ConfigCommandLineInfo.cpp @@ -0,0 +1,22 @@ +#include "ConfigCommandLineInfo.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(CCommandLineInfo, 0x24) +DECOMP_SIZE_ASSERT(CConfigCommandLineInfo, 0x24) + +// FUNCTION: CONFIG 0x00403b10 +CConfigCommandLineInfo::CConfigCommandLineInfo() +{ + currentConfigApp->m_run_config_dialog = FALSE; +} + +// FUNCTION: CONFIG 0x00403bf0 +void CConfigCommandLineInfo::ParseParam(LPCSTR pszParam, BOOL bFlag, BOOL bLast) +{ + if (bFlag) { + if (lstrcmpiA(pszParam, "config") == 0) { + currentConfigApp->m_run_config_dialog = TRUE; + } + } +} diff --git a/CONFIG/ConfigCommandLineInfo.h b/CONFIG/ConfigCommandLineInfo.h new file mode 100644 index 00000000..82510df1 --- /dev/null +++ b/CONFIG/ConfigCommandLineInfo.h @@ -0,0 +1,21 @@ +#if !defined(AFX_CONFIGCOMMANDLINEINFO_H) +#define AFX_CONFIGCOMMANDLINEINFO_H + +#include "StdAfx.h" +#include "compat.h" +#include "config.h" +#include "decomp.h" + +// VTABLE: CONFIG 0x004060e8 +// SIZE 0x24 +class CConfigCommandLineInfo : public CCommandLineInfo { +public: + CConfigCommandLineInfo(); + + void ParseParam(LPCSTR pszParam, BOOL bFlag, BOOL bLast) override; +}; + +// SYNTHETIC: CONFIG 0x00403b80 +// CConfigCommandLineInfo::`scalar deleting destructor' + +#endif // !defined(AFX_CONFIGCOMMANDLINEINFO_H) diff --git a/CONFIG/MainDlg.cpp b/CONFIG/MainDlg.cpp new file mode 100644 index 00000000..84083892 --- /dev/null +++ b/CONFIG/MainDlg.cpp @@ -0,0 +1,345 @@ +#include "MainDlg.h" + +#include "AboutDlg.h" +#include "config.h" +#include "res/resource.h" + +#include + +DECOMP_SIZE_ASSERT(CDialog, 0x60) +DECOMP_SIZE_ASSERT(CMainDialog, 0x70) + +// FUNCTION: CONFIG 0x00403d50 +CMainDialog::CMainDialog(CWnd* pParent) : CDialog(IDD, pParent) +{ + afxCurrentWinApp; + m_icon = LoadIconA(AfxFindResourceHandle(MAKEINTRESOURCE(IDI_CONFIG), RT_GROUP_ICON), MAKEINTRESOURCE(IDI_CONFIG)); +} + +// FUNCTION: CONFIG 0x00403e50 +void CMainDialog::DoDataExchange(CDataExchange* pDX) +{ +} + +BEGIN_MESSAGE_MAP(CMainDialog, CDialog) +ON_WM_SYSCOMMAND() +ON_WM_PAINT() +ON_WM_QUERYDRAGICON() +ON_COMMAND(IDC_CHK_FLIP_VIDEO_MEM_PAGES, OnCheckboxFlipVideoMemPages) +ON_LBN_SELCHANGE(IDC_LIST_3DDEVICES, OnList3DevicesSelectionChanged) +ON_COMMAND(IDC_RAD_PALETTE_16BIT, OnRadiobuttonPalette16bit) +ON_COMMAND(IDC_RAD_PALETTE_256, OnRadiobuttonPalette256) +ON_COMMAND(IDC_CHK_3D_VIDEO_MEMORY, OnCheckbox3DVideoMemory) +ON_WM_DESTROY() // FIXME: CONFIG.EXE calls Default +ON_COMMAND(IDABORT, OnButtonCancel) +ON_COMMAND(IDC_CHK_3DSOUND, OnCheckbox3DSound) +ON_COMMAND(IDC_RAD_MODEL_QUALITY_LOW, OnRadiobuttonModelLowQuality) +ON_COMMAND(IDC_RAD_MODEL_QUALITY_HIGH, OnRadiobuttonModelHighQuality) +ON_COMMAND(IDC_RAD_TEXTURE_QUALITY_LOW, OnRadiobuttonTextureLowQuality) +ON_COMMAND(IDC_RAD_TEXTURE_QUALITY_HIGH, OnRadiobuttonTextureHighQuality) +ON_COMMAND(IDC_CHK_JOYSTICK, OnCheckboxJoystick) +ON_COMMAND(IDC_BTN_ADVANCED, OnButtonAdvanced) +ON_COMMAND(IDC_CHK_DRAW_CURSOR, OnCheckboxDrawCursor) +ON_COMMAND(IDC_CHK_MUSIC, OnCheckboxMusic) +END_MESSAGE_MAP() + +// FUNCTION: CONFIG 0x00403e80 +BOOL CMainDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + SwitchToAdvanced(FALSE); + CMenu* system_menu = CMenu::FromHandle(::GetSystemMenu(m_hWnd, FALSE)); + CString about_text; + about_text.LoadString(IDS_ABOUT); + if (system_menu) { + AppendMenuA(system_menu->m_hMenu, MF_SEPARATOR, 0, NULL); + AppendMenuA(system_menu->m_hMenu, MF_STRING, 16, (LPCTSTR) about_text); + } + SendMessage(WM_SETICON, ICON_BIG, (LPARAM) m_icon); + SendMessage(WM_SETICON, ICON_SMALL, (LPARAM) m_icon); + MxDeviceEnumerate* enumerator = currentConfigApp->m_device_enumerator; + enumerator->FUN_1009d210(); + m_modified = currentConfigApp->ReadRegisterSettings(); + CWnd* list_3d_devices = GetDlgItem(IDC_LIST_3DDEVICES); + int driver_i = 0; + int device_i = 0; + int selected = 0; + char device_name[256]; + const list& driver_list = enumerator->GetDriverList(); + for (list::const_iterator it_driver = driver_list.begin(); it_driver != driver_list.end(); it_driver++) { + const MxDriver& driver = *it_driver; + for (list::const_iterator it_device = driver.m_devices.begin(); + it_device != driver.m_devices.end(); + it_device++) { + const Direct3DDeviceInfo& device = *it_device; + if (&device == currentConfigApp->m_device) { + selected = device_i; + } + device_i += 1; + sprintf( + device_name, + driver_i == 0 ? "%s ( Primary Device )" : "%s ( Secondary Device )", + device.m_deviceName + ); + ::SendMessage(list_3d_devices->m_hWnd, LB_ADDSTRING, 0, (LPARAM) device_name); + } + driver_i += 1; + } + ::SendMessage(list_3d_devices->m_hWnd, LB_SETCURSEL, selected, 0); + UpdateInterface(); + return TRUE; +} + +// FUNCTION: CONFIG 0x00404080 +void CMainDialog::OnSysCommand(UINT nID, LPARAM lParam) +{ + if ((nID & 0xfff0) == 0x10) { + CAboutDialog about_dialog; + about_dialog.DoModal(); + } + else { + Default(); + } +} + +// FUNCTION: CONFIG 0x00404150 +void CMainDialog::OnPaint() +{ + if (IsIconic()) { + CPaintDC painter(this); + ::SendMessage(m_hWnd, WM_ICONERASEBKGND, (WPARAM) painter.m_hDC, 0); + RECT dim; + GetClientRect(&dim); + DrawIcon( + painter.m_hDC, + (dim.right - dim.left - GetSystemMetrics(SM_CXICON) + 1) / 2, + (dim.bottom - dim.top - GetSystemMetrics(SM_CYICON) + 1) / 2, + m_icon + ); + } + else { + Default(); + } +} + +// FUNCTION: CONFIG 0x00404230 +HCURSOR CMainDialog::OnQueryDragIcon() +{ + return m_icon; +} + +// FUNCTION: CONFIG 0x00404240 +void CMainDialog::OnList3DevicesSelectionChanged() +{ + MxDeviceEnumerate* device_enumerator = currentConfigApp->m_device_enumerator; + int selected = ::SendMessage(GetDlgItem(IDC_LIST_3DDEVICES)->m_hWnd, LB_GETCURSEL, 0, 0); + device_enumerator->GetDevice(selected, currentConfigApp->m_driver, currentConfigApp->m_device); + if (currentConfigApp->GetHardwareDeviceColorModel()) { + GetDlgItem(IDC_CHK_DRAW_CURSOR)->EnableWindow(TRUE); + } + else { + currentConfigApp->m_3d_video_ram = FALSE; + currentConfigApp->m_flip_surfaces = FALSE; + CheckDlgButton(IDC_CHK_3D_VIDEO_MEMORY, currentConfigApp->m_3d_video_ram); + CheckDlgButton(IDC_CHK_FLIP_VIDEO_MEM_PAGES, currentConfigApp->m_flip_surfaces); + } + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x00404320 +void CMainDialog::OnCancel() +{ + CDialog::OnCancel(); +} + +// FUNCTION: CONFIG 0x00404330 +void CMainDialog::OnDestroy() +{ + CDialog::Default(); +} + +// FUNCTION: CONFIG 0x00404340 +void CMainDialog::OnButtonCancel() +{ + if (m_modified) { + currentConfigApp->WriteRegisterSettings(); + } + OnCancel(); +} + +// FUNCTION: CONFIG 0x00404360 +void CMainDialog::UpdateInterface() +{ + currentConfigApp->ValidateSettings(); + GetDlgItem(IDC_CHK_3D_VIDEO_MEMORY) + ->EnableWindow(!currentConfigApp->m_flip_surfaces && !currentConfigApp->GetHardwareDeviceColorModel()); + CheckDlgButton(IDC_CHK_FLIP_VIDEO_MEM_PAGES, currentConfigApp->m_flip_surfaces); + CheckDlgButton(IDC_CHK_3D_VIDEO_MEMORY, currentConfigApp->m_3d_video_ram); + BOOL full_screen = currentConfigApp->m_full_screen; + currentConfigApp->FUN_00403810(); + if (currentConfigApp->GetHardwareDeviceColorModel()) { + CheckDlgButton(IDC_CHK_DRAW_CURSOR, TRUE); + } + else { + CheckDlgButton(IDC_CHK_DRAW_CURSOR, FALSE); + currentConfigApp->m_draw_cursor = FALSE; + GetDlgItem(IDC_CHK_DRAW_CURSOR)->EnableWindow(FALSE); + } + if (full_screen) { + CheckRadioButton( + IDC_RAD_PALETTE_256, + IDC_RAD_PALETTE_16BIT, + currentConfigApp->m_display_bit_depth == 8 ? IDC_RAD_PALETTE_256 : IDC_RAD_PALETTE_16BIT + ); + } + else { + CheckDlgButton(IDC_RAD_PALETTE_256, 0); + CheckDlgButton(IDC_RAD_PALETTE_16BIT, 0); + currentConfigApp->m_display_bit_depth = 0; + } + GetDlgItem(IDC_RAD_PALETTE_256)->EnableWindow(full_screen && currentConfigApp->FUN_004037a0()); + GetDlgItem(IDC_RAD_PALETTE_16BIT)->EnableWindow(full_screen && currentConfigApp->FUN_004037e0()); + CheckDlgButton(IDC_CHK_3DSOUND, currentConfigApp->m_3d_sound); + CheckDlgButton(IDC_CHK_DRAW_CURSOR, currentConfigApp->m_draw_cursor); + switch (currentConfigApp->m_model_quality) { + case 1: + CheckRadioButton(IDC_RAD_MODEL_QUALITY_LOW, IDC_RAD_MODEL_QUALITY_HIGH, IDC_RAD_MODEL_QUALITY_LOW); + break; + case 2: + CheckRadioButton(IDC_RAD_MODEL_QUALITY_LOW, IDC_RAD_MODEL_QUALITY_HIGH, IDC_RAD_MODEL_QUALITY_HIGH); + break; + } + CheckRadioButton( + IDC_RAD_TEXTURE_QUALITY_LOW, + IDC_RAD_TEXTURE_QUALITY_HIGH, + currentConfigApp->m_texture_quality == 0 ? IDC_RAD_TEXTURE_QUALITY_LOW : IDC_RAD_TEXTURE_QUALITY_HIGH + ); + CheckDlgButton(IDC_CHK_JOYSTICK, currentConfigApp->m_use_joystick); + CheckDlgButton(IDC_CHK_MUSIC, currentConfigApp->m_music); +} + +// FUNCTION: CONFIG 0x004045e0 +void CMainDialog::OnCheckbox3DSound() +{ + currentConfigApp->m_3d_sound = IsDlgButtonChecked(IDC_CHK_3DSOUND); + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x00404610 +void CMainDialog::OnCheckbox3DVideoMemory() +{ + currentConfigApp->m_3d_video_ram = IsDlgButtonChecked(IDC_CHK_3D_VIDEO_MEMORY); + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x00404640 +void CMainDialog::OnRadiobuttonPalette16bit() +{ + currentConfigApp->m_display_bit_depth = 16; + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x00404670 +void CMainDialog::OnRadiobuttonPalette256() +{ + currentConfigApp->m_display_bit_depth = 8; + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x004046a0 +void CMainDialog::OnCheckboxFlipVideoMemPages() +{ + currentConfigApp->m_flip_surfaces = IsDlgButtonChecked(IDC_CHK_FLIP_VIDEO_MEM_PAGES); + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x004046d0 +void CMainDialog::OnRadiobuttonModelLowQuality() +{ + currentConfigApp->m_model_quality = 1; + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x00404700 +void CMainDialog::OnRadiobuttonModelHighQuality() +{ + currentConfigApp->m_model_quality = 2; + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x00404730 +void CMainDialog::OnRadiobuttonTextureLowQuality() +{ + currentConfigApp->m_texture_quality = 0; + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x00404760 +void CMainDialog::OnRadiobuttonTextureHighQuality() +{ + currentConfigApp->m_texture_quality = 1; + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x00404790 +void CMainDialog::OnCheckboxJoystick() +{ + currentConfigApp->m_use_joystick = IsDlgButtonChecked(IDC_CHK_JOYSTICK); + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x004047c0 +void CMainDialog::OnButtonAdvanced() +{ + SwitchToAdvanced(!m_advanced); +} + +// FUNCTION: CONFIG 0x004047d0 +void CMainDialog::SwitchToAdvanced(BOOL p_advanced) +{ + RECT dialog_rect; + RECT grp_advanced_rect; + ::GetWindowRect(m_hWnd, &dialog_rect); + ::GetWindowRect(GetDlgItem(IDC_GRP_ADVANCED)->m_hWnd, &grp_advanced_rect); + CWnd* button_advanced = GetDlgItem(IDC_BTN_ADVANCED); + m_advanced = p_advanced; + int height; + if (p_advanced) { + height = grp_advanced_rect.bottom - dialog_rect.top + 10; + GetDlgItem(IDC_BMP_SHARK)->EnableWindow(TRUE); + button_advanced->SetWindowText("Basic"); + } + else { + height = grp_advanced_rect.top - dialog_rect.top; + GetDlgItem(IDC_BMP_SHARK)->EnableWindow(FALSE); + button_advanced->SetWindowText("Advanced"); + } + SetWindowPos(&wndTop, 0, 0, dialog_rect.right - dialog_rect.left, height, SWP_NOMOVE); +} + +// FUNCTION: CONFIG 0x00404890 +void CMainDialog::OnCheckboxDrawCursor() +{ + currentConfigApp->m_draw_cursor = IsDlgButtonChecked(IDC_CHK_DRAW_CURSOR); + m_modified = TRUE; + UpdateInterface(); +} + +// FUNCTION: CONFIG 0x004048c0 +void CMainDialog::OnCheckboxMusic() +{ + currentConfigApp->m_music = IsDlgButtonChecked(IDC_CHK_MUSIC); + m_modified = TRUE; + UpdateInterface(); +} diff --git a/CONFIG/MainDlg.h b/CONFIG/MainDlg.h new file mode 100644 index 00000000..eeebc868 --- /dev/null +++ b/CONFIG/MainDlg.h @@ -0,0 +1,70 @@ +#if !defined(AFX_MAINDLG_H) +#define AFX_MAINDLG_H + +#include "StdAfx.h" +#include "compat.h" +#include "decomp.h" +#include "res/resource.h" + +// VTABLE: CONFIG 0x004063e0 +// SIZE 0x70 +class CMainDialog : public CDialog { +public: + CMainDialog(CWnd* pParent); + enum { + IDD = IDD_MAIN + }; + +protected: + void DoDataExchange(CDataExchange* pDX) override; + void UpdateInterface(); + void SwitchToAdvanced(BOOL p_advanced); + + undefined m_unk0x60[4]; // 0x60 + HCURSOR m_icon; // 0x64 + BOOL m_modified; // 0x68 + BOOL m_advanced; // 0x6c + // Implementation + +protected: + BOOL OnInitDialog() override; + void OnSysCommand(UINT nID, LPARAM lParam); + void OnPaint(); + HCURSOR OnQueryDragIcon(); + void OnList3DevicesSelectionChanged(); + void OnCancel(); + void OnDestroy(); + void OnButtonCancel(); + void OnCheckbox3DSound(); + void OnCheckbox3DVideoMemory(); + void OnRadiobuttonPalette16bit(); + void OnRadiobuttonPalette256(); + void OnCheckboxFlipVideoMemPages(); + void OnRadiobuttonModelLowQuality(); + void OnRadiobuttonModelHighQuality(); + void OnRadiobuttonTextureLowQuality(); + void OnRadiobuttonTextureHighQuality(); + void OnCheckboxJoystick(); + void OnButtonAdvanced(); + void OnCheckboxDrawCursor(); + void OnCheckboxMusic(); + + DECLARE_MESSAGE_MAP() +}; + +// SYNTHETIC: CONFIG 0x00403de0 +// CMainDialog::`scalar deleting destructor' + +// FUNCTION: CONFIG 0x00403e60 +// CMainDialog::_GetBaseMessageMap + +// FUNCTION: CONFIG 0x00403e70 +// CMainDialog::GetMessageMap + +// GLOBAL: CONFIG 0x00406120 +// CMainDialog::messageMap + +// GLOBAL: CONFIG 0x00406128 +// CMainDialog::_messageEntries + +#endif // !defined(AFX_MAINDLG_H) diff --git a/CONFIG/StdAfx.cpp b/CONFIG/StdAfx.cpp new file mode 100644 index 00000000..3e0b3d04 --- /dev/null +++ b/CONFIG/StdAfx.cpp @@ -0,0 +1,5 @@ +// stdafx.cpp : source file that includes just the standard includes +// simple.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" diff --git a/CONFIG/StdAfx.h b/CONFIG/StdAfx.h new file mode 100644 index 00000000..39243b3b --- /dev/null +++ b/CONFIG/StdAfx.h @@ -0,0 +1,31 @@ +#if !defined(AFX_STDAFX_H) +#define AFX_STDAFX_H + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include // MFC extensions +#include // MFC core and standard components +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include // MFC support for Windows Common Controls +#endif // _AFX_NO_AFXCMN_SUPPORT + +#if 0 + +// FUNCTION: CONFIG 0x402ca0 +// CObject::Serialize + +// FUNCTION: CONFIG 0x402cb0 +// CObject::AssertValid + +// FUNCTION: CONFIG 0x402cc0 +// CObject::Dump + +// FUNCTION: CONFIG 0x00403c90 +// CWnd::BeginModalState + +// FUNCTION: CONFIG 0x00403ca0 +// CWnd::EndModalState + +#endif + +#endif // !defined(AFX_STDAFX_H) diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp new file mode 100644 index 00000000..78c6b6c2 --- /dev/null +++ b/CONFIG/config.cpp @@ -0,0 +1,434 @@ +#include "config.h" + +#include "ConfigCommandLineInfo.h" +#include "MainDlg.h" +#include "detectdx5.h" + +#include // _chdir +#include +#include // _spawnl + +DECOMP_SIZE_ASSERT(CWinApp, 0xc4) +DECOMP_SIZE_ASSERT(CConfigApp, 0x108) + +DECOMP_STATIC_ASSERT(offsetof(CConfigApp, m_display_bit_depth) == 0xd0) + +BEGIN_MESSAGE_MAP(CConfigApp, CWinApp) +ON_COMMAND(ID_HELP, OnHelp) +END_MESSAGE_MAP() + +// FUNCTION: CONFIG 0x00402c40 +CConfigApp::CConfigApp() +{ +} + +#define MiB (1024 * 1024) + +// FUNCTION: CONFIG 0x00402dc0 +BOOL CConfigApp::InitInstance() +{ + if (!IsLegoNotRunning()) { + return FALSE; + } + if (!DetectDirectX5()) { + AfxMessageBox( + "\"LEGO\xae Island\" is not detecting DirectX 5 or later. Please quit all other applications and try " + "again." + ); + return FALSE; + } +#ifdef _AFXDLL + Enable3dControls(); +#else + Enable3dControlsStatic(); +#endif + CConfigCommandLineInfo cmdInfo; + ParseCommandLine(cmdInfo); + if (_stricmp(afxCurrentAppName, "config") == 0) { + m_run_config_dialog = TRUE; + } + m_device_enumerator = new MxDeviceEnumerate; + if (m_device_enumerator->DoEnumerate()) { + return FALSE; + } + m_driver = NULL; + m_device = NULL; + m_full_screen = TRUE; + m_wide_view_angle = TRUE; + m_use_joystick = FALSE; + m_music = TRUE; + m_flip_surfaces = FALSE; + m_3d_video_ram = FALSE; + m_joystick_index = -1; + m_display_bit_depth = 16; + MEMORYSTATUS memory_status; + memory_status.dwLength = sizeof(memory_status); + GlobalMemoryStatus(&memory_status); + if (memory_status.dwTotalPhys < 12 * MiB) { + m_3d_sound = FALSE; + m_model_quality = 0; + m_texture_quality = 1; + } + else if (memory_status.dwTotalPhys < 20 * MiB) { + m_3d_sound = FALSE; + m_model_quality = 1; + m_texture_quality = 1; + } + else { + m_model_quality = 2; + m_3d_sound = TRUE; + m_texture_quality = 1; + } + if (!m_run_config_dialog) { + ReadRegisterSettings(); + ValidateSettings(); + WriteRegisterSettings(); + delete m_device_enumerator; + m_device_enumerator = NULL; + m_driver = NULL; + m_device = NULL; + char password[256]; + ReadReg("password", password, sizeof(password)); + const char* exe = _stricmp("ogel", password) == 0 ? "isled.exe" : "isle.exe"; + char diskpath[1024]; + if (ReadReg("diskpath", diskpath, sizeof(diskpath))) { + _chdir(diskpath); + } + _spawnl(_P_NOWAIT, exe, exe, "/diskstream", "/script", "\\lego\\scripts\\isle\\isle.si", NULL); + return FALSE; + } + CMainDialog main_dialog(NULL); + main_dialog.DoModal(); + return FALSE; +} + +// FUNCTION: CONFIG 0x00403100 +BOOL CConfigApp::IsLegoNotRunning() +{ + HWND hWnd = FindWindowA("Lego Island MainNoM App", "LEGO\xae"); + if (_stricmp(afxCurrentAppName, "config") == 0 || !hWnd) { + return TRUE; + } + if (SetForegroundWindow(hWnd)) { + ShowWindow(hWnd, SW_RESTORE); + } + return FALSE; +} + +// FUNCTION: CONFIG 0x004031b0 +BOOL CConfigApp::WriteReg(const char* p_key, const char* p_value) const +{ + HKEY hKey; + DWORD pos; + + if (RegCreateKeyExA( + HKEY_LOCAL_MACHINE, + "SOFTWARE\\Mindscape\\LEGO Island", + 0, + "string", + 0, + KEY_READ | KEY_WRITE, + NULL, + &hKey, + &pos + ) == ERROR_SUCCESS) { + if (RegSetValueExA(hKey, p_key, 0, REG_SZ, (LPBYTE) p_value, strlen(p_value)) == ERROR_SUCCESS) { + if (RegCloseKey(hKey) == ERROR_SUCCESS) { + return TRUE; + } + } + else { + RegCloseKey(hKey); + } + } + return FALSE; +} + +// FUNCTION: CONFIG 0x00403240 +BOOL CConfigApp::ReadReg(LPCSTR p_key, LPCSTR p_value, DWORD p_size) const +{ + HKEY hKey; + DWORD valueType; + + BOOL out = FALSE; + DWORD size = p_size; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Mindscape\\LEGO Island", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + if (RegQueryValueExA(hKey, p_key, NULL, &valueType, (LPBYTE) p_value, &size) == ERROR_SUCCESS) { + if (RegCloseKey(hKey) == ERROR_SUCCESS) { + out = TRUE; + } + } + } + return out; +} + +// FUNCTION: CONFIG 0x004032b0 +BOOL CConfigApp::ReadRegBool(LPCSTR p_key, BOOL* p_bool) const +{ + char buffer[256]; + + BOOL read = ReadReg(p_key, buffer, sizeof(buffer)); + if (read) { + if (strcmp("YES", buffer) == 0) { + *p_bool = TRUE; + return read; + } + + if (strcmp("NO", buffer) == 0) { + *p_bool = FALSE; + return read; + } + + read = FALSE; + } + return read; +} + +// FUNCTION: CONFIG 0x00403380 +BOOL CConfigApp::ReadRegInt(LPCSTR p_key, int* p_value) const +{ + char buffer[256]; + + BOOL read = ReadReg(p_key, buffer, sizeof(buffer)); + if (read) { + *p_value = atoi(buffer); + } + + return read; +} + +// FUNCTION: CONFIG 0x004033d0 +BOOL CConfigApp::FUN_004033d0() const +{ + /* + * BUG: should be: + * return !GetHardwareDeviceColorModel() && (m_device->m_HELDesc.dcmColorModel & D3DCOLOR_RGB); + */ + return !GetHardwareDeviceColorModel() && m_device->m_HELDesc.dcmColorModel == D3DCOLOR_RGB; +} + +// FUNCTION: CONFIG 0x00403400 +D3DCOLORMODEL CConfigApp::GetHardwareDeviceColorModel() const +{ + return m_device->m_HWDesc.dcmColorModel; +} + +// FUNCTION: CONFIG 0x00403410 +BOOL CConfigApp::IsPrimaryDriver() const +{ + return m_driver == &m_device_enumerator->GetDriverList().front(); +} + +// FUNCTION: CONFIG 0x00403430 +BOOL CConfigApp::ReadRegisterSettings() +{ + char buffer[256]; + BOOL is_modified = FALSE; + int tmp = -1; + + if (ReadReg("3D Device ID", buffer, sizeof(buffer))) { + tmp = m_device_enumerator->ParseDeviceName(buffer); + if (tmp >= 0) { + tmp = m_device_enumerator->GetDevice(tmp, m_driver, m_device); + } + } + if (tmp != 0) { + is_modified = TRUE; + m_device_enumerator->FUN_1009d210(); + tmp = m_device_enumerator->FUN_1009d0d0(); + m_device_enumerator->GetDevice(tmp, m_driver, m_device); + } + if (!ReadRegInt("Display Bit Depth", &m_display_bit_depth)) { + is_modified = TRUE; + } + if (!ReadRegBool("Flip Surfaces", &m_flip_surfaces)) { + is_modified = TRUE; + } + if (!ReadRegBool("Full Screen", &m_full_screen)) { + is_modified = TRUE; + } + if (!ReadRegBool("Back Buffers in Video RAM", &m_3d_video_ram)) { + is_modified = TRUE; + } + if (!ReadRegBool("Wide View Angle", &m_wide_view_angle)) { + is_modified = TRUE; + } + if (!ReadRegBool("3DSound", &m_3d_sound)) { + is_modified = TRUE; + } + if (!ReadRegBool("Draw Cursor", &m_draw_cursor)) { + is_modified = TRUE; + } + if (!ReadRegInt("Island Quality", &m_model_quality)) { + is_modified = TRUE; + } + if (!ReadRegInt("Island Texture", &m_texture_quality)) { + is_modified = TRUE; + } + if (!ReadRegBool("UseJoystick", &m_use_joystick)) { + is_modified = TRUE; + } + if (!ReadRegBool("Music", &m_music)) { + is_modified = TRUE; + } + if (!ReadRegInt("JoystickIndex", &m_joystick_index)) { + is_modified = TRUE; + } + return is_modified; +} + +// FUNCTION: CONFIG 0x00403630 +BOOL CConfigApp::ValidateSettings() +{ + BOOL is_modified = FALSE; + + if (!IsPrimaryDriver() && !m_full_screen) { + m_full_screen = TRUE; + is_modified = TRUE; + } + if (FUN_004033d0()) { + if (m_3d_video_ram) { + m_3d_video_ram = FALSE; + is_modified = TRUE; + } + if (m_flip_surfaces) { + m_flip_surfaces = FALSE; + is_modified = TRUE; + } + if (m_display_bit_depth != 16) { + m_display_bit_depth = 16; + is_modified = TRUE; + } + } + if (!GetHardwareDeviceColorModel()) { + m_draw_cursor = FALSE; + is_modified = TRUE; + } + else { + if (!m_3d_video_ram) { + m_3d_video_ram = TRUE; + is_modified = TRUE; + } + if (m_full_screen && !m_flip_surfaces) { + m_flip_surfaces = TRUE; + is_modified = TRUE; + } + } + if (m_flip_surfaces) { + if (!m_3d_video_ram) { + m_3d_video_ram = TRUE; + is_modified = TRUE; + } + if (!m_full_screen) { + m_full_screen = TRUE; + is_modified = TRUE; + } + } + if ((m_display_bit_depth != 8 && m_display_bit_depth != 16) && (m_display_bit_depth != 0 || m_full_screen)) { + m_display_bit_depth = 8; + is_modified = TRUE; + } + if (m_model_quality < 0 || m_model_quality > 2) { + m_model_quality = 1; + is_modified = TRUE; + } + if (m_texture_quality < 0 || m_texture_quality > 1) { + m_texture_quality = 0; + is_modified = TRUE; + } + return is_modified; +} + +// FUNCTION: CONFIG 0x004037a0 +DWORD CConfigApp::FUN_004037a0() const +{ + if (FUN_004033d0()) { + return 0; + } + if (GetHardwareDeviceColorModel()) { + return 0; + } + return m_device->m_HELDesc.dwDeviceRenderBitDepth & 0x800; +} + +// FUNCTION: CONFIG 0x004037e0 +DWORD CConfigApp::FUN_004037e0() const +{ + if (GetHardwareDeviceColorModel()) { + return m_device->m_HWDesc.dwDeviceRenderBitDepth & 0x400; + } + else { + return m_device->m_HELDesc.dwDeviceRenderBitDepth & 0x400; + } +} + +// FUNCTION: CONFIG 0x00403810 +BOOL CConfigApp::FUN_00403810() +{ + if (m_display_bit_depth == 8) { + if (FUN_004037a0()) { + return FALSE; + } + } + if (m_display_bit_depth == 16) { + if (FUN_004037e0()) { + return FALSE; + } + } + if (FUN_004037a0()) { + m_display_bit_depth = 8; + return TRUE; + } + if (FUN_004037e0()) { + m_display_bit_depth = 16; + return TRUE; + } + m_display_bit_depth = 8; + return TRUE; +} + +// FUNCTION: CONFIG 00403890 +void CConfigApp::WriteRegisterSettings() const + +{ + char buffer[128]; + +#define WriteRegBool(NAME, VALUE) WriteReg(NAME, VALUE ? "YES" : "NO") +#define WriteRegInt(NAME, VALUE) \ + do { \ + sprintf(buffer, "%d", VALUE); \ + WriteReg(NAME, buffer); \ + } while (0) + + m_device_enumerator->FormatDeviceName(buffer, m_driver, m_device); + WriteReg("3D Device ID", buffer); + WriteReg("3D Device Name", m_device->m_deviceName); + WriteRegInt("Display Bit Depth", m_display_bit_depth); + WriteRegBool("Flip Surfaces", m_flip_surfaces); + WriteRegBool("Full Screen", m_full_screen); + WriteRegBool("Back Buffers in Video RAM", m_3d_video_ram); + WriteRegBool("Wide View Angle", m_wide_view_angle); + WriteRegBool("3DSound", m_3d_sound); + WriteRegBool("Draw Cursor", m_draw_cursor); + WriteRegInt("Island Quality", m_model_quality); + WriteRegInt("Island Texture", m_texture_quality); + WriteRegBool("UseJoystick", m_use_joystick); + WriteRegBool("Music", m_music); + WriteRegInt("JoystickIndex", m_joystick_index); + +#undef WriteRegBool +#undef WriteRegInt +} + +// FUNCTION: CONFIG 0x00403a90 +int CConfigApp::ExitInstance() +{ + if (m_device_enumerator) { + delete m_device_enumerator; + m_device_enumerator = NULL; + } + return CWinApp::ExitInstance(); +} + +// GLOBAL: CONFIG 0x00408e50 +CConfigApp g_theApp; diff --git a/CONFIG/config.h b/CONFIG/config.h new file mode 100644 index 00000000..75195e7e --- /dev/null +++ b/CONFIG/config.h @@ -0,0 +1,91 @@ +#if !defined(AFX_CONFIG_H) +#define AFX_CONFIG_H + +#include "StdAfx.h" +#include "compat.h" +#include "decomp.h" + +#include + +class MxDeviceEnumerate; +struct Direct3DDeviceInfo; +struct MxDriver; + +#define currentConfigApp ((CConfigApp*) afxCurrentWinApp) + +// VTABLE: CONFIG 0x00406040 +// SIZE 0x108 +class CConfigApp : public CWinApp { +public: + CConfigApp(); + + // Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CConfigApp) + +public: + BOOL InitInstance() override; + int ExitInstance() override; + //}}AFX_VIRTUAL + + // Implementation + + BOOL WriteReg(const char* p_key, const char* p_value) const; + BOOL ReadReg(LPCSTR p_key, LPCSTR p_value, DWORD p_size) const; + BOOL ReadRegBool(LPCSTR p_key, BOOL* p_bool) const; + BOOL ReadRegInt(LPCSTR p_key, int* p_value) const; + BOOL FUN_004033d0() const; + D3DCOLORMODEL GetHardwareDeviceColorModel() const; + BOOL IsPrimaryDriver() const; + BOOL ReadRegisterSettings(); + BOOL ValidateSettings(); + DWORD FUN_004037a0() const; + DWORD FUN_004037e0() const; + BOOL FUN_00403810(); + void CConfigApp::WriteRegisterSettings() const; + + //{{AFX_MSG(CConfigApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +private: + BOOL IsLegoNotRunning(); + +public: + MxDeviceEnumerate* m_device_enumerator; // 0x0c4 + MxDriver* m_driver; // 0x0c8 + Direct3DDeviceInfo* m_device; // 0x0cc + int m_display_bit_depth; // 0x0d0 + BOOL m_flip_surfaces; // 0x0d4 + BOOL m_full_screen; // 0x0d8 + BOOL m_3d_video_ram; // 0x0dc + BOOL m_wide_view_angle; // 0x0e0 + BOOL m_3d_sound; // 0x0e4 + BOOL m_draw_cursor; // 0x0e8 + BOOL m_use_joystick; // 0x0ec + int m_joystick_index; // 0x0f0 + BOOL m_run_config_dialog; // 0x0f4 + int m_model_quality; // 0x0f8 + int m_texture_quality; // 0x0fc + undefined m_unk0x100[4]; // 0x100 + BOOL m_music; // 0x104 +}; + +// SYNTHETIC: CONFIG 0x00402cd0 +// CConfigApp::`scalar deleting destructor' + +// FUNCTION: CONFIG 0x402c20 +// CConfigApp::_GetBaseMessageMap + +// FUNCTION: CONFIG 0x402c30 +// CConfigApp::GetMessageMap + +// GLOBAL: CONFIG 0x406008 +// CConfigApp::messageMap + +// GLOBAL: CONFIG 0x406010 +// CConfigApp::_messageEntries + +#endif // !defined(AFX_CONFIG_H) diff --git a/CONFIG/detectdx5.cpp b/CONFIG/detectdx5.cpp new file mode 100644 index 00000000..546f0dbd --- /dev/null +++ b/CONFIG/detectdx5.cpp @@ -0,0 +1,142 @@ +#include "detectdx5.h" + +#include +#include + +typedef HRESULT WINAPI DirectDrawCreate_fn(GUID FAR* lpGUID, LPDIRECTDRAW FAR* lplpDD, IUnknown FAR* pUnkOuter); +typedef HRESULT WINAPI +DirectInputCreateA_fn(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA* ppDI, LPUNKNOWN punkOuter); + +// FUNCTION: CONFIG 0x004048f0 +BOOL DetectDirectX5() +{ + unsigned int version; + BOOL found; + DetectDirectX(&version, &found); + return version >= 0x500; +} + +// FUNCTION: CONFIG 0x00404920 +void DetectDirectX(unsigned int* p_version, BOOL* p_found) +{ + OSVERSIONINFOA os_version; + + os_version.dwOSVersionInfoSize = sizeof(os_version); + if (!GetVersionExA(&os_version)) { + *p_version = 0; + *p_found = 0; + return; + } + if (os_version.dwPlatformId == 2) { + *p_found = 2; + if (os_version.dwMajorVersion < 4) { + *p_found = 0; + return; + } + if (os_version.dwMajorVersion != 4) { + *p_version = 0x501; + return; + } + *p_version = 0x200; + HMODULE dinput_module = LoadLibraryA("DINPUT.DLL"); + if (!dinput_module) { + OutputDebugStringA("Couldn't LoadLibrary DInput\r\n"); + return; + } + DirectInputCreateA_fn* func_DirectInputCreateA = + (DirectInputCreateA_fn*) GetProcAddress(dinput_module, "DirectInputCreateA"); + FreeLibrary(dinput_module); + if (!func_DirectInputCreateA) { + OutputDebugStringA("Couldn't GetProcAddress DInputCreate\r\n"); + return; + } + *p_version = 0x300; + return; + } + *p_found = 1; + if (LOWORD(os_version.dwBuildNumber) >= 0x550) { + *p_version = 0x501; + return; + } + HMODULE ddraw_module = LoadLibraryA("DDRAW.DLL"); + if (!ddraw_module) { + *p_version = 0; + *p_found = 0; + FreeLibrary(ddraw_module); + return; + } + DirectDrawCreate_fn* func_DirectDrawCreate = + (DirectDrawCreate_fn*) GetProcAddress(ddraw_module, "DirectDrawCreate"); + if (!func_DirectDrawCreate) { + *p_version = 0; + *p_found = 0; + FreeLibrary(ddraw_module); + OutputDebugStringA("Couldn't LoadLibrary DDraw\r\n"); + return; + } + LPDIRECTDRAW ddraw; + if (FAILED(func_DirectDrawCreate(NULL, &ddraw, NULL))) { + *p_version = 0; + *p_found = 0; + FreeLibrary(ddraw_module); + OutputDebugStringA("Couldn't create DDraw\r\n"); + return; + } + *p_version = 0x100; + LPDIRECTDRAW2 ddraw2; + if (FAILED(ddraw->QueryInterface(IID_IDirectDraw2, (LPVOID*) &ddraw2))) { + ddraw->Release(); + FreeLibrary(ddraw_module); + OutputDebugStringA("Couldn't QI DDraw2\r\n"); + return; + } + ddraw->Release(); + *p_version = 0x200; + HMODULE dinput_module = LoadLibraryA("DINPUT.DLL"); + if (!dinput_module) { + OutputDebugStringA("Couldn't LoadLibrary DInput\r\n"); + ddraw2->Release(); + FreeLibrary(ddraw_module); + return; + } + DirectInputCreateA_fn* func_DirectInputCreateA = + (DirectInputCreateA_fn*) GetProcAddress(dinput_module, "DirectInputCreateA"); + FreeLibrary(dinput_module); + if (!func_DirectInputCreateA) { + FreeLibrary(ddraw_module); + ddraw2->Release(); + OutputDebugStringA("Couldn't GetProcAddress DInputCreate\r\n"); + return; + } + *p_version = 0x300; + DDSURFACEDESC surface_desc; + memset(&surface_desc, 0, sizeof(surface_desc)); + surface_desc.dwSize = sizeof(surface_desc); + surface_desc.dwFlags = DDSD_CAPS; + surface_desc.ddsCaps.dwCaps = DDCAPS2_NONLOCALVIDMEM; + if (FAILED(ddraw2->SetCooperativeLevel(NULL, DISCL_BACKGROUND))) { + ddraw2->Release(); + FreeLibrary(ddraw_module); + *p_version = 0; + OutputDebugStringA("Couldn't Set coop level\r\n"); + return; + } + LPDIRECTDRAWSURFACE surface; + if (FAILED(ddraw2->CreateSurface(&surface_desc, &surface, NULL))) { + ddraw2->Release(); + FreeLibrary(ddraw_module); + *p_version = 0; + OutputDebugStringA("Couldn't CreateSurface\r\n"); + return; + } + LPDIRECTDRAWSURFACE3 surface3; + if (FAILED(surface->QueryInterface(IID_IDirectDrawSurface3, (LPVOID*) &surface3))) { + ddraw2->Release(); + FreeLibrary(ddraw_module); + return; + } + *p_version = 0x500; + surface3->Release(); + ddraw2->Release(); + FreeLibrary(ddraw_module); +} diff --git a/CONFIG/detectdx5.h b/CONFIG/detectdx5.h new file mode 100644 index 00000000..6f45837c --- /dev/null +++ b/CONFIG/detectdx5.h @@ -0,0 +1,10 @@ +#if !defined(AFX_DETECTDX5_H) +#define AFX_DETECTDX5_H + +#include + +extern BOOL DetectDirectX5(); + +extern void DetectDirectX(unsigned int* p_version, BOOL* p_found); + +#endif // !defined(AFX_DETECTDX5_H) diff --git a/CONFIG/res/config.rc b/CONFIG/res/config.rc new file mode 100644 index 00000000..a6164bfa --- /dev/null +++ b/CONFIG/res/config.rc @@ -0,0 +1,82 @@ +#include "resource.h" +#include "afxres.h" + +IDI_CONFIG ICON "lego.ico" + +IDB_SHARK BITMAP "shark.bmp" + +IDD_ABOUT DIALOG 0, 0, 217, 55 +STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About Configure LEGO\xAE Island" +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +FONT 8, "MS Sans Serif" +BEGIN + CONTROL IDI_CONFIG, -1, "STATIC", SS_ICON | WS_CHILD | WS_VISIBLE, 11, 17, 18, 20 + CONTROL "Configure LEGO Island Version 1.0", -1, "STATIC", SS_LEFT | SS_NOPREFIX | WS_CHILD | WS_VISIBLE | WS_GROUP, 40, 10, 119, 8 + CONTROL "Copyright \xA9 1997 mindscape", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 40, 25, 119, 8 + CONTROL "OK", IDOK, "BUTTON", BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP, 178, 7, 32, 14 +END + +STRINGTABLE +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +BEGIN + IDS_ABOUT, "&About Config..." +END + +IDD_MAIN DIALOGEX 0, 0, 289, 247 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_APPWINDOW +CAPTION "Configure LEGO Island" +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "OK", IDABORT, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 172, 125, 44, 14 + CONTROL "Cancel", IDCANCEL, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 238, 125, 44, 14 + CONTROL "Fast", IDC_RAD_MODEL_QUALITY_LOW, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE, 124, 18, 42, 10 + CONTROL "High", IDC_RAD_MODEL_QUALITY_HIGH, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE, 192, 18, 69, 10 + CONTROL "Fast", IDC_RAD_TEXTURE_QUALITY_LOW, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE, 124, 49, 43, 10 + CONTROL "High", IDC_RAD_TEXTURE_QUALITY_HIGH, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE, 192, 49, 69, 10 + CONTROL "256 Color", IDC_RAD_PALETTE_256, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE, 124, 80, 50, 10 + CONTROL "High Color(16 bit)", IDC_RAD_PALETTE_16BIT, "BUTTON", BS_AUTORADIOBUTTON | WS_CHILD | WS_VISIBLE, 192, 80, 76, 10 + CONTROL "Use Joystick", IDC_CHK_JOYSTICK, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 192, 104, 60, 10 + CONTROL "", IDC_LIST_3DDEVICES, "LISTBOX", LBS_NOTIFY | LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL, 115, 168, 161, 36 , WS_EX_TRANSPARENT + CONTROL "Flip Video Memory Pages", IDC_CHK_FLIP_VIDEO_MEM_PAGES, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE, 116, 224, 96, 15 + CONTROL "Draw 3D to Video Memory", IDC_CHK_3D_VIDEO_MEMORY, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE, 116, 210, 99, 10 + CONTROL "Color Palette", -1, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE, 107, 69, 175, 26 + CONTROL "Direct 3D Devices", -1, "STATIC", SS_CENTER | WS_CHILD | WS_VISIBLE | WS_GROUP, 123, 158, 143, 10 + CONTROL "3D Sound", IDC_CHK_3DSOUND, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE, 220, 210, 45, 10 + CONTROL "Island Model Quality", -1, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE, 107, 7, 175, 26 + CONTROL "Island Texture Quality", -1, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE, 107, 38, 175, 26 + CONTROL "Advanced Settings", IDC_GRP_ADVANCED, "BUTTON", BS_GROUPBOX | WS_CHILD | WS_VISIBLE, 107, 147, 175, 93 + CONTROL "Advanced", IDC_BTN_ADVANCED, "BUTTON", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE, 109, 124, 44, 14 + CONTROL IDB_SHARK, IDC_BMP_SHARK, "STATIC", SS_BITMAP | WS_CHILD | WS_VISIBLE, 7, 7, 83, 249 + CONTROL "Draw Cursor", IDC_CHK_DRAW_CURSOR, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE, 219, 227, 54, 10 + CONTROL "Music", IDC_CHK_MUSIC, "BUTTON", BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 124, 104, 35, 10 +END + +1 VERSIONINFO +FILEVERSION 1,1,0,0 +PRODUCTVERSION 1,1,0,0 +FILEOS 0x4 +FILETYPE 0x1 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Mindscape, Inc." + VALUE "FileDescription", "LEGOIsland & Configuration application" + VALUE "FileVersion", "1, 1, 0, 0" + VALUE "InternalName", "LEGOISLE.EXE" + VALUE "LegalCopyright", "Copyright \xA9 1997" + VALUE "OriginalFilename", "CONFIG.EXE" + VALUE "ProductName", "LEGO Island" + VALUE "ProductVersion", "1, 1, 0, 0" + END + END + + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 0x04B0 // U.S. English, Unicode + END +END diff --git a/CONFIG/res/lego.ico b/CONFIG/res/lego.ico new file mode 100644 index 00000000..7db1421d Binary files /dev/null and b/CONFIG/res/lego.ico differ diff --git a/CONFIG/res/resource.h b/CONFIG/res/resource.h new file mode 100644 index 00000000..4c72eaa1 --- /dev/null +++ b/CONFIG/res/resource.h @@ -0,0 +1,25 @@ +#define IDI_CONFIG 128 + +#define IDD_ABOUT 100 +#define IDS_ABOUT 101 + +#define IDD_MAIN 102 + +#define IDC_LIST_3DDEVICES 1000 +#define IDC_CHK_FLIP_VIDEO_MEM_PAGES 1001 +#define IDC_CHK_3D_VIDEO_MEMORY 1003 +#define IDC_RAD_PALETTE_256 1004 +#define IDC_RAD_PALETTE_16BIT 1005 +#define IDC_CHK_3DSOUND 1006 +#define IDC_CHK_DRAW_CURSOR 1008 +#define IDC_RAD_MODEL_QUALITY_LOW 1010 +#define IDC_RAD_MODEL_QUALITY_HIGH 1011 +#define IDC_RAD_TEXTURE_QUALITY_LOW 1013 +#define IDC_RAD_TEXTURE_QUALITY_HIGH 1014 +#define IDC_CHK_JOYSTICK 1015 +#define IDC_GRP_ADVANCED 1017 +#define IDC_BTN_ADVANCED 1020 +#define IDC_BMP_SHARK 1023 +#define IDC_CHK_MUSIC 1024 + +#define IDB_SHARK 135 diff --git a/CONFIG/res/shark.bmp b/CONFIG/res/shark.bmp new file mode 100644 index 00000000..0829a1d1 Binary files /dev/null and b/CONFIG/res/shark.bmp differ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..20b61718 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,63 @@ +# Contributing + +## Important Note + +While we're thrilled that there is so much interest in reverse engineering LEGO Island and are happy to accept contributions from anyone who would like to help progress us further to our goal of a complete codebase, proposed changes to this repository must adhere to a certain degree of engineering quality. While the established contributors here are more than happy to provide code reviews and constructive criticism, it is not their job to teach potential contributors C++ or decompilation fundamentals. As a project that is largely an artifact of the free time of its contributors, the more of that (often scarce) resource that can be dedicated to efficient work, the faster the decompilation will progress. Unfortunately, this results in well-intentioned but poorly constructed contributions actually hurting progress in the long-term. While we are greatly appreciative of the sentiment, if you aren't very confident in your decompilation abilities, it is generally in the project's best interest that you return when you have a better grasp over the process. + +Generally, decompilation is a fairly advanced skill. Depending on your current proficiency with C/C++ and x86 assembly, it could take you months or even years to learn the skills necessary to do it adequately. If you're still interested in learning, [part 1 of the decompilation vlog](https://www.youtube.com/watch?v=MToTEqoVv3I) covers the overall process and should give you a starting point that you can dive in from. Once again, please make yourself familiar with this process before attempting to contribute code to this project. + +## Ghidra Server + +For documenting the original binaries and generating pseudocode that we decompile with, we primarily use [Ghidra](https://ghidra-sre.org/) (it's free and open source). To help with collaboration, we have a shared Ghidra repository with all of our current work. You are free to check it out and mess around with it locally, however to prevent sabotage, you will need to request permission before you can push your changes back to the server (ask in the Matrix room). + +To access the Ghidra repository, use the following details: + +- Address: `server.mattkc.com` +- Port: `13100` + +**Please note that at the time of writing, much of the information found on the Ghidra server is severely outdated**. Generally, the source code found in this repository represents the latest "source of truth" and should be referenced whenever possible. + +## General Guidelines + +If you feel fit to contribute, feel free to create a pull request! Someone will review and merge it (or provide feedback) as soon as possible. + +Please keep your pull requests small and understandable; you may be able to shoot ahead and make a lot of progress in a short amount of time, but this is a collaborative project, so you must allow others to catch up and follow along. Large pull requests become significantly more unwieldy to review, and as such make it exponentially more likely for a mistake or error to go undetected. They also make it harder to merge other pull requests because the more files you modify, the more likely it is for a merge conflict to occur. A general guideline is to keep submissions limited to one class at a time. Sometimes two or more classes may be too interlinked for this to be feasible, so this is not a hard rule, however if your PR is starting to modify more than 10 or so files, it's probably getting too big. + +This repository currently has only one goal: accuracy to the original executables. We are byte/instruction matching as much as possible, which means the priority is making the original compiler (MSVC 4.20) produce code that matches the original game. As such, modernizations and bug fixes will probably be rejected for the time being. + +## Overview + +* [`3rdparty`](/3rdparty): Contains code obtained from third parties, not including Mindscape. Generally, these are libraries that have been placed in the public domain or are freely available on the web. As these are unaltered files, our style guide (see below) does not apply. +* [`CONFIG`](/CONFIG): Decompilation of `CONFIG.EXE`. It depends on some code in `LEGO1`. +* [`ISLE`](/ISLE): Decompilation of `ISLE.EXE`. It depends on some code in `LEGO1`. +* [`LEGO1`](/LEGO1): Decompilation of `LEGO1.DLL`. This folder contains code from Mindscape's custom in-house engine called **Omni** (file pattern: `mx*`), the LEGO Island-specific extensions for Omni and the game's code (file pattern: `lego*`) as well as several utility libraries developed by Mindscape. +* [`tools`](/tools): A set of tools aiding in the decompilation effort. +* [`util`](/util): Utility headers aiding in the decompilation effort. + +## Tooling + +Please make yourself familiar with the [available tooling and annotations](/tools/README.md). These are generally required to contribute to the project. + +## Notes on MSVC 4.20 + +As outlined in the [`README`](/README.md), Microsoft Visual C++ 4.20 is the compiler we use to build the game. + +One important aspect to know about this compiler in the context of the decompilation project is that the assembly code generation is somewhat erratic. We call this peculiarity "compiler randomness" or entropy. In essence, what it comes down to is that changes to the code base, for instance in a header, can pseudo-randomly affect the code generation of functions in compilation units that include this header, even if the changes are completely unrelated to those functions. For example, by adding an extra (unused) inline function or an enum declaration in a header, the code in some functions may unexpectedly wind up looking different and our main tool, [`reccmp`](/tools/README.md), will report either a (significantly) reduced or increased accuracy for those functions. This issue roughly affects around ~5% of all decompiled functions. + +We are currently unaware of the exact nature of this phenomenon. Unfortunately it represents a significant obstacle in our effort to achieve 100% matching binaries. If you or anyone you know has knowledge about the compiler internals that lead to the described observations, please contact us. + +## Code Style + +In general, we're not exhaustively strict about coding style, but there are some preferable guidelines to follow that have been adopted from what we know about the original codebase: + +### Formatting + +We are currently using [clang-format](https://clang.llvm.org/docs/ClangFormat.html) and [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) with configuration files that aim to replicate the code formatting employed by the original developers. There are [integrations](https://clang.llvm.org/docs/ClangFormat.html#vim-integration) available for most editors and IDEs. The required `clang-format` version is `17.x`. + +### Naming conventions + +We are currently using a customized version of [ncc](https://github.com/nithinn/ncc) with a configuration file that aims to replicate the naming conventions employed by the original developers. `ncc` requires Clang `16.x`; please refer to the [tool](/tools/ncc) and the [GitHub action](/.github/workflows/naming.yml) for guidance. + +## Questions? + +For any further questions, feel free to ask in either the [Matrix chatroom](https://matrix.to/#/#isledecomp:matrix.org) or on the [forum](https://forum.mattkc.com/viewforum.php?f=1). diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp new file mode 100644 index 00000000..6f6296aa --- /dev/null +++ b/ISLE/isleapp.cpp @@ -0,0 +1,919 @@ +#include "isleapp.h" + +#include "3dmanager/lego3dmanager.h" +#include "decomp.h" +#include "legoanimationmanager.h" +#include "legobuildingmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "legomodelpresenter.h" +#include "legopartpresenter.h" +#include "legovideomanager.h" +#include "legoworldpresenter.h" +#include "misc.h" +#include "mxbackgroundaudiomanager.h" +#include "mxdirectx/mxdirect3d.h" +#include "mxdsaction.h" +#include "mxmisc.h" +#include "mxomnicreateflags.h" +#include "mxomnicreateparam.h" +#include "mxstreamer.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "mxtransitionmanager.h" +#include "mxvariabletable.h" +#include "res/resource.h" +#include "roi/legoroi.h" +#include "viewmanager/viewmanager.h" + +#include + +DECOMP_SIZE_ASSERT(IsleApp, 0x8c) + +// GLOBAL: ISLE 0x410030 +IsleApp* g_isle = NULL; + +// GLOBAL: ISLE 0x410034 +unsigned char g_mousedown = 0; + +// GLOBAL: ISLE 0x410038 +unsigned char g_mousemoved = 0; + +// GLOBAL: ISLE 0x41003c +BOOL g_closed = FALSE; + +// GLOBAL: ISLE 0x410040 +RECT g_windowRect = {0, 0, 640, 480}; + +// GLOBAL: ISLE 0x410050 +BOOL g_rmDisabled = FALSE; + +// GLOBAL: ISLE 0x410054 +BOOL g_waitingForTargetDepth = TRUE; + +// GLOBAL: ISLE 0x410058 +int g_targetWidth = 640; + +// GLOBAL: ISLE 0x41005c +int g_targetHeight = 480; + +// GLOBAL: ISLE 0x410060 +int g_targetDepth = 16; + +// GLOBAL: ISLE 0x410064 +BOOL g_reqEnableRMDevice = FALSE; + +// STRING: ISLE 0x4101c4 +#define WNDCLASS_NAME "Lego Island MainNoM App" + +// STRING: ISLE 0x4101dc +#define WINDOW_TITLE "LEGO\xAE" + +// Might be static functions of IsleApp +BOOL FindExistingInstance(); +BOOL StartDirectSound(); + +// FUNCTION: ISLE 0x401000 +IsleApp::IsleApp() +{ + m_hdPath = NULL; + m_cdPath = NULL; + m_deviceId = NULL; + m_savePath = NULL; + m_fullScreen = TRUE; + m_flipSurfaces = FALSE; + m_backBuffersInVram = TRUE; + m_using8bit = FALSE; + m_using16bit = TRUE; + m_unk0x24 = 0; + m_drawCursor = FALSE; + m_use3dSound = TRUE; + m_useMusic = TRUE; + m_useJoystick = FALSE; + m_joystickIndex = 0; + m_wideViewAngle = TRUE; + m_islandQuality = 1; + m_islandTexture = 1; + m_gameStarted = FALSE; + m_frameDelta = 10; + m_windowActive = TRUE; + +#ifdef COMPAT_MODE + { + MxRect32 r(0, 0, 639, 479); + MxVideoParamFlags flags; + m_videoParam = MxVideoParam(r, NULL, 1, flags); + } +#else + m_videoParam = MxVideoParam(MxRect32(0, 0, 639, 479), NULL, 1, MxVideoParamFlags()); +#endif + m_videoParam.Flags().Set16Bit(MxDirectDraw::GetPrimaryBitDepth() == 16); + + m_windowHandle = NULL; + m_cursorArrow = NULL; + m_cursorBusy = NULL; + m_cursorNo = NULL; + m_cursorCurrent = NULL; + + LegoOmni::CreateInstance(); +} + +// FUNCTION: ISLE 0x4011a0 +IsleApp::~IsleApp() +{ + if (LegoOmni::GetInstance()) { + Close(); + MxOmni::DestroyInstance(); + } + + if (m_hdPath) { + delete[] m_hdPath; + } + + if (m_cdPath) { + delete[] m_cdPath; + } + + if (m_deviceId) { + delete[] m_deviceId; + } + + if (m_savePath) { + delete[] m_savePath; + } +} + +// FUNCTION: ISLE 0x401260 +void IsleApp::Close() +{ + MxDSAction ds; + ds.SetUnknown24(-2); + + if (Lego()) { + GameState()->Save(0); + if (InputManager()) { + InputManager()->QueueEvent(c_notificationKeyPress, 0, 0, 0, 0x20); + } + + VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->RemoveAll(NULL); + + Lego()->RemoveWorld(ds.GetAtomId(), ds.GetObjectId()); + Lego()->DeleteObject(ds); + TransitionManager()->SetWaitIndicator(NULL); + Lego()->StopTimer(); + + MxLong lVar8; + do { + lVar8 = Streamer()->Close(NULL); + } while (lVar8 == 0); + + while (Lego()) { + if (Lego()->DoesEntityExist(ds)) { + break; + } + + Timer()->GetRealTime(); + TickleManager()->Tickle(); + } + } +} + +// FUNCTION: ISLE 0x4013b0 +BOOL IsleApp::SetupLegoOmni() +{ + BOOL result = FALSE; + char mediaPath[256]; + GetProfileStringA("LEGO Island", "MediaPath", "", mediaPath, sizeof(mediaPath)); + +#ifdef COMPAT_MODE + BOOL failure; + { + MxOmniCreateParam param(mediaPath, (struct HWND__*) m_windowHandle, m_videoParam, MxOmniCreateFlags()); + failure = Lego()->Create(param) == FAILURE; + } +#else + BOOL failure = + Lego()->Create(MxOmniCreateParam(mediaPath, (struct HWND__*) m_windowHandle, m_videoParam, MxOmniCreateFlags()) + ) == FAILURE; +#endif + + if (!failure) { + VariableTable()->SetVariable("ACTOR_01", ""); + TickleManager()->SetClientTickleInterval(VideoManager(), 10); + result = TRUE; + } + + return result; +} + +// FUNCTION: ISLE 0x401560 +void IsleApp::SetupVideoFlags( + BOOL fullScreen, + BOOL flipSurfaces, + BOOL backBuffers, + BOOL using8bit, + BOOL using16bit, + BOOL param_6, + BOOL param_7, + BOOL wideViewAngle, + char* deviceId +) +{ + m_videoParam.Flags().SetFullScreen(fullScreen); + m_videoParam.Flags().SetFlipSurfaces(flipSurfaces); + m_videoParam.Flags().SetBackBuffers(!backBuffers); + m_videoParam.Flags().SetF2bit0(!param_6); + m_videoParam.Flags().SetF1bit7(param_7); + m_videoParam.Flags().SetWideViewAngle(wideViewAngle); + m_videoParam.Flags().SetF2bit1(1); + m_videoParam.SetDeviceName(deviceId); + if (using8bit) { + m_videoParam.Flags().Set16Bit(0); + } + if (using16bit) { + m_videoParam.Flags().Set16Bit(1); + } +} + +// FUNCTION: ISLE 0x401610 +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) +{ + // Look for another instance, if we find one, bring it to the foreground instead + if (!FindExistingInstance()) { + return 0; + } + + // Attempt to create DirectSound instance + BOOL soundReady = FALSE; + for (int i = 0; i < 20; i++) { + if (StartDirectSound()) { + soundReady = TRUE; + break; + } + Sleep(500); + } + + // Throw error if sound unavailable + if (!soundReady) { + MessageBoxA( + NULL, + "\"LEGO\xAE Island\" is not detecting a DirectSound compatible sound card. Please quit all other " + "applications and try again.", + "Lego Island Error", + MB_OK + ); + return 0; + } + + // Create global app instance + g_isle = new IsleApp(); + + // Create window + if (g_isle->SetupWindow(hInstance, lpCmdLine) != SUCCESS) { + MessageBoxA( + NULL, + "\"LEGO\xAE Island\" failed to start. Please quit all other applications and try again.", + "LEGO\xAE Island Error", + MB_OK + ); + return 0; + } + + // Get reference to window + HWND window; + if (g_isle->GetWindowHandle()) { + window = g_isle->GetWindowHandle(); + } + + // Load accelerators (this call actually achieves nothing - there is no "AppAccel" resource in the original - but + // we'll keep this for authenticity) This line may actually be here because it's in DFVIEW, an example project that + // ships with MSVC420, and was such a clean example of a Win32 app, that it was later adapted into an "ExeSkeleton" + // sample for MSVC600. It's quite possible Mindscape derived this app from that example since they no longer had the + // luxury of the MFC AppWizard which we know they used for the frontend used during development (ISLEMFC.EXE, + // MAIN.EXE, et al.) + LoadAcceleratorsA(hInstance, "AppAccel"); + + MSG msg; + + while (!g_closed) { + while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE)) { + if (g_isle) { + g_isle->Tick(1); + } + } + + if (g_isle) { + g_isle->Tick(0); + } + + while (!g_closed) { + if (!PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) { + break; + } + + MSG nextMsg; + if (!g_isle || !g_isle->GetWindowHandle() || msg.message != WM_MOUSEMOVE || + !PeekMessageA(&nextMsg, NULL, 0, 0, PM_NOREMOVE) || nextMsg.message != WM_MOUSEMOVE) { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + + if (g_reqEnableRMDevice) { + g_reqEnableRMDevice = FALSE; + VideoManager()->EnableRMDevice(); + g_rmDisabled = FALSE; + Lego()->StopTimer(); + } + + if (g_closed) { + break; + } + + if (g_mousedown && g_mousemoved && g_isle) { + g_isle->Tick(0); + } + + if (g_mousemoved) { + g_mousemoved = FALSE; + } + } + } + + DestroyWindow(window); + + return msg.wParam; +} + +// FUNCTION: ISLE 0x401ca0 +BOOL FindExistingInstance() +{ + HWND hWnd = FindWindowA(WNDCLASS_NAME, WINDOW_TITLE); + if (hWnd) { + if (SetForegroundWindow(hWnd)) { + ShowWindow(hWnd, SW_RESTORE); + } + return 0; + } + return 1; +} + +// FUNCTION: ISLE 0x401ce0 +BOOL StartDirectSound() +{ + LPDIRECTSOUND lpDS = NULL; + HRESULT ret = DirectSoundCreate(NULL, &lpDS, NULL); + if (ret == DS_OK && lpDS != NULL) { + lpDS->Release(); + return TRUE; + } + + return FALSE; +} + +// FUNCTION: ISLE 0x401d20 +LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + NotificationId type; + unsigned char keyCode = 0; + + if (!g_isle) { + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + } + + switch (uMsg) { + case WM_PAINT: + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_ACTIVATE: + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_ACTIVATEAPP: + if (g_isle) { + if ((wParam != 0) && (g_isle->GetFullScreen())) { + MoveWindow( + hWnd, + g_windowRect.left, + g_windowRect.top, + (g_windowRect.right - g_windowRect.left) + 1, + (g_windowRect.bottom - g_windowRect.top) + 1, + TRUE + ); + } + g_isle->SetWindowActive(wParam); + } + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_CLOSE: + if (!g_closed && g_isle) { + if (g_isle) { + delete g_isle; + } + g_isle = NULL; + g_closed = TRUE; + return 0; + } + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_GETMINMAXINFO: + ((MINMAXINFO*) lParam)->ptMaxTrackSize.x = (g_windowRect.right - g_windowRect.left) + 1; + ((MINMAXINFO*) lParam)->ptMaxTrackSize.y = (g_windowRect.bottom - g_windowRect.top) + 1; + ((MINMAXINFO*) lParam)->ptMinTrackSize.x = (g_windowRect.right - g_windowRect.left) + 1; + ((MINMAXINFO*) lParam)->ptMinTrackSize.y = (g_windowRect.bottom - g_windowRect.top) + 1; + return 0; + case WM_ENTERMENULOOP: + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_SYSCOMMAND: + if (wParam == SC_SCREENSAVE) { + return 0; + } + if (wParam == SC_CLOSE && g_closed == FALSE) { + if (g_isle) { + if (g_rmDisabled) { + ShowWindow(g_isle->GetWindowHandle(), SW_RESTORE); + } + PostMessageA(g_isle->GetWindowHandle(), WM_CLOSE, 0, 0); + return 0; + } + } + else if (g_isle && g_isle->GetFullScreen() && (wParam == SC_MOVE || wParam == SC_KEYMENU)) { + return 0; + } + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_EXITMENULOOP: + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_MOVING: + if (g_isle && g_isle->GetFullScreen()) { + GetWindowRect(hWnd, (LPRECT) lParam); + return 0; + } + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_NCPAINT: + if (g_isle && g_isle->GetFullScreen()) { + return 0; + } + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_DISPLAYCHANGE: + if (g_isle && VideoManager() && g_isle->GetFullScreen() && VideoManager()->GetDirect3D()) { + if (VideoManager()->GetDirect3D()->AssignedDevice()) { + int targetDepth = wParam; + int targetWidth = LOWORD(lParam); + int targetHeight = HIWORD(lParam); + + if (g_waitingForTargetDepth) { + g_waitingForTargetDepth = FALSE; + g_targetDepth = targetDepth; + } + else { + BOOL valid = FALSE; + + if (g_targetWidth == targetWidth && g_targetHeight == targetHeight && + g_targetDepth == targetDepth) { + valid = TRUE; + } + + if (g_rmDisabled) { + if (valid) { + g_reqEnableRMDevice = TRUE; + } + } + else if (!valid) { + g_rmDisabled = TRUE; + Lego()->StartTimer(); + VideoManager()->DisableRMDevice(); + } + } + } + } + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + case WM_KEYDOWN: + // While this probably should be (HIWORD(lParam) & KF_REPEAT), this seems + // to be what the assembly is actually doing + if (lParam & (KF_REPEAT << 16)) { + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + } + type = c_notificationKeyPress; + keyCode = wParam; + break; + case WM_MOUSEMOVE: + g_mousemoved = 1; + type = c_notificationMouseMove; + break; + case WM_TIMER: + type = c_notificationTimer; + break; + case WM_LBUTTONDOWN: + g_mousedown = 1; + type = c_notificationButtonDown; + break; + case WM_LBUTTONUP: + g_mousedown = 0; + type = c_notificationButtonUp; + break; + case 0x5400: + if (g_isle) { + g_isle->SetupCursor(wParam); + return 0; + } + break; + case WM_SETCURSOR: + if (g_isle && (g_isle->GetCursorCurrent() == g_isle->GetCursorBusy() || + g_isle->GetCursorCurrent() == g_isle->GetCursorNo() || !g_isle->GetCursorCurrent())) { + SetCursor(g_isle->GetCursorCurrent()); + return 0; + } + break; + default: + return DefWindowProcA(hWnd, uMsg, wParam, lParam); + } + + if (g_isle) { + if (InputManager()) { + InputManager()->QueueEvent(type, wParam, LOWORD(lParam), HIWORD(lParam), keyCode); + } + if (g_isle && g_isle->GetDrawCursor() && type == c_notificationMouseMove) { + int x = LOWORD(lParam); + int y = HIWORD(lParam); + if (x >= 640) { + x = 639; + } + if (y >= 480) { + y = 479; + } + VideoManager()->MoveCursor(x, y); + } + } + + return 0; +} + +// FUNCTION: ISLE 0x4023e0 +MxResult IsleApp::SetupWindow(HINSTANCE hInstance, LPSTR lpCmdLine) +{ + WNDCLASSA wndclass; + ZeroMemory(&wndclass, sizeof(WNDCLASSA)); + + LoadConfig(); + + SetupVideoFlags( + m_fullScreen, + m_flipSurfaces, + m_backBuffersInVram, + m_using8bit, + m_using16bit, + m_unk0x24, + FALSE, + m_wideViewAngle, + m_deviceId + ); + + MxOmni::SetSound3D(m_use3dSound); + + srand(timeGetTime() / 1000); + SystemParametersInfoA(SPI_SETMOUSETRAILS, 0, NULL, 0); + + ZeroMemory(&wndclass, sizeof(WNDCLASSA)); + + wndclass.cbClsExtra = 0; + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndProc; + wndclass.cbWndExtra = 0; + wndclass.hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(APP_ICON)); + wndclass.hCursor = m_cursorArrow = m_cursorCurrent = LoadCursorA(hInstance, MAKEINTRESOURCEA(ISLE_ARROW)); + m_cursorBusy = LoadCursorA(hInstance, MAKEINTRESOURCEA(ISLE_BUSY)); + m_cursorNo = LoadCursorA(hInstance, MAKEINTRESOURCEA(ISLE_NO)); + wndclass.hInstance = hInstance; + wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH); + wndclass.lpszClassName = WNDCLASS_NAME; + + if (!RegisterClassA(&wndclass)) { + return FAILURE; + } + + if (m_fullScreen) { + AdjustWindowRectEx(&g_windowRect, WS_CAPTION | WS_SYSMENU, 0, WS_EX_APPWINDOW); + + m_windowHandle = CreateWindowExA( + WS_EX_APPWINDOW, + WNDCLASS_NAME, + WINDOW_TITLE, + WS_CAPTION | WS_SYSMENU, + g_windowRect.left, + g_windowRect.top, + g_windowRect.right - g_windowRect.left + 1, + g_windowRect.bottom - g_windowRect.top + 1, + NULL, + NULL, + hInstance, + NULL + ); + } + else { + AdjustWindowRectEx(&g_windowRect, WS_CAPTION | WS_SYSMENU, 0, WS_EX_APPWINDOW); + + m_windowHandle = CreateWindowExA( + WS_EX_APPWINDOW, + WNDCLASS_NAME, + WINDOW_TITLE, + WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, + CW_USEDEFAULT, + CW_USEDEFAULT, + g_windowRect.right - g_windowRect.left + 1, + g_windowRect.bottom - g_windowRect.top + 1, + NULL, + NULL, + hInstance, + NULL + ); + } + + if (!m_windowHandle) { + return FAILURE; + } + + if (m_fullScreen) { + MoveWindow( + m_windowHandle, + g_windowRect.left, + g_windowRect.top, + (g_windowRect.right - g_windowRect.left) + 1, + (g_windowRect.bottom - g_windowRect.top) + 1, + TRUE + ); + } + + ShowWindow(m_windowHandle, SW_SHOWNORMAL); + UpdateWindow(m_windowHandle); + if (!SetupLegoOmni()) { + return FAILURE; + } + + GameState()->SetSavePath(m_savePath); + GameState()->SerializePlayersInfo(1); + GameState()->SerializeScoreHistory(1); + + int iVar10; + switch (m_islandQuality) { + case 0: + iVar10 = 1; + break; + case 1: + iVar10 = 2; + break; + default: + iVar10 = 100; + } + + int uVar1 = (m_islandTexture == 0); + LegoModelPresenter::configureLegoModelPresenter(uVar1); + LegoPartPresenter::configureLegoPartPresenter(uVar1, iVar10); + LegoWorldPresenter::configureLegoWorldPresenter(m_islandQuality); + LegoBuildingManager::configureLegoBuildingManager(m_islandQuality); + LegoROI::configureLegoROI(iVar10); + LegoAnimationManager::configureLegoAnimationManager(m_islandQuality); + if (LegoOmni::GetInstance()) { + if (LegoOmni::GetInstance()->GetInputManager()) { + LegoOmni::GetInstance()->GetInputManager()->SetUseJoystick(m_useJoystick); + LegoOmni::GetInstance()->GetInputManager()->SetJoystickIndex(m_joystickIndex); + } + } + if (m_fullScreen) { + MoveWindow( + m_windowHandle, + g_windowRect.left, + g_windowRect.top, + (g_windowRect.right - g_windowRect.left) + 1, + (g_windowRect.bottom - g_windowRect.top) + 1, + TRUE + ); + } + ShowWindow(m_windowHandle, SW_SHOWNORMAL); + UpdateWindow(m_windowHandle); + + return SUCCESS; +} + +// FUNCTION: ISLE 0x402740 +BOOL IsleApp::ReadReg(LPCSTR name, LPSTR outValue, DWORD outSize) +{ + HKEY hKey; + DWORD valueType; + + BOOL out = FALSE; + DWORD size = outSize; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Mindscape\\LEGO Island", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { + if (RegQueryValueExA(hKey, name, NULL, &valueType, (LPBYTE) outValue, &size) == ERROR_SUCCESS) { + if (RegCloseKey(hKey) == ERROR_SUCCESS) { + out = TRUE; + } + } + } + + return out; +} + +// FUNCTION: ISLE 0x4027b0 +BOOL IsleApp::ReadRegBool(LPCSTR name, BOOL* out) +{ + char buffer[256]; + + BOOL read = ReadReg(name, buffer, sizeof(buffer)); + if (read) { + if (strcmp("YES", buffer) == 0) { + *out = TRUE; + return read; + } + + if (strcmp("NO", buffer) == 0) { + *out = FALSE; + return read; + } + + read = FALSE; + } + return read; +} + +// FUNCTION: ISLE 0x402880 +BOOL IsleApp::ReadRegInt(LPCSTR name, int* out) +{ + char buffer[256]; + + BOOL read = ReadReg(name, buffer, sizeof(buffer)); + if (read) { + *out = atoi(buffer); + } + + return read; +} + +// FUNCTION: ISLE 0x4028d0 +void IsleApp::LoadConfig() +{ + char buffer[1024]; + + if (!ReadReg("diskpath", buffer, sizeof(buffer))) { + strcpy(buffer, MxOmni::GetHD()); + } + + m_hdPath = new char[strlen(buffer) + 1]; + strcpy(m_hdPath, buffer); + MxOmni::SetHD(m_hdPath); + + if (!ReadReg("cdpath", buffer, sizeof(buffer))) { + strcpy(buffer, MxOmni::GetCD()); + } + + m_cdPath = new char[strlen(buffer) + 1]; + strcpy(m_cdPath, buffer); + MxOmni::SetCD(m_cdPath); + + ReadRegBool("Flip Surfaces", &m_flipSurfaces); + ReadRegBool("Full Screen", &m_fullScreen); + ReadRegBool("Wide View Angle", &m_wideViewAngle); + ReadRegBool("3DSound", &m_use3dSound); + ReadRegBool("Music", &m_useMusic); + ReadRegBool("UseJoystick", &m_useJoystick); + ReadRegInt("JoystickIndex", &m_joystickIndex); + ReadRegBool("Draw Cursor", &m_drawCursor); + + int backBuffersInVRAM; + if (ReadRegBool("Back Buffers in Video RAM", &backBuffersInVRAM)) { + m_backBuffersInVram = !backBuffersInVRAM; + } + + int bitDepth; + if (ReadRegInt("Display Bit Depth", &bitDepth)) { + if (bitDepth == 8) { + m_using8bit = TRUE; + } + else if (bitDepth == 16) { + m_using16bit = TRUE; + } + } + + if (!ReadReg("Island Quality", buffer, sizeof(buffer))) { + strcpy(buffer, "1"); + } + m_islandQuality = atoi(buffer); + + if (!ReadReg("Island Texture", buffer, sizeof(buffer))) { + strcpy(buffer, "1"); + } + m_islandTexture = atoi(buffer); + + if (ReadReg("3D Device ID", buffer, sizeof(buffer))) { + m_deviceId = new char[strlen(buffer) + 1]; + strcpy(m_deviceId, buffer); + } + + if (ReadReg("savepath", buffer, sizeof(buffer))) { + m_savePath = new char[strlen(buffer) + 1]; + strcpy(m_savePath, buffer); + } +} + +// FUNCTION: ISLE 0x402c20 +inline void IsleApp::Tick(BOOL sleepIfNotNextFrame) +{ + // GLOBAL: ISLE 0x4101c0 + static MxLong g_lastFrameTime = 0; + + // GLOBAL: ISLE 0x4101bc + static int g_startupDelay = 200; + + if (!m_windowActive) { + Sleep(0); + return; + } + + if (!Lego()) { + return; + } + if (!TickleManager()) { + return; + } + if (!Timer()) { + return; + } + + MxLong currentTime = Timer()->GetRealTime(); + if (currentTime < g_lastFrameTime) { + g_lastFrameTime = -m_frameDelta; + } + + if (m_frameDelta + g_lastFrameTime < currentTime) { + if (!Lego()->IsTimerRunning()) { + TickleManager()->Tickle(); + } + g_lastFrameTime = currentTime; + + if (g_startupDelay == 0) { + return; + } + + g_startupDelay--; + if (g_startupDelay != 0) { + return; + } + + LegoOmni::GetInstance()->CreateBackgroundAudio(); + BackgroundAudioManager()->Enable(this->m_useMusic); + + MxStreamController* stream = Streamer()->Open("\\lego\\scripts\\isle\\isle", MxStreamer::e_diskStream); + MxDSAction ds; + + if (!stream) { + stream = Streamer()->Open("\\lego\\scripts\\nocd", MxStreamer::e_diskStream); + if (!stream) { + return; + } + + ds.SetAtomId(stream->GetAtom()); + ds.SetUnknown24(-1); + ds.SetObjectId(0); + VideoManager()->EnableFullScreenMovie(TRUE, TRUE); + + if (Start(&ds) != SUCCESS) { + return; + } + } + else { + ds.SetAtomId(stream->GetAtom()); + ds.SetUnknown24(-1); + ds.SetObjectId(0); + if (Start(&ds) != SUCCESS) { + return; + } + m_gameStarted = TRUE; + } + } + else if (sleepIfNotNextFrame != 0) { + Sleep(0); + } +} + +// FUNCTION: ISLE 0x402e80 +void IsleApp::SetupCursor(WPARAM wParam) +{ + switch (wParam) { + case 0: + m_cursorCurrent = m_cursorArrow; + break; + case 1: + m_cursorCurrent = m_cursorBusy; + break; + case 2: + m_cursorCurrent = m_cursorNo; + break; + case 0xB: + m_cursorCurrent = NULL; + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + case 0xA: + break; + } + + SetCursor(m_cursorCurrent); +} diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h new file mode 100644 index 00000000..9fcd5df6 --- /dev/null +++ b/ISLE/isleapp.h @@ -0,0 +1,79 @@ +#ifndef ISLEAPP_H +#define ISLEAPP_H + +#include "mxtypes.h" +#include "mxvideoparam.h" + +#include + +// SIZE 0x8c +class IsleApp { +public: + IsleApp(); + ~IsleApp(); + + void Close(); + + BOOL SetupLegoOmni(); + void SetupVideoFlags( + BOOL fullScreen, + BOOL flipSurfaces, + BOOL backBuffers, + BOOL using8bit, + BOOL using16bit, + BOOL param_6, + BOOL param_7, + BOOL wideViewAngle, + char* deviceId + ); + MxResult SetupWindow(HINSTANCE hInstance, LPSTR lpCmdLine); + + BOOL ReadReg(LPCSTR name, LPSTR outValue, DWORD outSize); + BOOL ReadRegBool(LPCSTR name, BOOL* out); + BOOL ReadRegInt(LPCSTR name, int* out); + + void LoadConfig(); + void Tick(BOOL sleepIfNotNextFrame); + void SetupCursor(WPARAM wParam); + + inline HWND GetWindowHandle() { return m_windowHandle; } + inline MxLong GetFrameDelta() { return m_frameDelta; } + inline BOOL GetFullScreen() { return m_fullScreen; } + inline HCURSOR GetCursorCurrent() { return m_cursorCurrent; } + inline HCURSOR GetCursorBusy() { return m_cursorBusy; } + inline HCURSOR GetCursorNo() { return m_cursorNo; } + inline BOOL GetDrawCursor() { return m_drawCursor; } + + inline void SetWindowActive(BOOL p_windowActive) { m_windowActive = p_windowActive; } + +private: + LPSTR m_hdPath; // 0x00 + LPSTR m_cdPath; // 0x04 + LPSTR m_deviceId; // 0x08 + LPSTR m_savePath; // 0x0c + BOOL m_fullScreen; // 0x10 + BOOL m_flipSurfaces; // 0x14 + BOOL m_backBuffersInVram; // 0x18 + BOOL m_using8bit; // 0x1c + BOOL m_using16bit; // 0x20 + int m_unk0x24; // 0x24 + BOOL m_use3dSound; // 0x28 + BOOL m_useMusic; // 0x2c + BOOL m_useJoystick; // 0x30 + int m_joystickIndex; // 0x34 + BOOL m_wideViewAngle; // 0x38 + int m_islandQuality; // 0x3c + int m_islandTexture; // 0x40 + BOOL m_gameStarted; // 0x44 + MxLong m_frameDelta; // 0x48 + MxVideoParam m_videoParam; // 0x4c + BOOL m_windowActive; // 0x70 + HWND m_windowHandle; // 0x74 + BOOL m_drawCursor; // 0x78 + HCURSOR m_cursorArrow; // 0x7c + HCURSOR m_cursorBusy; // 0x80 + HCURSOR m_cursorNo; // 0x84 + HCURSOR m_cursorCurrent; // 0x88 +}; + +#endif // ISLEAPP_H diff --git a/ISLE/library_msvc.h b/ISLE/library_msvc.h new file mode 100644 index 00000000..a837fd3b --- /dev/null +++ b/ISLE/library_msvc.h @@ -0,0 +1,63 @@ +#ifdef 0 +// For ISLE symbols only + +// aka `operator new` +// LIBRARY: ISLE 0x402f80 +// ??2@YAPAXI@Z + +// aka `operator delete` +// LIBRARY: ISLE 0x402fa0 +// ??3@YAXPAX@Z + +// LIBRARY: ISLE 0x406dd0 +// _malloc + +// LIBRARY: ISLE 0x406f00 +// _free + +// LIBRARY: ISLE 0x407ec0 +// ___CxxFrameHandler + +// LIBRARY: ISLE 0x4081e0 +// _srand + +// LIBRARY: ISLE 0x4081f0 +// _rand + +// LIBRARY: ISLE 0x408220 +// _atol + +// LIBRARY: ISLE 0x4082d0 +// _atoi + +// LIBRARY: ISLE 0x4084c0 +// ?_query_new_handler@@YAP6AHI@ZXZ + +// LIBRARY: ISLE 0x4084d0 +// ?_query_new_mode@@YAHXZ + +// LIBRARY: ISLE 0x4085c0 +// _sprintf + +// LIBRARY: ISLE 0x408630 +// _abort + +// LIBRARY: ISLE 0x409110 +// __mtinit + +// LIBRARY: ISLE 0x409190 +// __getptd + +// GLOBAL: ISLE 0x4108e8 +// __osver + +// GLOBAL: ISLE 0x4108f0 +// __winmajor + +// GLOBAL: ISLE 0x4108f4 +// __winminor + +// GLOBAL: ISLE 0x410d50 +// __newmode + +#endif diff --git a/ISLE/library_smartheap.h b/ISLE/library_smartheap.h new file mode 100644 index 00000000..c503372e --- /dev/null +++ b/ISLE/library_smartheap.h @@ -0,0 +1,312 @@ +#ifdef 0 + +// LIBRARY: ISLE 0x402f10 +// ?shi_New@@YAPAXKIPAU_SHI_Pool@@@Z + +// LIBRARY: ISLE 0x402fb0 +// _MemInitDefaultPool@0 + +// LIBRARY: ISLE 0x403020 +// _shi_call_new_handler_msc + +// LIBRARY: ISLE 0x403050 +// _MemPoolShrink@4 + +// LIBRARY: ISLE 0x403180 +// _MemPoolPreAllocate@12 + +// LIBRARY: ISLE 0x403300 +// @_shi_initPageHeaders@4 + +// LIBRARY: ISLE 0x403570 +// @shi_allocPageHeader@4 + +// LIBRARY: ISLE 0x4035a0 +// @shi_freePageHeader@8 + +// LIBRARY: ISLE 0x403750 +// @_shi_deletePage@8 + +// LIBRARY: ISLE 0x403830 +// @_shi_allocExternal@12 + +// LIBRARY: ISLE 0x403a50 +// @_shi_initPageVariable@8 + +// LIBRARY: ISLE 0x403b00 +// _MemAllocPtr@12 + +// LIBRARY: ISLE 0x403d60 +// @_shi_allocVar@12 + +// LIBRARY: ISLE 0x403ef0 +// @_shi_allocBlock@12 + +// LIBRARY: ISLE 0x4040c0 +// _MemFreePtr@4 + +// LIBRARY: ISLE 0x404170 +// @_shi_freeVar@4 + +// LIBRARY: ISLE 0x404260 +// _MemReAllocPtr@12 + +// LIBRARY: ISLE 0x4043b0 +// @_shi_resizeAny@16 + +// LIBRARY: ISLE 0x404650 +// @_shi_resizeVar@8 + +// LIBRARY: ISLE 0x404820 +// _MemSizePtr@4 + +// LIBRARY: ISLE 0x4048d0 +// @shi_findAllocAddress@4 + +// LIBRARY: ISLE 0x404910 +// @_shi_sysAlloc@8 + +// LIBRARY: ISLE 0x4049a0 +// @_shi_sysFree@4 + +// LIBRARY: ISLE 0x404a00 +// @_shi_sysRealloc@12 + +// LIBRARY: ISLE 0x404ab0 +// @_shi_sysResize@12 + +// LIBRARY: ISLE 0x404b90 +// @_shi_sysSize@4 + +// LIBRARY: ISLE 0x404bd0 +// @_shi_sysAllocNear@4 + +// LIBRARY: ISLE 0x404bf0 +// @_shi_sysFreeNear@4 + +// LIBRARY: ISLE 0x404c10 +// @_shi_sysValidatePtr@12 + +// LIBRARY: ISLE 0x404d10 +// @_shi_sysValidateFunction@4 + +// LIBRARY: ISLE 0x405300 +// @_shi_sysAllocPool@12 + +// LIBRARY: ISLE 0x405520 +// @_shi_sysResizePool@16 + +// LIBRARY: ISLE 0x405690 +// @_shi_sysFreePage@4 + +// LIBRARY: ISLE 0x4057b0 +// @_shi_sysSizePage@4 + +// LIBRARY: ISLE 0x4057e0 +// @_shi_sysSizePool@8 + +// LIBRARY: ISLE 0x405800 +// @_shi_registerShared@16 + +// LIBRARY: ISLE 0x405a00 +// @_shi_unregisterShared@8 + +// LIBRARY: ISLE 0x405b20 +// @_shi_getNextPool@4 + +// LIBRARY: ISLE 0x405b30 +// @shi_delNextPool@4 + +// LIBRARY: ISLE 0x405d30 +// @shi_createAndEnterMutexShr@12 + +// LIBRARY: ISLE 0x405e20 +// @shi_termPoolMutexShr@4 + +// LIBRARY: ISLE 0x405e40 +// @shi_enterPoolMutexShr@4 + +// LIBRARY: ISLE 0x405e60 +// @shi_leavePoolMutexShr@4 + +// LIBRARY: ISLE 0x405e80 +// __shi_enterCriticalSection@0 + +// LIBRARY: ISLE 0x405ea0 +// __shi_leaveCriticalSection@0 + +// LIBRARY: ISLE 0x405ec0 +// __shi_createAndEnterMutex + +// LIBRARY: ISLE 0x405ef0 +// _shi_enterPoolMutexSafely + +// LIBRARY: ISLE 0x405fd0 +// _shi_enterPoolInitMutexReader + +// LIBRARY: ISLE 0x406060 +// _shi_leavePoolInitMutexReader + +// LIBRARY: ISLE 0x406090 +// _shi_enterPoolInitMutexWriter + +// LIBRARY: ISLE 0x406160 +// _shi_leavePoolInitMutexWriter + +// LIBRARY: ISLE 0x406180 +// _shi_isNT + +// LIBRARY: ISLE 0x4061b0 +// _MemPoolInit@4 + +// LIBRARY: ISLE 0x406520 +// _MemPoolSetPageSize@8 + +// LIBRARY: ISLE 0x406630 +// _MemPoolSetBlockSizeFS@8 + +// LIBRARY: ISLE 0x406710 +// @_shi_poolFree@8 + +// LIBRARY: ISLE 0x4068c0 +// @_shi_invokeErrorHandler1@8 + +// LIBRARY: ISLE 0x406be0 +// _MemErrorUnwind@0 + +// LIBRARY: ISLE 0x406c30 +// _MemDefaultErrorHandler@4 + +// LIBRARY: ISLE 0x406cb0 +// @_shi_taskRemovePool@4 + +// LIBRARY: ISLE 0x406d50 +// @_shi_getCurrentThreadContext@8 + +// LIBRARY: ISLE 0x406db0 +// @_shi_deleteThreadContext@8 + +// LIBRARY: ISLE 0x406e40 +// _calloc + +// LIBRARY: ISLE 0x406ea0 +// _realloc + +// LIBRARY: ISLE 0x406f10 +// __expand + +// LIBRARY: ISLE 0x406f50 +// __heapadd + +// LIBRARY: ISLE 0x406f60 +// __heapwalk + +// LIBRARY: ISLE 0x406ff0 +// __heapused + +// LIBRARY: ISLE 0x407020 +// __heapmin + +// LIBRARY: ISLE 0x407040 +// __msize + +// LIBRARY: ISLE 0x407050 +// __heapchk + +// LIBRARY: ISLE 0x407080 +// __heapset + +// LIBRARY: ISLE 0x407090 +// @_shi_sysReportError@16 + +// LIBRARY: ISLE 0x407110 +// _MemPoolSize@4 + +// LIBRARY: ISLE 0x4071a0 +// _MemPoolWalk@8 + +// LIBRARY: ISLE 0x407240 +// @_shi_walkPool@16 + +// LIBRARY: ISLE 0x407540 +// @shi_isBlockInUseSmall@8 + +// LIBRARY: ISLE 0x407800 +// @_shi_isBlockInUseFS@12 + +// LIBRARY: ISLE 0x407880 +// _MemPoolCheck@4 + +// LIBRARY: ISLE 0x407b20 +// _MemCheckPtr@8 + +// LIBRARY: ISLE 0x4084e0 +// __except_handler3 + +// GLOBAL: ISLE 0x40f0a0 +// _szLibName + +// GLOBAL: ISLE 0x4102f4 +// ?_new_handler@@3P6AXXZA + +// GLOBAL: ISLE 0x4102fc +// _MemDefaultPool + +// GLOBAL: ISLE 0x41031c +// __shi_compactPoolFn + +// GLOBAL: ISLE 0x410320 +// __shi_compactPageFn + +// GLOBAL: ISLE 0x410324 +// _MemDefaultPoolFlags + +// GLOBAL: ISLE 0x41032c +// __shi_mutexGlobalInit + +// GLOBAL: ISLE 0x410330 +// __shi_mutexMovInit + +// GLOBAL: ISLE 0x410334 +// __shi_mutexMovLockCount + +// GLOBAL: ISLE 0x410338 +// _shi_initPoolReaders + +// GLOBAL: ISLE 0x41033c +// _shi_eventInitPool + +// GLOBAL: ISLE 0x410340 +// _shi_mutexMovShr + +// GLOBAL: ISLE 0x410368 +// _shi_deferFreePools + +// GLOBAL: ISLE 0x410378 +// __shi_poolTerminating + +// GLOBAL: ISLE 0x41037c +// _MemDefaultPoolBlockSizeFS + +// GLOBAL: ISLE 0x410380 +// _MemDefaultPoolPageSize + +// GLOBAL: ISLE 0x410384 +// _SmartHeap_malloc + +// GLOBAL: ISLE 0x4105b0 +// __shi_TaskRecord + +// ~GLOBAL: ISLE 0x4125f8 +// ?_pnhHeap@@3P6AHI@ZA + +// GLOBAL: ISLE 0x412830 +// __shi_mutexMov + +// GLOBAL: ISLE 0x412850 +// _shi_mutexPoolSynch + +// GLOBAL: ISLE 0x412870 +// __shi_mutexGlobal + +#endif diff --git a/ISLE/res/arrow.cur b/ISLE/res/arrow.cur new file mode 100644 index 00000000..548b8dac Binary files /dev/null and b/ISLE/res/arrow.cur differ diff --git a/ISLE/res/busy.cur b/ISLE/res/busy.cur new file mode 100644 index 00000000..320d6b9a Binary files /dev/null and b/ISLE/res/busy.cur differ diff --git a/ISLE/res/isle.ico b/ISLE/res/isle.ico new file mode 100644 index 00000000..0d41ffde Binary files /dev/null and b/ISLE/res/isle.ico differ diff --git a/ISLE/res/isle.rc b/ISLE/res/isle.rc new file mode 100644 index 00000000..95432e06 --- /dev/null +++ b/ISLE/res/isle.rc @@ -0,0 +1,35 @@ +#include "resource.h" + +ISLE_ARROW CURSOR "arrow.cur" +ISLE_NO CURSOR "no.cur" +ISLE_BUSY CURSOR "busy.cur" +APP_ICON ICON "isle.ico" + +1 VERSIONINFO +FILEVERSION 1,1,0,0 +PRODUCTVERSION 1,1,0,0 +FILEOS 0x40004 +FILETYPE 0x1 +{ +BLOCK "StringFileInfo" +{ + BLOCK "040904b0" + { + VALUE "Comments", "DG JB AG RC EE" + VALUE "CompanyName", "Mindscape" + VALUE "FileDescription", "isle" + VALUE "FileVersion", "1, 1, 0, 0" + VALUE "InternalName", "isle" + VALUE "LegalCopyright", "Copyright \xA9 1997" + VALUE "OriginalFilename", "isle.exe" + VALUE "ProductName", "Adventures on LEGO Island" + VALUE "ProductVersion", "1, 1, 0, 0" + VALUE "SpecialBuild", "Very" + } +} + +BLOCK "VarFileInfo" +{ + VALUE "Translation", 0x0409, 0x04B0 +} +} diff --git a/ISLE/res/no.cur b/ISLE/res/no.cur new file mode 100644 index 00000000..b3966420 Binary files /dev/null and b/ISLE/res/no.cur differ diff --git a/ISLE/res/resource.h b/ISLE/res/resource.h new file mode 100644 index 00000000..647c616e --- /dev/null +++ b/ISLE/res/resource.h @@ -0,0 +1,5 @@ +#define ISLE_ARROW 102 +#define ISLE_NO 103 +#define ISLE_BUSY 104 + +#define APP_ICON 105 diff --git a/LEGO1/LegoOmni.def b/LEGO1/LegoOmni.def new file mode 100644 index 00000000..a3bbfe66 --- /dev/null +++ b/LEGO1/LegoOmni.def @@ -0,0 +1,138 @@ +; LegoOmni.def : Declares the module paarameters for the LEGO1.DLL. + +DESCRIPTION "Lego OMNI Windows Dynamic Link Library" + +EXPORTS + +; EXPORTs really required only. + +??0LegoBackgroundColor@@QAE@PBD0@Z +??0LegoGameState@@QAE@XZ +??0LegoWorld@@QAE@XZ +??0MxAtomId@@QAE@PBDW4LookupMode@@@Z +??0MxBitmap@@QAE@XZ +??0MxCore@@QAE@XZ +??0MxCriticalSection@@QAE@XZ +??0MxDSAction@@QAE@XZ +??0MxDSFile@@QAE@PBDK@Z +??0MxOmniCreateFlags@@QAE@XZ +??0MxOmniCreateParam@@QAE@PBDPAUHWND__@@AAVMxVideoParam@@VMxOmniCreateFlags@@@Z +??0MxString@@QAE@ABV0@@Z +??0MxVideoParam@@QAE@AAV0@@Z +??0MxVideoParam@@QAE@AAVMxRect32@@PAVMxPalette@@KAAVMxVideoParamFlags@@@Z +??0MxVideoParam@@QAE@XZ +??0MxVideoParamFlags@@QAE@XZ +??1LegoEntity@@UAE@XZ +??1LegoGameState@@QAE@XZ +??1LegoWorld@@UAE@XZ +??1MXIOINFO@@QAE@XZ +??1MxAtomId@@QAE@XZ +??1MxBitmap@@UAE@XZ +??1MxCore@@UAE@XZ +??1MxCriticalSection@@QAE@XZ +??1MxDSAction@@UAE@XZ +??1MxDSFile@@UAE@XZ +??1MxPresenter@@UAE@XZ +??1MxString@@UAE@XZ +??1MxVideoParam@@QAE@XZ +??4MxAtomId@@QAEAAV0@ABV0@@Z +??4MxString@@QAEABV0@PBD@Z +??4MxVideoParam@@QAEAAV0@ABV0@@Z +??8MxPalette@@QAEEAAV0@@Z +?BackgroundAudioManager@@YAPAVMxBackgroundAudioManager@@XZ +?Close@MxDSFile@@UAEJXZ +?Close@MxStreamer@@QAEJPBD@Z +?CreateBackgroundAudio@LegoOmni@@QAEXXZ +?CreateInstance@LegoOmni@@SAXXZ +?CreatePalette@MxBitmap@@UAEPAVMxPalette@@XZ +?CreateStreamObject@@YAPAVMxDSObject@@PAVMxDSFile@@F@Z +?DestroyInstance@MxOmni@@SAXXZ +?Detach@MxPalette@@QAEXXZ +?DisableRMDevice@LegoVideoManager@@QAEHXZ +?DoneTickle@MxPresenter@@MAEXXZ +?Enable@MxBackgroundAudioManager@@QAEXE@Z +?Enable@MxPresenter@@UAEXE@Z +?EnableFullScreenMovie@LegoVideoManager@@QAEXEE@Z +?EnableRMDevice@LegoVideoManager@@QAEHXZ +?EndAction@MxPresenter@@UAEXXZ +?EventManager@@YAPAVMxEventManager@@XZ +?FlipToGDISurface@MxDirectDraw@@QAEHXZ +?GameState@@YAPAVLegoGameState@@XZ +?GetBufferSize@MxDSFile@@UAEKXZ +?GetCD@MxOmni@@SAPBDXZ +?GetCurrPathInfo@LegoOmni@@SAHPAPAVLegoPathBoundary@@AAH@Z +?GetDefaults@LegoNavController@@SAXPAHPAM11111111PAE@Z +?GetHD@MxOmni@@SAPBDXZ +?GetInstance@LegoOmni@@SAPAV1@XZ +?GetInstance@MxOmni@@SAPAV1@XZ +?GetInstance@MxScheduler@@SAPAV1@XZ +?GetNoCD_SourceName@@YAPBDXZ +?GetPartsThreshold@RealtimeView@@SAMXZ +?GetPrimaryBitDepth@MxDirectDraw@@SAHXZ +?GetRealTime@MxTimer@@QAEJXZ +?GetStreamBuffersNum@MxDSFile@@UAEKXZ +?GetUserMaxLOD@RealtimeView@@SAMXZ +?GetVariable@MxVariableTable@@QAEPBDPBD@Z +?Init@MxPresenter@@IAEXXZ +?InputManager@@YAPAVLegoInputManager@@XZ +?InvalidateRect@MxVideoManager@@QAEXAAVMxRect32@@@Z +?IsSound3D@MxOmni@@SAEXZ +?Lego@@YAPAVLegoOmni@@XZ +?Load@LegoGameState@@QAEJK@Z +?MSoundManager@@YAPAVMxSoundManager@@XZ +?MakeSourceName@@YAXPADPBD@Z +?MoveCursor@LegoVideoManager@@QAEXHH@Z +?MusicManager@@YAPAVMxMusicManager@@XZ +?NotificationManager@@YAPAVMxNotificationManager@@XZ +?Notify@MxCore@@UAEJAAVMxParam@@@Z +?Open@MxDSFile@@UAEJK@Z +?Open@MxStreamer@@QAEPAVMxStreamController@@PBDG@Z +?ParseExtra@MxPresenter@@MAEXXZ +?Pause@MxDirectDraw@@QAEHH@Z +?PickEntity@@YAPAVLegoEntity@@JJ@Z +?PickROI@@YAPAVLegoROI@@JJ@Z +?QueueEvent@LegoInputManager@@QAEXW4NotificationId@@EJJE@Z +?Read@MxBitmap@@UAEJPBD@Z +?Read@MxDSFile@@UAEJPAEK@Z +?RealizePalette@MxVideoManager@@UAEJPAVMxPalette@@@Z +?Register@LegoInputManager@@QAEXPAVMxCore@@@Z +?RemoveAll@ViewManager@@QAEXPAVViewROI@@@Z +?RemoveWorld@LegoOmni@@QAEXABVMxAtomId@@J@Z +?Save@LegoGameState@@QAEJK@Z +?Seek@MxDSFile@@UAEJJH@Z +?SerializePlayersInfo@LegoGameState@@QAEXF@Z +?SerializeScoreHistory@LegoGameState@@QAEXF@Z +?SetCD@MxOmni@@SAXPBD@Z +?SetDefaults@LegoNavController@@SAXHMMMMMMMMME@Z +?SetDeviceName@MxVideoParam@@QAEXPAD@Z +?SetDisplayBB@LegoROI@@QAEXH@Z +?SetDoMutex@MxCriticalSection@@SAXXZ +?SetHD@MxOmni@@SAXPBD@Z +?SetObjectName@MxDSObject@@QAEXPBD@Z +?SetOmniUserMessage@@YAXP6AXPBDH@Z@Z +?SetPartsThreshold@RealtimeView@@SAXM@Z +?SetSavePath@LegoGameState@@QAEXPAD@Z +?SetSound3D@MxOmni@@SAXE@Z +?SetUserMaxLOD@RealtimeView@@SAXM@Z +?SetVariable@MxVariableTable@@QAEXPAVMxVariable@@@Z +?SetVariable@MxVariableTable@@QAEXPBD0@Z +?SetWaitIndicator@MxTransitionManager@@QAEXPAVMxVideoPresenter@@@Z +?SoundManager@@YAPAVLegoSoundManager@@XZ +?Start@@YAJPAVMxDSAction@@@Z +?StartAction@MxPresenter@@UAEJPAVMxStreamController@@PAVMxDSAction@@@Z +?StartMultiTasking@MxScheduler@@QAEXK@Z +?Streamer@@YAPAVMxStreamer@@XZ +?Tickle@MxPresenter@@UAEJXZ +?TickleManager@@YAPAVMxTickleManager@@XZ +?Timer@@YAPAVMxTimer@@XZ +?TransitionManager@@YAPAVMxTransitionManager@@XZ +?UnRegister@LegoInputManager@@QAEXPAVMxCore@@@Z +?VariableTable@@YAPAVMxVariableTable@@XZ +?VideoManager@@YAPAVLegoVideoManager@@XZ +?configureLegoAnimationManager@LegoAnimationManager@@SAXH@Z +?configureLegoBuildingManager@LegoBuildingManager@@SAXH@Z +?configureLegoModelPresenter@LegoModelPresenter@@SAXH@Z +?configureLegoPartPresenter@LegoPartPresenter@@SAXHH@Z +?configureLegoROI@LegoROI@@SAXH@Z +?configureLegoWorldPresenter@LegoWorldPresenter@@SAXH@Z +_DllMain@12 diff --git a/LEGO1/LegoOmni.mingw.def b/LEGO1/LegoOmni.mingw.def new file mode 100644 index 00000000..e2c4ce5f --- /dev/null +++ b/LEGO1/LegoOmni.mingw.def @@ -0,0 +1,164 @@ +; LegoOmni.def : Declares the module paarameters for the LEGO1.DLL. + +; DESCRIPTION " Lego OMNI Windows Dynamic Link Library" + +EXPORTS + +; EXPORTs really required only. + +_ZN13LegoGameState11SetSavePathEPc +_ZN13LegoGameState20SerializePlayersInfoEs +_ZN13LegoGameState21SerializeScoreHistoryEs +_ZN13LegoGameState4SaveEj +_ZN13LegoGameStateC1Ev +_ZN13LegoGameStateC2Ev +_ZN13LegoGameStateD1Ev +_ZN13LegoGameStateD2Ev +_ZN9LegoWorldC1Ev +_ZN9LegoWorldC2Ev +_ZN9LegoWorldD0Ev +_ZN9LegoWorldD1Ev +_ZN9LegoWorldD2Ev +DllMain@12 +_Z10PickEntityii +_Z12EventManagerv +_Z12InputManagerv +_Z12MusicManagerv +_Z12SoundManagerv +_Z12VideoManagerv +_Z13MSoundManagerv +_Z13TickleManagerv +_Z13VariableTablev +_Z14MakeSourceNamePcPKc +_Z17TransitionManagerv +_Z18CreateStreamObjectP8MxDSFiles +_Z18GetNoCD_SourceNamev +_Z18SetOmniUserMessagePFvPKciE +_Z19NotificationManagerv +_Z22BackgroundAudioManagerv +_Z4Legov +_Z5StartP10MxDSAction +_Z5Timerv +_Z7PickROIii +_Z8Streamerv +_Z9GameStatev +_ZN10MxDSActionC1Ev +_ZN10MxDSActionC2Ev +_ZN10MxDSActionD0Ev +_ZN10MxDSActionD1Ev +_ZN10MxDSActionD2Ev +_ZN10MxDSObject13SetObjectNameEPKc +_ZN10MxStreamer4OpenEPKct +_ZN10MxStreamer5CloseEPKc +_ZN11MxPresenter10DoneTickleEv +_ZN11MxPresenter10ParseExtraEv +_ZN11MxPresenter11StartActionEP18MxStreamControllerP10MxDSAction +_ZN11MxPresenter4InitEv +_ZN11MxPresenter6EnableEh +_ZN11MxPresenter6TickleEv +_ZN11MxPresenter9EndActionEv +_ZN11MxScheduler11GetInstanceEv +_ZN11MxScheduler17StartMultiTaskingEj +_ZN11ViewManager9RemoveAllEP7ViewROI +_ZN12MxDirectDraw16FlipToGDISurfaceEv +_ZN12MxDirectDraw18GetPrimaryBitDepthEv +_ZN12MxDirectDraw5PauseEi +_ZN12MxVideoParam13SetDeviceNameEPc +_ZN12MxVideoParamC1ERS_ +_ZN12MxVideoParamC1Ev +_ZN12MxVideoParamC2ERS_ +_ZN12MxVideoParamC2Ev +_ZN12MxVideoParamD1Ev +_ZN12MxVideoParamD2Ev +_ZN12MxVideoParamaSERKS_ +_ZN12RealtimeView13GetUserMaxLODEv +_ZN12RealtimeView13SetUserMaxLODEf +_ZN12RealtimeView17GetPartsThresholdEv +_ZN12RealtimeView17SetPartsThresholdEf +_ZN14MxVideoManager14InvalidateRectER8MxRect32 +_ZN14MxVideoManager14RealizePaletteEP9MxPalette +_ZN15MxVariableTable11GetVariableEPKc +_ZN15MxVariableTable11SetVariableEP10MxVariable +_ZN15MxVariableTable11SetVariableEPKcS1_ = _ZN15MxVariableTable11SetVariableEPKcS1_ +;_ZN16LegoInputManager10QueueEventE14NotificationIdhiih +_ZN16LegoInputManager10QueueEventE14NotificationIdhiih +_ZN16LegoInputManager10UnRegisterEP6MxCore +_ZN16LegoInputManager8RegisterEP6MxCore +_ZN16LegoVideoManager10MoveCursorEii +_ZN16LegoVideoManager14EnableRMDeviceEv +_ZN16LegoVideoManager15DisableRMDeviceEv +_ZN16LegoVideoManager21EnableFullScreenMovieEhh +_ZN17LegoNavController11GetDefaultsEPiPfS1_S1_S1_S1_S1_S1_S1_S1_Ph +_ZN17LegoNavController11SetDefaultsEifffffffffh +_ZN17LegoPartPresenter26configureLegoPartPresenterEii +_ZN17MxCriticalSection10SetDoMutexEv +_ZN17MxCriticalSectionC1Ev +_ZN17MxCriticalSectionC2Ev +_ZN17MxCriticalSectionD1Ev +_ZN17MxCriticalSectionD2Ev +_ZN17MxOmniCreateFlagsC1Ev +_ZN17MxOmniCreateFlagsC2Ev +_ZN17MxOmniCreateParamC1EPKcP6HWND__R12MxVideoParam17MxOmniCreateFlags +_ZN17MxVideoParamFlagsC1Ev +_ZN17MxVideoParamFlagsC2Ev +_ZN18LegoModelPresenter27configureLegoModelPresenterEi +_ZN18LegoWorldPresenter27configureLegoWorldPresenterEi +_ZN19LegoBuildingManager28configureLegoBuildingManagerEi +_ZN19MxTransitionManager16SetWaitIndicatorEP16MxVideoPresenter +_ZN20LegoAnimationManager29configureLegoAnimationManagerEi +_ZN24MxBackgroundAudioManager6EnableEh +_ZN6MxCore6NotifyER7MxParam +_ZN6MxCoreC1Ev +_ZN6MxCoreC2Ev +_ZN6MxCoreD0Ev +_ZN6MxCoreD1Ev +_ZN6MxCoreD2Ev +_ZN6MxOmni10SetSound3DEh +_ZN6MxOmni11GetInstanceEv +_ZN6MxOmni15DestroyInstanceEv +_ZN6MxOmni5GetCDEv +_ZN6MxOmni5GetHDEv +_ZN6MxOmni5SetCDEPKc +_ZN6MxOmni5SetHDEPKc +_ZN6MxOmni9IsSound3DEv +_ZN7LegoROI12SetDisplayBBEi +_ZN7LegoROI16configureLegoROIEi +_ZN7MxTimer11GetRealTimeEv +_ZN8LegoOmni11GetInstanceEv +_ZN8LegoOmni11RemoveWorldERK8MxAtomIdi +_ZN8LegoOmni14CreateInstanceEv +_ZN8LegoOmni15GetCurrPathInfoEPP16LegoPathBoundaryRi +_ZN8LegoOmni21CreateBackgroundAudioEv +_ZN8MXIOINFOD1Ev +_ZN8MXIOINFOD2Ev +_ZN8MxAtomIdC1EPKc10LookupMode +_ZN8MxAtomIdC2EPKc10LookupMode +_ZN8MxAtomIdD1Ev +_ZN8MxAtomIdD2Ev +_ZN8MxAtomIdaSERKS_ +_ZN8MxBitmap13CreatePaletteEv +_ZN8MxBitmap4ReadEPKc +_ZN8MxBitmapC1Ev +_ZN8MxBitmapC2Ev +_ZN8MxBitmapD0Ev +_ZN8MxBitmapD1Ev +_ZN8MxBitmapD2Ev +_ZN8MxDSFile13GetBufferSizeEv +_ZN8MxDSFile19GetStreamBuffersNumEv +_ZN8MxDSFile4OpenEj +_ZN8MxDSFile4ReadEPhj +_ZN8MxDSFile4SeekEii +_ZN8MxDSFile5CloseEv +_ZN8MxDSFileC1EPKcj +_ZN8MxDSFileC2EPKcj +_ZN8MxDSFileD0Ev +_ZN8MxDSFileD1Ev +_ZN8MxDSFileD2Ev +_ZN8MxStringC1ERKS_ +_ZN8MxStringC2ERKS_ +_ZN8MxStringD0Ev +_ZN8MxStringD1Ev +_ZN8MxStringD2Ev +_ZN8MxStringaSEPKc +_ZN9MxPalette6DetachEv +_ZN9MxPaletteeqERS_ diff --git a/LEGO1/define.cpp b/LEGO1/define.cpp new file mode 100644 index 00000000..89d70dd0 --- /dev/null +++ b/LEGO1/define.cpp @@ -0,0 +1,125 @@ +#include "define.h" + +// GLOBAL: LEGO1 0x10102048 +// STRING: LEGO1 0x10102040 +const char* g_strACTION = "ACTION"; + +// GLOBAL: LEGO1 0x1010204c +// STRING: LEGO1 0x10102034 +const char* g_strANIMATION = "ANIMATION"; + +// GLOBAL: LEGO1 0x10102050 +// STRING: LEGO1 0x10102024 +const char* g_strATTACH_CAMERA = "ATTACH_CAMERA"; + +// GLOBAL: LEGO1 0x10102054 +// STRING: LEGO1 0x10102018 +const char* g_strAUTO_CREATE = "AUTO_CREATE"; + +// GLOBAL: LEGO1 0x1010205c +// STRING: LEGO1 0x10102000 +const char* g_strBOTTOM_TO_TOP = "BOTTOM_TO_TOP"; + +// GLOBAL: LEGO1 0x10102064 +// STRING: LEGO1 0x10101fec +const char* g_strSTYLE = "STYLE"; + +// GLOBAL: LEGO1 0x10102068 +// STRING: LEGO1 0x10101fe4 +const char* g_strGRID = "GRID"; + +// GLOBAL: LEGO1 0x1010206c +// STRING: LEGO1 0x10101fe0 +const char* g_strMAP = "MAP"; + +// GLOBAL: LEGO1 0x10102074 +// STRING: LEGO1 0x10101fd0 +const char* g_strTOGGLE = "TOGGLE"; + +// GLOBAL: LEGO1 0x10102078 +// STRING: LEGO1 0x10101fc4 +const char* g_strDB_CREATE = "DB_CREATE"; + +// GLOBAL: LEGO1 0x1010207c +// STRING: LEGO1 0x10101fb4 +const char* g_strFILLER_INDEX = "FILLER_INDEX"; + +// GLOBAL: LEGO1 0x10102080 +// STRING: LEGO1 0x100f4368 +const char* g_strFROM_PARENT = "FROM_PARENT"; + +// GLOBAL: LEGO1 0x10102084 +// STRING: LEGO1 0x10101fa4 +const char* g_strHIDE_ON_STOP = "HIDE_ON_STOP"; + +// GLOBAL: LEGO1 0x10102088 +// STRING: LEGO1 0x10101f94 +const char* g_strLEFT_TO_RIGHT = "LEFT_TO_RIGHT"; + +// GLOBAL: LEGO1 0x10102094 +// STRING: LEGO1 0x10101f70 +const char* g_strTYPE = "TYPE"; + +// GLOBAL: LEGO1 0x10102098 +// STRING: LEGO1 0x10101f60 +const char* g_strMUST_SUCCEED = "MUST_SUCCEED"; + +// GLOBAL: LEGO1 0x1010209c +// STRING: LEGO1 0x10101f58 +const char* g_strOBJECT = "OBJECT"; + +// GLOBAL: LEGO1 0x101020a8 +// STRING: LEGO1 0x10101f38 +const char* g_strPTATCAM = "PTATCAM"; + +// GLOBAL: LEGO1 0x101020ac +// STRING: LEGO1 0x10101f28 +const char* g_strRIGHT_TO_LEFT = "RIGHT_TO_LEFT"; + +// GLOBAL: LEGO1 0x101020b0 +// STRING: LEGO1 0x10101f20 +const char* g_strSOUND = "SOUND"; + +// GLOBAL: LEGO1 0x101020b4 +// STRING: LEGO1 0x10101f18 +const char* g_strMUTE = "MUTE"; + +// GLOBAL: LEGO1 0x101020b8 +// STRING: LEGO1 0x100f09cc +const char* g_strSPEED = "SPEED"; + +// GLOBAL: LEGO1 0x101020bc +// STRING: LEGO1 0x10101f10 +const char* g_strSUBST = "SUBST"; + +// GLOBAL: LEGO1 0x101020c0 +// STRING: LEGO1 0x10101f00 +const char* g_strTOP_TO_BOTTOM = "TOP_TO_BOTTOM"; + +// GLOBAL: LEGO1 0x101020c4 +// STRING: LEGO1 0x10101ef0 +const char* g_strTRIGGERS_SOURCE = "TRIGGERS_SOURCE"; + +// GLOBAL: LEGO1 0x101020c8 +// STRING: LEGO1 0x10101ee4 +const char* g_strVARIABLE = "VARIABLE"; + +// GLOBAL: LEGO1 0x101020cc +// STRING: LEGO1 0x100f3808 +const char* g_strVISIBILITY = "VISIBILITY"; + +// GLOBAL: LEGO1 0x101020d0 +// STRING: LEGO1 0x10101edc +const char* g_strWORLD = "WORLD"; + +// GLOBAL: LEGO1 0x101020d4 +// STRING: LEGO1 0x10101ed0 +const char* g_strANIMMAN_ID = "ANIMMAN_ID"; + +// GLOBAL: LEGO1 0x101020e0 +// STRING: LEGO1 0x10101eb0 +const char* g_strBMP_ISMAP = "BMP_ISMAP"; + +// GLOBAL: LEGO1 0x101020e4 +// STRING: LEGO1 0x10101eac +const char* g_parseExtraTokens = ":;"; diff --git a/LEGO1/define.h b/LEGO1/define.h new file mode 100644 index 00000000..9bb1962a --- /dev/null +++ b/LEGO1/define.h @@ -0,0 +1,38 @@ +#ifndef DEFINE_H +#define DEFINE_H + +#include "mxtypes.h" + +extern const char* g_parseExtraTokens; +extern const char* g_strWORLD; +extern const char* g_strSOUND; +extern const char* g_strOBJECT; +extern const char* g_strANIMATION; +extern const char* g_strACTION; +extern const char* g_strVISIBILITY; +extern const char* g_strSPEED; +extern const char* g_strATTACH_CAMERA; +extern const char* g_strMUTE; +extern const char* g_strANIMMAN_ID; +extern const char* g_strFROM_PARENT; +extern const char* g_strHIDE_ON_STOP; +extern const char* g_strMUST_SUCCEED; +extern const char* g_strSUBST; +extern const char* g_strTRIGGERS_SOURCE; +extern const char* g_strPTATCAM; +extern const char* g_strTOGGLE; +extern const char* g_strMAP; +extern const char* g_strGRID; +extern const char* g_strSTYLE; +extern const char* g_strTYPE; +extern const char* g_strLEFT_TO_RIGHT; +extern const char* g_strRIGHT_TO_LEFT; +extern const char* g_strBOTTOM_TO_TOP; +extern const char* g_strTOP_TO_BOTTOM; +extern const char* g_strFILLER_INDEX; +extern const char* g_strVARIABLE; +extern const char* g_strBMP_ISMAP; +extern const char* g_strAUTO_CREATE; +extern const char* g_strDB_CREATE; + +#endif // DEFINE_H diff --git a/LEGO1/lego/legoomni/include/act1state.h b/LEGO1/lego/legoomni/include/act1state.h new file mode 100644 index 00000000..dcc09959 --- /dev/null +++ b/LEGO1/lego/legoomni/include/act1state.h @@ -0,0 +1,136 @@ +#ifndef ACT1STATE_H +#define ACT1STATE_H + +#include "legostate.h" + +class LegoNamedTexture; + +// VTABLE: LEGO1 0x100d7028 +// SIZE 0x26c +class Act1State : public LegoState { +public: + enum ElevatorFloor { + c_floor1 = 1, + c_floor2, + c_floor3 + }; + + enum { + e_unk953 = 953, + e_unk954 = 954, + e_unk955 = 955, + }; + + // SIZE 0x4c + class NamedPlane { + public: + // FUNCTION: LEGO1 0x10033800 + NamedPlane() {} + + inline void SetName(const char* p_name) { m_name = p_name; } + inline const MxString* GetName() const { return &m_name; } + + // FUNCTION: LEGO1 0x100344d0 + MxResult Serialize(LegoFile* p_file) + { + if (p_file->IsWriteMode()) { + p_file->WriteString(m_name); + p_file->WriteVector3(m_point1); + p_file->WriteVector3(m_point2); + p_file->WriteVector3(m_point3); + } + else if (p_file->IsReadMode()) { + p_file->ReadString(m_name); + p_file->ReadVector3(m_point1); + p_file->ReadVector3(m_point2); + p_file->ReadVector3(m_point3); + } + + return SUCCESS; + } + + private: + MxString m_name; // 0x00 + Mx3DPointFloat m_point1; // 0x10 + Mx3DPointFloat m_point2; // 0x24 + Mx3DPointFloat m_point3; // 0x38 + }; + + Act1State(); + + // FUNCTION: LEGO1 0x100338a0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0154 + return "Act1State"; + } + + // FUNCTION: LEGO1 0x100338b0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Act1State::ClassName()) || LegoState::IsA(p_name); + } + + MxBool SetFlag() override; // vtable+0x18 + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + void FUN_10034660(); + void FUN_100346a0(); + void FUN_10034b60(); + void FUN_10034d00(); + + inline MxU32 GetUnknown18() { return m_unk0x018; } + inline ElevatorFloor GetElevatorFloor() { return (ElevatorFloor) m_elevFloor; } + inline MxU8 GetUnknown21() { return m_unk0x021; } + + inline void SetUnknown18(MxU32 p_unk0x18) { m_unk0x018 = p_unk0x18; } + inline void SetElevatorFloor(ElevatorFloor p_elevFloor) { m_elevFloor = p_elevFloor; } + inline void SetUnknown21(MxU8 p_unk0x21) { m_unk0x021 = p_unk0x21; } + + // SYNTHETIC: LEGO1 0x10033960 + // Act1State::`scalar deleting destructor' + + friend class Isle; + friend class SkateBoard; + +protected: + MxS32* m_unk0x008; // 0x008 FIXME: count for m_unk0x008 + MxS16 m_unk0x00c; // 0x00c + undefined2 m_unk0x00e; // 0x00e + undefined2 m_unk0x010; // 0x010 + undefined m_unk0x012; // 0x012 + MxS32 m_unk0x014; // 0x014 + MxU32 m_unk0x018; // 0x018 + MxS16 m_elevFloor; // 0x01c + MxBool m_unk0x01e; // 0x01e + MxBool m_unk0x01f; // 0x01f + MxBool m_planeActive; // 0x020 + undefined m_unk0x021; // 0x021 + MxBool m_unk0x022; // 0x022 + undefined m_unk0x023; // 0x023 + NamedPlane m_unk0x024; // 0x024 + NamedPlane m_unk0x070; // 0x070 + NamedPlane m_unk0x0bc; // 0x0bc + NamedPlane m_unk0x108; // 0x108 + LegoNamedTexture* m_unk0x154; // 0x154 + LegoNamedTexture* m_unk0x158; // 0x158 + LegoNamedTexture* m_unk0x15c; // 0x15c + MxCore* m_unk0x160; // 0x160 + NamedPlane m_unk0x164; // 0x164 + LegoNamedTexture* m_unk0x1b0; // 0x1b0 + LegoNamedTexture* m_unk0x1b4; // 0x1b4 + MxCore* m_unk0x1b8; // 0x1b8 + NamedPlane m_unk0x1bc; // 0x1bc + LegoNamedTexture* m_unk0x208; // 0x208 + MxCore* m_unk0x20c; // 0x20c + NamedPlane m_unk0x210; // 0x210 + LegoNamedTexture* m_unk0x25c; // 0x25c + LegoNamedTexture* m_unk0x260; // 0x260 + LegoNamedTexture* m_unk0x264; // 0x264 + MxCore* m_unk0x268; // 0x268 +}; + +// FUNCTION: LEGO1 0x10033a70 +// Act1State::NamedPlane::~NamedPlane + +#endif // ACT1STATE_H diff --git a/LEGO1/lego/legoomni/include/act2actor.h b/LEGO1/lego/legoomni/include/act2actor.h new file mode 100644 index 00000000..f73c6d07 --- /dev/null +++ b/LEGO1/lego/legoomni/include/act2actor.h @@ -0,0 +1,28 @@ +#ifndef ACT2ACTOR_H +#define ACT2ACTOR_H + +#include "legoanimactor.h" + +// VTABLE: LEGO1 0x100d6078 LegoPathActor +// VTABLE: LEGO1 0x100d6148 LegoAnimActor +// SIZE 0x1a8 +class Act2Actor : public LegoAnimActor { +public: + Act2Actor(); + + void SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2) override; // vtable+0x24 + void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 + MxS32 VTable0x68(Vector3&, Vector3&, Vector3&) override; // vtable+0x68 + void VTable0x70(float p_und) override; // vtable+0x70 + MxResult VTable0x94(LegoPathActor*, MxBool) override; // vtable+0x94 + MxResult WaitForAnimation() override; // vtable+0x9c + MxS32 VTable0xa0() override; // vtable+0xa0 + + // SYNTHETIC: LEGO1 0x1001a0a0 + // Act2Actor::`scalar deleting destructor' + +private: + undefined m_unk0x1c[0x34]; // 0x1c +}; + +#endif // ACT2ACTOR_H diff --git a/LEGO1/lego/legoomni/include/act2brick.h b/LEGO1/lego/legoomni/include/act2brick.h new file mode 100644 index 00000000..18d03d4e --- /dev/null +++ b/LEGO1/lego/legoomni/include/act2brick.h @@ -0,0 +1,43 @@ +#ifndef ACT2BRICK_H +#define ACT2BRICK_H + +#include "legopathactor.h" + +// VTABLE: LEGO1 0x100d9b60 +// SIZE 0x194 +class Act2Brick : public LegoPathActor { +public: + Act2Brick(); + ~Act2Brick() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1007a360 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0438 + return "Act2Brick"; + } + + // FUNCTION: LEGO1 0x1007a370 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Act2Brick::ClassName()) || LegoEntity::IsA(p_name); + } + + MxResult VTable0x94(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 + + // SYNTHETIC: LEGO1 0x1007a450 + // Act2Brick::`scalar deleting destructor' + +private: + undefined4 m_unk0x154; // 0x154 + undefined m_unk0x158[0x0c]; // 0x158 + undefined4 m_unk0x164; // 0x164 + Mx3DPointFloat m_unk0x168; // 0x168 + Mx3DPointFloat m_unk0x17c; // 0x17c + undefined4 m_unk0x190; // 0x190 +}; + +#endif // ACT2BRICK_H diff --git a/LEGO1/lego/legoomni/include/act2policestation.h b/LEGO1/lego/legoomni/include/act2policestation.h new file mode 100644 index 00000000..02d95e5b --- /dev/null +++ b/LEGO1/lego/legoomni/include/act2policestation.h @@ -0,0 +1,29 @@ +#ifndef ACT2POLICESTATION_H +#define ACT2POLICESTATION_H + +#include "legoentity.h" + +// VTABLE: LEGO1 0x100d53a8 +// SIZE 0x68 +class Act2PoliceStation : public LegoEntity { +public: + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x1000e200 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03fc + return "Act2PoliceStation"; + } + + // FUNCTION: LEGO1 0x1000e210 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Act2PoliceStation::ClassName()) || LegoEntity::IsA(p_name); + } + + // SYNTHETIC: LEGO1 0x1000f610 + // Act2PoliceStation::`scalar deleting destructor' +}; + +#endif // ACT2POLICESTATION_H diff --git a/LEGO1/lego/legoomni/include/act3.h b/LEGO1/lego/legoomni/include/act3.h new file mode 100644 index 00000000..2883ff9d --- /dev/null +++ b/LEGO1/lego/legoomni/include/act3.h @@ -0,0 +1,56 @@ +#ifndef ACT3_H +#define ACT3_H + +#include "legoworld.h" + +// VTABLE: LEGO1 0x100d9628 +// SIZE 0x4274 +class Act3 : public LegoWorld { +public: + Act3(); + + ~Act3() override; // vtable+00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x10072510 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f013c + return "Act3"; + } + + // FUNCTION: LEGO1 0x10072520 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Act3::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void Destroy(MxBool p_fromDestructor) override; // vtable+0x1c + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x5c() override; // vtable+0x5c + void VTable0x60() override; // vtable+0x60 + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + inline void SetUnknown420c(MxEntity* p_entity) { m_unk0x420c = p_entity; } + inline void SetUnknown4270(MxU32 p_unk0x4270) { m_unk0x4270 = p_unk0x4270; } + + // SYNTHETIC: LEGO1 0x10072630 + // Act3::`scalar deleting destructor' + + MxBool FUN_100727e0(LegoPathController*, Mx3DPointFloat& p_loc, Mx3DPointFloat& p_dir, Mx3DPointFloat& p_up); + MxBool FUN_10072980(LegoPathController*, Mx3DPointFloat& p_loc, Mx3DPointFloat& p_dir, Mx3DPointFloat& p_up); + void FUN_10073400(); + void FUN_10073430(); + +protected: + undefined m_unk0xf8[0x4114]; // 0xf8 + MxEntity* m_unk0x420c; // 0x420c + undefined m_unk0x4210[0x60]; // 0x4210 + MxU32 m_unk0x4270; // 0x4270 +}; + +#endif // ACT3_H diff --git a/LEGO1/lego/legoomni/include/act3actor.h b/LEGO1/lego/legoomni/include/act3actor.h new file mode 100644 index 00000000..3e6b3150 --- /dev/null +++ b/LEGO1/lego/legoomni/include/act3actor.h @@ -0,0 +1,30 @@ +#ifndef ACT3ACTOR_H +#define ACT3ACTOR_H + +#include "legoanimactor.h" + +// VTABLE: LEGO1 0x100d7668 LegoPathActor +// VTABLE: LEGO1 0x100d7738 LegoAnimActor +// SIZE 0x178 +class Act3Actor : public LegoAnimActor { +public: + Act3Actor(); + + // FUNCTION: LEGO1 0x100431b0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03ac + return "Act3Actor"; + } + + MxU32 VTable0x90(float, Matrix4&) override; // vtable+0x90 + MxResult VTable0x94(LegoPathActor*, MxBool) override; // vtable+0x94 + + // SYNTHETIC: LEGO1 0x10043330 + // Act3Actor::`scalar deleting destructor' + +private: + undefined4 m_unk0x1c; // 0x1c +}; + +#endif // ACT3ACTOR_H diff --git a/LEGO1/lego/legoomni/include/act3shark.h b/LEGO1/lego/legoomni/include/act3shark.h new file mode 100644 index 00000000..3e9fbf32 --- /dev/null +++ b/LEGO1/lego/legoomni/include/act3shark.h @@ -0,0 +1,42 @@ +#ifndef ACT3SHARK_H +#define ACT3SHARK_H + +#include "legoanimactor.h" + +// VTABLE: LEGO1 0x100d7920 LegoPathActor +// VTABLE: LEGO1 0x100d79f0 LegoAnimActor +// SIZE 0x1a8 +class Act3Shark : public LegoAnimActor { +public: + Act3Shark(); + + // FUNCTION: LEGO1 0x100430d0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03a0 + return "Act3Shark"; + } + + void ParseAction(char*) override; // vtable+0x20 + void VTable0x70(float p_float) override; // vtable+0x70 + + // LegoAnimActor vtable + virtual MxResult FUN_10042ce0(void*); // vtable+0x10 + + // SYNTHETIC: LEGO1 0x10043030 + // Act3Shark::`scalar deleting destructor' + +private: + list m_unk0x1c; // 0x1c + undefined4 m_unk0x28; // 0x28 + undefined4 m_unk0x2c; // 0x2c + undefined m_unk0x30[0x0c]; // 0x30 + Mx3DPointFloat m_unk0x3c; // 0x3c +}; + +// STUB: LEGO1 0x10042c90 +// List::~List +// TODO: Update once type is known. +// STUB to resolve diff in scalar dtor and not create a new one. + +#endif // ACT3SHARK_H diff --git a/LEGO1/lego/legoomni/include/act3state.h b/LEGO1/lego/legoomni/include/act3state.h new file mode 100644 index 00000000..3df4e4f3 --- /dev/null +++ b/LEGO1/lego/legoomni/include/act3state.h @@ -0,0 +1,36 @@ +#ifndef ACT3STATE_H +#define ACT3STATE_H + +#include "legostate.h" + +// VTABLE: LEGO1 0x100d4fc8 +// SIZE 0x0c +class Act3State : public LegoState { +public: + inline Act3State() { m_unk0x08 = 0; } + + // FUNCTION: LEGO1 0x1000e300 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03f0 + return "Act3State"; + } + + // FUNCTION: LEGO1 0x1000e310 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Act3State::ClassName()) || LegoState::IsA(p_name); + } + + MxBool IsSerializable() override; + + // SYNTHETIC: LEGO1 0x1000e3c0 + // Act3State::`scalar deleting destructor' + + inline undefined4 GetUnknown0x08() { return m_unk0x08; } + +private: + undefined4 m_unk0x08; // 0x08 +}; + +#endif // ACT3STATE_H diff --git a/LEGO1/lego/legoomni/include/actions/act2main_actions.h b/LEGO1/lego/legoomni/include/actions/act2main_actions.h new file mode 100644 index 00000000..c0163504 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/act2main_actions.h @@ -0,0 +1,842 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef ACT2MAIN_ACTIONS_H +#define ACT2MAIN_ACTIONS_H + +namespace Act2mainScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneAct2main = -1, + + c__Act2Main = 0, + + c_Brickster_Actor = 8, + c_Brickster_Model = 9, + + c_Ambul_Actor = 18, + c_Ambul_Model = 19, + c_Ambul_Anim0 = 20, + + c_Ambul_Anim2 = 26, + c_Ambul_Anim3 = 27, + c_BrShoot = 28, + c_Act2Path = 29, + + c_xarrow_PlayWav = 45, + c_LoadCrashSound = 46, + c_LoadHitSound = 47, + c_LoadBrickPickSound = 48, + c_LoadBrickMusic = 49, + + c_SetAnimationFile = 88, + c_InfCtr = 89, + c_InfCtrModel = 90, + c_polices_entity = 91, + c_polices = 92, + c_tBrick1_entity = 93, + c_tBrick1 = 94, + c_tBrick2_entity = 95, + c_tBrick2 = 96, + c_tBrick3_entity = 97, + c_tBrick3 = 98, + c_tBrick4_entity = 99, + c_tBrick4 = 100, + c_hBrick1_entity = 101, + c_hBrick1 = 102, + c_hBrick2_entity = 103, + c_hBrick2 = 104, + c_hBrick3_entity = 105, + c_hBrick3 = 106, + c_hBrick4_entity = 107, + c_hBrick4 = 108, + c_Block01_entity = 109, + c_Block01 = 110, + c_Block02_entity = 111, + c_Block02 = 112, + c_CNs001xx = 113, + c_CNs002xx = 114, + c_CNs003xx = 115, + c_CNs004xx = 116, + c_CNs005xx = 117, + c_CNs007xx = 118, + c_CNs006xx = 119, + c_CNs008xx = 120, + c_CNs009xx = 121, + c_CNs010xx = 122, + c_CNs011xx = 123, + c_CNs012xx = 124, + c_CNs001Pe = 125, + c_CNs002Pe = 126, + c_CNs003Pe = 127, + c_CNs004Pe = 128, + c_CNs005Pe = 129, + c_CNs007Pe = 130, + c_CNs006Pe = 131, + c_CNs008Pe = 132, + c_CNs009Pe = 133, + c_CNs010Pe = 134, + c_CNs001Ma = 135, + c_CNs002Ma = 136, + c_CNs003Ma = 137, + c_CNs004Ma = 138, + c_CNs005Ma = 139, + c_CNs007Ma = 140, + c_CNs006Ma = 141, + c_CNs008Ma = 142, + c_CNs009Ma = 143, + c_CNs010Ma = 144, + c_CNs011Ma = 145, + c_CNs012Ma = 146, + c_CNs013Ma = 147, + c_CNs0x4Ma = 148, + c_CNs001Pa = 149, + c_CNs002Pa = 150, + c_CNs003Pa = 151, + c_CNs004Pa = 152, + c_CNs005Pa = 153, + c_CNs007Pa = 154, + c_CNs006Pa = 155, + c_CNs008Pa = 156, + c_CNs009Pa = 157, + c_CNs010Pa = 158, + c_CNs011Pa = 159, + c_CNs012Pa = 160, + c_CNs013Pa = 161, + c_CNs0x4Pa = 162, + c_CNs001Ni = 163, + c_CNs002Ni = 164, + c_CNs003Ni = 165, + c_CNs004Ni = 166, + c_CNs005Ni = 167, + c_CNs007Ni = 168, + c_CNs006Ni = 169, + c_CNs008Ni = 170, + c_CNs009Ni = 171, + c_CNs010Ni = 172, + c_CNs011Ni = 173, + c_CNsx11Ni = 174, + c_CNs001La = 175, + c_CNs002La = 176, + c_CNs003La = 177, + c_CNs004La = 178, + c_CNs005La = 179, + c_CNs007La = 180, + c_CNs006La = 181, + c_CNs008La = 182, + c_CNs009La = 183, + c_CNs010La = 184, + c_CNs011La = 185, + c_CNsx11La = 186, + c_CNs001Br = 187, + c_CNs002Br = 188, + c_CNs003Br = 189, + c_CNs004Br = 190, + c_CNs005Br = 191, + c_CNs007Br = 192, + c_CNs006Br = 193, + c_CNs008Br = 194, + c_CNs009Br = 195, + c_CNs010Br = 196, + c_CNs011Br = 197, + c_CNs012Br = 198, + c_CNs013Br = 199, + + c_CNs014Br = 201, + c_CNs900Br = 202, + c_CNs901BR = 203, + c_CNs001Bd = 204, + c_CNs001Pg = 205, + c_CNs001Rd = 206, + c_CNs001Sy = 207, + c_CNs001Sk = 208, + c_BNsAss01 = 209, + c_BadEnd_Movie = 210, + c_BNsAss02 = 211, + c_BNsAss03 = 212, + c_BNsDis01 = 213, + c_BNsDis02 = 214, + c_BNsDis03 = 215, + c_crash5_PlayWav = 216, + c_s12_crash_PlayWav = 217, + c_NNs001Br_Wav = 218, + c_NNs001Br_Anim = 219, + c_BadEnd_Wave = 220, + c_BadEnd_Smk = 221, + c_snsx50bu_Wav_500 = 222, + c_snsx50bu_Pho_500 = 223, + c_snsx50bu_0_sfx = 224, + c_snsx50bu_1_sfx = 225, + c_snsx50bu_2_sfx = 226, + c_snsx50bu_Anim = 227, + c_snsx51bu_Wav_501 = 228, + c_snsx51bu_Pho_501 = 229, + c_snsx51bu_0_sfx = 230, + c_snsx51bu_1_sfx = 231, + c_snsx51bu_2_sfx = 232, + c_snsx51bu_Anim = 233, + c_SNSX29NU_Wav_502 = 234, + c_SNSX29NU_Pho_502 = 235, + c_snsx29nu_0_sfx = 236, + c_snsx29nu_1_sfx = 237, + c_snsx29nu_2_sfx = 238, + c_snsx29nu_3_sfx = 239, + c_BldgCrash = 240, + c_NNs001Br_RunAnim = 241, + c_snsx29nu_Anim = 242, + c_SNSX30NU_Wav_503 = 243, + c_SNSX30NU_Pho_503 = 244, + c_snsx30nu_0_sfx = 245, + c_snsx30nu_1_sfx = 246, + c_snsx30nu_2_sfx = 247, + c_snsx30nu_Anim = 248, + c_SNSX33NA_Wav_504 = 249, + c_SNSX33NA_Pho_504 = 250, + c_snsx33na_0_sfx = 251, + c_snsx33na_1_sfx = 252, + c_snsx33na_2_sfx = 253, + c_snsx33na_3_sfx = 254, + c_VOhead0_PlayWav = 255, + c_VOhead1_PlayWav = 256, + c_snsx33na_4_sfx = 257, + c_snsx33na_Anim = 258, + c_SNSX34NA_Wav_505 = 259, + c_VOinterrupt0_PlayWav = 260, + c_VOinterrupt1_PlayWav = 261, + c_VOinterrupt2_PlayWav = 262, + c_VOinterrupt3_PlayWav = 263, + c_SNSX34NA_Pho_505 = 264, + c_snsx34na_0_sfx = 265, + c_snsx34na_1_sfx = 266, + c_snsx34na_2_sfx = 267, + c_snsx34na_3_sfx = 268, + c_snsx34na_4_sfx = 269, + c_VObehind0_PlayWav = 270, + c_VObehind1_PlayWav = 271, + c_VObehind2_PlayWav = 272, + c_VObehind3_PlayWav = 273, + c_snsx34na_Anim = 274, + c_tns001br_0_sfx = 275, + c_tns001br_1_sfx = 276, + c_tns001br_Anim = 277, + c_tns005br_Wav_507 = 278, + c_tns005br_Pho_507 = 279, + c_VOhide_PlayWav = 280, + c_tns002br_Wav_507 = 281, + c_tns002br_Pho_507 = 282, + c_tns002br_0_sfx = 283, + c_tns002br_1_sfx = 284, + c_tns002br_2_sfx = 285, + c_tns002br_3_sfx = 286, + c_tns002br_4_sfx = 287, + c_tns002br_5_sfx = 288, + c_tns002br_6_sfx = 289, + c_tns002br_Anim = 290, + c_tns006br_Wav_508 = 291, + c_tns006br_Pho_508 = 292, + c_tns003br_Wav_508 = 293, + c_tns003br_Pho_508 = 294, + c_tns003br_0_sfx = 295, + c_tns003br_1_sfx = 296, + c_tns003br_2_sfx = 297, + c_tns003br_3_sfx = 298, + c_tns003br_4_sfx = 299, + + c_tns003br_Anim = 304, + c_tns007br_Wav_509 = 305, + c_tns007br_Pho_509 = 306, + c_tns004br_Wav_509 = 307, + c_tns004br_Pho_509 = 308, + c_tns004br_0_sfx = 309, + c_tns004br_1_sfx = 310, + c_tns004br_2_sfx = 311, + c_tns004br_3_sfx = 312, + c_tns004br_4_sfx = 313, + c_tns004br_5_sfx = 314, + c_tns004br_6_sfx = 315, + c_tns004br_7_sfx = 316, + c_tns004br_Anim = 317, + c_TJA028PA_Wav_510 = 318, + c_TJA028PA_Pho_510 = 319, + c_TJA027LA_Wav_510 = 320, + c_TJA027LA_Pho_510 = 321, + c_TJA026NI_Wav_510 = 322, + c_TJA026NI_Pho_510 = 323, + c_TJA025MA_Wav_510 = 324, + c_TJA025MA_Pho_510 = 325, + c_TJA024LA_Wav_510 = 326, + c_TJA024LA_Pho_510 = 327, + c_TJA023IN_Wav_510 = 328, + c_TJA023IN_Pho_510 = 329, + c_TJA022LA_Wav_510 = 330, + c_TJA022LA_Pho_510 = 331, + c_TJA021NI_Wav_510 = 332, + c_TJA021NI_Pho_510 = 333, + c_TJA019IN_Wav_510 = 334, + c_TJA019IN_Pho_510 = 335, + c_TJA018NI_Wav_510 = 336, + c_TJA018NI_Pho_510 = 337, + c_TJA017IN_Wav_510 = 338, + c_TJA017IN_Pho_510 = 339, + c_TJA016MA_Wav_510 = 340, + c_TJA016MA_Pho_510 = 341, + c_tja015pa_Wav_510 = 342, + c_tja015pa_Pho_510 = 343, + c_tja013in_Wav_510 = 344, + c_tja013in_Pho_510 = 345, + c_tja012ni_Wav_510 = 346, + c_tja012ni_Pho_510 = 347, + c_tja011ni_Wav_510 = 348, + c_tja011ni_Pho_510 = 349, + c_tja010la_Wav_510 = 350, + c_tja010la_Pho_510 = 351, + c_tja009ni_Wav_510 = 352, + c_tja009ni_Pho_510 = 353, + c_tja009ni_0_sfx = 354, + c_tja009ni_1_sfx = 355, + c_tja009ni_2_sfx = 356, + c_tja009ni_3_sfx = 357, + c_tja009ni_4_sfx = 358, + c_tja009ni_5_sfx = 359, + c_tja009ni_6_sfx = 360, + c_tja009ni_7_sfx = 361, + c_tja009ni_8_sfx = 362, + c_tja009ni_9_sfx = 363, + c_tja009ni_Anim = 364, + c_TNS005BR_Wav_511 = 365, + c_TNS005BR_Pho_511 = 366, + c_tns005br_0_sfx = 367, + c_tns005br_1_sfx = 368, + c_tns005br_2_sfx = 369, + c_tns005br_Anim = 370, + c_tns006br_Wav_512 = 371, + c_tns006br_Pho_512 = 372, + c_tns006br_0_sfx = 373, + c_tns006br_1_sfx = 374, + c_tns006br_2_sfx = 375, + c_tns006br_Anim = 376, + c_tns007br_Wav_513 = 377, + c_tns007br_Pho_513 = 378, + c_tns007br_0_sfx = 379, + c_tns007br_1_sfx = 380, + c_tns007br_2_sfx = 381, + c_tns007br_Anim = 382, + c_snsx58va_Wav_514 = 383, + c_snsx58va_Pho_514 = 384, + c_snsx58va_0_sfx = 385, + c_snsx58va_Anim = 386, + c_snsx59va_Wav_515 = 387, + c_snsx59va_Pho_515 = 388, + c_snsx59va_0_sfx = 389, + c_snsx59va_1_sfx = 390, + c_snsx59va_Anim = 391, + c_snsx60va_Wav_516 = 392, + c_snsx60va_Pho_516 = 393, + c_snsx60va_0_sfx = 394, + c_snsx60va_1_sfx = 395, + c_snsx60va_2_sfx = 396, + c_snsx60va_Anim = 397, + c_SNSX31SH_Wav_517 = 398, + c_snsx31sh_0_sfx = 399, + + c_snsx31sh_Anim = 401, + c_SNSX52SN_Wav_518 = 402, + c_SNSX52SN_Pho_518 = 403, + c_snsx52sn_0_sfx = 404, + c_snsx52sn_1_sfx = 405, + c_snsx52sn_2_sfx = 406, + c_snsx52sn_Anim = 407, + c_SNSX53SN_Wav_519 = 408, + c_SNSX53SN_Pho_519 = 409, + c_snsx53sn_0_sfx = 410, + c_snsx53sn_1_sfx = 411, + c_snsx53sn_2_sfx = 412, + c_snsx53sn_Anim = 413, + c_SNSX54SN_Wav_520 = 414, + c_SNSX54SN_Pho_520 = 415, + c_snsx54sn_0_sfx = 416, + c_snsx54sn_1_sfx = 417, + c_snsx54sn_2_sfx = 418, + c_snsx54sn_Anim = 419, + c_SNSX45EN_Wav_521 = 420, + c_SNSX45EN_Pho_521 = 421, + c_SNSX43EN_Wav_521 = 422, + c_SNSX43EN_Pho_521 = 423, + c_SNSX41EN_Wav_521 = 424, + c_SNSX41EN_Pho_521 = 425, + c_SNSX39EN_Wav_521 = 426, + c_SNSX39EN_Pho_521 = 427, + c_SNSX45RE_Wav_521 = 428, + c_SNSX45RE_Pho_521 = 429, + c_SNSX44RE_Wav_521 = 430, + c_SNSX44RE_Pho_521 = 431, + c_SNSX42RE_Wav_521 = 432, + c_SNSX42RE_Pho_521 = 433, + c_SNSX40RE_Wav_521 = 434, + c_SNSX40RE_Pho_521 = 435, + c_SNSX38RE_Wav_521 = 436, + c_SNSX38RE_Pho_521 = 437, + c_snsx38re_0_sfx = 438, + c_snsx38re_1_sfx = 439, + c_snsx38re_2_sfx = 440, + c_snsx38re_3_sfx = 441, + c_snsx38re_4_sfx = 442, + c_snsx38re_Anim = 443, + c_snsx13la_Wav_522 = 444, + c_snsx13la_Pho_522 = 445, + c_snsx13la_0_sfx = 446, + c_snsx13la_1_sfx = 447, + c_snsx13la_Anim = 448, + c_snsx09ni_Wav_523 = 449, + c_snsx09ni_Pho_523 = 450, + c_snsx09ni_0_sfx = 451, + c_snsx09ni_1_sfx = 452, + c_snsx09ni_2_sfx = 453, + c_snsx09ni_3_sfx = 454, + c_snsx09ni_4_sfx = 455, + c_snsx09ni_Anim = 456, + c_snsx01ma_Wav_524 = 457, + c_snsx01ma_Pho_524 = 458, + c_snsx01ma_0_sfx = 459, + c_snsx01ma_1_sfx = 460, + c_snsx01ma_2_sfx = 461, + c_snsx01ma_Anim = 462, + c_snsx03ma_Wav_525 = 463, + c_snsx03ma_Pho_525 = 464, + c_snsx03ma_Anim = 465, + c_snsx05pa_Wav_526 = 466, + c_snsx05pa_Pho_526 = 467, + c_snsx05pa_0_sfx = 468, + c_snsx05pa_1_sfx = 469, + c_snsx05pa_Anim = 470, + c_SNSX23BR_Wav_527 = 471, + c_SNSX23BR_Pho_527 = 472, + c_TRA043NI_Wav_527 = 473, + c_TRA043NI_Pho_527 = 474, + c_TRA042LA_Wav_527 = 475, + c_TRA042LA_Pho_527 = 476, + c_TRA040NI_Wav_527 = 477, + c_TRA040NI_Pho_527 = 478, + c_TRA039LA_Wav_527 = 479, + c_TRA039LA_Pho_527 = 480, + c_TRA037NI_Wav_527 = 481, + c_TRA037NI_Pho_527 = 482, + c_TRA036RO_Wav_527 = 483, + c_TRA035BR_Wav_527 = 484, + c_TRA035BR_Pho_527 = 485, + c_TRA033LA_Wav_527 = 486, + c_TRA033LA_Pho_527 = 487, + c_TRA031NI_Wav_527 = 488, + c_TRA031NI_Pho_527 = 489, + c_tra031ni_0_sfx = 490, + c_tra031ni_1_sfx = 491, + c_tra031ni_2_sfx = 492, + c_tra031ni_3_sfx = 493, + c_tra031ni_4_sfx = 494, + c_tra031ni_5_sfx = 495, + c_tra031ni_Anim = 496, + c_SNSX23BR_Wav_528 = 497, + c_SNSX23BR_Pho_528 = 498, + c_TRA043NI_Wav_528 = 499, + c_snsx50bu_RunAnim = 500, + c_snsx51bu_RunAnim = 501, + c_snsx29nu_RunAnim = 502, + c_snsx30nu_RunAnim = 503, + c_snsx33na_RunAnim = 504, + c_snsx34na_RunAnim = 505, + c_tns001br_RunAnim = 506, + c_tns002br_RunAnim = 507, + c_tns003br_RunAnim = 508, + c_tns004br_RunAnim = 509, + c_tja009ni_RunAnim = 510, + c_tns005br_RunAnim = 511, + c_tns006br_RunAnim = 512, + c_tns007br_RunAnim = 513, + c_snsx58va_RunAnim = 514, + c_snsx59va_RunAnim = 515, + c_snsx60va_RunAnim = 516, + c_snsx31sh_RunAnim = 517, + c_snsx52sn_RunAnim = 518, + c_snsx53sn_RunAnim = 519, + c_snsx54sn_RunAnim = 520, + c_snsx38re_RunAnim = 521, + c_snsx13la_RunAnim = 522, + c_snsx09ni_RunAnim = 523, + c_snsx01ma_RunAnim = 524, + c_snsx03ma_RunAnim = 525, + c_snsx05pa_RunAnim = 526, + c_tra031ni_RunAnim = 527, + c_tra032ni_RunAnim = 528, + c_snsx55sl_RunAnim = 529, + c_snsx56sl_RunAnim = 530, + c_snsx57sl_RunAnim = 531, + c_nnsxx1br_RunAnim = 532, + c_snsx02ma_RunAnim = 533, + c_snsx04ma_RunAnim = 534, + c_snsx06pa_RunAnim = 535, + c_snsx07pa_RunAnim = 536, + c_snsx08pa_RunAnim = 537, + c_snsx10ni_RunAnim = 538, + c_snsx11ni_RunAnim = 539, + c_snsx12ni_RunAnim = 540, + c_snsx14la_RunAnim = 541, + c_snsx15la_RunAnim = 542, + c_snsx16la_RunAnim = 543, + c_snsx17br_RunAnim = 544, + c_snsx18br_RunAnim = 545, + c_snsx19br_RunAnim = 546, + c_snsx20br_RunAnim = 547, + c_snsx21br_RunAnim = 548, + c_snsx22br_RunAnim = 549, + c_snsx23br_RunAnim = 550, + c_snsx24br_RunAnim = 551, + c_snsx25br_RunAnim = 552, + c_snsx26br_RunAnim = 553, + c_snsx27br_RunAnim = 554, + c_snsx28br_RunAnim = 555, + c_snsx32na_RunAnim = 556, + c_snsx35ro_RunAnim = 557, + c_snsx36ro_RunAnim = 558, + c_snsx37ro_RunAnim = 559, + c_snsx46cl_RunAnim = 560, + c_snsx47cl_RunAnim = 561, + c_snsx48cl_RunAnim = 562, + c_snsx49ml_RunAnim = 563, + c_snsx61mg_RunAnim = 564, + c_snsx62mg_RunAnim = 565, + c_snsx63mg_RunAnim = 566, + c_snsx64rd_RunAnim = 567, + c_snsx65pg_RunAnim = 568, + c_snsx66bd_RunAnim = 569, + c_snsx67sy_RunAnim = 570, + c_snsx68pg_RunAnim = 571, + c_snsx69rd_RunAnim = 572, + c_snsx70pg_RunAnim = 573, + c_snsx72sy_RunAnim = 574, + c_snsx73rd_RunAnim = 575, + c_tns048ma_RunAnim = 576, + c_tns051in_RunAnim = 577, + c_tra045la_RunAnim = 578, + c_tns030bd_RunAnim = 579, + c_tns030pg_RunAnim = 580, + c_tns030rd_RunAnim = 581, + c_tns030sy_RunAnim = 582, + c_tra036ro_PlayWav = 583, + c_Avo906In_PlayWav = 584, + c_Avo907In_PlayWav = 585, + c_Avo908In_PlayWav = 586, + c_Avo900Ps_PlayWav = 587, + c_Avo901Ps_PlayWav = 588, + c_Avo902Ps_PlayWav = 589, + c_Avo903Ps_PlayWav = 590, + c_Avo904Ps_PlayWav = 591, + c_TRA043NI_Pho_528 = 592, + c_TRA042LA_Wav_528 = 593, + c_TRA042LA_Pho_528 = 594, + c_TRA040NI_Wav_528 = 595, + c_TRA040NI_Pho_528 = 596, + c_TRA039LA_Wav_528 = 597, + c_TRA039LA_Pho_528 = 598, + c_TRA037NI_Wav_528 = 599, + c_TRA037NI_Pho_528 = 600, + c_TRA036RO_Wav_528 = 601, + c_TRA035BR_Wav_528 = 602, + c_TRA035BR_Pho_528 = 603, + c_TRA033LA_Wav_528 = 604, + c_TRA033LA_Pho_528 = 605, + c_TRA032NI_Wav_528 = 606, + c_TRA032NI_Pho_528 = 607, + c_tra032ni_0_sfx = 608, + c_tra032ni_1_sfx = 609, + c_tra032ni_2_sfx = 610, + c_tra032ni_3_sfx = 611, + c_tra032ni_4_sfx = 612, + c_tra032ni_5_sfx = 613, + c_tra032ni_Anim = 614, + c_snsx55sl_Wav_529 = 615, + c_snsx55sl_Pho_529 = 616, + c_snsx55sl_0_sfx = 617, + c_snsx55sl_1_sfx = 618, + c_snsx55sl_2_sfx = 619, + c_snsx55sl_3_sfx = 620, + c_snsx55sl_Anim = 621, + c_snsx56sl_Wav_530 = 622, + c_snsx56sl_Pho_530 = 623, + c_snsx56sl_Anim = 624, + c_snsx57sl_Wav_531 = 625, + c_snsx57sl_Pho_531 = 626, + c_snsx57sl_0_sfx = 627, + c_snsx57sl_Anim = 628, + c_nnsxx1br_Anim = 629, + c_snsx02ma_Wav_533 = 630, + c_snsx02ma_Pho_533 = 631, + c_snsx02ma_0_sfx = 632, + c_snsx02ma_1_sfx = 633, + c_snsx02ma_2_sfx = 634, + c_snsx02ma_3_sfx = 635, + c_snsx02ma_4_sfx = 636, + c_snsx02ma_5_sfx = 637, + c_snsx02ma_Anim = 638, + c_snsx04ma_Wav_534 = 639, + c_snsx04ma_Pho_534 = 640, + c_snsx04ma_0_sfx = 641, + c_snsx04ma_1_sfx = 642, + c_snsx04ma_2_sfx = 643, + c_snsx04ma_3_sfx = 644, + c_snsx04ma_4_sfx = 645, + c_snsx04ma_Anim = 646, + c_snsx06pa_Wav_535 = 647, + c_snsx06pa_Pho_535 = 648, + c_snsx06pa_0_sfx = 649, + c_snsx06pa_1_sfx = 650, + c_snsx06pa_Anim = 651, + c_snsx07pa_Wav_536 = 652, + c_snsx07pa_Pho_536 = 653, + c_snsx07pa_0_sfx = 654, + c_snsx07pa_1_sfx = 655, + c_snsx07pa_Anim = 656, + c_snsx08pa_Wav_537 = 657, + c_snsx08pa_Pho_537 = 658, + c_snsx08pa_0_sfx = 659, + c_snsx08pa_1_sfx = 660, + c_snsx08pa_Anim = 661, + c_snsx10ni_Wav_538 = 662, + c_snsx10ni_Pho_538 = 663, + c_snsx10ni_0_sfx = 664, + c_snsx10ni_1_sfx = 665, + c_snsx10ni_2_sfx = 666, + c_snsx10ni_Anim = 667, + c_snsx11ni_Wav_539 = 668, + c_snsx11ni_Pho_539 = 669, + c_snsx11ni_0_sfx = 670, + c_snsx11ni_1_sfx = 671, + c_snsx11ni_2_sfx = 672, + c_snsx11ni_3_sfx = 673, + c_snsx11ni_Anim = 674, + c_snsx12ni_Wav_540 = 675, + c_snsx12ni_Pho_540 = 676, + c_snsx12ni_Anim = 677, + c_snsx14la_Wav_541 = 678, + c_snsx14la_Pho_541 = 679, + c_snsx14la_0_sfx = 680, + c_snsx14la_1_sfx = 681, + c_snsx14la_2_sfx = 682, + c_snsx14la_Anim = 683, + c_snsx15la_Wav_542 = 684, + c_snsx15la_Pho_542 = 685, + c_snsx15la_0_sfx = 686, + c_snsx15la_1_sfx = 687, + c_snsx15la_Anim = 688, + c_snsx16la_Wav_543 = 689, + c_snsx16la_Pho_543 = 690, + c_snsx16la_Anim = 691, + c_snsx17br_Wav_544 = 692, + c_snsx17br_Pho_544 = 693, + c_snsx17br_0_sfx = 694, + c_snsx17br_1_sfx = 695, + c_snsx17br_2_sfx = 696, + c_snsx17br_Anim = 697, + c_snsx18br_Wav_545 = 698, + c_snsx18br_Pho_545 = 699, + c_snsx18br_0_sfx = 700, + c_snsx18br_1_sfx = 701, + c_snsx18br_Anim = 702, + c_snsx19br_Wav_546 = 703, + c_snsx19br_Pho_546 = 704, + c_snsx19br_0_sfx = 705, + c_snsx19br_1_sfx = 706, + c_snsx19br_2_sfx = 707, + c_snsx19br_Anim = 708, + c_snsx20br_Wav_547 = 709, + c_snsx20br_Pho_547 = 710, + c_snsx20br_0_sfx = 711, + c_snsx20br_1_sfx = 712, + c_snsx20br_2_sfx = 713, + c_snsx20br_3_sfx = 714, + c_snsx20br_Anim = 715, + c_SNSX21BR_Wav_548 = 716, + c_SNSX21BR_Pho_548 = 717, + c_snsx21br_0_sfx = 718, + c_snsx21br_1_sfx = 719, + c_snsx21br_2_sfx = 720, + c_snsx21br_3_sfx = 721, + c_snsx21br_Anim = 722, + c_snsx22br_Wav_549 = 723, + c_snsx22br_Pho_549 = 724, + c_snsx22br_0_sfx = 725, + c_snsx22br_1_sfx = 726, + c_snsx22br_2_sfx = 727, + c_snsx22br_Anim = 728, + c_snsx23br_Wav_550 = 729, + c_snsx23br_Pho_550 = 730, + c_snsx23br_0_sfx = 731, + c_snsx23br_1_sfx = 732, + c_snsx23br_2_sfx = 733, + c_snsx23br_3_sfx = 734, + c_snsx23br_4_sfx = 735, + c_snsx23br_Anim = 736, + c_snsx24br_Wav_551 = 737, + c_snsx24br_Pho_551 = 738, + c_snsx24br_0_sfx = 739, + c_snsx24br_Anim = 740, + c_snsx25br_Wav_552 = 741, + c_snsx25br_Pho_552 = 742, + c_snsx25br_0_sfx = 743, + c_snsx25br_1_sfx = 744, + c_snsx25br_Anim = 745, + c_snsx26br_Wav_553 = 746, + c_snsx26br_Pho_553 = 747, + c_snsx26br_0_sfx = 748, + c_snsx26br_1_sfx = 749, + c_snsx26br_Anim = 750, + c_snsx27br_Wav_554 = 751, + c_snsx27br_Pho_554 = 752, + c_snsx27br_0_sfx = 753, + c_snsx27br_1_sfx = 754, + c_snsx27br_Anim = 755, + c_snsx28br_Wav_555 = 756, + c_snsx28br_Pho_555 = 757, + c_snsx28br_0_sfx = 758, + c_snsx28br_Anim = 759, + c_SNSX32NA_Wav_556 = 760, + c_SNSX32NA_Pho_556 = 761, + c_snsx32na_0_sfx = 762, + c_snsx32na_1_sfx = 763, + c_snsx32na_2_sfx = 764, + c_snsx32na_3_sfx = 765, + c_snsx32na_Anim = 766, + c_SNSX35RO_Wav_557 = 767, + c_SNSX35RO_Pho_557 = 768, + c_snsx35ro_Anim = 769, + c_SNSX36RO_Wav_558 = 770, + c_SNSX36RO_Pho_558 = 771, + c_snsx36ro_0_sfx = 772, + c_snsx36ro_1_sfx = 773, + c_snsx36ro_Anim = 774, + c_SNSX37RO_Wav_559 = 775, + c_SNSX37RO_Pho_559 = 776, + c_snsx37ro_0_sfx = 777, + c_snsx37ro_1_sfx = 778, + c_snsx37ro_Anim = 779, + c_snsx46cl_Wav_560 = 780, + c_snsx46cl_Pho_560 = 781, + c_snsx46cl_Anim = 782, + c_snsx47cl_Wav_561 = 783, + c_snsx47cl_Pho_561 = 784, + c_snsx47cl_0_sfx = 785, + c_snsx47cl_Anim = 786, + c_snsx48cl_Wav_562 = 787, + c_snsx48cl_Pho_562 = 788, + c_snsx48cl_0_sfx = 789, + c_snsx48cl_1_sfx = 790, + c_snsx48cl_2_sfx = 791, + c_snsx48cl_Anim = 792, + c_snsx49ml_Wav_563 = 793, + c_snsx49ml_Pho_563 = 794, + c_snsx49ml_0_sfx = 795, + c_snsx49ml_1_sfx = 796, + c_snsx49ml_Anim = 797, + c_SNSX61MG_Wav_564 = 798, + c_SNSX61MG_Pho_564 = 799, + c_snsx61mg_0_sfx = 800, + c_snsx61mg_1_sfx = 801, + c_snsx61mg_2_sfx = 802, + c_snsx61mg_3_sfx = 803, + c_snsx61mg_Anim = 804, + c_SNSX62MG_Wav_565 = 805, + c_SNSX62MG_Pho_565 = 806, + c_snsx62mg_0_sfx = 807, + c_snsx62mg_1_sfx = 808, + c_snsx62mg_2_sfx = 809, + c_snsx62mg_Anim = 810, + c_SNSX63MG_Wav_566 = 811, + c_SNSX63MG_Pho_566 = 812, + c_snsx63mg_0_sfx = 813, + c_snsx63mg_1_sfx = 814, + c_snsx63mg_2_sfx = 815, + c_snsx63mg_3_sfx = 816, + c_snsx63mg_Anim = 817, + c_SNSX64RD_Wav_567 = 818, + c_SNSX64RD_Pho_567 = 819, + c_snsx64rd_0_sfx = 820, + c_snsx64rd_1_sfx = 821, + c_snsx64rd_Anim = 822, + c_SNSX65PG_Wav_568 = 823, + c_SNSX65PG_Pho_568 = 824, + c_snsx65pg_0_sfx = 825, + c_snsx65pg_1_sfx = 826, + c_snsx65pg_Anim = 827, + c_snsx66bd_Wav_569 = 828, + c_snsx66bd_Pho_569 = 829, + c_snsx66bd_0_sfx = 830, + c_snsx66bd_1_sfx = 831, + c_snsx66bd_Anim = 832, + c_SNSX67SY_Wav_570 = 833, + c_SNSX67SY_Pho_570 = 834, + c_snsx67sy_0_sfx = 835, + c_snsx67sy_1_sfx = 836, + c_snsx67sy_Anim = 837, + c_snsx68pg_Wav_571 = 838, + c_snsx68pg_Pho_571 = 839, + c_snsx68pg_0_sfx = 840, + c_snsx68pg_1_sfx = 841, + c_snsx68pg_Anim = 842, + c_snsx69rd_Wav_572 = 843, + c_snsx69rd_Pho_572 = 844, + c_snsx69rd_0_sfx = 845, + c_snsx69rd_Anim = 846, + c_snsx70pg_Wav_573 = 847, + c_snsx70pg_Pho_573 = 848, + c_snsx70pg_0_sfx = 849, + c_snsx70pg_1_sfx = 850, + c_snsx70pg_Anim = 851, + c_snsx72sy_Wav_574 = 852, + c_snsx72sy_Pho_574 = 853, + c_snsx72sy_0_sfx = 854, + c_snsx72sy_Anim = 855, + c_snsx73rd_Wav_575 = 856, + c_snsx73rd_Pho_575 = 857, + c_snsx73rd_0_sfx = 858, + c_snsx73rd_1_sfx = 859, + c_snsx73rd_Anim = 860, + c_TNS049PA_Wav_576 = 861, + c_TNS049PA_Pho_576 = 862, + c_TNS048MA_Wav_576 = 863, + c_TNS048MA_Pho_576 = 864, + c_tns048ma_0_sfx = 865, + c_tns048ma_1_sfx = 866, + c_tns048ma_2_sfx = 867, + c_tns048ma_Anim = 868, + c_TNS051IN_Wav_577 = 869, + c_TNS051IN_Pho_577 = 870, + c_tns051in_0_sfx = 871, + c_tns051in_1_sfx = 872, + c_tns051in_2_sfx = 873, + c_tns051in_Anim = 874, + c_TRA046NI_Wav_578 = 875, + c_TRA046NI_Pho_578 = 876, + c_TRA045LA_Wav_578 = 877, + c_TRA045LA_Pho_578 = 878, + c_tra045la_0_sfx = 879, + c_tra045la_1_sfx = 880, + c_tra045la_2_sfx = 881, + c_tra045la_Anim = 882, + c_tns030bd_Wav_579 = 883, + c_tns030bd_Pho_579 = 884, + c_tns030bd_Anim = 885, + c_tns030pg_Wav_580 = 886, + c_tns030pg_Pho_580 = 887, + c_tns030pg_Anim = 888, + c_tns030rd_Wav_581 = 889, + c_tns030rd_Pho_581 = 890, + c_tns030rd_Anim = 891, + c_tns030sy_Wav_582 = 892, + c_tns030sy_Pho_582 = 893, + c_tns030sy_Anim = 894 +}; +} // namespace Act2mainScript + +#endif // ACT2MAIN_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/act3_actions.h b/LEGO1/lego/legoomni/include/actions/act3_actions.h new file mode 100644 index 00000000..c68229ee --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/act3_actions.h @@ -0,0 +1,241 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef ACT3_ACTIONS_H +#define ACT3_ACTIONS_H + +namespace Act3Script +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneAct3 = -1, + + c__Act3 = 0, + + c_shootpz_PlayWav = 8, + c_shootdn_PlayWav = 9, + + c_eatdn_PlayWav = 18, + c_eatpz_PlayWav = 19, + c_pzhitdn_PlayWav = 20, + c_HelicopterDashboard = 21, + c_HelicopterDashboard_Bitmap = 22, + + c_Helicopter_Pizza_Ctl = 26, + c_Helicopter_Donut_Ctl = 27, + c_Helicopter_Info_Ctl = 28, + + c_HelicopterTakeOff_Anim = 32, + c_HelicopterLand_Anim = 33, + + c_dnhitpz_PlayWav = 45, + c_stickpz_PlayWav = 46, + c_stickdn_PlayWav = 47, + c_xarrow_PlayWav = 48, + c_thpt_PlayWav = 49, + + c_Act3Path = 88, + c_InfCtr = 89, + c_InfCtrModel = 90, + c_Helicopter_Actor = 91, + c_Chptr_Model = 92, + c_Brickstr_Walk = 93, + c_Brickstr_Shoot = 94, + c_Shark_Eat = 95, + c_Shark_Actor = 96, + c_Shark_Model = 97, + c_BrickstrCar_Actor = 98, + c_BrickstrCar_Model = 99, + c_Brickstr_Actor = 100, + c_Brickstr_Model = 101, + c_Laura_Walk = 102, + c_Laura_Eat = 103, + c_LauraCar_Actor = 104, + c_LauraCar_Model = 105, + c_Laura_Actor = 106, + c_Laura_Model = 107, + c_Nick_Walk = 108, + c_Nick_Eat = 109, + c_NickCar_Actor = 110, + c_NickCar_Model = 111, + c_Nick_Actor = 112, + c_Nick_Model = 113, + c_Cm_Walk = 114, + c_Cm_Actor = 115, + c_Cm_Model = 116, + c_Bd_Walk = 117, + c_Bd_Actor = 118, + c_Bd_Model = 119, + c_Helicopter_Pizza_Up_Bitmap = 120, + c_Helicopter_Pizza_Down_Bitmap = 121, + c_Helicopter_Donut_Up_Bitmap = 122, + c_Helicopter_Donut_Down_Bitmap = 123, + c_Helicopter_Info_Up_Bitmap = 124, + c_Helicopter_Info_Down_Bitmap = 125, + c_HelicopterDotOn1_Bitmap = 126, + c_HelicopterDotOn2_Bitmap = 127, + c_HelicopterDotOn3_Bitmap = 128, + c_HelicopterDotOn4_Bitmap = 129, + c_HelicopterDotOn5_Bitmap = 130, + c_HelicopterDotOn6_Bitmap = 131, + c_HelicopterDotOn7_Bitmap = 132, + c_HelicopterDotOn8_Bitmap = 133, + c_HelicopterDotOn9_Bitmap = 134, + c_HelicopterDotOn10_Bitmap = 135, + c_HelicopterDotOn11_Bitmap = 136, + c_HelicopterDotOn12_Bitmap = 137, + c_HelicopterDotOn13_Bitmap = 138, + c_HelicopterDotOn14_Bitmap = 139, + c_HelicopterDotOn15_Bitmap = 140, + c_TLP067PA_Wav_500 = 141, + c_TLP067PA_Pho_500 = 142, + c_TLP066MA_Wav_500 = 143, + c_TLP066MA_Pho_500 = 144, + c_TLP065NI_Wav_500 = 145, + c_TLP065NI_Pho_500 = 146, + c_TLP053IN_Wav_500 = 147, + c_TLP053IN_Pho_500 = 148, + c_TLP064LA_Wav_500 = 149, + c_TLP064LA_Pho_500 = 150, + c_TLP063MA_Wav_500 = 151, + c_TLP063MA_Pho_500 = 152, + c_TLP061NI_Wav_500 = 153, + c_TLP061NI_Pho_500 = 154, + c_TLP060IN_Wav_500 = 155, + c_TLP060IN_Pho_500 = 156, + c_TLP058MA_Wav_500 = 157, + c_TLP058MA_Pho_500 = 158, + c_TLP057IN_Wav_500 = 159, + c_TLP057IN_Pho_500 = 160, + c_TLP055PA_Wav_500 = 161, + c_TLP055PA_Pho_500 = 162, + c_tlp053in_0_sfx = 163, + c_tlp053in_1_sfx = 164, + c_tlp053in_2_sfx = 165, + c_tlp053in_3_sfx = 166, + c_tlp053in_4_sfx = 167, + c_tlp053in_5_sfx = 168, + c_tlp053in_Anim = 169, + c_TLP065NI_Wav_501 = 170, + c_TLP065NI_Pho_501 = 171, + c_TLP064LA_Wav_501 = 172, + c_TLP064LA_Pho_501 = 173, + c_tlp064la_0_sfx = 174, + c_tlp064la_Anim = 175, + c_TLP068IN_Wav_502 = 176, + c_TLP068IN_Pho_502 = 177, + c_tlp068in_0_sfx = 178, + c_tlp068in_1_sfx = 179, + c_tlp068in_2_sfx = 180, + c_tlp068in_3_sfx = 181, + c_tlp068in_4_sfx = 182, + c_tlp068in_5_sfx = 183, + c_tlp068in_Anim = 184, + + c_tlp053in_RunAnim = 500, + c_tlp064la_RunAnim = 501, + c_tlp068in_RunAnim = 502, + c_sns76xra_PlayWav = 503, + c_sns77xra_PlayWav = 504, + c_sns02xni_PlayWav = 505, + c_sns03xni_PlayWav = 506, + c_sns04xni_PlayWav = 507, + c_sns05xni_PlayWav = 508, + c_sns06xni_PlayWav = 509, + c_sns07xni_PlayWav = 510, + c_sns08xni_PlayWav = 511, + c_sns09xni_PlayWav = 512, + c_sns10xni_PlayWav = 513, + c_sns11xni_PlayWav = 514, + c_sns12xla_PlayWav = 515, + c_sns13xla_PlayWav = 516, + c_sns14xla_PlayWav = 517, + c_sns15xla_PlayWav = 518, + c_sns16xla_PlayWav = 519, + c_sns17xla_PlayWav = 520, + c_sns18xni_PlayWav = 521, + c_sns19xni_PlayWav = 522, + c_sns20xni_PlayWav = 523, + c_sns21xni_PlayWav = 524, + c_sns22xni_PlayWav = 525, + c_sns23xni_PlayWav = 526, + c_sns24xni_PlayWav = 527, + c_sns25xni_PlayWav = 528, + c_sns26xni_PlayWav = 529, + c_sns27xni_PlayWav = 530, + c_sns28xni_PlayWav = 531, + c_sns29xni_PlayWav = 532, + c_sns30xni_PlayWav = 533, + c_sns31xni_PlayWav = 534, + c_sns32xni_PlayWav = 535, + c_sns33xni_PlayWav = 536, + c_sns34xla_PlayWav = 537, + c_sns35xla_PlayWav = 538, + c_sns36xla_PlayWav = 539, + c_sns37xla_PlayWav = 540, + c_sns38xla_PlayWav = 541, + c_sns39xla_PlayWav = 542, + c_sns40xla_PlayWav = 543, + c_sns41xla_PlayWav = 544, + c_sns42xla_PlayWav = 545, + c_sns43xma_PlayWav = 546, + c_sns44xma_PlayWav = 547, + c_sns45xma_PlayWav = 548, + c_sns46xin_PlayWav = 549, + c_sns47xin_PlayWav = 550, + c_sns48xin_PlayWav = 551, + c_sns49xin_PlayWav = 552, + c_sns50xin_PlayWav = 553, + c_sns51xin_PlayWav = 554, + c_sns52xro_PlayWav = 555, + c_sns53xro_PlayWav = 556, + c_sns54xro_PlayWav = 557, + c_sns55xnu_PlayWav = 558, + c_sns56xnu_PlayWav = 559, + c_sns57xnu_PlayWav = 560, + c_sns58xna_PlayWav = 561, + c_sns59xna_PlayWav = 562, + c_sns60xna_PlayWav = 563, + c_sns61xva_PlayWav = 564, + c_sns62xmg_PlayWav = 565, + c_sns63xcl_PlayWav = 566, + c_sns64xen_PlayWav = 567, + c_sns65xre_PlayWav = 568, + c_sns66xsl_PlayWav = 569, + c_sns67xml_PlayWav = 570, + c_sns68xbu_PlayWav = 571, + c_sns69xsn_PlayWav = 572, + c_sns70xni_PlayWav = 573, + c_sns71xni_PlayWav = 574, + c_sns72xni_PlayWav = 575, + c_sns73xla_PlayWav = 576, + c_sns74xla_PlayWav = 577, + c_sns75xla_PlayWav = 578, + c_sns76xja_PlayWav = 579, + c_sns76xjs_PlayWav = 580, + c_sns77xja_PlayWav = 581, + c_sns77xjs_PlayWav = 582, + c_tns069ni_PlayWav = 583, + c_tns070br_PlayWav = 584, + c_tns071ni_PlayWav = 585, + c_tns072br_PlayWav = 586, + c_tns073ni_PlayWav = 587, + c_tns074ni_PlayWav = 588, + c_tns075br_PlayWav = 589, + c_tns076la_PlayWav = 590, + c_tns077br_PlayWav = 591, + + c_tns079la_PlayWav = 593, + c_tns081ni_PlayWav = 594, + c_tns082br_PlayWav = 595, + c_tns080br_PlayWav = 596, + c_tnsx07br_PlayWav = 597, + c_tnsx02br_PlayWav = 598, + c_snsxx2br_PlayWav = 599, + c_snsy23br_PlayWav = 600 +}; +} // namespace Act3Script + +#endif // ACT3_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/actionsfwd.h b/LEGO1/lego/legoomni/include/actions/actionsfwd.h new file mode 100644 index 00000000..27bfa613 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/actionsfwd.h @@ -0,0 +1,246 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef ACTIONSFWD_H +#define ACTIONSFWD_H + +namespace SndanimScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace SndanimScript + +namespace NocdScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace NocdScript + +namespace CreditsScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace CreditsScript + +namespace IntroScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace IntroScript + +namespace HospitalScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace HospitalScript + +namespace CarraceScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace CarraceScript + +namespace JetraceScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace JetraceScript + +namespace CarracerScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace CarracerScript + +namespace JetracerScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace JetracerScript + +namespace InfoscorScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace InfoscorScript + +namespace RegbookScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace RegbookScript + +namespace HistbookScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace HistbookScript + +namespace InfomainScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace InfomainScript + +namespace ElevbottScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace ElevbottScript + +namespace InfodoorScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace InfodoorScript + +namespace RacecarScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace RacecarScript + +namespace DunecarScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace DunecarScript + +namespace CopterScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace CopterScript + +namespace JetskiScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace JetskiScript + +namespace GarageScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace GarageScript + +namespace Act3Script +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace Act3Script + +namespace Act2mainScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace Act2mainScript + +namespace JukeboxwScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace JukeboxwScript + +namespace IsleScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif + +#if __cplusplus >= 201103L +enum Script2 : int; +#else +enum Script2; +#endif +} // namespace IsleScript + +namespace JukeboxScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace JukeboxScript + +namespace PoliceScript +{ +#if __cplusplus >= 201103L +enum Script : int; +#else +enum Script; +#endif +} // namespace PoliceScript + +#endif // ACTIONSFWD_H diff --git a/LEGO1/lego/legoomni/include/actions/carrace_actions.h b/LEGO1/lego/legoomni/include/actions/carrace_actions.h new file mode 100644 index 00000000..8f742ecf --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/carrace_actions.h @@ -0,0 +1,410 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef CARRACE_ACTIONS_H +#define CARRACE_ACTIONS_H + +namespace CarraceScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneCarrace = -1, + + c__CarRace_World = 0, + c_SpeedMeter = 1, + c_FuelMeter = 2, + c_Info_Ctl = 3, + c_DistanceMeter = 4, + c_Horn_Ctl = 5, + c_Horn_Up_Bitmap = 6, + c_Horn_Down = 7, + c_Horn_Sound = 8, + c_Horn_Down_Bitmap = 9, + c_UserCar_Actor = 10, + c_Studs_Actor = 11, + c_Rhoda_Actor = 12, + c_irtx08ra_PlayWav = 13, + c_Map_Ctl = 14, + c_Map_Up_Bitmap = 15, + c_Map_Down_Bitmap = 16, + c_Info_Up_Bitmap = 17, + c_Info_Down_Bitmap = 18, + c_CarLocator2 = 19, + c_CarLocator3 = 20, + c_StartTriggers = 21, + c_RacePath = 22, + c_HitWallSound = 23, + c_SetHitWallSound = 24, + c_HitActorSound = 25, + c_SetHitActorSound = 26, + c_VO1 = 27, + c_VO2 = 28, + c_VO3 = 29, + c_VO4 = 30, + c_VO5 = 31, + c_VO6 = 32, + c_VO7 = 33, + c_VO8 = 34, + c_VO9 = 35, + c_VO10 = 36, + c_VO11 = 37, + c_VO12 = 38, + c_VO13 = 39, + c_VO14 = 40, + c_RaceCarDashboard11_Bitmap = 41, + c_RaceCarDashboard12_Bitmap = 42, + c_RaceCarDashboard13_Bitmap = 43, + c_RaceCarDashboard14_Bitmap = 44, + c_RaceCarDashboard15_Bitmap = 45, + c_RaceCarDashboard16_Bitmap = 46, + c_VO15 = 47, + c_VO16 = 48, + c_VO17 = 49, + c_VO18 = 50, + c_RaceCarDashboard21_Bitmap = 51, + c_RaceCarDashboard22_Bitmap = 52, + c_RaceCarDashboard23_Bitmap = 53, + c_RaceCarDashboard24_Bitmap = 54, + c_RaceCarDashboard25_Bitmap = 55, + c_RaceCarDashboard26_Bitmap = 56, + c_VO19 = 57, + c_VO20 = 58, + c_VO21 = 59, + c_SkelKick_Sound = 60, + c_RaceCarDashboard31_Bitmap = 61, + c_RaceCarDashboard32_Bitmap = 62, + c_RaceCarDashboard33_Bitmap = 63, + c_RaceCarDashboard34_Bitmap = 64, + c_RaceCarDashboard35_Bitmap = 65, + c_RaceCarDashboard36_Bitmap = 66, + c_Rhoda_Sound = 67, + c_Rhoda_Locator = 68, + c_RcRhod00_Anim = 69, + c_RcRhod01_Anim = 70, + c_RaceCarDashboard41_Bitmap = 71, + c_RaceCarDashboard42_Bitmap = 72, + c_RaceCarDashboard43_Bitmap = 73, + c_RaceCarDashboard44_Bitmap = 74, + c_RaceCarDashboard45_Bitmap = 75, + c_RaceCarDashboard46_Bitmap = 76, + c_RcRhod02_Anim = 77, + c_RhodaCar_Actor = 78, + c_RhodaCar_Model = 79, + c_Rhoda_Model = 80, + c_RaceCarDashboard51_Bitmap = 81, + c_RaceCarDashboard52_Bitmap = 82, + c_RaceCarDashboard53_Bitmap = 83, + c_RaceCarDashboard54_Bitmap = 84, + c_RaceCarDashboard55_Bitmap = 85, + c_RaceCarDashboard56_Bitmap = 86, + c_Studs_Sound = 87, + c_Studs_Locator = 88, + c_RcStud00_Anim = 89, + c_RcStud01_Anim = 90, + c_RaceCarDashboard61_Bitmap = 91, + c_RaceCarDashboard62_Bitmap = 92, + c_RaceCarDashboard63_Bitmap = 93, + c_RaceCarDashboard64_Bitmap = 94, + c_RaceCarDashboard65_Bitmap = 95, + c_RaceCarDashboard66_Bitmap = 96, + c_RaceCarDashboard = 97, + c_RaceCarArms_Ctl = 98, + c_RcStud02_Anim = 99, + c_StudsCar_Actor = 100, + c_StudsCar_Model = 101, + c_Studs_Model = 102, + c_SkelKick1_Anim = 103, + c_SkelKick2_Anim = 104, + c_User_Locator = 105, + c_UserCar_Model = 106, + c_ScaryRun_Sound = 107, + c_ScaryRun_Anim = 108, + c_Skeleton_Actor = 109, + c_Skeleton_Model = 110, + c_Ghost_Sound = 111, + c_Ghost_Anim = 112, + c_Ghost_Actor = 113, + c_Ghost_Model = 114, + c_TireGuy_Anim = 115, + c_TireGuy_Actor = 116, + c_TireGuy_Model = 117, + c_Skelton1_Sound = 118, + c_SJump_Anim = 119, + c_Skelton1_Actor = 120, + c_Skelton1_Model = 121, + c_SkelBig_Anim = 122, + c_SkelBig_Actor = 123, + c_SkelBig_Model = 124, + c_DorA_Actor = 125, + c_DorA_Model = 126, + c_DorB_Actor = 127, + c_DorB_Model = 128, + c_DorC_Actor = 129, + c_DorC_Model = 130, + c_DorD_Actor = 131, + c_DorD_Model = 132, + c_DorE_Actor = 133, + c_DorE_Model = 134, + c_DorF_Actor = 135, + c_DorF_Model = 136, + c_DorG_Actor = 137, + c_DorG_Model = 138, + c_DorH_Actor = 139, + c_DorH_Model = 140, + c_DorI_Actor = 141, + c_DorI_Model = 142, + c_DorJ_Actor = 143, + c_DorJ_Model = 144, + c_HideAni_Anim = 145, + c_RaceCarArms_Mask_Bitmap = 146, + c_srt001rh_Wav_500 = 147, + c_srt001rh_Pho_500 = 148, + c_srt001rh_0_sfx = 149, + c_srt001rh_1_sfx = 150, + c_srt001rh_2_sfx = 151, + c_srt001rh_Anim = 152, + c_SRT001SL_Wav_501 = 153, + c_SRT001SL_Pho_501 = 154, + c_srt001sl_0_sfx = 155, + c_srt001sl_1_sfx = 156, + c_srt001sl_2_sfx = 157, + c_srt001sl_3_sfx = 158, + c_srt001sl_4_sfx = 159, + c_srt001sl_Anim = 160, + c_srt002rh_Wav_502 = 161, + c_srt002rh_Pho_502 = 162, + c_srt002rh_0_sfx = 163, + c_srt002rh_1_sfx = 164, + c_srt002rh_2_sfx = 165, + c_srt002rh_Anim = 166, + c_SRT002SL_Wav_503 = 167, + c_SRT002SL_Pho_503 = 168, + c_srt002sl_0_sfx = 169, + c_srt002sl_1_sfx = 170, + c_srt002sl_2_sfx = 171, + c_srt002sl_3_sfx = 172, + c_srt002sl_Anim = 173, + c_srt003rh_Wav_504 = 174, + c_srt003rh_Pho_504 = 175, + c_srt003rh_0_sfx = 176, + c_srt003rh_1_sfx = 177, + c_srt003rh_Anim = 178, + c_SRT003SL_Wav_505 = 179, + c_SRT003SL_Pho_505 = 180, + c_srt003sl_0_sfx = 181, + c_srt003sl_1_sfx = 182, + c_srt003sl_Anim = 183, + c_SRT004SL_Wav_506 = 184, + c_SRT004SL_Pho_506 = 185, + c_srt004sl_0_sfx = 186, + c_srt004sl_1_sfx = 187, + c_srt004sl_2_sfx = 188, + c_srt004sl_Anim = 189, + c_srt005sl_Wav_507 = 190, + c_srt005sl_Pho_507 = 191, + c_srt005sl_0_sfx = 192, + c_srt005sl_1_sfx = 193, + c_srt005sl_2_sfx = 194, + c_srt005sl_3_sfx = 195, + c_srt005sl_Anim = 196, + c_IRTX08RA_Wav_508 = 197, + c_nrtflag0_Anim = 198, + c_SRT007RH_Wav_509 = 199, + c_SRT007RH_Pho_509 = 200, + c_srt007rh_0_sfx = 201, + c_srt007rh_1_sfx = 202, + c_srt007rh_2_sfx = 203, + c_srt007rh_3_sfx = 204, + c_srt007rh_Anim = 205, + c_SRT008RH_Wav_510 = 206, + c_SRT008RH_Pho_510 = 207, + c_srt008rh_0_sfx = 208, + c_srt008rh_1_sfx = 209, + c_srt008rh_2_sfx = 210, + c_srt008rh_3_sfx = 211, + c_srt008rh_Anim = 212, + c_SRT009RH_Wav_511 = 213, + c_SRT009RH_Pho_511 = 214, + c_srt009rh_0_sfx = 215, + c_srt009rh_1_sfx = 216, + c_srt009rh_2_sfx = 217, + c_srt009rh_3_sfx = 218, + c_srt009rh_Anim = 219, + c_SRT010RH_Wav_512 = 220, + c_SRT010RH_Pho_512 = 221, + c_srt010rh_0_sfx = 222, + c_srt010rh_1_sfx = 223, + c_srt010rh_2_sfx = 224, + c_srt010rh_Anim = 225, + c_SRT011RH_Wav_513 = 226, + c_SRT011RH_Pho_513 = 227, + c_srt011rh_0_sfx = 228, + c_srt011rh_1_sfx = 229, + c_srt011rh_2_sfx = 230, + c_srt011rh_3_sfx = 231, + c_srt011rh_Anim = 232, + c_SRT011SL_Wav_514 = 233, + c_SRT011SL_Pho_514 = 234, + c_srt011sl_0_sfx = 235, + c_srt011sl_1_sfx = 236, + c_srt011sl_2_sfx = 237, + c_srt011sl_3_sfx = 238, + c_srt011sl_Anim = 239, + c_SRT012RH_Wav_515 = 240, + c_SRT012RH_Pho_515 = 241, + c_srt012rh_0_sfx = 242, + c_srt012rh_1_sfx = 243, + c_srt012rh_2_sfx = 244, + c_srt012rh_3_sfx = 245, + c_srt012rh_Anim = 246, + c_SRT012SL_Wav_516 = 247, + c_SRT012SL_Pho_516 = 248, + c_srt012sl_0_sfx = 249, + c_srt012sl_1_sfx = 250, + c_srt012sl_2_sfx = 251, + c_srt012sl_3_sfx = 252, + c_srt012sl_Anim = 253, + c_SRT013SL_Wav_517 = 254, + c_SRT013SL_Pho_517 = 255, + c_srt013sl_0_sfx = 256, + c_srt013sl_1_sfx = 257, + c_srt013sl_2_sfx = 258, + c_srt013sl_3_sfx = 259, + c_srt013sl_Anim = 260, + c_SRT014SL_Wav_518 = 261, + c_SRT014SL_Pho_518 = 262, + c_srt014sl_0_sfx = 263, + c_srt014sl_1_sfx = 264, + c_srt014sl_2_sfx = 265, + c_srt014sl_3_sfx = 266, + c_srt014sl_4_sfx = 267, + c_srt014sl_Anim = 268, + c_SRT015SL_Wav_519 = 269, + c_SRT015SL_Pho_519 = 270, + c_srt015sl_0_sfx = 271, + c_srt015sl_1_sfx = 272, + c_srt015sl_2_sfx = 273, + c_srt015sl_3_sfx = 274, + c_srt015sl_Anim = 275, + c_SRT016SL_Wav_520 = 276, + c_SRT016SL_Pho_520 = 277, + c_srt016sl_0_sfx = 278, + c_srt016sl_1_sfx = 279, + c_srt016sl_2_sfx = 280, + c_srt016sl_3_sfx = 281, + c_srt016sl_4_sfx = 282, + c_srt016sl_Anim = 283, + c_SRT017SL_Wav_521 = 284, + c_SRT017SL_Pho_521 = 285, + c_srt017sl_0_sfx = 286, + c_srt017sl_1_sfx = 287, + c_srt017sl_2_sfx = 288, + c_srt017sl_3_sfx = 289, + c_srt017sl_Anim = 290, + c_nrtrhod0_Anim = 291, + c_nrt001pz_Anim = 292, + c_nrt002pz_Anim = 293, + c_nrt003sh_Anim = 294, + c_nrt004sh_Anim = 295, + c_nrt005ft_Anim = 296, + c_nrt008oc_Anim = 297, + c_nrt010pz_Anim = 298, + c_nrt011pz_Anim = 299, + c_nrt012sl_Anim = 300, + c_nrt013sl_Anim = 301, + c_nrt014sl_Anim = 302, + c_nrt015gh_Anim = 303, + c_nrt015sl_Anim = 304, + c_nrt016gh_Anim = 305, + c_nrt017rc_Anim = 306, + c_nrt018rc_Anim = 307, + c_nrt020a1_Anim = 308, + c_nrt022sp_Anim = 309, + c_nrt023sk_Anim = 310, + c_nrt024a2_Anim = 311, + c_nrt025sw_Anim = 312, + c_nrt026sw_Anim = 313, + c_nrt027sw_Anim = 314, + c_nrt028sw_Anim = 315, + c_nrt029sw_Anim = 316, + c_nrt030bk_Anim = 317, + c_nrt031bk_Anim = 318, + c_nrt032bk_Anim = 319, + c_nrt033bk_Anim = 320, + c_nrt034bk_Anim = 321, + c_nrt035bk_Anim = 322, + c_nrtrhod1_Anim = 323, + c_nrtrhod2_Anim = 324, + c_nrtrhod3_Anim = 325, + c_nrtstud0_Anim = 326, + c_nrtstud1_Anim = 327, + c_nrtstud2_Anim = 328, + c_nrtstud3_Anim = 329, + + c_srt001rh_RunAnim = 500, + c_srt001sl_RunAnim = 501, + c_srt002rh_RunAnim = 502, + c_srt002sl_RunAnim = 503, + c_srt003rh_RunAnim = 504, + c_srt003sl_RunAnim = 505, + c_srt004sl_RunAnim = 506, + c_srt005sl_RunAnim = 507, + c_nrtflag0_RunAnim = 508, + c_srt007rh_RunAnim = 509, + c_srt008rh_RunAnim = 510, + c_srt009rh_RunAnim = 511, + c_srt010rh_RunAnim = 512, + c_srt011rh_RunAnim = 513, + c_srt011sl_RunAnim = 514, + c_srt012rh_RunAnim = 515, + c_srt012sl_RunAnim = 516, + c_srt013sl_RunAnim = 517, + c_srt014sl_RunAnim = 518, + c_srt015sl_RunAnim = 519, + c_srt016sl_RunAnim = 520, + c_srt017sl_RunAnim = 521, + c_nrtrhod0_RunAnim = 522, + c_nrt001pz_RunAnim = 523, + c_nrt002pz_RunAnim = 524, + c_nrt003sh_RunAnim = 525, + c_nrt004sh_RunAnim = 526, + c_nrt005ft_RunAnim = 527, + c_nrt008oc_RunAnim = 528, + c_nrt010pz_RunAnim = 529, + c_nrt011pz_RunAnim = 530, + c_nrt012sl_RunAnim = 531, + c_nrt013sl_RunAnim = 532, + c_nrt014sl_RunAnim = 533, + c_nrt015gh_RunAnim = 534, + c_nrt015sl_RunAnim = 535, + c_nrt016gh_RunAnim = 536, + c_nrt017rc_RunAnim = 537, + c_nrt018rc_RunAnim = 538, + c_nrt020a1_RunAnim = 539, + c_nrt022sp_RunAnim = 540, + c_nrt023sk_RunAnim = 541, + c_nrt024a2_RunAnim = 542, + c_nrt025sw_RunAnim = 543, + c_nrt026sw_RunAnim = 544, + c_nrt027sw_RunAnim = 545, + c_nrt028sw_RunAnim = 546, + c_nrt029sw_RunAnim = 547, + c_nrt030bk_RunAnim = 548, + c_nrt031bk_RunAnim = 549, + c_nrt032bk_RunAnim = 550, + c_nrt033bk_RunAnim = 551, + c_nrt034bk_RunAnim = 552, + c_nrt035bk_RunAnim = 553, + c_nrtrhod1_RunAnim = 554, + c_nrtrhod2_RunAnim = 555, + c_nrtrhod3_RunAnim = 556, + c_nrtstud0_RunAnim = 557, + c_nrtstud1_RunAnim = 558, + c_nrtstud2_RunAnim = 559, + c_nrtstud3_RunAnim = 560 +}; +} // namespace CarraceScript + +#endif // CARRACE_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/carracer_actions.h b/LEGO1/lego/legoomni/include/actions/carracer_actions.h new file mode 100644 index 00000000..f7b4c43e --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/carracer_actions.h @@ -0,0 +1,96 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef CARRACER_ACTIONS_H +#define CARRACER_ACTIONS_H + +namespace CarracerScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneCarracer = -1, + + c_nrt002pz_Anim = 0, + c_NRT100DR_Anim = 1, + c_NRT110DR_Anim = 2, + c_NRT101DR_Anim = 3, + c_NRT111DR_Anim = 4, + c_NRT102DR_Anim = 5, + c_NRT112DR_Anim = 6, + c_NRT103DR_Anim = 7, + c_NRT113DR_Anim = 8, + c_NRT104DR_Anim = 9, + c_NRT114DR_Anim = 10, + c_NRT105DR_Anim = 11, + c_NRT115DR_Anim = 12, + c_NRT106DR_Anim = 13, + c_NRT116DR_Anim = 14, + c_NRT107DR_Anim = 15, + c_NRT117DR_Anim = 16, + c_NRT108DR_Anim = 17, + c_NRT118DR_Anim = 18, + c_NRT109DR_Anim = 19, + c_NRT119DR_Anim = 20, + c_nrt015gh_RunAnim = 21, + c_nrt001pz_RunAnim = 22, + c_nrt002pz_RunAnim = 23, + c_nrt030bk_RunAnim = 24, + c_nrt031bk_RunAnim = 25, + c_nrt032bk_RunAnim = 26, + c_nrt025sw_RunAnim = 27, + c_nrt004sh_RunAnim = 28, + c_nrt003sh_RunAnim = 29, + c_nrt022sp_RunAnim = 30, + c_nrt015sl_RunAnim = 31, + c_nrt014sl_RunAnim = 32, + c_nrt013sl_RunAnim = 33, + c_nrt012sl_RunAnim = 34, + c_nrt026sw_RunAnim = 35, + c_nrt027sw_RunAnim = 36, + c_nrt028sw_RunAnim = 37, + c_nrt029sw_RunAnim = 38, + c_nrt033bk_RunAnim = 39, + c_nrt034bk_RunAnim = 40, + c_nrt035bk_RunAnim = 41, + c_nrt016gh_RunAnim = 42, + c_nrt030sw_RunAnim = 43, + c_nrt005ft_RunAnim = 44, + c_nrt010pz_RunAnim = 45, + c_nrt011pz_RunAnim = 46, + c_nrt008oc_RunAnim = 47, + c_nrt003sh_Anim = 48, + c_nrt004sh_Anim = 49, + c_nrt005ft_Anim = 50, + c_nrt008oc_Anim = 51, + c_nrt010pz_Anim = 52, + c_nrt011pz_Anim = 53, + c_nrt012sl_Anim = 54, + c_nrt013sl_Anim = 55, + c_nrt014sl_Anim = 56, + c_nrt015gh_Anim = 57, + c_nrt015sl_Anim = 58, + c_nrt016gh_Anim = 59, + c_nrt026sw_Anim = 60, + c_nrt027sw_Anim = 61, + c_nrt028sw_Anim = 62, + c_nrt029sw_Anim = 63, + c_nrt031bk_Anim = 64, + c_nrt032bk_Anim = 65, + c_nrt035bk_Anim = 66, + c_nrt025sw_Anim = 67, + c_nrt022sp_Anim = 68, + c_nrt030sw_Anim = 69, + + c_TRS100_BlackSky = 100, + + c_TRS200_DkBlueSky = 200, + + c_TRS300_BlackSky = 300, + + c_TRS400_BlueSky = 400 +}; +} // namespace CarracerScript + +#endif // CARRACER_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/copter_actions.h b/LEGO1/lego/legoomni/include/actions/copter_actions.h new file mode 100644 index 00000000..afdbcbbe --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/copter_actions.h @@ -0,0 +1,202 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef COPTER_ACTIONS_H +#define COPTER_ACTIONS_H + +namespace CopterScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneCopter = -1, + + c__StartUp = 0, + c_Helicopter_Actor = 1, + + c_Info_Ctl = 5, + c_Exit_Ctl = 6, + c_ShelfUp_Ctl = 7, + c_Platform_Ctl = 8, + + c_Background = 64, + c_ColorBook_Bitmap = 65, + c_ShelfUp_Up = 66, + c_ShelfUp_Up_Bitmap = 67, + c_ShelfUp_Down = 68, + c_ShelfUp_Down_Bitmap = 69, + c_PlatformUp_Bitmap = 70, + c_PlatformLeft = 71, + c_PlatformLeft_Bitmap = 72, + c_Rotate_Sound = 73, + c_Yellow_Ctl = 74, + c_Yellow_Up_Bitmap = 75, + c_Yellow_Down_Bitmap = 76, + c_Red_Ctl = 77, + c_Red_Up_Bitmap = 78, + c_Red_Down_Bitmap = 79, + c_Blue_Ctl = 80, + c_Blue_Up_Bitmap = 81, + c_Blue_Down_Bitmap = 82, + c_Green_Ctl = 83, + c_Green_Up_Bitmap = 84, + c_Green_Down_Bitmap = 85, + c_Gray_Ctl = 86, + c_Gray_Up_Bitmap = 87, + c_Gray_Down_Bitmap = 88, + c_Black_Ctl = 89, + c_Black_Up_Bitmap = 90, + c_Black_Down_Bitmap = 91, + c_Decals_Ctl = 92, + c_CHWIND_State_0 = 93, + c_CHWIND_State_0_Bitmap = 94, + c_CHWIND_State_1 = 95, + c_CHWIND_State_1_Bitmap = 96, + c_CHWIND_Texture_1 = 97, + c_CHWIND_State_3 = 98, + c_CHWIND_State_3_Bitmap = 99, + c_CHWIND_Texture_3 = 100, + c_CHWIND_State_2 = 101, + c_CHWIND_State_2_Bitmap = 102, + c_CHWIND_Texture_2 = 103, + c_CHWIND_State_4 = 104, + c_CHWIND_State_4_Bitmap = 105, + c_CHWIND_Texture_4 = 106, + c_Decals_Ctl1 = 107, + c_CHJETL_State_0 = 108, + c_CHJETL_State_0_Bitmap = 109, + c_CHJETL_State_1 = 110, + c_CHJETL_State_1_Bitmap = 111, + c_CHJETL_Texture_1 = 112, + c_CHJETL_State_3 = 113, + c_CHJETL_State_3_Bitmap = 114, + c_CHJETL_Texture_3 = 115, + c_CHJETL_State_2 = 116, + c_CHJETL_State_2_Bitmap = 117, + c_CHJETL_Texture_2 = 118, + c_CHJETL_State_4 = 119, + c_CHJETL_State_4_Bitmap = 120, + c_CHJETL_Texture_4 = 121, + c_Decals_Ctl2 = 122, + c_CHJETR_State_0 = 123, + c_CHJETR_State_0_Bitmap = 124, + c_CHJETR_State_1 = 125, + c_CHJETR_State_1_Bitmap = 126, + c_CHJETR_Texture_1 = 127, + c_CHJETR_State_3 = 128, + c_CHJETR_State_3_Bitmap = 129, + c_CHJETR_Texture_3 = 130, + c_CHJETR_State_2 = 131, + c_CHJETR_State_2_Bitmap = 132, + c_CHJETR_Texture_2 = 133, + c_CHJETR_State_4 = 134, + c_CHJETR_State_4_Bitmap = 135, + c_CHJETR_Texture_4 = 136, + c_Info_Up_Bitmap = 137, + c_Info_Down_Bitmap = 138, + c_Exit_Up_Bitmap = 139, + c_Exit_Down_Bitmap = 140, + c_Shelf_Sound = 141, + c_PlaceBrick_Sound = 142, + c_GetBrick_Sound = 143, + c_Paint_Sound = 144, + c_Decal_Sound = 145, + c_Build_Animation = 146, + c_Build_Anim0 = 147, + c_Build_Anim1 = 148, + c_Build_Anim2 = 149, + c_Chptr_Model = 150, + c_IPS001D2_Wav_500 = 151, + c_IPS001D2_Pho_500 = 152, + c_ips001d2_0_sfx = 153, + c_ips001d2_1_sfx = 154, + c_ips001d2_2_sfx = 155, + c_ips001d2_3_sfx = 156, + c_ips001d2_4_sfx = 157, + c_ips001d2_5_sfx = 158, + c_ips001d2_6_sfx = 159, + c_ips001d2_7_sfx = 160, + c_ips001d2_8_sfx = 161, + c_ips001d2_9_sfx = 162, + c_ips001d2_10_sfx = 163, + c_ips001d2_11_sfx = 164, + c_ips001d2_12_sfx = 165, + c_ips001d2_13_sfx = 166, + c_ips001d2_14_sfx = 167, + c_ips001d2_15_sfx = 168, + c_ips001d2_16_sfx = 169, + c_ips001d2_17_sfx = 170, + c_ips001d2_18_sfx = 171, + c_ips001d2_Anim = 172, + c_IPSxx1D2_Wav_501 = 173, + c_IPSxx1D2_Pho_501 = 174, + c_ipsxx1d2_0_sfx = 175, + c_ipsxx1d2_1_sfx = 176, + c_ipsxx1d2_2_sfx = 177, + c_ipsxx1d2_3_sfx = 178, + c_ipsxx1d2_Anim = 179, + c_IPS002D2_Wav_502 = 180, + c_IPS002D2_Pho_502 = 181, + c_ips002d2_0_sfx = 182, + c_ips002d2_1_sfx = 183, + c_ips002d2_2_sfx = 184, + c_ips002d2_3_sfx = 185, + c_ips002d2_Anim = 186, + c_IPS003D2_Wav_503 = 187, + c_IPS003D2_Pho_503 = 188, + c_ips003d2_0_sfx = 189, + c_ips003d2_1_sfx = 190, + c_ips003d2_2_sfx = 191, + c_ips003d2_3_sfx = 192, + c_ips003d2_4_sfx = 193, + c_ips003d2_5_sfx = 194, + c_ips003d2_Anim = 195, + c_IPS004D2_Wav_504 = 196, + c_IPS004D2_Pho_504 = 197, + c_ips004d2_0_sfx = 198, + c_ips004d2_1_sfx = 199, + c_ips004d2_2_sfx = 200, + c_ips004d2_3_sfx = 201, + c_ips004d2_4_sfx = 202, + c_ips004d2_Anim = 203, + c_IPS005D2_Wav_505 = 204, + c_IPS005D2_Pho_505 = 205, + c_ips005d2_0_sfx = 206, + c_ips005d2_1_sfx = 207, + c_ips005d2_2_sfx = 208, + c_ips005d2_3_sfx = 209, + c_ips005d2_4_sfx = 210, + c_ips005d2_5_sfx = 211, + c_ips005d2_6_sfx = 212, + c_ips005d2_7_sfx = 213, + c_ips005d2_Anim = 214, + c_IPS006D2_Wav_506 = 215, + c_IPS006D2_Pho_506 = 216, + c_ips006d2_0_sfx = 217, + c_ips006d2_1_sfx = 218, + c_ips006d2_2_sfx = 219, + c_ips006d2_3_sfx = 220, + c_ips006d2_4_sfx = 221, + c_ips006d2_5_sfx = 222, + c_ips006d2_Anim = 223, + c_SLP01XD2_Wav_507 = 224, + c_SLP01XD2_Pho_507 = 225, + c_slp01xd2_0_sfx = 226, + c_slp01xd2_1_sfx = 227, + c_slp01xd2_2_sfx = 228, + c_slp01xd2_3_sfx = 229, + c_slp01xd2_Anim = 230, + + c_ips001d2_RunAnim = 500, + c_ipsxx1d2_RunAnim = 501, + c_ips002d2_RunAnim = 502, + c_ips003d2_RunAnim = 503, + c_ips004d2_RunAnim = 504, + c_ips005d2_RunAnim = 505, + c_ips006d2_RunAnim = 506, + c_slp01xd2_RunAnim = 507 +}; +} // namespace CopterScript + +#endif // COPTER_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/credits_actions.h b/LEGO1/lego/legoomni/include/actions/credits_actions.h new file mode 100644 index 00000000..b18590eb --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/credits_actions.h @@ -0,0 +1,56 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef CREDITS_ACTIONS_H +#define CREDITS_ACTIONS_H + +namespace CreditsScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneCredits = -1, + + c_Credits_Wav = 0, + c_Credits_Smk = 1, + c_Credit01_Bitmap = 2, + c_Credit02_Bitmap = 3, + c_Credit03_Bitmap = 4, + c_Credit04_Bitmap = 5, + c_Credit05_Bitmap = 6, + c_Credit06_Bitmap = 7, + c_Credit07_Bitmap = 8, + c_Credit08_Bitmap = 9, + c_Credit09_Bitmap = 10, + c_Credit11_Bitmap = 11, + c_Credit12_Bitmap = 12, + c_Credit13_Bitmap = 13, + c_Credit14_Bitmap = 14, + c_Credit15_Bitmap = 15, + c_Credit16_Bitmap = 16, + c_Credit17_Bitmap = 17, + c_Credit21_Bitmap = 18, + c_Credit19_Bitmap = 19, + c_Credit22_Bitmap = 20, + c_Credit22b_Bitmap = 21, + c_Credit25_Bitmap = 22, + c_Credit20_Bitmap = 23, + c_Credit12b_Bitmap = 24, + c_Credit23_Bitmap = 25, + c_Credit24_Bitmap = 26, + c_Credit14b_Bitmap = 27, + c_Credit14c_Bitmap = 28, + c_Credit26_Bitmap = 29, + c_Credit27_Bitmap = 30, + c_Credit28_Bitmap = 31, + c_Credit29_Bitmap = 32, + c_Credit10_Bitmap = 33, + c_Credit17b_Bitmap = 34, + c_Credit17c_Bitmap = 35, + + c_LegoCredits = 499 +}; +} // namespace CreditsScript + +#endif // CREDITS_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/dunecar_actions.h b/LEGO1/lego/legoomni/include/actions/dunecar_actions.h new file mode 100644 index 00000000..2124a302 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/dunecar_actions.h @@ -0,0 +1,151 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef DUNECAR_ACTIONS_H +#define DUNECAR_ACTIONS_H + +namespace DunecarScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneDunecar = -1, + + c__StartUp = 0, + + c_DuneBugy_Actor = 2, + + c_Info_Ctl = 5, + c_Exit_Ctl = 6, + c_ShelfUp_Ctl = 7, + c_Platform_Ctl = 8, + + c_DuneBugy_Model = 64, + c_Background = 65, + c_ColorBook_Bitmap = 66, + c_ShelfUp_Up_Bitmap = 67, + c_ShelfUp_Down_Bitmap = 68, + c_PlatformUp_Bitmap = 69, + c_PlatformLeft = 70, + c_Rotate_Sound = 71, + c_PlatformLeft_Bitmap = 72, + c_Yellow_Ctl = 73, + c_Yellow_Up_Bitmap = 74, + c_Yellow_Down_Bitmap = 75, + c_Red_Ctl = 76, + c_Red_Up_Bitmap = 77, + c_Red_Down_Bitmap = 78, + c_Blue_Ctl = 79, + c_Blue_Up_Bitmap = 80, + c_Blue_Down_Bitmap = 81, + c_Green_Ctl = 82, + c_Green_Up_Bitmap = 83, + c_Green_Down_Bitmap = 84, + c_Gray_Ctl = 85, + c_Gray_Up_Bitmap = 86, + c_Gray_Down_Bitmap = 87, + c_Black_Ctl = 88, + c_Black_Up_Bitmap = 89, + c_Black_Down_Bitmap = 90, + c_Decals_Ctl = 91, + c_Decal_State_0 = 92, + c_Decal_State_0_Bitmap = 93, + c_Decal_State_1 = 94, + c_Decal_State_1_Bitmap = 95, + c_Decal_Texture_1 = 96, + c_Decal_State_2 = 97, + c_Decal_State_2_Bitmap = 98, + c_Decal_Texture_2 = 99, + c_Decal_State_3 = 100, + c_Decal_State_3_Bitmap = 101, + c_Decal_Texture_3 = 102, + c_Decal_State_4 = 103, + c_Decal_State_4_Bitmap = 104, + c_Decal_Texture_4 = 105, + c_Info_Up_Bitmap = 106, + c_Info_Down_Bitmap = 107, + c_Exit_Up_Bitmap = 108, + c_Exit_Down_Bitmap = 109, + c_Shelf_Sound = 110, + c_PlaceBrick_Sound = 111, + c_GetBrick_Sound = 112, + c_Paint_Sound = 113, + c_Decal_Sound = 114, + c_Build_Animation = 115, + c_Build_Anim0 = 116, + c_Build_Anim1 = 117, + c_Build_Anim2 = 118, + c_IGS001D3_Wav_500 = 119, + c_IGS001D3_Pho_500 = 120, + c_igs001d3_0_sfx = 121, + c_igs001d3_1_sfx = 122, + c_igs001d3_2_sfx = 123, + c_igs001d3_3_sfx = 124, + c_igs001d3_4_sfx = 125, + c_igs001d3_5_sfx = 126, + c_igs001d3_6_sfx = 127, + c_igs001d3_7_sfx = 128, + c_igs001d3_8_sfx = 129, + c_igs001d3_9_sfx = 130, + c_igs001d3_10_sfx = 131, + c_igs001d3_11_sfx = 132, + c_igs001d3_12_sfx = 133, + c_igs001d3_13_sfx = 134, + c_igs001d3_14_sfx = 135, + c_igs001d3_15_sfx = 136, + c_igs001d3_16_sfx = 137, + c_igs001d3_17_sfx = 138, + c_igs001d3_18_sfx = 139, + c_igs001d3_19_sfx = 140, + c_igs001d3_Anim = 141, + c_IGSxx1D3_Wav_501 = 142, + c_IGSxx1D3_Pho_501 = 143, + c_igsxx1d3_0_sfx = 144, + c_igsxx1d3_1_sfx = 145, + c_igsxx1d3_2_sfx = 146, + c_igsxx1d3_Anim = 147, + c_IGS002D3_Wav_502 = 148, + c_IGS002D3_Pho_502 = 149, + c_igs002d3_0_sfx = 150, + c_igs002d3_Anim = 151, + c_IGS003D3_Wav_503 = 152, + c_IGS003D3_Pho_503 = 153, + c_igs003d3_0_sfx = 154, + c_igs003d3_1_sfx = 155, + c_igs003d3_2_sfx = 156, + c_igs003d3_3_sfx = 157, + c_igs003d3_4_sfx = 158, + c_igs003d3_5_sfx = 159, + c_igs003d3_6_sfx = 160, + c_igs003d3_7_sfx = 161, + c_igs003d3_8_sfx = 162, + c_igs003d3_Anim = 163, + c_IGS004D3_Wav_504 = 164, + c_IGS004D3_Pho_504 = 165, + c_igs004d3_0_sfx = 166, + c_igs004d3_1_sfx = 167, + c_igs004d3_2_sfx = 168, + c_igs004d3_3_sfx = 169, + c_igs004d3_4_sfx = 170, + c_igs004d3_Anim = 171, + c_IGS005D3_Wav_505 = 172, + c_IGS005D3_Pho_505 = 173, + c_igs005d3_0_sfx = 174, + c_igs005d3_1_sfx = 175, + c_igs005d3_2_sfx = 176, + c_igs005d3_3_sfx = 177, + c_igs005d3_4_sfx = 178, + c_igs005d3_5_sfx = 179, + c_igs005d3_Anim = 180, + + c_igs001d3_RunAnim = 500, + c_igsxx1d3_RunAnim = 501, + c_igs002d3_RunAnim = 502, + c_igs003d3_RunAnim = 503, + c_igs004d3_RunAnim = 504, + c_igs005d3_RunAnim = 505 +}; +} // namespace DunecarScript + +#endif // DUNECAR_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/elevbott_actions.h b/LEGO1/lego/legoomni/include/actions/elevbott_actions.h new file mode 100644 index 00000000..f858c8cb --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/elevbott_actions.h @@ -0,0 +1,31 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef ELEVBOTT_ACTIONS_H +#define ELEVBOTT_ACTIONS_H + +namespace ElevbottScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneElevbott = -1, + + c__StartUp = 0, + c_LeftArrow_Ctl = 1, + c_RightArrow_Ctl = 2, + c_ElevBott_Elevator_Ctl = 3, + c_Background_Bitmap = 4, + c_LeftArrow_Up_Bitmap = 5, + c_LeftArrow_Down_Bitmap = 6, + c_RightArrow_Up_Bitmap = 7, + c_RightArrow_Down_Bitmap = 8, + c_Elevator_Mask_Bitmap = 9, + c_ConfigAnimation = 10, + + c_iica31in_PlayWav = 500 +}; +} // namespace ElevbottScript + +#endif // ELEVBOTT_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/garage_actions.h b/LEGO1/lego/legoomni/include/actions/garage_actions.h new file mode 100644 index 00000000..21529b77 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/garage_actions.h @@ -0,0 +1,150 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef GARAGE_ACTIONS_H +#define GARAGE_ACTIONS_H + +namespace GarageScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneGarage = -1, + + c__StartUp = 0, + c_LeftArrow_Ctl = 1, + c_RightArrow_Ctl = 2, + c_Info_Ctl = 3, + c_Buggy_Ctl = 4, + c_Nubby_Entity = 5, + c_Nubby_Model = 6, + c_Background_Bitmap = 7, + c_TrackLed_Bitmap = 8, + c_LeftArrow_Up_Bitmap = 9, + c_LeftArrow_Down_Bitmap = 10, + c_RightArrow_Up_Bitmap = 11, + c_RightArrow_Down_Bitmap = 12, + c_Info_Up_Bitmap = 13, + c_Info_Down_Bitmap = 14, + c_Buggy_Up_Bitmap = 15, + c_Buggy_Down_Bitmap = 16, + c_RadioOff_Bitmap = 17, + c_Radio_Ctl = 18, + c_RadioOn_Bitmap = 19, + c_ConfigAnimation = 20, + c_wgs002nu_Wav_500 = 21, + c_wgs002nu_Pho_500 = 22, + c_wgs002nu_0_sfx = 23, + c_wgs002nu_1_sfx = 24, + c_wgs002nu_Anim = 25, + c_wgs003nu_Wav_501 = 26, + c_wgs003nu_Pho_501 = 27, + c_wgs003nu_0_sfx = 28, + c_wgs003nu_1_sfx = 29, + c_wgs003nu_2_sfx = 30, + c_wgs003nu_Anim = 31, + c_wgs004nu_Wav_502 = 32, + c_wgs004nu_Pho_502 = 33, + c_wgs004nu_0_sfx = 34, + c_wgs004nu_Anim = 35, + c_wgs006nu_Wav_503 = 36, + c_wgs006nu_Pho_503 = 37, + c_wgs006nu_0_sfx = 38, + c_wgs006nu_Anim = 39, + c_wgs007nu_Wav_504 = 40, + c_wgs007nu_Pho_504 = 41, + c_wgs007nu_Anim = 42, + c_wgs005nu_Wav_505 = 43, + c_wgs005nu_Pho_505 = 44, + c_wgs008nu_Anim = 45, + c_wgs009nu_Wav_506 = 46, + c_wgs009nu_Pho_506 = 47, + c_wgs009nu_0_sfx = 48, + c_wgs009nu_1_sfx = 49, + c_wgs009nu_Anim = 50, + c_wgs010nu_Wav_507 = 51, + c_wgs010nu_Pho_507 = 52, + c_wgs010nu_0_sfx = 53, + c_wgs010nu_Anim = 54, + c_wgs012nu_Wav_508 = 55, + c_wgs012nu_Pho_508 = 56, + c_wgs012nu_Anim = 57, + c_WGS014NU_Wav_509 = 58, + c_WGS014NU_Pho_509 = 59, + c_WGS016P1_Wav_509 = 60, + c_wgs014nu_0_sfx = 61, + c_wgs014nu_Anim = 62, + c_WGS019NU_Wav_510 = 63, + c_WGS019NU_Pho_510 = 64, + c_WGS017NU_Wav_510 = 65, + c_WGS017NU_Pho_510 = 66, + c_wgs017nu_0_sfx = 67, + c_wgs017nu_Anim = 68, + c_WGS020NU_Wav_511 = 69, + c_WGS020NU_Pho_511 = 70, + c_wgs020nu_0_sfx = 71, + c_wgs020nu_Anim = 72, + c_WGS021NU_Wav_512 = 73, + c_WGS021NU_Pho_512 = 74, + c_wgs021nu_0_sfx = 75, + c_wgs021nu_Anim = 76, + c_WGS022NU_Wav_513 = 77, + c_WGS022NU_Pho_513 = 78, + c_wgs022nu_0_sfx = 79, + c_wgs022nu_1_sfx = 80, + c_wgs022nu_2_sfx = 81, + c_wgs022nu_Anim = 82, + c_WGS028NU_Wav_514 = 83, + c_WGS028NU_Pho_514 = 84, + c_WGS027NA_Wav_514 = 85, + c_WGS027NA_Pho_514 = 86, + c_WGS026NA_Wav_514 = 87, + c_WGS026NA_Pho_514 = 88, + c_WGS025NA_Wav_514 = 89, + c_WGS025NA_Pho_514 = 90, + c_WGS024NA_Wav_514 = 91, + c_WGS024NA_Pho_514 = 92, + c_wgs023nu_0_sfx = 93, + c_wgs023nu_1_sfx = 94, + c_wgs023nu_2_sfx = 95, + c_wgs023nu_3_sfx = 96, + c_wgs023nu_4_sfx = 97, + c_wgs023nu_5_sfx = 98, + c_wgs023nu_6_sfx = 99, + c_wgs023nu_7_sfx = 100, + c_wgs023nu_8_sfx = 101, + c_wgs023nu_9_sfx = 102, + c_wgs023nu_Anim = 103, + c_wgs030nu_Wav_515 = 104, + c_wgs030nu_Pho_515 = 105, + c_wgs029nu_Wav_515 = 106, + c_wgs029nu_Pho_515 = 107, + c_wgs029nu_0_sfx = 108, + c_wgs029nu_Anim = 109, + c_wgs031nu_Wav_516 = 110, + c_wgs031nu_Pho_516 = 111, + c_wgs031nu_0_sfx = 112, + c_wgs031nu_Anim = 113, + + c_wgs002nu_RunAnim = 500, + c_wgs003nu_RunAnim = 501, + c_wgs004nu_RunAnim = 502, + c_wgs006nu_RunAnim = 503, + c_wgs007nu_RunAnim = 504, + c_wgs008nu_RunAnim = 505, + c_wgs009nu_RunAnim = 506, + c_wgs010nu_RunAnim = 507, + c_wgs012nu_RunAnim = 508, + c_wgs014nu_RunAnim = 509, + c_wgs017nu_RunAnim = 510, + c_wgs020nu_RunAnim = 511, + c_wgs021nu_RunAnim = 512, + c_wgs022nu_RunAnim = 513, + c_wgs023nu_RunAnim = 514, + c_wgs029nu_RunAnim = 515, + c_wgs031nu_RunAnim = 516 +}; +} // namespace GarageScript + +#endif // GARAGE_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/histbook_actions.h b/LEGO1/lego/legoomni/include/actions/histbook_actions.h new file mode 100644 index 00000000..d1074140 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/histbook_actions.h @@ -0,0 +1,47 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef HISTBOOK_ACTIONS_H +#define HISTBOOK_ACTIONS_H + +namespace HistbookScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneHistbook = -1, + + c__StartUp = 0, + c_ScoreBox = 1, + c_Background_Bitmap = 2, + c_A_Bitmap = 3, + c_B_Bitmap = 4, + c_C_Bitmap = 5, + c_D_Bitmap = 6, + c_E_Bitmap = 7, + c_F_Bitmap = 8, + c_G_Bitmap = 9, + c_H_Bitmap = 10, + c_I_Bitmap = 11, + c_J_Bitmap = 12, + c_K_Bitmap = 13, + c_L_Bitmap = 14, + c_M_Bitmap = 15, + c_N_Bitmap = 16, + c_O_Bitmap = 17, + c_P_Bitmap = 18, + c_Q_Bitmap = 19, + c_R_Bitmap = 20, + c_S_Bitmap = 21, + c_T_Bitmap = 22, + c_U_Bitmap = 23, + c_V_Bitmap = 24, + c_W_Bitmap = 25, + c_X_Bitmap = 26, + c_Y_Bitmap = 27, + c_Z_Bitmap = 28 +}; +} // namespace HistbookScript + +#endif // HISTBOOK_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/hospital_actions.h b/LEGO1/lego/legoomni/include/actions/hospital_actions.h new file mode 100644 index 00000000..06c3db1c --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/hospital_actions.h @@ -0,0 +1,175 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef HOSPITAL_ACTIONS_H +#define HOSPITAL_ACTIONS_H + +namespace HospitalScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneHospital = -1, + + c__StartUp = 0, + c_Doc_Entity = 1, + c_Doc_Model = 2, + c_Info_Ctl = 3, + c_Door_Ctl = 4, + c_Background_Bitmap = 5, + c_PizzaLed_Bitmap = 6, + c_CopLed_Bitmap = 7, + c_Info_Up_Bitmap = 8, + c_Info_Down_Bitmap = 9, + c_Door_Mask_Bitmap = 10, + c_ConfigAnimation = 11, + c_hho002cl_Wav_500 = 12, + c_hho002cl_Pho_500 = 13, + c_hho002cl_0_sfx = 14, + c_hho002cl_1_sfx = 15, + c_hho002cl_Anim = 16, + c_HHO003CL_Wav_501 = 17, + c_HHO003CL_Pho_501 = 18, + c_hho003cl_0_sfx = 19, + c_hho003cl_1_sfx = 20, + c_hho003cl_2_sfx = 21, + c_hho003cl_3_sfx = 22, + c_hho003cl_4_sfx = 23, + c_hho003cl_Anim = 24, + c_hho004jk_Wav_502 = 25, + c_hho004jk_Pho_502 = 26, + c_hho004jk_0_sfx = 27, + c_hho004jk_1_sfx = 28, + c_hho004jk_2_sfx = 29, + c_hho004jk_3_sfx = 30, + c_hho004jk_4_sfx = 31, + c_hho004jk_5_sfx = 32, + c_hho004jk_Anim = 33, + c_hho016cl_Wav_503 = 34, + c_hho016cl_Pho_503 = 35, + c_hho016cl_0_sfx = 36, + c_hho016cl_1_sfx = 37, + c_hho016cl_Anim = 38, + c_hho017cl_Wav_504 = 39, + c_hho017cl_Pho_504 = 40, + c_hho017cl_0_sfx = 41, + c_hho017cl_1_sfx = 42, + c_hho017cl_Anim = 43, + c_hho018cl_Wav_505 = 44, + c_hho018cl_Pho_505 = 45, + c_hho018cl_0_sfx = 46, + c_hho018cl_1_sfx = 47, + c_hho018cl_2_sfx = 48, + c_hho018cl_3_sfx = 49, + c_hho018cl_Anim = 50, + c_hho019cl_Wav_506 = 51, + c_hho019cl_Pho_506 = 52, + c_hho019cl_0_sfx = 53, + c_hho019cl_1_sfx = 54, + c_hho019cl_2_sfx = 55, + c_hho019cl_Anim = 56, + c_hho020cl_Wav_507 = 57, + c_hho020cl_Pho_507 = 58, + c_hho020cl_0_sfx = 59, + c_hho020cl_1_sfx = 60, + c_hho020cl_Anim = 61, + c_hho021cl_Wav_508 = 62, + c_hho021cl_Pho_508 = 63, + c_hho021cl_0_sfx = 64, + c_hho021cl_1_sfx = 65, + c_hho021cl_2_sfx = 66, + c_hho021cl_Anim = 67, + c_hho023cl_Wav_509 = 68, + c_hho023cl_Pho_509 = 69, + c_hho023cl_0_sfx = 70, + c_hho023cl_1_sfx = 71, + c_hho023cl_2_sfx = 72, + c_hho023cl_Anim = 73, + c_hho024cl_Wav_510 = 74, + c_hho024cl_Pho_510 = 75, + c_hho024cl_0_sfx = 76, + c_hho024cl_1_sfx = 77, + c_hho024cl_2_sfx = 78, + c_hho024cl_3_sfx = 79, + c_hho024cl_Anim = 80, + c_hho025cl_Wav_511 = 81, + c_hho025cl_Pho_511 = 82, + c_hho025cl_0_sfx = 83, + c_hho025cl_1_sfx = 84, + c_hho025cl_2_sfx = 85, + c_hho025cl_Anim = 86, + c_hho026cl_Wav_512 = 87, + c_hho026cl_Pho_512 = 88, + c_hho026cl_0_sfx = 89, + c_hho026cl_1_sfx = 90, + c_hho026cl_Anim = 91, + c_hhoa22cl_Wav_513 = 92, + c_hhoa22cl_Pho_513 = 93, + c_hhoa22cl_0_sfx = 94, + c_hhoa22cl_1_sfx = 95, + c_hhoa22cl_2_sfx = 96, + c_hhoa22cl_3_sfx = 97, + c_hhoa22cl_Anim = 98, + c_hho008p1_Wav_514 = 99, + c_hho007p1_Wav_514 = 100, + c_hho007p1_0_sfx = 101, + c_hho007p1_1_sfx = 102, + c_hho007p1_2_sfx = 103, + c_hho007p1_3_sfx = 104, + c_hho007p1_Anim = 105, + c_hho006cl_Wav_515 = 106, + c_hho006cl_Pho_515 = 107, + c_hho015cl_Wav_515 = 108, + c_hho015cl_Pho_515 = 109, + c_hho009en_Wav_515 = 110, + c_hho009en_Pho_515 = 111, + c_hho010re_Wav_515 = 112, + c_hho010re_Pho_515 = 113, + c_hho014en_Wav_515 = 114, + c_hho014en_Pho_515 = 115, + c_hho013re_Wav_515 = 116, + c_hho013re_Pho_515 = 117, + c_hho012en_Wav_515 = 118, + c_hho012en_Pho_515 = 119, + c_hho011en_Wav_515 = 120, + c_hho011en_Pho_515 = 121, + c_hho011re_Wav_515 = 122, + c_hho011re_Pho_515 = 123, + c_hho008cl_Wav_515 = 124, + c_hho008cl_Pho_515 = 125, + c_hho006cl_0_sfx = 126, + c_hho006cl_1_sfx = 127, + c_hho006cl_2_sfx = 128, + c_hho006cl_3_sfx = 129, + c_hho006cl_4_sfx = 130, + c_hho006cl_5_sfx = 131, + c_hho006cl_6_sfx = 132, + c_hho006cl_7_sfx = 133, + c_hho006cl_8_sfx = 134, + c_hho006cl_9_sfx = 135, + c_hho006cl_10_sfx = 136, + c_hho006cl_11_sfx = 137, + c_hho006cl_12_sfx = 138, + c_hho006cl_Anim = 139, + + c_hho002cl_RunAnim = 500, + c_hho003cl_RunAnim = 501, + c_hho004jk_RunAnim = 502, + c_hho016cl_RunAnim = 503, + c_hho017cl_RunAnim = 504, + c_hho018cl_RunAnim = 505, + c_hho019cl_RunAnim = 506, + c_hho020cl_RunAnim = 507, + c_hho021cl_RunAnim = 508, + c_hho023cl_RunAnim = 509, + c_hho024cl_RunAnim = 510, + c_hho025cl_RunAnim = 511, + c_hho026cl_RunAnim = 512, + c_hhoa22cl_RunAnim = 513, + c_hho007p1_RunAnim = 514, + c_hho006cl_RunAnim = 515 +}; +} // namespace HospitalScript + +#endif // HOSPITAL_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/infodoor_actions.h b/LEGO1/lego/legoomni/include/actions/infodoor_actions.h new file mode 100644 index 00000000..f473c8a6 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/infodoor_actions.h @@ -0,0 +1,37 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef INFODOOR_ACTIONS_H +#define INFODOOR_ACTIONS_H + +namespace InfodoorScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneInfodoor = -1, + + c__StartUp = 0, + c_LeftArrow_Ctl = 1, + c_RightArrow_Ctl = 2, + c_Info_Ctl = 3, + c_Door_Ctl = 4, + c_Background_Bitmap = 5, + c_LeftArrow_Up_Bitmap = 6, + c_LeftArrow_Down_Bitmap = 7, + c_RightArrow_Up_Bitmap = 8, + c_RightArrow_Down_Bitmap = 9, + c_Info_Up_Bitmap = 10, + c_Info_Down_Bitmap = 11, + c_Door_Up_Bitmap = 12, + c_ConfigAnimation = 13, + + c_iic037in_PlayWav = 500, + c_iic038in_PlayWav = 501, + c_iicb31in_PlayWav = 502, + c_iic007in_PlayWav = 503 +}; +} // namespace InfodoorScript + +#endif // INFODOOR_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/infomain_actions.h b/LEGO1/lego/legoomni/include/actions/infomain_actions.h new file mode 100644 index 00000000..273526cb --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/infomain_actions.h @@ -0,0 +1,583 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef INFOMAIN_ACTIONS_H +#define INFOMAIN_ACTIONS_H + +namespace InfomainScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneInfomain = -1, + + c__InfoMain = 0, + c_LeftArrow_Ctl = 1, + c_RightArrow_Ctl = 2, + c_Info_Ctl = 3, + c_Door_Ctl = 4, + c_Infoman_Entity = 5, + c_RedBrick_Entity = 6, + c_GreenBrick_Entity = 7, + c_RegBook_Bmp = 8, + c_RegBook_Flc = 9, + c_Boat_Ctl = 10, + c_Race_Ctl = 11, + c_Pizza_Ctl = 12, + c_Gas_Ctl = 13, + c_Med_Ctl = 14, + c_Cop_Ctl = 15, + c_BigInfo_Ctl = 16, + c_Book_Ctl = 17, + c_Radio_Ctl = 18, + c_RegBookRed_Bmp = 19, + c_RegBookRed_Flc = 20, + c_Mama_Ctl = 21, + c_Papa_Ctl = 22, + c_Pepper_Ctl = 23, + c_Nick_Ctl = 24, + c_Laura_Ctl = 25, + c_Info_A_Bitmap = 26, + c_Boat_A_Bitmap = 27, + c_Race_A_Bitmap = 28, + c_Pizza_A_Bitmap = 29, + c_MamaHot_Bitmap = 30, + c_PapaHot_Bitmap = 31, + c_PepperHot_Bitmap = 32, + c_NickHot_Bitmap = 33, + c_LauraHot_Bitmap = 34, + c_Gas_A_Bitmap = 35, + c_Med_A_Bitmap = 36, + c_Cop_A_Bitmap = 37, + c_FrameHot_Bitmap = 38, + c_Background_Bitmap = 39, + c_Mama_All_Movie = 40, + c_Papa_All_Movie = 41, + c_Pepper_All_Movie = 42, + c_Nick_All_Movie = 43, + c_Laura_All_Movie = 44, + c_BackgroundRed_Bitmap = 45, + c_Infoman_Model = 46, + c_Brick2x4grn_Model = 47, + c_Brick2x4red_Model = 48, + c_LeftArrow_Up_Bitmap = 49, + c_LeftArrow_Down_Bitmap = 50, + c_RightArrow_Up_Bitmap = 51, + c_RightArrow_Down_Bitmap = 52, + c_BigInfo_Up_Bitmap = 53, + c_BigInfo_Down = 54, + c_BigInfo_Down_Bitmap = 55, + c_RadioOff_Bitmap = 56, + c_RadioOn_Bitmap = 57, + c_Book_Mask_Bitmap = 58, + c_Door_Mask_Bitmap = 59, + c_Info_Up_Bitmap = 60, + c_Info_Down_Bitmap = 61, + c_Boat_Up_Bitmap = 62, + c_Boat_Down_Bitmap = 63, + c_Race_Up_Bitmap = 64, + c_Race_Down_Bitmap = 65, + c_Pizza_Up_Bitmap = 66, + c_Pizza_Down_Bitmap = 67, + c_Gas_Up_Bitmap = 68, + c_Gas_Down_Bitmap = 69, + c_GoTo_RegBook = 70, + c_GoTo_RegBook_Red = 71, + c_Med_Up_Bitmap = 72, + c_Med_Down_Bitmap = 73, + c_Cop_Up_Bitmap = 74, + c_Cop_Down_Bitmap = 75, + c_Mama_Up_Bitmap = 76, + c_Mama_Down_Bitmap = 77, + c_Papa_Up_Bitmap = 78, + c_Papa_Down_Bitmap = 79, + c_Pepper_Up_Bitmap = 80, + c_Pepper_Down_Bitmap = 81, + c_Nick_Up_Bitmap = 82, + c_Nick_Down_Bitmap = 83, + c_Laura_Up_Bitmap = 84, + c_Laura_Down_Bitmap = 85, + c_ConfigAnimation = 86, + c_Mama_Start_Movie = 87, + c_Mama_ScreenDown_Wave = 88, + c_Mama_ScreenDown_Smk = 89, + c_Mama_Movie = 90, + c_Mama_Wave = 91, + c_Mama_Smk = 92, + c_Mama_End_Movie = 93, + c_Mama_ScreenUp_Wave = 94, + c_Mama_ScreenUp_Smk = 95, + c_Papa_Start_Movie = 96, + c_Papa_ScreenDown_Wave = 97, + c_Papa_ScreenDown_Smk = 98, + c_Papa_Movie = 99, + c_Papa_Wave = 100, + c_Papa_Smk = 101, + c_Papa_End_Movie = 102, + c_Papa_ScreenUp_Wave = 103, + c_Papa_ScreenUp_Smk = 104, + c_Pepper_Start_Movie = 105, + c_Pepper_ScreenDown_Wave = 106, + c_Pepper_ScreenDown_Smk = 107, + c_Pepper_Movie = 108, + c_Pepper_Wave = 109, + c_Pepper_Smk = 110, + c_Pepper_End_Movie = 111, + c_Pepper_ScreenUp_Wave = 112, + c_Pepper_ScreenUp_Smk = 113, + c_Nick_Start_Movie = 114, + c_Nick_ScreenDown_Wave = 115, + c_Nick_ScreenDown_Smk = 116, + c_Nick_Movie = 117, + c_Nick_Wave = 118, + c_Nick_Smk = 119, + c_Nick_End_Movie = 120, + c_Nick_ScreenUp_Wave = 121, + c_Nick_ScreenUp_Smk = 122, + c_Laura_Start_Movie = 123, + c_Laura_ScreenDown_Wave = 124, + c_Laura_ScreenDown_Smk = 125, + c_Laura_Movie = 126, + c_Laura_Wave = 127, + c_Laura_Smk = 128, + c_Laura_End_Movie = 129, + c_Laura_ScreenUp_Wave = 130, + c_Laura_ScreenUp_Smk = 131, + c_IIC005IN_Wav_500 = 132, + c_IIC005IN_Pho_500 = 133, + c_IIC004IN_Wav_500 = 134, + c_IIC004IN_Pho_500 = 135, + c_IIC002IN_Wav_500 = 136, + c_IIC002IN_Pho_500 = 137, + c_iic001in_0_sfx = 138, + c_iic001in_1_sfx = 139, + c_iic001in_2_sfx = 140, + c_iic001in_3_sfx = 141, + c_iic001in_4_sfx = 142, + c_iic001in_5_sfx = 143, + c_iic001in_6_sfx = 144, + c_iic001in_7_sfx = 145, + c_iic001in_8_sfx = 146, + c_iic001in_9_sfx = 147, + c_iic001in_10_sfx = 148, + c_iic001in_11_sfx = 149, + c_iic001in_12_sfx = 150, + c_iic001in_13_sfx = 151, + c_iic001in_14_sfx = 152, + c_iic001in_15_sfx = 153, + c_iic001in_16_sfx = 154, + c_iic001in_17_sfx = 155, + c_iic001in_18_sfx = 156, + c_iic001in_19_sfx = 157, + c_iic001in_20_sfx = 158, + c_iic001in_21_sfx = 159, + c_iic001in_22_sfx = 160, + c_iic001in_Anim = 161, + c_IIC017IN_Wav_501 = 162, + c_IIC017IN_Pho_501 = 163, + c_IIC016IN_Wav_501 = 164, + c_IIC016IN_Pho_501 = 165, + c_iic016in_0_sfx = 166, + c_iic016in_1_sfx = 167, + c_iic016in_2_sfx = 168, + c_iic016in_3_sfx = 169, + c_iic016in_4_sfx = 170, + c_iic016in_5_sfx = 171, + c_iic016in_6_sfx = 172, + c_iic016in_7_sfx = 173, + c_iic016in_8_sfx = 174, + c_iic016in_9_sfx = 175, + c_iic016in_10_sfx = 176, + c_iic016in_11_sfx = 177, + c_iic016in_12_sfx = 178, + c_iic016in_13_sfx = 179, + c_iic016in_Anim = 180, + c_IICX17IN_Wav_502 = 181, + c_IICX17IN_Pho_502 = 182, + c_iicx17in_0_sfx = 183, + c_iicx17in_Anim = 184, + c_iic018in_Wav_503 = 185, + c_iic018in_Pho_503 = 186, + c_iic018in_0_sfx = 187, + c_iic018in_1_sfx = 188, + c_iic018in_2_sfx = 189, + c_iic018in_3_sfx = 190, + c_iic018in_4_sfx = 191, + c_iic018in_5_sfx = 192, + c_iic018in_6_sfx = 193, + c_iic018in_7_sfx = 194, + c_iic018in_8_sfx = 195, + c_iic018in_9_sfx = 196, + c_iic018in_10_sfx = 197, + c_iic018in_11_sfx = 198, + c_iic018in_12_sfx = 199, + c_iic018in_13_sfx = 200, + c_iic018in_14_sfx = 201, + c_iic018in_Anim = 202, + c_IICx18IN_Wav_504 = 203, + c_IICx18IN_Pho_504 = 204, + c_iicx18in_Anim = 205, + c_iic019in_Wav_505 = 206, + c_iic019in_Pho_505 = 207, + c_iic019in_0_sfx = 208, + c_iic019in_1_sfx = 209, + c_iic019in_2_sfx = 210, + c_iic019in_3_sfx = 211, + c_iic019in_4_sfx = 212, + c_iic019in_Anim = 213, + c_iic020in_Wav_506 = 214, + c_iic020in_Pho_506 = 215, + c_iic020in_0_sfx = 216, + c_iic020in_1_sfx = 217, + c_iic020in_2_sfx = 218, + c_iic020in_3_sfx = 219, + c_iic020in_4_sfx = 220, + c_iic020in_5_sfx = 221, + c_iic020in_Anim = 222, + c_iic021in_Wav_507 = 223, + c_iic021in_Pho_507 = 224, + c_iic021in_0_sfx = 225, + c_iic021in_1_sfx = 226, + c_iic021in_2_sfx = 227, + c_iic021in_Anim = 228, + c_iic022in_Wav_508 = 229, + c_iic022in_Pho_508 = 230, + c_iic022in_0_sfx = 231, + c_iic022in_1_sfx = 232, + c_iic022in_2_sfx = 233, + c_iic022in_3_sfx = 234, + c_iic022in_4_sfx = 235, + c_iic022in_5_sfx = 236, + c_iic022in_6_sfx = 237, + c_iic022in_7_sfx = 238, + c_iic022in_Anim = 239, + c_iic023in_Wav_509 = 240, + c_iic023in_Pho_509 = 241, + c_iic023in_0_sfx = 242, + c_iic023in_1_sfx = 243, + c_iic023in_2_sfx = 244, + c_iic023in_3_sfx = 245, + c_iic023in_4_sfx = 246, + c_iic023in_5_sfx = 247, + c_iic023in_6_sfx = 248, + c_iic023in_7_sfx = 249, + c_iic023in_8_sfx = 250, + c_iic023in_9_sfx = 251, + c_iic023in_10_sfx = 252, + c_iic023in_11_sfx = 253, + c_iic023in_Anim = 254, + c_iicx23in_Wav_510 = 255, + c_iicx23in_Pho_510 = 256, + c_iicx23in_Anim = 257, + c_iic024in_Wav_511 = 258, + c_iic024in_Pho_511 = 259, + c_iic024in_0_sfx = 260, + c_iic024in_1_sfx = 261, + c_iic024in_2_sfx = 262, + c_iic024in_3_sfx = 263, + c_iic024in_4_sfx = 264, + c_iic024in_Anim = 265, + c_iic025in_Wav_512 = 266, + c_iic025in_Pho_512 = 267, + c_iic025in_0_sfx = 268, + c_iic025in_Anim = 269, + c_iic026in_Wav_513 = 270, + c_iic026in_Pho_513 = 271, + c_iic026in_0_sfx = 272, + c_iic026in_1_sfx = 273, + c_iic026in_2_sfx = 274, + c_iic026in_3_sfx = 275, + c_iic026in_4_sfx = 276, + c_iic026in_5_sfx = 277, + c_iic026in_6_sfx = 278, + c_iic026in_7_sfx = 279, + c_iic026in_8_sfx = 280, + c_iic026in_9_sfx = 281, + c_iic026in_10_sfx = 282, + c_iic026in_11_sfx = 283, + c_iic026in_Anim = 284, + c_iicx26in_Wav_514 = 285, + c_iicx26in_Pho_514 = 286, + c_iicx26in_Anim = 287, + c_iic027in_Wav_515 = 288, + c_iic027in_Pho_515 = 289, + c_iic027in_0_sfx = 290, + c_iic027in_1_sfx = 291, + c_iic027in_2_sfx = 292, + c_iic027in_3_sfx = 293, + c_iic027in_4_sfx = 294, + c_iic027in_5_sfx = 295, + c_iic027in_Anim = 296, + c_IIC029IN_Wav_516 = 297, + c_IIC029IN_Pho_516 = 298, + c_iic029in_0_sfx = 299, + c_iic029in_1_sfx = 300, + c_iic029in_2_sfx = 301, + c_iic029in_Anim = 302, + c_IIC032IN_Wav_517 = 303, + c_IIC032IN_Pho_517 = 304, + c_iic032in_0_sfx = 305, + c_iic032in_1_sfx = 306, + c_iic032in_2_sfx = 307, + c_iic032in_3_sfx = 308, + c_iic032in_4_sfx = 309, + c_iic032in_Anim = 310, + c_iic033in_Wav_518 = 311, + c_iic033in_Pho_518 = 312, + c_iic033in_0_sfx = 313, + c_iic033in_1_sfx = 314, + c_iic033in_2_sfx = 315, + c_iic033in_3_sfx = 316, + c_iic033in_4_sfx = 317, + c_iic033in_5_sfx = 318, + c_iic033in_6_sfx = 319, + c_iic033in_Anim = 320, + c_iic034in_Wav_519 = 321, + c_iic034in_Pho_519 = 322, + c_iic034in_0_sfx = 323, + c_iic034in_1_sfx = 324, + c_iic034in_2_sfx = 325, + c_iic034in_3_sfx = 326, + c_iic034in_Anim = 327, + c_iic035in_Wav_520 = 328, + c_iic035in_Pho_520 = 329, + c_iic035in_0_sfx = 330, + c_iic035in_1_sfx = 331, + c_iic035in_Anim = 332, + c_iic036in_Wav_521 = 333, + c_iic036in_Pho_521 = 334, + c_iic036in_0_sfx = 335, + c_iic036in_1_sfx = 336, + c_iic036in_2_sfx = 337, + c_iic036in_3_sfx = 338, + c_iic036in_4_sfx = 339, + c_iic036in_5_sfx = 340, + c_iic036in_6_sfx = 341, + c_iic036in_7_sfx = 342, + c_iic036in_Anim = 343, + c_IIC044IN_Wav_522 = 344, + c_IIC044IN_Pho_522 = 345, + c_iic043in_0_sfx = 346, + c_iic043in_1_sfx = 347, + c_iic043in_2_sfx = 348, + c_iic043in_3_sfx = 349, + c_iic043in_4_sfx = 350, + c_iic043in_5_sfx = 351, + c_iic043in_6_sfx = 352, + c_iic043in_7_sfx = 353, + c_iic043in_8_sfx = 354, + c_iic043in_9_sfx = 355, + c_iic043in_10_sfx = 356, + c_iic043in_11_sfx = 357, + c_iic043in_12_sfx = 358, + c_iic043in_13_sfx = 359, + c_iic043in_14_sfx = 360, + c_iic043in_15_sfx = 361, + c_iic043in_16_sfx = 362, + c_iic043in_17_sfx = 363, + c_iic043in_Anim = 364, + c_IIC045IN_Wav_523 = 365, + c_IIC045IN_Pho_523 = 366, + c_iic045in_0_sfx = 367, + c_iic045in_1_sfx = 368, + c_iic045in_2_sfx = 369, + c_iic045in_3_sfx = 370, + c_iic045in_4_sfx = 371, + c_iic045in_5_sfx = 372, + c_iic045in_6_sfx = 373, + c_iic045in_7_sfx = 374, + c_iic045in_8_sfx = 375, + c_iic045in_Anim = 376, + c_iic046in_Wav_524 = 377, + c_iic046in_Pho_524 = 378, + c_iic046in_Anim = 379, + c_iic048in_Wav_525 = 380, + c_iic048in_Pho_525 = 381, + c_iic048in_0_sfx = 382, + c_iic048in_1_sfx = 383, + c_iic048in_2_sfx = 384, + c_iic048in_3_sfx = 385, + c_iic048in_4_sfx = 386, + c_iic048in_Anim = 387, + c_iic049in_Wav_526 = 388, + c_iic049in_Pho_526 = 389, + c_iic049in_0_sfx = 390, + c_iic049in_1_sfx = 391, + c_iic049in_2_sfx = 392, + c_iic049in_3_sfx = 393, + c_iic049in_4_sfx = 394, + c_iic049in_5_sfx = 395, + c_iic049in_6_sfx = 396, + c_iic049in_7_sfx = 397, + c_iic049in_8_sfx = 398, + c_iic049in_9_sfx = 399, + c_iic049in_10_sfx = 400, + c_iic049in_Anim = 401, + c_iic050in_Wav_527 = 402, + c_iic050in_Pho_527 = 403, + c_iic050in_0_sfx = 404, + c_iic050in_1_sfx = 405, + c_iic050in_2_sfx = 406, + c_iic050in_3_sfx = 407, + c_iic050in_4_sfx = 408, + c_iic050in_Anim = 409, + c_iic055in_Wav_528 = 410, + c_iic055in_Pho_528 = 411, + c_iic055in_0_sfx = 412, + c_iic055in_1_sfx = 413, + c_iic055in_2_sfx = 414, + c_iic055in_3_sfx = 415, + c_iic055in_4_sfx = 416, + c_iic055in_Anim = 417, + c_iic056in_Wav_529 = 418, + c_iic056in_Pho_529 = 419, + c_iic056in_0_sfx = 420, + c_iic056in_1_sfx = 421, + c_iic056in_2_sfx = 422, + c_iic056in_3_sfx = 423, + c_iic056in_4_sfx = 424, + c_iic056in_5_sfx = 425, + c_iic056in_6_sfx = 426, + c_iic056in_7_sfx = 427, + c_iic056in_Anim = 428, + c_iic057in_Wav_530 = 429, + c_iic057in_Pho_530 = 430, + c_iic057in_0_sfx = 431, + c_iic057in_1_sfx = 432, + c_iic057in_2_sfx = 433, + c_iic057in_3_sfx = 434, + c_iic057in_Anim = 435, + c_iic058in_Wav_531 = 436, + c_iic058in_Pho_531 = 437, + c_iic058in_0_sfx = 438, + c_iic058in_1_sfx = 439, + c_iic058in_2_sfx = 440, + c_iic058in_Anim = 441, + c_iica28in_Wav_532 = 442, + c_iica28in_Pho_532 = 443, + c_iica28in_Anim = 444, + c_iica30in_0_sfx = 445, + c_iica30in_Anim = 446, + c_iicb28in_Wav_534 = 447, + c_iicb28in_Pho_534 = 448, + c_iicb28in_0_sfx = 449, + c_iicb28in_Anim = 450, + c_iicb30in_0_sfx = 451, + c_iicb30in_Anim = 452, + c_iicc28in_Wav_536 = 453, + c_iicc28in_Pho_536 = 454, + c_iicc28in_0_sfx = 455, + c_iicc28in_Anim = 456, + c_nic002in_0_sfx = 457, + c_nic002in_Anim = 458, + c_nic003in_0_sfx = 459, + c_nic003in_Anim = 460, + c_tic089in_Wav_539 = 461, + c_tic089in_Pho_539 = 462, + c_tic089in_0_sfx = 463, + c_tic089in_1_sfx = 464, + c_tic089in_2_sfx = 465, + c_tic089in_Anim = 466, + c_tic092in_Wav_540 = 467, + c_tic092in_Pho_540 = 468, + c_tic092in_0_sfx = 469, + c_tic092in_1_sfx = 470, + c_tic092in_2_sfx = 471, + c_tic092in_Anim = 472, + c_AVO901IN_Wav_541 = 473, + c_AVO901IN_Pho_541 = 474, + c_avo901in_Anim = 475, + c_AVO902IN_Wav_542 = 476, + c_AVO902IN_Pho_542 = 477, + c_avo902in_Anim = 478, + c_AVO903IN_Wav_543 = 479, + c_AVO903IN_Pho_543 = 480, + c_avo903in_Anim = 481, + c_AVO904IN_Wav_544 = 482, + c_AVO904IN_Pho_544 = 483, + c_avo904in_Anim = 484, + c_AVO905IN_Wav_545 = 485, + c_AVO905IN_Pho_545 = 486, + c_avo905in_Anim = 487, + + c_iic001in_RunAnim = 500, + c_iic016in_RunAnim = 501, + c_iicx17in_RunAnim = 502, + c_iic018in_RunAnim = 503, + c_iicx18in_RunAnim = 504, + c_iic019in_RunAnim = 505, + c_iic020in_RunAnim = 506, + c_iic021in_RunAnim = 507, + c_iic022in_RunAnim = 508, + c_iic023in_RunAnim = 509, + c_iicx23in_RunAnim = 510, + c_iic024in_RunAnim = 511, + c_iic025in_RunAnim = 512, + c_iic026in_RunAnim = 513, + c_iicx26in_RunAnim = 514, + c_iic027in_RunAnim = 515, + c_iic029in_RunAnim = 516, + c_iic032in_RunAnim = 517, + c_iic033in_RunAnim = 518, + c_iic034in_RunAnim = 519, + c_iic035in_RunAnim = 520, + c_iic036in_RunAnim = 521, + c_iic043in_RunAnim = 522, + c_iic045in_RunAnim = 523, + c_iic046in_RunAnim = 524, + c_iic048in_RunAnim = 525, + c_iic049in_RunAnim = 526, + c_iic050in_RunAnim = 527, + c_iic055in_RunAnim = 528, + c_iic056in_RunAnim = 529, + c_iic057in_RunAnim = 530, + c_iic058in_RunAnim = 531, + c_iica28in_RunAnim = 532, + c_iica30in_RunAnim = 533, + c_iicb28in_RunAnim = 534, + c_iicb30in_RunAnim = 535, + c_iicc28in_RunAnim = 536, + c_nic002in_RunAnim = 537, + c_nic003in_RunAnim = 538, + c_tic089in_RunAnim = 539, + c_tic092in_RunAnim = 540, + c_avo901in_RunAnim = 541, + c_avo902in_RunAnim = 542, + c_avo903in_RunAnim = 543, + c_avo904in_RunAnim = 544, + c_avo905in_RunAnim = 545, + c_AVo901In_PlayWav = 546, + c_AVo902In_PlayWav = 547, + c_AVo903In_PlayWav = 548, + c_AVo904In_PlayWav = 549, + c_AVo905In_PlayWav = 550, + c_Avo929In_PlayWav = 551, + c_iic062in_PlayWav = 552, + c_iic063in_PlayWav = 553, + c_iic064in_PlayWav = 554, + c_igs004ra_PlayWav = 555, + c_iho003ra_PlayWav = 556, + c_iic007ra_PlayWav = 557, + c_ijs002ra_PlayWav = 558, + c_ips005ra_PlayWav = 559, + c_ipz006ra_PlayWav = 560, + c_irt001ra_PlayWav = 561, + c_iic039in_PlayWav = 562, + c_iic040in_PlayWav = 563, + c_iic041in_PlayWav = 564, + c_iic042in_PlayWav = 565, + c_iic059in_PlayWav = 566, + c_iic060in_PlayWav = 567, + c_iic061in_PlayWav = 568, + c_iic051in_PlayWav = 569, + c_iic052in_PlayWav = 570, + c_iic053in_PlayWav = 571, + c_iic054in_PlayWav = 572, + c_iic007in_PlayWav = 573, + c_sbleh2br_PlayWav = 574, + c_snshahbr_PlayWav = 575 +}; +} // namespace InfomainScript + +#endif // INFOMAIN_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/infoscor_actions.h b/LEGO1/lego/legoomni/include/actions/infoscor_actions.h new file mode 100644 index 00000000..2da8be36 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/infoscor_actions.h @@ -0,0 +1,41 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef INFOSCOR_ACTIONS_H +#define INFOSCOR_ACTIONS_H + +namespace InfoscorScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneInfoscor = -1, + + c__StartUp = 0, + c_LeftArrow_Ctl = 1, + c_RightArrow_Ctl = 2, + c_Book_Ctl = 3, + c_LegoBox_Ctl = 4, + c_HistBook_Bmp = 5, + c_HistBook_Flc = 6, + c_LegoBox1_Flc = 7, + c_LegoBox2_Flc = 8, + c_LegoBox3_Flc = 9, + c_GoTo_HistBook = 10, + c_Background_Bitmap = 11, + c_LeftArrow_Up_Bitmap = 12, + c_LeftArrow_Down_Bitmap = 13, + c_RightArrow_Up_Bitmap = 14, + c_RightArrow_Down_Bitmap = 15, + c_Book_Up_Bitmap = 16, + c_LegoBox_Mask_Bitmap = 17, + c_ConfigAnimation = 18, + c_nin001pr_Anim = 19, + + c_nin001pr_RunAnim = 500, + c_iicc31in_PlayWav = 501 +}; +} // namespace InfoscorScript + +#endif // INFOSCOR_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/intro_actions.h b/LEGO1/lego/legoomni/include/actions/intro_actions.h new file mode 100644 index 00000000..1cda6cc5 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/intro_actions.h @@ -0,0 +1,36 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef INTRO_ACTIONS_H +#define INTRO_ACTIONS_H + +namespace IntroScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneIntro = -1, + + c_Lego_Movie = 0, + c_Mindscape_Movie = 1, + c_Intro_Movie = 2, + c_Outro_Movie = 3, + c_BadEnd_Movie = 4, + c_GoodEnd_Movie = 5, + c_Lego_Smk = 6, + c_Lego_Wave = 7, + c_Mindscape_Smk = 8, + c_Mindscape_Wave = 9, + c_Intro_Smk = 10, + c_Intro_Wave = 11, + c_Outro_Smk = 12, + c_Outro_Wave = 13, + c_BadEnd_Smk = 14, + c_BadEnd_Wave = 15, + c_GoodEnd_Smk = 16, + c_GoodEnd_Wave = 17 +}; +} // namespace IntroScript + +#endif // INTRO_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/isle_actions.h b/LEGO1/lego/legoomni/include/actions/isle_actions.h new file mode 100644 index 00000000..9457a7d2 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/isle_actions.h @@ -0,0 +1,3730 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef ISLE_ACTIONS_H +#define ISLE_ACTIONS_H + +namespace IsleScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneIsle = -1, + + c__Isle = 0, + c_Floor2 = 1, + c_IslePath = 2, + c_Pizzeria_Actor = 3, + c_Pizzeria_Model = 4, + c_Gas = 5, + c_GasModel = 6, + c_Police = 7, + c_PoliceModel = 8, + c_InfCtrModel = 9, + c_BikeDashboard = 10, + c_BikeDashboard_Bitmap = 11, + c_BikeArms_Ctl = 12, + c_BikeInfo_Ctl = 13, + c_BikeHorn_Sound = 14, + c_BikeHorn_Ctl = 15, + c_Beach = 16, + c_BeachModel = 17, + c_Radio_Ctl = 18, + c_Racej = 19, + c_RacejModel = 20, + c_HelicopterDashboard = 21, + c_HelicopterDashboard_Bitmap = 22, + c_HelicopterArms_Ctl = 23, + c_Helicopter_TakeOff_Ctl = 24, + c_Helicopter_Land_Ctl = 25, + + c_Helicopter_Info_Ctl = 28, + + c_HelicopterTakeOff_Anim = 32, + c_HelicopterLand_Anim = 33, + c_MedCtr = 34, + c_MedCtrModel = 35, + c_BumpBouy_Actor = 36, + c_BumpBouy_Model = 37, + c_Bike_Model = 38, + c_JetskiSpeedMeter = 39, + c_JetskiFuelMeter = 40, + c_JetskiDashboard11_Bitmap = 41, + c_JetskiDashboard12_Bitmap = 42, + c_JetskiDashboard13_Bitmap = 43, + c_JetskiDashboard14_Bitmap = 44, + c_JetskiDashboard15_Bitmap = 45, + c_JetskiDashboard16_Bitmap = 46, + c_MotoBk_Model = 47, + c_Ambul_Actor = 48, + c_Ambul_Model = 49, + c_Towtk_Actor = 50, + c_JetskiDashboard21_Bitmap = 51, + c_JetskiDashboard22_Bitmap = 52, + c_JetskiDashboard23_Bitmap = 53, + c_JetskiDashboard24_Bitmap = 54, + c_JetskiDashboard25_Bitmap = 55, + c_JetskiDashboard26_Bitmap = 56, + c_Towtk_Model = 57, + c_SkateBoard_Model = 58, + c_JukeBox_Model = 59, + c_Pizpie_Model = 60, + c_JetskiDashboard31_Bitmap = 61, + c_JetskiDashboard32_Bitmap = 62, + c_JetskiDashboard33_Bitmap = 63, + c_JetskiDashboard34_Bitmap = 64, + c_JetskiDashboard35_Bitmap = 65, + c_JetskiDashboard36_Bitmap = 66, + c_Cave_Entity = 67, + c_Cave_Model = 68, + c_Jail_Entity = 69, + c_Jail_Model = 70, + c_JetskiDashboard41_Bitmap = 71, + c_JetskiDashboard42_Bitmap = 72, + c_JetskiDashboard43_Bitmap = 73, + c_JetskiDashboard44_Bitmap = 74, + c_JetskiDashboard45_Bitmap = 75, + c_JetskiDashboard46_Bitmap = 76, + c_TransitionSound1 = 77, + c_TransitionSound2 = 78, + c_SoundAndAnim = 79, + c_CNs001xx = 80, + c_JetskiDashboard51_Bitmap = 81, + c_JetskiDashboard52_Bitmap = 82, + c_JetskiDashboard53_Bitmap = 83, + c_JetskiDashboard54_Bitmap = 84, + c_JetskiDashboard55_Bitmap = 85, + c_JetskiDashboard56_Bitmap = 86, + c_CNs002xx = 87, + c_CNs003xx = 88, + c_CNs004xx = 89, + c_CNs005xx = 90, + c_JetskiDashboard61_Bitmap = 91, + c_JetskiDashboard62_Bitmap = 92, + c_JetskiDashboard63_Bitmap = 93, + c_JetskiDashboard64_Bitmap = 94, + c_JetskiDashboard65_Bitmap = 95, + c_JetskiDashboard66_Bitmap = 96, + c_JetskiDashboard = 97, + c_JetskiArms_Ctl = 98, + c_JetskiInfo_Ctl = 99, + c_CNs007xx = 100, + c_CNs006xx = 101, + c_CNs008xx = 102, + c_CNs009xx = 103, + c_CNs010xx = 104, + c_CNs011xx = 105, + c_CNs012xx = 106, + c_CNs001Pe = 107, + c_CNs002Pe = 108, + c_CNs003Pe = 109, + c_CNs004Pe = 110, + c_CNs005Pe = 111, + c_CNs007Pe = 112, + c_CNs006Pe = 113, + c_CNs008Pe = 114, + c_CNs009Pe = 115, + c_CNs010Pe = 116, + c_CNs001Ma = 117, + c_CNs002Ma = 118, + c_CNs003Ma = 119, + c_CNs004Ma = 120, + c_CNs005Ma = 121, + c_CNs007Ma = 122, + c_CNs006Ma = 123, + c_CNs008Ma = 124, + c_CNs009Ma = 125, + c_CNs010Ma = 126, + c_CNs011Ma = 127, + c_CNs012Ma = 128, + c_CNs013Ma = 129, + c_CNs0x4Ma = 130, + c_CNs001Pa = 131, + c_CNs002Pa = 132, + c_CNs003Pa = 133, + c_CNs004Pa = 134, + c_CNs005Pa = 135, + c_CNs007Pa = 136, + c_CNs006Pa = 137, + c_CNs008Pa = 138, + c_CNs009Pa = 139, + c_CNs010Pa = 140, + c_CNs011Pa = 141, + c_CNs012Pa = 142, + c_CNs013Pa = 143, + c_CNs0x4Pa = 144, + c_CNs001Ni = 145, + c_CNs002Ni = 146, + c_CNs003Ni = 147, + c_CNs004Ni = 148, + c_CNs005Ni = 149, + c_MotoBikeDashboard = 150, + c_MotoBikeDashboard_Bitmap = 151, + c_MotoBikeArms_Ctl = 152, + c_MotoBikeInfo_Ctl = 153, + c_MotoBikeSpeedMeter = 154, + c_MotoBikeFuelMeter = 155, + c_CNs007Ni = 156, + c_CNs006Ni = 157, + c_CNs008Ni = 158, + c_CNs009Ni = 159, + c_AmbulanceDashboard = 160, + c_AmbulanceDashboard_Bitmap = 161, + c_AmbulanceArms_Ctl = 162, + c_AmbulanceInfo_Ctl = 163, + c_AmbulanceHorn_Sound = 164, + c_AmbulanceHorn_Ctl = 165, + c_AmbulanceSpeedMeter = 166, + c_AmbulanceFuelMeter = 167, + c_CNs010Ni = 168, + c_CNs011Ni = 169, + c_TowTrackDashboard = 170, + c_TowTrackDashboard_Bitmap = 171, + c_TowTrackArms_Ctl = 172, + c_TowInfo_Ctl = 173, + c_TowHorn_Sound = 174, + c_TowHorn_Ctl = 175, + c_TowSpeedMeter = 176, + c_TowFuelMeter = 177, + c_CNsx11Ni = 178, + c_CNs001La = 179, + c_DuneCarSpeedMeter = 180, + c_DuneCarDashboard1_Bitmap = 181, + c_DuneCarDashboard2_Bitmap = 182, + c_DuneCarDashboard3_Bitmap = 183, + c_DuneCarDashboard4_Bitmap = 184, + c_DuneCarDashboard5_Bitmap = 185, + c_DuneCarDashboard6_Bitmap = 186, + c_DuneCarDashboard = 187, + c_DuneCarArms_Ctl = 188, + c_DuneCarInfo_Ctl = 189, + c_DuneCarHorn_Sound = 190, + c_DuneCarHorn_Ctl = 191, + c_DuneCarFuelMeter = 192, + c_SkateDashboard = 193, + c_SkatePizza_Bitmap = 194, + c_SkateArms_Ctl = 195, + c_CNs002La = 196, + c_CNs003La = 197, + c_CNs004La = 198, + c_CNs005La = 199, + c_CNs007La = 200, + c_CNs006La = 201, + c_CNs008La = 202, + c_CNs009La = 203, + c_CNs010La = 204, + c_CNs011La = 205, + c_CNsx11La = 206, + c_CNs001Br = 207, + c_CNs002Br = 208, + c_CNs003Br = 209, + c_CNs004Br = 210, + c_CNs005Br = 211, + c_CNs007Br = 212, + c_CNs006Br = 213, + c_CNs008Br = 214, + c_CNs009Br = 215, + c_CNs010Br = 216, + c_CNs011Br = 217, + c_CNs012Br = 218, + c_CNs013Br = 219, + c_CNs014Br = 220, + c_CNs900Br = 221, + c_CNs901BR = 222, + c_CNs001Bd = 223, + c_CNs001Pg = 224, + c_CNs001Rd = 225, + c_CNs001Sy = 226, + c_CNs001Sk = 227, + c_BNsAss01 = 228, + c_BNsAss02 = 229, + c_BNsAss03 = 230, + c_BNsDis01 = 231, + c_BNsDis02 = 232, + c_BNsDis03 = 233, + c_crash5_PlayWav = 234, + c_s12_crash_PlayWav = 235, + c_SkateArms_Mask_Bitmap_236 = 236, + c_SkateArms_Mask_Bitmap_237 = 237, + c_DuneCarArms_Bitmap = 238, + c_DuneCarHornUp_Bitmap = 239, + c_DuneCarHornDown = 240, + c_DuneCarHornDown_Bitmap = 241, + c_DuneCarInfoUp_Bitmap = 242, + c_DuneCarInfoDown_Bitmap = 243, + c_JetskiArms_Mask_Bitmap = 244, + c_JetskiInfoUp_Bitmap = 245, + c_JetskiInfoDown_Bitmap = 246, + c_HelicopterArms_Mask_Bitmap_247 = 247, + c_HelicopterArms_Mask_Bitmap_248 = 248, + c_Helicopter_TakeOff_Up_Bitmap = 249, + c_NoPizza_Texture = 250, + c_NoPizaz_Texture = 251, + c_Helicopter_TakeOff_Down_Bitmap = 252, + c_Helicopter_Land_Up_Bitmap = 253, + c_Helicopter_Land_Down_Bitmap = 254, + c_Helicopter_Info_Up_Bitmap = 255, + c_Helicopter_Info_Down_Bitmap = 256, + c_MotoBikeArms_Mask_Bitmap = 257, + c_MotoBikeInfoUp_Bitmap = 258, + c_MotoBikeInfoDown_Bitmap = 259, + c_BikeArms_Mask_Bitmap = 260, + c_BikeHornUp_Bitmap = 261, + c_BikeHornDown = 262, + c_BikeHornDown_Bitmap = 263, + c_BikeInfoUp_Bitmap = 264, + c_BikeInfoDown_Bitmap = 265, + c_TowTrackArms_Mask_Bitmap = 266, + c_TowHornUp_Bitmap = 267, + c_TowHornDown = 268, + c_TowHornDown_Bitmap = 269, + c_TowInfoUp_Bitmap = 270, + c_TowInfoDown_Bitmap = 271, + c_AmbulanceArms_Mask_Bitmap = 272, + c_AmbulanceHornUp_Bitmap = 273, + c_AmbulanceHornDown = 274, + c_AmbulanceHornDown_Bitmap = 275, + c_AmbulanceInfoUp_Bitmap = 276, + c_AmbulanceInfoDown_Bitmap = 277, + c_Floor2_Bitmap = 278, + c_Floor2_Smk = 279, + c_Floor2_Wave = 280, + c_ElevRide_Info_Up_Bitmap = 281, + c_ElevRide_Info_Down_Bitmap = 282, + c_ElevRide_Two_Up_Bitmap = 283, + c_ElevRide_Two_Down_Bitmap = 284, + c_ElevRide_Three_Up_Bitmap = 285, + c_ElevRide_Three_Down_Bitmap = 286, + c_Meter1_3_Flc = 287, + c_Elev1_3_Anim = 288, + c_Meter2_3_Flc = 289, + c_Elev2_3_Anim = 290, + c_Meter3_2_Flc = 291, + c_Elev3_2_Anim = 292, + c_Meter3_1_Flc = 293, + c_Elev3_1_Anim = 294, + c_Meter2_1_Flc = 295, + c_Elev2_1_Anim = 296, + c_Meter1_2_Flc = 297, + c_Elev1_2_Anim = 298, + c_ElevOpen_LeftArrow_Up_Bitmap = 299, + c_ElevOpen_LeftArrow_Down_Bitmap = 300, + c_ElevOpen_RightArrow_Up_Bitmap = 301, + c_ElevOpen_RightArrow_Down_Bitmap = 302, + c_Observe_LeftArrow_Up_Bitmap = 303, + c_Observe_LeftArrow_Down_Bitmap = 304, + c_Observe_RightArrow_Up_Bitmap = 305, + c_Observe_RightArrow_Down_Bitmap = 306, + c_Observe_Plane_Up_Bitmap = 307, + c_Observe_Plane_Down_Bitmap = 308, + c_Observe_Sun_Up_Bitmap = 309, + c_Observe_Sun_Down_Bitmap = 310, + c_Observe_Moon_Up_Bitmap = 311, + c_Observe_Moon_Down_Bitmap = 312, + c_Observe_SkyColor_Up_Bitmap = 313, + c_Observe_SkyColor_Down_Bitmap = 314, + c_Observe_LCab_Up_Bitmap = 315, + c_Observe_LCab_Down_Bitmap = 316, + c_Observe_RCab_Up_Bitmap = 317, + c_Observe_RCab_Down_Bitmap = 318, + c_Observe_GlobeRArrow_Up_Bitmap = 319, + c_Observe_GlobeRArrow_Down_Bitmap = 320, + c_Observe_GlobeLArrow_Up_Bitmap = 321, + c_Observe_GlobeLArrow_Down_Bitmap = 322, + c_Observe_Draw1_Bitmap = 323, + c_Observe_Draw2_Bitmap = 324, + c_RadioOff_Bitmap = 325, + c_RadioOn_Bitmap = 326, + c_SeaView_LeftArrow_Up_Bitmap = 327, + c_SeaView_LeftArrow_Down_Bitmap = 328, + c_SeaView_RightArrow_Up_Bitmap = 329, + c_SeaView_RightArrow_Down_Bitmap = 330, + c_ElevDown_LeftArrow_Up_Bitmap = 331, + c_ElevDown_LeftArrow_Down_Bitmap = 332, + c_ElevDown_RightArrow_Up_Bitmap = 333, + c_ElevDown_RightArrow_Down_Bitmap = 334, + c_ElevDown_Elevator_Up_Bitmap = 335, + c_ElevDown_Elevator_Down_Bitmap = 336, + c_PoliDoor_LeftArrow_Up_Bitmap = 337, + c_PoliDoor_LeftArrow_Down_Bitmap = 338, + c_PoliDoor_RightArrow_Up_Bitmap = 339, + c_PoliDoor_RightArrow_Down_Bitmap = 340, + c_PoliDoor_Door_Mask_Bitmap = 341, + c_GaraDoor_LeftArrow_Up_Bitmap = 342, + c_GaraDoor_LeftArrow_Down_Bitmap = 343, + c_GaraDoor_RightArrow_Up_Bitmap = 344, + c_GaraDoor_RightArrow_Down_Bitmap = 345, + c_GaraDoor_Door_Mask_Bitmap = 346, + c_sba001bu_Wav_500 = 347, + c_sba001bu_Pho_500 = 348, + c_sba001bu_0_sfx = 349, + c_sba001bu_1_sfx = 350, + c_sba001bu_Anim = 351, + c_sba002bu_Wav_501 = 352, + c_sba002bu_Pho_501 = 353, + c_sba002bu_0_sfx = 354, + c_sba002bu_1_sfx = 355, + c_sba002bu_Anim = 356, + c_sba003bu_Wav_502 = 357, + c_sba003bu_Pho_502 = 358, + c_sba003bu_0_sfx = 359, + c_sba003bu_1_sfx = 360, + c_sba003bu_2_sfx = 361, + c_sba003bu_3_sfx = 362, + c_sba003bu_4_sfx = 363, + c_sba003bu_5_sfx = 364, + c_sba003bu_6_sfx = 365, + c_sba003bu_7_sfx = 366, + c_sba003bu_8_sfx = 367, + c_sba003bu_9_sfx = 368, + c_sba003bu_10_sfx = 369, + c_sba003bu_11_sfx = 370, + c_sba003bu_Anim = 371, + c_bns146rd_0_sfx = 372, + c_bns146rd_1_sfx = 373, + c_bns146rd_2_sfx = 374, + c_bns146rd_3_sfx = 375, + c_bns146rd_Anim = 376, + c_bns144rd_0_sfx = 377, + c_bns144rd_Anim = 378, + c_Fns017la_Wav_505 = 379, + c_Fns017la_Pho_505 = 380, + c_fns017la_0_sfx = 381, + c_fns017la_Anim = 382, + c_bns005p1_0_sfx = 383, + c_bns005p1_1_sfx = 384, + c_bns005p1_2_sfx = 385, + c_bns005p1_3_sfx = 386, + c_bns005p1_4_sfx = 387, + c_bns005p1_5_sfx = 388, + c_bns005p1_6_sfx = 389, + c_bns005p1_7_sfx = 390, + c_bns005p1_Anim = 391, + c_bns147rd_0_sfx = 392, + c_bns147rd_1_sfx = 393, + c_bns147rd_2_sfx = 394, + c_bns147rd_Anim = 395, + c_IGS007NA_Wav_508 = 396, + c_IGS007NA_Pho_508 = 397, + c_IGS005NA_Wav_508 = 398, + c_IGS005NA_Pho_508 = 399, + c_wns050p1_RunAnim = 400, + c_wns049p1_RunAnim = 401, + c_wns048p1_RunAnim = 402, + c_wns057rd_RunAnim = 403, + c_pns123pr_RunAnim = 404, + c_wns045di_RunAnim = 405, + c_wns053pr_RunAnim = 406, + c_wns046mg_RunAnim = 407, + c_wns051bd_RunAnim = 408, + c_pnsx48pr_RunAnim = 409, + c_pnsx69pr_RunAnim = 410, + c_pns125ni_RunAnim = 411, + c_pns122pr_RunAnim = 412, + c_pns050p1_RunAnim = 413, + c_pns069pr_RunAnim = 414, + c_pns066db_RunAnim = 415, + c_pns065rd_RunAnim = 416, + c_pns067gd_RunAnim = 417, + c_pns099pr_RunAnim = 418, + c_pns098pr_RunAnim = 419, + c_pns097pr_RunAnim = 420, + c_pns096pr_RunAnim = 421, + c_pns042bm_RunAnim = 422, + c_pns045p1_RunAnim = 423, + c_pns048pr_RunAnim = 424, + c_pns043en_RunAnim = 425, + c_pns022pr_RunAnim = 426, + c_pns018rd_RunAnim = 427, + c_pns019pr_RunAnim = 428, + c_pns021dl_RunAnim = 429, + c_IGS001NA_Wav_508 = 430, + c_IGS001NA_Pho_508 = 431, + c_IGS003NA_Wav_508 = 432, + c_IGS003NA_Pho_508 = 433, + c_igs001na_0_sfx = 434, + c_igs001na_1_sfx = 435, + c_igs001na_2_sfx = 436, + c_igs001na_3_sfx = 437, + c_igs001na_4_sfx = 438, + c_igs001na_5_sfx = 439, + c_igs001na_6_sfx = 440, + c_igs001na_7_sfx = 441, + c_igs001na_8_sfx = 442, + c_igs001na_9_sfx = 443, + c_igs001na_10_sfx = 444, + c_igs001na_11_sfx = 445, + c_igs001na_12_sfx = 446, + c_igs001na_13_sfx = 447, + c_igs001na_14_sfx = 448, + c_igs001na_15_sfx = 449, + c_igs001na_16_sfx = 450, + c_igs001na_17_sfx = 451, + c_igs001na_Anim = 452, + c_sns003nu_Wav_509 = 453, + c_sns003nu_Pho_509 = 454, + c_sns003nu_0_sfx = 455, + c_sns003nu_1_sfx = 456, + c_sns003nu_2_sfx = 457, + c_sns003nu_3_sfx = 458, + c_sns003nu_Anim = 459, + c_sgs001na_Wav_510 = 460, + c_sgs001na_Pho_510 = 461, + c_sgs001na_0_sfx = 462, + c_sgs001na_1_sfx = 463, + c_sgs001na_2_sfx = 464, + c_sgs001na_Anim = 465, + c_sns001nu_Wav_511 = 466, + c_sns001nu_Pho_511 = 467, + c_sns001nu_0_sfx = 468, + c_sns001nu_1_sfx = 469, + c_sns001nu_2_sfx = 470, + c_sns001nu_Anim = 471, + c_sns002nu_Wav_512 = 472, + c_sns002nu_Pho_512 = 473, + c_sns002nu_0_sfx = 474, + c_sns002nu_1_sfx = 475, + c_sns002nu_2_sfx = 476, + c_sns002nu_3_sfx = 477, + c_sns002nu_Anim = 478, + c_sgs002na_Wav_513 = 479, + c_sgs002na_Pho_513 = 480, + c_sgs002na_0_sfx = 481, + c_sgs002na_1_sfx = 482, + c_sgs002na_2_sfx = 483, + c_sgs002na_3_sfx = 484, + c_sgs002na_Anim = 485, + c_sgs003na_Wav_514 = 486, + c_sgs003na_Pho_514 = 487, + c_sgs003na_0_sfx = 488, + c_sgs003na_1_sfx = 489, + c_sgs003na_2_sfx = 490, + c_sgs003na_3_sfx = 491, + c_sgs003na_Anim = 492, + c_FNS003RE_Wav_515 = 493, + c_FNS003RE_Pho_515 = 494, + c_FNS002EN_Wav_515 = 495, + c_FNS002EN_Pho_515 = 496, + c_FNS001RE_Wav_515 = 497, + c_FNS001RE_Pho_515 = 498, + c_fns001re_0_sfx = 499, + c_sba001bu_RunAnim = 500, + c_sba002bu_RunAnim = 501, + c_sba003bu_RunAnim = 502, + c_bns146rd_RunAnim = 503, + c_bns144rd_RunAnim = 504, + c_fns017la_RunAnim = 505, + c_bns005p1_RunAnim = 506, + c_bns147rd_RunAnim = 507, + c_igs001na_RunAnim = 508, + c_sns003nu_RunAnim = 509, + c_sgs001na_RunAnim = 510, + c_sns001nu_RunAnim = 511, + c_sns002nu_RunAnim = 512, + c_sgs002na_RunAnim = 513, + c_sgs003na_RunAnim = 514, + c_fns001re_RunAnim = 515, + c_fns0x1re_RunAnim = 516, + c_fns007re_RunAnim = 517, + c_fns011re_RunAnim = 518, + c_sns001cl_RunAnim = 519, + c_sns002cl_RunAnim = 520, + c_sns003cl_RunAnim = 521, + c_bns191en_RunAnim = 522, + c_bho142en_RunAnim = 523, + c_bic143sy_RunAnim = 524, + c_sja004br_RunAnim = 525, + c_sja005br_RunAnim = 526, + c_sja006br_RunAnim = 527, + c_sja007br_RunAnim = 528, + c_sja008br_RunAnim = 529, + c_sja009br_RunAnim = 530, + c_sja010br_RunAnim = 531, + c_sja011br_RunAnim = 532, + c_sja012br_RunAnim = 533, + c_sja013br_RunAnim = 534, + c_sja014br_RunAnim = 535, + c_sja015br_RunAnim = 536, + c_sja016br_RunAnim = 537, + c_sja017br_RunAnim = 538, + c_sja018br_RunAnim = 539, + c_sja001br_RunAnim = 540, + c_sja002br_RunAnim = 541, + c_sja003br_RunAnim = 542, + c_ijs001sn_RunAnim = 543, + c_fjs148gd_RunAnim = 544, + c_fjs149va_RunAnim = 545, + c_sjs001va_RunAnim = 546, + c_sjs002va_RunAnim = 547, + c_sjs003va_RunAnim = 548, + c_sjs004va_RunAnim = 549, + c_fjs019rd_RunAnim = 550, + c_bjs009gd_RunAnim = 551, + c_sjs001sn_RunAnim = 552, + c_sjs002sn_RunAnim = 553, + c_sjs003sn_RunAnim = 554, + c_sjs004sn_RunAnim = 555, + c_sjs005sn_RunAnim = 556, + c_snsx31sh_RunAnim = 557, + c_bns007gd_RunAnim = 558, + c_fns001l1_RunAnim = 559, + c_fns001l2_RunAnim = 560, + c_fra157bm_RunAnim = 561, + c_bns145rd_RunAnim = 562, + c_ips001ro_RunAnim = 563, + c_sns010ni_RunAnim = 564, + c_sns003la_RunAnim = 565, + c_fps181ni_RunAnim = 566, + c_ipz001rd_RunAnim = 567, + c_spz004ma_RunAnim = 568, + c_spz005ma_RunAnim = 569, + c_spz006ma_RunAnim = 570, + c_spz004pa_RunAnim = 571, + c_spz013ma_RunAnim = 572, + c_spz006pa_RunAnim = 573, + c_spz014ma_RunAnim = 574, + c_spz005pa_RunAnim = 575, + c_spz015ma_RunAnim = 576, + c_spz007ma_RunAnim = 577, + c_spz013pa_RunAnim = 578, + c_spz008ma_RunAnim = 579, + c_spz014pa_RunAnim = 580, + c_spz009ma_RunAnim = 581, + c_spz015pa_RunAnim = 582, + c_spz007pa_RunAnim = 583, + c_spz011pe_RunAnim = 584, + c_spz008pa_RunAnim = 585, + c_spz009pa_RunAnim = 586, + c_spz010ma_RunAnim = 587, + c_spz010pa_RunAnim = 588, + c_spz011ma_RunAnim = 589, + c_spz011pa_RunAnim = 590, + c_spz012pa_RunAnim = 591, + c_spz001ma_RunAnim = 592, + c_spz002ma_RunAnim = 593, + c_spz003ma_RunAnim = 594, + c_spz003pa_RunAnim = 595, + c_fpz166p1_RunAnim = 596, + c_fpz172rd_RunAnim = 597, + c_spz001pa_RunAnim = 598, + c_spz002pa_RunAnim = 599, + c_ppz086bs_RunAnim = 600, + c_ppz008rd_RunAnim = 601, + c_ppz009pg_RunAnim = 602, + c_ivo918in_RunAnim = 603, + c_spz004pe_RunAnim = 604, + c_spz005pe_RunAnim = 605, + c_srp006pe_RunAnim = 606, + c_spz013pe_RunAnim = 607, + c_sns001pe_RunAnim = 608, + c_fra192pe_RunAnim = 609, + c_fra163mg_RunAnim = 610, + c_fns185gd_RunAnim = 611, + c_irt001in_RunAnim = 612, + c_irtx01sl_RunAnim = 613, + c_frt135df_RunAnim = 614, + c_frt137df_RunAnim = 615, + c_frt139df_RunAnim = 616, + c_frt025rd_RunAnim = 617, + c_frt132rd_RunAnim = 618, + c_srt001rd_RunAnim = 619, + c_srt003bd_RunAnim = 620, + c_sst001mg_RunAnim = 621, + c_sns004la_RunAnim = 622, + c_sns005la_RunAnim = 623, + c_sns006la_RunAnim = 624, + c_sps004ni_RunAnim = 625, + c_sps005ni_RunAnim = 626, + c_sps006ni_RunAnim = 627, + c_sns007la_RunAnim = 628, + c_sns008la_RunAnim = 629, + c_sns009la_RunAnim = 630, + c_sns007ni_RunAnim = 631, + c_sns008ni_RunAnim = 632, + c_sns009ni_RunAnim = 633, + c_pns017ml_RunAnim = 634, + c_sns010la_RunAnim = 635, + c_sns010pe_RunAnim = 636, + c_sns011la_RunAnim = 637, + c_sns012la_RunAnim = 638, + c_sns007pe_RunAnim = 639, + c_sns008pe_RunAnim = 640, + c_sns013la_RunAnim = 641, + c_sns013ni_RunAnim = 642, + c_sns014la_RunAnim = 643, + c_sns014ni_RunAnim = 644, + c_sns015la_RunAnim = 645, + c_sns015ni_RunAnim = 646, + c_sns011ni_RunAnim = 647, + c_sns012ni_RunAnim = 648, + c_sns014pe_RunAnim = 649, + c_sns015pe_RunAnim = 650, + c_sns003pe_RunAnim = 651, + c_sns017ni_RunAnim = 652, + c_sps001ni_RunAnim = 653, + c_sps002ni_RunAnim = 654, + c_sps003ni_RunAnim = 655, + c_sns017la_RunAnim = 656, + c_sps001la_RunAnim = 657, + c_sps002la_RunAnim = 658, + c_bns005pg_RunAnim = 659, + c_sns001ml_RunAnim = 660, + c_sns002mg_RunAnim = 661, + c_sns002ml_RunAnim = 662, + c_sns002pe_RunAnim = 663, + c_sns003mg_RunAnim = 664, + c_sns004mg_RunAnim = 665, + c_sns004rd_RunAnim = 666, + c_sns006bd_RunAnim = 667, + c_sns006ro_RunAnim = 668, + c_sns011in_RunAnim = 669, + c_sps001ro_RunAnim = 670, + c_sps002ro_RunAnim = 671, + c_sps003ro_RunAnim = 672, + c_sps004ro_RunAnim = 673, + c_srt005pg_RunAnim = 674, + c_pns100ml_RunAnim = 675, + c_ppz029rd_RunAnim = 676, + c_sns007sy_RunAnim = 677, + c_cnsx12la_RunAnim = 678, + c_cnsx12ni_RunAnim = 679, + c_ijs006sn_RunAnim = 680, + c_igs008na_RunAnim = 681, + c_irt007in_RunAnim = 682, + c_ips002ro_RunAnim = 683, + c_hho142cl_RunAnim = 684, + c_hho143cl_RunAnim = 685, + c_hho144cl_RunAnim = 686, + c_hho027en_RunAnim = 687, + c_hps116bd_RunAnim = 688, + c_hps117bd_RunAnim = 689, + c_hps118re_RunAnim = 690, + c_hps120en_RunAnim = 691, + c_hps122en_RunAnim = 692, + c_hpz047pe_RunAnim = 693, + c_hpz048pe_RunAnim = 694, + c_hpz049bd_RunAnim = 695, + c_hpz050bd_RunAnim = 696, + c_hpz052ma_RunAnim = 697, + c_hpz053pa_RunAnim = 698, + c_hpz055pa_RunAnim = 699, + c_hpz057ma_RunAnim = 700, + c_hpza51gd_RunAnim = 701, + c_hpzb51gd_RunAnim = 702, + c_hpzc51gd_RunAnim = 703, + c_hpzf51gd_RunAnim = 704, + c_hpzw51gd_RunAnim = 705, + c_hpzx51gd_RunAnim = 706, + c_hpzy51gd_RunAnim = 707, + c_hpzz51gd_RunAnim = 708, + c_nic002pr_RunAnim = 709, + c_nic003pr_RunAnim = 710, + c_nic004pr_RunAnim = 711, + c_pps025ni_RunAnim = 712, + c_pps026ni_RunAnim = 713, + c_pps027ni_RunAnim = 714, + c_ppz001pe_RunAnim = 715, + c_ppz006pa_RunAnim = 716, + c_ppz007pa_RunAnim = 717, + c_ppz010pa_RunAnim = 718, + c_ppz011pa_RunAnim = 719, + c_ppz013pa_RunAnim = 720, + c_ppz014pe_RunAnim = 721, + c_ppz015pe_RunAnim = 722, + c_ppz016pe_RunAnim = 723, + c_pgs050nu_RunAnim = 724, + c_pgs051nu_RunAnim = 725, + c_pgs052nu_RunAnim = 726, + c_ppz031ma_RunAnim = 727, + c_ppz035pa_RunAnim = 728, + c_ppz036pa_RunAnim = 729, + c_ppz037ma_RunAnim = 730, + c_ppz038ma_RunAnim = 731, + c_ppz054ma_RunAnim = 732, + c_ppz055ma_RunAnim = 733, + c_ppz056ma_RunAnim = 734, + c_ppz059ma_RunAnim = 735, + c_ppz060ma_RunAnim = 736, + c_ppz061ma_RunAnim = 737, + c_ppz064ma_RunAnim = 738, + c_prt072sl_RunAnim = 739, + c_prt073sl_RunAnim = 740, + c_prt074sl_RunAnim = 741, + c_pho104re_RunAnim = 742, + c_pho105re_RunAnim = 743, + c_pho106re_RunAnim = 744, + c_ppz075pa_RunAnim = 745, + c_ppz082pa_RunAnim = 746, + c_ppz084pa_RunAnim = 747, + c_ppz088ma_RunAnim = 748, + c_ppz089ma_RunAnim = 749, + c_ppz090ma_RunAnim = 750, + c_ppz093pe_RunAnim = 751, + c_ppz094pe_RunAnim = 752, + c_ppz095pe_RunAnim = 753, + c_prp101pr_RunAnim = 754, + c_pja126br_RunAnim = 755, + c_pja127br_RunAnim = 756, + c_pja129br_RunAnim = 757, + c_pja130br_RunAnim = 758, + c_pja131br_RunAnim = 759, + c_pja132br_RunAnim = 760, + c_ppz107ma_RunAnim = 761, + c_ppz114pa_RunAnim = 762, + c_ppz117ma_RunAnim = 763, + c_ppz118ma_RunAnim = 764, + c_ppz119ma_RunAnim = 765, + c_ppz120pa_RunAnim = 766, + c_wgs083nu_RunAnim = 767, + c_wgs085nu_RunAnim = 768, + c_wgs086nu_RunAnim = 769, + c_wgs087nu_RunAnim = 770, + c_wgs088nu_RunAnim = 771, + c_wgs089nu_RunAnim = 772, + c_wgs090nu_RunAnim = 773, + c_wgs091nu_RunAnim = 774, + c_wgs092nu_RunAnim = 775, + c_wgs093nu_RunAnim = 776, + c_wgs094nu_RunAnim = 777, + c_wgs095nu_RunAnim = 778, + c_wgs096nu_RunAnim = 779, + c_wgs097nu_RunAnim = 780, + c_wgs098nu_RunAnim = 781, + c_wgs099nu_RunAnim = 782, + c_wgs100nu_RunAnim = 783, + c_wgs101nu_RunAnim = 784, + c_wgs102nu_RunAnim = 785, + c_wgs103nu_RunAnim = 786, + c_wrt060bm_RunAnim = 787, + c_wrt074sl_RunAnim = 788, + c_wrt075rh_RunAnim = 789, + c_wrt076df_RunAnim = 790, + c_wrt078ni_RunAnim = 791, + c_wrt079bm_RunAnim = 792, + c_npz001bd_RunAnim = 793, + c_npz002bd_RunAnim = 794, + c_npz003bd_RunAnim = 795, + c_npz004bd_RunAnim = 796, + c_npz005bd_RunAnim = 797, + c_npz006bd_RunAnim = 798, + c_npz007bd_RunAnim = 799, + c_nca001ca_RunAnim = 800, + c_nca002sk_RunAnim = 801, + c_nca003gh_RunAnim = 802, + c_nla001ha_RunAnim = 803, + c_nla002sd_RunAnim = 804, + c_npa001ns_RunAnim = 805, + c_npa002ns_RunAnim = 806, + c_npa003ns_RunAnim = 807, + c_npa004ns_RunAnim = 808, + c_npa005dl_RunAnim = 809, + c_npa007dl_RunAnim = 810, + c_npa009dl_RunAnim = 811, + c_npa010db_RunAnim = 812, + c_npa012db_RunAnim = 813, + c_npa014db_RunAnim = 814, + c_npa015ca_RunAnim = 815, + c_npa017ca_RunAnim = 816, + c_npa019ca_RunAnim = 817, + c_npa020p1_RunAnim = 818, + c_npa022p1_RunAnim = 819, + c_npa024p1_RunAnim = 820, + c_npa025sh_RunAnim = 821, + c_npa027sh_RunAnim = 822, + c_npa029sh_RunAnim = 823, + c_npa030fl_RunAnim = 824, + c_npa031fl_RunAnim = 825, + c_npa032fl_RunAnim = 826, + c_npa034bh_RunAnim = 827, + c_npa035bh_RunAnim = 828, + c_npa036bh_RunAnim = 829, + c_npa038pn_RunAnim = 830, + c_npa039pn_RunAnim = 831, + c_npa040pn_RunAnim = 832, + c_npa042pm_RunAnim = 833, + c_npa043pm_RunAnim = 834, + c_npa044pm_RunAnim = 835, + c_npa046sr_RunAnim = 836, + c_npa047sr_RunAnim = 837, + c_npa048sr_RunAnim = 838, + c_npa050ba_RunAnim = 839, + c_npa051ba_RunAnim = 840, + c_npa052ba_RunAnim = 841, + c_npa054po_RunAnim = 842, + c_npa055po_RunAnim = 843, + c_npa056po_RunAnim = 844, + c_npa058r1_RunAnim = 845, + c_npa059r1_RunAnim = 846, + c_npa060r1_RunAnim = 847, + c_npa061r3_RunAnim = 848, + c_npa062r2_RunAnim = 849, + c_npa062r3_RunAnim = 850, + c_npa063r2_RunAnim = 851, + c_npa063r3_RunAnim = 852, + c_npa065r2_RunAnim = 853, + c_nja001pr_RunAnim = 854, + c_nja002pr_RunAnim = 855, + c_sjs007in_RunAnim = 856, + c_sns005in_RunAnim = 857, + c_sns006in_RunAnim = 858, + c_sns008in_RunAnim = 859, + c_sjs012in_RunAnim = 860, + c_sjs013in_RunAnim = 861, + c_sjs014in_RunAnim = 862, + c_sjs015in_RunAnim = 863, + c_srt001in_RunAnim = 864, + c_srt002in_RunAnim = 865, + c_srt003in_RunAnim = 866, + c_srt004in_RunAnim = 867, + c_nrtflag0_RunAnim = 868, + c_sns001ja_PlayWav = 869, + c_sns002ja_PlayWav = 870, + c_sns002jb_PlayWav = 871, + c_sns002js_PlayWav = 872, + c_sns002ra_PlayWav = 873, + c_sns003ra_PlayWav = 874, + c_sns004ra_PlayWav = 875, + c_sns005ra_PlayWav = 876, + c_sns006ra_PlayWav = 877, + c_sns007ra_PlayWav = 878, + c_sns008ra_PlayWav = 879, + c_sns009ra_PlayWav = 880, + c_sns010ra_PlayWav = 881, + c_sns010su_PlayWav = 882, + c_sns012ra_PlayWav = 883, + c_sns013ra_PlayWav = 884, + c_snsa01js_PlayWav = 885, + c_snsb01js_PlayWav = 886, + c_snsc01js_PlayWav = 887, + c_ham033cl_PlayWav = 888, + c_ham034ra_PlayWav = 889, + c_ham035ra_PlayWav = 890, + c_ham036ra_PlayWav = 891, + c_ham039ra_PlayWav = 892, + c_ham040cl_PlayWav = 893, + c_ham041cl_PlayWav = 894, + c_ham042cl_PlayWav = 895, + c_ham043cl_PlayWav = 896, + c_ham044cl_PlayWav = 897, + c_ham045cl_PlayWav = 898, + c_ham046cl_PlayWav = 899, + c_ham075cl_PlayWav = 900, + c_ham076cl_PlayWav = 901, + c_ham078cl_PlayWav = 902, + c_ham079cl_PlayWav = 903, + c_ham087cl_PlayWav = 904, + c_ham088cl_PlayWav = 905, + c_ham113cl_PlayWav = 906, + c_ham115cl_PlayWav = 907, + c_hpz037ma_PlayWav = 908, + c_sns078pa_PlayWav = 909, + c_sns079pa_PlayWav = 910, + c_wgs032nu_PlayWav = 911, + c_wns033na_PlayWav = 912, + c_wns034na_PlayWav = 913, + c_wns035na_PlayWav = 914, + c_wns036na_PlayWav = 915, + c_wns037na_PlayWav = 916, + c_wns038na_PlayWav = 917, + c_wns039na_PlayWav = 918, + c_wns040na_PlayWav = 919, + c_wns041na_PlayWav = 920, + c_wns042na_PlayWav = 921, + c_wns043na_PlayWav = 922, + c_wns044na_PlayWav = 923, + c_wrt061na_PlayWav = 924, + c_wrt082na_PlayWav = 925, + c_Avo900In_PlayWav = 926, + c_Avo909In_PlayWav = 927, + c_Avo910In_PlayWav = 928, + c_Avo911In_PlayWav = 929, + c_Avo912In_PlayWav = 930, + c_Avo913In_PlayWav = 931, + c_Avo914In_PlayWav = 932, + c_Avo915In_PlayWav = 933, + c_Avo916In_PlayWav = 934, + c_Avo917In_PlayWav = 935, + c_Avo919In_PlayWav = 936, + c_Avo920In_PlayWav = 937, + c_Avo921In_PlayWav = 938, + c_Avo922In_PlayWav = 939, + c_Avo923In_PlayWav = 940, + c_Avo924In_PlayWav = 941, + c_Avo927In_PlayWav = 942, + c_Avo928In_PlayWav = 943, + c_Avo930In_PlayWav = 944, + c_Avo931In_PlayWav = 945, + c_Avo932In_PlayWav = 946, + c_Avo933In_PlayWav = 947, + c_Avo900Ps_PlayWav = 948, + c_Avo901Ps_PlayWav = 949, + c_Avo902Ps_PlayWav = 950, + c_Avo903Ps_PlayWav = 951, + c_Avo904Ps_PlayWav = 952, + c_Avo905Ps_PlayWav = 953, + c_Avo906Ps_PlayWav = 954, + c_Avo907Ps_PlayWav = 955, + c_fns001re_1_sfx = 956, + c_fns001re_2_sfx = 957, + c_fns001re_3_sfx = 958, + c_fns001re_4_sfx = 959, + c_fns001re_Anim = 960, + c_FNS004RE_Wav_516 = 961, + c_FNS004RE_Pho_516 = 962, + c_FNS006RE_Wav_516 = 963, + c_FNS006RE_Pho_516 = 964, + c_FNS005EN_Wav_516 = 965, + c_FNS005EN_Pho_516 = 966, + c_fns0x1re_0_sfx = 967, + c_fns0x1re_1_sfx = 968, + c_fns0x1re_2_sfx = 969, + c_fns0x1re_3_sfx = 970, + c_fns0x1re_4_sfx = 971, + c_fns0x1re_5_sfx = 972, + c_fns0x1re_6_sfx = 973, + c_fns0x1re_Anim = 974, + c_FNS010EN_Wav_517 = 975, + c_FNS010EN_Pho_517 = 976, + c_FNS009RE_Wav_517 = 977, + c_FNS009RE_Pho_517 = 978, + c_FNS007RE_Wav_517 = 979, + c_FNS007RE_Pho_517 = 980, + c_fns007re_0_sfx = 981, + c_fns007re_1_sfx = 982, + c_fns007re_2_sfx = 983, + c_fns007re_3_sfx = 984, + c_fns007re_4_sfx = 985, + c_fns007re_5_sfx = 986, + c_fns007re_6_sfx = 987, + c_fns007re_7_sfx = 988, + c_fns007re_8_sfx = 989, + c_fns007re_9_sfx = 990, + c_fns007re_10_sfx = 991, + c_fns007re_11_sfx = 992, + c_fns007re_12_sfx = 993, + c_fns007re_Anim = 994, + c_FNS011RE_Wav_518 = 995, + c_FNS011RE_Pho_518 = 996, + c_FNS019RE_Wav_518 = 997, + c_FNS019RE_Pho_518 = 998, + c_FNS018EN_Wav_518 = 999, + c_FNS018EN_Pho_518 = 1000, + c_FNS017RE_Wav_518 = 1001, + c_FNS017RE_Pho_518 = 1002, + c_FNS016EN_Wav_518 = 1003, + c_FNS016EN_Pho_518 = 1004, + c_FNS015RE_Wav_518 = 1005, + c_FNS015RE_Pho_518 = 1006, + c_FNS014EN_Wav_518 = 1007, + c_FNS014EN_Pho_518 = 1008, + c_FNS013RE_Wav_518 = 1009, + c_FNS013RE_Pho_518 = 1010, + c_FNS012EN_Wav_518 = 1011, + c_FNS012EN_Pho_518 = 1012, + c_fns011re_0_sfx = 1013, + c_fns011re_1_sfx = 1014, + c_fns011re_2_sfx = 1015, + c_fns011re_3_sfx = 1016, + c_fns011re_4_sfx = 1017, + c_fns011re_5_sfx = 1018, + c_fns011re_6_sfx = 1019, + c_fns011re_7_sfx = 1020, + c_fns011re_8_sfx = 1021, + c_fns011re_9_sfx = 1022, + c_fns011re_10_sfx = 1023, + c_fns011re_11_sfx = 1024, + c_fns011re_12_sfx = 1025, + c_fns011re_13_sfx = 1026, + c_fns011re_14_sfx = 1027, + c_fns011re_15_sfx = 1028, + c_fns011re_16_sfx = 1029, + c_fns011re_17_sfx = 1030, + c_fns011re_18_sfx = 1031, + c_fns011re_19_sfx = 1032, + c_fns011re_20_sfx = 1033, + c_fns011re_21_sfx = 1034, + c_fns011re_22_sfx = 1035, + c_fns011re_23_sfx = 1036, + c_fns011re_24_sfx = 1037, + c_fns011re_25_sfx = 1038, + c_fns011re_Anim = 1039, + c_sns001cl_Wav_519 = 1040, + c_sns001cl_Pho_519 = 1041, + c_sns001cl_0_sfx = 1042, + c_sns001cl_1_sfx = 1043, + c_sns001cl_Anim = 1044, + c_sns002cl_Wav_520 = 1045, + c_sns002cl_Pho_520 = 1046, + c_sns002cl_0_sfx = 1047, + c_sns002cl_1_sfx = 1048, + c_sns002cl_2_sfx = 1049, + c_ElevRide = 1050, + c_ElevRide_Background_Bitmap = 1051, + c_ElevRide_Info_Ctl = 1052, + c_ElevRide_Two_Ctl = 1053, + c_ElevRide_Three_Ctl = 1054, + c_Elev1_3_Ride = 1055, + c_Meter1_3_Bitmap = 1056, + c_Elev2_3_Ride = 1057, + c_Meter2_3_Bitmap = 1058, + c_Elev3_1_Ride = 1059, + c_Meter3_1_Bitmap = 1060, + c_Elev3_2_Ride = 1061, + c_Meter3_2_Bitmap = 1062, + c_Elev2_1_Ride = 1063, + c_Meter2_1_Bitmap = 1064, + c_Elev1_2_Ride = 1065, + c_Meter1_2_Bitmap = 1066, + c_Meter3_Bitmap = 1067, + c_sns002cl_3_sfx = 1068, + c_sns002cl_Anim = 1069, + c_sns003cl_Wav_521 = 1070, + c_sns003cl_Pho_521 = 1071, + c_sns003cl_0_sfx = 1072, + c_sns003cl_1_sfx = 1073, + c_sns003cl_2_sfx = 1074, + c_sns003cl_3_sfx = 1075, + c_sns003cl_4_sfx = 1076, + c_sns003cl_Anim = 1077, + c_bns191en_0_sfx = 1078, + c_bns191en_1_sfx = 1079, + c_bns191en_2_sfx = 1080, + c_bns191en_3_sfx = 1081, + c_bns191en_4_sfx = 1082, + c_bns191en_5_sfx = 1083, + c_bns191en_6_sfx = 1084, + c_bns191en_7_sfx = 1085, + c_bns191en_8_sfx = 1086, + c_bns191en_Anim = 1087, + c_bho142en_0_sfx = 1088, + c_bho142en_1_sfx = 1089, + c_bho142en_2_sfx = 1090, + c_bho142en_Anim = 1091, + c_bic143sy_0_sfx = 1092, + c_bic143sy_1_sfx = 1093, + c_bic143sy_2_sfx = 1094, + c_bic143sy_3_sfx = 1095, + c_bic143sy_4_sfx = 1096, + c_bic143sy_5_sfx = 1097, + c_bic143sy_6_sfx = 1098, + c_bic143sy_7_sfx = 1099, + c_bic143sy_8_sfx = 1100, + c_bic143sy_9_sfx = 1101, + c_bic143sy_10_sfx = 1102, + c_bic143sy_11_sfx = 1103, + c_bic143sy_Anim = 1104, + c_SJA004BR_Wav_525 = 1105, + c_SJA004BR_Pho_525 = 1106, + c_sja004br_0_sfx = 1107, + c_sja004br_1_sfx = 1108, + c_sja004br_Anim = 1109, + c_sja005br_Wav_526 = 1110, + c_sja005br_Pho_526 = 1111, + c_sja005br_0_sfx = 1112, + c_sja005br_1_sfx = 1113, + c_ElevOpen = 1114, + c_ElevOpen_Background_Bitmap = 1115, + c_ElevOpen_LeftArrow_Ctl = 1116, + c_ElevOpen_RightArrow_Ctl = 1117, + c_Observe = 1118, + c_Observe_Background_Bitmap = 1119, + c_Observe_LeftArrow_Ctl = 1120, + c_Observe_RightArrow_Ctl = 1121, + c_Observe_Plane_Ctl = 1122, + c_Observe_Sun_Ctl = 1123, + c_Observe_Moon_Ctl = 1124, + c_Observe_SkyColor_Ctl = 1125, + c_Observe_LCab_Ctl = 1126, + c_Observe_RCab_Ctl = 1127, + c_Observe_GlobeLArrow_Ctl = 1128, + c_Observe_GlobeRArrow_Ctl = 1129, + c_Observe_Globe1_Bitmap = 1130, + c_Observe_Globe2_Bitmap = 1131, + c_Observe_Globe3_Bitmap = 1132, + c_Observe_Globe4_Bitmap = 1133, + c_Observe_Globe5_Bitmap = 1134, + c_Observe_Globe6_Bitmap = 1135, + c_Observe_Monkey_Flc = 1136, + c_Observe_Draw1_Ctl = 1137, + c_Observe_Draw2_Ctl = 1138, + c_sja005br_2_sfx = 1139, + c_SeaView = 1140, + c_SeaView_Background_Bitmap = 1141, + c_SeaView_LeftArrow_Ctl = 1142, + c_SeaView_RightArrow_Ctl = 1143, + c_sja005br_Anim = 1144, + c_ElevDown = 1145, + c_ElevDown_Background_Bitmap = 1146, + c_ElevDown_LeftArrow_Ctl = 1147, + c_ElevDown_RightArrow_Ctl = 1148, + c_ElevDown_Elevator_Ctl = 1149, + c_PoliDoor = 1150, + c_PoliDoor_Background_Bitmap = 1151, + c_PoliDoor_LeftArrow_Ctl = 1152, + c_PoliDoor_RightArrow_Ctl = 1153, + c_PoliDoor_Door_Ctl = 1154, + c_sja006br_Wav_527 = 1155, + c_sja006br_Pho_527 = 1156, + c_sja006br_0_sfx = 1157, + c_sja006br_1_sfx = 1158, + c_sja006br_2_sfx = 1159, + c_GaraDoor = 1160, + c_GaraDoor_Background_Bitmap = 1161, + c_GaraDoor_LeftArrow_Ctl = 1162, + c_GaraDoor_RightArrow_Ctl = 1163, + c_GaraDoor_Door_Ctl = 1164, + c_sja006br_3_sfx = 1165, + c_sja006br_Anim = 1166, + c_sja007br_Wav_528 = 1167, + c_sja007br_Pho_528 = 1168, + c_sja007br_0_sfx = 1169, + + c_sja007br_Anim = 1171, + c_sja008br_Wav_529 = 1172, + c_sja008br_Pho_529 = 1173, + c_sja008br_0_sfx = 1174, + c_sja008br_1_sfx = 1175, + c_sja008br_Anim = 1176, + c_sja009br_Wav_530 = 1177, + c_sja009br_Pho_530 = 1178, + c_sja009br_0_sfx = 1179, + c_JukeBox_Entity = 1180, + c_Pizza_Actor = 1181, + c_SkateBoard_Actor = 1182, + c_InfoCenter_Entity = 1183, + c_Bike_Actor = 1184, + c_MotoBk_Actor = 1185, + c_sja009br_1_sfx = 1186, + c_sja009br_2_sfx = 1187, + c_sja009br_3_sfx = 1188, + c_sja009br_4_sfx = 1189, + c_sja009br_Anim = 1190, + c_sja010br_Wav_531 = 1191, + c_sja010br_Pho_531 = 1192, + c_sja010br_0_sfx = 1193, + c_sja010br_1_sfx = 1194, + c_sja010br_2_sfx = 1195, + c_sja010br_Anim = 1196, + c_sja011br_Wav_532 = 1197, + c_sja011br_Pho_532 = 1198, + c_sja011br_0_sfx = 1199, + c_sja011br_Anim = 1200, + c_sja012br_Wav_533 = 1201, + c_sja012br_Pho_533 = 1202, + c_sja012br_0_sfx = 1203, + c_sja012br_1_sfx = 1204, + c_sja012br_Anim = 1205, + c_sja013br_Wav_534 = 1206, + c_sja013br_Pho_534 = 1207, + c_sja013br_0_sfx = 1208, + c_sja013br_1_sfx = 1209, + c_sja013br_2_sfx = 1210, + c_sja013br_3_sfx = 1211, + c_sja013br_4_sfx = 1212, + c_sja013br_Anim = 1213, + c_sja014br_Wav_535 = 1214, + c_sja014br_Pho_535 = 1215, + c_sja014br_0_sfx = 1216, + c_sja014br_1_sfx = 1217, + c_sja014br_2_sfx = 1218, + c_sja014br_3_sfx = 1219, + c_sja014br_Anim = 1220, + c_sja015br_Wav_536 = 1221, + c_sja015br_Pho_536 = 1222, + c_sja015br_0_sfx = 1223, + c_sja015br_1_sfx = 1224, + c_sja015br_Anim = 1225, + c_sja016br_Wav_537 = 1226, + c_sja016br_Pho_537 = 1227, + c_sja016br_0_sfx = 1228, + c_sja016br_1_sfx = 1229, + c_sja016br_2_sfx = 1230, + c_sja016br_3_sfx = 1231, + c_sja016br_4_sfx = 1232, + c_sja016br_Anim = 1233, + c_sja017br_Wav_538 = 1234, + c_sja017br_Pho_538 = 1235, + c_sja017br_0_sfx = 1236, + c_sja017br_1_sfx = 1237, + c_sja017br_2_sfx = 1238, + c_sja017br_3_sfx = 1239, + c_sja017br_Anim = 1240, + c_sja018br_Wav_539 = 1241, + c_sja018br_Pho_539 = 1242, + c_sja018br_0_sfx = 1243, + c_sja018br_1_sfx = 1244, + c_sja018br_2_sfx = 1245, + c_sja018br_3_sfx = 1246, + c_sja018br_Anim = 1247, + c_sja001br_Wav_540 = 1248, + c_sja001br_Pho_540 = 1249, + c_sja001br_0_sfx = 1250, + c_sja001br_1_sfx = 1251, + c_sja001br_2_sfx = 1252, + c_sja001br_Anim = 1253, + c_sja002br_Wav_541 = 1254, + c_sja002br_Pho_541 = 1255, + c_sja002br_0_sfx = 1256, + c_sja002br_1_sfx = 1257, + c_sja002br_Anim = 1258, + c_sja003br_Wav_542 = 1259, + c_sja003br_Pho_542 = 1260, + c_sja003br_0_sfx = 1261, + c_sja003br_1_sfx = 1262, + c_sja003br_2_sfx = 1263, + c_sja003br_Anim = 1264, + c_IJS005SN_Wav_543 = 1265, + c_IJS005SN_Pho_543 = 1266, + c_IJS003SN_Wav_543 = 1267, + c_IJS003SN_Pho_543 = 1268, + c_IJS001SN_Wav_543 = 1269, + c_IJS001SN_Pho_543 = 1270, + c_ijs001sn_0_sfx = 1271, + c_ijs001sn_1_sfx = 1272, + c_ijs001sn_2_sfx = 1273, + c_ijs001sn_3_sfx = 1274, + c_ijs001sn_4_sfx = 1275, + c_ijs001sn_5_sfx = 1276, + c_ijs001sn_6_sfx = 1277, + c_ijs001sn_7_sfx = 1278, + c_ijs001sn_8_sfx = 1279, + c_ijs001sn_9_sfx = 1280, + c_ijs001sn_10_sfx = 1281, + c_ijs001sn_11_sfx = 1282, + c_ijs001sn_12_sfx = 1283, + c_ijs001sn_13_sfx = 1284, + c_ijs001sn_14_sfx = 1285, + c_ijs001sn_15_sfx = 1286, + c_ijs001sn_Anim = 1287, + c_FJS148GD_Wav_544 = 1288, + c_FJS148GD_Pho_544 = 1289, + c_fjs148gd_0_sfx = 1290, + c_fjs148gd_1_sfx = 1291, + c_fjs148gd_2_sfx = 1292, + c_fjs148gd_3_sfx = 1293, + c_fjs148gd_4_sfx = 1294, + c_fjs148gd_5_sfx = 1295, + c_fjs148gd_6_sfx = 1296, + c_fjs148gd_7_sfx = 1297, + c_fjs148gd_8_sfx = 1298, + c_fjs148gd_9_sfx = 1299, + c_fjs148gd_10_sfx = 1300, + c_fjs148gd_11_sfx = 1301, + c_fjs148gd_12_sfx = 1302, + c_fjs148gd_13_sfx = 1303, + c_fjs148gd_14_sfx = 1304, + c_fjs148gd_15_sfx = 1305, + c_fjs148gd_16_sfx = 1306, + c_fjs148gd_17_sfx = 1307, + c_fjs148gd_Anim = 1308, + c_FJS150VA_Wav_545 = 1309, + c_FJS150VA_Pho_545 = 1310, + c_FJS149VA_Wav_545 = 1311, + c_FJS149VA_Pho_545 = 1312, + c_fjs149va_0_sfx = 1313, + c_fjs149va_1_sfx = 1314, + c_fjs149va_2_sfx = 1315, + c_fjs149va_3_sfx = 1316, + c_fjs149va_4_sfx = 1317, + c_fjs149va_5_sfx = 1318, + c_fjs149va_6_sfx = 1319, + c_fjs149va_Anim = 1320, + c_SJS001VA_Wav_546 = 1321, + c_SJS001VA_Pho_546 = 1322, + c_sjs001va_0_sfx = 1323, + c_sjs001va_1_sfx = 1324, + c_sjs001va_2_sfx = 1325, + c_sjs001va_3_sfx = 1326, + c_sjs001va_Anim = 1327, + c_sjs002va_Wav_547 = 1328, + c_sjs002va_Pho_547 = 1329, + c_sjs002va_0_sfx = 1330, + c_sjs002va_Anim = 1331, + c_SJS003VA_Wav_548 = 1332, + c_SJS003VA_Pho_548 = 1333, + c_sjs003va_0_sfx = 1334, + c_sjs003va_1_sfx = 1335, + c_sjs003va_Anim = 1336, + c_sjs004va_Wav_549 = 1337, + c_sjs004va_Pho_549 = 1338, + c_sjs004va_0_sfx = 1339, + c_sjs004va_Anim = 1340, + c_FJS024PG_Wav_550 = 1341, + c_FJS024PG_Pho_550 = 1342, + c_FJS023RD_Wav_550 = 1343, + c_FJS023RD_Pho_550 = 1344, + c_FJS022PG_Wav_550 = 1345, + c_FJS022PG_Pho_550 = 1346, + c_FJS021RD_Wav_550 = 1347, + c_FJS021RD_Pho_550 = 1348, + c_FJS020PG_Wav_550 = 1349, + c_FJS020PG_Pho_550 = 1350, + c_FJS019RD_Wav_550 = 1351, + c_FJS019RD_Pho_550 = 1352, + c_fjs019rd_0_sfx = 1353, + c_fjs019rd_1_sfx = 1354, + c_fjs019rd_2_sfx = 1355, + c_fjs019rd_3_sfx = 1356, + c_fjs019rd_4_sfx = 1357, + c_fjs019rd_5_sfx = 1358, + c_fjs019rd_6_sfx = 1359, + c_fjs019rd_7_sfx = 1360, + c_fjs019rd_8_sfx = 1361, + c_fjs019rd_9_sfx = 1362, + c_fjs019rd_Anim = 1363, + c_bjs009gd_0_sfx = 1364, + c_bjs009gd_1_sfx = 1365, + c_bjs009gd_2_sfx = 1366, + c_bjs009gd_3_sfx = 1367, + c_bjs009gd_4_sfx = 1368, + c_bjs009gd_5_sfx = 1369, + c_bjs009gd_6_sfx = 1370, + c_bjs009gd_7_sfx = 1371, + c_bjs009gd_8_sfx = 1372, + c_bjs009gd_9_sfx = 1373, + c_bjs009gd_10_sfx = 1374, + c_bjs009gd_11_sfx = 1375, + c_bjs009gd_Anim = 1376, + c_SJS001SN_Wav_552 = 1377, + c_SJS001SN_Pho_552 = 1378, + c_sjs001sn_0_sfx = 1379, + c_sjs001sn_1_sfx = 1380, + c_sjs001sn_Anim = 1381, + c_SJS002SN_Wav_553 = 1382, + c_SJS002SN_Pho_553 = 1383, + c_sjs002sn_0_sfx = 1384, + c_sjs002sn_1_sfx = 1385, + c_sjs002sn_2_sfx = 1386, + c_sjs002sn_Anim = 1387, + c_sjs003sn_Wav_554 = 1388, + c_sjs003sn_Pho_554 = 1389, + c_sjs003sn_0_sfx = 1390, + c_sjs003sn_1_sfx = 1391, + c_sjs003sn_2_sfx = 1392, + c_sjs003sn_3_sfx = 1393, + c_sjs003sn_Anim = 1394, + c_SJS004SN_Wav_555 = 1395, + c_SJS004SN_Pho_555 = 1396, + c_sjs004sn_0_sfx = 1397, + c_sjs004sn_1_sfx = 1398, + c_sjs004sn_Anim = 1399, + c_SJS005SN_Wav_556 = 1400, + c_SJS005SN_Pho_556 = 1401, + c_sjs005sn_0_sfx = 1402, + c_sjs005sn_1_sfx = 1403, + c_sjs005sn_2_sfx = 1404, + c_sjs005sn_Anim = 1405, + c_SNSX31SH_Wav_557 = 1406, + c_snsx31sh_0_sfx = 1407, + c_snsx31sh_Anim = 1408, + c_bns007gd_0_sfx = 1409, + c_bns007gd_1_sfx = 1410, + c_bns007gd_2_sfx = 1411, + c_bns007gd_3_sfx = 1412, + c_bns007gd_4_sfx = 1413, + c_bns007gd_5_sfx = 1414, + c_bns007gd_Anim = 1415, + c_FNSH01L4_Wav_559 = 1416, + c_FNSH01L4_Pho_559 = 1417, + c_FNSA01L2_Wav_559 = 1418, + c_FNSA01L2_Pho_559 = 1419, + c_FNSD01L2_Wav_559 = 1420, + c_FNSD01L2_Pho_559 = 1421, + c_FNSI01L1_Wav_559 = 1422, + c_FNSI01L1_Pho_559 = 1423, + c_FNSK01L1_Wav_559 = 1424, + c_FNSK01L1_Pho_559 = 1425, + c_FNSB01L2_Wav_559 = 1426, + c_FNSB01L2_Pho_559 = 1427, + c_FNSI01L4_Wav_559 = 1428, + c_FNSI01L4_Pho_559 = 1429, + c_FNSC01L3_Wav_559 = 1430, + c_FNSC01L3_Pho_559 = 1431, + c_fns001l1_0_sfx = 1432, + c_fns001l1_Anim = 1433, + c_FNSJ01L4_Wav_560 = 1434, + c_FNSJ01L4_Pho_560 = 1435, + c_FNSI01L1_Wav_560 = 1436, + c_FNSI01L1_Pho_560 = 1437, + c_FNSH01L4_Wav_560 = 1438, + c_FNSH01L4_Pho_560 = 1439, + c_FNSH01L1_Wav_560 = 1440, + c_FNSH01L1_Pho_560 = 1441, + c_FNSE01L2_Wav_560 = 1442, + c_FNSE01L2_Pho_560 = 1443, + c_FNSD01L4_Wav_560 = 1444, + c_FNSD01L4_Pho_560 = 1445, + c_FNSD01L2_Wav_560 = 1446, + c_FNSD01L2_Pho_560 = 1447, + c_FNSC01L3_Wav_560 = 1448, + c_FNSC01L3_Pho_560 = 1449, + c_FNSB01L2_Wav_560 = 1450, + c_FNSB01L2_Pho_560 = 1451, + c_FNSB01L1_Wav_560 = 1452, + c_FNSB01L1_Pho_560 = 1453, + c_FNSA01L3_Wav_560 = 1454, + c_FNSA01L3_Pho_560 = 1455, + c_FNSA01L2_Wav_560 = 1456, + c_FNSA01L2_Pho_560 = 1457, + c_FNSD01L3_Wav_560 = 1458, + c_FNSD01L3_Pho_560 = 1459, + c_FNSB01L3_Wav_560 = 1460, + c_FNSB01L3_Pho_560 = 1461, + c_fns001l2_0_sfx = 1462, + c_fns001l2_1_sfx = 1463, + c_fns001l2_2_sfx = 1464, + c_fns001l2_3_sfx = 1465, + c_fns001l2_4_sfx = 1466, + c_fns001l2_5_sfx = 1467, + c_fns001l2_6_sfx = 1468, + c_fns001l2_7_sfx = 1469, + c_fns001l2_8_sfx = 1470, + c_fns001l2_9_sfx = 1471, + c_fns001l2_10_sfx = 1472, + c_fns001l2_11_sfx = 1473, + c_fns001l2_12_sfx = 1474, + c_fns001l2_13_sfx = 1475, + c_fns001l2_14_sfx = 1476, + c_fns001l2_15_sfx = 1477, + c_fns001l2_16_sfx = 1478, + c_fns001l2_17_sfx = 1479, + c_fns001l2_Anim = 1480, + c_FRA161BM_Wav_561 = 1481, + c_FRA161BM_Pho_561 = 1482, + c_FRA160JK_Wav_561 = 1483, + c_FRA160JK_Pho_561 = 1484, + c_FRA159BM_Wav_561 = 1485, + c_FRA159BM_Pho_561 = 1486, + c_FRF158GD_Wav_561 = 1487, + c_FRF158GD_Pho_561 = 1488, + c_FRD158GD_Wav_561 = 1489, + c_FRD158GD_Pho_561 = 1490, + c_FRC158GD_Wav_561 = 1491, + c_FRC158GD_Pho_561 = 1492, + c_FRB158GD_Wav_561 = 1493, + c_FRB158GD_Pho_561 = 1494, + c_FRA157BM_Wav_561 = 1495, + c_FRA157BM_Pho_561 = 1496, + c_fra157bm_0_sfx = 1497, + c_fra157bm_1_sfx = 1498, + c_fra157bm_2_sfx = 1499, + c_fra157bm_3_sfx = 1500, + c_fra157bm_4_sfx = 1501, + c_fra157bm_5_sfx = 1502, + c_fra157bm_6_sfx = 1503, + c_fra157bm_7_sfx = 1504, + c_fra157bm_8_sfx = 1505, + c_fra157bm_9_sfx = 1506, + c_fra157bm_Anim = 1507, + c_bns145rd_0_sfx = 1508, + c_bns145rd_1_sfx = 1509, + c_bns145rd_2_sfx = 1510, + c_bns145rd_3_sfx = 1511, + c_bns145rd_4_sfx = 1512, + c_bns145rd_5_sfx = 1513, + c_bns145rd_6_sfx = 1514, + c_bns145rd_7_sfx = 1515, + c_bns145rd_8_sfx = 1516, + c_bns145rd_Anim = 1517, + c_IPS001RO_Wav_563 = 1518, + c_IPS001RO_Pho_563 = 1519, + c_ips001ro_0_sfx = 1520, + c_ips001ro_1_sfx = 1521, + c_ips001ro_2_sfx = 1522, + c_ips001ro_3_sfx = 1523, + c_ips001ro_4_sfx = 1524, + c_ips001ro_5_sfx = 1525, + c_ips001ro_6_sfx = 1526, + c_ips001ro_7_sfx = 1527, + c_ips001ro_8_sfx = 1528, + c_ips001ro_9_sfx = 1529, + c_ips001ro_10_sfx = 1530, + c_ips001ro_Anim = 1531, + c_sns010ni_Wav_564 = 1532, + c_sns010ni_Pho_564 = 1533, + c_sns010ni_0_sfx = 1534, + c_sns010ni_1_sfx = 1535, + c_sns010ni_2_sfx = 1536, + c_sns010ni_3_sfx = 1537, + c_sns010ni_Anim = 1538, + c_sns003la_Wav_565 = 1539, + c_sns003la_Pho_565 = 1540, + c_sns003la_0_sfx = 1541, + c_sns003la_1_sfx = 1542, + c_sns003la_2_sfx = 1543, + c_sns003la_3_sfx = 1544, + c_sns003la_Anim = 1545, + c_Fps182p1_Wav_566 = 1546, + c_Fps184gd_Wav_566 = 1547, + c_Fps184gd_Pho_566 = 1548, + c_Fps183p2_Wav_566 = 1549, + c_Fps181ni_Wav_566 = 1550, + c_Fps181ni_Pho_566 = 1551, + c_fps181ni_0_sfx = 1552, + c_fps181ni_1_sfx = 1553, + c_fps181ni_2_sfx = 1554, + c_fps181ni_3_sfx = 1555, + c_fps181ni_4_sfx = 1556, + c_fps181ni_5_sfx = 1557, + c_fps181ni_6_sfx = 1558, + c_fps181ni_7_sfx = 1559, + c_fps181ni_8_sfx = 1560, + c_fps181ni_Anim = 1561, + c_IPZ004PG_Wav_567 = 1562, + c_IPZ004PG_Pho_567 = 1563, + c_IPZ003RD_Wav_567 = 1564, + c_IPZ003RD_Pho_567 = 1565, + c_IPZ002PG_Wav_567 = 1566, + c_IPZ002PG_Pho_567 = 1567, + c_IPZ001RD_Wav_567 = 1568, + c_IPZ001RD_Pho_567 = 1569, + c_ipz001rd_0_sfx = 1570, + c_ipz001rd_1_sfx = 1571, + c_ipz001rd_2_sfx = 1572, + c_ipz001rd_3_sfx = 1573, + c_ipz001rd_4_sfx = 1574, + c_ipz001rd_5_sfx = 1575, + c_ipz001rd_6_sfx = 1576, + c_ipz001rd_7_sfx = 1577, + c_ipz001rd_8_sfx = 1578, + c_ipz001rd_9_sfx = 1579, + c_ipz001rd_10_sfx = 1580, + c_ipz001rd_Anim = 1581, + c_spz004ma_Wav_568 = 1582, + c_spz004ma_Pho_568 = 1583, + c_spz004ma_0_sfx = 1584, + c_spz004ma_1_sfx = 1585, + c_spz004ma_2_sfx = 1586, + c_spz004ma_3_sfx = 1587, + c_spz004ma_4_sfx = 1588, + c_spz004ma_Anim = 1589, + c_spz005ma_Wav_569 = 1590, + c_spz005ma_Pho_569 = 1591, + c_spz005ma_0_sfx = 1592, + c_spz005ma_1_sfx = 1593, + c_spz005ma_Anim = 1594, + c_spz006ma_Wav_570 = 1595, + c_spz006ma_Pho_570 = 1596, + c_spz006ma_0_sfx = 1597, + c_spz006ma_1_sfx = 1598, + c_spz006ma_Anim = 1599, + c_SPZ004PA_Wav_571 = 1600, + c_SPZ004PA_Pho_571 = 1601, + c_spz004pa_0_sfx = 1602, + c_spz004pa_1_sfx = 1603, + c_spz004pa_Anim = 1604, + c_spz013ma_Wav_572 = 1605, + c_spz013ma_Pho_572 = 1606, + c_spz013ma_0_sfx = 1607, + c_spz013ma_1_sfx = 1608, + c_spz013ma_2_sfx = 1609, + c_spz013ma_3_sfx = 1610, + c_spz013ma_Anim = 1611, + c_spz006pa_Wav_573 = 1612, + c_spz006pa_Pho_573 = 1613, + c_spz006pa_0_sfx = 1614, + c_spz006pa_1_sfx = 1615, + c_spz006pa_2_sfx = 1616, + c_spz006pa_Anim = 1617, + c_spz014ma_Wav_574 = 1618, + c_spz014ma_Pho_574 = 1619, + c_spz014ma_0_sfx = 1620, + c_spz014ma_1_sfx = 1621, + c_spz014ma_2_sfx = 1622, + c_spz014ma_3_sfx = 1623, + c_spz014ma_Anim = 1624, + c_spz005pa_Wav_575 = 1625, + c_spz005pa_Pho_575 = 1626, + c_spz005pa_0_sfx = 1627, + c_spz005pa_1_sfx = 1628, + c_spz005pa_Anim = 1629, + c_spz015ma_Wav_576 = 1630, + c_spz015ma_Pho_576 = 1631, + c_spz015ma_0_sfx = 1632, + c_spz015ma_1_sfx = 1633, + c_spz015ma_Anim = 1634, + c_spz007ma_Wav_577 = 1635, + c_spz007ma_Pho_577 = 1636, + c_spz007ma_0_sfx = 1637, + c_spz007ma_1_sfx = 1638, + c_spz007ma_2_sfx = 1639, + c_spz007ma_Anim = 1640, + c_spz013pa_Wav_578 = 1641, + c_spz013pa_Pho_578 = 1642, + c_spz013pa_0_sfx = 1643, + c_spz013pa_1_sfx = 1644, + c_spz013pa_2_sfx = 1645, + c_spz013pa_3_sfx = 1646, + c_spz013pa_Anim = 1647, + c_spz008ma_Wav_579 = 1648, + c_spz008ma_Pho_579 = 1649, + c_spz008ma_0_sfx = 1650, + c_spz008ma_Anim = 1651, + c_spz014pa_Wav_580 = 1652, + c_spz014pa_Pho_580 = 1653, + c_spz014pa_0_sfx = 1654, + c_spz014pa_Anim = 1655, + c_spz009ma_Wav_581 = 1656, + c_spz009ma_Pho_581 = 1657, + c_spz009ma_0_sfx = 1658, + c_spz009ma_1_sfx = 1659, + c_spz009ma_2_sfx = 1660, + c_spz009ma_3_sfx = 1661, + c_spz009ma_4_sfx = 1662, + c_spz009ma_5_sfx = 1663, + c_spz009ma_6_sfx = 1664, + c_spz009ma_Anim = 1665, + c_spz015pa_Wav_582 = 1666, + c_spz015pa_Pho_582 = 1667, + c_spz015pa_0_sfx = 1668, + c_spz015pa_1_sfx = 1669, + c_spz015pa_2_sfx = 1670, + c_spz015pa_Anim = 1671, + c_spz007pa_Wav_583 = 1672, + c_spz007pa_Pho_583 = 1673, + c_spz007pa_0_sfx = 1674, + c_spz007pa_1_sfx = 1675, + c_spz007pa_2_sfx = 1676, + c_spz007pa_Anim = 1677, + c_SPZ011PE_Wav_584 = 1678, + c_SPZ011PE_Pho_584 = 1679, + c_spz011pe_0_sfx = 1680, + c_spz011pe_1_sfx = 1681, + c_spz011pe_Anim = 1682, + c_spz008pa_Wav_585 = 1683, + c_spz008pa_Pho_585 = 1684, + c_spz008pa_0_sfx = 1685, + c_spz008pa_1_sfx = 1686, + c_spz008pa_Anim = 1687, + c_spz009pa_Wav_586 = 1688, + c_spz009pa_Pho_586 = 1689, + c_spz009pa_0_sfx = 1690, + c_spz009pa_1_sfx = 1691, + c_spz009pa_2_sfx = 1692, + c_spz009pa_3_sfx = 1693, + c_spz009pa_Anim = 1694, + c_spz010ma_Wav_587 = 1695, + c_spz010ma_Pho_587 = 1696, + c_spz010ma_0_sfx = 1697, + c_spz010ma_1_sfx = 1698, + c_spz010ma_2_sfx = 1699, + c_spz010ma_3_sfx = 1700, + c_spz010ma_Anim = 1701, + c_spz010pa_Wav_588 = 1702, + c_spz010pa_Pho_588 = 1703, + c_spz010pa_0_sfx = 1704, + c_spz010pa_1_sfx = 1705, + c_spz010pa_2_sfx = 1706, + c_spz010pa_Anim = 1707, + c_spz011ma_Wav_589 = 1708, + c_spz011ma_Pho_589 = 1709, + c_spz011ma_0_sfx = 1710, + c_spz011ma_1_sfx = 1711, + c_spz011ma_2_sfx = 1712, + c_spz011ma_3_sfx = 1713, + c_spz011ma_Anim = 1714, + c_spz011pa_Wav_590 = 1715, + c_spz011pa_Pho_590 = 1716, + c_spz011pa_0_sfx = 1717, + c_spz011pa_1_sfx = 1718, + c_spz011pa_2_sfx = 1719, + c_spz011pa_Anim = 1720, + c_spz012pa_Wav_591 = 1721, + c_spz012pa_Pho_591 = 1722, + c_spz012pa_0_sfx = 1723, + c_spz012pa_1_sfx = 1724, + c_spz012pa_2_sfx = 1725, + c_spz012pa_Anim = 1726, + c_spz001ma_Wav_592 = 1727, + c_spz001ma_Pho_592 = 1728, + c_spz001ma_0_sfx = 1729, + c_spz001ma_Anim = 1730, + c_spz002ma_Wav_593 = 1731, + c_spz002ma_Pho_593 = 1732, + c_spz002ma_0_sfx = 1733, + c_spz002ma_1_sfx = 1734, + c_spz002ma_2_sfx = 1735, + c_spz002ma_3_sfx = 1736, + c_spz002ma_4_sfx = 1737, + c_spz002ma_Anim = 1738, + c_spz003ma_Wav_594 = 1739, + c_spz003ma_Pho_594 = 1740, + c_spz003ma_0_sfx = 1741, + c_spz003ma_1_sfx = 1742, + c_spz003ma_2_sfx = 1743, + c_spz003ma_3_sfx = 1744, + c_spz003ma_Anim = 1745, + c_spz003pa_Wav_595 = 1746, + c_spz003pa_Pho_595 = 1747, + c_spz003pa_0_sfx = 1748, + c_spz003pa_1_sfx = 1749, + c_spz003pa_2_sfx = 1750, + c_spz003pa_3_sfx = 1751, + c_spz003pa_4_sfx = 1752, + c_spz003pa_5_sfx = 1753, + c_spz003pa_Anim = 1754, + c_FPZ167P2_Wav_596 = 1755, + c_FPZ166P1_Wav_596 = 1756, + c_fpz166p1_Anim = 1757, + c_FPZ172RD_Wav_597 = 1758, + c_FPZ172RD_Pho_597 = 1759, + c_FPZ177PG_Wav_597 = 1760, + c_FPZ177PG_Pho_597 = 1761, + c_FPZ176RD_Wav_597 = 1762, + c_FPZ176RD_Pho_597 = 1763, + c_FPZ175SY_Wav_597 = 1764, + c_FPZ175SY_Pho_597 = 1765, + c_FPZ174BD_Wav_597 = 1766, + c_FPZ174BD_Pho_597 = 1767, + c_FPZ173PG_Wav_597 = 1768, + c_FPZ173PG_Pho_597 = 1769, + c_fpz172rd_0_sfx = 1770, + c_fpz172rd_1_sfx = 1771, + c_fpz172rd_2_sfx = 1772, + c_fpz172rd_3_sfx = 1773, + c_fpz172rd_4_sfx = 1774, + c_fpz172rd_5_sfx = 1775, + c_fpz172rd_6_sfx = 1776, + c_fpz172rd_7_sfx = 1777, + c_fpz172rd_Anim = 1778, + c_spz001pa_Wav_598 = 1779, + c_spz001pa_Pho_598 = 1780, + c_spz001pa_0_sfx = 1781, + c_spz001pa_1_sfx = 1782, + c_spz001pa_2_sfx = 1783, + c_spz001pa_Anim = 1784, + c_spz002pa_Wav_599 = 1785, + c_spz002pa_Pho_599 = 1786, + c_spz002pa_0_sfx = 1787, + c_spz002pa_1_sfx = 1788, + c_spz002pa_2_sfx = 1789, + c_spz002pa_Anim = 1790, + c_ppz086bs_0_sfx = 1791, + c_ppz086bs_1_sfx = 1792, + c_ppz086bs_2_sfx = 1793, + c_ppz086bs_Anim = 1794, + c_ppz008rd_0_sfx = 1795, + c_ppz008rd_1_sfx = 1796, + c_ppz008rd_2_sfx = 1797, + c_ppz008rd_3_sfx = 1798, + c_ppz008rd_4_sfx = 1799, + c_ppz008rd_Anim = 1800, + c_ppz009pg_0_sfx = 1801, + c_ppz009pg_1_sfx = 1802, + c_ppz009pg_2_sfx = 1803, + c_ppz009pg_3_sfx = 1804, + c_ppz009pg_Anim = 1805, + c_avo918in_Wav_603 = 1806, + c_avo918in_Pho_603 = 1807, + c_ivo918in_0_sfx = 1808, + c_ivo918in_1_sfx = 1809, + c_ivo918in_2_sfx = 1810, + c_ivo918in_3_sfx = 1811, + c_ivo918in_4_sfx = 1812, + c_ivo918in_5_sfx = 1813, + c_ivo918in_6_sfx = 1814, + c_ivo918in_7_sfx = 1815, + c_ivo918in_8_sfx = 1816, + c_ivo918in_9_sfx = 1817, + c_ivo918in_10_sfx = 1818, + c_ivo918in_Anim = 1819, + c_SPZ004PE_Wav_604 = 1820, + c_SPZ004PE_Pho_604 = 1821, + c_spz004pe_0_sfx = 1822, + c_spz004pe_1_sfx = 1823, + c_spz004pe_2_sfx = 1824, + c_spz004pe_Anim = 1825, + c_SPZ005PE_Wav_605 = 1826, + c_SPZ005PE_Pho_605 = 1827, + c_spz005pe_0_sfx = 1828, + c_spz005pe_1_sfx = 1829, + c_spz005pe_2_sfx = 1830, + c_spz005pe_Anim = 1831, + c_SRP006PE_Wav_606 = 1832, + c_SRP006PE_Pho_606 = 1833, + c_srp006pe_0_sfx = 1834, + c_srp006pe_1_sfx = 1835, + c_srp006pe_2_sfx = 1836, + c_srp006pe_3_sfx = 1837, + c_srp006pe_4_sfx = 1838, + c_srp006pe_5_sfx = 1839, + c_srp006pe_Anim = 1840, + c_SPZ013PE_Wav_607 = 1841, + c_SPZ013PE_Pho_607 = 1842, + c_spz013pe_0_sfx = 1843, + c_spz013pe_1_sfx = 1844, + c_spz013pe_2_sfx = 1845, + c_spz013pe_3_sfx = 1846, + c_spz013pe_4_sfx = 1847, + c_spz013pe_5_sfx = 1848, + c_spz013pe_Anim = 1849, + c_sns001pe_Wav_608 = 1850, + c_sns001pe_Pho_608 = 1851, + c_sns001pe_0_sfx = 1852, + c_sns001pe_1_sfx = 1853, + c_sns001pe_2_sfx = 1854, + c_sns001pe_Anim = 1855, + c_FRA193PE_Wav_609 = 1856, + c_FRA193PE_Pho_609 = 1857, + c_FRA194PE_Wav_609 = 1858, + c_FRA194PE_Pho_609 = 1859, + c_FRA192PE_Wav_609 = 1860, + c_FRA192PE_Pho_609 = 1861, + c_fra192pe_0_sfx = 1862, + c_fra192pe_1_sfx = 1863, + c_fra192pe_2_sfx = 1864, + c_fra192pe_3_sfx = 1865, + c_fra192pe_4_sfx = 1866, + c_fra192pe_5_sfx = 1867, + c_fra192pe_6_sfx = 1868, + c_fra192pe_7_sfx = 1869, + c_fra192pe_8_sfx = 1870, + c_fra192pe_9_sfx = 1871, + c_fra192pe_10_sfx = 1872, + c_fra192pe_11_sfx = 1873, + c_fra192pe_12_sfx = 1874, + c_fra192pe_13_sfx = 1875, + c_fra192pe_14_sfx = 1876, + c_fra192pe_15_sfx = 1877, + c_fra192pe_16_sfx = 1878, + c_fra192pe_17_sfx = 1879, + c_fra192pe_18_sfx = 1880, + c_fra192pe_19_sfx = 1881, + c_fra192pe_20_sfx = 1882, + c_fra192pe_21_sfx = 1883, + c_fra192pe_22_sfx = 1884, + c_fra192pe_Anim = 1885, + c_FRA164MG_Wav_610 = 1886, + c_FRA164MG_Pho_610 = 1887, + c_FRA165MG_Wav_610 = 1888, + c_FRA165MG_Pho_610 = 1889, + c_FRA163MG_Wav_610 = 1890, + c_FRA163MG_Pho_610 = 1891, + c_fra163mg_0_sfx = 1892, + c_fra163mg_1_sfx = 1893, + c_fra163mg_2_sfx = 1894, + c_fra163mg_3_sfx = 1895, + c_fra163mg_4_sfx = 1896, + c_fra163mg_Anim = 1897, + c_FNS188GD_Wav_611 = 1898, + c_FNS188GD_Pho_611 = 1899, + c_FNS187GD_Wav_611 = 1900, + c_FNS187GD_Pho_611 = 1901, + c_FNS186GD_Wav_611 = 1902, + c_FNS186GD_Pho_611 = 1903, + c_FNS185GD_Wav_611 = 1904, + c_FNS185GD_Pho_611 = 1905, + c_fns185gd_0_sfx = 1906, + c_fns185gd_1_sfx = 1907, + c_fns185gd_2_sfx = 1908, + c_fns185gd_3_sfx = 1909, + c_fns185gd_4_sfx = 1910, + c_fns185gd_5_sfx = 1911, + c_fns185gd_6_sfx = 1912, + c_fns185gd_7_sfx = 1913, + c_fns185gd_8_sfx = 1914, + c_fns185gd_9_sfx = 1915, + c_fns185gd_10_sfx = 1916, + c_fns185gd_11_sfx = 1917, + c_fns185gd_12_sfx = 1918, + c_fns185gd_13_sfx = 1919, + c_fns185gd_14_sfx = 1920, + c_fns185gd_15_sfx = 1921, + c_fns185gd_16_sfx = 1922, + c_fns185gd_Anim = 1923, + c_IRT001IN_Wav_612 = 1924, + c_IRT001IN_Pho_612 = 1925, + c_irt001in_0_sfx = 1926, + c_irt001in_1_sfx = 1927, + c_irt001in_2_sfx = 1928, + c_irt001in_3_sfx = 1929, + c_irt001in_4_sfx = 1930, + c_irt001in_5_sfx = 1931, + c_irt001in_6_sfx = 1932, + c_irt001in_7_sfx = 1933, + c_irt001in_8_sfx = 1934, + c_irt001in_Anim = 1935, + c_IRT006SL_Wav_613 = 1936, + c_IRT006SL_Pho_613 = 1937, + c_IRT005SL_Wav_613 = 1938, + c_IRT005SL_Pho_613 = 1939, + c_IRT004SL_Wav_613 = 1940, + c_IRT004SL_Pho_613 = 1941, + c_IRT003SL_Wav_613 = 1942, + c_IRT003SL_Pho_613 = 1943, + c_irtx01sl_0_sfx = 1944, + c_irtx01sl_1_sfx = 1945, + c_irtx01sl_2_sfx = 1946, + c_irtx01sl_3_sfx = 1947, + c_irtx01sl_4_sfx = 1948, + c_irtx01sl_5_sfx = 1949, + c_irtx01sl_6_sfx = 1950, + c_irtx01sl_7_sfx = 1951, + c_irtx01sl_8_sfx = 1952, + c_irtx01sl_Anim = 1953, + c_FRT135DF_Wav_614 = 1954, + c_FRT135DF_Pho_614 = 1955, + c_FRT136GN_Wav_614 = 1956, + c_FRT136GN_Pho_614 = 1957, + c_frt135df_0_sfx = 1958, + c_frt135df_1_sfx = 1959, + c_frt135df_2_sfx = 1960, + c_frt135df_3_sfx = 1961, + c_frt135df_4_sfx = 1962, + c_frt135df_5_sfx = 1963, + c_frt135df_6_sfx = 1964, + c_frt135df_7_sfx = 1965, + c_frt135df_8_sfx = 1966, + c_frt135df_9_sfx = 1967, + c_frt135df_Anim = 1968, + c_FRt138Gn_Wav_615 = 1969, + c_FRt138Gn_Pho_615 = 1970, + c_FRt137DF_Wav_615 = 1971, + c_FRt137DF_Pho_615 = 1972, + c_frt137df_0_sfx = 1973, + c_frt137df_1_sfx = 1974, + c_frt137df_2_sfx = 1975, + c_frt137df_3_sfx = 1976, + c_frt137df_4_sfx = 1977, + c_frt137df_5_sfx = 1978, + c_frt137df_6_sfx = 1979, + c_frt137df_7_sfx = 1980, + c_frt137df_8_sfx = 1981, + c_frt137df_9_sfx = 1982, + c_frt137df_10_sfx = 1983, + c_frt137df_11_sfx = 1984, + c_frt137df_12_sfx = 1985, + c_frt137df_13_sfx = 1986, + c_frt137df_14_sfx = 1987, + c_frt137df_15_sfx = 1988, + c_frt137df_16_sfx = 1989, + c_frt137df_Anim = 1990, + c_FRt140Gn_Wav_616 = 1991, + c_FRt140Gn_Pho_616 = 1992, + c_FRt139DF_Wav_616 = 1993, + c_FRt139DF_Pho_616 = 1994, + c_frt139df_0_sfx = 1995, + c_frt139df_1_sfx = 1996, + c_frt139df_2_sfx = 1997, + c_frt139df_3_sfx = 1998, + c_frt139df_4_sfx = 1999, + c_frt139df_5_sfx = 2000, + c_frt139df_6_sfx = 2001, + c_frt139df_7_sfx = 2002, + c_frt139df_8_sfx = 2003, + c_frt139df_9_sfx = 2004, + c_frt139df_10_sfx = 2005 +}; + +#if __cplusplus >= 201103L +enum Script2 : int { +#else +enum Script2 { +#endif + c_frt139df_11_sfx = 2006, + c_frt139df_12_sfx = 2007, + c_frt139df_13_sfx = 2008, + c_frt139df_Anim = 2009, + c_FRT031NI_Wav_617 = 2010, + c_FRT031NI_Pho_617 = 2011, + c_FRT029SY_Wav_617 = 2012, + c_FRT029SY_Pho_617 = 2013, + c_FRT030SY_Wav_617 = 2014, + c_FRT030SY_Pho_617 = 2015, + c_FRT028SY_Wav_617 = 2016, + c_FRT028SY_Pho_617 = 2017, + c_FRT027BD_Wav_617 = 2018, + c_FRT027BD_Pho_617 = 2019, + c_FRT026PG_Wav_617 = 2020, + c_FRT026PG_Pho_617 = 2021, + c_FRT025RD_Wav_617 = 2022, + c_FRT025RD_Pho_617 = 2023, + c_frt025rd_0_sfx = 2024, + c_frt025rd_1_sfx = 2025, + c_frt025rd_2_sfx = 2026, + c_frt025rd_3_sfx = 2027, + c_frt025rd_4_sfx = 2028, + c_frt025rd_5_sfx = 2029, + c_frt025rd_6_sfx = 2030, + c_frt025rd_7_sfx = 2031, + c_frt025rd_8_sfx = 2032, + c_frt025rd_9_sfx = 2033, + c_frt025rd_10_sfx = 2034, + c_frt025rd_11_sfx = 2035, + c_frt025rd_12_sfx = 2036, + c_frt025rd_13_sfx = 2037, + c_frt025rd_14_sfx = 2038, + c_frt025rd_15_sfx = 2039, + c_frt025rd_Anim = 2040, + c_FRT134NI_Wav_618 = 2041, + c_FRT134NI_Pho_618 = 2042, + c_FRT133PG_Wav_618 = 2043, + c_FRT133PG_Pho_618 = 2044, + c_FRT132RD_Wav_618 = 2045, + c_FRT132RD_Pho_618 = 2046, + c_frt132rd_0_sfx = 2047, + c_frt132rd_1_sfx = 2048, + c_frt132rd_2_sfx = 2049, + c_frt132rd_3_sfx = 2050, + c_frt132rd_4_sfx = 2051, + c_frt132rd_5_sfx = 2052, + c_frt132rd_6_sfx = 2053, + c_frt132rd_7_sfx = 2054, + c_frt132rd_8_sfx = 2055, + c_frt132rd_9_sfx = 2056, + c_frt132rd_10_sfx = 2057, + c_frt132rd_11_sfx = 2058, + c_frt132rd_12_sfx = 2059, + c_frt132rd_13_sfx = 2060, + c_frt132rd_14_sfx = 2061, + c_frt132rd_Anim = 2062, + c_SRT001RD_Wav_619 = 2063, + c_SRT001RD_Pho_619 = 2064, + c_srt001rd_0_sfx = 2065, + c_srt001rd_1_sfx = 2066, + c_srt001rd_2_sfx = 2067, + c_srt001rd_3_sfx = 2068, + c_srt001rd_4_sfx = 2069, + c_srt001rd_5_sfx = 2070, + c_srt001rd_6_sfx = 2071, + c_srt001rd_7_sfx = 2072, + c_srt001rd_8_sfx = 2073, + c_srt001rd_9_sfx = 2074, + c_srt001rd_10_sfx = 2075, + c_srt001rd_11_sfx = 2076, + c_srt001rd_12_sfx = 2077, + c_srt001rd_13_sfx = 2078, + c_srt001rd_14_sfx = 2079, + c_srt001rd_15_sfx = 2080, + c_srt001rd_Anim = 2081, + c_SRT003BD_Wav_620 = 2082, + c_SRT003BD_Pho_620 = 2083, + c_srt003bd_0_sfx = 2084, + c_srt003bd_1_sfx = 2085, + c_srt003bd_2_sfx = 2086, + c_srt003bd_3_sfx = 2087, + c_srt003bd_4_sfx = 2088, + c_srt003bd_5_sfx = 2089, + c_srt003bd_6_sfx = 2090, + c_srt003bd_Anim = 2091, + c_sst001mg_Wav_621 = 2092, + c_sst001mg_Pho_621 = 2093, + c_sst001mg_0_sfx = 2094, + c_sst001mg_1_sfx = 2095, + c_sst001mg_2_sfx = 2096, + c_sst001mg_Anim = 2097, + c_sns004la_Wav_622 = 2098, + c_sns004la_Pho_622 = 2099, + c_sns004la_Anim = 2100, + c_sns005la_Wav_623 = 2101, + c_sns005la_Pho_623 = 2102, + c_sns005la_0_sfx = 2103, + c_sns005la_1_sfx = 2104, + c_sns005la_Anim = 2105, + c_sns006la_Wav_624 = 2106, + c_sns006la_Pho_624 = 2107, + c_sns006la_0_sfx = 2108, + c_sns006la_1_sfx = 2109, + c_sns006la_Anim = 2110, + c_sps004ni_Wav_625 = 2111, + c_sps004ni_Pho_625 = 2112, + c_sps004ni_0_sfx = 2113, + c_sps004ni_1_sfx = 2114, + c_sps004ni_2_sfx = 2115, + c_sps004ni_Anim = 2116, + c_sps005ni_Wav_626 = 2117, + c_sps005ni_Pho_626 = 2118, + c_sps005ni_0_sfx = 2119, + c_sps005ni_1_sfx = 2120, + c_sps005ni_Anim = 2121, + c_sps006ni_Wav_627 = 2122, + c_sps006ni_Pho_627 = 2123, + c_sps006ni_0_sfx = 2124, + c_sps006ni_Anim = 2125, + c_sns007la_Wav_628 = 2126, + c_sns007la_Pho_628 = 2127, + c_sns007la_0_sfx = 2128, + c_sns007la_1_sfx = 2129, + c_sns007la_2_sfx = 2130, + c_sns007la_Anim = 2131, + c_sns008la_Wav_629 = 2132, + c_sns008la_Pho_629 = 2133, + c_sns008la_0_sfx = 2134, + c_sns008la_1_sfx = 2135, + c_sns008la_2_sfx = 2136, + c_sns008la_3_sfx = 2137, + c_sns008la_Anim = 2138, + c_sns009la_Wav_630 = 2139, + c_sns009la_Pho_630 = 2140, + c_sns009la_0_sfx = 2141, + c_sns009la_1_sfx = 2142, + c_sns009la_Anim = 2143, + c_sns007ni_Wav_631 = 2144, + c_sns007ni_Pho_631 = 2145, + c_sns007ni_0_sfx = 2146, + c_sns007ni_1_sfx = 2147, + c_sns007ni_2_sfx = 2148, + c_sns007ni_Anim = 2149, + c_sns008ni_Wav_632 = 2150, + c_sns008ni_Pho_632 = 2151, + c_sns008ni_0_sfx = 2152, + c_sns008ni_1_sfx = 2153, + c_sns008ni_Anim = 2154, + c_sns009ni_Wav_633 = 2155, + c_sns009ni_Pho_633 = 2156, + c_sns009ni_0_sfx = 2157, + c_sns009ni_1_sfx = 2158, + c_sns009ni_Anim = 2159, + c_pns017ml_Wav_634 = 2160, + c_pns017ml_Pho_634 = 2161, + c_pns017ml_Anim = 2162, + c_sns010la_Wav_635 = 2163, + c_sns010la_Pho_635 = 2164, + c_sns010la_Anim = 2165, + c_sns010pe_Wav_636 = 2166, + c_sns010pe_Pho_636 = 2167, + c_sns010pe_0_sfx = 2168, + c_sns010pe_1_sfx = 2169, + c_sns010pe_2_sfx = 2170, + c_sns010pe_3_sfx = 2171, + c_sns010pe_Anim = 2172, + c_sns011la_Wav_637 = 2173, + c_sns011la_Pho_637 = 2174, + c_sns011la_0_sfx = 2175, + c_sns011la_1_sfx = 2176, + c_sns011la_2_sfx = 2177, + c_sns011la_3_sfx = 2178, + c_sns011la_Anim = 2179, + c_sns012la_Wav_638 = 2180, + c_sns012la_Pho_638 = 2181, + c_sns012la_Anim = 2182, + c_sns007pe_Wav_639 = 2183, + c_sns007pe_Pho_639 = 2184, + c_sns007pe_0_sfx = 2185, + c_sns007pe_1_sfx = 2186, + c_sns007pe_2_sfx = 2187, + c_sns007pe_3_sfx = 2188, + c_sns007pe_Anim = 2189, + c_sns008pe_Wav_640 = 2190, + c_sns008pe_Pho_640 = 2191, + c_sns008pe_0_sfx = 2192, + c_sns008pe_1_sfx = 2193, + c_sns008pe_2_sfx = 2194, + c_sns008pe_Anim = 2195, + c_sns013la_Wav_641 = 2196, + c_sns013la_Pho_641 = 2197, + c_sns013la_0_sfx = 2198, + c_sns013la_1_sfx = 2199, + c_sns013la_Anim = 2200, + c_sns013ni_Wav_642 = 2201, + c_sns013ni_Pho_642 = 2202, + c_sns013ni_Anim = 2203, + c_sns014la_Wav_643 = 2204, + c_sns014la_Pho_643 = 2205, + c_sns014la_0_sfx = 2206, + c_sns014la_Anim = 2207, + c_sns014ni_Wav_644 = 2208, + c_sns014ni_Pho_644 = 2209, + c_sns014ni_0_sfx = 2210, + c_sns014ni_1_sfx = 2211, + c_sns014ni_2_sfx = 2212, + c_sns014ni_3_sfx = 2213, + c_sns014ni_Anim = 2214, + c_sns015la_Wav_645 = 2215, + c_sns015la_Pho_645 = 2216, + c_sns015la_0_sfx = 2217, + c_sns015la_1_sfx = 2218, + c_sns015la_2_sfx = 2219, + c_sns015la_Anim = 2220, + c_sns015ni_Wav_646 = 2221, + c_sns015ni_Pho_646 = 2222, + c_sns015ni_0_sfx = 2223, + c_sns015ni_1_sfx = 2224, + c_sns015ni_Anim = 2225, + c_sns011ni_Wav_647 = 2226, + c_sns011ni_Pho_647 = 2227, + c_sns011ni_0_sfx = 2228, + c_sns011ni_1_sfx = 2229, + c_sns011ni_Anim = 2230, + c_sns012ni_Wav_648 = 2231, + c_sns012ni_Pho_648 = 2232, + c_sns012ni_Anim = 2233, + c_sns014pe_Wav_649 = 2234, + c_sns014pe_Pho_649 = 2235, + c_sns014pe_0_sfx = 2236, + c_sns014pe_1_sfx = 2237, + c_sns014pe_Anim = 2238, + c_sns015pe_Wav_650 = 2239, + c_sns015pe_Pho_650 = 2240, + c_sns015pe_0_sfx = 2241, + c_sns015pe_1_sfx = 2242, + c_sns015pe_2_sfx = 2243, + c_sns015pe_3_sfx = 2244, + c_sns015pe_Anim = 2245, + c_sns003pe_Wav_651 = 2246, + c_sns003pe_Pho_651 = 2247, + c_sns003pe_0_sfx = 2248, + c_sns003pe_1_sfx = 2249, + c_sns003pe_2_sfx = 2250, + c_sns003pe_3_sfx = 2251, + c_sns003pe_Anim = 2252, + c_sns017ni_Wav_652 = 2253, + c_sns017ni_Pho_652 = 2254, + c_sns017ni_0_sfx = 2255, + c_sns017ni_1_sfx = 2256, + c_sns017ni_2_sfx = 2257, + c_sns017ni_3_sfx = 2258, + c_sns017ni_Anim = 2259, + c_sps001ni_Wav_653 = 2260, + c_sps001ni_Pho_653 = 2261, + c_sps001ni_Anim = 2262, + c_sps002ni_Wav_654 = 2263, + c_sps002ni_Pho_654 = 2264, + c_sps002ni_0_sfx = 2265, + c_sps002ni_1_sfx = 2266, + c_sps002ni_2_sfx = 2267, + c_sps002ni_Anim = 2268, + c_sps003ni_Wav_655 = 2269, + c_sps003ni_Pho_655 = 2270, + c_sps003ni_0_sfx = 2271, + c_sps003ni_1_sfx = 2272, + c_sps003ni_Anim = 2273, + c_sns017la_Wav_656 = 2274, + c_sns017la_Pho_656 = 2275, + c_sns017la_0_sfx = 2276, + c_sns017la_1_sfx = 2277, + c_sns017la_Anim = 2278, + c_sps001la_Wav_657 = 2279, + c_sps001la_Pho_657 = 2280, + c_sps001la_0_sfx = 2281, + c_sps001la_Anim = 2282, + c_sps002la_Wav_658 = 2283, + c_sps002la_Pho_658 = 2284, + c_sps002la_Anim = 2285, + c_bns005pg_0_sfx = 2286, + c_bns005pg_1_sfx = 2287, + c_bns005pg_2_sfx = 2288, + c_bns005pg_3_sfx = 2289, + c_bns005pg_Anim = 2290, + c_sns001ml_Wav_660 = 2291, + c_sns001ml_Pho_660 = 2292, + c_sns001ml_0_sfx = 2293, + c_sns001ml_1_sfx = 2294, + c_sns001ml_2_sfx = 2295, + c_sns001ml_Anim = 2296, + c_sns002mg_Wav_661 = 2297, + c_sns002mg_Pho_661 = 2298, + c_sns002mg_0_sfx = 2299, + c_sns002mg_1_sfx = 2300, + c_sns002mg_2_sfx = 2301, + c_sns002mg_3_sfx = 2302, + c_sns002mg_4_sfx = 2303, + c_sns002mg_5_sfx = 2304, + c_sns002mg_6_sfx = 2305, + c_sns002mg_7_sfx = 2306, + c_sns002mg_Anim = 2307, + c_sns002ml_Wav_662 = 2308, + c_sns002ml_Pho_662 = 2309, + c_sns002ml_0_sfx = 2310, + c_sns002ml_1_sfx = 2311, + c_sns002ml_Anim = 2312, + c_sns002pe_Wav_663 = 2313, + c_sns002pe_Pho_663 = 2314, + c_sns002pe_0_sfx = 2315, + c_sns002pe_1_sfx = 2316, + c_sns002pe_Anim = 2317, + c_sns003mg_Wav_664 = 2318, + c_sns003mg_Pho_664 = 2319, + c_sns003mg_0_sfx = 2320, + c_sns003mg_1_sfx = 2321, + c_sns003mg_Anim = 2322, + c_sns004mg_Wav_665 = 2323, + c_sns004mg_Pho_665 = 2324, + c_sns004mg_0_sfx = 2325, + c_sns004mg_1_sfx = 2326, + c_sns004mg_2_sfx = 2327, + c_sns004mg_3_sfx = 2328, + c_sns004mg_Anim = 2329, + c_sns004rd_Wav_666 = 2330, + c_sns004rd_Pho_666 = 2331, + c_sns004rd_0_sfx = 2332, + c_sns004rd_1_sfx = 2333, + c_sns004rd_Anim = 2334, + c_sns006bd_Wav_667 = 2335, + c_sns006bd_Pho_667 = 2336, + c_sns006bd_0_sfx = 2337, + c_sns006bd_1_sfx = 2338, + c_sns006bd_2_sfx = 2339, + c_sns006bd_Anim = 2340, + c_sns006ro_Wav_668 = 2341, + c_sns006ro_Pho_668 = 2342, + c_sns006ro_0_sfx = 2343, + c_sns006ro_1_sfx = 2344, + c_sns006ro_Anim = 2345, + c_sns011in_Wav_669 = 2346, + c_sns011in_Pho_669 = 2347, + c_sns011in_0_sfx = 2348, + c_sns011in_1_sfx = 2349, + c_sns011in_2_sfx = 2350, + c_sns011in_Anim = 2351, + c_sps001ro_Wav_670 = 2352, + c_sps001ro_Pho_670 = 2353, + c_sps001ro_0_sfx = 2354, + c_sps001ro_1_sfx = 2355, + c_sps001ro_2_sfx = 2356, + c_sps001ro_Anim = 2357, + c_sps002ro_Wav_671 = 2358, + c_sps002ro_Pho_671 = 2359, + c_sps002ro_0_sfx = 2360, + c_sps002ro_1_sfx = 2361, + c_sps002ro_Anim = 2362, + c_SPS003RO_Wav_672 = 2363, + c_SPS003RO_Pho_672 = 2364, + c_sps003ro_0_sfx = 2365, + c_sps003ro_1_sfx = 2366, + c_sps003ro_Anim = 2367, + c_SPS004RO_Wav_673 = 2368, + c_SPS004RO_Pho_673 = 2369, + c_sps004ro_Anim = 2370, + c_SRT005PG_Wav_674 = 2371, + c_SRT005PG_Pho_674 = 2372, + c_srt005pg_0_sfx = 2373, + c_srt005pg_Anim = 2374, + c_pns100ml_0_sfx = 2375, + c_pns100ml_1_sfx = 2376, + c_pns100ml_2_sfx = 2377, + c_pns100ml_Anim = 2378, + c_PPZ029RD_Wav_676 = 2379, + c_PPZ029RD_Pho_676 = 2380, + c_ppz029rd_0_sfx = 2381, + c_ppz029rd_1_sfx = 2382, + c_ppz029rd_Anim = 2383, + c_sns007sy_Wav_677 = 2384, + c_sns007sy_Pho_677 = 2385, + c_sns007sy_0_sfx = 2386, + c_sns007sy_Anim = 2387, + c_cnsx12la_Anim = 2388, + c_cnsx12ni_Anim = 2389, + c_IJS006SN_Wav_680 = 2390, + c_IJS006SN_Pho_680 = 2391, + c_ijs006sn_0_sfx = 2392, + c_ijs006sn_1_sfx = 2393, + c_ijs006sn_2_sfx = 2394, + c_ijs006sn_3_sfx = 2395, + c_ijs006sn_4_sfx = 2396, + c_ijs006sn_5_sfx = 2397, + c_ijs006sn_6_sfx = 2398, + c_ijs006sn_7_sfx = 2399, + c_ijs006sn_8_sfx = 2400, + c_ijs006sn_9_sfx = 2401, + c_ijs006sn_Anim = 2402, + c_IGS008NA_Wav_681 = 2403, + c_IGS008NA_Pho_681 = 2404, + c_igs008na_0_sfx = 2405, + c_igs008na_1_sfx = 2406, + c_igs008na_Anim = 2407, + c_irt007in_Wav_682 = 2408, + c_irt007in_Pho_682 = 2409, + c_irt007in_0_sfx = 2410, + c_irt007in_1_sfx = 2411, + c_irt007in_2_sfx = 2412, + c_irt007in_3_sfx = 2413, + c_irt007in_4_sfx = 2414, + c_irt007in_5_sfx = 2415, + c_irt007in_Anim = 2416, + c_IPS002RO_Wav_683 = 2417, + c_IPS002RO_Pho_683 = 2418, + c_ips002ro_0_sfx = 2419, + c_ips002ro_1_sfx = 2420, + c_ips002ro_2_sfx = 2421, + c_ips002ro_3_sfx = 2422, + c_ips002ro_Anim = 2423, + c_hho142cl_Wav_684 = 2424, + c_hho142cl_Pho_684 = 2425, + c_hho141cl_Wav_684 = 2426, + c_hho141cl_Pho_684 = 2427, + c_hho142cl_0_sfx = 2428, + c_hho142cl_1_sfx = 2429, + c_hho142cl_2_sfx = 2430, + c_hho142cl_3_sfx = 2431, + c_hho142cl_4_sfx = 2432, + c_hho142cl_5_sfx = 2433, + c_hho142cl_6_sfx = 2434, + c_hho142cl_7_sfx = 2435, + c_hho142cl_8_sfx = 2436, + c_hho142cl_9_sfx = 2437, + c_hho142cl_10_sfx = 2438, + c_hho142cl_11_sfx = 2439, + c_hho142cl_12_sfx = 2440, + c_hho142cl_13_sfx = 2441, + c_hho142cl_14_sfx = 2442, + c_hho142cl_15_sfx = 2443, + c_hho142cl_Anim = 2444, + c_hho143cl_Wav_685 = 2445, + c_hho143cl_Pho_685 = 2446, + c_hho141cl_Wav_685 = 2447, + c_hho141cl_Pho_685 = 2448, + c_hho143cl_0_sfx = 2449, + c_hho143cl_1_sfx = 2450, + c_hho143cl_2_sfx = 2451, + c_hho143cl_3_sfx = 2452, + c_hho143cl_4_sfx = 2453, + c_hho143cl_5_sfx = 2454, + c_hho143cl_6_sfx = 2455, + c_hho143cl_7_sfx = 2456, + c_hho143cl_8_sfx = 2457, + c_hho143cl_9_sfx = 2458, + c_hho143cl_10_sfx = 2459, + c_hho143cl_11_sfx = 2460, + c_hho143cl_12_sfx = 2461, + c_hho143cl_Anim = 2462, + c_hho144cl_Wav_686 = 2463, + c_hho144cl_Pho_686 = 2464, + c_hho141cl_Wav_686 = 2465, + c_hho141cl_Pho_686 = 2466, + c_hho144cl_0_sfx = 2467, + c_hho144cl_1_sfx = 2468, + c_hho144cl_2_sfx = 2469, + c_hho144cl_3_sfx = 2470, + c_hho144cl_4_sfx = 2471, + c_hho144cl_5_sfx = 2472, + c_hho144cl_6_sfx = 2473, + c_hho144cl_7_sfx = 2474, + c_hho144cl_8_sfx = 2475, + c_hho144cl_9_sfx = 2476, + c_hho144cl_10_sfx = 2477, + c_hho144cl_Anim = 2478, + c_hho032re_Wav_687 = 2479, + c_hho032re_Pho_687 = 2480, + c_hho031en_Wav_687 = 2481, + c_hho031en_Pho_687 = 2482, + c_hho030re_Wav_687 = 2483, + c_hho030re_Pho_687 = 2484, + c_hho029en_Wav_687 = 2485, + c_hho029en_Pho_687 = 2486, + c_hho028re_Wav_687 = 2487, + c_hho028re_Pho_687 = 2488, + c_hho027en_Wav_687 = 2489, + c_hho027en_Pho_687 = 2490, + c_hho027en_0_sfx = 2491, + c_hho027en_1_sfx = 2492, + c_hho027en_2_sfx = 2493, + c_hho027en_3_sfx = 2494, + c_hho027en_4_sfx = 2495, + c_hho027en_5_sfx = 2496, + c_hho027en_6_sfx = 2497, + c_hho027en_7_sfx = 2498, + c_hho027en_8_sfx = 2499, + c_hho027en_9_sfx = 2500, + c_hho027en_10_sfx = 2501, + c_hho027en_11_sfx = 2502, + c_hho027en_12_sfx = 2503, + c_hho027en_13_sfx = 2504, + c_hho027en_14_sfx = 2505, + c_hho027en_15_sfx = 2506, + c_hho027en_16_sfx = 2507, + c_hho027en_17_sfx = 2508, + c_hho027en_18_sfx = 2509, + c_hho027en_19_sfx = 2510, + c_hho027en_20_sfx = 2511, + c_hho027en_21_sfx = 2512, + c_hho027en_22_sfx = 2513, + c_hho027en_23_sfx = 2514, + c_hho027en_24_sfx = 2515, + c_hho027en_Anim = 2516, + c_HPS126EN_Wav_688 = 2517, + c_HPS126EN_Pho_688 = 2518, + c_HPS120BD_Wav_688 = 2519, + c_HPS120BD_Pho_688 = 2520, + c_HPS119BD_Wav_688 = 2521, + c_HPS119BD_Pho_688 = 2522, + c_HPS118BD_Wav_688 = 2523, + c_HPS118BD_Pho_688 = 2524, + c_HPS116JK_Wav_688 = 2525, + c_HPS116JK_Pho_688 = 2526, + c_HPS127RE_Wav_688 = 2527, + c_HPS127RE_Pho_688 = 2528, + c_HPS117BD_Wav_688 = 2529, + c_HPS117BD_Pho_688 = 2530, + c_hps116bd_0_sfx = 2531, + c_hps116bd_1_sfx = 2532, + c_hps116bd_2_sfx = 2533, + c_hps116bd_3_sfx = 2534, + c_hps116bd_4_sfx = 2535, + c_hps116bd_5_sfx = 2536, + c_hps116bd_6_sfx = 2537, + c_hps116bd_7_sfx = 2538, + c_hps116bd_8_sfx = 2539, + c_hps116bd_9_sfx = 2540, + c_hps116bd_Anim = 2541, + c_HPS117BD_Wav_689 = 2542, + c_HPS117BD_Pho_689 = 2543, + c_HPS120BD_Wav_689 = 2544, + c_HPS120BD_Pho_689 = 2545, + c_HPS119BD_Wav_689 = 2546, + c_HPS119BD_Pho_689 = 2547, + c_HPS118BD_Wav_689 = 2548, + c_HPS118BD_Pho_689 = 2549, + c_hps117bd_0_sfx = 2550, + c_hps117bd_1_sfx = 2551, + c_hps117bd_2_sfx = 2552, + c_hps117bd_3_sfx = 2553, + c_hps117bd_4_sfx = 2554, + c_hps117bd_5_sfx = 2555, + c_hps117bd_Anim = 2556, + c_HPS117BD_Wav_690 = 2557, + c_HPS117BD_Pho_690 = 2558, + c_HPS120BD_Wav_690 = 2559, + c_HPS120BD_Pho_690 = 2560, + c_HPS119BD_Wav_690 = 2561, + c_HPS119BD_Pho_690 = 2562, + c_HPS118BD_Wav_690 = 2563, + c_HPS118BD_Pho_690 = 2564, + c_HPS127RE_Wav_690 = 2565, + c_HPS127RE_Pho_690 = 2566, + c_HPS119EN_Wav_690 = 2567, + c_HPS119EN_Pho_690 = 2568, + c_HPS118RE_Wav_690 = 2569, + c_HPS118RE_Pho_690 = 2570, + c_HPS126EN_Wav_690 = 2571, + c_HPS126EN_Pho_690 = 2572, + c_hps118re_0_sfx = 2573, + c_hps118re_1_sfx = 2574, + c_hps118re_2_sfx = 2575, + c_hps118re_3_sfx = 2576, + c_hps118re_4_sfx = 2577, + c_hps118re_5_sfx = 2578, + c_hps118re_6_sfx = 2579, + c_hps118re_7_sfx = 2580, + c_hps118re_8_sfx = 2581, + c_hps118re_Anim = 2582, + c_HPS117BD_Wav_691 = 2583, + c_HPS117BD_Pho_691 = 2584, + c_HPS120BD_Wav_691 = 2585, + c_HPS120BD_Pho_691 = 2586, + c_HPS119BD_Wav_691 = 2587, + c_HPS119BD_Pho_691 = 2588, + c_HPS118BD_Wav_691 = 2589, + c_HPS118BD_Pho_691 = 2590, + c_HPS129RE_Wav_691 = 2591, + c_HPS129RE_Pho_691 = 2592, + c_HPS121RE_Wav_691 = 2593, + c_HPS121RE_Pho_691 = 2594, + c_HPS120EN_Wav_691 = 2595, + c_HPS120EN_Pho_691 = 2596, + c_HPS128EN_Wav_691 = 2597, + c_HPS128EN_Pho_691 = 2598, + c_hps120en_0_sfx = 2599, + c_hps120en_1_sfx = 2600, + c_hps120en_2_sfx = 2601, + c_hps120en_3_sfx = 2602, + c_hps120en_4_sfx = 2603, + c_hps120en_5_sfx = 2604, + c_hps120en_6_sfx = 2605, + c_hps120en_7_sfx = 2606, + c_hps120en_8_sfx = 2607, + c_hps120en_Anim = 2608, + c_HPS133RE_Wav_692 = 2609, + c_HPS133RE_Pho_692 = 2610, + c_HPS132RE_Wav_692 = 2611, + c_HPS132RE_Pho_692 = 2612, + c_HPS125EN_Wav_692 = 2613, + c_HPS125EN_Pho_692 = 2614, + c_HPS124RE_Wav_692 = 2615, + c_HPS124RE_Pho_692 = 2616, + c_HPS124EN_Wav_692 = 2617, + c_HPS124EN_Pho_692 = 2618, + c_HPS117BD_Wav_692 = 2619, + c_HPS117BD_Pho_692 = 2620, + c_HPS120BD_Wav_692 = 2621, + c_HPS120BD_Pho_692 = 2622, + c_HPS119BD_Wav_692 = 2623, + c_HPS119BD_Pho_692 = 2624, + c_HPS118BD_Wav_692 = 2625, + c_HPS118BD_Pho_692 = 2626, + c_HPS131RE_Wav_692 = 2627, + c_HPS131RE_Pho_692 = 2628, + c_HPS123RE_Wav_692 = 2629, + c_HPS123RE_Pho_692 = 2630, + c_HPS122EN_Wav_692 = 2631, + c_HPS122EN_Pho_692 = 2632, + c_HPS130EN_Wav_692 = 2633, + c_HPS130EN_Pho_692 = 2634, + c_hps122en_0_sfx = 2635, + c_hps122en_1_sfx = 2636, + c_hps122en_2_sfx = 2637, + c_hps122en_3_sfx = 2638, + c_hps122en_Anim = 2639, + c_HPZ050BD_Wav_693 = 2640, + c_HPZ050BD_Pho_693 = 2641, + c_HPZ047PE_Wav_693 = 2642, + c_HPZ047PE_Pho_693 = 2643, + c_HPZ051GD_Wav_693 = 2644, + c_HPZ051GD_Pho_693 = 2645, + c_hpz047pe_0_sfx = 2646, + c_hpz047pe_1_sfx = 2647, + c_hpz047pe_2_sfx = 2648, + c_hpz047pe_3_sfx = 2649, + c_hpz047pe_Anim = 2650, + c_HPZ050BD_Wav_694 = 2651, + c_HPZ050BD_Pho_694 = 2652, + c_HPZ048PE_Wav_694 = 2653, + c_HPZ048PE_Pho_694 = 2654, + c_HPZ051GD_Wav_694 = 2655, + c_HPZ051GD_Pho_694 = 2656, + c_hpz048pe_0_sfx = 2657, + c_hpz048pe_1_sfx = 2658, + c_hpz048pe_2_sfx = 2659, + c_hpz048pe_3_sfx = 2660, + c_hpz048pe_Anim = 2661, + c_HPZ050BD_Wav_695 = 2662, + c_HPZ050BD_Pho_695 = 2663, + c_HPZ049BD_Wav_695 = 2664, + c_HPZ049BD_Pho_695 = 2665, + c_HPZ051GD_Wav_695 = 2666, + c_HPZ051GD_Pho_695 = 2667, + c_hpz049bd_0_sfx = 2668, + c_hpz049bd_1_sfx = 2669, + c_hpz049bd_2_sfx = 2670, + c_hpz049bd_3_sfx = 2671, + c_hpz049bd_Anim = 2672, + c_HPZ050BD_Wav_696 = 2673, + c_HPZ050BD_Pho_696 = 2674, + c_HPZ047PE_Wav_696 = 2675, + c_HPZ047PE_Pho_696 = 2676, + c_HPZ051GD_Wav_696 = 2677, + c_HPZ051GD_Pho_696 = 2678, + c_hpz050bd_0_sfx = 2679, + c_hpz050bd_1_sfx = 2680, + c_hpz050bd_2_sfx = 2681, + c_hpz050bd_3_sfx = 2682, + c_hpz050bd_Anim = 2683, + c_HPZ052MA_Wav_697 = 2684, + c_HPZ052MA_Pho_697 = 2685, + c_HPZB51GD_Wav_697 = 2686, + c_HPZB51GD_Pho_697 = 2687, + c_hpz052ma_0_sfx = 2688, + c_hpz052ma_1_sfx = 2689, + c_hpz052ma_Anim = 2690, + c_HPZ053PA_Wav_698 = 2691, + c_HPZ053PA_Pho_698 = 2692, + c_HPZB51GD_Wav_698 = 2693, + c_HPZB51GD_Pho_698 = 2694, + c_hpz053pa_0_sfx = 2695, + c_hpz053pa_1_sfx = 2696, + c_hpz053pa_Anim = 2697, + c_HPZ070EN_Wav_699 = 2698, + c_HPZ070EN_Pho_699 = 2699, + c_HPZ074EN_Wav_699 = 2700, + c_HPZ074EN_Pho_699 = 2701, + c_HPZ072EN_Wav_699 = 2702, + c_HPZ072EN_Pho_699 = 2703, + c_HPZ073RE_Wav_699 = 2704, + c_HPZ073RE_Pho_699 = 2705, + c_HPZ071RE_Wav_699 = 2706, + c_HPZ071RE_Pho_699 = 2707, + c_HPZ069RE_Wav_699 = 2708, + c_HPZ069RE_Pho_699 = 2709, + c_HPZ068EN_Wav_699 = 2710, + c_HPZ068EN_Pho_699 = 2711, + c_HPZC63DL_Wav_699 = 2712, + c_HPZD64CA_Wav_699 = 2713, + c_HPZH60DL_Wav_699 = 2714, + c_HPZF60DL_Wav_699 = 2715, + c_HPZE60DL_Wav_699 = 2716, + c_HPZD60DL_Wav_699 = 2717, + c_HPZB60DL_Wav_699 = 2718, + c_HPZ058PA_Wav_699 = 2719, + c_HPZ058PA_Pho_699 = 2720, + c_HPZ066PA_Wav_699 = 2721, + c_HPZ066PA_Pho_699 = 2722, + c_HPZ059SH_Wav_699 = 2723, + c_HPZ057SH_Wav_699 = 2724, + c_HPZ055PA_Wav_699 = 2725, + c_HPZ055PA_Pho_699 = 2726, + c_HPZ067P1_Wav_699 = 2727, + c_HPZB54GD_Wav_699 = 2728, + c_HPZB54GD_Pho_699 = 2729, + c_HPZC54GD_Wav_699 = 2730, + c_HPZC54GD_Pho_699 = 2731, + c_HPZE54GD_Wav_699 = 2732, + c_HPZE54GD_Pho_699 = 2733, + c_HPZF54GD_Wav_699 = 2734, + c_HPZF54GD_Pho_699 = 2735, + c_HPZA54GD_Wav_699 = 2736, + c_HPZA54GD_Pho_699 = 2737, + c_hpz055pa_0_sfx = 2738, + c_hpz055pa_1_sfx = 2739, + c_hpz055pa_2_sfx = 2740, + c_hpz055pa_3_sfx = 2741, + c_hpz055pa_4_sfx = 2742, + c_hpz055pa_5_sfx = 2743, + c_hpz055pa_6_sfx = 2744, + c_hpz055pa_7_sfx = 2745, + c_hpz055pa_8_sfx = 2746, + c_hpz055pa_9_sfx = 2747, + c_hpz055pa_10_sfx = 2748, + c_hpz055pa_11_sfx = 2749, + c_hpz055pa_12_sfx = 2750, + c_hpz055pa_13_sfx = 2751, + c_hpz055pa_14_sfx = 2752, + c_hpz055pa_15_sfx = 2753, + c_hpz055pa_Anim = 2754, + c_HPZ070EN_Wav_700 = 2755, + c_HPZ070EN_Pho_700 = 2756, + c_HPZ074EN_Wav_700 = 2757, + c_HPZ074EN_Pho_700 = 2758, + c_HPZ072EN_Wav_700 = 2759, + c_HPZ072EN_Pho_700 = 2760, + c_HPZ073RE_Wav_700 = 2761, + c_HPZ073RE_Pho_700 = 2762, + c_HPZ071RE_Wav_700 = 2763, + c_HPZ071RE_Pho_700 = 2764, + c_HPZ069RE_Wav_700 = 2765, + c_HPZ069RE_Pho_700 = 2766, + c_HPZ068EN_Wav_700 = 2767, + c_HPZ068EN_Pho_700 = 2768, + c_HPZC63DL_Wav_700 = 2769, + c_HPZD64CA_Wav_700 = 2770, + c_HPZH60DL_Wav_700 = 2771, + c_HPZF60DL_Wav_700 = 2772, + c_HPZE60DL_Wav_700 = 2773, + c_HPZD60DL_Wav_700 = 2774, + c_HPZB60DL_Wav_700 = 2775, + c_HPZ061MA_Wav_700 = 2776, + c_HPZ061MA_Pho_700 = 2777, + c_HPZ065MA_Wav_700 = 2778, + c_HPZ065MA_Pho_700 = 2779, + c_HPZ059SH_Wav_700 = 2780, + c_HPZ057SH_Wav_700 = 2781, + c_HPZ057MA_Wav_700 = 2782, + c_HPZ057MA_Pho_700 = 2783, + c_HPZ067P1_Wav_700 = 2784, + c_HPZB54GD_Wav_700 = 2785, + c_HPZB54GD_Pho_700 = 2786, + c_HPZC54GD_Wav_700 = 2787, + c_HPZC54GD_Pho_700 = 2788, + c_HPZE54GD_Wav_700 = 2789, + c_HPZE54GD_Pho_700 = 2790, + c_HPZF54GD_Wav_700 = 2791, + c_HPZF54GD_Pho_700 = 2792, + c_HPZA54GD_Wav_700 = 2793, + c_HPZA54GD_Pho_700 = 2794, + c_hpz057ma_0_sfx = 2795, + c_hpz057ma_1_sfx = 2796, + c_hpz057ma_2_sfx = 2797, + c_hpz057ma_3_sfx = 2798, + c_hpz057ma_4_sfx = 2799, + c_hpz057ma_5_sfx = 2800, + c_hpz057ma_6_sfx = 2801, + c_hpz057ma_7_sfx = 2802, + c_hpz057ma_8_sfx = 2803, + c_hpz057ma_9_sfx = 2804, + c_hpz057ma_10_sfx = 2805, + c_hpz057ma_11_sfx = 2806, + c_hpz057ma_12_sfx = 2807, + c_hpz057ma_13_sfx = 2808, + c_hpz057ma_14_sfx = 2809, + c_hpz057ma_15_sfx = 2810, + c_hpz057ma_Anim = 2811, + c_HPZA51GD_Wav_701 = 2812, + c_HPZA51GD_Pho_701 = 2813, + c_hpza51gd_0_sfx = 2814, + c_hpza51gd_1_sfx = 2815, + c_hpza51gd_Anim = 2816, + c_HPZB51GD_Wav_702 = 2817, + c_HPZB51GD_Pho_702 = 2818, + c_hpzb51gd_0_sfx = 2819, + c_hpzb51gd_1_sfx = 2820, + c_hpzb51gd_2_sfx = 2821, + c_hpzb51gd_Anim = 2822, + c_HPZC51GD_Wav_703 = 2823, + c_HPZC51GD_Pho_703 = 2824, + c_hpzc51gd_0_sfx = 2825, + c_hpzc51gd_1_sfx = 2826, + c_hpzc51gd_2_sfx = 2827, + c_hpzc51gd_3_sfx = 2828, + c_hpzc51gd_Anim = 2829, + c_HPZF51GD_Wav_704 = 2830, + c_HPZF51GD_Pho_704 = 2831, + c_hpzf51gd_0_sfx = 2832, + c_hpzf51gd_Anim = 2833, + c_HPZA51GD_Wav_705 = 2834, + c_HPZA51GD_Pho_705 = 2835, + c_hpzw51gd_0_sfx = 2836, + c_hpzw51gd_1_sfx = 2837, + c_hpzw51gd_Anim = 2838, + c_HPZB51GD_Wav_706 = 2839, + c_HPZB51GD_Pho_706 = 2840, + c_hpzx51gd_0_sfx = 2841, + c_hpzx51gd_1_sfx = 2842, + c_hpzx51gd_Anim = 2843, + c_HPZC51GD_Wav_707 = 2844, + c_HPZC51GD_Pho_707 = 2845, + c_hpzy51gd_0_sfx = 2846, + c_hpzy51gd_1_sfx = 2847, + c_hpzy51gd_Anim = 2848, + c_HPZF51GD_Wav_708 = 2849, + c_HPZF51GD_Pho_708 = 2850, + c_hpzz51gd_0_sfx = 2851, + c_hpzz51gd_1_sfx = 2852, + c_hpzz51gd_Anim = 2853, + c_nic002pr_0_sfx = 2854, + c_nic002pr_Anim = 2855, + c_nic003pr_0_sfx = 2856, + c_nic003pr_1_sfx = 2857, + c_nic003pr_Anim = 2858, + c_nic004pr_0_sfx = 2859, + c_nic004pr_1_sfx = 2860, + c_nic004pr_2_sfx = 2861, + c_nic004pr_Anim = 2862, + c_PPS025NI_Wav_712 = 2863, + c_PPS025NI_Pho_712 = 2864, + c_PPS024NI_Wav_712 = 2865, + c_PPS024NI_Pho_712 = 2866, + c_pps025ni_0_sfx = 2867, + c_pps025ni_1_sfx = 2868, + c_pps025ni_Anim = 2869, + c_PPS026NI_Wav_713 = 2870, + c_PPS026NI_Pho_713 = 2871, + c_PPS024NI_Wav_713 = 2872, + c_PPS024NI_Pho_713 = 2873, + c_pps026ni_0_sfx = 2874, + c_pps026ni_Anim = 2875, + c_PPS027NI_Wav_714 = 2876, + c_PPS027NI_Pho_714 = 2877, + c_PPS024NI_Wav_714 = 2878, + c_PPS024NI_Pho_714 = 2879, + c_pps027ni_0_sfx = 2880, + c_pps027ni_Anim = 2881, + c_PPZ005PA_Wav_715 = 2882, + c_PPZ005PA_Pho_715 = 2883, + c_PPZ004PE_Wav_715 = 2884, + c_PPZ004PE_Pho_715 = 2885, + c_PPZ003PA_Wav_715 = 2886, + c_PPZ003PA_Pho_715 = 2887, + c_PPZ002PA_Wav_715 = 2888, + c_PPZ002PA_Pho_715 = 2889, + c_PPZ001PE_Wav_715 = 2890, + c_PPZ001PE_Pho_715 = 2891, + c_ppz001pe_0_sfx = 2892, + c_ppz001pe_1_sfx = 2893, + c_ppz001pe_2_sfx = 2894, + c_ppz001pe_3_sfx = 2895, + c_ppz001pe_4_sfx = 2896, + c_ppz001pe_Anim = 2897, + c_PPZ006PA_Wav_716 = 2898, + c_PPZ006PA_Pho_716 = 2899, + c_ppz006pa_0_sfx = 2900, + c_ppz006pa_1_sfx = 2901, + c_ppz006pa_Anim = 2902, + c_PPZ007PA_Wav_717 = 2903, + c_PPZ007PA_Pho_717 = 2904, + c_ppz007pa_0_sfx = 2905, + c_ppz007pa_Anim = 2906, + c_PPZ014PE_Wav_718 = 2907, + c_PPZ014PE_Pho_718 = 2908, + c_PPZ012PE_Wav_718 = 2909, + c_PPZ012PE_Pho_718 = 2910, + c_PPZ010PA_Wav_718 = 2911, + c_PPZ010PA_Pho_718 = 2912, + c_ppz010pa_0_sfx = 2913, + c_ppz010pa_1_sfx = 2914, + c_ppz010pa_Anim = 2915, + c_PPZ015PE_Wav_719 = 2916, + c_PPZ015PE_Pho_719 = 2917, + c_PPZ012PE_Wav_719 = 2918, + c_PPZ012PE_Pho_719 = 2919, + c_PPZ011PA_Wav_719 = 2920, + c_PPZ011PA_Pho_719 = 2921, + c_ppz011pa_0_sfx = 2922, + c_ppz011pa_1_sfx = 2923, + c_ppz011pa_2_sfx = 2924, + c_ppz011pa_Anim = 2925, + c_PPZ013PA_Wav_720 = 2926, + c_PPZ013PA_Pho_720 = 2927, + c_ppz013pa_0_sfx = 2928, + c_ppz013pa_1_sfx = 2929, + c_ppz013pa_Anim = 2930, + c_PPZ014PE_Wav_721 = 2931, + c_PPZ014PE_Pho_721 = 2932, + c_ppz014pe_0_sfx = 2933, + c_ppz014pe_1_sfx = 2934, + c_ppz014pe_2_sfx = 2935, + c_ppz014pe_3_sfx = 2936, + c_ppz014pe_Anim = 2937, + c_PPZ015PE_Wav_722 = 2938, + c_PPZ015PE_Pho_722 = 2939, + c_ppz015pe_0_sfx = 2940, + c_ppz015pe_1_sfx = 2941, + c_ppz015pe_2_sfx = 2942, + c_ppz015pe_Anim = 2943, + c_PPZ016PE_Wav_723 = 2944, + c_PPZ016PE_Pho_723 = 2945, + c_ppz016pe_0_sfx = 2946, + c_ppz016pe_1_sfx = 2947, + c_ppz016pe_Anim = 2948, + c_PGS050NU_Wav_724 = 2949, + c_PGS050NU_Pho_724 = 2950, + c_PGS049NU_Wav_724 = 2951, + c_PGS049NU_Pho_724 = 2952, + c_pgs050nu_0_sfx = 2953, + c_pgs050nu_Anim = 2954, + c_pgs051nu_Wav_725 = 2955, + c_pgs051nu_Pho_725 = 2956, + c_PGS049NU_Wav_725 = 2957, + c_PGS049NU_Pho_725 = 2958, + c_pgs051nu_0_sfx = 2959, + c_pgs051nu_1_sfx = 2960, + c_pgs051nu_2_sfx = 2961, + c_pgs051nu_Anim = 2962, + c_pgs052nu_Wav_726 = 2963, + c_pgs052nu_Pho_726 = 2964, + c_PGS049NU_Wav_726 = 2965, + c_PGS049NU_Pho_726 = 2966, + c_pgs052nu_0_sfx = 2967, + c_pgs052nu_1_sfx = 2968, + c_pgs052nu_2_sfx = 2969, + c_pgs052nu_3_sfx = 2970, + c_pgs052nu_Anim = 2971, + c_PPZ031MA_Wav_727 = 2972, + c_PPZ031MA_Pho_727 = 2973, + c_PPZ032PA_Wav_727 = 2974, + c_PPZ032PA_Pho_727 = 2975, + c_PPZ033MA_Wav_727 = 2976, + c_PPZ033MA_Pho_727 = 2977, + c_PPZ034PA_Wav_727 = 2978, + c_PPZ034PA_Pho_727 = 2979, + c_ppz031ma_0_sfx = 2980, + c_ppz031ma_1_sfx = 2981, + c_ppz031ma_2_sfx = 2982, + c_ppz031ma_3_sfx = 2983, + c_ppz031ma_Anim = 2984, + c_PPZ035PA_Wav_728 = 2985, + c_PPZ035PA_Pho_728 = 2986, + c_ppz035pa_0_sfx = 2987, + c_ppz035pa_1_sfx = 2988, + c_ppz035pa_2_sfx = 2989, + c_ppz035pa_3_sfx = 2990, + c_ppz035pa_4_sfx = 2991, + c_ppz035pa_5_sfx = 2992, + c_ppz035pa_Anim = 2993, + c_PPZ036pa_Wav_729 = 2994, + c_PPZ036pa_Pho_729 = 2995, + c_ppz036pa_0_sfx = 2996, + c_ppz036pa_1_sfx = 2997, + c_ppz036pa_2_sfx = 2998, + c_ppz036pa_3_sfx = 2999, + c_ppz036pa_Anim = 3000, + c_PPZ037MA_Wav_730 = 3001, + c_PPZ037MA_Pho_730 = 3002, + c_ppz037ma_0_sfx = 3003, + c_ppz037ma_1_sfx = 3004, + c_ppz037ma_Anim = 3005, + c_PPZ038MA_Wav_731 = 3006, + c_PPZ038MA_Pho_731 = 3007, + c_ppz038ma_Anim = 3008, + c_PPZ054MA_Wav_732 = 3009, + c_PPZ054MA_Pho_732 = 3010, + c_ppz054ma_0_sfx = 3011, + c_ppz054ma_1_sfx = 3012, + c_ppz054ma_2_sfx = 3013, + c_ppz054ma_3_sfx = 3014, + c_ppz054ma_4_sfx = 3015, + c_ppz054ma_5_sfx = 3016, + c_ppz054ma_6_sfx = 3017, + c_ppz054ma_Anim = 3018, + c_PPZ055MA_Wav_733 = 3019, + c_PPZ055MA_Pho_733 = 3020, + c_ppz055ma_0_sfx = 3021, + c_ppz055ma_1_sfx = 3022, + c_ppz055ma_2_sfx = 3023, + c_ppz055ma_3_sfx = 3024, + c_ppz055ma_4_sfx = 3025, + c_ppz055ma_5_sfx = 3026, + c_ppz055ma_6_sfx = 3027, + c_ppz055ma_7_sfx = 3028, + c_ppz055ma_8_sfx = 3029, + c_ppz055ma_9_sfx = 3030, + c_ppz055ma_Anim = 3031, + c_PPZ056MA_Wav_734 = 3032, + c_PPZ056MA_Pho_734 = 3033, + c_ppz056ma_0_sfx = 3034, + c_ppz056ma_Anim = 3035, + c_PPZX62MA_Wav_735 = 3036, + c_PPZX62MA_Pho_735 = 3037, + c_PPZ059MA_Wav_735 = 3038, + c_PPZ059MA_Pho_735 = 3039, + c_ppz059ma_0_sfx = 3040, + c_ppz059ma_1_sfx = 3041, + c_ppz059ma_2_sfx = 3042, + c_ppz059ma_Anim = 3043, + c_PPZ063MA_Wav_736 = 3044, + c_PPZ063MA_Pho_736 = 3045, + c_PPZ060MA_Wav_736 = 3046, + c_PPZ060MA_Pho_736 = 3047, + c_ppz060ma_0_sfx = 3048, + c_ppz060ma_1_sfx = 3049, + c_ppz060ma_Anim = 3050, + c_PPZ061MA_Wav_737 = 3051, + c_PPZ061MA_Pho_737 = 3052, + c_ppz061ma_Anim = 3053, + c_PPZ064MA_Wav_738 = 3054, + c_PPZ064MA_Pho_738 = 3055, + c_ppz064ma_0_sfx = 3056, + c_ppz064ma_1_sfx = 3057, + c_ppz064ma_Anim = 3058, + c_PRt072Sl_Wav_739 = 3059, + c_PRt072Sl_Pho_739 = 3060, + c_PRt071Sl_Wav_739 = 3061, + c_PRt071Sl_Pho_739 = 3062, + c_prt072sl_0_sfx = 3063, + c_prt072sl_1_sfx = 3064, + c_prt072sl_2_sfx = 3065, + c_prt072sl_3_sfx = 3066, + c_prt072sl_4_sfx = 3067, + c_prt072sl_5_sfx = 3068, + c_prt072sl_6_sfx = 3069, + c_prt072sl_7_sfx = 3070, + c_prt072sl_8_sfx = 3071, + c_prt072sl_9_sfx = 3072, + c_prt072sl_10_sfx = 3073, + c_prt072sl_11_sfx = 3074, + c_prt072sl_12_sfx = 3075, + c_prt072sl_Anim = 3076, + c_PRt071Sl_Wav_740 = 3077, + c_PRt071Sl_Pho_740 = 3078, + c_PRt073Sl_Wav_740 = 3079, + c_PRt073Sl_Pho_740 = 3080, + c_prt073sl_0_sfx = 3081, + c_prt073sl_1_sfx = 3082, + c_prt073sl_2_sfx = 3083, + c_prt073sl_3_sfx = 3084, + c_prt073sl_4_sfx = 3085, + c_prt073sl_5_sfx = 3086, + c_prt073sl_Anim = 3087, + c_PRt074Sl_Wav_741 = 3088, + c_PRt074Sl_Pho_741 = 3089, + c_PRt071Sl_Wav_741 = 3090, + c_PRt071Sl_Pho_741 = 3091, + c_prt074sl_0_sfx = 3092, + c_prt074sl_1_sfx = 3093, + c_prt074sl_2_sfx = 3094, + c_prt074sl_3_sfx = 3095, + c_prt074sl_4_sfx = 3096, + c_prt074sl_5_sfx = 3097, + c_prt074sl_6_sfx = 3098, + c_prt074sl_7_sfx = 3099, + c_prt074sl_Anim = 3100, + c_PHO103EN_Wav_742 = 3101, + c_PHO103EN_Pho_742 = 3102, + c_PHO104RE_Wav_742 = 3103, + c_PHO104RE_Pho_742 = 3104, + c_pho104re_0_sfx = 3105, + c_pho104re_Anim = 3106, + c_PHO103EN_Wav_743 = 3107, + c_PHO103EN_Pho_743 = 3108, + c_PHO105RE_Wav_743 = 3109, + c_PHO105RE_Pho_743 = 3110, + c_pho105re_0_sfx = 3111, + c_pho105re_Anim = 3112, + c_PHO103EN_Wav_744 = 3113, + c_PHO103EN_Pho_744 = 3114, + c_PHO106RE_Wav_744 = 3115, + c_PHO106RE_Pho_744 = 3116, + c_pho106re_0_sfx = 3117, + c_pho106re_Anim = 3118, + c_PPZ076PE_Wav_745 = 3119, + c_PPZ076PE_Pho_745 = 3120, + c_ppz078pe_Wav_745 = 3121, + c_ppz078pe_Pho_745 = 3122, + c_ppz080ma_Wav_745 = 3123, + c_ppz080ma_Pho_745 = 3124, + c_ppz079pa_Wav_745 = 3125, + c_ppz079pa_Pho_745 = 3126, + c_ppz077pa_Wav_745 = 3127, + c_ppz077pa_Pho_745 = 3128, + c_ppz081pa_Wav_745 = 3129, + c_ppz081pa_Pho_745 = 3130, + c_ppz075pa_0_sfx = 3131, + c_ppz075pa_1_sfx = 3132, + c_ppz075pa_2_sfx = 3133, + c_ppz075pa_3_sfx = 3134, + c_ppz075pa_4_sfx = 3135, + c_ppz075pa_5_sfx = 3136, + c_ppz075pa_6_sfx = 3137, + c_ppz075pa_7_sfx = 3138, + c_ppz075pa_8_sfx = 3139, + c_ppz075pa_9_sfx = 3140, + c_ppz075pa_10_sfx = 3141, + c_ppz075pa_11_sfx = 3142, + c_ppz075pa_12_sfx = 3143, + c_ppz075pa_13_sfx = 3144, + c_ppz075pa_14_sfx = 3145, + c_ppz075pa_15_sfx = 3146, + c_ppz075pa_16_sfx = 3147, + c_ppz075pa_17_sfx = 3148, + c_ppz075pa_18_sfx = 3149, + c_ppz075pa_Anim = 3150, + c_ppz080ma_Wav_746 = 3151, + c_ppz080ma_Pho_746 = 3152, + c_ppz083ma_Wav_746 = 3153, + c_ppz083ma_Pho_746 = 3154, + c_ppz082pa_Wav_746 = 3155, + c_ppz082pa_Pho_746 = 3156, + c_ppz082pa_0_sfx = 3157, + c_ppz082pa_1_sfx = 3158, + c_ppz082pa_2_sfx = 3159, + c_ppz082pa_3_sfx = 3160, + c_ppz082pa_4_sfx = 3161, + c_ppz082pa_5_sfx = 3162, + c_ppz082pa_6_sfx = 3163, + c_ppz082pa_Anim = 3164, + c_ppz084pa_Wav_747 = 3165, + c_ppz084pa_Pho_747 = 3166, + c_ppz084pa_0_sfx = 3167, + c_ppz084pa_Anim = 3168, + c_ppz093pe_Wav_748 = 3169, + c_ppz093pe_Pho_748 = 3170, + c_ppz088ma_Wav_748 = 3171, + c_ppz088ma_Pho_748 = 3172, + c_ppz088ma_Anim = 3173, + c_PPZ094PE_Wav_749 = 3174, + c_PPZ094PE_Pho_749 = 3175, + c_ppz089ma_Wav_749 = 3176, + c_ppz089ma_Pho_749 = 3177, + c_ppz089ma_0_sfx = 3178, + c_ppz089ma_1_sfx = 3179, + c_ppz089ma_2_sfx = 3180, + c_ppz089ma_3_sfx = 3181, + c_ppz089ma_Anim = 3182, + c_ppz090ma_Wav_750 = 3183, + c_ppz090ma_Pho_750 = 3184, + c_ppz091pe_Wav_750 = 3185, + c_ppz091pe_Pho_750 = 3186, + c_ppz092ma_Wav_750 = 3187, + c_ppz092ma_Pho_750 = 3188, + c_ppz090ma_0_sfx = 3189, + c_ppz090ma_1_sfx = 3190, + c_ppz090ma_2_sfx = 3191, + c_ppz090ma_3_sfx = 3192, + c_ppz090ma_Anim = 3193, + c_ppz093pe_Wav_751 = 3194, + c_ppz093pe_Pho_751 = 3195, + c_ppz093pe_0_sfx = 3196, + c_ppz093pe_1_sfx = 3197, + c_ppz093pe_2_sfx = 3198, + c_ppz093pe_3_sfx = 3199, + c_ppz093pe_4_sfx = 3200, + c_ppz093pe_5_sfx = 3201, + c_ppz093pe_Anim = 3202, + c_ppz094pe_Wav_752 = 3203, + c_ppz094pe_Pho_752 = 3204, + c_ppz094pe_0_sfx = 3205, + c_ppz094pe_1_sfx = 3206, + c_ppz094pe_2_sfx = 3207, + c_ppz094pe_3_sfx = 3208, + c_ppz094pe_4_sfx = 3209, + c_ppz094pe_Anim = 3210, + c_ppz095pe_Wav_753 = 3211, + c_ppz095pe_Pho_753 = 3212, + c_ppz095pe_0_sfx = 3213, + c_ppz095pe_1_sfx = 3214, + c_ppz095pe_2_sfx = 3215, + c_ppz095pe_Anim = 3216, + c_prp101pr_Anim = 3217, + c_pja126br_Wav_755 = 3218, + c_pja126br_Pho_755 = 3219, + c_pja126br_0_sfx = 3220, + c_pja126br_Anim = 3221, + c_PJA127BR_Wav_756 = 3222, + c_PJA127BR_Pho_756 = 3223, + c_PJa128Br_Wav_756 = 3224, + c_PJa128Br_Pho_756 = 3225, + c_pja127br_0_sfx = 3226, + c_pja127br_1_sfx = 3227, + c_pja127br_2_sfx = 3228, + c_pja127br_3_sfx = 3229, + c_pja127br_4_sfx = 3230, + c_pja127br_Anim = 3231, + c_PJA129BR_Wav_757 = 3232, + c_PJA129BR_Pho_757 = 3233, + c_pja129br_0_sfx = 3234, + c_pja129br_1_sfx = 3235, + c_pja129br_2_sfx = 3236, + c_pja129br_3_sfx = 3237, + c_pja129br_4_sfx = 3238, + c_pja129br_Anim = 3239, + c_pja130br_Wav_758 = 3240, + c_pja130br_Pho_758 = 3241, + c_pja130br_0_sfx = 3242, + c_pja130br_1_sfx = 3243, + c_pja130br_2_sfx = 3244, + c_pja130br_3_sfx = 3245, + c_pja130br_Anim = 3246, + c_PJA131BR_Wav_759 = 3247, + c_PJA131BR_Pho_759 = 3248, + c_pja131br_0_sfx = 3249, + c_pja131br_1_sfx = 3250, + c_pja131br_2_sfx = 3251, + c_pja131br_Anim = 3252, + c_PJA132BR_Wav_760 = 3253, + c_PJA132BR_Pho_760 = 3254, + c_pja132br_0_sfx = 3255, + c_pja132br_1_sfx = 3256, + c_pja132br_2_sfx = 3257, + c_pja132br_3_sfx = 3258, + c_pja132br_Anim = 3259, + c_PPZ114PA_Wav_761 = 3260, + c_PPZ114PA_Pho_761 = 3261, + c_PPZ113PA_Wav_761 = 3262, + c_PPZ113PA_Pho_761 = 3263, + c_PPZ112MA_Wav_761 = 3264, + c_PPZ112MA_Pho_761 = 3265, + c_PPZ111PA_Wav_761 = 3266, + c_PPZ111PA_Pho_761 = 3267, + c_PPZ110MA_Wav_761 = 3268, + c_PPZ110MA_Pho_761 = 3269, + c_PPZ109PA_Wav_761 = 3270, + c_PPZ109PA_Pho_761 = 3271, + c_PPZ108MA_Wav_761 = 3272, + c_PPZ108MA_Pho_761 = 3273, + c_PPZ107MA_Wav_761 = 3274, + c_PPZ107MA_Pho_761 = 3275, + c_ppz107ma_0_sfx = 3276, + c_ppz107ma_1_sfx = 3277, + c_ppz107ma_2_sfx = 3278, + c_ppz107ma_3_sfx = 3279, + c_ppz107ma_4_sfx = 3280, + c_ppz107ma_5_sfx = 3281, + c_ppz107ma_6_sfx = 3282, + c_ppz107ma_7_sfx = 3283, + c_ppz107ma_8_sfx = 3284, + c_ppz107ma_9_sfx = 3285, + c_ppz107ma_10_sfx = 3286, + c_ppz107ma_11_sfx = 3287, + c_ppz107ma_12_sfx = 3288, + c_ppz107ma_13_sfx = 3289, + c_ppz107ma_14_sfx = 3290, + c_ppz107ma_15_sfx = 3291, + c_ppz107ma_16_sfx = 3292, + c_ppz107ma_17_sfx = 3293, + c_ppz107ma_18_sfx = 3294, + c_ppz107ma_19_sfx = 3295, + c_ppz107ma_20_sfx = 3296, + c_ppz107ma_Anim = 3297, + c_PPZ114PA_Wav_762 = 3298, + c_PPZ114PA_Pho_762 = 3299, + c_ppz114pa_0_sfx = 3300, + c_ppz114pa_1_sfx = 3301, + c_ppz114pa_Anim = 3302, + c_PPZ117MA_Wav_763 = 3303, + c_PPZ117MA_Pho_763 = 3304, + c_ppz117ma_0_sfx = 3305, + c_ppz117ma_1_sfx = 3306, + c_ppz117ma_Anim = 3307, + c_PPZ118MA_Wav_764 = 3308, + c_PPZ118MA_Pho_764 = 3309, + c_ppz118ma_0_sfx = 3310, + c_ppz118ma_1_sfx = 3311, + c_ppz118ma_Anim = 3312, + c_PPZ119MA_Wav_765 = 3313, + c_PPZ119MA_Pho_765 = 3314, + c_ppz119ma_0_sfx = 3315, + c_ppz119ma_1_sfx = 3316, + c_ppz119ma_Anim = 3317, + c_PPZ120PA_Wav_766 = 3318, + c_PPZ120PA_Pho_766 = 3319, + c_ppz120pa_Anim = 3320, + c_wgs084nu_Wav_767 = 3321, + c_wgs084nu_Pho_767 = 3322, + c_wgs083nu_0_sfx = 3323, + c_wgs083nu_1_sfx = 3324, + c_wgs083nu_2_sfx = 3325, + c_wgs083nu_Anim = 3326, + c_wgs085nu_Wav_768 = 3327, + c_wgs085nu_Pho_768 = 3328, + c_wgs085nu_0_sfx = 3329, + c_wgs085nu_Anim = 3330, + c_wgs086nu_Wav_769 = 3331, + c_wgs086nu_Pho_769 = 3332, + c_wgs086nu_Anim = 3333, + c_wgs087nu_Wav_770 = 3334, + c_wgs087nu_Pho_770 = 3335, + c_wgs087nu_0_sfx = 3336, + c_wgs087nu_Anim = 3337, + c_wgs088nu_Wav_771 = 3338, + c_wgs088nu_Pho_771 = 3339, + c_wgs088nu_0_sfx = 3340, + c_wgs088nu_Anim = 3341, + c_wgs089nu_Wav_772 = 3342, + c_wgs089nu_Pho_772 = 3343, + c_wgs089nu_Anim = 3344, + c_wgs090nu_Wav_773 = 3345, + c_wgs090nu_Pho_773 = 3346, + c_wgs090nu_0_sfx = 3347, + c_wgs090nu_1_sfx = 3348, + c_wgs090nu_2_sfx = 3349, + c_wgs090nu_Anim = 3350, + c_wgs091nu_Wav_774 = 3351, + c_wgs091nu_Pho_774 = 3352, + c_wgs091nu_0_sfx = 3353, + c_wgs091nu_1_sfx = 3354, + c_wgs091nu_2_sfx = 3355, + c_wgs091nu_Anim = 3356, + c_wgs092nu_Wav_775 = 3357, + c_wgs092nu_Pho_775 = 3358, + c_wgs092nu_0_sfx = 3359, + c_wgs092nu_1_sfx = 3360, + c_wgs092nu_Anim = 3361, + c_wgs093nu_Wav_776 = 3362, + c_wgs093nu_Pho_776 = 3363, + c_wgs093nu_0_sfx = 3364, + c_wgs093nu_1_sfx = 3365, + c_wgs093nu_Anim = 3366, + c_wgs094nu_Wav_777 = 3367, + c_wgs094nu_Pho_777 = 3368, + c_wgs094nu_0_sfx = 3369, + c_wgs094nu_1_sfx = 3370, + c_wgs094nu_Anim = 3371, + c_wgs095nu_Wav_778 = 3372, + c_wgs095nu_Pho_778 = 3373, + c_wgs095nu_0_sfx = 3374, + c_wgs095nu_1_sfx = 3375, + c_wgs095nu_2_sfx = 3376, + c_wgs095nu_Anim = 3377, + c_wgs096nu_Wav_779 = 3378, + c_wgs096nu_Pho_779 = 3379, + c_wgs096nu_Anim = 3380, + c_wgs097nu_Wav_780 = 3381, + c_wgs097nu_Pho_780 = 3382, + c_wgs097nu_0_sfx = 3383, + c_wgs097nu_1_sfx = 3384, + c_wgs097nu_2_sfx = 3385, + c_wgs097nu_Anim = 3386, + c_wgs098nu_Wav_781 = 3387, + c_wgs098nu_Pho_781 = 3388, + c_wgs098nu_0_sfx = 3389, + c_wgs098nu_1_sfx = 3390, + c_wgs098nu_2_sfx = 3391, + c_wgs098nu_Anim = 3392, + c_wgs099nu_Wav_782 = 3393, + c_wgs099nu_Pho_782 = 3394, + c_wgs099nu_0_sfx = 3395, + c_wgs099nu_1_sfx = 3396, + c_wgs099nu_Anim = 3397, + c_wgs100nu_Wav_783 = 3398, + c_wgs100nu_Pho_783 = 3399, + c_wgs100nu_0_sfx = 3400, + c_wgs100nu_Anim = 3401, + c_wgs101nu_Wav_784 = 3402, + c_wgs101nu_Pho_784 = 3403, + c_wgs101nu_0_sfx = 3404, + c_wgs101nu_Anim = 3405, + c_wgs102nu_Wav_785 = 3406, + c_wgs102nu_Pho_785 = 3407, + c_wgs102nu_Anim = 3408, + c_wgs103nu_Wav_786 = 3409, + c_wgs103nu_Pho_786 = 3410, + c_wgs103nu_0_sfx = 3411, + c_wgs103nu_1_sfx = 3412, + c_wgs103nu_Anim = 3413, + c_WRT064BM_Wav_787 = 3414, + c_WRT064BM_Pho_787 = 3415, + c_WRT066BM_Wav_787 = 3416, + c_WRT066BM_Pho_787 = 3417, + c_WRT068BM_Wav_787 = 3418, + c_WRT068BM_Pho_787 = 3419, + c_WRT070BM_Wav_787 = 3420, + c_WRT070BM_Pho_787 = 3421, + c_WRT065JK_Wav_787 = 3422, + c_WRT065JK_Pho_787 = 3423, + c_WRT067JK_Wav_787 = 3424, + c_WRT067JK_Pho_787 = 3425, + c_WRT069JK_Wav_787 = 3426, + c_WRT069JK_Pho_787 = 3427, + c_WRT071JK_Wav_787 = 3428, + c_WRT071JK_Pho_787 = 3429, + c_wrt060bm_0_sfx = 3430, + c_wrt060bm_1_sfx = 3431, + c_wrt060bm_2_sfx = 3432, + c_wrt060bm_3_sfx = 3433, + c_wrt060bm_4_sfx = 3434, + c_wrt060bm_5_sfx = 3435, + c_wrt060bm_Anim = 3436, + c_WRT074SL_Wav_788 = 3437, + c_WRT074SL_Pho_788 = 3438, + c_WRT081JK_Wav_788 = 3439, + c_WRT081JK_Pho_788 = 3440, + c_WRT080BM_Wav_788 = 3441, + c_WRT080BM_Pho_788 = 3442, + c_wrt074sl_0_sfx = 3443, + c_wrt074sl_1_sfx = 3444, + c_wrt074sl_2_sfx = 3445, + c_wrt074sl_3_sfx = 3446, + c_wrt074sl_Anim = 3447, + c_WRT081JK_Wav_789 = 3448, + c_WRT081JK_Pho_789 = 3449, + c_WRT080BM_Wav_789 = 3450, + c_WRT080BM_Pho_789 = 3451, + c_WRT075RH_Wav_789 = 3452, + c_WRT075RH_Pho_789 = 3453, + c_wrt075rh_0_sfx = 3454, + c_wrt075rh_1_sfx = 3455, + c_wrt075rh_2_sfx = 3456, + c_wrt075rh_3_sfx = 3457, + c_wrt075rh_4_sfx = 3458, + c_wrt075rh_5_sfx = 3459, + c_wrt075rh_Anim = 3460, + c_WRT077GN_Wav_790 = 3461, + c_WRT077GN_Pho_790 = 3462, + c_WRT076DF_Wav_790 = 3463, + c_WRT076DF_Pho_790 = 3464, + c_WRT081JK_Wav_790 = 3465, + c_WRT081JK_Pho_790 = 3466, + c_WRT080BM_Wav_790 = 3467, + c_WRT080BM_Pho_790 = 3468, + c_wrt076df_0_sfx = 3469, + c_wrt076df_1_sfx = 3470, + c_wrt076df_2_sfx = 3471, + c_wrt076df_3_sfx = 3472, + c_wrt076df_4_sfx = 3473, + c_wrt076df_5_sfx = 3474, + c_wrt076df_6_sfx = 3475, + c_wrt076df_Anim = 3476, + c_WRT078NI_Wav_791 = 3477, + c_WRT078NI_Pho_791 = 3478, + c_WRT081JK_Wav_791 = 3479, + c_WRT081JK_Pho_791 = 3480, + c_WRT080BM_Wav_791 = 3481, + c_WRT080BM_Pho_791 = 3482, + c_wrt078ni_0_sfx = 3483, + c_wrt078ni_1_sfx = 3484, + c_wrt078ni_2_sfx = 3485, + c_wrt078ni_3_sfx = 3486, + c_wrt078ni_4_sfx = 3487, + c_wrt078ni_5_sfx = 3488, + c_wrt078ni_Anim = 3489, + c_WRT081JK_Wav_792 = 3490, + c_WRT081JK_Pho_792 = 3491, + c_WRT080BM_Wav_792 = 3492, + c_WRT080BM_Pho_792 = 3493, + c_wrt079bm_0_sfx = 3494, + c_wrt079bm_1_sfx = 3495, + c_wrt079bm_2_sfx = 3496, + c_wrt079bm_3_sfx = 3497, + c_wrt079bm_4_sfx = 3498, + c_wrt079bm_5_sfx = 3499, + c_wrt079bm_Anim = 3500, + c_npz001bd_Anim = 3501, + c_npz002bd_Anim = 3502, + c_npz003bd_Anim = 3503, + c_npz004bd_Anim = 3504, + c_npz005bd_Anim = 3505, + c_npz006bd_Anim = 3506, + c_npz007bd_Anim = 3507, + c_nca001ca_0_sfx = 3508, + c_nca001ca_1_sfx = 3509, + c_nca001ca_2_sfx = 3510, + c_nca001ca_3_sfx = 3511, + c_nca001ca_4_sfx = 3512, + c_nca001ca_Anim = 3513, + c_nca002sk_0_sfx = 3514, + c_nca002sk_1_sfx = 3515, + c_nca002sk_2_sfx = 3516, + c_nca002sk_3_sfx = 3517, + c_nca002sk_4_sfx = 3518, + c_nca002sk_5_sfx = 3519, + c_nca002sk_6_sfx = 3520, + c_nca002sk_7_sfx = 3521, + c_nca002sk_Anim = 3522, + c_nca003gh_0_sfx = 3523, + c_nca003gh_1_sfx = 3524, + c_nca003gh_2_sfx = 3525, + c_nca003gh_3_sfx = 3526, + c_nca003gh_4_sfx = 3527, + c_nca003gh_5_sfx = 3528, + c_nca003gh_Anim = 3529, + c_nla001ha_Anim = 3530, + c_nla002sd_Anim = 3531, + c_npa001ns_Anim = 3532, + c_npa002ns_Anim = 3533, + c_npa003ns_Anim = 3534, + c_npa004ns_Anim = 3535, + c_npa005dl_Anim = 3536, + c_npa007dl_Anim = 3537, + c_npa009dl_Anim = 3538, + c_npa010db_Anim = 3539, + c_npa012db_Anim = 3540, + c_npa014db_Anim = 3541, + c_npa015ca_Anim = 3542, + c_npa017ca_Anim = 3543, + c_npa019ca_Anim = 3544, + c_npa020p1_Anim = 3545, + c_npa022p1_Anim = 3546, + c_npa024p1_Anim = 3547, + c_npa025sh_Anim = 3548, + c_npa027sh_Anim = 3549, + c_npa029sh_Anim = 3550, + c_npa030fl_Anim = 3551, + c_npa031fl_Anim = 3552, + c_npa032fl_Anim = 3553, + c_npa034bh_Anim = 3554, + c_npa035bh_Anim = 3555, + c_npa036bh_Anim = 3556, + c_npa038pn_Anim = 3557, + c_npa039pn_Anim = 3558, + c_npa040pn_Anim = 3559, + c_npa042pm_Anim = 3560, + c_npa043pm_Anim = 3561, + c_npa044pm_Anim = 3562, + c_npa046sr_Anim = 3563, + c_npa047sr_Anim = 3564, + c_npa048sr_Anim = 3565, + c_npa050ba_Anim = 3566, + c_npa051ba_Anim = 3567, + c_npa052ba_Anim = 3568, + c_npa054po_Anim = 3569, + c_npa055po_Anim = 3570, + c_npa056po_Anim = 3571, + c_npa058r1_Anim = 3572, + c_npa059r1_Anim = 3573, + c_npa060r1_Anim = 3574, + c_npa061r3_Anim = 3575, + c_npa062r2_Anim = 3576, + c_npa062r3_Anim = 3577, + c_npa063r2_Anim = 3578, + c_npa063r3_Anim = 3579, + c_npa065r2_Anim = 3580, + c_nja001pr_Anim = 3581, + c_nja002pr_Anim = 3582, + c_sjs007in_Wav_856 = 3583, + c_sjs007in_Pho_856 = 3584, + c_sjs007in_0_sfx = 3585, + c_sjs007in_1_sfx = 3586, + c_sjs007in_Anim = 3587, + c_sns005in_Wav_857 = 3588, + c_sns005in_Pho_857 = 3589, + c_sns005in_0_sfx = 3590, + c_sns005in_1_sfx = 3591, + c_sns005in_Anim = 3592, + c_sns006in_Wav_858 = 3593, + c_sns006in_Pho_858 = 3594, + c_sns006in_0_sfx = 3595, + c_sns006in_1_sfx = 3596, + c_sns006in_2_sfx = 3597, + c_sns006in_3_sfx = 3598, + c_sns006in_Anim = 3599, + c_sns008in_Wav_859 = 3600, + c_sns008in_Pho_859 = 3601, + c_sns008in_0_sfx = 3602, + c_sns008in_1_sfx = 3603, + c_sns008in_2_sfx = 3604, + c_sns008in_3_sfx = 3605, + c_sns008in_Anim = 3606, + c_sjs012in_Wav_860 = 3607, + c_sjs012in_Pho_860 = 3608, + c_sjs012in_0_sfx = 3609, + c_sjs012in_1_sfx = 3610, + c_sjs012in_2_sfx = 3611, + c_sjs012in_3_sfx = 3612, + c_sjs012in_4_sfx = 3613, + c_sjs012in_Anim = 3614, + c_sjs013in_Wav_861 = 3615, + c_sjs013in_Pho_861 = 3616, + c_sjs013in_0_sfx = 3617, + c_sjs013in_1_sfx = 3618, + c_sjs013in_2_sfx = 3619, + c_sjs013in_3_sfx = 3620, + c_sjs013in_Anim = 3621, + c_sjs014in_Wav_862 = 3622, + c_sjs014in_Pho_862 = 3623, + c_sjs014in_0_sfx = 3624, + c_sjs014in_1_sfx = 3625, + c_sjs014in_2_sfx = 3626, + c_sjs014in_3_sfx = 3627, + c_sjs014in_Anim = 3628, + c_sjs015in_Wav_863 = 3629, + c_sjs015in_Pho_863 = 3630, + c_sjs015in_0_sfx = 3631, + c_sjs015in_1_sfx = 3632, + c_sjs015in_2_sfx = 3633, + c_sjs015in_Anim = 3634, + c_srt001in_Wav_864 = 3635, + c_srt001in_Pho_864 = 3636, + c_srt001in_0_sfx = 3637, + c_srt001in_1_sfx = 3638, + c_srt001in_2_sfx = 3639, + c_srt001in_3_sfx = 3640, + c_srt001in_Anim = 3641, + c_srt002in_Wav_865 = 3642, + c_srt002in_Pho_865 = 3643, + c_srt002in_0_sfx = 3644, + c_srt002in_1_sfx = 3645, + c_srt002in_2_sfx = 3646, + c_srt002in_Anim = 3647, + c_srt003in_Wav_866 = 3648, + c_srt003in_Pho_866 = 3649, + c_srt003in_0_sfx = 3650, + c_srt003in_1_sfx = 3651, + c_srt003in_2_sfx = 3652, + c_srt003in_Anim = 3653, + c_srt004in_Wav_867 = 3654, + c_srt004in_Pho_867 = 3655, + c_srt004in_0_sfx = 3656, + c_srt004in_1_sfx = 3657, + c_srt004in_2_sfx = 3658, + c_srt004in_3_sfx = 3659, + c_srt004in_4_sfx = 3660, + c_srt004in_5_sfx = 3661, + c_srt004in_6_sfx = 3662, + c_srt004in_Anim = 3663, + c_IRTX08RA_Wav_868 = 3664, + c_nrtflag0_Anim = 3665, + c_WNS050P1_Wav_3666 = 3666, + c_wns050p1_0_sfx = 3667, + c_wns050p1_1_sfx = 3668, + c_wns050p1_Anim = 3669, + c_wns049p1_Anim = 3670, + c_wns048p1_Anim = 3671, + c_pns123pr_Anim = 3672, + c_wns045di_Anim = 3673, + c_wns053pr_Anim = 3674, + c_wns046mg_Anim = 3675, + c_wns051bd_Anim = 3676, + c_pns122pr_Anim = 3677, + c_WNS050P1_Wav_3678 = 3678, + c_pns050p1_Anim = 3679, + c_pns069pr_Anim = 3680, + c_pns066db_Anim = 3681, + c_pns065rd_Anim = 3682, + c_pns067gd_Wav = 3683, + c_pns067gd_Pho = 3684, + c_pns067gd_0_sfx = 3685, + c_pns067gd_1_sfx = 3686, + c_pns067gd_2_sfx = 3687, + c_pns067gd_3_sfx = 3688, + c_pns067gd_Anim = 3689, + c_pns099pr_Anim = 3690, + c_pns098pr_Anim = 3691, + c_pns097pr_Anim = 3692, + c_pns096pr_Anim = 3693, + c_pns042bm_Anim = 3694, + c_pns048pr_Anim = 3695, + c_PNS043EN_Wav = 3696, + c_PNS043EN_Pho = 3697, + c_PNS044RE_Wav = 3698, + c_PNS044RE_Pho = 3699, + c_PNS046EN_Wav = 3700, + c_PNS046EN_Pho = 3701, + c_PNS047RE_Wav = 3702, + c_PNS047RE_Pho = 3703, + c_pns043en_Anim = 3704, + c_pns018rd_Anim = 3705, + c_pns019pr_Anim = 3706, + c_pns021dl_Anim = 3707 +}; +} // namespace IsleScript + +#endif // ISLE_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/jetrace_actions.h b/LEGO1/lego/legoomni/include/actions/jetrace_actions.h new file mode 100644 index 00000000..5cd77773 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/jetrace_actions.h @@ -0,0 +1,183 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef JETRACE_ACTIONS_H +#define JETRACE_ACTIONS_H + +namespace JetraceScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneJetrace = -1, + + c__JetRace_World = 0, + c_DistanceMeter = 1, + c_Map_Ctl = 2, + + c_Map_Up_Bitmap = 4, + c_Map_Down_Bitmap = 5, + c_JetskiLocator2 = 6, + c_JetskiLocator3 = 7, + c_StartTriggers = 8, + c_HitActorSound = 9, + c_UserJetski_Actor = 10, + c_Snap_Actor = 11, + c_Valerie_Actor = 12, + c_AirHorn_PlayWav = 13, + c_SetHitActorSound = 14, + c_HitWallSound = 15, + c_SetHitWallSound = 16, + c_RacePath = 17, + c_HideAni_Anim = 18, + c_VO1 = 19, + c_VO2 = 20, + c_VO3 = 21, + c_VO4 = 22, + c_VO5 = 23, + c_VO6 = 24, + c_VO7 = 25, + c_Jetski_Sound = 26, + c_BlackJetskiLocator = 27, + c_JsSnap00_Anim = 28, + c_JsSnap99_Anim = 29, + c_BlackJetski_Actor = 30, + c_BlackJetski_Model = 31, + c_Snap_Model = 32, + c_YellowJetskiLocator = 33, + c_JsVal00_Anim = 34, + c_JsVal99_Anim = 35, + c_JsVal04_Anim = 36, + c_YellowJetski_Actor = 37, + c_YellowJetski_Model = 38, + c_JetskiSpeedMeter = 39, + c_JetskiFuelMeter = 40, + c_JetskiDashboard11_Bitmap = 41, + c_JetskiDashboard12_Bitmap = 42, + c_JetskiDashboard13_Bitmap = 43, + c_JetskiDashboard14_Bitmap = 44, + c_JetskiDashboard15_Bitmap = 45, + c_JetskiDashboard16_Bitmap = 46, + c_Valerie_Model = 47, + c_User_Locator = 48, + c_UserJetski_Model = 49, + c_CopBoat_Actor = 50, + c_JetskiDashboard21_Bitmap = 51, + c_JetskiDashboard22_Bitmap = 52, + c_JetskiDashboard23_Bitmap = 53, + c_JetskiDashboard24_Bitmap = 54, + c_JetskiDashboard25_Bitmap = 55, + c_JetskiDashboard26_Bitmap = 56, + c_CopBoat_Model = 57, + c_L1_Actor = 58, + c_L1_Model = 59, + c_CM_Actor = 60, + c_JetskiDashboard31_Bitmap = 61, + c_JetskiDashboard32_Bitmap = 62, + c_JetskiDashboard33_Bitmap = 63, + c_JetskiDashboard34_Bitmap = 64, + c_JetskiDashboard35_Bitmap = 65, + c_JetskiDashboard36_Bitmap = 66, + c_CM_Model = 67, + c_NU_Actor = 68, + c_NU_Model = 69, + c_JK_Actor = 70, + c_JetskiDashboard41_Bitmap = 71, + c_JetskiDashboard42_Bitmap = 72, + c_JetskiDashboard43_Bitmap = 73, + c_JetskiDashboard44_Bitmap = 74, + c_JetskiDashboard45_Bitmap = 75, + c_JetskiDashboard46_Bitmap = 76, + c_JK_Model = 77, + c_BS_Actor = 78, + c_BS_Model = 79, + c_NA_Actor = 80, + c_JetskiDashboard51_Bitmap = 81, + c_JetskiDashboard52_Bitmap = 82, + c_JetskiDashboard53_Bitmap = 83, + c_JetskiDashboard54_Bitmap = 84, + c_JetskiDashboard55_Bitmap = 85, + c_JetskiDashboard56_Bitmap = 86, + c_NA_Model = 87, + c_RD_Actor = 88, + c_RD_Model = 89, + c_Cop01_Actor = 90, + c_JetskiDashboard61_Bitmap = 91, + c_JetskiDashboard62_Bitmap = 92, + c_JetskiDashboard63_Bitmap = 93, + c_JetskiDashboard64_Bitmap = 94, + c_JetskiDashboard65_Bitmap = 95, + c_JetskiDashboard66_Bitmap = 96, + c_JetskiDashboard = 97, + c_JetskiArms_Ctl = 98, + c_JetskiInfo_Ctl = 99, + c_Cop01_Model = 100, + c_Boat_Actor = 101, + c_Boat_Model = 102, + c_Shark_Actor = 103, + c_Shark_Model = 104, + c_LfJacket_Actor = 105, + c_LfJacket_Model = 106, + c_FishRod_Actor = 107, + c_FishRod_Model = 108, + c_Sharkj1_Actor = 109, + c_Sharkj1_Model = 110, + c_Trig01_Actor = 111, + c_Trig01_Model = 112, + c_Trig02_Actor = 113, + c_Trig02_Model = 114, + c_Trig03_Actor = 115, + c_Trig03_Model = 116, + c_Trig04_Actor = 117, + c_Trig04_Model = 118, + c_BouyBump_Actor = 119, + c_BouyBump_Model = 120, + c_Brickster_Actor = 121, + c_Brickster_Model = 122, + c_Yeeheemx_Sound = 123, + c_Bronco_Anim = 124, + c_Cboycycl_Actor = 125, + c_Cboycycl_Model = 126, + c_Shkbrnco_Actor = 127, + c_Shkbrnco_Model = 128, + c_Shrkfast_Anim = 129, + c_Sharkswm_Actor = 130, + c_Sharkswm_Model = 131, + c_Splash1_Sound = 132, + c_Shrkjump_Anim = 133, + c_Shkjmcyc_Actor = 134, + c_Shkjmcyc_Model = 135, + c_JetskiArms_Mask_Bitmap = 136, + c_JetskiInfoUp_Bitmap = 137, + c_JetskiInfoDown_Bitmap = 138, + c_sjs012in_Wav_500 = 139, + c_sjs012in_Pho_500 = 140, + c_sjs012in_0_sfx = 141, + c_sjs012in_1_sfx = 142, + c_sjs012in_2_sfx = 143, + c_sjs012in_3_sfx = 144, + c_sjs012in_4_sfx = 145, + c_sjs012in_Anim = 146, + c_sjs013in_Wav_501 = 147, + c_sjs013in_Pho_501 = 148, + c_sjs013in_0_sfx = 149, + c_sjs013in_1_sfx = 150, + c_sjs013in_2_sfx = 151, + c_sjs013in_3_sfx = 152, + c_sjs013in_Anim = 153, + c_sjs014in_Wav_502 = 154, + c_sjs014in_Pho_502 = 155, + c_sjs014in_0_sfx = 156, + c_sjs014in_1_sfx = 157, + c_sjs014in_2_sfx = 158, + c_sjs014in_3_sfx = 159, + c_sjs014in_Anim = 160, + + c_sjs012in_RunAnim = 500, + c_sjs013in_RunAnim = 501, + c_sjs014in_RunAnim = 502 +}; +} // namespace JetraceScript + +#endif // JETRACE_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/jetracer_actions.h b/LEGO1/lego/legoomni/include/actions/jetracer_actions.h new file mode 100644 index 00000000..0b8aa2c3 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/jetracer_actions.h @@ -0,0 +1,29 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef JETRACER_ACTIONS_H +#define JETRACER_ACTIONS_H + +namespace JetracerScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneJetracer = -1, + + c_Trigger200_Drown = 200, + c_Trigger201_BtShark = 201, + c_Trigger202_SwimShrk = 202, + c_Trigger203_Hover_Anim = 203, + c_Trigger204_SwimSj01 = 204, + c_Trigger205_BtShark1 = 205, + c_Trigger206_ShrkJum1 = 206, + c_Trigger207_TriSpin = 207, + c_Trigger208_TriSpin01 = 208, + c_Trigger209_SwimBouy = 209, + c_Trigger210_SwimSJ02 = 210 +}; +} // namespace JetracerScript + +#endif // JETRACER_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/jetski_actions.h b/LEGO1/lego/legoomni/include/actions/jetski_actions.h new file mode 100644 index 00000000..ccdb5689 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/jetski_actions.h @@ -0,0 +1,217 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef JETSKI_ACTIONS_H +#define JETSKI_ACTIONS_H + +namespace JetskiScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneJetski = -1, + + c__StartUp = 0, + + c_Jetski_Actor = 3, + + c_Info_Ctl = 5, + c_Exit_Ctl = 6, + c_ShelfUp_Ctl = 7, + c_Platform_Ctl = 8, + + c_Background = 64, + c_ColorBook_Bitmap = 65, + c_ShelfUp_Up_Bitmap = 66, + c_ShelfUp_Down_Bitmap = 67, + c_PlatformUp_Bitmap = 68, + c_PlatformLeft = 69, + c_Rotate_Sound = 70, + c_PlatformLeft_Bitmap = 71, + c_Yellow_Ctl = 72, + c_Yellow_Up_Bitmap = 73, + c_Yellow_Down_Bitmap = 74, + c_Red_Ctl = 75, + c_Red_Up_Bitmap = 76, + c_Red_Down_Bitmap = 77, + c_Blue_Ctl = 78, + c_Blue_Up_Bitmap = 79, + c_Blue_Down_Bitmap = 80, + c_Green_Ctl = 81, + c_Green_Up_Bitmap = 82, + c_Green_Down_Bitmap = 83, + c_Gray_Ctl = 84, + c_Gray_Up_Bitmap = 85, + c_Gray_Down_Bitmap = 86, + c_Black_Ctl = 87, + c_Black_Up_Bitmap = 88, + c_Black_Down_Bitmap = 89, + c_Info_Up_Bitmap = 90, + c_Info_Down_Bitmap = 91, + c_Exit_Up_Bitmap = 92, + c_Exit_Down_Bitmap = 93, + c_Decal_Bitmap = 94, + c_Decals_Ctl = 95, + c_JSFRNT_T1_Up = 96, + c_JSFRNT_T1_Up_Bitmap = 97, + c_JSFRNT_T1_Dn = 98, + c_JSFRNT_T1_Dn_Bitmap = 99, + c_JSFRNT_Texture_1 = 100, + c_Decals_Ctl1 = 101, + c_JSFRNT_T2_Up = 102, + c_JSFRNT_T2_Up_Bitmap = 103, + c_JSFRNT_T2_Dn = 104, + c_JSFRNT_T2_Dn_Bitmap = 105, + c_JSFRNT_Texture_2 = 106, + c_Decals_Ctl2 = 107, + c_JSFRNT_B1_Up = 108, + c_JSFRNT_B1_Up_Bitmap = 109, + c_JSFRNT_B1_Dn = 110, + c_JSFRNT_B1_Dn_Bitmap = 111, + c_JSFRNT_Texture_3 = 112, + c_Decals_Ctl3 = 113, + c_JSFRNT_B2_Up = 114, + c_JSFRNT_B2_Up_Bitmap = 115, + c_JSFRNT_B2_Dn = 116, + c_JSFRNT_B2_Dn_Bitmap = 117, + c_JSFRNT_Texture_4 = 118, + c_Decals_Ctl4 = 119, + c_JSWNSH_T1_Up = 120, + c_JSWNSH_T1_Up_Bitmap = 121, + c_JSWNSH_T1_Dn = 122, + c_JSWNSH_T1_Dn_Bitmap = 123, + c_JSWNSH_Texture_1 = 124, + c_Decals_Ctl5 = 125, + c_JSWNSH_T2_Up = 126, + c_JSWNSH_T2_Up_Bitmap = 127, + c_JSWNSH_T2_Dn = 128, + c_JSWNSH_T2_Dn_Bitmap = 129, + c_JSWNSH_Texture_2 = 130, + c_Decals_Ctl6 = 131, + c_JSWNSH_B1_Up = 132, + c_JSWNSH_B1_Up_Bitmap = 133, + c_JSWNSH_B1_Dn = 134, + c_JSWNSH_B1_Dn_Bitmap = 135, + c_JSWNSH_Texture_3 = 136, + c_Decals_Ctl7 = 137, + c_JSWNSH_B2_Up = 138, + c_JSWNSH_B2_Up_Bitmap = 139, + c_JSWNSH_B2_Dn = 140, + c_JSWNSH_B2_Dn_Bitmap = 141, + c_JSWNSH_Texture_4 = 142, + c_Shelf_Sound = 143, + c_PlaceBrick_Sound = 144, + c_GetBrick_Sound = 145, + c_Paint_Sound = 146, + c_Decal_Sound = 147, + c_Build_Animation = 148, + c_Build_Anim0 = 149, + c_Build_Anim1 = 150, + c_Build_Anim2 = 151, + c_Jsuser_Model = 152, + c_IJS001D4_Wav_500 = 153, + c_IJS001D4_Pho_500 = 154, + c_IJS002D4_Wav_500 = 155, + c_IJS002D4_Pho_500 = 156, + c_ijs001d4_0_sfx = 157, + c_ijs001d4_1_sfx = 158, + c_ijs001d4_2_sfx = 159, + c_ijs001d4_3_sfx = 160, + c_ijs001d4_4_sfx = 161, + c_ijs001d4_5_sfx = 162, + c_ijs001d4_6_sfx = 163, + c_ijs001d4_7_sfx = 164, + c_ijs001d4_8_sfx = 165, + c_ijs001d4_9_sfx = 166, + c_ijs001d4_10_sfx = 167, + c_ijs001d4_11_sfx = 168, + c_ijs001d4_12_sfx = 169, + c_ijs001d4_13_sfx = 170, + c_ijs001d4_14_sfx = 171, + c_ijs001d4_15_sfx = 172, + c_ijs001d4_Anim = 173, + c_IJSxx2D4_Wav_501 = 174, + c_IJSxx2D4_Pho_501 = 175, + c_ijsxx2d4_0_sfx = 176, + c_ijsxx2d4_1_sfx = 177, + c_ijsxx2d4_2_sfx = 178, + c_ijsxx2d4_3_sfx = 179, + c_ijsxx2d4_4_sfx = 180, + c_ijsxx2d4_5_sfx = 181, + c_ijsxx2d4_6_sfx = 182, + c_ijsxx2d4_Anim = 183, + c_IJS003D4_Wav_502 = 184, + c_IJS003D4_Pho_502 = 185, + c_ijs003d4_0_sfx = 186, + c_ijs003d4_1_sfx = 187, + c_ijs003d4_Anim = 188, + c_IJS004D4_Wav_503 = 189, + c_IJS004D4_Pho_503 = 190, + c_ijs004d4_0_sfx = 191, + c_ijs004d4_1_sfx = 192, + c_ijs004d4_2_sfx = 193, + c_ijs004d4_3_sfx = 194, + c_ijs004d4_4_sfx = 195, + c_ijs004d4_5_sfx = 196, + c_ijs004d4_Anim = 197, + c_IJS005D4_Wav_504 = 198, + c_IJS005D4_Pho_504 = 199, + c_ijs005d4_0_sfx = 200, + c_ijs005d4_1_sfx = 201, + c_ijs005d4_2_sfx = 202, + c_ijs005d4_3_sfx = 203, + c_ijs005d4_4_sfx = 204, + c_ijs005d4_5_sfx = 205, + c_ijs005d4_6_sfx = 206, + c_ijs005d4_7_sfx = 207, + c_ijs005d4_8_sfx = 208, + c_ijs005d4_9_sfx = 209, + c_ijs005d4_10_sfx = 210, + c_ijs005d4_11_sfx = 211, + c_ijs005d4_12_sfx = 212, + c_ijs005d4_Anim = 213, + c_IJS006D4_Wav_505 = 214, + c_IJS006D4_Pho_505 = 215, + c_ijs006d4_0_sfx = 216, + c_ijs006d4_1_sfx = 217, + c_ijs006d4_2_sfx = 218, + c_ijs006d4_3_sfx = 219, + c_ijs006d4_4_sfx = 220, + c_ijs006d4_5_sfx = 221, + c_ijs006d4_6_sfx = 222, + c_ijs006d4_7_sfx = 223, + c_ijs006d4_8_sfx = 224, + c_ijs006d4_9_sfx = 225, + c_ijs006d4_10_sfx = 226, + c_ijs006d4_11_sfx = 227, + c_ijs006d4_12_sfx = 228, + c_ijs006d4_13_sfx = 229, + c_ijs006d4_14_sfx = 230, + c_ijs006d4_15_sfx = 231, + c_ijs006d4_16_sfx = 232, + c_ijs006d4_Anim = 233, + c_IJS007D4_Wav_506 = 234, + c_IJS007D4_Pho_506 = 235, + c_ijs007d4_0_sfx = 236, + c_ijs007d4_1_sfx = 237, + c_ijs007d4_2_sfx = 238, + c_ijs007d4_3_sfx = 239, + c_ijs007d4_4_sfx = 240, + c_ijs007d4_5_sfx = 241, + c_ijs007d4_6_sfx = 242, + c_ijs007d4_7_sfx = 243, + c_ijs007d4_8_sfx = 244, + c_ijs007d4_Anim = 245, + + c_ijs001d4_RunAnim = 500, + c_ijsxx2d4_RunAnim = 501, + c_ijs003d4_RunAnim = 502, + c_ijs004d4_RunAnim = 503, + c_ijs005d4_RunAnim = 504, + c_ijs006d4_RunAnim = 505, + c_ijs007d4_RunAnim = 506 +}; +} // namespace JetskiScript + +#endif // JETSKI_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/jukebox_actions.h b/LEGO1/lego/legoomni/include/actions/jukebox_actions.h new file mode 100644 index 00000000..56149d88 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/jukebox_actions.h @@ -0,0 +1,86 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef JUKEBOX_ACTIONS_H +#define JUKEBOX_ACTIONS_H + +namespace JukeboxScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneJukebox = -1, + + c_MusicTheme1 = 0, + c_MusicTheme3 = 1, + c_Act2Cave = 2, + c_BrickstrChase = 3, + c_BrickHunt = 4, + c_ResidentalArea_Music = 5, + c_BeachBlvd_Music = 6, + c_Cave_Music = 7, + c_CentralRoads_Music = 8, + c_Jail_Music = 9, + c_Hospital_Music = 10, + c_InformationCenter_Music = 11, + c_PoliceStation_Music = 12, + c_Park_Music = 13, + c_CentralNorthRoad_Music = 14, + c_GarageArea_Music = 15, + c_RaceTrackRoad_Music = 16, + c_Beach_Music = 17, + c_Quiet_Audio = 18, + c_JetskiRace_Music = 19, + c_Act3Music = 20, + c_sns002ra_Audio = 21, + c_sns001ja_Audio = 22, + c_snsc01js_Audio = 23, + c_snsb01js_Audio = 24, + c_snsa01js_Audio = 25, + c_sns009ra_Audio = 26, + c_ham035ra_Audio = 27, + c_ham039ra_Audio = 28, + c_sns005ra_Audio = 29, + c_sns078pa_Audio = 30, + c_ham036ra_Audio = 31, + c_sns006ra_Audio = 32, + c_sns013ra_Audio = 33, + c_sns004ra_Audio = 34, + c_sns079pa_Audio = 35, + c_sns007ra_Audio = 36, + c_sns008ra_Audio = 37, + c_hpz037ma_Audio = 38, + c_sns003ra_Audio = 39, + c_sns010ra_Audio = 40, + c_Radio1_Music = 41, + c_Radio2_Music = 42, + c_Radio3_Music = 43, + c_Radio4_Music = 44, + c_Radio5_Music = 45, + c_Radio6_Music = 46, + c_HelicopterBuild_Movie = 47, + c_HelicopterBuild_Music = 48, + c_DuneCarBuild_Movie = 49, + c_DuneCarBuild_Music = 50, + c_JetskiBuild_Movie = 51, + c_JetskiBuild_Music = 52, + c_RaceCarBuild_Movie = 53, + c_RaceCarBuild_Music = 54, + c_JBMusic1 = 55, + c_JBMusic2 = 56, + c_JBMusic3 = 57, + c_JBMusic4 = 58, + c_JBMusic5 = 59, + c_JBMusic6 = 60, + c_InfoCenter_3rd_Floor_Music = 61, + c_Elevator_Music = 62, + c_PizzaMission_Music = 63, + c_HelicopterBuild_Flic = 64, + c_DuneCarBuild_Flic = 65, + c_JetskiBuild_Flic = 66, + c_RaceCarBuild_Flic = 67 +}; +} // namespace JukeboxScript + +#endif // JUKEBOX_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/jukeboxw_actions.h b/LEGO1/lego/legoomni/include/actions/jukeboxw_actions.h new file mode 100644 index 00000000..17af33bf --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/jukeboxw_actions.h @@ -0,0 +1,40 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef JUKEBOXW_ACTIONS_H +#define JUKEBOXW_ACTIONS_H + +namespace JukeboxwScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneJukeboxw = -1, + + c__StartUp = 0, + c_Voldown_Ctl = 1, + c_Volup_Ctl = 2, + c_Dback_Ctl = 3, + c_Dfwd_Ctl = 4, + c_Note_Ctl = 5, + c_Background_Bitmap = 6, + c_Right_Bitmap = 7, + c_Decal_Bitmap = 8, + c_Wallis_Bitmap = 9, + c_Nelson_Bitmap = 10, + c_Torpedos_Bitmap = 11, + c_Voldown_Up_Bitmap = 12, + c_Voldown_Down_Bitmap = 13, + c_Volup_Up_Bitmap = 14, + c_Volup_Down_Bitmap = 15, + c_Dback_Up_Bitmap = 16, + c_Dback_Down_Bitmap = 17, + c_Dfwd_Up_Bitmap = 18, + c_Dfwd_Down_Bitmap = 19, + c_Note_Up_Bitmap = 20, + c_Note_Down_Bitmap = 21 +}; +} // namespace JukeboxwScript + +#endif // JUKEBOXW_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/nocd_actions.h b/LEGO1/lego/legoomni/include/actions/nocd_actions.h new file mode 100644 index 00000000..cd2e664e --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/nocd_actions.h @@ -0,0 +1,21 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef NOCD_ACTIONS_H +#define NOCD_ACTIONS_H + +namespace NocdScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneNocd = -1, + + c_NoCD_Movie = 0, + c_CDSpin1_Smk = 1, + c_Iicx62In_Wave = 2 +}; +} // namespace NocdScript + +#endif // NOCD_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/police_actions.h b/LEGO1/lego/legoomni/include/actions/police_actions.h new file mode 100644 index 00000000..146756d0 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/police_actions.h @@ -0,0 +1,55 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef POLICE_ACTIONS_H +#define POLICE_ACTIONS_H + +namespace PoliceScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_nonePolice = -1, + + c__StartUp = 0, + c_LeftArrow_Ctl = 1, + c_RightArrow_Ctl = 2, + c_Info_Ctl = 3, + c_Door_Ctl = 4, + c_Donut_Ctl = 5, + c_Background_Bitmap = 6, + c_LeftArrow_Up_Bitmap = 7, + c_LeftArrow_Down_Bitmap = 8, + c_RightArrow_Up_Bitmap = 9, + c_RightArrow_Down_Bitmap = 10, + c_Info_Up_Bitmap = 11, + c_Info_Down_Bitmap = 12, + c_Door_Mask_Bitmap = 13, + c_Donut_Up_Bitmap = 14, + c_Donut_Down_Bitmap = 15, + c_RadioOff_Bitmap = 16, + c_RadioOn_Bitmap = 17, + c_Radio_Ctl = 18, + c_ConfigAnimation = 19, + c_nps001ni_0_sfx = 20, + c_nps001ni_1_sfx = 21, + c_nps001ni_2_sfx = 22, + c_nps001ni_3_sfx = 23, + c_nps001ni_4_sfx = 24, + c_nps001ni_5_sfx = 25, + c_nps001ni_Anim = 26, + c_nps002la_0_sfx = 27, + c_nps002la_1_sfx = 28, + c_nps002la_2_sfx = 29, + c_nps002la_3_sfx = 30, + c_nps002la_4_sfx = 31, + c_nps002la_5_sfx = 32, + c_nps002la_Anim = 33, + + c_nps001ni_RunAnim = 500, + c_nps002la_RunAnim = 501 +}; +} // namespace PoliceScript + +#endif // POLICE_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/racecar_actions.h b/LEGO1/lego/legoomni/include/actions/racecar_actions.h new file mode 100644 index 00000000..0293c25b --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/racecar_actions.h @@ -0,0 +1,179 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef RACECAR_ACTIONS_H +#define RACECAR_ACTIONS_H + +namespace RacecarScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneRacecar = -1, + + c__StartUp = 0, + + c_RaceCar_Actor = 4, + c_Info_Ctl = 5, + c_Exit_Ctl = 6, + c_ShelfUp_Ctl = 7, + c_Platform_Ctl = 8, + + c_Background = 64, + c_ColorBook_Bitmap = 65, + c_ShelfUp_Up_Bitmap = 66, + c_ShelfUp_Down_Bitmap = 67, + c_PlatformUp_Bitmap = 68, + c_PlatformLeft = 69, + c_Rotate_Sound = 70, + c_PlatformLeft_Bitmap = 71, + c_Yellow_Ctl = 72, + c_Yellow_Down_Bitmap = 73, + c_Yellow_Up_Bitmap = 74, + c_Red_Ctl = 75, + c_Red_Down_Bitmap = 76, + c_Red_Up_Bitmap = 77, + c_Blue_Ctl = 78, + c_Blue_Down_Bitmap = 79, + c_Blue_Up_Bitmap = 80, + c_Green_Ctl = 81, + c_Green_Down_Bitmap = 82, + c_Green_Up_Bitmap = 83, + c_Gray_Ctl = 84, + c_Gray_Down_Bitmap = 85, + c_Gray_Up_Bitmap = 86, + c_Black_Ctl = 87, + c_Black_Down_Bitmap = 88, + c_Black_Up_Bitmap = 89, + c_Decals_Ctl = 90, + c_RCFRNT_State_0 = 91, + c_RCFRNT_State_0_Bitmap = 92, + c_RCFRNT_State_1 = 93, + c_RCFRNT_State_1_Bitmap = 94, + c_RCFRNT_Texture_1 = 95, + c_RCFRNT_State_2 = 96, + c_RCFRNT_State_2_Bitmap = 97, + c_RCFRNT_Texture_2 = 98, + c_RCFRNT_State_3 = 99, + c_RCFRNT_State_3_Bitmap = 100, + c_RCFRNT_Texture_3 = 101, + c_RCFRNT_State_4 = 102, + c_RCFRNT_State_4_Bitmap = 103, + c_RCFRNT_Texture_4 = 104, + c_Decals_Ctl1 = 105, + c_RCBACK_State_0 = 106, + c_RCBACK_State_0_Bitmap = 107, + c_RCBACK_State_1 = 108, + c_RCBACK_State_1_Bitmap = 109, + c_RCBACK_Texture_1 = 110, + c_RCBACK_State_2 = 111, + c_RCBACK_State_2_Bitmap = 112, + c_RCBACK_Texture_2 = 113, + c_RCBACK_State_3 = 114, + c_RCBACK_State_3_Bitmap = 115, + c_RCBACK_Texture_3 = 116, + c_RCBACK_State_4 = 117, + c_RCBACK_State_4_Bitmap = 118, + c_RCBACK_Texture_4 = 119, + c_Decals_Ctl2 = 120, + c_RCTAIL_State_0 = 121, + c_RCTAIL_State_0_Bitmap = 122, + c_RCTAIL_State_1 = 123, + c_RCTAIL_State_1_Bitmap = 124, + c_RCTAIL_Texture_1 = 125, + c_RCTAIL_State_2 = 126, + c_RCTAIL_State_2_Bitmap = 127, + c_RCTAIL_Texture_2 = 128, + c_RCTAIL_State_3 = 129, + c_RCTAIL_State_3_Bitmap = 130, + c_RCTAIL_Texture_3 = 131, + c_RCTAIL_State_4 = 132, + c_RCTAIL_State_4_Bitmap = 133, + c_RCTAIL_Texture_4 = 134, + c_Info_Up_Bitmap = 135, + c_Info_Down_Bitmap = 136, + c_Exit_Up_Bitmap = 137, + c_Exit_Down_Bitmap = 138, + c_Shelf_Sound = 139, + c_PlaceBrick_Sound = 140, + c_GetBrick_Sound = 141, + c_Paint_Sound = 142, + c_Decal_Sound = 143, + c_Build_Animation = 144, + c_Build_Anim0 = 145, + c_Build_Anim1 = 146, + c_Build_Anim2 = 147, + c_Rcuser_Model = 148, + c_IRT001D1_Wav_500 = 149, + c_IRT001D1_Pho_500 = 150, + c_irt001d1_0_sfx = 151, + c_irt001d1_1_sfx = 152, + c_irt001d1_2_sfx = 153, + c_irt001d1_3_sfx = 154, + c_irt001d1_4_sfx = 155, + c_irt001d1_5_sfx = 156, + c_irt001d1_Anim = 157, + c_IRT002D1_Wav_501 = 158, + c_IRT002D1_Pho_501 = 159, + c_irt002d1_0_sfx = 160, + c_irt002d1_1_sfx = 161, + c_irt002d1_2_sfx = 162, + c_irt002d1_Anim = 163, + c_IRT003D1_Wav_502 = 164, + c_IRT003D1_Pho_502 = 165, + c_irt003d1_0_sfx = 166, + c_irt003d1_1_sfx = 167, + c_irt003d1_2_sfx = 168, + c_irt003d1_3_sfx = 169, + c_irt003d1_4_sfx = 170, + c_irt003d1_5_sfx = 171, + c_irt003d1_6_sfx = 172, + c_irt003d1_7_sfx = 173, + c_irt003d1_Anim = 174, + c_IRT004D1_Wav_503 = 175, + c_IRT004D1_Pho_503 = 176, + c_irt004d1_0_sfx = 177, + c_irt004d1_1_sfx = 178, + c_irt004d1_2_sfx = 179, + c_irt004d1_3_sfx = 180, + c_irt004d1_4_sfx = 181, + c_irt004d1_Anim = 182, + c_IRTXX4D1_Wav_504 = 183, + c_IRTXX4D1_Pho_504 = 184, + c_irtxx4d1_0_sfx = 185, + c_irtxx4d1_1_sfx = 186, + c_irtxx4d1_2_sfx = 187, + c_irtxx4d1_3_sfx = 188, + c_irtxx4d1_4_sfx = 189, + c_irtxx4d1_5_sfx = 190, + c_irtxx4d1_6_sfx = 191, + c_irtxx4d1_Anim = 192, + c_IRT005D1_Wav_505 = 193, + c_IRT005D1_Pho_505 = 194, + c_irt005d1_0_sfx = 195, + c_irt005d1_1_sfx = 196, + c_irt005d1_2_sfx = 197, + c_irt005d1_3_sfx = 198, + c_irt005d1_4_sfx = 199, + c_irt005d1_5_sfx = 200, + c_irt005d1_6_sfx = 201, + c_irt005d1_7_sfx = 202, + c_irt005d1_8_sfx = 203, + c_irt005d1_9_sfx = 204, + c_irt005d1_10_sfx = 205, + c_irt005d1_11_sfx = 206, + c_irt005d1_12_sfx = 207, + c_irt005d1_13_sfx = 208, + c_irt005d1_Anim = 209, + + c_irt001d1_RunAnim = 500, + c_irt002d1_RunAnim = 501, + c_irt003d1_RunAnim = 502, + c_irt004d1_RunAnim = 503, + c_irtxx4d1_RunAnim = 504, + c_irt005d1_RunAnim = 505 +}; +} // namespace RacecarScript + +#endif // RACECAR_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/regbook_actions.h b/LEGO1/lego/legoomni/include/actions/regbook_actions.h new file mode 100644 index 00000000..e90b40b5 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/regbook_actions.h @@ -0,0 +1,180 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef REGBOOK_ACTIONS_H +#define REGBOOK_ACTIONS_H + +namespace RegbookScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneRegbook = -1, + + c__StartUp = 0, + c_RB_Helicopter_Actor = 1, + c_RB_DuneBugy_Actor = 2, + c_RB_Jetski_Actor = 3, + c_RB_RaceCar_Actor = 4, + c_Alphabet_Ctl = 5, + c_A_Bitmap = 6, + c_B_Bitmap = 7, + c_C_Bitmap = 8, + c_D_Bitmap = 9, + + c_Infoman_Entity = 12, + c_E_Bitmap = 13, + c_F_Bitmap = 14, + c_G_Bitmap = 15, + c_H_Bitmap = 16, + c_I_Bitmap = 17, + c_J_Bitmap = 18, + c_K_Bitmap = 19, + c_L_Bitmap = 20, + c_M_Bitmap = 21, + c_N_Bitmap = 22, + c_O_Bitmap = 23, + c_P_Bitmap = 24, + c_Q_Bitmap = 25, + c_R_Bitmap = 26, + c_S_Bitmap = 27, + c_T_Bitmap = 28, + c_U_Bitmap = 29, + c_V_Bitmap = 30, + c_W_Bitmap = 31, + c_X_Bitmap = 32, + c_Y_Bitmap = 33, + c_Z_Bitmap = 34, + c_Infoman_Model = 35, + c_Background_Bitmap = 36, + c_CheckHiLite_Bitmap = 37, + c_Alphabet_Mask_Bitmap = 38, + c_A_Down_Bitmap = 39, + c_B_Down_Bitmap = 40, + c_C_Down_Bitmap = 41, + c_D_Down_Bitmap = 42, + c_E_Down_Bitmap = 43, + c_F_Down_Bitmap = 44, + c_G_Down_Bitmap = 45, + c_H_Down_Bitmap = 46, + c_I_Down_Bitmap = 47, + c_J_Down_Bitmap = 48, + c_K_Down_Bitmap = 49, + c_L_Down_Bitmap = 50, + c_M_Down_Bitmap = 51, + c_N_Down_Bitmap = 52, + c_O_Down_Bitmap = 53, + c_P_Down_Bitmap = 54, + c_Textures = 55, + c_Q_Down_Bitmap = 56, + c_R_Down_Bitmap = 57, + c_S_Down_Bitmap = 58, + c_T_Down_Bitmap = 59, + c_U_Down_Bitmap = 60, + c_V_Down_Bitmap = 61, + c_W_Down_Bitmap = 62, + c_X_Down_Bitmap = 63, + c_Y_Down_Bitmap = 64, + c_Z_Down_Bitmap = 65, + c_Back_Down_Bitmap = 66, + c_Info_Down_Bitmap = 67, + c_Check0_Ctl = 68, + c_Check0_Bitmap_69 = 69, + c_Check0_Bitmap_70 = 70, + c_Check1_Ctl = 71, + c_Check1_Bitmap_72 = 72, + c_Check1_Bitmap_73 = 73, + c_Check2_Ctl = 74, + c_Check2_Bitmap_75 = 75, + c_Check2_Bitmap_76 = 76, + c_Check3_Ctl = 77, + c_Check3_Bitmap_78 = 78, + c_Check3_Bitmap_79 = 79, + c_Check4_Ctl = 80, + c_Check4_Bitmap_81 = 81, + c_Check4_Bitmap_82 = 82, + c_Check5_Ctl = 83, + c_Check5_Bitmap_84 = 84, + c_Check5_Bitmap_85 = 85, + c_Check6_Ctl = 86, + c_Check6_Bitmap_87 = 87, + c_Check6_Bitmap_88 = 88, + c_Check7_Ctl = 89, + c_Check7_Bitmap_90 = 90, + c_Check7_Bitmap_91 = 91, + c_Check8_Ctl = 92, + c_Check8_Bitmap_93 = 93, + c_Check8_Bitmap_94 = 94, + c_Check9_Ctl = 95, + c_Check9_Bitmap_96 = 96, + c_Check9_Bitmap_97 = 97, + c_ConfigAnimation = 98, + c_Chptr_Model = 99, + c_DuneBugy_Model = 100, + c_Jsuser_Model = 101, + c_Rcuser_Model = 102, + c_CHWIND_Texture_1 = 103, + c_CHJETL_Texture_1 = 104, + c_CHJETR_Texture_1 = 105, + c_Decal_Texture_1 = 106, + c_JSFRNT_Texture_1 = 107, + c_JSWNSH_Texture_1 = 108, + c_RCFRNT_Texture_1 = 109, + c_RCBACK_Texture_1 = 110, + c_RCTAIL_Texture_1 = 111, + c_iic006in_Wav_500 = 112, + c_iic006in_Pho_500 = 113, + c_iic006in_0_sfx = 114, + c_iic006in_1_sfx = 115, + c_iic006in_2_sfx = 116, + c_iic006in_3_sfx = 117, + c_iic006in_Anim = 118, + c_IIC010IN_Wav_501 = 119, + c_IIC010IN_Pho_501 = 120, + c_iic010in_0_sfx = 121, + c_iic010in_1_sfx = 122, + c_iic010in_2_sfx = 123, + c_iic010in_3_sfx = 124, + c_iic010in_4_sfx = 125, + c_iic010in_5_sfx = 126, + c_iic010in_6_sfx = 127, + c_iic010in_7_sfx = 128, + c_iic010in_8_sfx = 129, + c_iic010in_9_sfx = 130, + c_iic010in_Anim = 131, + c_IIC012IN_Wav_502 = 132, + c_IIC012IN_Pho_502 = 133, + c_iic012in_0_sfx = 134, + c_iic012in_1_sfx = 135, + c_iic012in_2_sfx = 136, + c_iic012in_3_sfx = 137, + c_iic012in_4_sfx = 138, + c_iic012in_5_sfx = 139, + c_iic012in_6_sfx = 140, + c_iic012in_7_sfx = 141, + c_iic012in_Anim = 142, + c_iic014in_Wav_503 = 143, + c_iic014in_Pho_503 = 144, + c_iic014in_0_sfx = 145, + c_iic014in_1_sfx = 146, + c_iic014in_2_sfx = 147, + c_iic014in_3_sfx = 148, + c_iic014in_4_sfx = 149, + c_iic014in_5_sfx = 150, + c_iic014in_6_sfx = 151, + c_iic014in_7_sfx = 152, + c_iic014in_8_sfx = 153, + c_iic014in_Anim = 154, + + c_iic006in_RunAnim = 500, + c_iic010in_RunAnim = 501, + c_iic012in_RunAnim = 502, + c_iic014in_RunAnim = 503, + c_iic009in_PlayWav = 504, + c_iic007in_PlayWav = 505, + c_iic008in_PlayWav = 506 +}; +} // namespace RegbookScript + +#endif // REGBOOK_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/actions/sndanim_actions.h b/LEGO1/lego/legoomni/include/actions/sndanim_actions.h new file mode 100644 index 00000000..96b23c93 --- /dev/null +++ b/LEGO1/lego/legoomni/include/actions/sndanim_actions.h @@ -0,0 +1,83 @@ +// This file was automatically generated by the actionheadergen tool. +// Please do not manually edit this file. +#ifndef SNDANIM_ACTIONS_H +#define SNDANIM_ACTIONS_H + +namespace SndanimScript +{ +#if __cplusplus >= 201103L +enum Script : int { +#else +enum Script { +#endif + c_noneSndanim = -1, + + c_SoundAndAnim_Action = 0, + + c_ThisFilename = 4, + + c_AnimC1 = 10, + c_AnimC2 = 11, + c_AnimC3 = 12, + c_AnimC4 = 13, + + c_AnimF1 = 30, + c_AnimF2 = 31, + c_AnimF3 = 32, + c_AnimT1 = 33, + c_AnimT2 = 34, + c_AnimT3 = 35, + c_AnimB1 = 36, + c_AnimB2 = 37, + c_AnimB3 = 38, + c_AnimP1 = 39, + c_AnimP2 = 40, + c_AnimP3 = 41, + + c_Sound1 = 50, + c_Sound2 = 51, + c_Sound3 = 52, + c_Sound4 = 53, + c_Sound5 = 54, + c_Sound6 = 55, + c_Sound7 = 56, + c_Sound8 = 57, + c_Sound9 = 58, + c_Sound10 = 59, + c_Sound11 = 60, + c_Sound12 = 61, + c_Sound13 = 62, + c_Sound14 = 63, + c_Sound15 = 64, + c_Sound16 = 65, + c_Sound17 = 66, + c_Sound18 = 67, + c_Sound19 = 68, + c_Sound20 = 69, + c_AnimBld1 = 70, + c_AnimBld2 = 71, + c_AnimBld3 = 72, + c_AnimBld4 = 73, + c_AnimBld5 = 74, + c_AnimBld6 = 75, + c_AnimBld7 = 76, + c_AnimBld8 = 77, + c_AnimBld9 = 78, + c_AnimBld10 = 79, + c_AnimBld11 = 80, + c_AnimBld12 = 81, + c_AnimBld13 = 82, + c_AnimBld14 = 83, + c_AnimBld15 = 84, + c_AnimBld16 = 85, + c_AnimBld17 = 86, + c_AnimBld18 = 87, + + c_TRS302_OpenJailDoor = 302, + c_BRS303_CloseJailDoor = 303, + + c_BookWig_Flic = 400 +}; +} // namespace SndanimScript + +#endif // SNDANIM_ACTIONS_H diff --git a/LEGO1/lego/legoomni/include/ambulance.h b/LEGO1/lego/legoomni/include/ambulance.h new file mode 100644 index 00000000..1aff83a0 --- /dev/null +++ b/LEGO1/lego/legoomni/include/ambulance.h @@ -0,0 +1,60 @@ +#ifndef AMBULANCE_H +#define AMBULANCE_H + +#include "islepathactor.h" + +class AmbulanceMissionState; + +// VTABLE: LEGO1 0x100d71a8 +// SIZE 0x184 +class Ambulance : public IslePathActor { +public: + Ambulance(); + ~Ambulance() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x10035fa0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03c4 + return "Ambulance"; + } + + // FUNCTION: LEGO1 0x10035fb0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Ambulance::ClassName()) || IslePathActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void Destroy(MxBool p_fromDestructor) override; // vtable+0x1c + void VTable0x70(float p_float) override; // vtable+0x70 + MxU32 VTable0xcc() override; // vtable+0xcc + MxU32 VTable0xd4(LegoControlManagerEvent& p_param) override; // vtable+0xd4 + MxU32 VTable0xdc(MxType19NotificationParam&) override; // vtable+0xdc + void VTable0xe4() override; // vtable+0xe4 + + void FUN_10036e60(); + void FUN_10037060(); + + // SYNTHETIC: LEGO1 0x10036130 + // Ambulance::`scalar deleting destructor' + +private: + undefined m_unk0x160[4]; // 0x160 + AmbulanceMissionState* m_state; // 0x164 + MxS16 m_unk0x168; // 0x168 + MxS16 m_unk0x16a; // 0x16a + MxS16 m_unk0x16c; // 0x16c + MxS16 m_unk0x16e; // 0x16e + MxS16 m_unk0x170; // 0x170 + MxS16 m_unk0x172; // 0x172 + MxS32 m_unk0x174; // 0x174 + MxS32 m_unk0x178; // 0x178 + MxFloat m_unk0x17c; // 0x17c + MxFloat m_time; // 0x180 +}; + +#endif // AMBULANCE_H diff --git a/LEGO1/lego/legoomni/include/ambulancemissionstate.h b/LEGO1/lego/legoomni/include/ambulancemissionstate.h new file mode 100644 index 00000000..88bcf4b8 --- /dev/null +++ b/LEGO1/lego/legoomni/include/ambulancemissionstate.h @@ -0,0 +1,65 @@ +#ifndef AMBULANCEMISSIONSTATE_H +#define AMBULANCEMISSIONSTATE_H + +#include "legostate.h" + +// VTABLE: LEGO1 0x100d72a0 +// SIZE 0x24 +class AmbulanceMissionState : public LegoState { +public: + AmbulanceMissionState(); + + // FUNCTION: LEGO1 0x10037600 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f00e8 + return "AmbulanceMissionState"; + } + + // FUNCTION: LEGO1 0x10037610 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, AmbulanceMissionState::ClassName()) || LegoState::IsA(p_name); + } + + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + inline void SetUnknown0x08(undefined4 p_unk0x08) { m_unk0x08 = p_unk0x08; } + + inline MxU16 GetScore(MxU8 p_id) + { + switch (p_id) { + case 1: + return m_score1; + case 2: + return m_score2; + case 3: + return m_score3; + case 4: + return m_score4; + case 5: + return m_score5; + default: + return 0; + } + } + + // SYNTHETIC: LEGO1 0x100376c0 + // AmbulanceMissionState::`scalar deleting destructor' + +protected: + undefined4 m_unk0x08; // 0x08 + undefined4 m_unk0x0c; // 0x0c + MxU16 m_unk0x10; // 0x10 + MxU16 m_unk0x12; // 0x12 + MxU16 m_unk0x14; // 0x14 + MxU16 m_unk0x16; // 0x16 + MxU16 m_unk0x18; // 0x18 + MxU16 m_score1; // 0x1a + MxU16 m_score2; // 0x1c + MxU16 m_score3; // 0x1e + MxU16 m_score4; // 0x20 + MxU16 m_score5; // 0x22 +}; + +#endif // AMBULANCEMISSIONSTATE_H diff --git a/LEGO1/lego/legoomni/include/animstate.h b/LEGO1/lego/legoomni/include/animstate.h new file mode 100644 index 00000000..ca1ad20a --- /dev/null +++ b/LEGO1/lego/legoomni/include/animstate.h @@ -0,0 +1,71 @@ +#ifndef ANIMSTATE_H +#define ANIMSTATE_H + +#include "legostate.h" + +// SIZE 0x30 +struct ModelInfo { + char* m_name; // 0x00 + MxU8 m_unk0x04; // 0x04 + float m_location[3]; // 0x08 + float m_direction[3]; // 0x14 + float m_up[3]; // 0x20 + MxU8 m_unk0x2c; // 0x2c +}; + +// SIZE 0x30 +struct AnimInfo { + char* m_name; // 0x00 + MxU32 m_objectId; // 0x04 + MxS16 m_unk0x08; // 0x08 + MxBool m_unk0x0a; // 0x0a + MxU8 m_unk0x0b; // 0x0b + MxU8 m_unk0x0c; // 0x0c + MxU8 m_unk0x0d; // 0x0d + float m_unk0x10[4]; // 0x10 + MxU8 m_modelCount; // 0x20 + MxU16 m_unk0x22; // 0x22 + ModelInfo* m_models; // 0x24 + MxS8 m_unk0x28; // 0x28 + MxBool m_unk0x29; // 0x29 + MxS8 m_unk0x2a[3]; // 0x2a +}; + +// VTABLE: LEGO1 0x100d8d80 +// SIZE 0x1c +class AnimState : public LegoState { +public: + AnimState(); + ~AnimState() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x10065070 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0460 + return "AnimState"; + } + + // FUNCTION: LEGO1 0x10065080 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, AnimState::ClassName()) || LegoState::IsA(p_name); + } + + MxBool SetFlag() override; // vtable+0x18 + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + void FUN_100651d0(MxU32, AnimInfo*, MxU32&); + void FUN_10065240(MxU32, AnimInfo*, MxU32); + + // SYNTHETIC: LEGO1 0x10065130 + // AnimState::`scalar deleting destructor' + +private: + undefined4 m_unk0x08; // 0x08 + undefined4 m_unk0x0c; // 0x0c + void* m_unk0x10; // 0x10 + undefined4 m_unk0x14; // 0x14 + void* m_unk0x18; // 0x18 +}; + +#endif // ANIMSTATE_H diff --git a/LEGO1/lego/legoomni/include/beachhouseentity.h b/LEGO1/lego/legoomni/include/beachhouseentity.h new file mode 100644 index 00000000..34e9db47 --- /dev/null +++ b/LEGO1/lego/legoomni/include/beachhouseentity.h @@ -0,0 +1,29 @@ +#ifndef BEACHHOUSEENTITY_H +#define BEACHHOUSEENTITY_H + +#include "buildingentity.h" + +// VTABLE: LEGO1 0x100d4a18 +// SIZE 0x68 +class BeachHouseEntity : public BuildingEntity { +public: + // FUNCTION: LEGO1 0x1000ee80 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0314 + return "BeachHouseEntity"; + } + + // FUNCTION: LEGO1 0x1000ee90 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, BeachHouseEntity::ClassName()) || BuildingEntity::IsA(p_name); + } + + MxLong VTable0x50(MxParam& p_param) override; + + // SYNTHETIC: LEGO1 0x1000f970 + // BeachHouseEntity::`scalar deleting destructor' +}; + +#endif // BEACHHOUSEENTITY_H diff --git a/LEGO1/lego/legoomni/include/bike.h b/LEGO1/lego/legoomni/include/bike.h new file mode 100644 index 00000000..7355d1a7 --- /dev/null +++ b/LEGO1/lego/legoomni/include/bike.h @@ -0,0 +1,41 @@ +#ifndef BIKE_H +#define BIKE_H + +#include "decomp.h" +#include "islepathactor.h" + +// VTABLE: LEGO1 0x100d9808 +// SIZE 0x164 +class Bike : public IslePathActor { +public: + Bike(); + + // FUNCTION: LEGO1 0x100766f0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03d0 + return "Bike"; + } + + // FUNCTION: LEGO1 0x10076700 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Bike::ClassName()) || IslePathActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + MxU32 VTable0xcc() override; // vtable+0xcc + MxU32 VTable0xd4(LegoControlManagerEvent& p_param) override; // vtable+0xd4 + void VTable0xe4() override; // vtable+0xe4 + + void FUN_10076b60(); + + // SYNTHETIC: LEGO1 0x10076880 + // Bike::`scalar deleting destructor' + +private: + // TODO: Bike fields + undefined m_unk0x160[4]; +}; + +#endif // BIKE_H diff --git a/LEGO1/lego/legoomni/include/buildingentity.h b/LEGO1/lego/legoomni/include/buildingentity.h new file mode 100644 index 00000000..dd6d4594 --- /dev/null +++ b/LEGO1/lego/legoomni/include/buildingentity.h @@ -0,0 +1,34 @@ +#ifndef BUILDINGENTITY_H +#define BUILDINGENTITY_H + +#include "legoentity.h" + +// VTABLE: LEGO1 0x100d5c88 +// SIZE 0x68 +class BuildingEntity : public LegoEntity { +public: + BuildingEntity(); + ~BuildingEntity() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10014f20 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f07e8 + return "BuildingEntity"; + } + + // FUNCTION: LEGO1 0x10014f30 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, BuildingEntity::ClassName()) || LegoEntity::IsA(p_name); + } + + virtual MxLong VTable0x50(MxParam& p_param) = 0; + + // SYNTHETIC: LEGO1 0x10015010 + // BuildingEntity::`scalar deleting destructor' +}; + +#endif // BUILDINGENTITY_H diff --git a/LEGO1/lego/legoomni/include/bumpbouy.h b/LEGO1/lego/legoomni/include/bumpbouy.h new file mode 100644 index 00000000..4b30a914 --- /dev/null +++ b/LEGO1/lego/legoomni/include/bumpbouy.h @@ -0,0 +1,33 @@ +#ifndef BUMPBOUY_H +#define BUMPBOUY_H + +#include "legoanimactor.h" +#include "mxtypes.h" + +// VTABLE: LEGO1 0x100d6790 LegoPathActor +// VTABLE: LEGO1 0x100d6860 LegoAnimActor +// SIZE 0x174 +class BumpBouy : public LegoAnimActor { +public: + BumpBouy(); + ~BumpBouy() override; + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x100274f0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0394 + return "BumpBouy"; + } + + // FUNCTION: LEGO1 0x10027510 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, BumpBouy::ClassName()) || LegoAnimActor::IsA(p_name); + } + + // SYNTHETIC: LEGO1 0x100274a0 + // BumpBouy::`scalar deleting destructor' +}; + +#endif // BUMPBOUY_H diff --git a/LEGO1/lego/legoomni/include/carrace.h b/LEGO1/lego/legoomni/include/carrace.h new file mode 100644 index 00000000..c5af66e8 --- /dev/null +++ b/LEGO1/lego/legoomni/include/carrace.h @@ -0,0 +1,42 @@ +#ifndef CARRACE_H +#define CARRACE_H + +#include "decomp.h" +#include "legorace.h" + +// VTABLE: LEGO1 0x100d5e50 +// SIZE 0x154 +class CarRace : public LegoRace { +public: + CarRace(); + + // FUNCTION: LEGO1 0x10016b20 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0528 + return "CarRace"; + } + + // FUNCTION: LEGO1 0x10016b30 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, CarRace::ClassName()) || LegoRace::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x64() override; // vtable+0x64 + undefined4 VTable0x6c(undefined4) override; // vtable+0x6c + undefined4 VTable0x70(undefined4) override; // vtable+0x70 + undefined4 VTable0x74(undefined4) override; // vtable+0x74 + undefined4 VTable0x78(undefined4) override; // vtable+0x78 + + // SYNTHETIC: LEGO1 0x10016c70 + // CarRace::`scalar deleting destructor' + +private: + undefined m_unk0x144[12]; // 0x144 + undefined4 m_unk0x150; // 0x150 +}; + +#endif // CARRACE_H diff --git a/LEGO1/lego/legoomni/include/carracestate.h b/LEGO1/lego/legoomni/include/carracestate.h new file mode 100644 index 00000000..c7a1e376 --- /dev/null +++ b/LEGO1/lego/legoomni/include/carracestate.h @@ -0,0 +1,27 @@ +#ifndef CARRACESTATE_H +#define CARRACESTATE_H + +#include "racestate.h" + +// VTABLE: LEGO1 0x100d4b70 +// SIZE 0x2c +class CarRaceState : public RaceState { +public: + // FUNCTION: LEGO1 0x1000dd30 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f009c + return "CarRaceState"; + } + + // FUNCTION: LEGO1 0x1000dd40 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, CarRaceState::ClassName()) || RaceState::IsA(p_name); + } + + // SYNTHETIC: LEGO1 0x1000f740 + // CarRaceState::`scalar deleting destructor' +}; + +#endif // CARRACESTATE_H diff --git a/LEGO1/lego/legoomni/include/caveentity.h b/LEGO1/lego/legoomni/include/caveentity.h new file mode 100644 index 00000000..24b9759f --- /dev/null +++ b/LEGO1/lego/legoomni/include/caveentity.h @@ -0,0 +1,10 @@ +#ifndef CAVEENTITY_H +#define CAVEENTITY_H + +#include "racestandsentity.h" + +// No overrides, uses vtable from RaceStandsEntity +// SIZE 0x68 +class CaveEntity : public RaceStandsEntity {}; + +#endif // CAVEENTITY_H diff --git a/LEGO1/lego/legoomni/include/doors.h b/LEGO1/lego/legoomni/include/doors.h new file mode 100644 index 00000000..be61fd15 --- /dev/null +++ b/LEGO1/lego/legoomni/include/doors.h @@ -0,0 +1,40 @@ +#ifndef DOORS_H +#define DOORS_H + +#include "legopathactor.h" + +// VTABLE: LEGO1 0x100d4788 +// SIZE 0x1f8 +class Doors : public LegoPathActor { +public: + // FUNCTION: LEGO1 0x1000e430 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03e8 + return "Doors"; + } + + // FUNCTION: LEGO1 0x1000e440 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Doors::ClassName()) || LegoPathActor::IsA(p_name); + } + + void ParseAction(char*) override; // vtable+0x20 + void VTable0x70(float p_float) override; // vtable+0x70 + MxResult VTable0x94(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 + + // SYNTHETIC: LEGO1 0x1000e580 + // Doors::`scalar deleting destructor' + +private: + undefined4 m_unk0x154; // 0x154 + undefined4 m_unk0x158; // 0x158 + undefined4 m_unk0x15c; // 0x15c + undefined4 m_unk0x160; // 0x160 + MxMatrix m_unk0x164; // 0x164 + MxMatrix m_unk0x1ac; // 0x1ac + undefined4 m_unk0x1f4; // 0x1f4 +}; + +#endif // DOORS_H diff --git a/LEGO1/lego/legoomni/include/dunebuggy.h b/LEGO1/lego/legoomni/include/dunebuggy.h new file mode 100644 index 00000000..c10ea949 --- /dev/null +++ b/LEGO1/lego/legoomni/include/dunebuggy.h @@ -0,0 +1,45 @@ +#ifndef DUNEBUGGY_H +#define DUNEBUGGY_H + +#include "decomp.h" +#include "islepathactor.h" + +// VTABLE: LEGO1 0x100d8f98 +// SIZE 0x16c +class DuneBuggy : public IslePathActor { +public: + DuneBuggy(); + + // FUNCTION: LEGO1 0x10067c30 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0410 + return "DuneBuggy"; + } + + // FUNCTION: LEGO1 0x10067c40 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, DuneBuggy::ClassName()) || IslePathActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void VTable0x70(float p_float) override; // vtable+0x70 + MxU32 VTable0xcc() override; // vtable+0xcc + MxU32 VTable0xd4(LegoControlManagerEvent& p_param) override; // vtable+0xd4 + MxU32 VTable0xdc(MxType19NotificationParam& p_param) override; // vtable+0xdc + void VTable0xe4() override; // vtable+0xe4 + + void FUN_10068350(); + + // SYNTHETIC: LEGO1 0x10067dc0 + // DuneBuggy::`scalar deleting destructor' + +private: + // TODO: Double check DuneBuggy field types + undefined4 m_unk0x160; + MxFloat m_unk0x164; + undefined4 m_unk0x168; +}; + +#endif // DUNEBUGGY_H diff --git a/LEGO1/lego/legoomni/include/elevatorbottom.h b/LEGO1/lego/legoomni/include/elevatorbottom.h new file mode 100644 index 00000000..e2886f5c --- /dev/null +++ b/LEGO1/lego/legoomni/include/elevatorbottom.h @@ -0,0 +1,50 @@ +#ifndef ELEVATORBOTTOM_H +#define ELEVATORBOTTOM_H + +#include "decomp.h" +#include "legogamestate.h" +#include "legoworld.h" + +class LegoControlManagerEvent; + +// VTABLE: LEGO1 0x100d5f20 +// SIZE 0xfc +class ElevatorBottom : public LegoWorld { +public: + ElevatorBottom(); + ~ElevatorBottom() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10017f20 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f04ac + return "ElevatorBottom"; + } + + // FUNCTION: LEGO1 0x10017f30 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ElevatorBottom::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + + // FUNCTION: LEGO1 0x10017f10 + MxBool VTable0x5c() override { return TRUE; } // vtable+0x5c + + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + // SYNTHETIC: LEGO1 0x10018040 + // ElevatorBottom::`scalar deleting destructor' + +private: + LegoGameState::Area m_destLocation; // 0xf8 + + MxLong HandleClick(LegoControlManagerEvent& p_param); +}; + +#endif // ELEVATORBOTTOM_H diff --git a/LEGO1/lego/legoomni/include/extra.h b/LEGO1/lego/legoomni/include/extra.h new file mode 100644 index 00000000..35f08033 --- /dev/null +++ b/LEGO1/lego/legoomni/include/extra.h @@ -0,0 +1,23 @@ +#ifndef EXTRA_H +#define EXTRA_H + +// Items related to the Extra string of key-value pairs found in MxOb + +struct Extra { + enum ActionType { + e_none = 0, + e_opendisk, + e_openram, + e_close, + e_start, + e_stop, + e_run, + e_exit, + e_enable, + e_disable, + e_notify, + e_unknown, + }; +}; + +#endif // EXTRA_H diff --git a/LEGO1/lego/legoomni/include/gasstation.h b/LEGO1/lego/legoomni/include/gasstation.h new file mode 100644 index 00000000..c6dd28d5 --- /dev/null +++ b/LEGO1/lego/legoomni/include/gasstation.h @@ -0,0 +1,66 @@ +#ifndef GASSTATION_H +#define GASSTATION_H + +#include "decomp.h" +#include "legogamestate.h" +#include "legoworld.h" +#include "radio.h" + +class GasStationState; +class MxStillPresenter; + +// VTABLE: LEGO1 0x100d4650 +// SIZE 0x128 +class GasStation : public LegoWorld { +public: + GasStation(); + ~GasStation() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x10004780 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0168 + return "GasStation"; + } + + // FUNCTION: LEGO1 0x10004790 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, GasStation::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x5c() override; // vtable+0x5c + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + virtual MxLong HandleClick(LegoControlManagerEvent& p_param); // vtable+0x6c + + inline void PlayAction(MxU32 p_objectId); + + // SYNTHETIC: LEGO1 0x100048a0 + // GasStation::`scalar deleting destructor' + +private: + MxLong HandleEndAction(MxEndActionNotificationParam& p_param); + MxLong HandleKeyPress(MxS8 p_key); + MxLong HandleButtonDown(LegoControlManagerEvent& p_param); + + MxS16 m_currentActorId; // 0xf8 + undefined2 m_unk0xfa; // 0xfa + LegoGameState::Area m_destLocation; // 0xfc + GasStationState* m_state; // 0x100 + undefined2 m_unk0x104; // 0x104 + undefined2 m_unk0x106; // 0x106 + MxStillPresenter* m_trackLedBitmap; // 0x108 + MxLong m_unk0x10c; // 0x10c + MxLong m_trackLedTimer; // 0x110 + MxBool m_unk0x114; // 0x114 + MxBool m_unk0x115; // 0x115 + Radio m_radio; // 0x118 +}; + +#endif // GASSTATION_H diff --git a/LEGO1/lego/legoomni/include/gasstationentity.h b/LEGO1/lego/legoomni/include/gasstationentity.h new file mode 100644 index 00000000..1b25cfd2 --- /dev/null +++ b/LEGO1/lego/legoomni/include/gasstationentity.h @@ -0,0 +1,29 @@ +#ifndef GASSTATIONENTITY_H +#define GASSTATIONENTITY_H + +#include "buildingentity.h" + +// VTABLE: LEGO1 0x100d5258 +// SIZE 0x68 +class GasStationEntity : public BuildingEntity { +public: + // FUNCTION: LEGO1 0x1000eb20 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0348 + return "GasStationEntity"; + } + + // FUNCTION: LEGO1 0x1000eb30 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, GasStationEntity::ClassName()) || BuildingEntity::IsA(p_name); + } + + MxLong VTable0x50(MxParam& p_param) override; + + // SYNTHETIC: LEGO1 0x1000f890 + // GasStationEntity::`scalar deleting destructor' +}; + +#endif // GASSTATIONENTITY_H diff --git a/LEGO1/lego/legoomni/include/gasstationstate.h b/LEGO1/lego/legoomni/include/gasstationstate.h new file mode 100644 index 00000000..bf0327da --- /dev/null +++ b/LEGO1/lego/legoomni/include/gasstationstate.h @@ -0,0 +1,50 @@ +#ifndef GASSTATIONSTATE_H +#define GASSTATIONSTATE_H + +#include "legostate.h" + +// VTABLE: LEGO1 0x100d46e0 +// SIZE 0x24 +class GasStationState : public LegoState { +public: + // SIZE 0x04 + struct Unknown0x14 { + undefined4 m_unk0x00; // 0x00 + }; + + GasStationState(); + + // FUNCTION: LEGO1 0x100061d0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0174 + return "GasStationState"; + } + + // FUNCTION: LEGO1 0x100061e0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, GasStationState::ClassName()) || LegoState::IsA(p_name); + } + + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + // SYNTHETIC: LEGO1 0x10006290 + // GasStationState::`scalar deleting destructor' + + void FUN_10006430(undefined4); + void FUN_10006490(); + + friend class GasStation; + +private: + undefined4 m_unk0x08[3]; // 0x08 + Unknown0x14 m_unk0x14; // 0x14 + MxS16 m_unk0x18; // 0x18 + MxS16 m_unk0x1a; // 0x1a + MxS16 m_unk0x1c; // 0x1c + MxS16 m_unk0x1e; // 0x1e + MxS16 m_unk0x20; // 0x20 +}; + +#endif // GASSTATIONSTATE_H diff --git a/LEGO1/lego/legoomni/include/helicopter.h b/LEGO1/lego/legoomni/include/helicopter.h new file mode 100644 index 00000000..b568390a --- /dev/null +++ b/LEGO1/lego/legoomni/include/helicopter.h @@ -0,0 +1,52 @@ +#ifndef HELICOPTER_H +#define HELICOPTER_H + +#include "islepathactor.h" +#include "realtime/matrix.h" + +class HelicopterState; + +// VTABLE: LEGO1 0x100d40f8 +// SIZE 0x230 +class Helicopter : public IslePathActor { +public: + Helicopter(); + ~Helicopter() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x10003070 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0130 + return "Helicopter"; + } + + // FUNCTION: LEGO1 0x10003080 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Helicopter::ClassName()) || IslePathActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void VTable0x70(float p_float) override; // vtable+0x70 + void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 + MxU32 VTable0xcc() override; // vtable+0xcc + MxU32 VTable0xd4(LegoControlManagerEvent& p_param) override; // vtable+0xd4 + MxU32 VTable0xd8(LegoEndAnimNotificationParam& p_param) override; // vtable+0xd8 + void VTable0xe4() override; // vtable+0xe4 + + // SYNTHETIC: LEGO1 0x10003210 + // Helicopter::`scalar deleting destructor' + +protected: + MxMatrix m_unk0x160; // 0x160 + MxMatrix m_unk0x1a8; // 0x1a8 + float m_unk0x1f0; // 0x1f0 + UnknownMx4DPointFloat m_unk0x1f4; // 0x1f4 + HelicopterState* m_state; // 0x228 + MxAtomId m_script; // 0x22c + +private: + void GetState(); +}; + +#endif // HELICOPTER_H diff --git a/LEGO1/lego/legoomni/include/helicopterstate.h b/LEGO1/lego/legoomni/include/helicopterstate.h new file mode 100644 index 00000000..7bda248f --- /dev/null +++ b/LEGO1/lego/legoomni/include/helicopterstate.h @@ -0,0 +1,44 @@ +#ifndef HELICOPTERSTATE_H +#define HELICOPTERSTATE_H + +#include "decomp.h" +#include "legostate.h" + +// VTABLE: LEGO1 0x100d5418 +// SIZE 0x0c +class HelicopterState : public LegoState { +public: + // FUNCTION: LEGO1 0x1000e0d0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0144 + return "HelicopterState"; + } + + // FUNCTION: LEGO1 0x1000e0e0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, HelicopterState::ClassName()) || LegoState::IsA(p_name); + } + + // FUNCTION: LEGO1 0x1000e0b0 + MxBool IsSerializable() override { return FALSE; } // vtable+0x14 + + // FUNCTION: LEGO1 0x1000e0c0 + MxBool SetFlag() override + { + m_unk0x08 = 0; + return TRUE; + } // vtable+0x18 + + inline void SetUnknown8(MxU32 p_unk0x08) { m_unk0x08 = p_unk0x08; } + inline MxU32 GetUnkown8() { return m_unk0x08; } + + // SYNTHETIC: LEGO1 0x1000e190 + // HelicopterState::`scalar deleting destructor' + +protected: + MxU32 m_unk0x08; // 0x08 +}; + +#endif // HELICOPTERSTATE_H diff --git a/LEGO1/lego/legoomni/include/historybook.h b/LEGO1/lego/legoomni/include/historybook.h new file mode 100644 index 00000000..af3b9be2 --- /dev/null +++ b/LEGO1/lego/legoomni/include/historybook.h @@ -0,0 +1,46 @@ +#ifndef HISTORYBOOK_H +#define HISTORYBOOK_H + +#include "decomp.h" +#include "legogamestate.h" +#include "legoworld.h" + +class MxStillPresenter; + +// VTABLE: LEGO1 0x100da328 +// SIZE 0x3e4 +class HistoryBook : public LegoWorld { +public: + HistoryBook(); + ~HistoryBook() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10082390 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f04bc + return "HistoryBook"; + } + + // FUNCTION: LEGO1 0x100823a0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, HistoryBook::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x64() override; // vtable+0x64 + + // SYNTHETIC: LEGO1 0x100824b0 + // HistoryBook::`scalar deleting destructor' + +private: + LegoGameState::Area m_destLocation; // 0xf8 + MxStillPresenter* m_alphabet[26]; // 0xfc + MxStillPresenter* m_names[20][7]; // 0x164 + MxStillPresenter* m_scores[20]; // 0x394 +}; + +#endif // HISTORYBOOK_H diff --git a/LEGO1/lego/legoomni/include/hospital.h b/LEGO1/lego/legoomni/include/hospital.h new file mode 100644 index 00000000..40f4f947 --- /dev/null +++ b/LEGO1/lego/legoomni/include/hospital.h @@ -0,0 +1,69 @@ +#ifndef HOSPITAL_H +#define HOSPITAL_H + +#include "actionsfwd.h" +#include "decomp.h" +#include "legogamestate.h" +#include "legoworld.h" + +class HospitalState; +class LegoControlManagerEvent; +class MxEndActionNotificationParam; +class MxStillPresenter; + +// VTABLE: LEGO1 0x100d9730 +// SIZE 0x12c +class Hospital : public LegoWorld { +public: + Hospital(); + ~Hospital() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x100746b0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0490 + return "Hospital"; + } + + // FUNCTION: LEGO1 0x100746c0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Hospital::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x5c() override; // vtable+0x5c + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + inline void PlayAction(MxU32 p_objectId); + + // SYNTHETIC: LEGO1 0x100747d0 + // Hospital::`scalar deleting destructor' + +private: + MxLong HandleKeyPress(MxS8 p_key); + MxLong HandleEndAction(MxEndActionNotificationParam& p_param); + MxLong HandleButtonDown(LegoControlManagerEvent& p_param); + MxBool HandleClick(LegoControlManagerEvent& p_param); + + MxS16 m_currentActorId; // 0xf8 + LegoGameState::Area m_destLocation; // 0xfc + undefined2 m_unk0x100; // 0x100 + HospitalState* m_hospitalState; // 0x104 + undefined2 m_unk0x108; // 0x108 + HospitalScript::Script m_currentAction; // 0x10c + MxStillPresenter* m_copLedBitmap; // 0x110 + MxStillPresenter* m_pizzaLedBitmap; // 0x114 + undefined m_unk0x118; // 0x118 + MxLong m_copLedAnimTimer; // 0x11c + MxLong m_pizzaLedAnimTimer; // 0x120 + MxLong m_time; // 0x124 + undefined m_unk0x128; // 0x128 +}; + +#endif // HOSPITAL_H diff --git a/LEGO1/lego/legoomni/include/hospitalentity.h b/LEGO1/lego/legoomni/include/hospitalentity.h new file mode 100644 index 00000000..3dbe7d54 --- /dev/null +++ b/LEGO1/lego/legoomni/include/hospitalentity.h @@ -0,0 +1,29 @@ +#ifndef HOSPITALENTITY_H +#define HOSPITALENTITY_H + +#include "buildingentity.h" + +// VTABLE: LEGO1 0x100d5068 +// SIZE 0x68 +class HospitalEntity : public BuildingEntity { +public: + // FUNCTION: LEGO1 0x1000ec40 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0338 + return "HospitalEntity"; + } + + // FUNCTION: LEGO1 0x1000ec50 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, HospitalEntity::ClassName()) || BuildingEntity::IsA(p_name); + } + + MxLong VTable0x50(MxParam& p_param) override; // vtable+0x50 + + // SYNTHETIC: LEGO1 0x1000f820 + // HospitalEntity::`scalar deleting destructor' +}; + +#endif // HOSPITALENTITY_H diff --git a/LEGO1/lego/legoomni/include/hospitalstate.h b/LEGO1/lego/legoomni/include/hospitalstate.h new file mode 100644 index 00000000..16d80cb6 --- /dev/null +++ b/LEGO1/lego/legoomni/include/hospitalstate.h @@ -0,0 +1,49 @@ +#ifndef HOSPITALSTATE_H +#define HOSPITALSTATE_H + +#include "decomp.h" +#include "legostate.h" + +// VTABLE: LEGO1 0x100d97a0 +// SIZE 0x18 +class HospitalState : public LegoState { +public: + // SIZE 0x04 + struct Unknown0x08 { + undefined4 m_unk0x00; // 0x00 + }; + + HospitalState(); + ~HospitalState() override {} + + // FUNCTION: LEGO1 0x10076400 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0480 + return "HospitalState"; + } + + // FUNCTION: LEGO1 0x10076410 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, HospitalState::ClassName()) || LegoState::IsA(p_name); + } + + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + // SYNTHETIC: LEGO1 0x100764c0 + // HospitalState::`scalar deleting destructor' + + friend class Hospital; + +private: + Unknown0x08 m_unk0x08; // 0x08 + MxS16 m_unk0x0c; // 0x0c + MxS16 m_unk0x0e; // 0x0e + MxS16 m_unk0x10; // 0x10 + MxS16 m_unk0x12; // 0x12 + MxS16 m_unk0x14; // 0x14 + MxS16 m_unk0x16; // 0x16 +}; + +#endif // HOSPITALSTATE_H diff --git a/LEGO1/lego/legoomni/include/infocenter.h b/LEGO1/lego/legoomni/include/infocenter.h new file mode 100644 index 00000000..04b56757 --- /dev/null +++ b/LEGO1/lego/legoomni/include/infocenter.h @@ -0,0 +1,119 @@ +#ifndef INFOCENTER_H +#define INFOCENTER_H + +#include "actionsfwd.h" +#include "legogamestate.h" +#include "legoworld.h" +#include "mxrect32.h" +#include "radio.h" + +class InfocenterState; +class MxNotificationParam; +class MxStillPresenter; +class LegoControlManagerEvent; + +// SIZE 0x18 +struct InfocenterMapEntry { + // FUNCTION: LEGO1 0x1006ec80 + InfocenterMapEntry() {} + + MxStillPresenter* m_presenter; // 0x00 + undefined4 m_unk0x04; // 0x04 + MxRect32 m_area; // 0x08 +}; + +// VTABLE: LEGO1 0x100d9338 +// SIZE 0x1d8 +class Infocenter : public LegoWorld { +public: + enum Cutscene { + e_noIntro = -1, + e_legoMovie, + e_mindscapeMovie, + e_introMovie, + e_outroMovie, + e_badEndMovie, + e_goodEndMovie + }; + + enum Character { + e_noCharacter = 0, + e_pepper, + e_mama, + e_papa, + e_nick, + e_laura + }; + + Infocenter(); + ~Infocenter() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1006eb40 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f04ec + return "Infocenter"; + } + + // FUNCTION: LEGO1 0x1006eb50 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Infocenter::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x5c() override; // vtable+0x5c + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + // SYNTHETIC: LEGO1 0x1006ec60 + // Infocenter::`scalar deleting destructor' + +private: + void InitializeBitmaps(); + + MxLong HandleKeyPress(MxS8 p_key); + MxU8 HandleMouseMove(MxS32 p_x, MxS32 p_y); + MxU8 HandleButtonUp(MxS32 p_x, MxS32 p_y); + MxU8 HandleClick(LegoControlManagerEvent& p_param); + MxLong HandleEndAction(MxEndActionNotificationParam& p_param); + MxLong HandleNotification0(MxNotificationParam& p_param); + + void UpdateFrameHot(MxBool p_display); + void Reset(); + + void PlayCutscene(Cutscene p_entityId, MxBool p_scale); + void StopCutscene(); + + void FUN_10070d10(MxS32 p_x, MxS32 p_y); + + void StartCredits(); + void StopCredits(); + + void PlayAction(InfomainScript::Script p_script); + void StopCurrentAction(); + + void PlayBookAnimation(); + void StopBookAnimation(); + + InfomainScript::Script m_currentInfomainScript; // 0xf8 + MxS16 m_selectedCharacter; // 0xfc + InfocenterState* m_infocenterState; // 0x100 + LegoGameState::Area m_destLocation; // 0x104 + Cutscene m_currentCutscene; // 0x108 + Radio m_radio; // 0x10c + MxStillPresenter* m_unk0x11c; // 0x11c + InfocenterMapEntry m_mapAreas[7]; // 0x120 + MxS16 m_unk0x1c8; // 0x1c8 + MxStillPresenter* m_frameHotBitmap; // 0x1cc + MxS16 m_infoManDialogueTimer; // 0x1d0 + MxS16 m_bookAnimationTimer; // 0x1d2 + MxU16 m_unk0x1d4; // 0x1d4 + MxS16 m_unk0x1d6; // 0x1d6 +}; + +#endif // INFOCENTER_H diff --git a/LEGO1/lego/legoomni/include/infocenterdoor.h b/LEGO1/lego/legoomni/include/infocenterdoor.h new file mode 100644 index 00000000..84854072 --- /dev/null +++ b/LEGO1/lego/legoomni/include/infocenterdoor.h @@ -0,0 +1,49 @@ +#ifndef INFOCENTERDOOR_H +#define INFOCENTERDOOR_H + +#include "legogamestate.h" +#include "legoworld.h" + +class LegoControlManagerEvent; + +// VTABLE: LEGO1 0x100d72d8 +// SIZE 0xfc +class InfocenterDoor : public LegoWorld { +public: + InfocenterDoor(); + ~InfocenterDoor() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x100377b0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f049c + return "InfocenterDoor"; + } + + // FUNCTION: LEGO1 0x100377c0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, InfocenterDoor::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + + // FUNCTION: LEGO1 0x100377a0 + MxBool VTable0x5c() override { return TRUE; } // vtable+0x5c + + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + // SYNTHETIC: LEGO1 0x100378d0 + // InfocenterDoor::`scalar deleting destructor' + +private: + LegoGameState::Area m_destLocation; // 0xf8 + + MxLong HandleClick(LegoControlManagerEvent& p_param); +}; + +#endif // INFOCENTERDOOR_H diff --git a/LEGO1/lego/legoomni/include/infocenterentity.h b/LEGO1/lego/legoomni/include/infocenterentity.h new file mode 100644 index 00000000..82fa3d30 --- /dev/null +++ b/LEGO1/lego/legoomni/include/infocenterentity.h @@ -0,0 +1,29 @@ +#ifndef INFOCENTERENTITY_H +#define INFOCENTERENTITY_H + +#include "buildingentity.h" + +// VTABLE: LEGO1 0x100d4b90 +// SIZE 0x68 +class InfoCenterEntity : public BuildingEntity { +public: + // FUNCTION: LEGO1 0x1000ea00 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f035c + return "InfoCenterEntity"; + } + + // FUNCTION: LEGO1 0x1000ea10 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, InfoCenterEntity::ClassName()) || BuildingEntity::IsA(p_name); + } + + MxLong VTable0x50(MxParam& p_param) override; // vtable+0x50 + + // SYNTHETIC: LEGO1 0x1000f7b0 + // InfoCenterEntity::`scalar deleting destructor' +}; + +#endif // INFOCENTERENTITY_H diff --git a/LEGO1/lego/legoomni/include/infocenterstate.h b/LEGO1/lego/legoomni/include/infocenterstate.h new file mode 100644 index 00000000..b1c418f1 --- /dev/null +++ b/LEGO1/lego/legoomni/include/infocenterstate.h @@ -0,0 +1,59 @@ +#ifndef INFOCENTERSTATE_H +#define INFOCENTERSTATE_H + +#include "decomp.h" +#include "legogamestate.h" +#include "legostate.h" + +class MxStillPresenter; + +// VTABLE: LEGO1 0x100d93a8 +// SIZE 0x94 +class InfocenterState : public LegoState { +public: + InfocenterState(); + ~InfocenterState() override; + + // FUNCTION: LEGO1 0x10071840 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f04dc + return "InfocenterState"; + } + + // FUNCTION: LEGO1 0x10071850 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, InfocenterState::ClassName()) || LegoState::IsA(p_name); + } + + // FUNCTION: LEGO1 0x10071830 + MxBool IsSerializable() override { return FALSE; } // vtable+0x14 + + inline MxS16 GetMaxNameLength() { return sizeOfArray(m_letters); } + inline MxStillPresenter* GetNameLetter(MxS32 p_index) { return m_letters[p_index]; } + inline void SetNameLetter(MxS32 p_index, MxStillPresenter* p_letter) { m_letters[p_index] = p_letter; } + inline MxBool HasRegistered() { return m_letters[0] != NULL; } + inline Playlist& GetExitDialogueAct1() { return m_exitDialogueAct1; } + inline Playlist& GetExitDialogueAct23() { return m_exitDialogueAct23; } + inline Playlist& GetReturnDialogue(LegoGameState::Act p_act) { return m_returnDialogue[p_act]; } + inline Playlist& GetLeaveDialogue(LegoGameState::Act p_act) { return m_leaveDialogue[p_act]; } + inline Playlist& GetBricksterDialogue() { return m_bricksterDialogue; } + inline MxU32 GetUnknown0x74() { return m_unk0x74; } + + inline void SetUnknown0x74(MxU32 p_unk0x74) { m_unk0x74 = p_unk0x74; } + + // SYNTHETIC: LEGO1 0x10071900 + // InfocenterState::`scalar deleting destructor' + +private: + Playlist m_exitDialogueAct1; // 0x08 + Playlist m_exitDialogueAct23; // 0x14 + Playlist m_returnDialogue[3]; // 0x20 + Playlist m_leaveDialogue[3]; // 0x44 + Playlist m_bricksterDialogue; // 0x68 + MxU32 m_unk0x74; // 0x74 + MxStillPresenter* m_letters[7]; // 0x78 +}; + +#endif // INFOCENTERSTATE_H diff --git a/LEGO1/lego/legoomni/include/isle.h b/LEGO1/lego/legoomni/include/isle.h new file mode 100644 index 00000000..38895964 --- /dev/null +++ b/LEGO1/lego/legoomni/include/isle.h @@ -0,0 +1,103 @@ +#ifndef ISLE_H +#define ISLE_H + +#include "actionsfwd.h" +#include "legogamestate.h" +#include "legoworld.h" +#include "radio.h" + +class Pizza; +class Pizzeria; +class TowTrack; +class Ambulance; +class JukeBoxEntity; +class Helicopter; +class Bike; +class DuneBuggy; +class Motocycle; +class SkateBoard; +class RaceCar; +class Jetski; +class Act1State; + +// VTABLE: LEGO1 0x100d6fb8 +// SIZE 0x140 +class Isle : public LegoWorld { +public: + // For g_unk0x100f1198 + enum { + c_bit7 = 0x40 + }; + + Isle(); + ~Isle() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10030910 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0458 + return "Isle"; + } + + // FUNCTION: LEGO1 0x10030920 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Isle::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+50 + void Add(MxCore* p_object) override; // vtable+58 + + // FUNCTION: LEGO1 0x10030900 + MxBool VTable0x5c() override { return TRUE; } // vtable+5c + + // FUNCTION: LEGO1 0x10033170 + void VTable0x60() override {} // vtable+60 + + MxBool VTable0x64() override; // vtable+64 + void Enable(MxBool p_enable) override; // vtable+68 + virtual void VTable0x6c(IslePathActor* p_actor); // vtable+6c + + MxLong HandleEndAction(MxEndActionNotificationParam& p_param); + MxLong HandleClick(LegoControlManagerEvent& p_param); + MxLong HandleType19Notification(MxParam& p_param); + MxLong HandleTransitionEnd(); + void HandleElevatorEndAction(); + void FUN_10031590(); + void FUN_10032620(); + void FUN_100330e0(); + void FUN_10033350(); + void FUN_10032d30( + IsleScript::Script p_script, + JukeboxScript::Script p_music, + const char* p_cameraLocation, + MxBool p_und + ); + + inline void SetDestLocation(LegoGameState::Area p_destLocation) { m_destLocation = p_destLocation; } + + // SYNTHETIC: LEGO1 0x10030a30 + // Isle::`scalar deleting destructor' + +protected: + Act1State* m_act1state; // 0xf8 + Pizza* m_pizza; // 0xfc + Pizzeria* m_pizzeria; // 0x100 + TowTrack* m_towtrack; // 0x104 + Ambulance* m_ambulance; // 0x108 + JukeBoxEntity* m_jukebox; // 0x10c + Helicopter* m_helicopter; // 0x110 + Bike* m_bike; // 0x114 + DuneBuggy* m_dunebuggy; // 0x118 + Motocycle* m_motocycle; // 0x11c + SkateBoard* m_skateboard; // 0x120 + RaceCar* m_racecar; // 0x124 + Jetski* m_jetski; // 0x128 + Radio m_radio; // 0x12c + LegoGameState::Area m_destLocation; // 0x13c +}; + +#endif // ISLE_H diff --git a/LEGO1/lego/legoomni/include/isleactor.h b/LEGO1/lego/legoomni/include/isleactor.h new file mode 100644 index 00000000..1affab4a --- /dev/null +++ b/LEGO1/lego/legoomni/include/isleactor.h @@ -0,0 +1,62 @@ +#ifndef ISLEACTOR_H +#define ISLEACTOR_H + +#include "legoactor.h" + +class LegoWorld; +class MxEndActionNotificationParam; +class MxNotificationParam; + +// VTABLE: LEGO1 0x100d5178 +// SIZE 0x7c +class IsleActor : public LegoActor { +public: + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x1000e660 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f07dc + return "IsleActor"; + } + + // FUNCTION: LEGO1 0x1000e670 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, IsleActor::ClassName()) || LegoActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + + // FUNCTION: LEGO1 0x1000e5f0 + virtual undefined4 VTable0x68() { return 0; } // vtable+0x68 + + // FUNCTION: LEGO1 0x1000e600 + virtual undefined4 VTable0x6c() { return 0; } // vtable+0x6c + + // FUNCTION: LEGO1 0x1000e610 + virtual undefined4 VTable0x70() { return 0; } // vtable+0x70 + + // FUNCTION: LEGO1 0x1000e620 + virtual undefined4 HandleEndAction(MxEndActionNotificationParam&) { return 0; } // vtable+0x74 + + // FUNCTION: LEGO1 0x1000e630 + virtual undefined4 HandleButtonDown(MxNotificationParam&) { return 0; } // vtable+0x78 + + // FUNCTION: LEGO1 0x1000e640 + virtual undefined4 HandleButtonUp(MxNotificationParam&) { return 0; } // vtable+0x7c + + // FUNCTION: LEGO1 0x1000e650 + virtual undefined4 VTable0x80(MxParam&) { return 0; } // vtable+0x80 + +private: + LegoWorld* m_world; // 0x78 +}; + +// SYNTHETIC: LEGO1 0x1000e940 +// IsleActor::~IsleActor + +// SYNTHETIC: LEGO1 0x1000e990 +// IsleActor::`scalar deleting destructor' + +#endif // ISLEACTOR_H diff --git a/LEGO1/lego/legoomni/include/islepathactor.h b/LEGO1/lego/legoomni/include/islepathactor.h new file mode 100644 index 00000000..569221f1 --- /dev/null +++ b/LEGO1/lego/legoomni/include/islepathactor.h @@ -0,0 +1,144 @@ +#ifndef ISLEPATHACTOR_H +#define ISLEPATHACTOR_H + +#include "legogamestate.h" +#include "legopathactor.h" +#include "mxtypes.h" + +class LegoControlManagerEvent; +class LegoEndAnimNotificationParam; +class LegoWorld; +class MxType19NotificationParam; + +// VTABLE: LEGO1 0x100d4398 +// SIZE 0x160 +class IslePathActor : public LegoPathActor { +public: + enum { + c_LOCATIONS_NUM = 29 + }; + + enum { + c_spawnBit1 = 0x01, + c_playMusic = 0x02, + c_spawnBit3 = 0x04 + }; + + // SIZE 0x38 + struct SpawnLocation { + SpawnLocation() {} + + // FUNCTION: LEGO1 0x1001b1b0 + SpawnLocation( + LegoGameState::Area p_area, + MxAtomId* p_script, + MxS32 p_entityId, + const char* p_name, + MxS16 p_src, + float p_srcScale, + MxS16 p_dest, + float p_destScale, + undefined4 p_unk0x30, + JukeboxScript::Script p_music + ) + { + m_area = p_area; + m_script = p_script; + m_entityId = p_entityId; + strcpy(m_name, p_name); + m_src = p_src; + m_srcScale = p_srcScale; + m_dest = p_dest; + m_destScale = p_destScale; + m_unk0x30 = p_unk0x30; + m_music = p_music; + } + + // FUNCTION: LEGO1 0x1001b230 + SpawnLocation& operator=(const SpawnLocation& p_location) + { + m_area = p_location.m_area; + m_script = p_location.m_script; + m_entityId = p_location.m_entityId; + strcpy(m_name, p_location.m_name); + m_src = p_location.m_src; + m_srcScale = p_location.m_srcScale; + m_dest = p_location.m_dest; + m_destScale = p_location.m_destScale; + m_unk0x30 = p_location.m_unk0x30; + m_music = p_location.m_music; + return *this; + } + + LegoGameState::Area m_area; // 0x00 + MxAtomId* m_script; // 0x04 + MxS32 m_entityId; // 0x08 + char m_name[20]; // 0x0c + MxS16 m_src; // 0x20 + float m_srcScale; // 0x24 + MxS16 m_dest; // 0x28 + float m_destScale; // 0x2c + undefined4 m_unk0x30; // 0x30 + JukeboxScript::Script m_music; // 0x34 + }; + + IslePathActor(); + + // FUNCTION: LEGO1 0x10002e10 + inline ~IslePathActor() override { IslePathActor::Destroy(TRUE); } + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10002ea0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0104 + return "IslePathActor"; + } + + // FUNCTION: LEGO1 0x10002eb0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, IslePathActor::ClassName()) || LegoPathActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void Destroy(MxBool p_fromDestructor) override; // vtable+0x1c + + // FUNCTION: LEGO1 0x10002e70 + virtual MxU32 VTable0xcc() { return 0; } // vtable+0xcc + + // FUNCTION: LEGO1 0x10002df0 + virtual MxU32 VTable0xd0() { return 0; } // vtable+0xd0 + + // FUNCTION: LEGO1 0x10002e80 + virtual MxU32 VTable0xd4(LegoControlManagerEvent&) { return 0; } // vtable+0xd4 + + // FUNCTION: LEGO1 0x10002e90 + virtual MxU32 VTable0xd8(LegoEndAnimNotificationParam&) { return 0; } // vtable+0xd8 + + // FUNCTION: LEGO1 0x10002e00 + virtual MxU32 VTable0xdc(MxType19NotificationParam&) { return 0; } // vtable+0xdc + + virtual void VTable0xe0(); // vtable+0xe0 + virtual void VTable0xe4(); // vtable+0xe4 + virtual void SpawnPlayer(LegoGameState::Area p_area, MxBool p_und, MxU8 p_flags); // vtable+0xe8 + virtual void VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset); // vtable+0xec + + // SYNTHETIC: LEGO1 0x10002ff0 + // IslePathActor::`scalar deleting destructor' + + inline void SetWorld(LegoWorld* p_world) { m_world = p_world; } + inline LegoWorld* GetWorld() { return m_world; } + + void FUN_1001b660(); + + static void RegisterSpawnLocations(); + +protected: + LegoWorld* m_world; // 0x154 + IslePathActor* m_unk0x158; // 0x158 + MxFloat m_unk0x15c; // 0x15c +}; + +#endif // ISLEPATHACTOR_H diff --git a/LEGO1/lego/legoomni/include/jailentity.h b/LEGO1/lego/legoomni/include/jailentity.h new file mode 100644 index 00000000..adf7089a --- /dev/null +++ b/LEGO1/lego/legoomni/include/jailentity.h @@ -0,0 +1,29 @@ +#ifndef JAILENTITY_H +#define JAILENTITY_H + +#include "buildingentity.h" + +// VTABLE: LEGO1 0x100d5200 +// SIZE 0x68 +class JailEntity : public BuildingEntity { + // FUNCTION: LEGO1 0x1000f0c0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0300 + return "RaceStandsEntity"; + } + + // FUNCTION: LEGO1 0x1000f0d0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, JailEntity::ClassName()) || BuildingEntity::IsA(p_name); + } + + // STUB: LEGO1 0x100154f0 + MxLong VTable0x50(MxParam& p_param) override { return 0; } + + // SYNTHETIC: LEGO1 0x1000fac0 + // JailEntity::`scalar deleting destructor' +}; + +#endif // JAILENTITY_H diff --git a/LEGO1/lego/legoomni/include/jetski.h b/LEGO1/lego/legoomni/include/jetski.h new file mode 100644 index 00000000..263b2a4f --- /dev/null +++ b/LEGO1/lego/legoomni/include/jetski.h @@ -0,0 +1,47 @@ +#ifndef JETSKI_H +#define JETSKI_H + +#include "decomp.h" +#include "islepathactor.h" + +class LegoControlManagerEvent; + +// VTABLE: LEGO1 0x100d9ec8 +// SIZE 0x164 +class Jetski : public IslePathActor { +public: + Jetski(); + + // FUNCTION: LEGO1 0x1007e430 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03d8 + return "Jetski"; + } + + // FUNCTION: LEGO1 0x1007e440 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Jetski::ClassName()) || IslePathActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void VTable0x70(float p_float) override; // vtable+0x70 + MxU32 VTable0xcc() override; // vtable+0xcc + MxU32 VTable0xd4(LegoControlManagerEvent&) override; // vtable+0xd4 + void VTable0xe4() override; // vtable+0xe4 + + void FUN_1007e990(); + + inline MxS16 GetUnknown0x160() { return m_unk0x160; } + + // SYNTHETIC: LEGO1 0x1007e5c0 + // Jetski::`scalar deleting destructor' + +private: + // TODO: Jetski fields + MxS16 m_unk0x160; // 0x160 + undefined m_unk0x162[2]; // 0x162 +}; + +#endif // JETSKI_H diff --git a/LEGO1/lego/legoomni/include/jetskirace.h b/LEGO1/lego/legoomni/include/jetskirace.h new file mode 100644 index 00000000..4d039f70 --- /dev/null +++ b/LEGO1/lego/legoomni/include/jetskirace.h @@ -0,0 +1,34 @@ +#ifndef JETSKIRACE_H +#define JETSKIRACE_H + +#include "legorace.h" + +// VTABLE: LEGO1 0x100d4fe8 +// SIZE 0x144 +class JetskiRace : public LegoRace { +public: + // FUNCTION: LEGO1 0x1000daf0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0530 + return "JetskiRace"; + } + + // FUNCTION: LEGO1 0x1000db00 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, JetskiRace::ClassName()) || LegoRace::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x64() override; // vtable+0x64 + undefined4 VTable0x6c(undefined4) override; // vtable+0x6c + undefined4 VTable0x70(undefined4) override; // vtable+0x70 + undefined4 VTable0x74(undefined4) override; // vtable+0x74 +}; + +// SYNTHETIC: LEGO1 0x1000f530 +// JetskiRace::`scalar deleting destructor' + +#endif // JETSKIRACE_H diff --git a/LEGO1/lego/legoomni/include/jetskiracestate.h b/LEGO1/lego/legoomni/include/jetskiracestate.h new file mode 100644 index 00000000..812a0a0f --- /dev/null +++ b/LEGO1/lego/legoomni/include/jetskiracestate.h @@ -0,0 +1,27 @@ +#ifndef JETSKIRACESTATE_H +#define JETSKIRACESTATE_H + +#include "racestate.h" + +// VTABLE: LEGO1 0x100d4fa8 +// SIZE 0x2c +class JetskiRaceState : public RaceState { +public: + // FUNCTION: LEGO1 0x1000dc40 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f00ac + return "JetskiRaceState"; + } + + // FUNCTION: LEGO1 0x1000dc50 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, JetskiRaceState::ClassName()) || RaceState::IsA(p_name); + } + + // SYNTHETIC: LEGO1 0x1000f680 + // JetskiRaceState::`scalar deleting destructor' +}; + +#endif // JETSKIRACESTATE_H diff --git a/LEGO1/lego/legoomni/include/jukebox.h b/LEGO1/lego/legoomni/include/jukebox.h new file mode 100644 index 00000000..260fb9a5 --- /dev/null +++ b/LEGO1/lego/legoomni/include/jukebox.h @@ -0,0 +1,51 @@ +#ifndef JUKEBOX_H +#define JUKEBOX_H + +#include "decomp.h" +#include "legogamestate.h" +#include "legoworld.h" + +class LegoControlManagerEvent; +class JukeBoxState; + +// VTABLE: LEGO1 0x100d8958 +// SIZE 0x104 +class JukeBox : public LegoWorld { +public: + JukeBox(); + ~JukeBox() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1005d6f0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f02cc + return "JukeBox"; + } + + // FUNCTION: LEGO1 0x1005d700 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, JukeBox::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x5c() override; // vtable+0x5c + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + // SYNTHETIC: LEGO1 0x1005d810 + // JukeBox::`scalar deleting destructor' + +private: + MxBool HandleClick(LegoControlManagerEvent& p_param); + + LegoGameState::Area m_destLocation; // 0xf8 + JukeBoxState* m_state; // 0xfc + undefined2 m_unk0x100; // 0x100 +}; + +#endif // JUKEBOX_H diff --git a/LEGO1/lego/legoomni/include/jukeboxentity.h b/LEGO1/lego/legoomni/include/jukeboxentity.h new file mode 100644 index 00000000..4166cf1e --- /dev/null +++ b/LEGO1/lego/legoomni/include/jukeboxentity.h @@ -0,0 +1,41 @@ +#ifndef JUKEBOXENTITY_H +#define JUKEBOXENTITY_H + +#include "actionsfwd.h" +#include "legoentity.h" + +// VTABLE: LEGO1 0x100da8a0 +// SIZE 0x6c +class JukeBoxEntity : public LegoEntity { +public: + JukeBoxEntity(); + ~JukeBoxEntity() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10085cc0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f02f0 + return "JukeBoxEntity"; + } + + // FUNCTION: LEGO1 0x10085cd0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, JukeBoxEntity::ClassName()) || LegoEntity::IsA(p_name); + } + + void StartAction(); + void StopAction(JukeboxScript::Script p_script); + + inline MxBool IsBackgroundAudioEnabled() { return m_audioEnabled; } + + // SYNTHETIC: LEGO1 0x10085db0 + // JukeBoxEntity::`scalar deleting destructor' + +protected: + MxBool m_audioEnabled; // 0x68 +}; + +#endif // JUKEBOXENTITY_H diff --git a/LEGO1/lego/legoomni/include/jukeboxstate.h b/LEGO1/lego/legoomni/include/jukeboxstate.h new file mode 100644 index 00000000..dc465dfd --- /dev/null +++ b/LEGO1/lego/legoomni/include/jukeboxstate.h @@ -0,0 +1,38 @@ +#ifndef JUKEBOXSTATE_H +#define JUKEBOXSTATE_H + +#include "legostate.h" + +// VTABLE: LEGO1 0x100d4a90 +// SIZE 0x10 +class JukeBoxState : public LegoState { +public: + // FUNCTION: LEGO1 0x1000f310 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f02bc + return "JukeBoxState"; + } + + // FUNCTION: LEGO1 0x1000f320 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, JukeBoxState::ClassName()) || LegoState::IsA(p_name); + } + + MxBool IsSerializable() override; // vtable+0x14 + + inline MxU32 IsActive() { return m_active; } + inline void SetActive(MxU32 p_active) { m_active = p_active; } + inline MxU32 GetState() { return m_state; } + inline void SetState(MxU32 p_state) { m_state = p_state; } + + // SYNTHETIC: LEGO1 0x1000f3d0 + // JukeBoxState::`scalar deleting destructor' + +protected: + MxU32 m_state; // 0x08 + MxU32 m_active; // 0x0c +}; + +#endif // JUKEBOXSTATE_H diff --git a/LEGO1/lego/legoomni/include/lego3dwavepresenter.h b/LEGO1/lego/legoomni/include/lego3dwavepresenter.h new file mode 100644 index 00000000..79be1834 --- /dev/null +++ b/LEGO1/lego/legoomni/include/lego3dwavepresenter.h @@ -0,0 +1,38 @@ +#ifndef LEGO3DWAVEPRESENTER_H +#define LEGO3DWAVEPRESENTER_H + +#include "decomp.h" +#include "legounknown100d5778.h" +#include "mxwavepresenter.h" + +// VTABLE: LEGO1 0x100d52b0 +// SIZE 0xa0 +class Lego3DWavePresenter : public MxWavePresenter { +public: + // FUNCTION: LEGO1 0x1000d890 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f058c + return "Lego3DWavePresenter"; + } + + // FUNCTION: LEGO1 0x1000d8a0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Lego3DWavePresenter::ClassName()) || MxWavePresenter::IsA(p_name); + } + + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + + // SYNTHETIC: LEGO1 0x1000f4b0 + // Lego3DWavePresenter::`scalar deleting destructor' + +private: + undefined m_unk0x6c[4]; // 0x6c + LegoUnknown100d5778 m_unk0x70; // 0x70 +}; + +#endif // LEGO3DWAVEPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legoact2.h b/LEGO1/lego/legoomni/include/legoact2.h new file mode 100644 index 00000000..c7dd6a35 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoact2.h @@ -0,0 +1,50 @@ +#ifndef LEGOACT2_H +#define LEGOACT2_H + +#include "act2brick.h" +#include "legoworld.h" + +// VTABLE: LEGO1 0x100d82e0 +// SIZE 0x1154 +class LegoAct2 : public LegoWorld { +public: + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x5c() override; // vtable+0x5c + void VTable0x60() override; // vtable+0x60 + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + inline void SetUnknown0x1150(undefined4 p_unk0x1150) { m_unk0x1150 = p_unk0x1150; } + + // SYNTHETIC: LEGO1 0x1004fe20 + // LegoAct2::`scalar deleting destructor' + +private: + Act2Brick m_bricks[10]; // 0x00f8 + undefined m_unk0x10c0; // 0x10c0 + undefined m_unk0x10c1; // 0x10c1 + undefined m_unk0x10c2; // 0x10c2 + undefined4 m_unk0x10c4; // 0x10c4 + undefined4 m_unk0x10c8; // 0x10c8 + undefined4 m_unk0x10cc; // 0x10cc + undefined4 m_unk0x10d0; // 0x10d0 + char* m_unk0x10d4; // 0x10d4 + undefined4 m_unk0x10d8; // 0x10d8 + MxMatrix m_unk0x10dc; // 0x10dc + undefined4 m_unk0x1124; // 0x1124 + undefined4 m_unk0x1128; // 0x1128 + undefined4 m_unk0x112c; // 0x112c + undefined4 m_unk0x1130; // 0x1130 + undefined4 m_unk0x1134; // 0x1134 + undefined4 m_unk0x1138; // 0x1138 + undefined m_unk0x113c; // 0x113c + undefined4 m_unk0x1140; // 0x1140 + undefined4 m_unk0x1144; // 0x1144 + undefined m_unk0x1148[0x08]; // 0x1148 + undefined4 m_unk0x1150; // 0x1150 +}; + +#endif // LEGOACT2_H diff --git a/LEGO1/lego/legoomni/include/legoact2state.h b/LEGO1/lego/legoomni/include/legoact2state.h new file mode 100644 index 00000000..5f046e74 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoact2state.h @@ -0,0 +1,38 @@ +#ifndef LEGOACT2STATE_H +#define LEGOACT2STATE_H + +#include "legostate.h" + +// VTABLE: LEGO1 0x100d4a70 +// SIZE 0x10 +class LegoAct2State : public LegoState { +public: + ~LegoAct2State() override {} + + // FUNCTION: LEGO1 0x1000df80 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0428 + return "LegoAct2State"; + } + + // FUNCTION: LEGO1 0x1000df90 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoAct2State::ClassName()) || LegoState::IsA(p_name); + } + + MxBool IsSerializable() override; // vtable+0x14 + + // SYNTHETIC: LEGO1 0x1000e040 + // LegoAct2State::`scalar deleting destructor' + + inline undefined4 GetUnknown0x08() { return m_unk0x08; } + inline void SetUnknown0x0c(undefined p_unk0x0c) { m_unk0x0c = p_unk0x0c; } + +private: + undefined4 m_unk0x08; // 0x08 + undefined m_unk0x0c; // 0x0c +}; + +#endif // LEGOACT2STATE_H diff --git a/LEGO1/lego/legoomni/include/legoactioncontrolpresenter.h b/LEGO1/lego/legoomni/include/legoactioncontrolpresenter.h new file mode 100644 index 00000000..98ee03f2 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoactioncontrolpresenter.h @@ -0,0 +1,44 @@ +#ifndef LEGOACTIONCONTROLPRESENTER_H +#define LEGOACTIONCONTROLPRESENTER_H + +#include "decomp.h" +#include "extra.h" +#include "mxmediapresenter.h" +#include "mxstring.h" + +// VTABLE: LEGO1 0x100d5118 +// SIZE 0x68 +class LegoActionControlPresenter : public MxMediaPresenter { +public: + LegoActionControlPresenter() { m_unk0x50 = Extra::ActionType::e_none; } + ~LegoActionControlPresenter() override { Destroy(TRUE); } // vtable+0x00 + + // FUNCTION: LEGO1 0x1000d0e0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f05bc + return "LegoActionControlPresenter"; + } + + // FUNCTION: LEGO1 0x1000d0f0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoActionControlPresenter::ClassName()) || MxMediaPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void RepeatingTickle() override; // vtable+0x24 + void ParseExtra() override; // vtable+0x30 + MxResult AddToManager() override; // vtable+0x34 + virtual void Destroy(MxBool p_fromDestructor); // vtable+0x5c + +private: + Extra::ActionType m_unk0x50; // 0x50 + MxString m_unk0x54; // 0x54 + undefined4 m_unk0x64; // 0x64 +}; + +// SYNTHETIC: LEGO1 0x1000d1d0 +// LegoActionControlPresenter::`scalar deleting destructor' + +#endif // LEGOACTIONCONTROLPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legoactor.h b/LEGO1/lego/legoomni/include/legoactor.h new file mode 100644 index 00000000..ebde373c --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoactor.h @@ -0,0 +1,64 @@ +#ifndef LEGOACTOR_H +#define LEGOACTOR_H + +#include "decomp.h" +#include "legoentity.h" + +class LegoCacheSound; + +// VTABLE: LEGO1 0x100d6d68 +// SIZE 0x78 +class LegoActor : public LegoEntity { +public: + LegoActor(); + ~LegoActor() override; + + // FUNCTION: LEGO1 0x1002d210 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0124 + return "LegoActor"; + } + + // FUNCTION: LEGO1 0x1002d220 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoActor::ClassName()) || LegoEntity::IsA(p_name); + } + + void ParseAction(char* p_extra) override; // vtable+0x20 + void SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2) override; // vtable+0x24 + + // FUNCTION: LEGO1 0x10002cc0 + virtual MxFloat VTable0x50() { return m_unk0x68; } // vtable+0x50 + + // FUNCTION: LEGO1 0x10002cd0 + virtual void VTable0x54(MxFloat p_unk0x68) { m_unk0x68 = p_unk0x68; } // vtable+0x54 + + // FUNCTION: LEGO1 0x10002ce0 + virtual void VTable0x58(MxFloat p_unk0x70) { m_unk0x70 = p_unk0x70; } // vtable+0x58 + + // FUNCTION: LEGO1 0x10002cf0 + virtual MxFloat VTable0x5c() { return m_unk0x70; } // vtable+0x5c + + // FUNCTION: LEGO1 0x10002d00 + virtual MxU8 GetActorId() { return m_actorId; } // vtable+0x60 + + // FUNCTION: LEGO1 0x10002d10 + virtual void SetActorId(MxU8 p_actorId) { m_actorId = p_actorId; } // vtable+0x64 + + static const char* GetActorName(MxU8 p_id); + +protected: + void FUN_1002d6e0(MxBool); + + MxFloat m_unk0x68; // 0x68 + LegoCacheSound* m_sound; // 0x6c + MxFloat m_unk0x70; // 0x70 + MxU8 m_actorId; // 0x74 +}; + +// SYNTHETIC: LEGO1 0x1002d300 +// LegoActor::`scalar deleting destructor' + +#endif // LEGOACTOR_H diff --git a/LEGO1/lego/legoomni/include/legoactorpresenter.h b/LEGO1/lego/legoomni/include/legoactorpresenter.h new file mode 100644 index 00000000..aea15b64 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoactorpresenter.h @@ -0,0 +1,36 @@ +#ifndef LEGOACTORPRESENTER_H +#define LEGOACTORPRESENTER_H + +#include "legoentitypresenter.h" + +// VTABLE: LEGO1 0x100d5320 +// SIZE 0x50 +class LegoActorPresenter : public LegoEntityPresenter { +public: + // LegoActorPresenter() {} + + // FUNCTION: LEGO1 0x100679c0 + ~LegoActorPresenter() override {} + + // FUNCTION: LEGO1 0x1000cb10 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f06a4 + return "LegoActorPresenter"; + } + + // FUNCTION: LEGO1 0x1000cb20 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoActorPresenter::ClassName()) || LegoEntityPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void ParseExtra() override; // vtable+0x30 +}; + +// SYNTHETIC: LEGO1 0x1000cc30 +// LegoActorPresenter::`scalar deleting destructor' + +#endif // LEGOACTORPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legoanimactor.h b/LEGO1/lego/legoomni/include/legoanimactor.h new file mode 100644 index 00000000..296c48d0 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoanimactor.h @@ -0,0 +1,93 @@ +#ifndef LEGOANIMACTOR_H +#define LEGOANIMACTOR_H + +#include "decomp.h" +#include "legopathactor.h" + +class LegoAnim; + +// SIZE 0x20 +struct LegoAnimActorStruct { + LegoAnimActorStruct(float p_unk0x00, LegoAnim* p_AnimTreePtr, LegoROI** p_roiMap, MxU32 p_numROIs); + ~LegoAnimActorStruct(); + + float GetDuration(); + + inline float GetUnknown0x00() { return m_unk0x00; } + + float m_unk0x00; // 0x00 + LegoAnim* m_AnimTreePtr; // 0x04 + LegoROI** m_roiMap; // 0x08 + MxU32 m_numROIs; // 0x0c + vector m_unk0x10; // 0x10 +}; + +// VTABLE: LEGO1 0x100d5440 LegoPathActor +// VTABLE: LEGO1 0x100d5510 LegoAnimActor +// SIZE 0x174 +class LegoAnimActor : public virtual LegoPathActor { +public: + LegoAnimActor() { m_curAnim = -1; } + ~LegoAnimActor() override; + + // FUNCTION: LEGO1 0x1000fba0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f057c + return "LegoAnimActor"; + } + + // FUNCTION: LEGO1 0x1000fbc0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoAnimActor::ClassName()) || LegoPathActor::IsA(p_name); + } + + void ParseAction(char* p_extra) override; // vtable+0x20 + void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 + void VTable0x70(float p_und) override; // vtable+0x70 + void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 + + virtual MxResult FUN_1001c1f0(float& p_und); + virtual MxResult FUN_1001c360(float, Matrix4& p_transform); + virtual MxResult FUN_1001c450(LegoAnim* p_AnimTreePtr, float p_unk0x00, LegoROI** p_roiMap, MxU32 p_numROIs); + virtual void ClearMaps(); + + // SYNTHETIC: LEGO1 0x1000fb60 + // LegoAnimActor::`scalar deleting destructor' + +protected: + vector m_animMaps; // 0x08 + MxS16 m_curAnim; // 0x18 +}; + +// clang-format off +// TEMPLATE: LEGO1 0x1000da20 +// vector >::~vector > + +// TEMPLATE: LEGO1 0x1000da60 +// Vector::~Vector + +// SYNTHETIC: LEGO1 0x10012b90 +// LegoAnimActor::`vbase destructor' + +// TEMPLATE: LEGO1 0x1001c010 +// vector >::~vector > + +// TEMPLATE: LEGO1 0x1001c050 +// Vector::~Vector + +// TEMPLATE: LEGO1 0x1001c7c0 +// vector >::size + +// TEMPLATE: LEGO1 0x1001c7e0 +// vector >::_Destroy + +// TEMPLATE: LEGO1 0x1001c9e0 +// uninitialized_fill_n + +// TEMPLATE: LEGO1 0x1001ca10 +// uninitialized_copy +// clang-format on + +#endif // LEGOANIMACTOR_H diff --git a/LEGO1/lego/legoomni/include/legoanimationmanager.h b/LEGO1/lego/legoomni/include/legoanimationmanager.h new file mode 100644 index 00000000..30d72d41 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoanimationmanager.h @@ -0,0 +1,200 @@ +#ifndef LEGOANIMATIONMANAGER_H +#define LEGOANIMATIONMANAGER_H + +#include "actionsfwd.h" +#include "decomp.h" +#include "legolocations.h" +#include "legotraninfolist.h" +#include "mxcore.h" +#include "mxgeometry/mxgeometry3d.h" + +class AnimState; +class LegoAnimPresenter; +class LegoEntity; +class LegoExtraActor; +class LegoFile; +class LegoPathBoundary; +class LegoROIList; +class LegoWorld; +struct ModelInfo; +class MxDSAction; + +// VTABLE: LEGO1 0x100d8c18 +// SIZE 0x500 +class LegoAnimationManager : public MxCore { +public: + // SIZE 0x18 + struct Character { + char* m_name; // 0x00 + MxBool m_unk0x04; // 0x04 + MxS8 m_vehicleId; // 0x05 + undefined m_unk0x06; // 0x06 (unused?) + MxBool m_unk0x07; // 0x07 + MxBool m_unk0x08; // 0x08 + MxBool m_unk0x09; // 0x09 + MxU32 m_unk0x0c; // 0x0c + MxS32 m_unk0x10; // 0x10 + MxBool m_active; // 0x14 + MxU8 m_unk0x15; // 0x15 + MxU8 m_unk0x16; // 0x16 + }; + + // SIZE 0x08 + struct Vehicle { + char* m_name; // 0x00 + MxBool m_unk0x04; // 0x04 + MxBool m_unk0x05; // 0x05 + }; + + // SIZE 0x18 + struct Extra { + LegoROI* m_roi; // 0x00 + MxS32 m_characterId; // 0x04 + MxLong m_unk0x08; // 0x08 + undefined m_unk0x0c; // 0x0c + MxBool m_unk0x0d; // 0x0d + float m_unk0x10; // 0x10 + MxBool m_unk0x14; // 0x14 + }; + + LegoAnimationManager(); + ~LegoAnimationManager() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1005ec80 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f7508 + return "LegoAnimationManager"; + } + + // FUNCTION: LEGO1 0x1005ec90 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || MxCore::IsA(p_name); + } + + void Reset(MxBool p_und); + void Suspend(); + void Resume(); + void FUN_1005f6d0(MxBool p_unk0x400); + void FUN_1005f700(MxBool p_unk0x3a); + MxResult LoadScriptInfo(MxS32 p_scriptIndex); + MxBool FindVehicle(const char* p_name, MxU32& p_index); + MxResult ReadAnimInfo(LegoFile* p_file, AnimInfo* p_info); + MxResult ReadModelInfo(LegoFile* p_file, ModelInfo* p_info); + void FUN_10060570(MxBool p_unk0x1a); + MxResult StartEntityAction(MxDSAction& p_dsAction, LegoEntity* p_entity); + MxResult FUN_10060dc0( + IsleScript::Script p_objectId, + MxMatrix* p_matrix, + MxBool p_param3, + MxBool p_param4, + LegoROI* p_roi, + MxBool p_param6, + MxBool p_param7, + MxBool p_param8, + MxBool p_param9 + ); + void FUN_10061010(MxBool p_und); + LegoTranInfo* GetTranInfo(MxU32 p_index); + void FUN_10062770(); + void PurgeExtra(MxBool p_und); + void AddExtra(MxS32 p_location, MxBool p_und); + void FUN_10063270(LegoROIList*, LegoAnimPresenter*); + void FUN_10063780(LegoROIList* p_list); + void FUN_10064670(Vector3*); + void FUN_10064740(Vector3*); + + static void configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig); + + // SYNTHETIC: LEGO1 0x1005ed10 + // LegoAnimationManager::`scalar deleting destructor' + +private: + void Init(); + MxResult FUN_100605e0( + MxU32 p_index, + MxBool p_unk0x0a, + MxMatrix* p_matrix, + MxBool p_bool1, + LegoROI* p_roi, + MxBool p_bool2, + MxBool p_bool3, + MxBool p_bool4, + MxBool p_bool5 + ); + MxResult FUN_100609f0(MxU32 p_objectId, MxMatrix* p_matrix, MxBool p_und1, MxBool p_und2); + void DeleteAnimations(); + void FUN_10061530(); + MxResult FUN_100617c0(MxS32 p_unk0x08, MxU16& p_unk0x0e, MxU16& p_unk0x10); + MxU16 FUN_10062110( + LegoROI* p_roi, + Vector3& p_direction, + Vector3& p_position, + LegoPathBoundary* p_boundary, + float p_speed, + MxU8 p_unk0x0c, + MxBool p_unk0x14 + ); + MxS8 GetCharacterIndex(const char* p_name); + MxBool FUN_100623a0(AnimInfo& p_info); + MxBool ModelExists(AnimInfo& p_info, const char* p_name); + void FUN_10062580(AnimInfo& p_info); + MxBool FUN_10062650(Vector3& p_position, float p_und, LegoROI* p_roi); + MxBool FUN_10062710(AnimInfo& p_info); + void FUN_10063aa0(); + MxBool FUN_10063b90(LegoWorld* p_world, LegoExtraActor* p_actor, MxU8 p_unk0x14, MxU32 p_characterId); + void FUN_10063d10(); + MxBool FUN_10063fb0(LegoLocation::Boundary* p_boundary, LegoWorld* p_world); + MxBool FUN_10064120(LegoLocation::Boundary* p_boundary, MxBool, MxBool); + void FUN_100648f0(LegoTranInfo*, MxLong); + void FUN_10064b50(MxLong p_time); + + MxS32 m_scriptIndex; // 0x08 + MxU16 m_animCount; // 0x0c + MxU16 m_unk0x0e; // 0x0e + MxU16 m_unk0x10; // 0x10 + AnimInfo* m_anims; // 0x14 + undefined2 m_unk0x18; // 0x18 + MxBool m_unk0x1a; // 0x1a + MxU32 m_unk0x1c; // 0x1c + LegoTranInfoList* m_tranInfoList; // 0x20 + LegoTranInfoList* m_tranInfoList2; // 0x24 + MxPresenter* m_unk0x28[2]; // 0x28 + MxLong m_unk0x30[2]; // 0x30 + MxBool m_unk0x38; // 0x38 + MxBool m_unk0x39; // 0x39 + MxBool m_unk0x3a; // 0x3a + Extra m_extras[40]; // 0x3c + MxU32 m_lastExtraCharacterId; // 0x3fc + MxBool m_unk0x400; // 0x400 + MxBool m_unk0x401; // 0x401 + MxBool m_unk0x402; // 0x402 + MxLong m_unk0x404; // 0x404 + MxLong m_unk0x408; // 0x408 + MxLong m_unk0x40c; // 0x40c + MxLong m_unk0x410; // 0x410 + MxU32 m_unk0x414; // 0x414 + MxU32 m_numAllowedExtras; // 0x418 + undefined4 m_unk0x41c; // 0x41c + AnimState* m_animState; // 0x420 + LegoROIList* m_unk0x424; // 0x424 + MxBool m_unk0x428; // 0x428 + MxBool m_unk0x429; // 0x429 + MxBool m_unk0x42a; // 0x42a + MxBool m_suspended; // 0x42b + LegoTranInfo* m_unk0x42c; // 0x42c + MxBool m_unk0x430; // 0x430 + undefined4 m_unk0x434[2]; // 0x434 + MxMatrix m_unk0x43c; // 0x43c + MxMatrix m_unk0x484; // 0x484 + UnknownMx4DPointFloat m_unk0x4cc; // 0x4cc +}; + +// TEMPLATE: LEGO1 0x10061750 +// MxListCursor::MxListCursor + +#endif // LEGOANIMATIONMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legoanimmmpresenter.h b/LEGO1/lego/legoomni/include/legoanimmmpresenter.h new file mode 100644 index 00000000..4ca63a7b --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoanimmmpresenter.h @@ -0,0 +1,88 @@ +#ifndef LEGOANIMMMPRESENTER_H +#define LEGOANIMMMPRESENTER_H + +#include "mxcompositepresenter.h" + +class LegoAnimPresenter; +class LegoWorld; +class LegoROI; +struct LegoTranInfo; +class MxMatrix; + +// VTABLE: LEGO1 0x100d7de8 +// SIZE 0x74 +class LegoAnimMMPresenter : public MxCompositePresenter { +public: + enum { + e_unk0, + e_unk1, + e_unk2, + e_unk3, + e_unk4, + e_unk5, + e_unk6, + e_unk7 + }; + + LegoAnimMMPresenter(); + ~LegoAnimMMPresenter() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x1004a950 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f046c + return "LegoAnimMMPresenter"; + } + + // FUNCTION: LEGO1 0x1004a960 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoAnimMMPresenter::ClassName()) || MxCompositePresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + void RepeatingTickle() override; // vtable+0x24 + void DoneTickle() override; // vtable+0x2c + void ParseExtra() override; // vtable+0x30 + MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c + void EndAction() override; // vtable+0x40 + void VTable0x60(MxPresenter* p_presenter) override; // vtable+0x60 + + // SYNTHETIC: LEGO1 0x1004aa40 + // LegoAnimMMPresenter::`scalar deleting destructor' + + void FUN_1004b840(); + MxBool FUN_1004b8b0(); + void FUN_1004b8c0(); + + inline LegoAnimPresenter* GetPresenter() { return m_presenter; } + +private: + MxBool FUN_1004b450(); + MxBool FUN_1004b530(MxLong p_time); + MxBool FUN_1004b570(MxLong p_time); + MxBool FUN_1004b580(MxLong p_time); + MxBool FUN_1004b5b0(MxLong p_time); + MxBool FUN_1004b600(MxLong p_time); + MxBool FUN_1004b610(MxLong p_time); + MxBool FUN_1004b6b0(MxLong p_time); + MxBool FUN_1004b6d0(MxLong p_time); + + LegoAnimPresenter* m_presenter; // 0x4c + MxLong m_unk0x50; // 0x50 + undefined4 m_unk0x54; // 0x54 + MxU8 m_unk0x58; // 0x58 + MxU8 m_unk0x59; // 0x59 + MxU32 m_animmanId; // 0x5c + LegoTranInfo* m_tranInfo; // 0x60 + LegoWorld* m_unk0x64; // 0x64 + MxMatrix* m_unk0x68; // 0x68 + LegoROI** m_roiMap; // 0x6c + MxU32 m_roiMapSize; // 0x70 +}; + +#endif // LEGOANIMMMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legoanimpresenter.h b/LEGO1/lego/legoomni/include/legoanimpresenter.h new file mode 100644 index 00000000..09fd00a8 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoanimpresenter.h @@ -0,0 +1,194 @@ +#ifndef LEGOANIMPRESENTER_H +#define LEGOANIMPRESENTER_H + +#include "legoroilist.h" +#include "mxatom.h" +#include "mxvideopresenter.h" + +class LegoAnim; +class LegoWorld; +class LegoAnimActor; +class LegoPathBoundary; +class MxMatrix; +class Vector3; + +struct LegoAnimStructComparator { + MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; } +}; + +struct LegoAnimSubstComparator { + MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; } +}; + +// SIZE 0x08 +struct LegoAnimStruct { + LegoROI* m_roi; // 0x00 + MxU32 m_index; // 0x04 +}; + +typedef map LegoAnimStructMap; +typedef map LegoAnimSubstMap; + +// VTABLE: LEGO1 0x100d90c8 +// SIZE 0xbc +class LegoAnimPresenter : public MxVideoPresenter { +public: + enum { + c_hideOnStop = 0x01, + c_mustSucceed = 0x02 + }; + + LegoAnimPresenter(); + ~LegoAnimPresenter() override; + + // FUNCTION: LEGO1 0x10068530 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f071c + return "LegoAnimPresenter"; + } + + // FUNCTION: LEGO1 0x10068540 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoAnimPresenter::ClassName()) || MxVideoPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + void DoneTickle() override; // vtable+0x2c + void ParseExtra() override; // vtable+0x30 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c + void EndAction() override; // vtable+0x40 + void PutFrame() override; // vtable+0x6c + virtual MxResult CreateAnim(MxStreamChunk* p_chunk); // vtable+0x88 + virtual void VTable0x8c(); // vtable+0x8c + virtual void VTable0x90(); // vtable+0x90 + virtual MxU32 VTable0x94(Vector3& p_vec1, Vector3& p_vec2, float p_f1, float p_f2, Vector3& p_vec3); // vtable+0x94 + virtual MxResult VTable0x98(LegoPathBoundary* p_boundary); // vtable+0x98 + + // FUNCTION: LEGO1 0x1000c990 + virtual LegoROI** GetROIMap(MxU32& p_roiMapSize) + { + p_roiMapSize = m_roiMapSize; + return m_roiMap; + } // vtable+0x9c + + virtual void VTable0xa0(Matrix4& p_matrix); // vtable+0xa0 + + MxResult FUN_1006afc0(MxMatrix*& p_matrix, float p_und); + MxResult FUN_1006b140(LegoROI* p_roi); + const char* GetActionObjectName(); + + inline LegoAnim* GetAnimation() { return m_anim; } + +protected: + void Init(); + void Destroy(MxBool p_fromDestructor); + LegoChar* FUN_10069150(const LegoChar* p_und1); + void FUN_100692b0(); + void FUN_100695c0(); + LegoChar* FUN_100697c0(const LegoChar* p_und1, const LegoChar* p_und2); + LegoBool FUN_100698b0(const CompoundObject& p_rois, const LegoChar* p_und2); + LegoROI* FUN_100699e0(const LegoChar* p_und); + void FUN_10069b10(); + void FUN_1006a3c0(LegoAnimStructMap& p_map, LegoTreeNode* p_node, LegoROI* p_roi); + void FUN_1006a4f0(LegoAnimStructMap& p_map, LegoAnimNodeData* p_data, const LegoChar* p_und, LegoROI* p_roi); + void FUN_1006aa60(); + void FUN_1006ab70(); + LegoBool FUN_1006aba0(); + MxBool FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi); + void SubstituteVariables(); + void FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); + void FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); + void FUN_1006c8a0(MxBool p_bool); + + LegoAnim* m_anim; // 0x64 + LegoROI** m_roiMap; // 0x68 + MxU32 m_roiMapSize; // 0x6c + LegoROIList* m_unk0x70; // 0x70 + LegoROIList* m_unk0x74; // 0x74 + MxMatrix* m_unk0x78; // 0x78 + MxU32 m_flags; // 0x7c + LegoWorld* m_currentWorld; // 0x80 + MxAtomId m_worldAtom; // 0x84 + MxS32 m_worldId; // 0x88 + LegoROI** m_unk0x8c; // 0x8c + char** m_unk0x90; // 0x90 + MxU8 m_unk0x94; // 0x94 + MxBool m_unk0x95; // 0x95 + MxBool m_unk0x96; // 0x96 + undefined m_unk0x97; // 0x97 + LegoAnimSubstMap* m_substMap; // 0x98 + MxS16 m_unk0x9c; // 0x9c + undefined4* m_unk0xa0; // 0xa0 + float m_unk0xa4; // 0xa4 + Mx3DPointFloat m_unk0xa8; // 0xa8 +}; + +// clang-format off +// SYNTHETIC: LEGO1 0x10068650 +// LegoAnimPresenter::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100689c0 +// map >::~map > + +// TEMPLATE: LEGO1 0x10068a10 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::~_Tree,map + +// TEMPLATE: LEGO1 0x10068ae0 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x10068b20 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x10068f70 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::_Erase + +// TEMPLATE: LEGO1 0x10069d80 +// _Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::~_Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x10069e90 +// _Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x1006a2e0 +// _Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::_Erase + +// TEMPLATE: LEGO1 0x1006a320 +// Map::~Map + +// TEMPLATE: LEGO1 0x1006a370 +// map >::~map > + +// TEMPLATE: LEGO1 0x1006a750 +// _Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x1006a7a0 +// _Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::_Insert + +// TEMPLATE: LEGO1 0x1006c1b0 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x1006c200 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::_Insert + +// TEMPLATE: LEGO1 0x1006c4b0 +// list >::~list > + +// TEMPLATE: LEGO1 0x1006c520 +// List::~List + +// GLOBAL: LEGO1 0x100f7680 +// _Tree,map >::_Kfn,LegoAnimSubstComparator,allocator >::_Nil + +// GLOBAL: LEGO1 0x100f7688 +// _Tree,map >::_Kfn,LegoAnimStructComparator,allocator >::_Nil +// clang-format on + +#endif // LEGOANIMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legobackgroundcolor.h b/LEGO1/lego/legoomni/include/legobackgroundcolor.h new file mode 100644 index 00000000..3e8b4457 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legobackgroundcolor.h @@ -0,0 +1,24 @@ +#ifndef LEGOBACKGROUNDCOLOR_H +#define LEGOBACKGROUNDCOLOR_H + +#include "mxvariable.h" + +// VTABLE: LEGO1 0x100d74a8 +// SIZE 0x30 +class LegoBackgroundColor : public MxVariable { +public: + LegoBackgroundColor(const char* p_key, const char* p_value); + + void SetValue(const char* p_colorString) override; + void SetLightColor(float p_r, float p_g, float p_b); + void SetLightColor(); + void ToggleDayNight(MxBool); + void ToggleSkyColor(); + +private: + float m_h; + float m_s; + float m_v; +}; + +#endif // LEGOBACKGROUNDCOLOR_H diff --git a/LEGO1/lego/legoomni/include/legobuildingmanager.h b/LEGO1/lego/legoomni/include/legobuildingmanager.h new file mode 100644 index 00000000..bec82ceb --- /dev/null +++ b/LEGO1/lego/legoomni/include/legobuildingmanager.h @@ -0,0 +1,108 @@ +#ifndef LEGOBUILDINGMANAGER_H +#define LEGOBUILDINGMANAGER_H + +#include "decomp.h" +#include "misc/legotypes.h" +#include "mxcore.h" + +class LegoEntity; +class LegoROI; +class LegoStorage; +class LegoWorld; +class LegoCacheSound; +class LegoPathBoundary; + +// SIZE 0x2c +struct LegoBuildingInfo { + enum { + c_bit1 = 0x01, + c_bit2 = 0x02, + c_bit3 = 0x04, + c_bit4 = 0x08 + }; + + LegoEntity* m_entity; // 0x00 + const char* m_hausName; // 0x04 + MxU32 m_cycle1; // 0x08 + MxU32 m_cycle2; // 0x0c + MxU8 m_cycle3; // 0x10 + MxS8 m_unk0x11; // 0x11 + MxS8 m_initialUnk0x11; // 0x12 = initial value loaded to m_unk0x11 + MxU8 m_flags; // 0x13 + float m_unk0x014; // 0x14 + const char* m_unk0x18; // 0x18 + float m_x; // 0x1c + float m_y; // 0x20 + float m_z; // 0x24 + LegoPathBoundary* m_boundary; // 0x28 +}; + +// VTABLE: LEGO1 0x100d6f50 +// SIZE 0x30 +class LegoBuildingManager : public MxCore { +public: + // SIZE 0x14 + struct AnimEntry { + LegoEntity* m_entity; // 0x00 + LegoROI* m_roi; // 0x04 + LegoTime m_time; // 0x08 + float m_unk0x0c; // 0x0c + MxBool m_muted; // 0x10 + }; + + LegoBuildingManager(); + ~LegoBuildingManager() override; + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1002f930 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f37d0 + return "LegoBuildingManager"; + } + + static void configureLegoBuildingManager(MxS32); + static void SetCustomizeAnimFile(const char* p_value); + + void Init(); + void FUN_1002fa00(); + void UpdatePosition(MxS32 p_index, LegoWorld* p_world); + void FUN_1002fb30(); + MxResult Write(LegoStorage* p_storage); + MxResult Read(LegoStorage* p_storage); + LegoBuildingInfo* GetInfo(LegoEntity* p_entity); + MxBool IncrementVariant(LegoEntity* p_entity); + MxBool FUN_1002fe40(LegoEntity* p_entity); + MxBool FUN_1002fe80(LegoEntity* p_entity); + MxBool FUN_1002fed0(LegoEntity* p_entity); + MxU32 GetBuildingEntityId(LegoEntity* p_entity); + MxU32 FUN_1002ff40(LegoEntity*, MxBool); + MxBool FUN_10030000(LegoEntity* p_entity); + MxBool FUN_10030030(MxS32 p_index); + MxBool FUN_10030110(LegoBuildingInfo* p_data); + void ScheduleAnimation(LegoEntity* p_entity, MxU32 p_length, MxBool p_haveSound, MxBool p_unk0x28); + void FUN_10030590(); + void AdjustHeight(MxS32 p_index); + MxResult FUN_10030630(); + LegoBuildingInfo* GetInfoArray(MxS32& p_length); + void FUN_100307b0(LegoEntity* p_entity, MxS32 p_adjust); + + static void FUN_10030800(); + + // SYNTHETIC: LEGO1 0x1002f940 + // LegoBuildingManager::`scalar deleting destructor' + +private: + static char* g_customizeAnimFile; + + MxU8 m_nextVariant; // 0x08 + MxU8 m_unk0x09; // 0x09 + AnimEntry* m_entries[5]; // 0x0c + MxS8 m_numEntries; // 0x20 + LegoCacheSound* m_sound; // 0x24 + MxBool m_unk0x28; // 0x28 + LegoWorld* m_world; // 0x2c +}; + +#endif // LEGOBUILDINGMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legocachesoundlist.h b/LEGO1/lego/legoomni/include/legocachesoundlist.h new file mode 100644 index 00000000..e480c34b --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocachesoundlist.h @@ -0,0 +1,103 @@ +#ifndef LEGOCACHESOUNDLIST_H +#define LEGOCACHESOUNDLIST_H + +#include "legocachsound.h" +#include "mxlist.h" +#include "mxtypes.h" + +// VTABLE: LEGO1 0x100d63b0 +// class MxCollection + +// VTABLE: LEGO1 0x100d63c8 +// class MxList + +// VTABLE: LEGO1 0x100d63e0 +// class MxPtrList + +// VTABLE: LEGO1 0x100d63f8 +// SIZE 0x18 +class LegoCacheSoundList : public MxPtrList { +public: + LegoCacheSoundList(MxBool p_ownership = FALSE) : MxPtrList(p_ownership) {} + + // FUNCTION: LEGO1 0x1001e650 + MxS8 Compare(LegoCacheSound* p_a, LegoCacheSound* p_b) override + { + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; + } // vtable+0x14 +}; + +// VTABLE: LEGO1 0x100d64a0 +// class MxListCursor + +// VTABLE: LEGO1 0x100d6500 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d6518 +// SIZE 0x10 +class LegoCacheSoundListCursor : public MxPtrListCursor { +public: + LegoCacheSoundListCursor(LegoCacheSoundList* p_list) : MxPtrListCursor(p_list) {} +}; + +// TEMPLATE: LEGO1 0x1001e670 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1001e680 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1001e6d0 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1001e6e0 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x1001e770 +// MxPtrList::Destroy + +// SYNTHETIC: LEGO1 0x1001e780 +// LegoCacheSoundList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001e7f0 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x1001e840 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001e8b0 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001e960 +// MxPtrList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001f350 +// LegoCacheSoundListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001f3c0 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x1001f410 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001f480 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001f4f0 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x1001f540 +// LegoCacheSoundListCursor::~LegoCacheSoundListCursor + +// TEMPLATE: LEGO1 0x10020840 +// MxListCursor::MxListCursor + +// TEMPLATE: LEGO1 0x100224e0 +// MxList::InsertEntry + +// TEMPLATE: LEGO1 0x10022590 +// MxListCursor::Find + +// TEMPLATE: LEGO1 0x10022680 +// MxList::DeleteEntry + +#endif // LEGOCACHESOUNDLIST_H diff --git a/LEGO1/lego/legoomni/include/legocachesoundmanager.h b/LEGO1/lego/legoomni/include/legocachesoundmanager.h new file mode 100644 index 00000000..67d139ff --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocachesoundmanager.h @@ -0,0 +1,120 @@ +#ifndef LEGOCACHESOUNDMANAGER_H +#define LEGOCACHESOUNDMANAGER_H + +#include "decomp.h" +#include "legocachsound.h" +#include "mxstl/stlcompat.h" +#include "mxtypes.h" + +#pragma warning(disable : 4237) + +// SIZE 0x08 +struct LegoCacheSoundEntry { + LegoCacheSoundEntry() : m_sound(NULL), m_name(NULL) {} + LegoCacheSoundEntry(LegoCacheSound* p_sound, const char* p_name) : m_sound(p_sound), m_name(p_name) {} + LegoCacheSoundEntry(LegoCacheSound* p_sound) : m_sound(p_sound), m_name(p_sound->GetString0x48().GetData()) {} + + // FUNCTION: LEGO1 0x1003d030 + ~LegoCacheSoundEntry() + { + if (m_sound == NULL && m_name != NULL) { + delete[] const_cast(m_name); + } + } + + bool operator==(LegoCacheSoundEntry) const { return 0; } + bool operator<(LegoCacheSoundEntry) const { return 0; } + + inline LegoCacheSound* GetSound() const { return m_sound; } + inline const char* GetName() const { return m_name; } + + friend struct Set100d6b4cComparator; + +private: + LegoCacheSound* m_sound; // 0x00 + const char* m_name; // 0x04 +}; + +struct Set100d6b4cComparator { + bool operator()(const LegoCacheSoundEntry& p_a, const LegoCacheSoundEntry& p_b) const + { + return strcmpi(p_a.m_name, p_b.m_name) > 0; + } +}; + +typedef set Set100d6b4c; +typedef list List100d6b4c; + +// VTABLE: LEGO1 0x100d6b4c +// SIZE 0x20 +class LegoCacheSoundManager { +public: + LegoCacheSoundManager() {} + ~LegoCacheSoundManager(); + + virtual MxResult Tickle(); // vtable+0x00 + + LegoCacheSound* FUN_1003d170(const char* p_key); + LegoCacheSound* FUN_1003d290(LegoCacheSound* p_sound); + LegoCacheSound* FUN_1003dae0(const char* p_one, const char* p_two, MxBool p_three); + LegoCacheSound* FUN_1003db10(LegoCacheSound* p_one, const char* p_two, MxBool p_three); + void FUN_1003dc40(LegoCacheSound** p_und); + +private: + Set100d6b4c m_set; // 0x04 + List100d6b4c m_list; // 0x14 +}; + +// TODO: Function names subject to change. + +// clang-format off +// TEMPLATE: LEGO1 0x10029c30 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::~_Tree >::_Kfn,Set100d6b4cComparator,allocator > + +// TEMPLATE: LEGO1 0x10029d10 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x10029d50 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x1002a1b0 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::_Erase + +// TEMPLATE: LEGO1 0x1002a210 +// list >::~list > + +// TEMPLATE: LEGO1 0x1002a2a0 +// set >::~set > + +// TEMPLATE: LEGO1 0x1002a2f0 +// Set::~Set + +// TEMPLATE: LEGO1 0x1002a340 +// List::~List + +// TEMPLATE: LEGO1 0x1003dab0 +// list >::_Buynode + +// TEMPLATE: LEGO1 0x1003d450 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::insert + +// TEMPLATE: LEGO1 0x1003d6f0 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x1003d740 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::_Buynode + +// TEMPLATE: LEGO1 0x1003d760 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::_Insert + +// TEMPLATE: LEGO1 0x1003d9f0 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::_Lrotate + +// TEMPLATE: LEGO1 0x1003da50 +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::_Rrotate + +// GLOBAL: LEGO1 0x100f31cc +// _Tree >::_Kfn,Set100d6b4cComparator,allocator >::_Nil +// clang-format on + +#endif // LEGOCACHESOUNDMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legocachsound.h b/LEGO1/lego/legoomni/include/legocachsound.h new file mode 100644 index 00000000..178430ff --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocachsound.h @@ -0,0 +1,64 @@ +#ifndef LEGOCACHSOUND_H +#define LEGOCACHSOUND_H + +#include "decomp.h" +#include "legounknown100d5778.h" +#include "mxcore.h" +#include "mxstring.h" + +// VTABLE: LEGO1 0x100d4718 +// SIZE 0x88 +class LegoCacheSound : public MxCore { +public: + LegoCacheSound(); + ~LegoCacheSound() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x10006580 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f01c4 + return "LegoCacheSound"; + } + + // FUNCTION: LEGO1 0x10006590 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoCacheSound::ClassName()) || MxCore::IsA(p_name); + } + + virtual MxResult FUN_10006710(); // vtable+0x14 + virtual void Destroy(); // vtable+0x18 + virtual void FUN_10006cd0(undefined4, undefined4); // vtable+0x1c + + inline const MxString& GetString0x48() const { return m_string0x48; } + inline const undefined GetUnk0x58() const { return m_unk0x58; } + + LegoCacheSound* FUN_10006960(); + MxResult FUN_10006a30(const char* p_str, MxBool); + void FUN_10006b80(); + void FUN_10006be0(); + void FUN_10006cb0(undefined4 p_und1, undefined4 p_und2); + + // SYNTHETIC: LEGO1 0x10006610 + // LegoCacheSound::`scalar deleting destructor' + +private: + void Init(); + + LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x08 + undefined m_unk0xc[4]; // 0x0c + LegoUnknown100d5778 m_unk0x10; // 0x10 + undefined* m_unk0x40; // 0x40 + undefined4 m_unk0x44; // 0x44 + MxString m_string0x48; // 0x48 + undefined m_unk0x58; // 0x58 + PCMWAVEFORMAT m_unk0x59; // 0x59 + MxBool m_isLooping; // 0x69 + MxBool m_unk0x6a; // 0x6a + undefined4 m_unk0x6c; // 0x6c + undefined m_unk0x70; // 0x70 + MxString m_string0x74; // 0x74 + undefined m_unk0x84; // 0x84 +}; + +#endif // LEGOCACHSOUND_H diff --git a/LEGO1/lego/legoomni/include/legocameracontroller.h b/LEGO1/lego/legoomni/include/legocameracontroller.h new file mode 100644 index 00000000..f7325286 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocameracontroller.h @@ -0,0 +1,54 @@ +#ifndef LEGOCAMERACONTROLLER_H +#define LEGOCAMERACONTROLLER_H + +#include "legopointofviewcontroller.h" +#include "mxgeometry/mxgeometry3d.h" +#include "mxgeometry/mxmatrix.h" +#include "mxpoint32.h" + +// VTABLE: LEGO1 0x100d57b0 +// SIZE 0xc8 +class LegoCameraController : public LegoPointOfViewController { +public: + LegoCameraController(); + ~LegoCameraController() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+04 + + // FUNCTION: LEGO1 0x10011ec0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0850 + return "LegoCameraController"; + } + + // FUNCTION: LEGO1 0x10011ed0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || MxCore::IsA(p_name); + } + + virtual void OnLButtonDown(MxPoint32 p_point); // vtable+0x30 + virtual void OnLButtonUp(MxPoint32 p_point); // vtable+0x34 + virtual void OnRButtonDown(MxPoint32 p_point); // vtable+0x38 + virtual void OnRButtonUp(MxPoint32 p_point); // vtable+0x3c + virtual void OnMouseMove(MxU8 p_modifier, MxPoint32 p_point); // vtable+0x40 + virtual MxResult Create(); // vtable+0x44 + + void SetWorldTransform(const Vector3& p_at, const Vector3& p_dir, const Vector3& p_up); + void FUN_10012290(float); + void FUN_10012320(MxFloat); + void FUN_100123e0(const Matrix4& p_transform, MxU32 p_und); + Mx3DPointFloat GetWorldUp(); + Mx3DPointFloat GetWorldLocation(); + Mx3DPointFloat GetWorldDirection(); + +private: + MxMatrix m_matrix1; // 0x38 + MxMatrix m_matrix2; // 0x80 +}; + +// SYNTHETIC: LEGO1 0x10011f50 +// LegoCameraController::`scalar deleting destructor' + +#endif // LEGOCAMERACONTROLLER_H diff --git a/LEGO1/lego/legoomni/include/legocarbuild.h b/LEGO1/lego/legoomni/include/legocarbuild.h new file mode 100644 index 00000000..0d2eccc1 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocarbuild.h @@ -0,0 +1,92 @@ +#ifndef LEGOCARBUILD_H +#define LEGOCARBUILD_H + +#include "legoworld.h" + +// VTABLE: LEGO1 0x100d6658 +// SIZE 0x34c +class LegoCarBuild : public LegoWorld { +public: + LegoCarBuild(); + ~LegoCarBuild() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x10022940 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0504 + return "LegoCarBuild"; + } + + // FUNCTION: LEGO1 0x10022950 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoCarBuild::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x5c() override; // vtable+0x5c + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + // SYNTHETIC: LEGO1 0x10022a60 + // LegoCarBuild::`scalar deleting destructor' + +private: + undefined4 m_unk0xf8; // 0xf8 + undefined m_unk0xfc[0x8]; // 0xfc + undefined4 m_unk0x104; // 0x104 + undefined m_unk0x108; // 0x108 + undefined m_unk0x109; // 0x109 + undefined4 m_unk0x10c; // 0x10c + undefined4 m_unk0x110; // 0x110 + Mx3DPointFloat m_unk0x114; // 0x114 + undefined4 m_unk0x128; // 0x128 + MxMatrix m_unk0x12c; // 0x12c + undefined m_unk0x174; // 0x174 + MxMatrix m_unk0x178; // 0x178 + MxMatrix m_unk0x1c0; // 0x1c0 + MxMatrix m_unk0x208; // 0x208 + undefined m_unk0x250[0x08]; // 0x250 + undefined4 m_unk0x258; // 0x258 + Mx4DPointFloat m_unk0x25c; // 0x25c + Mx4DPointFloat m_unk0x274; // 0x274 + undefined m_unk0x28c[0x18]; // 0x28c + Mx4DPointFloat m_unk0x2a4; // 0x2a4 + Mx4DPointFloat m_unk0x2bc; // 0x2bc + undefined m_unk0x2d4; // 0x2d4 + undefined4 m_unk0x2dc; // 0x2dc + undefined4 m_unk0x2e0; // 0x2e0 + undefined4 m_unk0x2e4; // 0x2e4 + undefined4 m_unk0x2e8; // 0x2e8 + undefined4 m_unk0x2ec; // 0x2ec + undefined4 m_unk0x2f0; // 0x2f0 + undefined4 m_unk0x2f4; // 0x2f4 + undefined4 m_unk0x2f8; // 0x2f8 + undefined4 m_unk0x2fc; // 0x2fc + undefined4 m_unk0x300; // 0x300 + undefined4 m_unk0x304; // 0x304 + undefined4 m_unk0x308; // 0x308 + undefined4 m_unk0x30c; // 0x30c + undefined4 m_unk0x310; // 0x310 + undefined4 m_unk0x314; // 0x314 + undefined4 m_unk0x318; // 0x318 + undefined4 m_unk0x31c; // 0x31c + undefined4 m_unk0x320; // 0x320 + undefined4 m_unk0x324; // 0x324 + undefined4 m_unk0x328; // 0x328 + undefined4 m_unk0x2d8; // 0x2d8 + undefined4 m_unk0x32c; // 0x32c + undefined4 m_unk0x330; // 0x330 + undefined4 m_unk0x334; // 0x334 + undefined4 m_unk0x338; // 0x338 + undefined4 m_unk0x33c; // 0x33c + undefined4 m_unk0x340; // 0x340 + undefined4 m_unk0x344; // 0x344 + undefined4 m_unk0x348; // 0x348 +}; + +#endif // LEGOCARBUILD_H diff --git a/LEGO1/lego/legoomni/include/legocarbuildanimpresenter.h b/LEGO1/lego/legoomni/include/legocarbuildanimpresenter.h new file mode 100644 index 00000000..5b72d2be --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocarbuildanimpresenter.h @@ -0,0 +1,55 @@ +#ifndef LEGOCARBUILDANIMPRESENTER_H +#define LEGOCARBUILDANIMPRESENTER_H + +#include "anim/legoanim.h" +#include "legoanimpresenter.h" + +// VTABLE: LEGO1 0x100d99e0 +// SIZE 0x150 +class LegoCarBuildAnimPresenter : public LegoAnimPresenter { +public: + LegoCarBuildAnimPresenter(); + ~LegoCarBuildAnimPresenter() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x10078510 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f05ec + return "LegoCarBuildAnimPresenter"; + } + + // FUNCTION: LEGO1 0x10078520 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoCarBuildAnimPresenter::ClassName()) || LegoAnimPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StreamingTickle() override; // vtable+0x20 + void RepeatingTickle() override; // vtable+0x24 + void EndAction() override; // vtable+0x40 + void PutFrame() override; // vtable+0x6c + + // SYNTHETIC: LEGO1 0x10078660 + // LegoCarBuildAnimPresenter::`scalar deleting destructor' + +private: + undefined2 m_unk0xbc; // 0xbc + undefined2 m_unk0xbe; // 0xbe + undefined2 m_unk0xc0; // 0xc0 + undefined4 m_unk0xc4; // 0xc4 + LegoAnim m_unk0xc8; // 0xc8 + MxMatrix m_unk0xe0; // 0xe0 + undefined4 m_unk0x128; // 0x128 + undefined4 m_unk0x12c; // 0x12c + undefined4 m_unk0x130; // 0x130 + undefined4 m_unk0x134; // 0x134 + undefined4 m_unk0x138; // 0x138 + undefined4 m_unk0x13c; // 0x13c + undefined4 m_unk0x140; // 0x140 + MxS32 m_unk0x144; // 0x144 + MxS32 m_unk0x148; // 0x148 + undefined4 m_unk0x14c; // 0x14c +}; + +#endif // LEGOCARBUILDANIMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legocarraceactor.h b/LEGO1/lego/legoomni/include/legocarraceactor.h new file mode 100644 index 00000000..97e734cb --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocarraceactor.h @@ -0,0 +1,78 @@ +#ifndef LEGOCARRACEACTOR_H +#define LEGOCARRACEACTOR_H + +#include "legoraceactor.h" + +/* + VTABLE: LEGO1 0x100da0c0 LegoRaceActor + VTABLE: LEGO1 0x100da0c8 LegoAnimActor + VTABLE: LEGO1 0x100da0d8 LegoPathActor + VTABLE: LEGO1 0x100da1a8 LegoCarRaceActor +*/ +// SIZE 0x1a0 +class LegoCarRaceActor : public virtual LegoRaceActor { +public: + LegoCarRaceActor(); + + // FUNCTION: LEGO1 0x10081650 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0568 + return "LegoCarRaceActor"; + } + + // FUNCTION: LEGO1 0x10081670 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoCarRaceActor::ClassName()) || LegoRaceActor::IsA(p_name); + } + + MxU32 VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 + ) override; // vtable+0x6c + void VTable0x70(float p_float) override; // vtable+0x70 + MxU32 VTable0x90(float, Matrix4&) override; // vtable+0x90 + MxResult VTable0x94(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 + void VTable0x98() override; // vtable+0x98 + MxResult WaitForAnimation() override; // vtable+0x9c + + virtual void FUN_10080590(); + + // FUNCTION: LEGO1 0x10012bb0 + virtual void FUN_10012bb0(float p_unk0x14) { m_unk0x14 = p_unk0x14; } + + // FUNCTION: LEGO1 0x10012bc0 + virtual float FUN_10012bc0() { return m_unk0x14; } + + // FUNCTION: LEGO1 0x10012bd0 + virtual void FUN_10012bd0(float p_unk0x10) { m_unk0x10 = p_unk0x10; } + + // FUNCTION: LEGO1 0x10012be0 + virtual float FUN_10012be0() { return m_unk0x10; } + + // FUNCTION: LEGO1 0x10012bf0 + virtual void FUN_10012bf0(float p_unk0x18) { m_unk0x18 = p_unk0x18; } + + // FUNCTION: LEGO1 0x10012c00 + virtual float FUN_10012c00() { return m_unk0x18; } + + virtual void VTable0x1c(); // vtable+0x1c + + // SYNTHETIC: LEGO1 0x10081610 + // LegoCarRaceActor::`scalar deleting destructor' + +protected: + float m_unk0x08; // 0x08 + MxU8 m_unk0x0c; // 0x0c + float m_unk0x10; // 0x10 + float m_unk0x14; // 0x14 + float m_unk0x18; // 0x18 + undefined4 m_unk0x1c; // 0x1c +}; + +#endif // LEGOCARRACEACTOR_H diff --git a/LEGO1/lego/legoomni/include/legocharactermanager.h b/LEGO1/lego/legoomni/include/legocharactermanager.h new file mode 100644 index 00000000..aaeb584d --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocharactermanager.h @@ -0,0 +1,136 @@ +#ifndef LEGOCHARACTERMANAGER_H +#define LEGOCHARACTERMANAGER_H + +#include "decomp.h" +#include "mxstl/stlcompat.h" +#include "mxtypes.h" +#include "roi/legoroi.h" + +class CustomizeAnimFileVariable; +class LegoActor; +class LegoExtraActor; +class LegoStorage; +class LegoROI; + +#pragma warning(disable : 4237) + +struct LegoCharacterComparator { + MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmpi(p_a, p_b) < 0; } +}; + +// SIZE 0x08 +struct LegoCharacter { + LegoCharacter(LegoROI* p_roi) + { + m_roi = p_roi; + m_refCount = 1; + } + ~LegoCharacter() { delete m_roi; } + + inline void AddRef() { m_refCount++; } + inline MxU32 RemoveRef() + { + if (m_refCount != 0) { + m_refCount--; + } + + return m_refCount; + } + + LegoROI* m_roi; // 0x00 + MxU32 m_refCount; // 0x04 +}; + +struct LegoCharacterInfo; + +typedef map LegoCharacterMap; + +// SIZE 0x08 +class LegoCharacterManager { +public: + LegoCharacterManager(); + ~LegoCharacterManager(); + + MxResult Write(LegoStorage* p_storage); + MxResult Read(LegoStorage* p_storage); + LegoROI* GetROI(const char* p_key, MxBool p_createEntity); + + void Init(); + static void SetCustomizeAnimFile(const char* p_value); + static MxBool Exists(const char* p_key); + + void FUN_100832a0(); + MxBool FUN_10083b20(const char* p_key); + MxU32 GetRefCount(LegoROI* p_roi); + void FUN_10083c30(const char* p_name); + void FUN_10083db0(LegoROI* p_roi); + void FUN_10083f10(LegoROI* p_roi); + MxBool FUN_100849a0(LegoROI* p_roi, LegoTextureInfo* p_textureInfo); + LegoExtraActor* GetActor(const char* p_key); + LegoCharacterInfo* GetInfo(const char* p_key); + LegoCharacterInfo* GetInfo(LegoROI* p_roi); + MxBool SwitchHat(LegoROI* p_roi); + MxU32 FUN_10085140(LegoROI* p_roi, MxBool p_und); + MxU8 FUN_10085180(LegoROI* p_roi); + LegoROI* FUN_10085210(const char* p_name, const char* p_lodName, MxBool p_createEntity); + LegoROI* FUN_10085a80(const char* p_name, const char* p_lodName, MxBool p_createEntity); + + static const char* GetCustomizeAnimFile() { return g_customizeAnimFile; } + +private: + LegoROI* CreateROI(const char* p_key); + void RemoveROI(LegoROI* p_roi); + LegoROI* FindChildROI(LegoROI* p_roi, const char* p_name); + MxResult FUN_10085870(LegoROI* p_roi); + + static char* g_customizeAnimFile; + + LegoCharacterMap* m_characters; // 0x00 + CustomizeAnimFileVariable* m_customizeAnimFile; // 0x04 +}; + +// clang-format off +// TEMPLATE: LEGO1 0x1001a690 +// list >::_Buynode + +// TEMPLATE: LEGO1 0x10035790 +// _Construct + +// TEMPLATE: LEGO1 0x10082b90 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::~_Tree,map >::_Kfn,LegoCharacterComparator,allocator > + +// TEMPLATE: LEGO1 0x10082c60 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x10082ca0 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x100830f0 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::_Erase + +// TEMPLATE: LEGO1 0x10083130 +// map >::~map > + +// TEMPLATE: LEGO1 0x10083840 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x10083890 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::_Insert + +// TEMPLATE: LEGO1 0x10085500 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::insert + +// TEMPLATE: LEGO1 0x10085790 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::_Buynode + +// TEMPLATE: LEGO1 0x100857b0 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::_Lrotate + +// TEMPLATE: LEGO1 0x10085810 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::_Rrotate + +// GLOBAL: LEGO1 0x100fc508 +// _Tree,map >::_Kfn,LegoCharacterComparator,allocator >::_Nil +// clang-format on + +#endif // LEGOCHARACTERMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legocharacters.h b/LEGO1/lego/legoomni/include/legocharacters.h new file mode 100644 index 00000000..313a49e4 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocharacters.h @@ -0,0 +1,78 @@ +#ifndef LEGOCHARACTERS_H +#define LEGOCHARACTERS_H + +#include "decomp.h" +#include "mxtypes.h" + +class LegoExtraActor; +class LegoROI; + +// SIZE 0x108 +struct LegoCharacterInfo { + // SIZE 0x18 + struct Part { + MxU8* m_unk0x00; // 0x00 + const char** m_unk0x04; // 0x04 + MxU8 m_unk0x08; // 0x08 + MxU8* m_unk0x0c; // 0x0c + const char** m_unk0x10; // 0x10 + MxU8 m_unk0x14; // 0x14 + }; + + const char* m_name; // 0x00 + LegoROI* m_roi; // 0x04 + LegoExtraActor* m_actor; // 0x08 + MxS32 m_unk0x0c; // 0x0c + MxS32 m_unk0x10; // 0x10 + MxU8 m_unk0x14; // 0x14 + Part m_parts[10]; // 0x18 +}; + +// SIZE 0x58 +struct LegoCharacterLOD { + enum { + c_flag1 = 0x01, + c_flag2 = 0x02 + }; + + const char* m_name; // 0x00 + const char* m_parentName; // 0x04 + MxU32 m_flags; // 0x08 + float m_boundingSphere[4]; // 0x0c + float m_boundingBox[6]; // 0x1c + float m_position[3]; // 0x34 + float m_direction[3]; // 0x40 + float m_up[3]; // 0x4c +}; + +enum LegoCharacterLODs { + c_topLOD, + c_bodyLOD, + c_infohatLOD, + c_infogronLOD, + c_headLOD, + c_armlftLOD, + c_armrtLOD, + c_clawlftLOD, + c_clawrtLOD, + c_leglftLOD, + c_legrtLOD +}; + +enum LegoCharacterParts { + c_bodyPart, + c_infohatPart, + c_infogronPart, + c_headPart, + c_armlftPart, + c_armrtPart, + c_clawlftPart, + c_clawrtPart, + c_leglftPart, + c_legrtPart +}; + +extern LegoCharacterInfo g_characterInfoInit[66]; +extern LegoCharacterLOD g_characterLODs[11]; + +#endif // LEGOCHARACTERS_H diff --git a/LEGO1/lego/legoomni/include/legocontrolmanager.h b/LEGO1/lego/legoomni/include/legocontrolmanager.h new file mode 100644 index 00000000..46719167 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legocontrolmanager.h @@ -0,0 +1,88 @@ +#ifndef LEGOCONTROLMANAGER_H +#define LEGOCONTROLMANAGER_H + +#include "legoeventnotificationparam.h" +#include "legoinputmanager.h" +#include "mxcore.h" +#include "mxpresenterlist.h" + +class MxControlPresenter; + +// VTABLE: LEGO1 0x100d6a98 +// SIZE 0x2c +class LegoControlManagerEvent : public LegoEventNotificationParam { +public: + inline LegoControlManagerEvent() : LegoEventNotificationParam() + { + m_clickedObjectId = -1; + m_clickedAtom = NULL; + } + + inline MxS32 GetClickedObjectId() const { return m_clickedObjectId; } + inline const char* GetClickedAtom() const { return m_clickedAtom; } + inline MxS16 GetUnknown0x28() const { return m_unk0x28; } + + inline void SetClickedObjectId(MxS32 p_clickedObjectId) { m_clickedObjectId = p_clickedObjectId; } + inline void SetClickedAtom(const char* p_clickedAtom) { m_clickedAtom = p_clickedAtom; } + inline void SetUnknown0x28(MxS16 p_unk0x28) { m_unk0x28 = p_unk0x28; } + +private: + MxS32 m_clickedObjectId; // 0x20 + const char* m_clickedAtom; // 0x24 + MxS16 m_unk0x28; // 0x28 +}; + +// SYNTHETIC: LEGO1 0x10028bf0 +// LegoControlManagerEvent::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10028c60 +// LegoControlManagerEvent::~LegoControlManagerEvent + +// VTABLE: LEGO1 0x100d6a80 +class LegoControlManager : public MxCore { +public: + LegoControlManager(); + ~LegoControlManager() override; // vtable+0x00 + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x10028cb0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f31b8 + return "LegoControlManager"; + } + + // FUNCTION: LEGO1 0x10028cc0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoControlManager::ClassName()) || MxCore::IsA(p_name); + } + + void FUN_10028df0(MxPresenterList* p_presenterList); + void Register(MxCore* p_listener); + void Unregister(MxCore* p_listener); + MxBool FUN_10029210(LegoEventNotificationParam& p_param, MxPresenter* p_presenter); + void FUN_100293c0(undefined4, const char*, undefined2); + MxControlPresenter* FUN_100294e0(MxS32 p_x, MxS32 p_y); + MxBool FUN_10029630(); + MxBool FUN_10029750(); + void FUN_100292e0(); + + inline undefined4 GetUnknown0x0c() { return m_unk0x0c; } + inline undefined GetUnknown0x10() { return m_unk0x10; } + + // SYNTHETIC: LEGO1 0x10028d40 + // LegoControlManager::`scalar deleting destructor' + +private: + undefined4 m_unk0x08; // 0x08 + undefined4 m_unk0x0c; // 0x0c + MxBool m_unk0x10; // 0x10 + MxPresenter* m_unk0x14; // 0x14 + LegoControlManagerEvent m_event; // 0x18 + MxPresenterList* m_presenterList; // 0x44 + LegoNotifyList m_notifyList; // 0x48 +}; + +#endif // LEGOCONTROLMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legoendanimnotificationparam.h b/LEGO1/lego/legoomni/include/legoendanimnotificationparam.h new file mode 100644 index 00000000..be7e9315 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoendanimnotificationparam.h @@ -0,0 +1,34 @@ +#ifndef LEGOENDANIMNOTIFICATIONPARAM_H +#define LEGOENDANIMNOTIFICATIONPARAM_H + +#include "decomp.h" +#include "mxnotificationparam.h" + +// VTABLE: LEGO1 0x100d7e80 +// SIZE 0x10 +class LegoEndAnimNotificationParam : public MxNotificationParam { +public: + LegoEndAnimNotificationParam(NotificationId p_type, MxCore* p_sender, MxU32 p_index) + : MxNotificationParam(p_type, p_sender), m_index(p_index) + { + } + + // FUNCTION: LEGO1 0x1004afd0 + MxNotificationParam* Clone() const override + { + return new LegoEndAnimNotificationParam(m_type, m_sender, m_index); + } // vtable+0x04 + + inline MxU32 GetIndex() { return m_index; } + +protected: + MxU32 m_index; // 0x0c +}; + +// SYNTHETIC: LEGO1 0x1004b080 +// LegoEndAnimNotificationParam::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1004b0f0 +// LegoEndAnimNotificationParam::~LegoEndAnimNotificationParam + +#endif // LEGOENDANIMNOTIFICATIONPARAM_H diff --git a/LEGO1/lego/legoomni/include/legoentity.h b/LEGO1/lego/legoomni/include/legoentity.h new file mode 100644 index 00000000..034dc700 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoentity.h @@ -0,0 +1,119 @@ +#ifndef LEGOENTITY_H +#define LEGOENTITY_H + +#include "decomp.h" +#include "extra.h" +#include "mxentity.h" + +class LegoROI; +class MxDSAction; +class Vector3; + +// VTABLE: LEGO1 0x100d4858 +// SIZE 0x68 +class LegoEntity : public MxEntity { +public: + enum Type { + e_character = 0, + e_unk1, + e_plant, + e_building, + e_unk4 + }; + + enum { + c_bit1 = 0x01, + c_bit2 = 0x02 + }; + + enum { + c_altBit1 = 0x01 + }; + + inline LegoEntity() { Init(); } + + // FUNCTION: LEGO1 0x1000c290 + ~LegoEntity() override { Destroy(TRUE); } + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x1000c2f0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0064 + return "LegoEntity"; + } + + // FUNCTION: LEGO1 0x1000c300 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoEntity::ClassName()) || MxEntity::IsA(p_name); + } + + virtual MxResult Create(MxDSAction& p_dsAction); // vtable+0x18 + virtual void Destroy(MxBool p_fromDestructor); // vtable+0x1c + virtual void ParseAction(char* p_extra); // vtable+0x20 + virtual void SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2); // vtable+0x24 + virtual void SetWorldTransform( + const Vector3& p_location, + const Vector3& p_direction, + const Vector3& p_up + ); // vtable+0x28 + virtual void ResetWorldTransform(MxBool p_cameraFlag); // vtable+0x2c + + // FUNCTION: LEGO1 0x10001090 + virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30 + + virtual void VTable0x34(MxBool p_und); // vtable+0x34 + virtual void VTable0x38(); // vtable+0x38 + virtual void VTable0x3c(); // vtable+0x3c + virtual void VTable0x40(); // vtable+0x40 + virtual void VTable0x44(); // vtable+0x44 + virtual void VTable0x48(LegoROI* p_roi); // vtable+0x48 + virtual void VTable0x4c(); // vtable+0x4c + + void FUN_10010c30(); + void SetType(MxU8 p_type); + void SetLocation(const Vector3& p_location, const Vector3& p_direction, const Vector3& p_up, MxBool p_und); + Mx3DPointFloat GetWorldDirection(); + Mx3DPointFloat GetWorldUp(); + Mx3DPointFloat GetWorldPosition(); + + inline MxBool GetUnknown0x10IsSet(MxU8 p_flag) { return m_unk0x10 & p_flag; } + inline MxBool GetFlagsIsSet(MxU8 p_flag) { return m_flags & p_flag; } + inline MxU8 GetFlags() { return m_flags; } + inline MxFloat GetWorldSpeed() { return m_worldSpeed; } + inline LegoROI* GetROI() { return m_roi; } + inline MxU8 GetType() { return m_type; } + inline MxBool GetCameraFlag() { return m_cameraFlag; } + + inline void SetFlags(MxU8 p_flags) { m_flags = p_flags; } + inline void SetFlag(MxU8 p_flag) { m_flags |= p_flag; } + inline void ClearFlag(MxU8 p_flag) { m_flags &= ~p_flag; } + inline void SetUnknown0x10Flag(MxU8 p_flag) { m_unk0x10 |= p_flag; } + inline void ClearUnknown0x10Flag(MxU8 p_flag) { m_unk0x10 &= ~p_flag; } + +protected: + void Init(); + void SetWorld(); + + MxU8 m_unk0x10; // 0x10 + MxU8 m_flags; // 0x11 + Mx3DPointFloat m_worldLocation; // 0x14 + Mx3DPointFloat m_worldDirection; // 0x28 + Mx3DPointFloat m_worldUp; // 0x3c + MxFloat m_worldSpeed; // 0x50 + LegoROI* m_roi; // 0x54 + MxBool m_cameraFlag; // 0x58 + MxU8 m_type; // 0x59 + // For tokens from the extra string that look like this: + // "Action:openram;\lego\scripts\Race\CarRaceR;0" + Extra::ActionType m_actionType; // 0x5c + char* m_filename; // 0x60 + MxS32 m_targetEntityId; // 0x64 +}; + +// SYNTHETIC: LEGO1 0x1000c3b0 +// LegoEntity::`scalar deleting destructor' + +#endif // LEGOENTITY_H diff --git a/LEGO1/lego/legoomni/include/legoentitylist.h b/LEGO1/lego/legoomni/include/legoentitylist.h new file mode 100644 index 00000000..2a7320af --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoentitylist.h @@ -0,0 +1,100 @@ +#ifndef LEGOENTITYLIST_H +#define LEGOENTITYLIST_H + +#include "legoentity.h" +#include "mxlist.h" +#include "mxtypes.h" + +// VTABLE: LEGO1 0x100d6410 +// class MxCollection + +// VTABLE: LEGO1 0x100d6428 +// class MxList + +// VTABLE: LEGO1 0x100d6440 +// class MxPtrList + +// VTABLE: LEGO1 0x100d6458 +// SIZE 0x18 +class LegoEntityList : public MxPtrList { +public: + LegoEntityList(MxBool p_ownership = FALSE) : MxPtrList(p_ownership) {} + + // FUNCTION: LEGO1 0x1001e2d0 + MxS8 Compare(LegoEntity* p_a, LegoEntity* p_b) override + { + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; + } // vtable+0x14 +}; + +// VTABLE: LEGO1 0x100d64e8 +// class MxListCursor + +// VTABLE: LEGO1 0x100d64b8 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d64d0 +// SIZE 0x10 +class LegoEntityListCursor : public MxPtrListCursor { +public: + LegoEntityListCursor(LegoEntityList* p_list) : MxPtrListCursor(p_list) {} +}; + +// TEMPLATE: LEGO1 0x1001e2f0 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1001e300 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1001e350 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1001e360 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x1001e3f0 +// MxPtrList::Destroy + +// SYNTHETIC: LEGO1 0x1001e400 +// LegoEntityList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001e470 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x1001e4c0 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001e530 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001e5e0 +// MxPtrList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001f110 +// LegoEntityListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001f180 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x1001f1d0 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001f240 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001f2b0 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x1001f300 +// LegoEntityListCursor::~LegoEntityListCursor + +// TEMPLATE: LEGO1 0x100207d0 +// MxListCursor::MxListCursor + +// TEMPLATE: LEGO1 0x10022430 +// MxList::InsertEntry + +// TEMPLATE: LEGO1 0x10022630 +// MxList::DeleteEntry + +#endif // LEGOENTITYLIST_H diff --git a/LEGO1/lego/legoomni/include/legoentitypresenter.h b/LEGO1/lego/legoomni/include/legoentitypresenter.h new file mode 100644 index 00000000..e8bf6ff1 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoentitypresenter.h @@ -0,0 +1,52 @@ +#ifndef LEGOENTITYPRESENTER_H +#define LEGOENTITYPRESENTER_H + +#include "mxcompositepresenter.h" + +class LegoEntity; +class Vector3; + +// VTABLE: LEGO1 0x100d8398 +// SIZE 0x50 +class LegoEntityPresenter : public MxCompositePresenter { +public: + LegoEntityPresenter(); + ~LegoEntityPresenter() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x100534b0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f06b8 + return "LegoEntityPresenter"; + } + + // FUNCTION: LEGO1 0x100534c0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoEntityPresenter::ClassName()) || MxCompositePresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void RepeatingTickle() override; // vtable+0x24 + void ParseExtra() override; // vtable+0x30 + void Destroy() override; // vtable+0x38 + MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c + virtual void Init(); // vtable+0x68 + virtual undefined4 SetEntity(LegoEntity* p_entity); // vtable+0x6c + + void SetEntityLocation(const Vector3& p_location, const Vector3& p_direction, const Vector3& p_up); + + inline LegoEntity* GetInternalEntity() { return m_entity; } + inline void SetInternalEntity(LegoEntity* p_entity) { m_entity = p_entity; } + + // SYNTHETIC: LEGO1 0x100535a0 + // LegoEntityPresenter::`scalar deleting destructor' + +private: + void Destroy(MxBool p_fromDestructor); + +protected: + LegoEntity* m_entity; // 0x4c +}; + +#endif // LEGOENTITYPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legoeventnotificationparam.h b/LEGO1/lego/legoomni/include/legoeventnotificationparam.h new file mode 100644 index 00000000..cdd771e3 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoeventnotificationparam.h @@ -0,0 +1,74 @@ +#ifndef LEGOEVENTNOTIFICATIONPARAM_H +#define LEGOEVENTNOTIFICATIONPARAM_H + +#include "mxnotificationparam.h" +#include "mxtypes.h" + +#include + +class LegoROI; + +// VTABLE: LEGO1 0x100d6aa0 +// SIZE 0x20 +class LegoEventNotificationParam : public MxNotificationParam { +public: + enum { + c_lButtonState = 0x01, + c_rButtonState = 0x02, + c_modKey1 = 0x04, + c_modKey2 = 0x08, + }; + + // FUNCTION: LEGO1 0x10028690 + MxNotificationParam* Clone() const override + { + LegoEventNotificationParam* clone = + new LegoEventNotificationParam(m_type, m_sender, m_modifier, m_x, m_y, m_key); + clone->m_roi = m_roi; + return clone; + } // vtable+0x04 + + inline LegoEventNotificationParam() : MxNotificationParam(c_notificationType0, NULL) {} + inline LegoEventNotificationParam( + NotificationId p_type, + MxCore* p_sender, + MxU8 p_modifier, + MxS32 p_x, + MxS32 p_y, + MxU8 p_key + ) + : MxNotificationParam(p_type, p_sender), m_modifier(p_modifier), m_x(p_x), m_y(p_y), m_key(p_key), m_roi(NULL) + { + } + + inline LegoROI* GetROI() { return m_roi; } + inline MxU8 GetModifier() { return m_modifier; } + inline MxU8 GetKey() const { return m_key; } + + // FUNCTION: LEGO1 0x10012190 + inline MxS32 GetX() const { return m_x; } + + // FUNCTION: LEGO1 0x100121a0 + inline MxS32 GetY() const { return m_y; } + + inline void SetROI(LegoROI* p_roi) { m_roi = p_roi; } + inline void SetModifier(MxU8 p_modifier) { m_modifier = p_modifier; } + inline void SetKey(MxU8 p_key) { m_key = p_key; } + inline void SetX(MxS32 p_x) { m_x = p_x; } + inline void SetY(MxS32 p_y) { m_y = p_y; } + +protected: + MxU8 m_modifier; // 0x0c + MxS32 m_x; // 0x10 + MxS32 m_y; // 0x14 + MxU8 m_key; // 0x18 + LegoROI* m_roi; // 0x1c +}; + +// SYNTHETIC: LEGO1 0x10028770 +// LegoEventNotificationParam::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100287e0 +// LegoEventNotificationParam::~LegoEventNotificationParam + +#endif // LEGOEVENTNOTIFICATIONPARAM_H diff --git a/LEGO1/lego/legoomni/include/legoextraactor.h b/LEGO1/lego/legoomni/include/legoextraactor.h new file mode 100644 index 00000000..d2c846f3 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoextraactor.h @@ -0,0 +1,90 @@ +#ifndef LEGOEXTRAACTOR_H +#define LEGOEXTRAACTOR_H + +#include "legoanimactor.h" + +// VTABLE: LEGO1 0x100d6c00 LegoAnimActor +// VTABLE: LEGO1 0x100d6c10 LegoPathActor +// VTABLE: LEGO1 0x100d6cdc LegoExtraActor +// SIZE 0x1dc +class LegoExtraActor : public virtual LegoAnimActor { +public: + enum Axis { + e_posz, + e_negz, + e_posx, + e_negx + }; + + LegoExtraActor(); + ~LegoExtraActor() override; + + // FUNCTION: LEGO1 0x1002b7b0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f3204 + return "LegoExtraActor"; + } + + // FUNCTION: LEGO1 0x1002b7d0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoExtraActor::ClassName()) || LegoAnimActor::IsA(p_name); + } + + void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 + MxS32 VTable0x68(Vector3&, Vector3&, Vector3&) override; // vtable+0x68 + MxU32 VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 + ) override; // vtable+0x6c + void VTable0x70(float) override; // vtable+0x70 + void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 + MxU32 VTable0x90(float p_float, Matrix4& p_matrix) override; // vtable+0x90 + MxResult VTable0x94(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 + MxResult WaitForAnimation() override; // vtable+0x9c + void VTable0xa4(MxU8& p_und1, MxS32& p_und2) override; // vtable+0xa4 + void VTable0xc4() override; // vtable+0xc4 + virtual MxResult VTable0xc8(); // vtable+0xc8 + + void Restart(); + inline void FUN_1002ad8a(); + + inline void SetUnknown0x0c(undefined p_unk0x0c) { m_unk0x0c = p_unk0x0c; } + + // SYNTHETIC: LEGO1 0x1002b760 + // LegoExtraActor::`scalar deleting destructor' + +private: + MxFloat m_scheduledTime; // 0x08 + undefined m_unk0x0c; // 0x0c + MxU8 m_axis; // 0x0d + undefined m_unk0x0e; // 0x0e + MxFloat m_prevWorldSpeed; // 0x10 + MxU8 m_whichAnim; // 0x14 + MxU8 m_unk0x15; // 0x15 + MxMatrix m_unk0x18; // 0x18 + LegoAnimActorStruct* m_assAnim; // 0x60 + LegoAnimActorStruct* m_disAnim; // 0x64 +}; + +// GLOBAL: LEGO1 0x100d6be8 +// LegoExtraActor::`vbtable'{for `LegoAnimActor'} + +// GLOBAL: LEGO1 0x100d6bf0 +// LegoExtraActor::`vbtable'{for `LegoExtraActor'} + +// TEMPLATE: LEGO1 0x1002b200 +// vector >::vector > + +// TEMPLATE: LEGO1 0x1002b270 +// vector >::size + +// TEMPLATE: LEGO1 0x1002b720 +// uninitialized_copy + +#endif // LEGOEXTRAACTOR_H diff --git a/LEGO1/lego/legoomni/include/legoflctexturepresenter.h b/LEGO1/lego/legoomni/include/legoflctexturepresenter.h new file mode 100644 index 00000000..70f8a309 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoflctexturepresenter.h @@ -0,0 +1,34 @@ +#ifndef LEGOFLCTEXTUREPRESENTER_H +#define LEGOFLCTEXTUREPRESENTER_H + +#include "decomp.h" +#include "mxflcpresenter.h" + +// VTABLE: LEGO1 0x100d89e0 +// SIZE 0x70 +class LegoFlcTexturePresenter : public MxFlcPresenter { +public: + LegoFlcTexturePresenter(); + + // FUNCTION: LEGO1 0x1005def0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0634 + return "LegoFlcTexturePresenter"; + } + + void StartingTickle() override; // vtable+0x1c + void LoadFrame(MxStreamChunk* p_chunk) override; // vtable+0x68 + void PutFrame() override; // vtable+0x6c + + // SYNTHETIC: LEGO1 0x1005df00 + // LegoFlcTexturePresenter::`scalar deleting destructor' + +private: + void Init(); + + undefined4 m_unk0x68; // 0x68 + undefined4 m_unk0x6c; // 0x6c +}; + +#endif // LEGOFLCTEXTUREPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legofullscreenmovie.h b/LEGO1/lego/legoomni/include/legofullscreenmovie.h new file mode 100644 index 00000000..2f2f7614 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legofullscreenmovie.h @@ -0,0 +1,14 @@ +#ifndef LEGOFULLSCREENMOVIE_H +#define LEGOFULLSCREENMOVIE_H + +#include "mxvariable.h" + +// VTABLE: LEGO1 0x100d74b8 +// SIZE 0x24 +class LegoFullScreenMovie : public MxVariable { +public: + LegoFullScreenMovie(const char* p_key, const char* p_value); + void SetValue(const char* p_option) override; +}; + +#endif // LEGOFULLSCREENMOVIE_H diff --git a/LEGO1/lego/legoomni/include/legogamestate.h b/LEGO1/lego/legoomni/include/legogamestate.h new file mode 100644 index 00000000..b1a9051f --- /dev/null +++ b/LEGO1/lego/legoomni/include/legogamestate.h @@ -0,0 +1,238 @@ +#ifndef LEGOGAMESTATE_H +#define LEGOGAMESTATE_H + +#include "actionsfwd.h" +#include "decomp.h" +#include "mxtypes.h" + +#include + +class LegoBackgroundColor; +class LegoFile; +class LegoFullScreenMovie; +class LegoState; +class LegoStorage; +class MxVariable; +class MxVariableTable; +class MxString; + +extern const char* g_actorNames[7]; + +// SIZE 0x08 +struct ColorStringStruct { + const char* m_targetName; // 0x00 + const char* m_colorName; // 0x04 +}; + +// SIZE 0x430 +class LegoGameState { +public: + enum Act { + e_actNotFound = -1, + e_act1, + e_act2, + e_act3 + }; + + enum Area { + e_undefined = 0, + e_previousArea = 0, + e_isle, + e_infomain, + e_infodoor, + e_unk4, + e_elevbott, + e_elevride, + e_elevride2, + e_elevopen, + e_seaview, + e_observe, + e_elevdown, + e_regbook, + e_infoscor, + e_jetrace, + e_jetrace2, + e_jetraceExterior, + e_unk17, + e_carrace, + e_carraceExterior, + e_unk20, + e_unk21, + e_pizzeriaExterior, + e_unk23, + e_unk24, + e_garageExterior, + e_garage, + e_garadoor, + e_unk28, + e_hospitalExterior, + e_hospital, + e_unk31, + e_policeExterior, + e_unk33, + e_police, + e_polidoor, + e_copterbuild, + e_dunecarbuild, + e_jetskibuild, + e_racecarbuild, + e_unk40, + e_unk41, + e_unk42, + e_unk43, + e_unk44, + e_unk45, + e_act2main, + e_act3script, + e_unk48, + e_unk49, + e_unk50, + e_unk51, + e_unk52, + e_jukeboxw, + e_unk54, + e_unk55, + e_histbook, + e_bike, + e_dunecar, + e_motocycle, + e_copter, + e_skateboard, + e_ambulance, + e_towtrack, + e_jetski, + + e_unk66 = 66 + }; + + // SIZE 0x0e + struct Username { + Username(); + inline Username(Username& p_other) { Set(p_other); } + inline void Set(Username& p_other) { memcpy(m_letters, p_other.m_letters, sizeof(m_letters)); } + + MxResult ReadWrite(LegoStorage* p_storage); + Username& operator=(const Username& p_other); + + MxS16 m_letters[7]; // 0x00 + }; + + // SIZE 0x2c + struct ScoreItem { + undefined2 m_unk0x00; // 0x00 + MxU8 m_state[5][5]; // 0x02 + Username m_name; // 0x1c + undefined2 m_unk0x2a; // 0x2a + }; + + // SIZE 0x372 + struct History { + History(); + void WriteScoreHistory(); + void FUN_1003ccf0(LegoFile&); + + inline ScoreItem* GetScore(MxS16 p_index) { return p_index >= m_count ? NULL : &m_scores[p_index]; } + + MxS16 m_count; // 0x00 + ScoreItem m_scores[20]; // 0x02 + undefined2 m_unk0x372; // 0x372 + }; + + LegoGameState(); + ~LegoGameState(); + + void SetActor(MxU8 p_actorId); + void RemoveActor(); + void ResetROI(); + + MxResult Save(MxULong); + MxResult DeleteState(); + MxResult Load(MxULong); + + void SerializePlayersInfo(MxS16 p_flags); + MxResult AddPlayer(Username& p_player); + void SwitchPlayer(MxS16 p_playerId); + MxS16 FindPlayer(Username& p_player); + + void SerializeScoreHistory(MxS16 p_flags); + void SetSavePath(char*); + + LegoState* GetState(const char* p_stateName); + LegoState* CreateState(const char* p_stateName); + + void GetFileSavePath(MxString* p_outPath, MxU8 p_slotn); + void StopArea(Area p_area); + void SwitchArea(Area p_area); + void Init(); + + inline MxU8 GetActorId() { return m_actorId; } + + // FUNCTION: BETA10 0x1004a2d0 + inline const char* GetActorName() { return g_actorNames[GetActorId()]; } + + inline Act GetCurrentAct() { return m_currentAct; } + inline Act GetLoadedAct() { return m_loadedAct; } + inline Area GetCurrentArea() { return m_currentArea; } + inline Area GetPreviousArea() { return m_previousArea; } + inline JukeboxScript::Script GetUnknown0x41c() { return m_unk0x41c; } + inline Area GetUnknown0x42c() { return m_unk0x42c; } + inline History* GetHistory() { return &m_history; } + + inline void SetDirty(MxBool p_isDirty) { m_isDirty = p_isDirty; } + inline void SetCurrentArea(Area p_currentArea) { m_currentArea = p_currentArea; } + inline void SetPreviousArea(Area p_previousArea) { m_previousArea = p_previousArea; } + inline void SetActorId(MxU8 p_actorId) { m_actorId = p_actorId; } + inline void SetUnknown0x41c(JukeboxScript::Script p_unk0x41c) { m_unk0x41c = p_unk0x41c; } + inline void SetUnknown0x42c(Area p_unk0x42c) { m_unk0x42c = p_unk0x42c; } + inline Username* GetPlayersIndex(MxS32 p_index) { return &m_players[p_index]; } + inline MxS16 GetPlayerCount() { return m_playerCount; } + inline LegoBackgroundColor* GetBackgroundColor() { return m_backgroundColor; } + + void SetCurrentAct(Act p_currentAct); + void FindLoadedAct(); + void RegisterState(LegoState* p_state); + +private: + MxResult WriteVariable(LegoStorage* p_storage, MxVariableTable* p_from, const char* p_variableName); + MxResult WriteEndOfVariables(LegoStorage* p_storage); + MxS32 ReadVariable(LegoStorage* p_storage, MxVariableTable* p_to); + void SetColors(); + void SetROIHandlerFunction(); + + char* m_savePath; // 0x00 + MxS16 m_stateCount; // 0x04 + LegoState** m_stateArray; // 0x08 + MxU8 m_actorId; // 0x0c + Act m_currentAct; // 0x10 + Act m_loadedAct; // 0x14 + LegoBackgroundColor* m_backgroundColor; // 0x18 + LegoBackgroundColor* m_tempBackgroundColor; // 0x1c + LegoFullScreenMovie* m_fullScreenMovie; // 0x20 + MxU16 m_unk0x24; // 0x24 + + // Member visibility needs to be refactored, since most members are accessed directly. + +public: + MxS16 m_playerCount; // 0x26 + Username m_players[9]; // 0x28 + +private: + History m_history; // 0xa6 + undefined2 m_unk0x41a; // 0x41a + JukeboxScript::Script m_unk0x41c; // 0x41c + MxBool m_isDirty; // 0x420 + +public: + Area m_currentArea; // 0x424 + Area m_previousArea; // 0x428 + +private: + Area m_unk0x42c; // 0x42c +}; + +MxBool ROIHandlerFunction(const char* p_input, char* p_output, MxU32 p_copyLen); + +// SYNTHETIC: LEGO1 0x1003c860 +// LegoGameState::ScoreItem::ScoreItem + +#endif // LEGOGAMESTATE_H diff --git a/LEGO1/lego/legoomni/include/legohideanimpresenter.h b/LEGO1/lego/legoomni/include/legohideanimpresenter.h new file mode 100644 index 00000000..0bb652d7 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legohideanimpresenter.h @@ -0,0 +1,99 @@ +#ifndef LEGOHIDEANIMPRESENTER_H +#define LEGOHIDEANIMPRESENTER_H + +#include "decomp.h" +#include "legoloopinganimpresenter.h" + +class LegoPathBoundary; + +struct LegoHideAnimStructComparator { + MxBool operator()(const char* const& p_a, const char* const& p_b) const { return strcmp(p_a, p_b) < 0; } +}; + +// SIZE 0x08 +struct LegoHideAnimStruct { + LegoPathBoundary* m_boundary; // 0x00 + MxU32 m_index; // 0x04 +}; + +typedef map LegoHideAnimStructMap; + +// VTABLE: LEGO1 0x100d9278 +// SIZE 0xc4 +class LegoHideAnimPresenter : public LegoLoopingAnimPresenter { +public: + LegoHideAnimPresenter(); + ~LegoHideAnimPresenter() override; + + // FUNCTION: LEGO1 0x1006d880 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f06cc + return "LegoHideAnimPresenter"; + } + + // FUNCTION: LEGO1 0x1006d890 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x18 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + void EndAction() override; // vtable+0x40 + void PutFrame() override; // vtable+0x6c + void VTable0x8c() override; // vtable+0x8c + void VTable0x90() override; // vtable+0x90 + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + void FUN_1006db40(LegoTime p_time); + void FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time); + void FUN_1006dc10(); + void FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node); + void FUN_1006e470( + LegoHideAnimStructMap& p_map, + LegoAnimNodeData* p_data, + const char* p_name, + LegoPathBoundary* p_boundary + ); + + LegoPathBoundary** m_boundaryMap; // 0xc0 +}; + +// clang-format off +// SYNTHETIC: LEGO1 0x1006d9d0 +// LegoHideAnimPresenter::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1006ddb0 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::~_Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x1006dec0 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x1006e310 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::_Erase + +// TEMPLATE: LEGO1 0x1006e350 +// Map::~Map + +// TEMPLATE: LEGO1 0x1006e3a0 +// map >::~map > + +// TEMPLATE: LEGO1 0x1006e6d0 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x1006e720 +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::_Insert + +// GLOBAL: LEGO1 0x100f768c +// _Tree,map >::_Kfn,LegoHideAnimStructComparator,allocator >::_Nil +// clang-format on + +#endif // LEGOHIDEANIMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legoinputmanager.h b/LEGO1/lego/legoomni/include/legoinputmanager.h new file mode 100644 index 00000000..2bd7e26b --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoinputmanager.h @@ -0,0 +1,240 @@ +#ifndef LEGOINPUTMANAGER_H +#define LEGOINPUTMANAGER_H + +#include "decomp.h" +#include "legoeventnotificationparam.h" +#include "mxlist.h" +#include "mxpresenter.h" +#include "mxqueue.h" + +#include + +class LegoCameraController; +class LegoControlManager; +class LegoWorld; + +extern MxS32 g_unk0x100f31b0; +extern const char* g_unk0x100f31b4; + +// VTABLE: LEGO1 0x100d87b8 +// class MxCollection + +// VTABLE: LEGO1 0x100d87d0 +// class MxList + +// VTABLE: LEGO1 0x100d87e8 +// class MxQueue + +// VTABLE: LEGO1 0x100d8800 +// SIZE 0x18 +class LegoEventQueue : public MxQueue {}; + +// VTABLE: LEGO1 0x100d6a20 +// class MxCollection + +// VTABLE: LEGO1 0x100d6a38 +// class MxList + +// VTABLE: LEGO1 0x100d6a50 +// class MxPtrList + +// VTABLE: LEGO1 0x100d6a68 +// SIZE 0x18 +class LegoNotifyList : public MxPtrList { +protected: + // FUNCTION: LEGO1 0x10028830 + MxS8 Compare(MxCore* p_element1, MxCore* p_element2) override + { + return p_element1 == p_element2 ? 0 : p_element1 < p_element2 ? -1 : 1; + } // vtable+0x14 + +public: + LegoNotifyList(MxBool p_ownership = FALSE) : MxPtrList(p_ownership) {} +}; + +// VTABLE: LEGO1 0x100d6ac0 +// class MxListCursor + +// VTABLE: LEGO1 0x100d6ad8 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d6aa8 +// SIZE 0x10 +class LegoNotifyListCursor : public MxPtrListCursor { +public: + LegoNotifyListCursor(LegoNotifyList* p_list) : MxPtrListCursor(p_list) {} +}; + +// VTABLE: LEGO1 0x100d8760 +// SIZE 0x338 +class LegoInputManager : public MxPresenter { +public: + enum Keys { + c_left = 0x01, + c_right = 0x02, + c_up = 0x04, + c_down = 0x08, + c_bit5 = 0x10, + + c_leftOrRight = c_left | c_right, + c_upOrDown = c_up | c_down + }; + + LegoInputManager(); + ~LegoInputManager() override; + + void QueueEvent(NotificationId p_id, MxU8 p_modifier, MxLong p_x, MxLong p_y, MxU8 p_key); + void Register(MxCore*); + void UnRegister(MxCore*); + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1005b8c0 + MxResult PutData() override { return SUCCESS; } // vtable+0x4c + + MxResult Create(HWND p_hwnd); + void Destroy() override; + void CreateAndAcquireKeyboard(HWND p_hwnd); + void ReleaseDX(); + MxResult GetJoystickId(); + MxResult GetJoystickState(MxU32* p_joystickX, MxU32* p_joystickY, DWORD* p_buttonsState, MxU32* p_povPosition); + void StartAutoDragTimer(); + void StopAutoDragTimer(); + void EnableInputProcessing(); + void SetCamera(LegoCameraController* p_camera); + void ClearCamera(); + void SetWorld(LegoWorld* p_world); + void ClearWorld(); + + inline void SetUnknown88(MxBool p_unk0x88) { m_unk0x88 = p_unk0x88; } + inline void SetUnknown335(MxBool p_unk0x335) { m_unk0x335 = p_unk0x335; } + inline void SetUnknown336(MxBool p_unk0x336) { m_unk0x336 = p_unk0x336; } + inline void SetUseJoystick(MxBool p_useJoystick) { m_useJoystick = p_useJoystick; } + inline void SetJoystickIndex(MxS32 p_joystickIndex) { m_joystickIndex = p_joystickIndex; } + + inline void DisableInputProcessing() + { + m_unk0x88 = TRUE; + m_unk0x336 = FALSE; + } + + inline LegoControlManager* GetControlManager() { return m_controlManager; } + inline LegoWorld* GetWorld() { return m_world; } + inline LegoCameraController* GetCamera() { return m_camera; } + + void ProcessEvents(); + MxBool ProcessOneEvent(LegoEventNotificationParam& p_param); + MxBool FUN_1005cdf0(LegoEventNotificationParam& p_param); + void FUN_1005c0f0(); + MxResult FUN_1005c160(MxU32& p_keyFlags); + + // SYNTHETIC: LEGO1 0x1005b8d0 + // LegoInputManager::`scalar deleting destructor' + +private: + MxCriticalSection m_criticalSection; // 0x58 + LegoNotifyList* m_keyboardNotifyList; // 0x5c + LegoCameraController* m_camera; // 0x60 + LegoWorld* m_world; // 0x64 + LegoEventQueue* m_eventQueue; // 0x68 + MxS32 m_x; // 0x6c + MxS32 m_y; // 0x70 + MxS32 m_unk0x74; // 0x74 + UINT m_autoDragTimerID; // 0x78 + UINT m_autoDragTime; // 0x7c + MxBool m_unk0x80; // 0x80 + MxBool m_unk0x81; // 0x81 + LegoControlManager* m_controlManager; // 0x84 + MxBool m_unk0x88; // 0x88 + IDirectInput* m_directInput; // 0x8c + IDirectInputDevice* m_directInputDevice; // 0x90 + MxBool m_unk0x94; // 0x94 + MxU8 m_unk0x95[256]; // 0x95 + MxBool m_unk0x195; // 0x195 + MxS32 m_joyid; // 0x198 + MxS32 m_joystickIndex; // 0x19c + JOYCAPS m_joyCaps; // 0x200 + MxBool m_useJoystick; // 0x334 + MxBool m_unk0x335; // 0x335 + MxBool m_unk0x336; // 0x336 +}; + +// TEMPLATE: LEGO1 0x10028850 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x10028860 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x100288b0 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x100288c0 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x10028950 +// LegoNotifyList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100289c0 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x10028a10 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10028a80 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10028b30 +// MxPtrList::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x10028ba0 +// LegoNotifyList::~LegoNotifyList + +// SYNTHETIC: LEGO1 0x10028fd0 +// LegoNotifyListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x10029040 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x10029090 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10029100 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x10029170 +// MxListCursor::~MxListCursor + +// TEMPLATE: LEGO1 0x100291c0 +// LegoNotifyListCursor::~LegoNotifyListCursor + +// TEMPLATE: LEGO1 0x1005bb80 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1005bbe0 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1005bc30 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1005bc80 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x1005bd50 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1005bdc0 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1005beb0 +// LegoEventQueue::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1005bf20 +// MxQueue::~MxQueue + +// SYNTHETIC: LEGO1 0x1005bf70 +// MxQueue::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1005d010 +// MxListEntry::GetValue + +#endif // LEGOINPUTMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legojetski.h b/LEGO1/lego/legoomni/include/legojetski.h new file mode 100644 index 00000000..61fd0121 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legojetski.h @@ -0,0 +1,55 @@ +#ifndef LEGOJETSKI_H +#define LEGOJETSKI_H + +#include "legojetskiraceactor.h" +#include "legoracemap.h" + +/* + VTABLE: LEGO1 0x100d5a08 LegoJetskiRaceActor + VTABLE: LEGO1 0x100d5a28 LegoRaceActor + VTABLE: LEGO1 0x100d5a30 LegoAnimActor + VTABLE: LEGO1 0x100d5a40 LegoPathActor + VTABLE: LEGO1 0x100d5b10 LegoRaceMap +*/ +// SIZE 0x1dc +class LegoJetski : public LegoJetskiRaceActor, public LegoRaceMap { +public: + LegoJetski(); + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10013e80 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f053c + return "LegoJetski"; + } + + // FUNCTION: LEGO1 0x10013ea0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoJetski::ClassName()) || LegoJetskiRaceActor::IsA(p_name); + } + + void ParseAction(char*) override; // vtable+0x20 + void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 + MxU32 VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 + ) override; // vtable+0x6c + void VTable0x70(float p_float) override; // vtable+0x70 + MxResult VTable0x94(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 + void VTable0x98() override; // vtable+0x98 + MxResult WaitForAnimation() override; // vtable+0x9c + + virtual void FUN_100136f0(float p_worldSpeed); + + // SYNTHETIC: LEGO1 0x10013e20 + // LegoJetski::`scalar deleting destructor' +}; + +#endif // LEGOJETSKI_H diff --git a/LEGO1/lego/legoomni/include/legojetskiraceactor.h b/LEGO1/lego/legoomni/include/legojetskiraceactor.h new file mode 100644 index 00000000..388107d1 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legojetskiraceactor.h @@ -0,0 +1,47 @@ +#ifndef LEGOJETSKIRACEACTOR_H +#define LEGOJETSKIRACEACTOR_H + +#include "legocarraceactor.h" + +/* + VTABLE: LEGO1 0x100da208 LegoCarRaceActor + VTABLE: LEGO1 0x100da228 LegoRaceActor + VTABLE: LEGO1 0x100da230 LegoAnimActor + VTABLE: LEGO1 0x100da240 LegoPathActor +*/ +// SIZE 0x1a8 +class LegoJetskiRaceActor : public virtual LegoCarRaceActor { +public: + LegoJetskiRaceActor(); + + // FUNCTION: LEGO1 0x10081d80 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0554 + return "LegoJetskiRaceActor"; + } + + // FUNCTION: LEGO1 0x10081da0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoJetskiRaceActor::ClassName()) || LegoCarRaceActor::IsA(p_name); + } + + MxU32 VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 + ) override; // vtable+0x6c + void VTable0x70(float p_float) override; // vtable+0x70 + void VTable0x98() override; // vtable+0x98 + MxResult WaitForAnimation() override; // vtable+0x9c + void VTable0x1c() override; // vtable+0x1c + + // SYNTHETIC: LEGO1 0x10081d40 + // LegoJetskiRaceActor::`scalar deleting destructor' +}; + +#endif // LEGOJETSKIRACEACTOR_H diff --git a/LEGO1/lego/legoomni/include/legoloadcachesoundpresenter.h b/LEGO1/lego/legoomni/include/legoloadcachesoundpresenter.h new file mode 100644 index 00000000..cb6ad80a --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoloadcachesoundpresenter.h @@ -0,0 +1,43 @@ +#ifndef LEGOLOADCACHESOUNDPRESENTER_H +#define LEGOLOADCACHESOUNDPRESENTER_H + +#include "decomp.h" +#include "mxwavepresenter.h" + +class LegoCacheSound; + +// VTABLE: LEGO1 0x100d5fa8 +// SIZE 0x90 +class LegoLoadCacheSoundPresenter : public MxWavePresenter { +public: + LegoLoadCacheSoundPresenter(); + ~LegoLoadCacheSoundPresenter() override; + + // FUNCTION: LEGO1 0x10018450 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f05a0 + return "LegoLoadCacheSoundPresenter"; + } + + void ReadyTickle() override; // vtable+0x18 + void StreamingTickle() override; // vtable+0x20 + void DoneTickle() override; // vtable+0x2c + MxResult PutData() override; // vtable+0x4c + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + + LegoCacheSound* m_cacheSound; // 0x6c + undefined* m_unk0x70; // 0x70 + undefined* m_unk0x74; // 0x74 + undefined4 m_unk0x78; // 0x78 + undefined m_unk0x7c; // 0x7c + PCMWAVEFORMAT m_pcmWaveFormat; // 0x7d +}; + +// SYNTHETIC: LEGO1 0x10018460 +// LegoLoadCacheSoundPresenter::`scalar deleting destructor' + +#endif // LEGOLOADCACHESOUNDPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legolocations.h b/LEGO1/lego/legoomni/include/legolocations.h new file mode 100644 index 00000000..a049dc2f --- /dev/null +++ b/LEGO1/lego/legoomni/include/legolocations.h @@ -0,0 +1,31 @@ +#ifndef LEGOLOCATIONS_H +#define LEGOLOCATIONS_H + +#include "decomp.h" +#include "mxtypes.h" + +// SIZE 0x60 +struct LegoLocation { + // SIZE 0x18 + struct Boundary { + const char* m_name; // 0x00 + MxS32 m_src; // 0x04 + float m_srcScale; // 0x08 + MxS32 m_dest; // 0x0c + float m_destScale; // 0x10 + MxBool m_unk0x10; // 0x14 + }; + + MxU32 m_index; // 0x00 + const char* m_name; // 0x04 + float m_position[3]; // 0x08 + float m_direction[3]; // 0x14 + float m_up[3]; // 0x20 + Boundary m_boundaryA; // 0x2c + Boundary m_boundaryB; // 0x44 + undefined4 m_unk0x5c; // 0x5c +}; + +extern LegoLocation g_locations[70]; + +#endif // LEGOLOCATIONS_H diff --git a/LEGO1/lego/legoomni/include/legolocomotionanimpresenter.h b/LEGO1/lego/legoomni/include/legolocomotionanimpresenter.h new file mode 100644 index 00000000..1a06ab35 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legolocomotionanimpresenter.h @@ -0,0 +1,62 @@ +#ifndef LEGOLOCOMOTIONANIMPRESENTER_H +#define LEGOLOCOMOTIONANIMPRESENTER_H + +#include "legoloopinganimpresenter.h" +#include "legoroimaplist.h" + +// VTABLE: LEGO1 0x100d9170 +// SIZE 0xd8 +class LegoLocomotionAnimPresenter : public LegoLoopingAnimPresenter { +public: + LegoLocomotionAnimPresenter(); + ~LegoLocomotionAnimPresenter() override; + + // FUNCTION: LEGO1 0x1006ce50 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f06e4 + return "LegoLocomotionAnimPresenter"; + } + + // FUNCTION: LEGO1 0x1006ce60 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || LegoLoopingAnimPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + void EndAction() override; // vtable+0x40 + void PutFrame() override; // vtable+0x6c + MxResult CreateAnim(MxStreamChunk* p_chunk) override; // vtable+0x88 + + // SYNTHETIC: LEGO1 0x1006cfe0 + // LegoLocomotionAnimPresenter::`scalar deleting destructor' + + void FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value); + + inline void DecrementUnknown0xd4() + { + if (m_unk0xd4) { + --m_unk0xd4; + } + } + + inline undefined2 GetUnknown0xd4() { return m_unk0xd4; } + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + + undefined4 m_unk0xc0; // 0xc0 + undefined4* m_unk0xc4; // 0xc4 + LegoROIMapList* m_roiMapList; // 0xc8 + MxS32 m_unk0xcc; // 0xcc + MxS32 m_unk0xd0; // 0xd0 + undefined2 m_unk0xd4; // 0xd4 +}; + +#endif // LEGOLOCOMOTIONANIMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legolodlist.h b/LEGO1/lego/legoomni/include/legolodlist.h new file mode 100644 index 00000000..af538ccc --- /dev/null +++ b/LEGO1/lego/legoomni/include/legolodlist.h @@ -0,0 +1,83 @@ +#ifndef LEGOLODLIST_H +#define LEGOLODLIST_H + +#include "mxlist.h" +#include "roi/legolod.h" + +#pragma warning(disable : 4786) + +// VTABLE: LEGO1 0x100d9d30 +// class MxCollection + +// VTABLE: LEGO1 0x100d9d48 +// class MxList + +// VTABLE: LEGO1 0x100d9d60 +// class MxPtrList + +// VTABLE: LEGO1 0x100d9d78 +// SIZE 0x18 +class LegoLODList : public MxPtrList { +public: + LegoLODList() : MxPtrList(FALSE) {} + + // SYNTHETIC: LEGO1 0x1007de40 + // LegoLODList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100d9df0 +// class MxListCursor + +// VTABLE: LEGO1 0x100d9e08 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d9e20 +// SIZE 0x10 +class LegoLODListCursor : public MxPtrListCursor { +public: + LegoLODListCursor(LegoLODList* p_list) : MxPtrListCursor(p_list) {} +}; + +// SYNTHETIC: LEGO1 0x1007d9b0 +// LegoLODListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1007da20 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x1007da70 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1007dae0 +// MxPtrListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1007db50 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x1007dba0 +// LegoLODListCursor::~LegoLODListCursor + +// TEMPLATE: LEGO1 0x1007d480 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1007d490 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1007d4e0 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1007d4f0 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x1007d580 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1007d5f0 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1007d6a0 +// MxPtrList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1007d710 +// MxPtrList::~MxPtrList + +#endif // LEGOLODLIST_H diff --git a/LEGO1/lego/legoomni/include/legoloopinganimpresenter.h b/LEGO1/lego/legoomni/include/legoloopinganimpresenter.h new file mode 100644 index 00000000..c7095dac --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoloopinganimpresenter.h @@ -0,0 +1,36 @@ +#ifndef LEGOLOOPINGANIMPRESENTER_H +#define LEGOLOOPINGANIMPRESENTER_H + +#include "legoanimpresenter.h" + +// VTABLE: LEGO1 0x100d4900 +// SIZE 0xc0 +class LegoLoopingAnimPresenter : public LegoAnimPresenter { +public: + // FUNCTION: LEGO1 0x1000c9a0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0700 + return "LegoLoopingAnimPresenter"; + } + + // FUNCTION: LEGO1 0x1000c9b0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || LegoAnimPresenter::IsA(p_name); + } + + void StreamingTickle() override; // vtable+0x20 + void PutFrame() override; // vtable+0x6c + +private: + undefined4 m_unk0xbc; // 0xbc +}; + +// SYNTHETIC: LEGO1 0x1006d000 +// LegoLoopingAnimPresenter::~LegoLoopingAnimPresenter + +// SYNTHETIC: LEGO1 0x1000f440 +// LegoLoopingAnimPresenter::`scalar deleting destructor' + +#endif // LEGOLOOPINGANIMPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legomain.h b/LEGO1/lego/legoomni/include/legomain.h new file mode 100644 index 00000000..1d2191d5 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legomain.h @@ -0,0 +1,179 @@ +#ifndef LEGOMAIN_H +#define LEGOMAIN_H + +#include "compat.h" +#include "mxdsaction.h" +#include "mxomni.h" + +class Isle; +class IslePathActor; +class LegoAnimationManager; +class LegoBuildingManager; +class LegoCharacterManager; +class LegoEntity; +class LegoGameState; +class LegoInputManager; +class LegoNavController; +class LegoPathBoundary; +class LegoPlantManager; +class LegoROI; +class LegoSoundManager; +class LegoTextureContainer; +class LegoVideoManager; +class LegoWorld; +class LegoWorldList; +class MxAtomId; +class MxBackgroundAudioManager; +class MxTransitionManager; +class ViewLODListManager; + +// VTABLE: LEGO1 0x100d8638 +// SIZE 0x140 +class LegoOmni : public MxOmni { +public: + enum { + c_disableInput = 0x01, + c_disable3d = 0x02, + c_clearScreen = 0x04 + }; + + // SIZE 0x1c + struct ScriptContainer { + // FUNCTION: LEGO1 0x1005ac40 + ScriptContainer() + { + m_index = -1; + m_atomId = NULL; + } + + ScriptContainer(MxS32 p_index, const char* p_key, MxAtomId* p_atomId) + { + m_index = p_index; + + if (p_key) { + strcpy(m_key, p_key); + } + + m_atomId = p_atomId; + } + + // FUNCTION: LEGO1 0x1005ac50 + ScriptContainer& operator=(const ScriptContainer& p_container) + { + m_index = p_container.m_index; + strcpy(m_key, p_container.m_key); + m_atomId = p_container.m_atomId; + return *this; + } + + inline MxS32 GetIndex() { return m_index; } + inline const char* GetKey() { return m_key; } + + MxS32 m_index; // 0x00 + char m_key[20]; // 0x04 + MxAtomId* m_atomId; // 0x18 + }; + + LegoOmni(); + ~LegoOmni() override; // vtable+00 + + MxLong Notify(MxParam& p_param) override; // vtable+04 + + // FUNCTION: LEGO1 0x10058aa0 + inline const char* ClassName() const override // vtable+0c + { + // STRING: LEGO1 0x100f671c + return "LegoOmni"; + } + + // FUNCTION: LEGO1 0x10058ab0 + inline MxBool IsA(const char* p_name) const override // vtable+10 + { + return !strcmp(p_name, LegoOmni::ClassName()) || MxOmni::IsA(p_name); + } + + void Init() override; // vtable+14 + MxResult Create(MxOmniCreateParam& p_param) override; // vtable+18 + void Destroy() override; // vtable+1c + MxResult Start(MxDSAction* p_dsAction) override; // vtable+20 + void DeleteObject(MxDSAction& p_dsAction) override; // vtable+24 + MxBool DoesEntityExist(MxDSAction& p_dsAction) override; // vtable+28 + MxEntity* AddToWorld(const char* p_id, MxS32 p_entityId, MxPresenter* p_presenter) override; // vtable+30 + void NotifyCurrentEntity(const MxNotificationParam& p_param) override; // vtable+34 + void StartTimer() override; // vtable+38 + void StopTimer() override; // vtable+3c + + LegoWorld* FindWorld(const MxAtomId& p_atom, MxS32 p_entityid); + LegoROI* FindROI(const char* p_name); + void AddWorld(LegoWorld* p_world); + void DeleteWorld(LegoWorld* p_world); + void FUN_1005b4f0(MxBool p_disable, MxU16 p_flags); + void CreateBackgroundAudio(); + void RemoveWorld(const MxAtomId& p_atom, MxLong p_objectId); + MxResult RegisterScripts(); + const char* GetScriptName(MxU32 p_index); + MxAtomId* GetScriptAtom(MxU32 p_index); + MxS32 GetScriptIndex(const char* p_key); + void DeleteAction(); + + static MxS32 GetCurrPathInfo(LegoPathBoundary**, MxS32&); + static void CreateInstance(); + static LegoOmni* GetInstance(); + + LegoVideoManager* GetVideoManager() { return (LegoVideoManager*) m_videoManager; } + LegoSoundManager* GetSoundManager() { return (LegoSoundManager*) m_soundManager; } + LegoInputManager* GetInputManager() { return m_inputManager; } + LegoTextureContainer* GetTextureContainer() { return m_textureContainer; } + ViewLODListManager* GetViewLODListManager() { return m_viewLODListManager; } + LegoWorld* GetCurrentWorld() { return m_currentWorld; } + LegoNavController* GetNavController() { return m_navController; } + IslePathActor* GetCurrentActor() { return m_currentActor; } + LegoPlantManager* GetLegoPlantManager() { return m_plantManager; } + LegoAnimationManager* GetAnimationManager() { return m_animationManager; } + LegoBuildingManager* GetLegoBuildingManager() { return m_buildingManager; } + LegoGameState* GetGameState() { return m_gameState; } + MxBackgroundAudioManager* GetBackgroundAudioManager() { return m_bkgAudioManager; } + MxTransitionManager* GetTransitionManager() { return m_transitionManager; } + MxDSAction& GetCurrentAction() { return m_action; } + LegoCharacterManager* GetCharacterManager() { return m_characterManager; } + LegoWorldList* GetWorldList() { return m_worldList; } + + inline void SetNavController(LegoNavController* p_navController) { m_navController = p_navController; } + inline void SetCurrentActor(IslePathActor* p_currentActor) { m_currentActor = p_currentActor; } + inline void SetCurrentWorld(LegoWorld* p_currentWorld) { m_currentWorld = p_currentWorld; } + inline void SetExit(MxBool p_exit) { m_exit = p_exit; } + inline MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction) + { + return m_unk0x13c ? Start(&p_dsAction) : SUCCESS; + } + inline void SetUnknown13c(MxBool p_unk0x13c) { m_unk0x13c = p_unk0x13c; } + + inline void CloseMainWindow() { PostMessageA(m_windowHandle, WM_CLOSE, 0, 0); } + + // SYNTHETIC: LEGO1 0x10058b30 + // LegoOmni::`scalar deleting destructor' + +private: + ScriptContainer* m_scripts; // 0x68 + ViewLODListManager* m_viewLODListManager; // 0x6c + LegoInputManager* m_inputManager; // 0x70 + LegoTextureContainer* m_textureContainer; // 0x74 + LegoWorldList* m_worldList; // 0x78 + LegoWorld* m_currentWorld; // 0x7c + MxBool m_exit; // 0x80 + LegoNavController* m_navController; // 0x84 + IslePathActor* m_currentActor; // 0x88 + LegoCharacterManager* m_characterManager; // 0x8c + LegoPlantManager* m_plantManager; // 0x90 + LegoAnimationManager* m_animationManager; // 0x94 + LegoBuildingManager* m_buildingManager; // 0x98 + LegoGameState* m_gameState; // 0x9c + MxDSAction m_action; // 0xa0 + MxBackgroundAudioManager* m_bkgAudioManager; // 0x134 + MxTransitionManager* m_transitionManager; // 0x138 + +public: + MxBool m_unk0x13c; // 0x13c +}; + +#endif // LEGOMAIN_H diff --git a/LEGO1/lego/legoomni/include/legometerpresenter.h b/LEGO1/lego/legoomni/include/legometerpresenter.h new file mode 100644 index 00000000..ad43944d --- /dev/null +++ b/LEGO1/lego/legoomni/include/legometerpresenter.h @@ -0,0 +1,37 @@ +#ifndef LEGOMETERPRESENTER_H +#define LEGOMETERPRESENTER_H + +#include "mxstillpresenter.h" +#include "mxstring.h" + +// VTABLE: LEGO1 0x100d7ac8 +// SIZE 0x94 +class LegoMeterPresenter : public MxStillPresenter { +public: + LegoMeterPresenter(); + ~LegoMeterPresenter() override; + + // MxStillPresenter's `::ClassName` and `::IsA` are used. + + void StreamingTickle() override; // vtable+0x20 + void RepeatingTickle() override; // vtable+0x24 + void ParseExtra() override; // vtable+0x30 + +private: + void FUN_10043a50(); + + MxU8* m_unk0x6c; // 0x6c + MxU16 m_type; // 0x70 + MxString m_variable; // 0x74 + MxFloat m_unk0x84; // 0x84 + MxU16 m_unk0x88; // 0x88 + MxU16 m_unk0x8a; // 0x8a + MxU16 m_unk0x8c; // 0x8c + MxU16 m_unk0x8e; // 0x8e + MxU16 m_layout; // 0x90 +}; + +// SYNTHETIC: LEGO1 0x10043760 +// LegoMeterPresenter::`scalar deleting destructor' + +#endif // LEGOMETERPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legomodelpresenter.h b/LEGO1/lego/legoomni/include/legomodelpresenter.h new file mode 100644 index 00000000..f8b4cea1 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legomodelpresenter.h @@ -0,0 +1,60 @@ +#ifndef LEGOMODELPRESENTER_H +#define LEGOMODELPRESENTER_H + +#include "mxvideopresenter.h" + +class LegoROI; +class LegoWorld; +class LegoEntity; +class MxDSChunk; + +// VTABLE: LEGO1 0x100d4e50 +// SIZE 0x6c +class LegoModelPresenter : public MxVideoPresenter { +public: + LegoModelPresenter() { Reset(); } + + // FUNCTION: LEGO1 0x10067a10 + ~LegoModelPresenter() override { Destroy(TRUE); } + + static void configureLegoModelPresenter(MxS32 p_modelPresenterConfig); + + // FUNCTION: LEGO1 0x1000ccb0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f067c + return "LegoModelPresenter"; + } + + // FUNCTION: LEGO1 0x1000ccc0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || MxVideoPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void ParseExtra() override; // vtable+0x30 + void Destroy() override; // vtable+0x38 + + MxResult FUN_1007ff70(MxDSChunk& p_chunk, LegoEntity* p_entity, MxBool p_roiVisible, LegoWorld* p_world); + + inline void Reset() + { + m_roi = NULL; + m_addedToView = FALSE; + } + + // SYNTHETIC: LEGO1 0x1000cdd0 + // LegoModelPresenter::`scalar deleting destructor' + +protected: + void Destroy(MxBool p_fromDestructor); + +private: + LegoROI* m_roi; // 0x64 + MxBool m_addedToView; // 0x68 + + MxResult CreateROI(MxDSChunk* p_chunk); +}; + +#endif // LEGOMODELPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legonamedpart.h b/LEGO1/lego/legoomni/include/legonamedpart.h new file mode 100644 index 00000000..dcdee2f9 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legonamedpart.h @@ -0,0 +1,25 @@ +#ifndef LEGONAMEDPART_H +#define LEGONAMEDPART_H + +#include "legolodlist.h" +#include "mxstring.h" + +// SIZE 0x14 +class LegoNamedPart { +public: + LegoNamedPart(const char* p_name, LegoLODList* p_list) + { + m_name = p_name; + m_list = p_list; + } + ~LegoNamedPart() { delete m_list; } + + const MxString* GetName() const { return &m_name; } + LegoLODList* GetList() { return m_list; } + +private: + MxString m_name; // 0x00 + LegoLODList* m_list; // 0x04 +}; + +#endif // LEGONAMEDPART_H diff --git a/LEGO1/lego/legoomni/include/legonamedpartlist.h b/LEGO1/lego/legoomni/include/legonamedpartlist.h new file mode 100644 index 00000000..5026c53a --- /dev/null +++ b/LEGO1/lego/legoomni/include/legonamedpartlist.h @@ -0,0 +1,84 @@ +#ifndef LEGONAMEDPARTLIST_H +#define LEGONAMEDPARTLIST_H + +#include "legonamedpart.h" +#include "mxlist.h" + +// VTABLE: LEGO1 0x100d9d90 +// class MxCollection + +// VTABLE: LEGO1 0x100d9da8 +// class MxList + +// VTABLE: LEGO1 0x100d9dc0 +// class MxPtrList + +// VTABLE: LEGO1 0x100d9dd8 +// SIZE 0x18 +class LegoNamedPartList : public MxPtrList { +public: + LegoNamedPartList() : MxPtrList(TRUE) {} + + // SYNTHETIC: LEGO1 0x1007dbf0 + // LegoNamedPartList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100d9e68 +// class MxListCursor + +// VTABLE: LEGO1 0x100d9e38 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d9e50 +// SIZE 0x10 +class LegoNamedPartListCursor : public MxPtrListCursor { +public: + LegoNamedPartListCursor(LegoNamedPartList* p_list) : MxPtrListCursor(p_list) {} +}; + +// SYNTHETIC: LEGO1 0x1007e170 +// LegoNamedPartListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1007e1e0 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x1007e230 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1007e2a0 +// MxPtrListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1007e310 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x1007e360 +// LegoNamedPartListCursor::~LegoNamedPartListCursor + +// TEMPLATE: LEGO1 0x1007d760 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1007d770 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1007d7c0 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1007d7d0 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x1007d860 +// MxPtrList::Destroy + +// TEMPLATE: LEGO1 0x1007dc60 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x1007dcb0 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1007dd20 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1007ddd0 +// MxPtrList::`scalar deleting destructor' + +#endif // LEGONAMEDPARTLIST_H diff --git a/LEGO1/lego/legoomni/include/legonamedtexture.h b/LEGO1/lego/legoomni/include/legonamedtexture.h new file mode 100644 index 00000000..66b9663e --- /dev/null +++ b/LEGO1/lego/legoomni/include/legonamedtexture.h @@ -0,0 +1,27 @@ +#ifndef LEGONAMEDTEXTURE_H +#define LEGONAMEDTEXTURE_H + +#include "misc/legotexture.h" +#include "mxstring.h" + +// SIZE 0x14 +class LegoNamedTexture { +public: + LegoNamedTexture(const char* p_name, LegoTexture* p_texture) + { + m_name = p_name; + m_texture = p_texture; + } + ~LegoNamedTexture() { delete m_texture; } + + // FUNCTION: LEGO1 0x1003f920 + const MxString* GetName() const { return &m_name; } + + LegoTexture* GetTexture() { return m_texture; } + +private: + MxString m_name; // 0x00 + LegoTexture* m_texture; // 0x04 +}; + +#endif // LEGONAMEDTEXTURE_H diff --git a/LEGO1/lego/legoomni/include/legonamedtexturelist.h b/LEGO1/lego/legoomni/include/legonamedtexturelist.h new file mode 100644 index 00000000..05ed0ac3 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legonamedtexturelist.h @@ -0,0 +1,84 @@ +#ifndef LEGONAMEDTEXTURELIST_H +#define LEGONAMEDTEXTURELIST_H + +#include "legonamedtexture.h" +#include "mxlist.h" + +// VTABLE: LEGO1 0x100d8110 +// class MxCollection + +// VTABLE: LEGO1 0x100d8128 +// class MxList + +// VTABLE: LEGO1 0x100d8140 +// class MxPtrList + +// VTABLE: LEGO1 0x100d8158 +// SIZE 0x18 +class LegoNamedTextureList : public MxPtrList { +public: + LegoNamedTextureList() : MxPtrList(TRUE) {} + + // SYNTHETIC: LEGO1 0x1004f040 + // LegoNamedTextureList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100d8170 +// class MxListCursor + +// VTABLE: LEGO1 0x100d8188 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d81a0 +// SIZE 0x10 +class LegoNamedTextureListCursor : public MxPtrListCursor { +public: + LegoNamedTextureListCursor(LegoNamedTextureList* p_list) : MxPtrListCursor(p_list) {} +}; + +// SYNTHETIC: LEGO1 0x1004f500 +// LegoNamedTextureListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1004f570 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x1004f5c0 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1004f630 +// MxPtrListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1004f6a0 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x1004f6f0 +// LegoNamedTextureListCursor::~LegoNamedTextureListCursor + +// TEMPLATE: LEGO1 0x1004eec0 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1004eed0 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1004ef20 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1004ef30 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x1004efc0 +// MxPtrList::Destroy + +// TEMPLATE: LEGO1 0x1004f0b0 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x1004f100 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1004f170 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1004f220 +// MxPtrList::`scalar deleting destructor' + +#endif // LEGONAMEDTEXTURELIST_H diff --git a/LEGO1/lego/legoomni/include/legonavcontroller.h b/LEGO1/lego/legoomni/include/legonavcontroller.h new file mode 100644 index 00000000..8e54bd1e --- /dev/null +++ b/LEGO1/lego/legoomni/include/legonavcontroller.h @@ -0,0 +1,143 @@ +#ifndef __LEGONAVCONTROLLER_H +#define __LEGONAVCONTROLLER_H + +#include "decomp.h" +#include "mxcore.h" +#include "mxtypes.h" + +struct LegoLocation; +class Vector3; + +////////////////////////////////////////////////////////////////////////////// +// +// LegoMouseController + +// VTABLE: LEGO1 0x100d85b8 +// SIZE 0x70 +class LegoNavController : public MxCore { +public: + LegoNavController(); + ~LegoNavController() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10054b80 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f66d8 + return "LegoNavController"; + } + + // FUNCTION: LEGO1 0x10054b90 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || MxCore::IsA(p_name); + } + + void SetTargets(int p_hPos, int p_vPos, MxBool p_accel); + void SetControlMax(int p_hMax, int p_vMax); + void SetTrackDefaultParams(MxBool p_state) { m_trackDefault = p_state; } + void SetToDefaultParams(); + MxBool CalculateNewPosDir( + const Vector3& p_curPos, + const Vector3& p_curDir, + Vector3& p_newPos, + Vector3& p_newDir, + const Vector3* p_und + ); + + static void GetDefaults( + int* p_dz, + float* p_lv, + float* p_rv, + float* p_la, + float* p_ra, + float* p_ld, + float* p_rd, + float* p_lmina, + float* p_rmina, + float* p_rs, + MxBool* p_urs + ); + static void SetDefaults( + int p_dz, + float p_lv, + float p_rv, + float p_la, + float p_ra, + float p_ld, + float p_rd, + float p_lmina, + float p_rmina, + float p_rs, + MxBool p_urs + ); + static MxResult UpdateLocation(MxU32 p_location); + static MxResult UpdateLocation(const char* p_location); + static LegoLocation* GetLocation(MxU32 p_location); + + inline void SetLinearVel(MxFloat p_linearVel) { m_linearVel = p_linearVel; } + inline MxFloat GetLinearVel() { return m_linearVel; } + inline MxFloat GetRotationalVel() { return m_rotationalVel; } + inline MxFloat GetMaxLinearVel() { return m_maxLinearVel; } + inline void ResetLinearVel(MxFloat p_maxLinearVel) + { + m_maxLinearVel = p_maxLinearVel; + m_trackDefault = 0; + } + + // SYNTHETIC: LEGO1 0x10054c10 + // LegoNavController::`scalar deleting destructor' + +protected: + float CalculateNewVel(float p_targetVel, float p_currentVel, float p_accel, float p_time); + float CalculateNewTargetVel(int p_pos, int p_center, float p_max); + float CalculateNewAccel(int p_pos, int p_center, float p_max, int p_min); + + MxResult ProcessJoystickInput(MxBool& p_und); + MxResult ProcessKeyboardInput(); + + int m_hMax; // 0x08 + int m_vMax; // 0x0c + int m_deadZone; // 0x10 + float m_zeroThreshold; // 0x14 + float m_linearVel; // 0x18 + float m_rotationalVel; // 0x1c + float m_targetLinearVel; // 0x20 + float m_targetRotationalVel; // 0x24 + float m_maxLinearVel; // 0x28 + float m_maxRotationalVel; // 0x2c + float m_linearAccel; // 0x30 + float m_rotationalAccel; // 0x34 + float m_maxLinearAccel; // 0x38 + float m_maxRotationalAccel; // 0x3c + float m_minLinearAccel; // 0x40 + float m_minRotationalAccel; // 0x44 + float m_maxLinearDeccel; // 0x48 + float m_maxRotationalDeccel; // 0x4c + float m_rotSensitivity; // 0x50 + MxBool m_useRotationalVel; // 0x54 + MxTime m_lastTime; // 0x58 + MxBool m_trackDefault; // 0x5c + MxBool m_unk0x5d; // 0x5d + float m_unk0x60; // 0x60 + float m_unk0x64; // 0x64 + float m_unk0x68; // 0x68 + MxBool m_unk0x6c; // 0x6c + + // one copy of defaults (these can be set by App.) + static int g_defdeadZone; + static float g_defzeroThreshold; + static float g_defmaxLinearVel; + static float g_defmaxRotationalVel; + static float g_defmaxLinearAccel; + static float g_defmaxRotationalAccel; + static float g_defminLinearAccel; + static float g_defminRotationalAccel; + static float g_defmaxLinearDeccel; + static float g_defmaxRotationalDeccel; + static float g_defrotSensitivity; + static MxBool g_defuseRotationalVel; +}; + +#endif // __LEGOPOVCONTROLLER_H diff --git a/LEGO1/lego/legoomni/include/legonotify.h b/LEGO1/lego/legoomni/include/legonotify.h new file mode 100644 index 00000000..ed4218b2 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legonotify.h @@ -0,0 +1,11 @@ +#ifndef LEGONOTIFY_H +#define LEGONOTIFY_H + +enum LegoEventNotificationParamType { + c_lButtonState = 1, + c_rButtonState = 2, + c_modKey1 = 4, + c_modKey2 = 8, +}; + +#endif // LEGONOTIFY_H diff --git a/LEGO1/lego/legoomni/include/legoobjectfactory.h b/LEGO1/lego/legoomni/include/legoobjectfactory.h new file mode 100644 index 00000000..ceb5f56e --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoobjectfactory.h @@ -0,0 +1,124 @@ +#ifndef LEGOOBJECTFACTORY_H +#define LEGOOBJECTFACTORY_H + +#include "mxobjectfactory.h" + +#define FOR_LEGOOBJECTFACTORY_OBJECTS(X) \ + X(LegoEntityPresenter) \ + X(LegoActorPresenter) \ + X(LegoWorldPresenter) \ + X(LegoWorld) \ + X(LegoAnimPresenter) \ + X(LegoModelPresenter) \ + X(LegoTexturePresenter) \ + X(LegoPhonemePresenter) \ + X(LegoFlcTexturePresenter) \ + X(LegoPalettePresenter) \ + X(LegoPathPresenter) \ + X(LegoLoopingAnimPresenter) \ + X(LegoLocomotionAnimPresenter) \ + X(LegoHideAnimPresenter) \ + X(LegoPartPresenter) \ + X(LegoCarBuildAnimPresenter) \ + X(LegoActionControlPresenter) \ + X(MxVideoPresenter) \ + X(LegoLoadCacheSoundPresenter) \ + X(Lego3DWavePresenter) \ + X(LegoActor) \ + X(LegoPathActor) \ + X(LegoRaceCar) \ + X(LegoJetski) \ + X(JetskiRace) \ + X(LegoEntity) \ + X(LegoCarRaceActor) \ + X(LegoJetskiRaceActor) \ + X(LegoCarBuild) \ + X(Infocenter) \ + X(LegoAnimActor) \ + X(MxControlPresenter) \ + X(RegistrationBook) \ + X(HistoryBook) \ + X(ElevatorBottom) \ + X(InfocenterDoor) \ + X(Score) \ + X(ScoreState) \ + X(Hospital) \ + X(Isle) \ + X(Police) \ + X(GasStation) \ + X(LegoAct2) \ + X(LegoAct2State) \ + X(CarRace) \ + X(HospitalState) \ + X(InfocenterState) \ + X(PoliceState) \ + X(GasStationState) \ + X(SkateBoard) \ + X(Helicopter) \ + X(HelicopterState) \ + X(DuneBuggy) \ + X(Pizza) \ + X(PizzaMissionState) \ + X(Act2Actor) \ + X(Act2Brick) \ + /*X(Act2GenActor)*/ \ + X(Act2PoliceStation) \ + X(Act3) \ + X(Act3State) \ + X(Doors) \ + X(LegoAnimMMPresenter) \ + X(RaceCar) \ + X(Jetski) \ + X(Bike) \ + X(Motocycle) \ + X(Ambulance) \ + X(AmbulanceMissionState) \ + X(TowTrack) \ + X(TowTrackMissionState) \ + /*X(Act3Cop)*/ \ + /*X(Act3Brickster)*/ \ + X(Act3Shark) \ + X(BumpBouy) \ + X(Act3Actor) \ + X(JetskiRaceState) \ + X(CarRaceState) \ + X(Act1State) \ + X(Pizzeria) \ + X(PizzeriaState) \ + X(InfoCenterEntity) \ + X(HospitalEntity) \ + X(GasStationEntity) \ + X(PoliceEntity) \ + X(BeachHouseEntity) \ + X(RaceStandsEntity) \ + X(JukeBoxEntity) \ + X(RadioState) \ + X(CaveEntity) \ + X(JailEntity) \ + X(MxCompositeMediaPresenter) \ + X(JukeBox) \ + X(JukeBoxState) \ + X(RaceSkel) \ + X(AnimState) + +// VTABLE: LEGO1 0x100d4768 +// SIZE 0x1c8 +class LegoObjectFactory : public MxObjectFactory { +public: + LegoObjectFactory(); + MxCore* Create(const char* p_name) override; // vtable+0x14 + void Destroy(MxCore* p_object) override; // vtable+0x18 + + // SYNTHETIC: LEGO1 0x10009000 + // LegoObjectFactory::`scalar deleting destructor' + + // SYNTHETIC: LEGO1 0x10009170 + // LegoObjectFactory::~LegoObjectFactory + +private: +#define X(V) MxAtomId m_id##V; + FOR_LEGOOBJECTFACTORY_OBJECTS(X) +#undef X +}; + +#endif // LEGOOBJECTFACTORY_H diff --git a/LEGO1/lego/legoomni/include/legopalettepresenter.h b/LEGO1/lego/legoomni/include/legopalettepresenter.h new file mode 100644 index 00000000..d6906540 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legopalettepresenter.h @@ -0,0 +1,44 @@ +#ifndef LEGOPALETTEPRESENTER_H +#define LEGOPALETTEPRESENTER_H + +#include "decomp.h" +#include "mxvideopresenter.h" + +class MxPalette; + +// VTABLE: LEGO1 0x100d9aa0 +// SIZE 0x68 +class LegoPalettePresenter : public MxVideoPresenter { +public: + LegoPalettePresenter(); + ~LegoPalettePresenter() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x10079f30 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f061c + return "LegoPalettePresenter"; + } + + // FUNCTION: LEGO1 0x10079f40 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ClassName()) || MxVideoPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void Destroy() override; // vtable+0x38 + + MxResult ParsePalette(MxStreamChunk* p_chunk); + + // SYNTHETIC: LEGO1 0x1007a050 + // LegoPalettePresenter::`scalar deleting destructor' + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + + MxPalette* m_palette; // 0x64 +}; + +#endif // LEGOPALETTEPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legopartpresenter.h b/LEGO1/lego/legoomni/include/legopartpresenter.h new file mode 100644 index 00000000..5de1402d --- /dev/null +++ b/LEGO1/lego/legoomni/include/legopartpresenter.h @@ -0,0 +1,49 @@ +#ifndef LEGOPARTPRESENTER_H +#define LEGOPARTPRESENTER_H + +#include "legonamedpartlist.h" +#include "mxmediapresenter.h" + +// VTABLE: LEGO1 0x100d4df0 +// SIZE 0x54 +class LegoPartPresenter : public MxMediaPresenter { +public: + LegoPartPresenter() { Reset(); } + + // FUNCTION: LEGO1 0x10067300 + ~LegoPartPresenter() override { Destroy(TRUE); } + + // FUNCTION: LEGO1 0x1000cf70 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f05d8 + return "LegoPartPresenter"; + } + + // FUNCTION: LEGO1 0x1000cf80 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoPartPresenter::ClassName()) || MxMediaPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + + static void configureLegoPartPresenter(MxS32, MxS32); + + // SYNTHETIC: LEGO1 0x1000d060 + // LegoPartPresenter::`scalar deleting destructor' + + inline void Reset() { m_parts = NULL; } + + MxResult Read(MxDSChunk& p_chunk); + void Store(); + +private: + void Destroy(MxBool p_fromDestructor); + + LegoNamedPartList* m_parts; // 0x50 +}; + +#endif // LEGOPARTPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h new file mode 100644 index 00000000..43b6c480 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -0,0 +1,155 @@ +#ifndef LEGOPATHACTOR_H +#define LEGOPATHACTOR_H + +#include "legoactor.h" +#include "misc/legounknown.h" +#include "mxgeometry/mxmatrix.h" +#include "mxtypes.h" + +struct LegoEdge; +class LegoPathBoundary; +class LegoPathController; +struct LegoUnknown100db7f4; + +// VTABLE: LEGO1 0x100d6e28 +// SIZE 0x154 +class LegoPathActor : public LegoActor { +public: + enum { + c_bit3 = 0x04 + }; + + LegoPathActor(); + ~LegoPathActor() override; + + // FUNCTION: LEGO1 0x1000c430 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0114 + return "LegoPathActor"; + } + + // FUNCTION: LEGO1 0x1000c440 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoPathActor::ClassName()) || LegoActor::IsA(p_name); + } + + void ParseAction(char* p_extra) override; // vtable+0x20 + virtual MxS32 VTable0x68(Vector3&, Vector3&, Vector3&); // vtable+0x68 + virtual MxU32 VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 + ); // vtable+0x6c + virtual void VTable0x70(float p_time); // vtable+0x70 + virtual void VTable0x74(Matrix4& p_transform); // vtable+0x74 + + // FUNCTION: LEGO1 0x10002d20 + virtual void SetUserNavFlag(MxBool p_userNavFlag) { m_userNavFlag = p_userNavFlag; } // vtable+0x78 + + // FUNCTION: LEGO1 0x10002d30 + virtual MxU8 GetUserNavFlag() { return m_userNavFlag; } // vtable+0x7c + + virtual MxResult VTable0x80( + Vector3& p_point1, + Vector3& p_point2, + Vector3& p_point3, + Vector3& p_point4 + ); // vtable+0x80 + virtual MxResult VTable0x84( + LegoPathBoundary* p_boundary, + float p_time, + Vector3& p_p1, + Vector3& p_p4, + LegoUnknown100db7f4& p_destEdge, + float p_destScale + ); // vtable+0x84 + virtual MxResult VTable0x88( + LegoPathBoundary* p_boundary, + float p_time, + LegoEdge& p_srcEdge, + float p_srcScale, + LegoUnknown100db7f4& p_destEdge, + float p_destScale + ); // vtable+0x88 + virtual MxS32 VTable0x8c(float p_time, Matrix4& p_transform); // vtable+0x8c + + // FUNCTION: LEGO1 0x10002d40 + virtual MxU32 VTable0x90(float, Matrix4&) { return FALSE; } // vtable+0x90 + + // FUNCTION: LEGO1 0x10002d50 + virtual MxResult VTable0x94(LegoPathActor*, MxBool) { return 0; } // vtable+0x94 + + virtual void VTable0x98(); // vtable+0x98 + virtual MxResult WaitForAnimation(); // vtable+0x9c + + // FUNCTION: LEGO1 0x10002d60 + virtual MxS32 VTable0xa0() { return 0; } // vtable+0xa0 + + virtual void VTable0xa4(MxU8&, MxS32&); // vtable+0xa4 + virtual void VTable0xa8(); // vtable+0xa8 + + // FUNCTION: LEGO1 0x10002d70 + virtual void VTable0xac(MxFloat p_unk0x13c) { m_unk0x13c = p_unk0x13c; } // vtable+0xac + + // FUNCTION: LEGO1 0x10002d80 + virtual MxFloat VTable0xb0() { return m_unk0x13c; } // vtable+0xb0 + + // FUNCTION: LEGO1 0x10002d90 + virtual MxFloat VTable0xb4() { return m_unk0x140; } // vtable+0xb4 + + // FUNCTION: LEGO1 0x10002da0 + virtual MxFloat VTable0xb8() { return m_unk0x144; } // vtable+0xb8 + + // FUNCTION: LEGO1 0x10002db0 + virtual void VTable0xbc(MxFloat p_unk0x140) { m_unk0x140 = p_unk0x140; } // vtable+0xbc + + // FUNCTION: LEGO1 0x10002dc0 + virtual void VTable0xc0(MxFloat p_unk0x144) { m_unk0x144 = p_unk0x144; } // vtable+0xc0 + + // FUNCTION: LEGO1 0x10002dd0 + virtual void VTable0xc4() {} // vtable+0xc4 + + // FUNCTION: LEGO1 0x10002de0 + virtual void VTable0xc8(MxU8 p_unk0x148) { m_unk0x148 = p_unk0x148; } // vtable+0xc8 + + inline LegoPathBoundary* GetBoundary() { return m_boundary; } + inline MxU32 GetState() { return m_state; } + inline LegoPathController* GetController() { return m_controller; } + + inline void SetBoundary(LegoPathBoundary* p_boundary) { m_boundary = p_boundary; } + inline void SetState(MxU32 p_state) { m_state = p_state; } + inline void SetController(LegoPathController* p_controller) { m_controller = p_controller; } + + // SYNTHETIC: LEGO1 0x1002d800 + // LegoPathActor::`scalar deleting destructor' + +protected: + MxFloat m_BADuration; // 0x78 + MxFloat m_unk0x7c; // 0x7c + MxFloat m_actorTime; // 0x80 + MxFloat m_lastTime; // 0x84 + LegoPathBoundary* m_boundary; // 0x88 + LegoUnknown m_unk0x8c; // 0x8c + MxU32 m_state; // 0xdc + LegoEdge* m_destEdge; // 0xe0 + MxFloat m_unk0xe4; // 0xe4 + undefined m_unk0xe8; // 0xe8 + undefined m_unk0xe9; // 0xe9 + MxBool m_userNavFlag; // 0xea + MxMatrix m_unk0xec; // 0xec + undefined* m_unk0x134; // 0x134 + LegoPathController* m_controller; // 0x138 + MxFloat m_unk0x13c; // 0x13c + MxFloat m_unk0x140; // 0x140 + MxFloat m_unk0x144; // 0x144 + MxU8 m_unk0x148; // 0x148 + MxS32 m_unk0x14c; // 0x14c + MxFloat m_unk0x150; // 0x150 +}; + +#endif // LEGOPATHACTOR_H diff --git a/LEGO1/lego/legoomni/include/legopathboundary.h b/LEGO1/lego/legoomni/include/legopathboundary.h new file mode 100644 index 00000000..ba548d4f --- /dev/null +++ b/LEGO1/lego/legoomni/include/legopathboundary.h @@ -0,0 +1,129 @@ +#ifndef LEGOPATHBOUNDARY_H +#define LEGOPATHBOUNDARY_H + +#include "geom/legowegedge.h" +#include "legoanimpresenter.h" +#include "legopathactor.h" +#include "mxstl/stlcompat.h" +#include "mxtypes.h" + +struct LegoPathActorSetCompare { + MxU32 operator()(const LegoPathActor* p_lhs, const LegoPathActor* p_rhs) const + { + return (MxS32) p_lhs < (MxS32) p_rhs; + } +}; + +struct LegoAnimPresenterSetCompare { + MxBool operator()(const LegoAnimPresenter* p_lhs, const LegoAnimPresenter* p_rhs) const + { + return (MxS32) p_lhs < (MxS32) p_rhs; + } +}; + +typedef set LegoPathActorSet; +typedef set LegoAnimPresenterSet; + +// VTABLE: LEGO1 0x100d8618 +// SIZE 0x74 +class LegoPathBoundary : public LegoWEGEdge { +public: + LegoPathBoundary(); + ~LegoPathBoundary() override; + + MxResult AddActor(LegoPathActor* p_actor); + MxResult RemoveActor(LegoPathActor* p_actor); + void FUN_100575b0(Vector3& p_point1, Vector3& p_point2, LegoPathActor* p_actor); + MxU32 Intersect(float p_scale, Vector3& p_point1, Vector3& p_point2, Vector3& p_point3, LegoEdge*& p_edge); + MxU32 FUN_10057fe0(LegoAnimPresenter* p_presenter); + MxU32 FUN_100586e0(LegoAnimPresenter* p_presenter); + + inline LegoPathActorSet& GetActors() { return m_actors; } + inline LegoAnimPresenterSet& GetPresenters() { return m_presenters; } + + // SYNTHETIC: LEGO1 0x10047a80 + // LegoPathBoundary::`vector deleting destructor' + +private: + LegoPathActorSet m_actors; // 0x54 + LegoAnimPresenterSet m_presenters; // 0x64 +}; + +// clang-format off +// TEMPLATE: LEGO1 0x1002bee0 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::~_Tree >::_Kfn,LegoPathActorSetCompare,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x1002bff0 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::erase + +// TEMPLATE: LEGO1 0x1002c440 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::find + +// TEMPLATE: LEGO1 0x1002c4c0 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Copy + +// TEMPLATE: LEGO1 0x1002c630 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Erase + +// TEMPLATE: LEGO1 0x1002c670 +// set >::~set > + +// TEMPLATE: LEGO1 0x1002c6c0 +// Set::~Set + +// TEMPLATE: LEGO1 0x1002eb10 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Init + +// TEMPLATE: LEGO1 0x1002ebc0 +// _Tree >::_Kfn,LegoAnimPresenterSetCompare,allocator >::_Min + +// TEMPLATE: LEGO1 0x10045d80 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x10045dd0 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Insert + +// TEMPLATE: LEGO1 0x10046310 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::insert + +// TEMPLATE: LEGO1 0x10046580 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Lrotate + +// TEMPLATE: LEGO1 0x100465e0 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Rrotate + +// TEMPLATE: LEGO1 0x1004a7a0 +// _Construct + +// TEMPLATE: LEGO1 0x10056c20 +// _Tree >::_Kfn,LegoAnimPresenterSetCompare,allocator >::~_Tree >::_Kfn,LegoAnimPresenterSetCompare,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x10056d30 +// _Tree >::_Kfn,LegoAnimPresenterSetCompare,allocator >::erase + +// TEMPLATE: LEGO1 0x10057180 +// _Tree >::_Kfn,LegoAnimPresenterSetCompare,allocator >::_Erase + +// TEMPLATE: LEGO1 0x100571c0 +// set >::~set > + +// TEMPLATE: LEGO1 0x10057210 +// Set::~Set + +// TEMPLATE: LEGO1 0x100573e0 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::begin + +// GLOBAL: LEGO1 0x100f11a4 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Nil + +// GLOBAL: LEGO1 0x100f3200 +// _Tree >::_Kfn,LegoAnimPresenterSetCompare,allocator >::_Nil +// clang-format on + +#endif // LEGOPATHBOUNDARY_H diff --git a/LEGO1/lego/legoomni/include/legopathcontroller.h b/LEGO1/lego/legoomni/include/legopathcontroller.h new file mode 100644 index 00000000..46c4935c --- /dev/null +++ b/LEGO1/lego/legoomni/include/legopathcontroller.h @@ -0,0 +1,187 @@ +#ifndef LEGOPATHCONTROLLER_H +#define LEGOPATHCONTROLLER_H + +#include "decomp.h" +#include "geom/legounkown100db7f4.h" +#include "legopathactor.h" +#include "legopathboundary.h" +#include "mxcore.h" +#include "mxstl/stlcompat.h" + +class LegoAnimPresenter; +struct LegoPathStruct; +class LegoWorld; +class MxAtomId; +class Vector3; + +// VTABLE: LEGO1 0x100d7da8 +// SIZE 0x40 +struct LegoPathCtrlEdge : public LegoUnknown100db7f4 {}; + +struct LegoPathCtrlEdgeCompare { + MxU32 operator()(const LegoPathCtrlEdge* p_lhs, const LegoPathCtrlEdge* p_rhs) const + { + return (MxS32) p_lhs < (MxS32) p_rhs; + } +}; + +typedef set LegoPathCtrlEdgeSet; + +// VTABLE: LEGO1 0x100d7d60 +// SIZE 0x40 +class LegoPathController : public MxCore { +public: + // SIZE 0x08 + struct CtrlBoundary { + // FUNCTION: LEGO1 0x10046dc0 + CtrlBoundary() + { + m_controller = NULL; + m_boundary = NULL; + } + + LegoPathController* m_controller; // 0x00 + LegoPathBoundary* m_boundary; // 0x04 + }; + + // SIZE 0x08 + struct CtrlEdge { + // FUNCTION: LEGO1 0x10046dd0 + CtrlEdge() + { + m_controller = NULL; + m_edge = NULL; + } + + LegoPathController* m_controller; // 0x00 + LegoEdge* m_edge; // 0x04 + }; + + LegoPathController(); + ~LegoPathController() override { Destroy(); } + + MxResult Tickle() override; // vtable+08 + + // FUNCTION: LEGO1 0x10045110 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f11b8 + return "LegoPathController"; + } + + // FUNCTION: LEGO1 0x10045120 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoPathController::ClassName()) || MxCore::IsA(p_name); + } + + // SYNTHETIC: LEGO1 0x10045740 + // LegoPathController::`scalar deleting destructor' + + virtual MxResult Create(MxU8* p_data, const Vector3& p_location, const MxAtomId& p_trigger); // vtable+0x14 + virtual void Destroy(); // vtable+0x18 + + MxResult FUN_10045c20( + LegoPathActor* p_actor, + const char* p_name, + MxS32 p_src, + float p_srcScale, + MxS32 p_dest, + float p_destScale + ); + MxResult FUN_10046050( + LegoPathActor* p_actor, + LegoAnimPresenter* p_presenter, + Vector3& p_position, + Vector3& p_direction + ); + MxResult AddActor(LegoPathActor* p_actor); + MxResult RemoveActor(LegoPathActor* p_actor); + void FUN_100468f0(LegoAnimPresenter* p_presenter); + void FUN_10046930(LegoAnimPresenter* p_presenter); + MxResult FUN_10046b30(LegoPathBoundary*& p_boundaries, MxS32& p_numL); + LegoPathBoundary* GetPathBoundary(const char* p_name); + void Enable(MxBool p_enable); + void FUN_10046bb0(LegoWorld* p_world); + + static MxResult Init(); + static MxResult Reset(); + +private: + void FUN_10046970(); + MxResult Read(LegoStorage* p_storage); + MxResult ReadStructs(LegoStorage* p_storage); + MxResult ReadEdges(LegoStorage* p_storage); + MxResult ReadBoundaries(LegoStorage* p_storage); + static MxResult ReadVector(LegoStorage* p_storage, Mx3DPointFloat& p_vec); + static MxResult ReadVector(LegoStorage* p_storage, Mx4DPointFloat& p_vec); + + LegoPathBoundary* m_boundaries; // 0x08 + LegoPathCtrlEdge* m_edges; // 0x0c + Mx3DPointFloat* m_unk0x10; // 0x10 + LegoPathStruct* m_structs; // 0x14 + MxU16 m_numL; // 0x18 + MxU16 m_numE; // 0x1a + MxU16 m_numN; // 0x1c + MxU16 m_numT; // 0x1e + LegoPathCtrlEdgeSet m_pfsE; // 0x20 + LegoPathActorSet m_actors; // 0x30 +}; + +// clang-format off +// TEMPLATE: LEGO1 0x1001fd70 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Lbound + +// TEMPLATE: LEGO1 0x1002c4a0 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Buynode + +// TEMPLATE: LEGO1 0x100451a0 +// _Tree >::_Kfn,LegoPathCtrlEdgeCompare,allocator >::~_Tree::~Set + +// TEMPLATE: LEGO1 0x10045830 +// set >::~set > + +// TEMPLATE: LEGO1 0x10046640 +// _Tree >::_Kfn,LegoAnimPresenterSetCompare,allocator >::find + +// TEMPLATE: LEGO1 0x100468c0 +// _Tree >::_Kfn,LegoPathActorSetCompare,allocator >::_Ubound + +// TEMPLATE: LEGO1 0x10047550 +// _Tree >::_Kfn,LegoPathCtrlEdgeCompare,allocator >::_Insert + +// TEMPLATE: LEGO1 0x100474e0 +// _Tree >::_Kfn,LegoPathCtrlEdgeCompare,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x10047530 +// _Tree >::_Kfn,LegoPathCtrlEdgeCompare,allocator >::_Buynode + +// TEMPLATE: LEGO1 0x100477d0 +// _Tree >::_Kfn,LegoPathCtrlEdgeCompare,allocator >::_Lrotate + +// TEMPLATE: LEGO1 0x10047830 +// _Tree >::_Kfn,LegoPathCtrlEdgeCompare,allocator >::_Rrotate + +// SYNTHETIC: LEGO1 0x10047940 +// LegoPathCtrlEdge::`vector deleting destructor' + +// SYNTHETIC: LEGO1 0x100479d0 +// LegoPathCtrlEdge::LegoPathCtrlEdge + +// SYNTHETIC: LEGO1 0x10047a30 +// LegoPathCtrlEdge::~LegoPathCtrlEdge + +// SYNTHETIC: LEGO1 0x10047ae0 +// LegoUnknown100db7f4::~LegoUnknown100db7f4 + +// TEMPLATE: LEGO1 0x1004a780 +// _Construct + +// GLOBAL: LEGO1 0x100f4360 +// _Tree >::_Kfn,LegoPathCtrlEdgeCompare,allocator >::_Nil +// clang-format on + +#endif // LEGOPATHCONTROLLER_H diff --git a/LEGO1/lego/legoomni/include/legopathcontrollerlist.h b/LEGO1/lego/legoomni/include/legopathcontrollerlist.h new file mode 100644 index 00000000..f3728b06 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legopathcontrollerlist.h @@ -0,0 +1,97 @@ +#ifndef LEGOPATHCONTROLLERLIST_H +#define LEGOPATHCONTROLLERLIST_H + +#include "legopathcontroller.h" +#include "mxlist.h" +#include "mxtypes.h" + +// VTABLE: LEGO1 0x100d6380 +// class MxCollection + +// VTABLE: LEGO1 0x100d6398 +// class MxList + +// VTABLE: LEGO1 0x100d6320 +// class MxPtrList + +// VTABLE: LEGO1 0x100d6338 +// SIZE 0x18 +class LegoPathControllerList : public MxPtrList { +public: + LegoPathControllerList(MxBool p_ownership = FALSE) : MxPtrList(p_ownership) {} + + // FUNCTION: LEGO1 0x1001d210 + MxS8 Compare(LegoPathController* p_a, LegoPathController* p_b) override + { + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; + } // vtable+0x14 +}; + +// VTABLE: LEGO1 0x100d6578 +// class MxListCursor + +// VTABLE: LEGO1 0x100d6548 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d6560 +// SIZE 0x10 +class LegoPathControllerListCursor : public MxPtrListCursor { +public: + LegoPathControllerListCursor(LegoPathControllerList* p_list) : MxPtrListCursor(p_list) {} +}; + +// TEMPLATE: LEGO1 0x1001d230 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1001d240 +// MxList::MxList + +// TEMPLATE: LEGO1 0x1001d2d0 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1001d320 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1001d330 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x1001d3c0 +// MxPtrList::Destroy + +// SYNTHETIC: LEGO1 0x1001d3d0 +// LegoPathControllerList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001d440 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x1001d490 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001d500 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001d5b0 +// MxPtrList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001d620 +// LegoPathControllerList::~LegoPathControllerList + +// SYNTHETIC: LEGO1 0x1001f830 +// LegoPathControllerListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001f8a0 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x1001f8f0 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001f960 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001f9d0 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x1001fa20 +// LegoPathControllerListCursor::~LegoPathControllerListCursor + +#endif // LEGOPATHCONTROLLERLIST_H diff --git a/LEGO1/lego/legoomni/include/legopathpresenter.h b/LEGO1/lego/legoomni/include/legopathpresenter.h new file mode 100644 index 00000000..9e3f0f0f --- /dev/null +++ b/LEGO1/lego/legoomni/include/legopathpresenter.h @@ -0,0 +1,46 @@ +#ifndef LEGOPATHPRESENTER_H +#define LEGOPATHPRESENTER_H + +#include "mxatom.h" +#include "mxmediapresenter.h" + +// VTABLE: LEGO1 0x100d7c10 +// SIZE 0x54 +class LegoPathPresenter : public MxMediaPresenter { +public: + LegoPathPresenter(); + ~LegoPathPresenter() override; + + // FUNCTION: LEGO1 0x100449a0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0690 + return "LegoPathPresenter"; + } + + // FUNCTION: LEGO1 0x100449b0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoPathPresenter::ClassName()) || MxMediaPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StreamingTickle() override; // vtable+0x20 + void RepeatingTickle() override; // vtable+0x24 + void ParseExtra() override; // vtable+0x30 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + + // SYNTHETIC: LEGO1 0x10044a90 + // LegoPathPresenter::`scalar deleting destructor' + +private: + void Init(); + +protected: + void Destroy(MxBool p_fromDestructor); + + MxAtomId m_trigger; // 0x50 +}; + +#endif // LEGOPATHPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legopathstruct.h b/LEGO1/lego/legoomni/include/legopathstruct.h new file mode 100644 index 00000000..fd752050 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legopathstruct.h @@ -0,0 +1,53 @@ +#ifndef LEGOPATHSTRUCT_H +#define LEGOPATHSTRUCT_H + +#include "decomp.h" +#include "mxatom.h" +#include "mxtypes.h" + +class LegoWorld; + +// VTABLE: LEGO1 0x100d7d9c +// SIZE 0x0c +struct LegoPathStructBase { +public: + LegoPathStructBase() : m_name(NULL), m_unk0x08(0) {} + + // FUNCTION: LEGO1 0x10047420 + virtual ~LegoPathStructBase() + { + if (m_name != NULL) { + delete[] m_name; + } + } + + char* m_name; // 0x04 + undefined4 m_unk0x08; // 0x08 +}; + +// VTABLE: LEGO1 0x100d7da0 +// SIZE 0x14 +struct LegoPathStruct : public LegoPathStructBase { +public: + // FUNCTION: LEGO1 0x100473a0 + LegoPathStruct() : m_world(NULL) {} + + // FUNCTION: LEGO1 0x10047470 + ~LegoPathStruct() override {} + + void VTable0x04(undefined4, undefined4, undefined4); // vtable+0x04 + + inline void SetWorld(LegoWorld* p_world) { m_world = p_world; } + inline void SetAtomId(const MxAtomId& p_atomId) { m_atomId = p_atomId; } + + LegoWorld* m_world; // 0x0c + MxAtomId m_atomId; // 0x10 +}; + +// SYNTHETIC: LEGO1 0x10047440 +// LegoPathStructBase::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10047890 +// LegoPathStruct::`vector deleting destructor' + +#endif // LEGOPATHSTRUCT_H diff --git a/LEGO1/lego/legoomni/include/legophoneme.h b/LEGO1/lego/legoomni/include/legophoneme.h new file mode 100644 index 00000000..76485840 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legophoneme.h @@ -0,0 +1,41 @@ +#ifndef LEGOPHONEME_H +#define LEGOPHONEME_H + +#include "decomp.h" +#include "mxstring.h" + +class LegoTextureInfo; + +// VTABLE: LEGO1 0x100d7c88 +// SIZE 0x20 +class LegoPhoneme { +public: + LegoPhoneme(const char* p_name, undefined4 p_unk0x14) + { + m_name = p_name; + m_name.ToUpperCase(); + Init(); + m_unk0x14 = p_unk0x14; + } + ~LegoPhoneme(); + + virtual undefined4 VTable0x00(); // vtable+0x00 + virtual void VTable0x04(undefined4 p_unk0x14); // vtable+0x04 + virtual LegoTextureInfo* VTable0x08(); // vtable+0x08 + virtual void VTable0x0c(LegoTextureInfo* p_unk0x18); // vtable+0x0c + virtual LegoTextureInfo* VTable0x10(); // vtable+0x10 + virtual void VTable0x14(LegoTextureInfo* p_unk0x1c); // vtable+0x14 + virtual void VTable0x18(); // vtable+0x18 + virtual void Init(); // vtable+0x1c + virtual void VTable0x20(undefined4); // vtable+0x20 + + inline MxString& GetName() { return m_name; } + +private: + MxString m_name; // 0x04 + undefined4 m_unk0x14; // 0x14 + LegoTextureInfo* m_unk0x18; // 0x18 + LegoTextureInfo* m_unk0x1c; // 0x1c +}; + +#endif // LEGOPHONEME_H diff --git a/LEGO1/lego/legoomni/include/legophonemelist.h b/LEGO1/lego/legoomni/include/legophonemelist.h new file mode 100644 index 00000000..37e4b8b6 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legophonemelist.h @@ -0,0 +1,77 @@ +#ifndef LEGOPHONEMELIST_H +#define LEGOPHONEMELIST_H + +#include "decomp.h" +#include "legophoneme.h" +#include "mxlist.h" + +// VTABLE: LEGO1 0x100d9cd0 +// class MxCollection + +// VTABLE: LEGO1 0x100d9ce8 +// class MxList + +// VTABLE: LEGO1 0x100d9d00 +// VTABLE: BETA10 0x101bef58 +// SIZE 0x18 +class LegoPhonemeList : public MxList { +public: + LegoPhonemeList() { SetDestroy(Destroy); } + + // FUNCTION: LEGO1 0x1007b210 + // FUNCTION: BETA10 0x100d8340 + MxS8 Compare(LegoPhoneme* p_a, LegoPhoneme* p_b) override + { + MxString a(p_a->GetName()); + MxString b(p_b->GetName()); + return a.Equal(b) ? 0 : p_a < p_b ? -1 : 1; + } // vtable+0x14 + + // FUNCTION: LEGO1 0x1007b2e0 + static void Destroy(LegoPhoneme* p_element) { delete p_element; } +}; + +// VTABLE: LEGO1 0x100d80c8 +// class MxListCursor + +// VTABLE: LEGO1 0x100d80e0 +// SIZE 0x10 +class LegoPhonemeListCursor : public MxListCursor { +public: + LegoPhonemeListCursor(LegoPhonemeList* p_list) : MxListCursor(p_list) {} +}; + +// TEMPLATE: LEGO1 0x1004e680 +// LegoPhonemeListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1004e6f0 +// MxListCursor::~MxListCursor + +// TEMPLATE: LEGO1 0x1004e740 +// MxListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1004e7b0 +// LegoPhonemeListCursor::~LegoPhonemeListCursor + +// TEMPLATE: LEGO1 0x1007b300 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1007b310 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1007b360 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1007b370 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x1007b400 +// LegoPhonemeList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1007b470 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1007b4e0 +// MxList::`scalar deleting destructor' + +#endif // LEGOPHONEMELIST_H diff --git a/LEGO1/lego/legoomni/include/legophonemepresenter.h b/LEGO1/lego/legoomni/include/legophonemepresenter.h new file mode 100644 index 00000000..0f4a6a5d --- /dev/null +++ b/LEGO1/lego/legoomni/include/legophonemepresenter.h @@ -0,0 +1,46 @@ +#ifndef LEGOPHONEMEPRESENTER_H +#define LEGOPHONEMEPRESENTER_H + +#include "decomp.h" +#include "mxflcpresenter.h" +#include "mxstring.h" +#include "mxtypes.h" + +class LegoTextureInfo; + +// VTABLE: LEGO1 0x100d8040 +// SIZE 0x88 +class LegoPhonemePresenter : public MxFlcPresenter { +public: + LegoPhonemePresenter(); + ~LegoPhonemePresenter() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x1004e310 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f064c + return "LegoPhonemePresenter"; + } + + void StartingTickle() override; // vtable+0x1c + void EndAction() override; // vtable+0x40 + void LoadFrame(MxStreamChunk* p_chunk) override; // vtable+0x68 + void PutFrame() override; // vtable+0x6c + + // SYNTHETIC: LEGO1 0x1004e320 + // LegoPhonemePresenter::`scalar deleting destructor' + +private: + void Init(); + + MxS32 m_rectCount; // 0x68 + LegoTextureInfo* m_textureInfo; // 0x6c + MxBool m_unk0x70; // 0x70 + MxString m_roiName; // 0x74 + MxBool m_unk0x84; // 0x84 +}; + +// TEMPLATE: LEGO1 0x1004eb20 +// MxListEntry::MxListEntry + +#endif // LEGOPHONEMEPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legoplantmanager.h b/LEGO1/lego/legoomni/include/legoplantmanager.h new file mode 100644 index 00000000..e2eccd80 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoplantmanager.h @@ -0,0 +1,48 @@ +#ifndef LEGOPLANTMANAGER_H +#define LEGOPLANTMANAGER_H + +#include "decomp.h" +#include "mxcore.h" + +class LegoEntity; +class LegoROI; +class LegoStorage; + +// VTABLE: LEGO1 0x100d6758 +// SIZE 0x2c +class LegoPlantManager : public MxCore { +public: + LegoPlantManager(); + ~LegoPlantManager() override; // vtable+0x00 + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x10026290 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f318c + return "LegoPlantManager"; + } + + void Init(); + void FUN_10026360(MxS32 p_scriptIndex); + void FUN_100263a0(undefined4 p_und); + void Write(LegoStorage* p_storage); + MxResult Read(LegoStorage* p_storage); + MxBool FUN_100269e0(LegoEntity* p_entity); + MxU32 FUN_10026ba0(LegoEntity*, MxBool); + void FUN_10026c50(LegoEntity* p_entity); + void FUN_10027120(); + + static void SetCustomizeAnimFile(const char* p_value); + + // SYNTHETIC: LEGO1 0x100262a0 + // LegoPlantManager::`scalar deleting destructor' + +private: + static char* g_customizeAnimFile; + + undefined m_unk0x08[0x24]; // 0x08 +}; + +#endif // LEGOPLANTMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legopointofviewcontroller.h b/LEGO1/lego/legoomni/include/legopointofviewcontroller.h new file mode 100644 index 00000000..89a9e5e5 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legopointofviewcontroller.h @@ -0,0 +1,107 @@ +#ifndef LEGOPOINTOFVIEWCONTROLLER_H +#define LEGOPOINTOFVIEWCONTROLLER_H + +#include "decomp.h" +#include "mxcore.h" +#include "mxpoint32.h" + +#include + +class Lego3DView; +class LegoEntity; +class LegoNavController; + +////////////////////////////////////////////////////////////////////////////// +// +// LegoMouseController + +// VTABLE: LEGO1 0x100d8dd8 +// SIZE 0x20 +class LegoMouseController : public MxCore { +public: + LegoMouseController(); + ~LegoMouseController() override; + + virtual void LeftDown(int, int); // vtable+0x14 + virtual void LeftDrag(int, int); // vtable+0x18 + virtual void LeftUp(int, int); // vtable+0x1c + virtual void RightDown(int, int); // vtable+0x20 + virtual void RightDrag(int, int); // vtable+0x24 + virtual void RightUp(int, int); // vtable+0x28 + + BOOL GetIsButtonDown() { return m_isButtonDown; } + MxDouble GetButtonX() { return m_buttonX; } + MxDouble GetButtonY() { return m_buttonY; } + +private: + BOOL m_isButtonDown; // 0x08 + undefined4 m_unk0x0c; // 0x0c + MxDouble m_buttonX; // 0x10 + MxDouble m_buttonY; // 0x18 +}; + +// SYNTHETIC: LEGO1 0x100655b0 +// LegoMouseController::`scalar deleting destructor' + +// VTABLE: LEGO1 0x100d8e08 +// SIZE 0x38 +class LegoPointOfViewController : public LegoMouseController { +public: + LegoPointOfViewController(); + ~LegoPointOfViewController() override; + + MxResult Tickle() override; // vtable+0x08 + void LeftDown(int p_x, int p_y) override; // vtable+0x0c + void LeftDrag(int p_x, int p_y) override; // vtable+0x10 + + // FUNCTION: LEGO1 0x10011e40 + void LeftUp(int p_x, int p_y) override + { + LegoMouseController::LeftUp(p_x, p_y); + AffectPointOfView(); + } + // vtable+0x14 + + // FUNCTION: LEGO1 0x10011e60 + void RightDown(int p_x, int p_y) override + { + LegoMouseController::RightDown(p_x, p_y); + AffectPointOfView(); + } + // vtable+0x20 + + // FUNCTION: LEGO1 0x10011e80 + void RightDrag(int p_x, int p_y) override + { + LegoMouseController::RightDrag(p_x, p_y); + AffectPointOfView(); + } + // vtable+0x24 + + // FUNCTION: LEGO1 0x10011ea0 + void RightUp(int p_x, int p_y) override + { + LegoMouseController::RightUp(p_x, p_y); + AffectPointOfView(); + } // vtable+0x28 + virtual void SetEntity(LegoEntity* p_entity); // vtable+0x2c + + MxResult Create(Lego3DView* p_lego3DView); + void OnViewSize(int p_width, int p_height); + + inline LegoEntity* GetEntity() { return m_entity; } + inline LegoNavController* GetNavController() { return m_nav; } + +protected: + void AffectPointOfView(); + + Lego3DView* m_lego3DView; // 0x20 + LegoEntity* m_entity; // 0x24 + MxDouble m_entityOffsetUp; // 0x28 + LegoNavController* m_nav; // 0x30 +}; + +// SYNTHETIC: LEGO1 0x10065750 +// LegoPointOfViewController::`scalar deleting destructor' + +#endif /* LEGOPOINTOFVIEWCONTROLLER_H */ diff --git a/LEGO1/lego/legoomni/include/legorace.h b/LEGO1/lego/legoomni/include/legorace.h new file mode 100644 index 00000000..c8b02f2e --- /dev/null +++ b/LEGO1/lego/legoomni/include/legorace.h @@ -0,0 +1,67 @@ +#ifndef LEGORACE_H +#define LEGORACE_H + +#include "decomp.h" +#include "legoworld.h" +#include "mxrect32.h" +#include "mxtypes.h" + +// VTABLE: LEGO1 0x100d5db0 +// SIZE 0x144 +class LegoRace : public LegoWorld { +public: + LegoRace(); + ~LegoRace() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10015ba0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f07c4 + return "LegoRace"; + } + + // FUNCTION: LEGO1 0x10015bb0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoRace::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + MxBool VTable0x5c() override; // vtable+0x5c + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + virtual undefined4 VTable0x6c(undefined4) = 0; // vtable+0x6c + virtual undefined4 VTable0x70(undefined4); // vtable+0x70 + virtual undefined4 VTable0x74(undefined4); // vtable+0x74 + virtual undefined4 VTable0x78(undefined4); // vtable+0x78 + virtual void VTable0x7c(undefined4, undefined4); // vtable+0x7c + + // SYNTHETIC: LEGO1 0x10015cc0 + // LegoRace::`scalar deleting destructor' + +private: + undefined4 m_unk0xf8; // 0xf8 + undefined4 m_unk0xfc; // 0xfc + undefined4 m_unk0x100; // 0x100 + undefined4 m_unk0x104; // 0x104 + undefined4 m_unk0x108; // 0x108 + undefined4 m_unk0x10c; // 0x10c + undefined4 m_unk0x110; // 0x110 + undefined4 m_unk0x114; // 0x114 + undefined4 m_unk0x118; // 0x118 + undefined4 m_unk0x11c; // 0x11c + undefined4 m_unk0x120; // 0x120 + undefined4 m_unk0x124; // 0x124 + undefined4 m_unk0x128; // 0x128 + undefined4 m_unk0x12c; // 0x12c + +protected: + MxRect32 m_unk0x130; // 0x130 + +private: + undefined4 m_unk0x140; // 0x140 +}; + +#endif // LEGORACE_H diff --git a/LEGO1/lego/legoomni/include/legoraceactor.h b/LEGO1/lego/legoomni/include/legoraceactor.h new file mode 100644 index 00000000..92f1e8c7 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoraceactor.h @@ -0,0 +1,48 @@ +#ifndef LEGORACEACTOR_H +#define LEGORACEACTOR_H + +#include "legoanimactor.h" + +class Matrix4; + +/* + VTABLE: LEGO1 0x100d5b78 LegoAnimActor + VTABLE: LEGO1 0x100d5b88 LegoPathActor + VTABLE: LEGO1 0x100d5c54 LegoRaceActor +*/ +// SIZE 0x180 +class LegoRaceActor : public virtual LegoAnimActor { +public: + LegoRaceActor(); + + // FUNCTION: LEGO1 0x10014af0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0bf4 + return "LegoRaceActor"; + } + + // FUNCTION: LEGO1 0x10014b10 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoRaceActor::ClassName()) || LegoAnimActor::IsA(p_name); + } + + void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 + MxS32 VTable0x68(Vector3&, Vector3&, Vector3&) override; // vtable+0x68 + void VTable0x70(float p_float) override; // vtable+0x70 + void VTable0x74(Matrix4& p_transform) override; // vtable+0x74 + MxU32 VTable0x90(float, Matrix4&) override; // vtable+0x90 + MxResult VTable0x94(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 + + // FUNCTION: LEGO1 0x10014aa0 + virtual MxResult FUN_10014aa0() { return SUCCESS; } + + // SYNTHETIC: LEGO1 0x10014ab0 + // LegoRaceActor::`scalar deleting destructor' + +private: + undefined4 m_unk0x08; // 0x08 +}; + +#endif // LEGORACEACTOR_H diff --git a/LEGO1/lego/legoomni/include/legoracecar.h b/LEGO1/lego/legoomni/include/legoracecar.h new file mode 100644 index 00000000..d090b686 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoracecar.h @@ -0,0 +1,65 @@ +#ifndef LEGORACECAR_H +#define LEGORACECAR_H + +#include "legocarraceactor.h" +#include "legoracemap.h" + +/* + VTABLE: LEGO1 0x100d58a0 LegoRaceActor + VTABLE: LEGO1 0x100d58a8 LegoAnimActor + VTABLE: LEGO1 0x100d58b8 LegoPathActor + VTABLE: LEGO1 0x100d5894 LegoRaceMap + VTABLE: LEGO1 0x100d5898 LegoCarRaceActor +*/ +// SIZE 0x200 +class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { +public: + LegoRaceCar(); + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x10014290 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0548 + return "LegoRaceCar"; + } + + // FUNCTION: LEGO1 0x100142b0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoCarRaceActor::ClassName()) || LegoCarRaceActor::IsA(p_name); + } + + void ParseAction(char*) override; // vtable+0x20 + void SetWorldSpeed(MxFloat p_worldSpeed) override; // vtable+0x30 + MxU32 VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 + ) override; // vtable+0x6c + void VTable0x70(float p_float) override; // vtable+0x70 + MxResult VTable0x94(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94 + void VTable0x98() override; // vtable+0x98 + MxResult WaitForAnimation() override; // vtable+0x9c + + virtual void FUN_10012ea0(float p_worldSpeed); + virtual void FUN_10012ff0(float); + virtual MxBool FUN_10013130(float); + + // SYNTHETIC: LEGO1 0x10014230 + // LegoRaceCar::`scalar deleting destructor' + +private: + undefined m_unk0x54; // 0x54 + undefined4 m_unk0x58; // 0x58 + Mx3DPointFloat m_unk0x5c; // 0x5c + undefined4 m_unk0x70; // 0x70 + undefined4 m_unk0x74; // 0x74 + undefined4 m_unk0x78; // 0x78 + undefined4 m_unk0x7c; // 0x7c +}; + +#endif // LEGORACECAR_H diff --git a/LEGO1/lego/legoomni/include/legoracemap.h b/LEGO1/lego/legoomni/include/legoracemap.h new file mode 100644 index 00000000..11d3d69d --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoracemap.h @@ -0,0 +1,36 @@ +#ifndef LEGORACEMAP_H +#define LEGORACEMAP_H + +#include "legoraceactor.h" + +/* + VTABLE: LEGO1 0x100d8858 LegoRaceActor + VTABLE: LEGO1 0x100d8860 LegoAnimActor + VTABLE: LEGO1 0x100d8870 LegoPathActor + VTABLE: LEGO1 0x100d893c LegoRaceMap +*/ +// SIZE 0x1b4 +class LegoRaceMap : public virtual LegoRaceActor { +public: + LegoRaceMap(); + + virtual void FUN_1005d4b0(); + + // SYNTHETIC: LEGO1 0x1005d5c0 + // LegoRaceMap::`scalar deleting destructor' + +private: + MxBool m_unk0x08; // 0x08 + void* m_unk0x0c; // 0x0c + undefined4 m_unk0x10; // 0x10 + float m_unk0x14; // 0x14 + float m_unk0x18; // 0x18 + float m_unk0x1c; // 0x1c + float m_unk0x20; // 0x20 + float m_unk0x24; // 0x24 + float m_unk0x28; // 0x28 + float m_unk0x2c; // 0x2c + undefined4 m_unk0x30; // 0x30 +}; + +#endif // LEGORACEMAP_H diff --git a/LEGO1/lego/legoomni/include/legoroilist.h b/LEGO1/lego/legoomni/include/legoroilist.h new file mode 100644 index 00000000..ee95215a --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoroilist.h @@ -0,0 +1,88 @@ +#ifndef LEGOROILIST_H +#define LEGOROILIST_H + +#include "mxlist.h" +#include "mxtypes.h" +#include "roi/legoroi.h" + +// VTABLE: LEGO1 0x100d8c30 +// class MxCollection + +// VTABLE: LEGO1 0x100d8c48 +// class MxList + +// VTABLE: LEGO1 0x100d8c60 +// class MxPtrList + +// VTABLE: LEGO1 0x100d8c78 +// SIZE 0x18 +class LegoROIList : public MxPtrList { +public: + LegoROIList(MxBool p_ownership = FALSE) : MxPtrList(p_ownership) {} + + // FUNCTION: LEGO1 0x1005f360 + MxS8 Compare(LegoROI* p_a, LegoROI* p_b) override { return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; } // vtable+0x14 + + // SYNTHETIC: LEGO1 0x1005f480 + // LegoROIList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100d8d68 +// class MxListCursor + +// VTABLE: LEGO1 0x100d8d38 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d8d50 +// SIZE 0x10 +class LegoROIListCursor : public MxPtrListCursor { +public: + LegoROIListCursor(LegoROIList* p_list) : MxPtrListCursor(p_list) {} +}; + +// TEMPLATE: LEGO1 0x1005f380 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1005f390 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1005f3e0 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1005f3f0 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x1005f4f0 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x1005f540 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1005f5b0 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1005f660 +// MxPtrList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10063540 +// LegoROIListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x100635b0 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x10063600 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10063670 +// MxPtrListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x100636e0 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x10063730 +// LegoROIListCursor::~LegoROIListCursor + +// TEMPLATE: LEGO1 0x1006ea00 +// MxListEntry::MxListEntry + +#endif // LEGOROILIST_H diff --git a/LEGO1/lego/legoomni/include/legoroimaplist.h b/LEGO1/lego/legoomni/include/legoroimaplist.h new file mode 100644 index 00000000..697c2dd8 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoroimaplist.h @@ -0,0 +1,55 @@ +#ifndef LEGOROIMAPLIST_H +#define LEGOROIMAPLIST_H + +#include "mxlist.h" +#include "mxtypes.h" + +class LegoROI; + +// VTABLE: LEGO1 0x100d9218 +// class MxCollection + +// VTABLE: LEGO1 0x100d9230 +// class MxList + +// VTABLE: LEGO1 0x100d9248 +// class MxPtrList + +// VTABLE: LEGO1 0x100d9260 +// SIZE 0x18 +class LegoROIMapList : public MxPtrList { +public: + LegoROIMapList() : MxPtrList(TRUE) {} + + // SYNTHETIC: LEGO1 0x1006d360 + // LegoROIMapList::`scalar deleting destructor' +}; + +// TEMPLATE: LEGO1 0x1006d250 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1006d260 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1006d2b0 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1006d2c0 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x1006d3d0 +// MxPtrList::~MxPtrList + +// TEMPLATE: LEGO1 0x1006d350 +// MxPtrList::Destroy + +// SYNTHETIC: LEGO1 0x1006d420 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1006d490 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1006d540 +// MxPtrList::`scalar deleting destructor' + +#endif // LEGOROIMAPLIST_H diff --git a/LEGO1/lego/legoomni/include/legosoundmanager.h b/LEGO1/lego/legoomni/include/legosoundmanager.h new file mode 100644 index 00000000..ad46bf8f --- /dev/null +++ b/LEGO1/lego/legoomni/include/legosoundmanager.h @@ -0,0 +1,37 @@ +#ifndef LEGOSOUNDMANAGER_H +#define LEGOSOUNDMANAGER_H + +#include "mxsoundmanager.h" + +class LegoCacheSoundManager; + +// VTABLE: LEGO1 0x100d6b10 +// SIZE 0x44 +class LegoSoundManager : public MxSoundManager { +public: + LegoSoundManager(); + ~LegoSoundManager() override; + + MxResult Tickle() override; // vtable+0x08 + void Destroy() override; // vtable+0x18 + MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread) override; // vtable+0x30 + + // SYNTHETIC: LEGO1 0x10029920 + // LegoSoundManager::`scalar deleting destructor' + + void FUN_1002a410(const float* p_pos, const float* p_dir, const float* p_up, const float* p_vel); + + inline LegoCacheSoundManager* GetCacheSoundManager() { return m_cacheSoundManager; } + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + + LPDIRECTSOUND3DLISTENER m_listener; // 0x3c + LegoCacheSoundManager* m_cacheSoundManager; // 0x40 +}; + +// GLOBAL: LEGO1 0x100db6d0 +// IID_IDirectSound3DListener + +#endif // LEGOSOUNDMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legostate.h b/LEGO1/lego/legoomni/include/legostate.h new file mode 100644 index 00000000..21ddde85 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legostate.h @@ -0,0 +1,96 @@ +#ifndef LEGOSTATE_H +#define LEGOSTATE_H + +#include "decomp.h" +#include "misc/legostorage.h" +#include "mxcore.h" + +// VTABLE: LEGO1 0x100d46c0 +// SIZE 0x08 +class LegoState : public MxCore { +public: + // FUNCTION: LEGO1 0x10005f40 + ~LegoState() override {} + + // FUNCTION: LEGO1 0x100060d0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f01b8 + return "LegoState"; + } + + // FUNCTION: LEGO1 0x100060e0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoState::ClassName()) || MxCore::IsA(p_name); + } + + // FUNCTION: LEGO1 0x10005f90 + virtual MxBool IsSerializable() { return TRUE; } // vtable+0x14 + + // FUNCTION: LEGO1 0x10005fa0 + virtual MxBool SetFlag() { return FALSE; } // vtable+0x18 + + // FUNCTION: LEGO1 0x10005fb0 + virtual MxResult Serialize(LegoFile* p_legoFile) + { + if (p_legoFile->IsWriteMode()) { + p_legoFile->WriteString(ClassName()); + } + return SUCCESS; + } // vtable+0x1c + + // SYNTHETIC: LEGO1 0x10006160 + // LegoState::`scalar deleting destructor' + + // SIZE 0x0c + class Playlist { + public: + enum Mode { + e_loop, + e_once, + e_random, + e_loopSkipFirst + }; + + // FUNCTION: LEGO1 0x10017c00 + Playlist() + { + m_objectIds = NULL; + m_length = 0; + m_mode = e_loop; + m_nextIndex = 0; + } + + Playlist(MxU32* p_objectIds, MxS16 p_length) + { + m_objectIds = p_objectIds; + m_length = p_length; + m_mode = e_loop; + m_nextIndex = 0; + } + + // FUNCTION: LEGO1 0x10071800 + Playlist& operator=(const Playlist& p_shuffle) + { + m_objectIds = p_shuffle.m_objectIds; + m_length = p_shuffle.m_length; + m_nextIndex = p_shuffle.m_nextIndex; + m_mode = p_shuffle.m_mode; + return *this; + } + + MxU32 Next(); + MxBool Contains(MxU32 p_objectId); + + inline void SetUnknown0x08(MxS16 p_unk0x08) { m_nextIndex = p_unk0x08; } + + private: + MxU32* m_objectIds; // 0x00 + MxS16 m_length; // 0x04 + MxS16 m_mode; // 0x06 + MxS16 m_nextIndex; // 0x08 + }; +}; + +#endif // LEGOSTATE_H diff --git a/LEGO1/lego/legoomni/include/legotextureinfo.h b/LEGO1/lego/legoomni/include/legotextureinfo.h new file mode 100644 index 00000000..e7cd894b --- /dev/null +++ b/LEGO1/lego/legoomni/include/legotextureinfo.h @@ -0,0 +1,34 @@ +#ifndef LEGOTEXTUREINFO_H +#define LEGOTEXTUREINFO_H + +#include "misc/legotypes.h" +#include "tgl/tgl.h" + +#include +#include + +class LegoTexture; + +// SIZE 0x10 +class LegoTextureInfo { +public: + LegoTextureInfo(); + ~LegoTextureInfo(); + + static LegoTextureInfo* Create(const char* p_name, LegoTexture* p_texture); + static BOOL SetGroupTexture(Tgl::Mesh* pMesh, LegoTextureInfo* p_textureInfo); + static BOOL GetGroupTexture(Tgl::Mesh* pMesh, LegoTextureInfo*& p_textureInfo); + + LegoResult FUN_10066010(LegoU8* p_bits); + + // private: + char* m_name; // 0x00 + LPDIRECTDRAWSURFACE m_surface; // 0x04 + LPDIRECTDRAWPALETTE m_palette; // 0x08 + LPDIRECT3DRMTEXTURE2 m_texture; // 0x0c +}; + +// GLOBAL: LEGO1 0x100db6f0 +// IID_IDirect3DRMTexture2 + +#endif // LEGOTEXTUREINFO_H diff --git a/LEGO1/lego/legoomni/include/legotexturepresenter.h b/LEGO1/lego/legoomni/include/legotexturepresenter.h new file mode 100644 index 00000000..49947295 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legotexturepresenter.h @@ -0,0 +1,41 @@ +#ifndef LEGOTEXTUREPRESENTER_H +#define LEGOTEXTUREPRESENTER_H + +#include "legonamedtexturelist.h" +#include "mxmediapresenter.h" + +// VTABLE: LEGO1 0x100d4d90 +// SIZE 0x54 +class LegoTexturePresenter : public MxMediaPresenter { +public: + LegoTexturePresenter() : m_textures(NULL) {} + ~LegoTexturePresenter() override; + + // FUNCTION: LEGO1 0x1000ce50 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0664 + return "LegoTexturePresenter"; + } + + // FUNCTION: LEGO1 0x1000ce60 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoTexturePresenter::ClassName()) || MxMediaPresenter::IsA(p_name); + } + + void DoneTickle() override; // vtable+0x2c + MxResult AddToManager() override; // vtable+0x34 + MxResult PutData() override; // vtable+0x4c + + // SYNTHETIC: LEGO1 0x1000cf40 + // LegoTexturePresenter::`scalar deleting destructor' + + MxResult Read(MxDSChunk& p_chunk); + MxResult Store(); + +private: + LegoNamedTextureList* m_textures; // 0x50 +}; + +#endif // LEGOTEXTUREPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/legotraninfo.h b/LEGO1/lego/legoomni/include/legotraninfo.h new file mode 100644 index 00000000..3ded0903 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legotraninfo.h @@ -0,0 +1,57 @@ +#ifndef LEGOTRANINFO_H +#define LEGOTRANINFO_H + +#include "decomp.h" +#include "mxgeometry/mxmatrix.h" +#include "mxtypes.h" + +struct AnimInfo; +class LegoAnimMMPresenter; +class LegoROI; +class MxPresenter; + +// SIZE 0x78 +struct LegoTranInfo { + enum { + c_bit2 = 0x02 + }; + + LegoTranInfo() + { + m_index = 0; + m_unk0x08 = NULL; + m_unk0x0c = NULL; + m_unk0x10 = 0; + m_unk0x12 = -1; + m_unk0x14 = FALSE; + m_unk0x1c = NULL; + m_unk0x20 = NULL; + m_presenter = NULL; + m_unk0x15 = TRUE; + m_unk0x28 = TRUE; + m_unk0x29 = TRUE; + m_flags = 0; + m_unk0x2c.SetIdentity(); + } + + ~LegoTranInfo() { delete m_unk0x0c; } + + AnimInfo* m_animInfo; // 0x00 + MxU32 m_index; // 0x04 + LegoROI* m_unk0x08; // 0x08 + MxMatrix* m_unk0x0c; // 0x0c + MxU8 m_unk0x10; // 0x10 + MxS16 m_unk0x12; // 0x12 + MxBool m_unk0x14; // 0x14 + MxBool m_unk0x15; // 0x15 + MxU32 m_objectId; // 0x18 + MxPresenter** m_unk0x1c; // 0x1c + MxLong* m_unk0x20; // 0x20 + LegoAnimMMPresenter* m_presenter; // 0x24 + MxBool m_unk0x28; // 0x28 + MxBool m_unk0x29; // 0x29 + MxMatrix m_unk0x2c; // 0x2c + MxU32 m_flags; // 0x74 +}; + +#endif // LEGOTRANINFO_H diff --git a/LEGO1/lego/legoomni/include/legotraninfolist.h b/LEGO1/lego/legoomni/include/legotraninfolist.h new file mode 100644 index 00000000..06cd2558 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legotraninfolist.h @@ -0,0 +1,82 @@ +#ifndef LEGOTRANINFOLIST_H +#define LEGOTRANINFOLIST_H + +#include "legotraninfo.h" +#include "mxlist.h" +#include "mxtypes.h" + +// VTABLE: LEGO1 0x100d8ca8 +// class MxCollection + +// VTABLE: LEGO1 0x100d8cc0 +// class MxList + +// VTABLE: LEGO1 0x100d8cd8 +// class MxPtrList + +// VTABLE: LEGO1 0x100d8c90 +// SIZE 0x18 +class LegoTranInfoList : public MxPtrList { +public: + LegoTranInfoList() : MxPtrList(FALSE) {} +}; + +// VTABLE: LEGO1 0x100d8cf0 +// class MxListCursor + +// VTABLE: LEGO1 0x100d8d08 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d8d20 +// SIZE 0x10 +class LegoTranInfoListCursor : public MxPtrListCursor { +public: + LegoTranInfoListCursor(LegoTranInfoList* p_list) : MxPtrListCursor(p_list) {} +}; + +// TEMPLATE: LEGO1 0x1005fdf0 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1005fe00 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1005fe50 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1005fe60 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x1005fef0 +// LegoTranInfoList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1005ff60 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x1005ffb0 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10060020 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100600d0 +// MxPtrList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100612f0 +// LegoTranInfoListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x10061360 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x100613b0 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10061420 +// MxPtrListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x10061490 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x100614e0 +// LegoTranInfoListCursor::~LegoTranInfoListCursor + +#endif // LEGOTRANINFOLIST_H diff --git a/LEGO1/lego/legoomni/include/legounknown100d5778.h b/LEGO1/lego/legoomni/include/legounknown100d5778.h new file mode 100644 index 00000000..5ae43070 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legounknown100d5778.h @@ -0,0 +1,40 @@ +#ifndef LEGOUNKNOWN100D5778_H +#define LEGOUNKNOWN100D5778_H + +#include "decomp.h" +#include "mxtypes.h" + +#include + +class LegoROI; + +// VTABLE: LEGO1 0x100d5778 +// SIZE 0x30 +class LegoUnknown100d5778 { +public: + LegoUnknown100d5778(); + virtual ~LegoUnknown100d5778(); + + void Init(); + MxResult FUN_100116a0(LPDIRECTSOUND p_dsound, undefined4, undefined4 p_unk0x2c); + void Destroy(); + undefined4 FUN_100118e0(LPDIRECTSOUNDBUFFER p_dsBuffer); + void FUN_10011ca0(); + MxS32 FUN_10011cf0(undefined4, undefined4); + + // SYNTHETIC: LEGO1 0x10011650 + // LegoUnknown100d5778::`scalar deleting destructor' + +private: + undefined m_unk0x04[4]; // 0x04 + LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x08 + LegoROI* m_unk0x0c; // 0x0c + undefined4 m_unk0x10; // 0x10 + MxBool m_unk0x14; // 0x14 + MxBool m_unk0x15; // 0x15 + undefined4 m_unk0x18; // 0x18 + undefined m_unk0x1c[0x10]; // 0x1c + undefined4 m_unk0x2c; // 0x2c +}; + +#endif // LEGOUNKNOWN100D5778_H diff --git a/LEGO1/lego/legoomni/include/legoutils.h b/LEGO1/lego/legoomni/include/legoutils.h new file mode 100644 index 00000000..b02d7a6d --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoutils.h @@ -0,0 +1,43 @@ +#ifndef LEGOUTILS_H +#define LEGOUTILS_H + +#include "decomp.h" +#include "extra.h" +#include "mxtypes.h" + +#include + +class IslePathActor; +class MxAtomId; +class LegoEntity; +class LegoFile; +class LegoAnimPresenter; +class LegoNamedTexture; +class LegoROI; +class LegoTreeNode; + +LegoEntity* PickEntity(MxLong, MxLong); +LegoROI* PickROI(MxLong, MxLong); +MxS16 CountTotalTreeNodes(LegoTreeNode* p_node); +void FUN_1003e050(LegoAnimPresenter* p_presenter); +Extra::ActionType MatchActionString(const char*); +void InvokeAction(Extra::ActionType p_actionId, const MxAtomId& p_pAtom, MxS32 p_targetEntityId, LegoEntity* p_sender); +void SetCameraControllerFromIsle(); +void ConvertHSVToRGB(float p_h, float p_s, float p_v, float* p_rOut, float* p_bOut, float* p_gOut); +void FUN_1003ecc0(IslePathActor* p_actor, undefined4, undefined4, MxBool); +void FUN_1003eda0(); +MxBool RemoveFromCurrentWorld(const MxAtomId& p_atomId, MxS32 p_id); +void FUN_1003ef00(MxBool); +void SetAppCursor(WPARAM p_wparam); +MxBool FUN_1003ef60(); +MxBool RemoveFromWorld(MxAtomId& p_entityAtom, MxS32 p_entityId, MxAtomId& p_worldAtom, MxS32 p_worldEntityId); +MxS32 UpdateLightPosition(MxS32 p_increase); +void SetLightPosition(MxS32 p_index); +LegoNamedTexture* ReadNamedTexture(LegoFile* p_file); +void FUN_1003f540(LegoFile* p_file, const char* p_filename); +void WriteNamedTexture(LegoFile* p_file, LegoNamedTexture* p_texture); + +// SYNTHETIC: LEGO1 0x10034b40 +// LegoTexture::`scalar deleting destructor' + +#endif // LEGOUTILS_H diff --git a/LEGO1/lego/legoomni/include/legovariables.h b/LEGO1/lego/legoomni/include/legovariables.h new file mode 100644 index 00000000..ec02c530 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legovariables.h @@ -0,0 +1,57 @@ +#ifndef LEGOVARIABLES_H +#define LEGOVARIABLES_H + +#include "mxvariable.h" + +extern const char* g_varAMBULFUEL; +extern const char* g_varVISIBILITY; +extern const char* g_varCAMERALOCATION; +extern const char* g_varCURSOR; +extern const char* g_varWHOAMI; + +// VTABLE: LEGO1 0x100d86c8 +// SIZE 0x24 +class VisibilityVariable : public MxVariable { +public: + VisibilityVariable() { m_key = g_varVISIBILITY; } + + void SetValue(const char* p_value) override; // vtable+0x04 +}; + +// VTABLE: LEGO1 0x100d86b8 +// SIZE 0x24 +class CameraLocationVariable : public MxVariable { +public: + CameraLocationVariable() { m_key = g_varCAMERALOCATION; } + + void SetValue(const char* p_value) override; // vtable+0x04 +}; + +// VTABLE: LEGO1 0x100d86a8 +// SIZE 0x24 +class CursorVariable : public MxVariable { +public: + CursorVariable() { m_key = g_varCURSOR; } + + void SetValue(const char* p_value) override; // vtable+0x04 +}; + +// VTABLE: LEGO1 0x100d8698 +// SIZE 0x24 +class WhoAmIVariable : public MxVariable { +public: + WhoAmIVariable() { m_key = g_varWHOAMI; } + + void SetValue(const char* p_value) override; // vtable+0x04 +}; + +// VTABLE: LEGO1 0x100da878 +// SIZE 0x24 +class CustomizeAnimFileVariable : public MxVariable { +public: + CustomizeAnimFileVariable(const char* p_key); + + void SetValue(const char* p_value) override; // vtable+0x04 +}; + +#endif // LEGOVARIABLES_H diff --git a/LEGO1/lego/legoomni/include/legovehiclebuildstate.h b/LEGO1/lego/legoomni/include/legovehiclebuildstate.h new file mode 100644 index 00000000..7a70a873 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legovehiclebuildstate.h @@ -0,0 +1,52 @@ +#ifndef LEGOVEHICLEBUILDSTATE_H +#define LEGOVEHICLEBUILDSTATE_H + +#include "decomp.h" +#include "legostate.h" +#include "mxstring.h" + +// VTABLE: LEGO1 0x100d66e0 +// SIZE 0x50 +class LegoVehicleBuildState : public LegoState { +public: + LegoVehicleBuildState(char* p_classType); + + // FUNCTION: LEGO1 0x10025ff0 + inline const char* ClassName() const override // vtable+0x0c + { + return this->m_className.GetData(); + } + + // FUNCTION: LEGO1 0x10026000 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, this->m_className.GetData()) || LegoState::IsA(p_name); + } + + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + // SYNTHETIC: LEGO1 0x100260a0 + // LegoVehicleBuildState::`scalar deleting destructor' + + // private: + Playlist m_unk0x08[4]; // 0x08 + + // This can be one of the following: + // * LegoRaceCarBuildState + // * LegoCopterBuildState + // * LegoDuneCarBuildState + // * LegoJetskiBuildState + MxString m_className; // 0x38 + + // Known States: + // * 1 == enter(ing) build screen + // * 3 == cutscene/dialogue + // * 6 == exit(ing) build screen + MxU32 m_animationState; // 0x48 + undefined m_unk0x4c; // 0x4c + MxBool m_unk0x4d; // 0x4d + MxBool m_unk0x4e; // 0x4e + MxU8 m_placedPartCount; // 0x4f +}; + +#endif // LEGOVEHICLEBUILDSTATE_H diff --git a/LEGO1/lego/legoomni/include/legovideomanager.h b/LEGO1/lego/legoomni/include/legovideomanager.h new file mode 100644 index 00000000..ffdcbdcc --- /dev/null +++ b/LEGO1/lego/legoomni/include/legovideomanager.h @@ -0,0 +1,106 @@ +#ifndef LEGOVIDEOMANAGER_H +#define LEGOVIDEOMANAGER_H + +#include "decomp.h" +#include "legophonemelist.h" +#include "mxvideomanager.h" + +#include + +class Lego3DManager; +class LegoROI; +class MxDirect3D; +class MxStopWatch; + +namespace Tgl +{ +class Renderer; +} + +// VTABLE: LEGO1 0x100d9c88 +// SIZE 0x590 +class LegoVideoManager : public MxVideoManager { +public: + LegoVideoManager(); + ~LegoVideoManager() override; + + int EnableRMDevice(); + int DisableRMDevice(); + void EnableFullScreenMovie(MxBool p_enable); + void EnableFullScreenMovie(MxBool p_enable, MxBool p_scale); + void MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY); + void ToggleFPS(MxBool p_visible); + + MxResult Tickle() override; // vtable+0x08 + void Destroy() override; // vtable+0x18 + MxResult Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, MxBool p_createThread) override; // vtable+0x2c + MxResult RealizePalette(MxPalette*) override; // vtable+0x30 + void UpdateView(MxU32 p_x, MxU32 p_y, MxU32 p_width, MxU32 p_height) override; // vtable+0x34 + virtual MxPresenter* GetPresenterAt(MxS32 p_x, MxS32 p_y); // vtable+0x38 + + // FUNCTION: LEGO1 0x1007ab10 + virtual LegoPhonemeList* GetPhonemeList() { return m_phonemeRefList; } // vtable+0x3c + + void SetSkyColor(float p_red, float p_green, float p_blue); + void OverrideSkyColor(MxBool p_shouldOverride); + MxResult ResetPalette(MxBool p_ignoreSkyColor); + + void FUN_1007c520(); + + inline Tgl::Renderer* GetRenderer() { return this->m_renderer; } + inline Lego3DManager* Get3DManager() { return this->m_3dManager; } + inline LegoROI* GetViewROI() { return this->m_viewROI; } + inline MxDirect3D* GetDirect3D() { return this->m_direct3d; } + inline MxBool GetRender3D() { return this->m_render3d; } + inline double GetElapsedSeconds() { return this->m_elapsedSeconds; } + + inline void SetRender3D(MxBool p_render3d) { this->m_render3d = p_render3d; } + inline void SetUnk0x554(MxBool p_unk0x554) { this->m_unk0x554 = p_unk0x554; } + +private: + MxResult CreateDirect3D(); + MxResult ConfigureD3DRM(); + void DrawFPS(); + + inline void DrawCursor(); + + Tgl::Renderer* m_renderer; // 0x64 + Lego3DManager* m_3dManager; // 0x68 + LegoROI* m_viewROI; // 0x6c + undefined4 m_unk0x70; // 0x70 + MxDirect3D* m_direct3d; // 0x74 + undefined4 m_unk0x78[27]; // 0x78 + MxBool m_render3d; // 0xe4 + MxBool m_unk0xe5; // 0xe5 + MxBool m_unk0xe6; // 0xe6 + PALETTEENTRY m_paletteEntries[256]; // 0xe7 + undefined m_padding0x4e7; // 0x4e7 + LegoPhonemeList* m_phonemeRefList; // 0x4e8 + MxBool m_isFullscreenMovie; // 0x4ec + MxPalette* m_palette; // 0x4f0 + MxStopWatch* m_stopWatch; // 0x4f4 + double m_elapsedSeconds; // 0x4f8 + MxBool m_fullScreenMovie; // 0x500 + MxBool m_drawCursor; // 0x501 + MxS32 m_cursorXCopy; // 0x504 + MxS32 m_cursorYCopy; // 0x508 + MxS32 m_cursorX; // 0x50c + MxS32 m_cursorY; // 0x510 + LPDIRECTDRAWSURFACE m_cursorSurface; // 0x514 + RECT m_cursorRect; // 0x518 + LPDIRECTDRAWSURFACE m_unk0x528; // 0x528 + MxBool m_drawFPS; // 0x52c + RECT m_fpsRect; // 0x530 + HFONT m_arialFont; // 0x540 + SIZE m_fpsSize; // 0x544 + MxFloat m_unk0x54c; // 0x54c + MxFloat m_unk0x550; // 0x550 + MxBool m_unk0x554; // 0x554 + MxBool m_paused; // 0x555 + undefined m_pad0x556[0x39]; // 0x556 +}; + +// SYNTHETIC: LEGO1 0x1007ab20 +// LegoVideoManager::`scalar deleting destructor' + +#endif // LEGOVIDEOMANAGER_H diff --git a/LEGO1/lego/legoomni/include/legoworld.h b/LEGO1/lego/legoomni/include/legoworld.h new file mode 100644 index 00000000..cde4f4b1 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoworld.h @@ -0,0 +1,185 @@ +#ifndef LEGOWORLD_H +#define LEGOWORLD_H + +#include "legocachesoundlist.h" +#include "legoentity.h" +#include "legoentitylist.h" +#include "legopathcontrollerlist.h" +#include "mxpresenterlist.h" +#include "roi/legoroi.h" + +class IslePathActor; +class LegoCameraController; +class LegoPathBoundary; +class LegoHideAnimPresenter; + +struct CoreSetCompare { + MxS32 operator()(MxCore* const& p_a, MxCore* const& p_b) const { return (MxS32) p_a < (MxS32) p_b; } +}; + +typedef set MxCoreSet; + +// VTABLE: LEGO1 0x100d6280 +// SIZE 0xf8 +class LegoWorld : public LegoEntity { +public: + enum StartupTicks { + e_start = 0, + e_one, + e_two, + e_three, + e_four + }; + + LegoWorld(); + ~LegoWorld() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1001d690 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0058 + return "LegoWorld"; + } + + // FUNCTION: LEGO1 0x1001d6a0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoWorld::ClassName()) || LegoEntity::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void Destroy(MxBool p_fromDestructor) override; // vtable+0x1c + virtual void ReadyWorld(); // vtable+0x50 + virtual LegoCameraController* VTable0x54(); // vtable+0x54 + virtual void Add(MxCore* p_object); // vtable+0x58 + virtual MxBool VTable0x5c(); // vtable+0x5c + + // FUNCTION: LEGO1 0x100010a0 + virtual void VTable0x60() {} // vtable+0x60 + + virtual MxBool VTable0x64(); // vtable+0x64 + virtual void Enable(MxBool p_enable); // vtable+0x68 + + MxBool PresentersPending(); + void Remove(MxCore* p_object); + MxResult PlaceActor( + LegoPathActor* p_actor, + const char* p_name, + MxS32 p_src, + float p_srcScale, + MxS32 p_dest, + float p_destScale + ); + MxResult AddPathActor(LegoPathActor* p_actor); + MxResult FUN_1001fb70( + LegoPathActor* p_actor, + LegoAnimPresenter* p_presenter, + Vector3& p_position, + Vector3& p_direction + ); + void RemovePathActor(LegoPathActor* p_actor); + void FUN_1001fda0(LegoAnimPresenter* p_presenter); + void FUN_1001fe90(LegoAnimPresenter* p_presenter); + LegoPathBoundary* FindPathBoundary(const char* p_name); + void AddPath(LegoPathController* p_controller); + MxResult GetCurrPathInfo(LegoPathBoundary** p_boundaries, MxS32& p_numL); + MxCore* Find(const char* p_class, const char* p_name); + MxCore* Find(const MxAtomId& p_atom, MxS32 p_entityId); + + inline LegoCameraController* GetCamera() { return m_cameraController; } + inline LegoEntityList* GetEntityList() { return m_entityList; } + inline MxS32 GetScriptIndex() { return m_scriptIndex; } + inline MxCoreSet& GetUnknown0xd0() { return m_set0xd0; } + inline list& GetROIList() { return m_roiList; } + + inline void SetScriptIndex(MxS32 p_scriptIndex) { m_scriptIndex = p_scriptIndex; } + + // SYNTHETIC: LEGO1 0x1001dee0 + // LegoWorld::`scalar deleting destructor' + +protected: + LegoPathControllerList m_list0x68; // 0x68 + MxPresenterList m_animPresenters; // 0x80 + LegoCameraController* m_cameraController; // 0x98 + LegoEntityList* m_entityList; // 0x9c + LegoCacheSoundList* m_cacheSoundList; // 0xa0 + MxBool m_destroyed; // 0xa4 + MxCoreSet m_set0xa8; // 0xa8 + MxPresenterList m_controlPresenters; // 0xb8 + MxCoreSet m_set0xd0; // 0xd0 + list m_roiList; // 0xe0 + MxS32 m_scriptIndex; // 0xec + LegoHideAnimPresenter* m_hideAnimPresenter; // 0xf0 + MxS16 m_startupTicks; // 0xf4 + MxBool m_worldStarted; // 0xf6 + undefined m_unk0xf7; // 0xf7 +}; + +// clang-format off +// TEMPLATE: LEGO1 0x1001d780 +// _Tree >::_Kfn,CoreSetCompare,allocator >::~_Tree >::_Kfn,CoreSetCompare,allocator > + +// TEMPLATE: LEGO1 0x1001d850 +// _Tree >::_Kfn,CoreSetCompare,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x1001d890 +// _Tree >::_Kfn,CoreSetCompare,allocator >::erase + +// TEMPLATE: LEGO1 0x1001dcf0 +// _Tree >::_Kfn,CoreSetCompare,allocator >::_Erase + +// TEMPLATE: LEGO1 0x1001dd30 +// _Tree >::_Kfn,CoreSetCompare,allocator >::_Init + +// TEMPLATE: LEGO1 0x1001ddf0 +// list >::~list > + +// TEMPLATE: LEGO1 0x1001df50 +// List::~List + +// TEMPLATE: LEGO1 0x1001de60 +// list >::_Buynode + +// TEMPLATE: LEGO1 0x1001de90 +// set >::~set > + +// TEMPLATE: LEGO1 0x1001df00 +// Set::~Set + +// TEMPLATE: LEGO1 0x1001f590 +// list >::erase + +// TEMPLATE: LEGO1 0x100208b0 +// _Tree >::_Kfn,CoreSetCompare,allocator >::insert + +// TEMPLATE: LEGO1 0x10020b20 +// _Tree >::_Kfn,CoreSetCompare,allocator >::iterator::_Dec + +// XTEMPLATE LEGO1 0x10020b70 + +// TEMPLATE: LEGO1 0x10020bb0 +// _Tree >::_Kfn,CoreSetCompare,allocator >::_Buynode + +// TEMPLATE: LEGO1 0x10020bd0 +// _Tree >::_Kfn,CoreSetCompare,allocator >::_Insert + +// TEMPLATE: LEGO1 0x10020e50 +// _Tree >::_Kfn,CoreSetCompare,allocator >::_Lrotate + +// TEMPLATE: LEGO1 0x10020eb0 +// _Tree >::_Kfn,CoreSetCompare,allocator >::_Rrotate + +// TEMPLATE: LEGO1 0x10021340 +// _Tree >::_Kfn,CoreSetCompare,allocator >::find + +// TEMPLATE: LEGO1 0x10022360 +// ?_Construct@@YAXPAPAVMxCore@@ABQAV1@@Z + +// GLOBAL: LEGO1 0x100f11a0 +// _Tree >::_Kfn,CoreSetCompare,allocator >::_Nil +// clang-format on + +#endif // LEGOWORLD_H diff --git a/LEGO1/lego/legoomni/include/legoworldlist.h b/LEGO1/lego/legoomni/include/legoworldlist.h new file mode 100644 index 00000000..6d1006b0 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoworldlist.h @@ -0,0 +1,92 @@ +#ifndef LEGOWORLDLIST_H +#define LEGOWORLDLIST_H + +#include "mxlist.h" +#include "mxtypes.h" + +class LegoWorld; + +// VTABLE: LEGO1 0x100d8700 +// class MxCollection + +// VTABLE: LEGO1 0x100d8718 +// class MxList + +// VTABLE: LEGO1 0x100d8730 +// class MxPtrList + +// VTABLE: LEGO1 0x100d8680 +// SIZE 0x18 +class LegoWorldList : public MxPtrList { +public: + LegoWorldList(MxBool p_ownership = FALSE) : MxPtrList(p_ownership) {} + + // FUNCTION: LEGO1 0x100598d0 + MxS8 Compare(LegoWorld* p_a, LegoWorld* p_b) override { return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; } // vtable+0x14 + + // SYNTHETIC: LEGO1 0x10059a00 + // LegoWorldList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100d75b8 +// class MxListCursor + +// VTABLE: LEGO1 0x100d7588 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d75a0 +// SIZE 0x10 +class LegoWorldListCursor : public MxPtrListCursor { +public: + LegoWorldListCursor(LegoWorldList* p_list) : MxPtrListCursor(p_list) {} +}; + +// SYNTHETIC: LEGO1 0x1003e870 +// LegoWorldListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1003e8e0 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x1003e930 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1003e9a0 +// MxPtrListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1003ea10 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x1003ea60 +// LegoWorldListCursor::~LegoWorldListCursor + +// TEMPLATE: LEGO1 0x100598f0 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x10059900 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x10059950 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x10059960 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x100599f0 +// MxPtrList::Destroy + +// TEMPLATE: LEGO1 0x10059a70 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x10059ac0 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10059b30 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10059be0 +// MxPtrList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1005b740 +// MxList::DeleteEntry + +#endif // LEGOWORLDLIST_H diff --git a/LEGO1/lego/legoomni/include/legoworldpresenter.h b/LEGO1/lego/legoomni/include/legoworldpresenter.h new file mode 100644 index 00000000..831b64f5 --- /dev/null +++ b/LEGO1/lego/legoomni/include/legoworldpresenter.h @@ -0,0 +1,52 @@ +#ifndef LEGOWORLDPRESENTER_H +#define LEGOWORLDPRESENTER_H + +#include "legoentitypresenter.h" + +#include + +class LegoWorld; +struct ModelDbPart; +struct ModelDbModel; + +// VTABLE: LEGO1 0x100d8ee0 +// SIZE 0x54 +class LegoWorldPresenter : public LegoEntityPresenter { +public: + LegoWorldPresenter(); + ~LegoWorldPresenter() override; // vtable+0x00 + + static void configureLegoWorldPresenter(MxS32 p_legoWorldPresenterQuality); + + // FUNCTION: LEGO1 0x10066630 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0608 + return "LegoWorldPresenter"; + } + + // FUNCTION: LEGO1 0x10066640 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, LegoWorldPresenter::ClassName()) || LegoEntityPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void ParseExtra() override; // vtable+0x30 + MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c + void VTable0x60(MxPresenter* p_presenter) override; // vtable+0x60 + + MxResult LoadWorld(char* p_worldName, LegoWorld* p_world); + + // SYNTHETIC: LEGO1 0x10066750 + // LegoWorldPresenter::`scalar deleting destructor' + +private: + MxResult FUN_10067360(ModelDbPart& p_part, FILE* p_wdbFile); + MxResult FUN_100674b0(ModelDbModel& p_model, FILE* p_wdbFile, LegoWorld* p_world); + + undefined4 m_unk0x50; +}; + +#endif // LEGOWORLDPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/misc.h b/LEGO1/lego/legoomni/include/misc.h new file mode 100644 index 00000000..65606dfb --- /dev/null +++ b/LEGO1/lego/legoomni/include/misc.h @@ -0,0 +1,65 @@ +#ifndef MISC_H +#define MISC_H + +#include "compat.h" +#include "decomp.h" +// Long include path due to dependency of misc library on LegoOmni +#include "lego/legoomni/include/actions/actionsfwd.h" +#include "mxtypes.h" + +class IslePathActor; +class LegoAnimationManager; +class LegoBuildingManager; +class LegoCharacterManager; +class LegoControlManager; +class LegoGameState; +class LegoInputManager; +class LegoNavController; +class LegoOmni; +class LegoPlantManager; +class LegoROI; +class LegoSoundManager; +class LegoTextureContainer; +class LegoVideoManager; +class LegoWorld; +class MxAtomId; +class MxBackgroundAudioManager; +class MxDSAction; +class MxTransitionManager; +class ViewLODListManager; +class ViewManager; + +extern MxBool g_isWorldActive; + +LegoOmni* Lego(); +LegoSoundManager* SoundManager(); +LegoVideoManager* VideoManager(); +MxBackgroundAudioManager* BackgroundAudioManager(); +LegoInputManager* InputManager(); +LegoControlManager* ControlManager(); +LegoGameState* GameState(); +LegoAnimationManager* AnimationManager(); +LegoNavController* NavController(); +IslePathActor* CurrentActor(); +LegoWorld* CurrentWorld(); +LegoCharacterManager* CharacterManager(); +ViewManager* GetViewManager(); +LegoPlantManager* PlantManager(); +LegoBuildingManager* BuildingManager(); +LegoTextureContainer* TextureContainer(); +ViewLODListManager* GetViewLODListManager(); +void FUN_10015820(MxBool p_disable, MxU16 p_flags); +LegoROI* FindROI(const char* p_name); +void SetROIVisible(const char* p_name, MxBool p_visible); +void SetCurrentActor(IslePathActor* p_currentActor); +MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction); +void DeleteAction(); +LegoWorld* FindWorld(const MxAtomId& p_atom, MxS32 p_entityid); +MxDSAction& GetCurrentAction(); +void SetCurrentWorld(LegoWorld* p_world); +MxTransitionManager* TransitionManager(); +void PlayMusic(JukeboxScript::Script p_script); +void SetIsWorldActive(MxBool p_isWorldActive); +void DeleteObjects(MxAtomId* p_id, MxS32 p_first, MxS32 p_last); + +#endif // MISC_H diff --git a/LEGO1/lego/legoomni/include/motocycle.h b/LEGO1/lego/legoomni/include/motocycle.h new file mode 100644 index 00000000..638018f0 --- /dev/null +++ b/LEGO1/lego/legoomni/include/motocycle.h @@ -0,0 +1,44 @@ +#ifndef MOTOCYCLE_H +#define MOTOCYCLE_H + +#include "decomp.h" +#include "islepathactor.h" + +// VTABLE: LEGO1 0x100d7090 +// SIZE 0x16c +class Motocycle : public IslePathActor { +public: + Motocycle(); + + // FUNCTION: LEGO1 0x10035840 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f38e8 + return "Motorcycle"; + } + + // FUNCTION: LEGO1 0x10035850 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Motocycle::ClassName()) || IslePathActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void VTable0x70(float p_float) override; // vtable+0x70 + MxU32 VTable0xcc() override; // vtable+0xcc + MxU32 VTable0xd4(LegoControlManagerEvent& p_param) override; // vtable+0xd4 + MxU32 VTable0xdc(MxType19NotificationParam&) override; // vtable+0xdc + void VTable0xe4() override; // vtable+0xe4 + + void FUN_10035e10(); + + // SYNTHETIC: LEGO1 0x100359d0 + // Motocycle::`scalar deleting destructor' + +private: + undefined m_unk0x160[4]; + MxFloat m_unk0x164; + undefined m_unk0x168[4]; +}; + +#endif // MOTOCYCLE_H diff --git a/LEGO1/lego/legoomni/include/mxbackgroundaudiomanager.h b/LEGO1/lego/legoomni/include/mxbackgroundaudiomanager.h new file mode 100644 index 00000000..922ff625 --- /dev/null +++ b/LEGO1/lego/legoomni/include/mxbackgroundaudiomanager.h @@ -0,0 +1,70 @@ +#ifndef MXBACKGROUNDAUDIOMANAGER_H +#define MXBACKGROUNDAUDIOMANAGER_H + +#include "mxcore.h" +#include "mxdsaction.h" +#include "mxtypes.h" + +class MxAudioPresenter; + +// VTABLE: LEGO1 0x100d9fe8 +// SIZE 0x150 +class MxBackgroundAudioManager : public MxCore { +public: + MxBackgroundAudioManager(); + ~MxBackgroundAudioManager() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1007eb70 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f7ac4 + return "MxBackgroundAudioManager"; + } + + // FUNCTION: LEGO1 0x1007eb80 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxBackgroundAudioManager::ClassName()) || MxCore::IsA(p_name); + } + + inline MxBool GetEnabled() { return m_enabled; } + + void StartAction(MxParam& p_param); + void StopAction(MxParam& p_param); + MxResult PlayMusic(MxDSAction& p_action, undefined4 p_unk0x140, undefined4 p_unk0x13c); + + void FUN_1007ee70(); + void FUN_1007ef40(); + void FadeInOrFadeOut(); + + void Enable(MxBool p_enable); + virtual MxResult Create(MxAtomId& p_script, MxU32 p_frequencyMS); + + void Stop(); + void LowerVolume(); + void RaiseVolume(); + + // SYNTHETIC: LEGO1 0x1007ec00 + // MxBackgroundAudioManager::`scalar deleting destructor' + +private: + void Init(); + MxResult OpenMusic(MxAtomId& p_script); + void DestroyMusic(); + + MxBool m_enabled; // 0x08 + MxDSAction m_action1; // 0x0c + MxAudioPresenter* m_unk0xa0; // 0xa0 + MxDSAction m_action2; // 0xa4 + MxAudioPresenter* m_unk0x138; // 0x138 + MxS32 m_unk0x13c; // 0x13c + MxS32 m_unk0x140; // 0x140 + MxS32 m_targetVolume; // 0x144 + MxS16 m_unk0x148; // 0x148 + MxAtomId m_script; // 0x14c +}; + +#endif // MXBACKGROUNDAUDIOMANAGER_H diff --git a/LEGO1/lego/legoomni/include/mxcompositemediapresenter.h b/LEGO1/lego/legoomni/include/mxcompositemediapresenter.h new file mode 100644 index 00000000..efba804f --- /dev/null +++ b/LEGO1/lego/legoomni/include/mxcompositemediapresenter.h @@ -0,0 +1,40 @@ +#ifndef MXCOMPOSITEMEDIAPRESENTER_H +#define MXCOMPOSITEMEDIAPRESENTER_H + +#include "mxcompositepresenter.h" + +// VTABLE: LEGO1 0x100d96b0 +// SIZE 0x50 +class MxCompositeMediaPresenter : public MxCompositePresenter { +public: + MxCompositeMediaPresenter(); + ~MxCompositeMediaPresenter() override; + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x10073f10 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f02d4 + return "MxCompositeMediaPresenter"; + } + + // FUNCTION: LEGO1 0x10073f20 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxCompositeMediaPresenter::ClassName()) || MxCompositePresenter::IsA(p_name); + } + + void StartingTickle() override; // vtable+0x1c + MxResult StartAction(MxStreamController*, MxDSAction* p_action) override; // vtable+0x3c + MxResult PutData() override; // vtable+0x4c + +private: + MxS16 m_unk0x4c; // 0x4c + MxBool m_unk0x4e; // 0x4e +}; + +// SYNTHETIC: LEGO1 0x10074000 +// MxCompositeMediaPresenter::`scalar deleting destructor' + +#endif // MXCOMPOSITEMEDIAPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/mxcontrolpresenter.h b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h new file mode 100644 index 00000000..e12c1a25 --- /dev/null +++ b/LEGO1/lego/legoomni/include/mxcontrolpresenter.h @@ -0,0 +1,58 @@ +#ifndef MXCONTROLPRESENTER_H +#define MXCONTROLPRESENTER_H + +#include "decomp.h" +#include "mxcompositepresenter.h" + +class LegoControlManagerEvent; +class MxVideoPresenter; + +// VTABLE: LEGO1 0x100d7b88 +// SIZE 0x5c +class MxControlPresenter : public MxCompositePresenter { +public: + MxControlPresenter(); + ~MxControlPresenter() override; + + // FUNCTION: LEGO1 0x10044000 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0514 + return "MxControlPresenter"; + } + + // FUNCTION: LEGO1 0x10044010 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxControlPresenter::ClassName()) || MxCompositePresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void RepeatingTickle() override; // vtable+0x24 + void ParseExtra() override; // vtable+0x30 + MxResult AddToManager() override; // vtable+0x34 + MxResult StartAction(MxStreamController*, MxDSAction*) override; // vtable+0x3c + void EndAction() override; // vtable+0x40 + MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48 + void Enable(MxBool p_enable) override; // vtable+0x54 + MxBool VTable0x64(undefined4 p_undefined) override; // vtable+0x64 + virtual void VTable0x68(MxBool p_unk0x50); // vtable+0x68 + virtual void VTable0x6c(MxS16); // vtable+0x6c + + MxBool FUN_10044480(LegoControlManagerEvent* p_event, MxPresenter* p_presenter); + MxBool FUN_10044270(MxS32 p_x, MxS32 p_y, MxVideoPresenter* p_presenter); + +private: + undefined2 m_unk0x4c; // 0x4c + MxS16 m_unk0x4e; // 0x4e + MxBool m_unk0x50; // 0x50 + undefined2 m_unk0x52; // 0x52 + undefined2 m_unk0x54; // 0x54 + undefined2 m_unk0x56; // 0x56 + MxS16* m_unk0x58; // 0x58 +}; + +// SYNTHETIC: LEGO1 0x100440f0 +// MxControlPresenter::`scalar deleting destructor' + +#endif // MXCONTROLPRESENTER_H diff --git a/LEGO1/lego/legoomni/include/mxtransitionmanager.h b/LEGO1/lego/legoomni/include/mxtransitionmanager.h new file mode 100644 index 00000000..5fd23356 --- /dev/null +++ b/LEGO1/lego/legoomni/include/mxtransitionmanager.h @@ -0,0 +1,80 @@ +#ifndef MXTRANSITIONMANAGER_H +#define MXTRANSITIONMANAGER_H + +#include "decomp.h" +#include "mxcore.h" + +#include + +class MxVideoPresenter; + +// VTABLE: LEGO1 0x100d7ea0 +// SIZE 0x900 +class MxTransitionManager : public MxCore { +public: + MxTransitionManager(); + ~MxTransitionManager() override; // vtable+0x00 + + void SetWaitIndicator(MxVideoPresenter* p_waitIndicator); + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1004b950 + inline const char* ClassName() const override // vtable+0x0c + { + return "MxTransitionManager"; + } + + // FUNCTION: LEGO1 0x1004b960 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxTransitionManager::ClassName()) || MxCore::IsA(p_name); + } + + virtual MxResult GetDDrawSurfaceFromVideoManager(); // vtable+0x14 + + enum TransitionType { + e_notTransitioning = 0, + e_noAnimation, + e_dissolve, + e_mosaic, + e_wipeDown, + e_windows, + e_broken // Unknown what this is supposed to be, it locks the game up + }; + + MxResult StartTransition(TransitionType p_animationType, MxS32 p_speed, MxBool p_doCopy, MxBool p_playMusicInAnim); + + inline TransitionType GetTransitionType() { return m_transitionType; } + + // SYNTHETIC: LEGO1 0x1004b9e0 + // MxTransitionManager::`scalar deleting destructor' + +private: + void EndTransition(MxBool p_notifyWorld); + void NoTransition(); + void DissolveTransition(); + void MosaicTransition(); + void WipeDownTransition(); + void WindowsTransition(); + void BrokenTransition(); + + void SubmitCopyRect(LPDDSURFACEDESC p_ddsc); + void SetupCopyRect(LPDDSURFACEDESC p_ddsc); + + MxVideoPresenter* m_waitIndicator; // 0x08 + RECT m_copyRect; // 0x0c + MxU8* m_copyBuffer; // 0x1c + FlagBitfield m_copyFlags; // 0x20 + undefined4 m_unk0x24; // 0x24 + FlagBitfield m_unk0x28; // 0x28 + TransitionType m_transitionType; // 0x2c + LPDIRECTDRAWSURFACE m_ddSurface; // 0x30 + MxU16 m_animationTimer; // 0x34 + MxU16 m_columnOrder[640]; // 0x36 + MxU16 m_randomShift[480]; // 0x536 + MxULong m_systemTime; // 0x8f8 + MxS32 m_animationSpeed; // 0x8fc +}; + +#endif // MXTRANSITIONMANAGER_H diff --git a/LEGO1/lego/legoomni/include/pizza.h b/LEGO1/lego/legoomni/include/pizza.h new file mode 100644 index 00000000..bb8c18f7 --- /dev/null +++ b/LEGO1/lego/legoomni/include/pizza.h @@ -0,0 +1,55 @@ +#ifndef PIZZA_H +#define PIZZA_H + +#include "decomp.h" +#include "isleactor.h" + +class SkateBoard; + +// VTABLE: LEGO1 0x100d7380 +// SIZE 0x9c +class Pizza : public IsleActor { +public: + Pizza(); + ~Pizza() override; + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x10037f90 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f038c + return "Pizza"; + } + + // FUNCTION: LEGO1 0x10037fa0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Pizza::ClassName()) || IsleActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + undefined4 VTable0x68() override; // vtable+0x68 + undefined4 HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 + undefined4 VTable0x80(MxParam&) override; // vtable+0x80 + + void FUN_100382b0(); + void FUN_10038380(); + + inline void SetSkateboard(SkateBoard* p_skateboard) { m_skateboard = p_skateboard; } + + // SYNTHETIC: LEGO1 0x100380e0 + // Pizza::`scalar deleting destructor' + +private: + undefined4 m_unk0x7c; // 0x7c + undefined4 m_unk0x80; // 0x80 + SkateBoard* m_skateboard; // 0x84 + undefined4 m_unk0x88; // 0x88 + undefined4 m_unk0x8c; // 0x8c + undefined4 m_unk0x90; // 0x90 + undefined4 m_unk0x94; // 0x94 + undefined m_unk0x98; // 0x98 +}; + +#endif // PIZZA_H diff --git a/LEGO1/lego/legoomni/include/pizzamissionstate.h b/LEGO1/lego/legoomni/include/pizzamissionstate.h new file mode 100644 index 00000000..1796dde4 --- /dev/null +++ b/LEGO1/lego/legoomni/include/pizzamissionstate.h @@ -0,0 +1,49 @@ +#ifndef PIZZAMISSIONSTATE_H +#define PIZZAMISSIONSTATE_H + +#include "legostate.h" + +// SIZE 0x20 +struct PizzaMissionStateEntry { +public: + undefined2 m_unk0x00; // 0x00 + MxU8 m_id; // 0x02 + undefined m_unk0x03[0x15]; // 0x03 + MxU16 m_score; // 0x18 + undefined m_unk0x18[6]; // 0x1a +}; + +// VTABLE: LEGO1 0x100d7408 +// SIZE 0xb0 +class PizzaMissionState : public LegoState { +public: + // FUNCTION: LEGO1 0x10039290 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f00d4 + return "PizzaMissionState"; + } + + // FUNCTION: LEGO1 0x100392a0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, PizzaMissionState::ClassName()) || LegoState::IsA(p_name); + } + + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + inline MxU16 GetScore(MxU8 p_id) { return GetState(p_id)->m_score; } + + // SYNTHETIC: LEGO1 0x10039350 + // PizzaMissionState::`scalar deleting destructor' + +private: + PizzaMissionStateEntry* GetState(MxU8 p_id); + +protected: + undefined4 m_unk0x08; // 0x08 + undefined4 m_unk0x0c; // 0x0c + PizzaMissionStateEntry m_state[5]; // 0x10 +}; + +#endif // PIZZAMISSIONSTATE_H diff --git a/LEGO1/lego/legoomni/include/pizzeria.h b/LEGO1/lego/legoomni/include/pizzeria.h new file mode 100644 index 00000000..0f36dbdf --- /dev/null +++ b/LEGO1/lego/legoomni/include/pizzeria.h @@ -0,0 +1,42 @@ +#ifndef PIZZERIA_H +#define PIZZERIA_H + +#include "decomp.h" +#include "isleactor.h" + +class PizzeriaState; +class PizzaMissionState; + +// VTABLE: LEGO1 0x100d5520 +// SIZE 0x84 +class Pizzeria : public IsleActor { +public: + Pizzeria() : m_pizzeriaState(NULL) {} + + // FUNCTION: LEGO1 0x1000e780 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0380 + return "Pizzeria"; + } + + // FUNCTION: LEGO1 0x1000e790 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Pizzeria::ClassName()) || IsleActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + undefined4 VTable0x68() override; // vtable+0x68 + + // SYNTHETIC: LEGO1 0x1000e8d0 + // Pizzeria::`scalar deleting destructor' + +private: + void Init(); + + PizzeriaState* m_pizzeriaState; // 0x7c + PizzaMissionState* m_pizzaMissionState; // 0x80 +}; + +#endif // PIZZERIA_H diff --git a/LEGO1/lego/legoomni/include/pizzeriastate.h b/LEGO1/lego/legoomni/include/pizzeriastate.h new file mode 100644 index 00000000..6ddd23cd --- /dev/null +++ b/LEGO1/lego/legoomni/include/pizzeriastate.h @@ -0,0 +1,44 @@ +#ifndef PIZZERIASTATE_H +#define PIZZERIASTATE_H + +#include "legostate.h" + +// SIZE 0x14 +struct PizzeriaStateStruct { + undefined4 m_unk0x00; // 0x00 + undefined4 m_unk0x04; // 0x04 + undefined4 m_unk0x08; // 0x08 + undefined4 m_unk0x0c; // 0x0c + undefined4 m_unk0x10; // 0x10 +}; + +// VTABLE: LEGO1 0x100d5ee8 +// SIZE 0x58 +class PizzeriaState : public LegoState { +public: + PizzeriaState(); + + // FUNCTION: LEGO1 0x10017c20 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0370 + return "PizzeriaState"; + } + + // FUNCTION: LEGO1 0x10017c30 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, PizzeriaState::ClassName()) || LegoState::IsA(p_name); + } + + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + // SYNTHETIC: LEGO1 0x10017ce0 + // PizzeriaState::`scalar deleting destructor' + +private: + Playlist m_unk0x08[5]; // 0x08 + PizzeriaStateStruct m_unk0x44; // 0x44 +}; + +#endif // PIZZERIASTATE_H diff --git a/LEGO1/lego/legoomni/include/police.h b/LEGO1/lego/legoomni/include/police.h new file mode 100644 index 00000000..4ba7ac20 --- /dev/null +++ b/LEGO1/lego/legoomni/include/police.h @@ -0,0 +1,55 @@ +#ifndef POLICE_H +#define POLICE_H + +#include "decomp.h" +#include "legogamestate.h" +#include "legoworld.h" +#include "radio.h" + +class LegoControlManagerEvent; +class LegoEventNotificationParam; +class MxDSAction; +class PoliceState; + +// VTABLE: LEGO1 0x100d8a80 +// SIZE 0x110 +class Police : public LegoWorld { +public: + Police(); + ~Police() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x1005e1e0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0450 + return "Police"; + } + + // FUNCTION: LEGO1 0x1005e1f0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Police::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x5c() override; // vtable+0x5c + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + // SYNTHETIC: LEGO1 0x1005e300 + // Police::`scalar deleting destructor' + +private: + MxLong HandleClick(LegoControlManagerEvent& p_param); + MxLong HandleEndAction(MxEndActionNotificationParam& p_param); + MxLong HandleKeyPress(LegoEventNotificationParam& p_param); + + Radio m_radio; // 0xf8 + PoliceState* m_policeState; // 0x108 + LegoGameState::Area m_destLocation; // 0x10c +}; + +#endif // POLICE_H diff --git a/LEGO1/lego/legoomni/include/policeentity.h b/LEGO1/lego/legoomni/include/policeentity.h new file mode 100644 index 00000000..48156150 --- /dev/null +++ b/LEGO1/lego/legoomni/include/policeentity.h @@ -0,0 +1,29 @@ +#ifndef POLICEENTITY_H +#define POLICEENTITY_H + +#include "buildingentity.h" + +// VTABLE: LEGO1 0x100d4ab0 +// SIZE 0x68 +class PoliceEntity : public BuildingEntity { +public: + // FUNCTION: LEGO1 0x1000ed60 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0328 + return "PoliceEntity"; + } + + // FUNCTION: LEGO1 0x1000ed70 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, PoliceEntity::ClassName()) || BuildingEntity::IsA(p_name); + } + + MxLong VTable0x50(MxParam& p_param) override; // vtable+0x50 + + // SYNTHETIC: LEGO1 0x1000f900 + // PoliceEntity::`scalar deleting destructor' +}; + +#endif // POLICEENTITY_H diff --git a/LEGO1/lego/legoomni/include/policestate.h b/LEGO1/lego/legoomni/include/policestate.h new file mode 100644 index 00000000..75970729 --- /dev/null +++ b/LEGO1/lego/legoomni/include/policestate.h @@ -0,0 +1,43 @@ +#ifndef POLICESTATE_H +#define POLICESTATE_H + +#include "actionsfwd.h" +#include "decomp.h" +#include "legostate.h" + +// VTABLE: LEGO1 0x100d8af0 +// SIZE 0x10 +class PoliceState : public LegoState { +public: + PoliceState(); + ~PoliceState() override {} + + // FUNCTION: LEGO1 0x1005e860 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0444 + return "PoliceState"; + } + + // FUNCTION: LEGO1 0x1005e870 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, PoliceState::ClassName()) || LegoState::IsA(p_name); + } + + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + // SYNTHETIC: LEGO1 0x1005e920 + // PoliceState::`scalar deleting destructor' + + inline undefined4 GetUnknown0x0c() { return m_unk0x0c; } + inline void SetUnknown0x0c(undefined4 p_unk0x0c) { m_unk0x0c = p_unk0x0c; } + + void FUN_1005ea40(); + +private: + PoliceScript::Script m_policeScript; // 0x08 + undefined4 m_unk0x0c; // 0x0c +}; + +#endif // POLICESTATE_H diff --git a/LEGO1/lego/legoomni/include/racecar.h b/LEGO1/lego/legoomni/include/racecar.h new file mode 100644 index 00000000..462c2dbe --- /dev/null +++ b/LEGO1/lego/legoomni/include/racecar.h @@ -0,0 +1,38 @@ +#ifndef RACECAR_H +#define RACECAR_H + +#include "decomp.h" +#include "islepathactor.h" + +// VTABLE: LEGO1 0x100d6918 +// SIZE 0x164 +class RaceCar : public IslePathActor { +public: + RaceCar(); + ~RaceCar() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x10028270 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03e0 + return "RaceCar"; + } + + // FUNCTION: LEGO1 0x10028280 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, RaceCar::ClassName()) || IslePathActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + MxU32 VTable0xcc() override; // vtable+0xcc + + // SYNTHETIC: LEGO1 0x10028400 + // RaceCar::`scalar deleting destructor' + +private: + // TODO: RaceCar fields + undefined m_unk0x160[4]; +}; + +#endif // RACECAR_H diff --git a/LEGO1/lego/legoomni/include/raceskel.h b/LEGO1/lego/legoomni/include/raceskel.h new file mode 100644 index 00000000..6d9a270b --- /dev/null +++ b/LEGO1/lego/legoomni/include/raceskel.h @@ -0,0 +1,19 @@ +#ifndef RACESKEL_H +#define RACESKEL_H + +#include "legoanimactor.h" + +/* + VTABLE: LEGO1 0x100d7668 LegoPathActor + VTABLE: LEGO1 0x100d7738 LegoAnimActor +*/ +// SIZE 0x178 +class RaceSkel : public LegoAnimActor { +public: + RaceSkel(); + +private: + undefined4 m_unk0x1c; // 0x1c +}; + +#endif // RACESKEL_H diff --git a/LEGO1/lego/legoomni/include/racestandsentity.h b/LEGO1/lego/legoomni/include/racestandsentity.h new file mode 100644 index 00000000..22bc4dd2 --- /dev/null +++ b/LEGO1/lego/legoomni/include/racestandsentity.h @@ -0,0 +1,28 @@ +#ifndef RACESTANDSENTITY_H +#define RACESTANDSENTITY_H + +#include "buildingentity.h" + +// VTABLE: LEGO1 0x100d48a8 +// SIZE 0x68 +class RaceStandsEntity : public BuildingEntity { + // FUNCTION: LEGO1 0x1000efa0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0300 + return "RaceStandsEntity"; + } + + // FUNCTION: LEGO1 0x1000efb0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, RaceStandsEntity::ClassName()) || BuildingEntity::IsA(p_name); + } + + MxLong VTable0x50(MxParam& p_param) override; + + // SYNTHETIC: LEGO1 0x1000f9e0 + // RaceStandsEntity::`scalar deleting destructor' +}; + +#endif // RACESTANDSENTITY_H diff --git a/LEGO1/lego/legoomni/include/racestate.h b/LEGO1/lego/legoomni/include/racestate.h new file mode 100644 index 00000000..e2321be1 --- /dev/null +++ b/LEGO1/lego/legoomni/include/racestate.h @@ -0,0 +1,54 @@ +#ifndef RACESTATE_H +#define RACESTATE_H + +#include "legostate.h" + +// SIZE 0x06 +struct RaceStateEntry { +public: + inline MxS16 GetUnknown0x02() { return m_unk0x02; } + inline MxU16 GetScore() { return m_score; } + + // TODO: Possibly private + MxU8 m_id; // 0x00 + MxS16 m_unk0x02; // 0x02 + MxU16 m_score; // 0x04 +}; + +// VTABLE: LEGO1 0x100d5e30 +// SIZE 0x2c +class RaceState : public LegoState { +public: + RaceState(); + + // FUNCTION: LEGO1 0x10016010 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f07d0 + return "RaceState"; + } + + // FUNCTION: LEGO1 0x10016020 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, RaceState::ClassName()) || LegoState::IsA(p_name); + } + + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + RaceStateEntry* GetState(MxU8 p_id); + + inline undefined4 GetUnknown0x28() { return m_unk0x28; } + + // SYNTHETIC: LEGO1 0x1000f6f0 + // RaceState::~RaceState + + // SYNTHETIC: LEGO1 0x100160d0 + // RaceState::`scalar deleting destructor' + +protected: + RaceStateEntry m_state[5]; // 0x08 + undefined4 m_unk0x28; // 0x28 +}; + +#endif // RACESTATE_H diff --git a/LEGO1/lego/legoomni/include/radio.h b/LEGO1/lego/legoomni/include/radio.h new file mode 100644 index 00000000..3c35a300 --- /dev/null +++ b/LEGO1/lego/legoomni/include/radio.h @@ -0,0 +1,52 @@ +#ifndef RADIO_H +#define RADIO_H + +#include "mxcore.h" + +class LegoControlManagerEvent; +class MxEndActionNotificationParam; +class RadioState; + +// VTABLE: LEGO1 0x100d6d10 +// SIZE 0x10 +class Radio : public MxCore { +public: + Radio(); + ~Radio() override; + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x1002c8e0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f328c + return "Radio"; + } + + // FUNCTION: LEGO1 0x1002c8f0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Radio::ClassName()) || MxCore::IsA(p_name); + } + + void Initialize(MxBool p_und); + void Play(); + void Stop(); + + inline RadioState* GetState() { return m_state; } + + // SYNTHETIC: LEGO1 0x1002c970 + // Radio::`scalar deleting destructor' + +private: + void CreateRadioState(); + + RadioState* m_state; // 0x08 + MxBool m_unk0x0c; // 0x0c + MxBool m_audioEnabled; // 0x0d + + MxLong HandleEndAction(MxEndActionNotificationParam& p_param); + MxLong HandleClick(LegoControlManagerEvent& p_param); +}; + +#endif // RADIO_H diff --git a/LEGO1/lego/legoomni/include/radiostate.h b/LEGO1/lego/legoomni/include/radiostate.h new file mode 100644 index 00000000..e0c0066c --- /dev/null +++ b/LEGO1/lego/legoomni/include/radiostate.h @@ -0,0 +1,45 @@ +#ifndef RADIOSTATE_H +#define RADIOSTATE_H + +#include "legostate.h" + +class MxAtomId; + +// VTABLE: LEGO1 0x100d6d28 +// SIZE 0x30 +class RadioState : public LegoState { +public: + RadioState(); + + // FUNCTION: LEGO1 0x1002cf60 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f04f8 + return "RadioState"; + } + + // FUNCTION: LEGO1 0x1002cf70 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, RadioState::ClassName()) || LegoState::IsA(p_name); + } + + MxBool IsSerializable() override; // vtable+0x14 + + // SYNTHETIC: LEGO1 0x1002d020 + // RadioState::`scalar deleting destructor' + + inline MxBool IsActive() { return m_active; } + + inline void SetActive(MxBool p_active) { m_active = p_active; } + + undefined4 FUN_1002d090(); + MxBool FUN_1002d0c0(const MxAtomId& p_atom, MxU32 p_objectId); + +private: + Playlist m_unk0x08[3]; // 0x08 + MxS16 m_unk0x2c; // 0x2c + MxBool m_active; // 0x2e +}; + +#endif // RADIOSTATE_H diff --git a/LEGO1/lego/legoomni/include/registrationbook.h b/LEGO1/lego/legoomni/include/registrationbook.h new file mode 100644 index 00000000..1266d29b --- /dev/null +++ b/LEGO1/lego/legoomni/include/registrationbook.h @@ -0,0 +1,75 @@ +#ifndef REGISTRATIONBOOK_H +#define REGISTRATIONBOOK_H + +#include "legoworld.h" + +class InfocenterState; +class MxControlPresenter; +class MxEndActionNotificationParam; +class MxStillPresenter; +class LegoControlManagerEvent; + +// VTABLE: LEGO1 0x100d9928 +// SIZE 0x2d0 +class RegistrationBook : public LegoWorld { +public: + RegistrationBook(); + ~RegistrationBook() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x10076e10 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f04c8 + return "RegistrationBook"; + } + + // FUNCTION: LEGO1 0x10076e20 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, RegistrationBook::ClassName()) || LegoWorld::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + inline void PlayAction(MxU32 p_objectId); + + // SYNTHETIC: LEGO1 0x10076f30 + // RegistrationBook::`scalar deleting destructor' + +private: + MxS32 m_registerDialogueTimer; // 0xf8 + undefined m_unk0xfc; // 0xfc + undefined m_unk0xfd[3]; // 0xfd + MxStillPresenter* m_alphabet[26]; // 0x100 + MxStillPresenter* m_name[10][7]; // 0x168 + struct { + MxS16 m_letters[7]; // 0x00 + MxS16 m_cursorPos; // 0x0e + } m_unk0x280; // 0x280 + MxControlPresenter* m_checkmark[10]; // 0x290 + undefined2 m_unk0x2b8; // 0x2b8 + InfocenterState* m_infocenterState; // 0x2bc + undefined m_unk0x2c0; // 0x2c0 + undefined m_unk0x2c1; // 0x2c1 + undefined m_unk0x2c2[0x02]; // 0x2c2 + LPDIRECTDRAWSURFACE m_checkboxHilite; // 0x2c4 + LPDIRECTDRAWSURFACE m_checkboxSurface; // 0x2c8 + LPDIRECTDRAWSURFACE m_checkboxNormal; // 0x2cc + + MxLong HandleEndAction(MxEndActionNotificationParam& p_param); + MxLong HandleKeyPress(MxU8 p_key); + MxLong HandleClick(LegoControlManagerEvent& p_param); + MxLong HandleNotification19(MxParam& p_param); + void FUN_100775c0(MxS16 p_playerIndex); + void WriteInfocenterLetters(MxS16); + void FUN_100778c0(); + MxBool CreateSurface(); +}; + +#endif // REGISTRATIONBOOK_H diff --git a/LEGO1/lego/legoomni/include/score.h b/LEGO1/lego/legoomni/include/score.h new file mode 100644 index 00000000..71efd0f4 --- /dev/null +++ b/LEGO1/lego/legoomni/include/score.h @@ -0,0 +1,54 @@ +#ifndef SCORE_H +#define SCORE_H + +#include "legogamestate.h" +#include "legoworld.h" + +class LegoControlManagerEvent; +class MxEndActionNotificationParam; +class ScoreState; + +// VTABLE: LEGO1 0x100d4018 +// SIZE 0x104 +class Score : public LegoWorld { +public: + Score(); + ~Score() override; + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x100010c0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0050 + return "Score"; + } + + // FUNCTION: LEGO1 0x100010d0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, Score::ClassName()) || LegoWorld::IsA(p_name); + } + + // SYNTHETIC: LEGO1 0x100011e0 + // Score::`scalar deleting destructor' + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool VTable0x5c() override; // vtable+0x5c + MxBool VTable0x64() override; // vtable+0x64 + void Enable(MxBool p_enable) override; // vtable+0x68 + + void Paint(); + MxLong FUN_10001510(MxEndActionNotificationParam& p_param); + MxLong FUN_100016d0(LegoControlManagerEvent& p_param); + void FillArea(MxU32 i_activity, MxU32 i_actor, MxS16 score); + +protected: + void DeleteScript(); + + LegoGameState::Area m_destLocation; // 0xf8 + ScoreState* m_state; // 0xfc + MxU8* m_surface; // 0x100 +}; + +#endif // SCORE_H diff --git a/LEGO1/lego/legoomni/include/scorestate.h b/LEGO1/lego/legoomni/include/scorestate.h new file mode 100644 index 00000000..ac651a19 --- /dev/null +++ b/LEGO1/lego/legoomni/include/scorestate.h @@ -0,0 +1,36 @@ +#ifndef SCORESTATE_H +#define SCORESTATE_H + +#include "legostate.h" + +// VTABLE: LEGO1 0x100d53f8 +// SIZE 0x0c +class ScoreState : public LegoState { +public: + // FUNCTION: LEGO1 0x1000de40 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0084 + return "ScoreState"; + } + + // FUNCTION: LEGO1 0x1000de50 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, ScoreState::ClassName()) || LegoState::IsA(p_name); + } + + MxBool IsSerializable() override; // vtable+0x14 + MxBool SetFlag() override; // vtable+0x18 + + inline MxBool GetTutorialFlag() { return m_playCubeTutorial; } + inline void SetTutorialFlag(MxBool p_playCubeTutorial) { m_playCubeTutorial = p_playCubeTutorial; } + + // SYNTHETIC: LEGO1 0x1000df00 + // ScoreState::`scalar deleting destructor' + +private: + MxBool m_playCubeTutorial; // 0x08 +}; + +#endif // SCORESTATE_H diff --git a/LEGO1/lego/legoomni/include/scripts.h b/LEGO1/lego/legoomni/include/scripts.h new file mode 100644 index 00000000..a47c8995 --- /dev/null +++ b/LEGO1/lego/legoomni/include/scripts.h @@ -0,0 +1,39 @@ +#ifndef SCRIPTS_H +#define SCRIPTS_H + +class MxAtomId; + +extern MxAtomId* g_copterScript; +extern MxAtomId* g_dunecarScript; +extern MxAtomId* g_jetskiScript; +extern MxAtomId* g_racecarScript; +extern MxAtomId* g_carraceScript; +extern MxAtomId* g_carracerScript; +extern MxAtomId* g_jetraceScript; +extern MxAtomId* g_jetracerScript; +extern MxAtomId* g_isleScript; +extern MxAtomId* g_elevbottScript; +extern MxAtomId* g_infodoorScript; +extern MxAtomId* g_infomainScript; +extern MxAtomId* g_infoscorScript; +extern MxAtomId* g_regbookScript; +extern MxAtomId* g_histbookScript; +extern MxAtomId* g_hospitalScript; +extern MxAtomId* g_policeScript; +extern MxAtomId* g_garageScript; +extern MxAtomId* g_act2mainScript; +extern MxAtomId* g_act3Script; +extern MxAtomId* g_jukeboxScript; +extern MxAtomId* g_pz5Script; +extern MxAtomId* g_introScript; +extern MxAtomId* g_testScript; +extern MxAtomId* g_jukeboxwScript; +extern MxAtomId* g_sndAnimScript; +extern MxAtomId* g_creditsScript; +extern MxAtomId* g_nocdSourceName; + +void CreateScripts(); +void DestroyScripts(); +const char* GetNoCD_SourceName(); + +#endif // SCRIPTS_H diff --git a/LEGO1/lego/legoomni/include/skateboard.h b/LEGO1/lego/legoomni/include/skateboard.h new file mode 100644 index 00000000..63a2bb87 --- /dev/null +++ b/LEGO1/lego/legoomni/include/skateboard.h @@ -0,0 +1,47 @@ +#ifndef SKATEBOARD_H +#define SKATEBOARD_H + +#include "decomp.h" +#include "islepathactor.h" + +class Act1State; + +// VTABLE: LEGO1 0x100d55f0 +// SIZE 0x168 +class SkateBoard : public IslePathActor { +public: + SkateBoard(); + ~SkateBoard() override; + + // FUNCTION: LEGO1 0x1000fdd0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f041c + return "SkateBoard"; + } + + // FUNCTION: LEGO1 0x1000fde0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, SkateBoard::ClassName()) || IslePathActor::IsA(p_name); + } + + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + MxU32 VTable0xcc() override; // vtable+0xcc + MxU32 VTable0xd0() override; // vtable+0xd0 + MxU32 VTable0xd4(LegoControlManagerEvent& p_param) override; // vtable+0xd4 + void VTable0xe4() override; // vtable+0xe4 + + void FUN_10010510(); + + // SYNTHETIC: LEGO1 0x1000ff60 + // SkateBoard::`scalar deleting destructor' + +private: + void FUN_10010270(MxBool p_enable); + + MxBool m_unk0x160; // 0x160 + Act1State* m_act1state; // 0x164 +}; + +#endif // SKATEBOARD_H diff --git a/LEGO1/lego/legoomni/include/towtrack.h b/LEGO1/lego/legoomni/include/towtrack.h new file mode 100644 index 00000000..056f0793 --- /dev/null +++ b/LEGO1/lego/legoomni/include/towtrack.h @@ -0,0 +1,55 @@ +#ifndef TOWTRACK_H +#define TOWTRACK_H + +#include "decomp.h" +#include "islepathactor.h" + +// VTABLE: LEGO1 0x100d7ee0 +// SIZE 0x180 +class TowTrack : public IslePathActor { +public: + TowTrack(); + + // FUNCTION: LEGO1 0x1004c7c0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f03b8 + return "TowTrack"; + } + + // FUNCTION: LEGO1 0x1004c7d0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, TowTrack::ClassName()) || IslePathActor::IsA(p_name); + } + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void VTable0x70(float p_float) override; // vtable+0x70 + MxU32 VTable0xcc() override; // vtable+0xcc + MxU32 VTable0xd4(LegoControlManagerEvent& p_param) override; // vtable+0xd4 + MxU32 VTable0xd8(LegoEndAnimNotificationParam& p_param) override; // vtable+0xd8 + MxU32 VTable0xdc(MxType19NotificationParam& p_param) override; // vtable+0xdc + void VTable0xe4() override; // vtable+0xe4 + + void FUN_1004dab0(); + void FUN_1004dad0(); + + // SYNTHETIC: LEGO1 0x1004c950 + // TowTrack::`scalar deleting destructor' + +private: + // TODO: TowTrack field types + undefined m_unk0x154[4]; + MxS32 m_unk0x164; + MxS16 m_unk0x168; + MxS16 m_unk0x16a; + MxS16 m_unk0x16c; + MxS16 m_unk0x16e; + MxS32 m_unk0x170; + MxS32 m_unk0x174; + MxFloat m_unk0x178; + undefined4 m_unk0x17c; +}; + +#endif // TOWTRACK_H diff --git a/LEGO1/lego/legoomni/include/towtrackmissionstate.h b/LEGO1/lego/legoomni/include/towtrackmissionstate.h new file mode 100644 index 00000000..da9361f2 --- /dev/null +++ b/LEGO1/lego/legoomni/include/towtrackmissionstate.h @@ -0,0 +1,64 @@ +#ifndef TOWTRACKMISSIONSTATE_H +#define TOWTRACKMISSIONSTATE_H + +#include "legostate.h" + +// VTABLE: LEGO1 0x100d7fd8 +// SIZE 0x28 +class TowTrackMissionState : public LegoState { +public: + TowTrackMissionState(); + + // FUNCTION: LEGO1 0x1004dfa0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f00bc + return "TowTrackMissionState"; + } + + // FUNCTION: LEGO1 0x1004dfb0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, TowTrackMissionState::ClassName()) || LegoState::IsA(p_name); + } + + MxResult Serialize(LegoFile* p_legoFile) override; // vtable+0x1c + + inline MxU16 GetScore(MxU8 p_id) + { + switch (p_id) { + case 1: + return m_score1; + case 2: + return m_score2; + case 3: + return m_score3; + case 4: + return m_score4; + case 5: + return m_score5; + default: + return 0; + } + } + + // SYNTHETIC: LEGO1 0x1004e060 + // TowTrackMissionState::`scalar deleting destructor' + +protected: + undefined4 m_unk0x08; // 0x08 + undefined4 m_unk0x0c; // 0x0c + MxU8 m_unk0x10; // 0x10 + MxU16 m_unk0x12; // 0x12 + MxU16 m_unk0x14; // 0x14 + MxU16 m_unk0x16; // 0x16 + MxU16 m_unk0x18; // 0x18 + MxU16 m_unk0x1a; // 0x1a + MxU16 m_score1; // 0x1c + MxU16 m_score2; // 0x1e + MxU16 m_score3; // 0x20 + MxU16 m_score4; // 0x22 + MxU16 m_score5; // 0x24 +}; + +#endif // TOWTRACKMISSIONSTATE_H diff --git a/LEGO1/lego/legoomni/src/act1/act1state.cpp b/LEGO1/lego/legoomni/src/act1/act1state.cpp new file mode 100644 index 00000000..013347d3 --- /dev/null +++ b/LEGO1/lego/legoomni/src/act1/act1state.cpp @@ -0,0 +1,296 @@ +#include "act1state.h" + +#include "legonamedtexture.h" +#include "legoutils.h" + +DECOMP_SIZE_ASSERT(Act1State, 0x26c) +DECOMP_SIZE_ASSERT(Act1State::NamedPlane, 0x4c) + +// GLOBAL: ISLE 0x100f37f0 +MxS32 g_unk0x100f37f0[] = { + Act1State::e_unk953, + Act1State::e_unk954, + Act1State::e_unk955, +}; + +extern MxAtomId* g_isleScript; + +// STUB: LEGO1 0x100334b0 +Act1State::Act1State() : m_unk0x00c(0), m_unk0x00e(0), m_unk0x008(NULL), m_unk0x010(0) +{ + m_unk0x01e = FALSE; + m_unk0x018 = 1; + m_unk0x010 = 0; + m_planeActive = FALSE; + m_unk0x00e = 0; + m_unk0x01f = FALSE; + m_unk0x008 = g_unk0x100f37f0; + m_unk0x014 = -1; + m_unk0x022 = FALSE; + m_unk0x154 = NULL; + m_unk0x158 = NULL; + m_unk0x15c = NULL; + m_unk0x160 = NULL; + m_unk0x1b0 = NULL; + m_unk0x021 = 1; + m_elevFloor = Act1State::c_floor1; + m_unk0x00c = sizeOfArray(g_unk0x100f37f0); + m_unk0x1b4 = NULL; + m_unk0x1b8 = NULL; + m_unk0x208 = NULL; + m_unk0x20c = NULL; + m_unk0x25c = NULL; + m_unk0x260 = NULL; + m_unk0x264 = NULL; + m_unk0x268 = NULL; + SetFlag(); +} + +// FUNCTION: LEGO1 0x10033ac0 +MxResult Act1State::Serialize(LegoFile* p_legoFile) +{ + LegoState::Serialize(p_legoFile); + + m_unk0x024.Serialize(p_legoFile); + m_unk0x070.Serialize(p_legoFile); + m_unk0x0bc.Serialize(p_legoFile); + m_unk0x108.Serialize(p_legoFile); + m_unk0x164.Serialize(p_legoFile); + m_unk0x1bc.Serialize(p_legoFile); + m_unk0x210.Serialize(p_legoFile); + + if (p_legoFile->IsWriteMode()) { + if (m_unk0x108.GetName()->Compare("") != 0) { + if (m_unk0x154) { + WriteNamedTexture(p_legoFile, m_unk0x154); + } + else { + FUN_1003f540(p_legoFile, "chwind.gif"); + } + if (m_unk0x158) { + WriteNamedTexture(p_legoFile, m_unk0x158); + } + else { + FUN_1003f540(p_legoFile, "chjetl.gif"); + } + if (m_unk0x15c) { + WriteNamedTexture(p_legoFile, m_unk0x15c); + } + else { + FUN_1003f540(p_legoFile, "chjetr.gif"); + } + } + if (m_unk0x164.GetName()->Compare("") != 0) { + if (m_unk0x1b0) { + WriteNamedTexture(p_legoFile, m_unk0x1b0); + } + else { + FUN_1003f540(p_legoFile, "jsfrnt.gif"); + } + if (m_unk0x1b4) { + WriteNamedTexture(p_legoFile, m_unk0x1b4); + } + else { + FUN_1003f540(p_legoFile, "jswnsh.gif"); + } + } + if (m_unk0x1bc.GetName()->Compare("") != 0) { + if (m_unk0x208) { + WriteNamedTexture(p_legoFile, m_unk0x208); + } + else { + FUN_1003f540(p_legoFile, "dbfrfn.gif"); + } + } + if (m_unk0x210.GetName()->Compare("") != 0) { + if (m_unk0x25c) { + WriteNamedTexture(p_legoFile, m_unk0x25c); + } + else { + FUN_1003f540(p_legoFile, "rcfrnt.gif"); + } + if (m_unk0x260) { + WriteNamedTexture(p_legoFile, m_unk0x260); + } + else { + FUN_1003f540(p_legoFile, "rcback.gif"); + } + if (m_unk0x264) { + WriteNamedTexture(p_legoFile, m_unk0x264); + } + else { + FUN_1003f540(p_legoFile, "rctail.gif"); + } + } + + p_legoFile->Write(&m_unk0x010, sizeof(m_unk0x010)); + p_legoFile->Write(&m_unk0x022, sizeof(m_unk0x022)); + } + else if (p_legoFile->IsReadMode()) { + if (m_unk0x108.GetName()->Compare("") != 0) { + m_unk0x154 = ReadNamedTexture(p_legoFile); + if (m_unk0x154 == NULL) { + return FAILURE; + } + + m_unk0x158 = ReadNamedTexture(p_legoFile); + if (m_unk0x158 == NULL) { + return FAILURE; + } + + m_unk0x15c = ReadNamedTexture(p_legoFile); + if (m_unk0x15c == NULL) { + return FAILURE; + } + } + if (m_unk0x164.GetName()->Compare("") != 0) { + m_unk0x1b0 = ReadNamedTexture(p_legoFile); + if (m_unk0x1b0 == NULL) { + return FAILURE; + } + + m_unk0x1b4 = ReadNamedTexture(p_legoFile); + if (m_unk0x1b4 == NULL) { + return FAILURE; + } + } + if (m_unk0x1bc.GetName()->Compare("") != 0) { + m_unk0x208 = ReadNamedTexture(p_legoFile); + if (m_unk0x208 == NULL) { + return FAILURE; + } + } + if (m_unk0x210.GetName()->Compare("") != 0) { + m_unk0x25c = ReadNamedTexture(p_legoFile); + if (m_unk0x25c == NULL) { + return FAILURE; + } + + m_unk0x260 = ReadNamedTexture(p_legoFile); + if (m_unk0x260 == NULL) { + return FAILURE; + } + + m_unk0x264 = ReadNamedTexture(p_legoFile); + if (m_unk0x264 == NULL) { + return FAILURE; + } + } + + p_legoFile->Read(&m_unk0x010, sizeof(m_unk0x010)); + p_legoFile->Read(&m_unk0x022, sizeof(m_unk0x022)); + } + + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10034660 +void Act1State::FUN_10034660() +{ + // TODO +} + +// FUNCTION: LEGO1 0x100346a0 +void Act1State::FUN_100346a0() +{ + if (m_unk0x014 != -1) { + InvokeAction(Extra::e_stop, *g_isleScript, m_unk0x014, NULL); + m_unk0x014 = -1; + } +} + +// FUNCTION: LEGO1 0x100346d0 +MxBool Act1State::SetFlag() +{ + m_unk0x024.SetName(""); + m_unk0x070.SetName(""); + m_unk0x0bc.SetName(""); + m_unk0x022 = FALSE; + m_unk0x108.SetName(""); + + if (m_unk0x154) { + delete m_unk0x154; + m_unk0x154 = NULL; + } + + if (m_unk0x158) { + delete m_unk0x158; + m_unk0x158 = NULL; + } + + if (m_unk0x15c) { + delete m_unk0x15c; + m_unk0x15c = NULL; + } + + if (m_unk0x160) { + delete m_unk0x160; + m_unk0x160 = NULL; + } + + m_unk0x164.SetName(""); + + if (m_unk0x1b0) { + delete m_unk0x1b0; + m_unk0x1b0 = NULL; + } + + if (m_unk0x1b4) { + delete m_unk0x1b4; + m_unk0x1b4 = NULL; + } + + if (m_unk0x1b8) { + delete m_unk0x1b8; + m_unk0x1b8 = NULL; + } + + m_unk0x1bc.SetName(""); + + if (m_unk0x208) { + delete m_unk0x208; + m_unk0x208 = NULL; + } + + if (m_unk0x20c) { + delete m_unk0x20c; + m_unk0x20c = NULL; + } + + m_unk0x210.SetName(""); + + if (m_unk0x25c) { + delete m_unk0x25c; + m_unk0x25c = NULL; + } + + if (m_unk0x260) { + delete m_unk0x260; + m_unk0x260 = NULL; + } + + if (m_unk0x264) { + delete m_unk0x264; + m_unk0x264 = NULL; + } + + if (m_unk0x268) { + delete m_unk0x268; + m_unk0x268 = NULL; + } + + return TRUE; +} + +// STUB: LEGO1 0x10034b60 +void Act1State::FUN_10034b60() +{ + // TODO +} + +// STUB: LEGO1 0x10034d00 +void Act1State::FUN_10034d00() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/act2/legoact2state.cpp b/LEGO1/lego/legoomni/src/act2/legoact2state.cpp new file mode 100644 index 00000000..955de04e --- /dev/null +++ b/LEGO1/lego/legoomni/src/act2/legoact2state.cpp @@ -0,0 +1,9 @@ +#include "legoact2state.h" + +DECOMP_SIZE_ASSERT(LegoAct2State, 0x10) + +// FUNCTION: LEGO1 0x1000df70 +MxBool LegoAct2State::IsSerializable() +{ + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/act3/act3shark.cpp b/LEGO1/lego/legoomni/src/act3/act3shark.cpp new file mode 100644 index 00000000..8cc9f698 --- /dev/null +++ b/LEGO1/lego/legoomni/src/act3/act3shark.cpp @@ -0,0 +1,28 @@ +#include "act3shark.h" + +DECOMP_SIZE_ASSERT(Act3Shark, 0x1a8) + +// STUB: LEGO1 0x10042ab0 +Act3Shark::Act3Shark() +{ + // TODO +} + +// STUB: LEGO1 0x10042ce0 +MxResult Act3Shark::FUN_10042ce0(void*) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10042d40 +void Act3Shark::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x10042f30 +void Act3Shark::ParseAction(char*) +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/act3/act3state.cpp b/LEGO1/lego/legoomni/src/act3/act3state.cpp new file mode 100644 index 00000000..de1bac5f --- /dev/null +++ b/LEGO1/lego/legoomni/src/act3/act3state.cpp @@ -0,0 +1,9 @@ +#include "act3state.h" + +DECOMP_SIZE_ASSERT(Act3State, 0x0c) + +// FUNCTION: LEGO1 0x1000e2f0 +MxBool Act3State::IsSerializable() +{ + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/actors/act2actor.cpp b/LEGO1/lego/legoomni/src/actors/act2actor.cpp new file mode 100644 index 00000000..bd187361 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/act2actor.cpp @@ -0,0 +1,55 @@ +#include "act2actor.h" + +DECOMP_SIZE_ASSERT(Act2Actor, 0x1a8) + +// STUB: LEGO1 0x100187e0 +Act2Actor::Act2Actor() +{ + // TODO +} + +// STUB: LEGO1 0x10018940 +void Act2Actor::SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2) +{ + // TODO +} + +// STUB: LEGO1 0x100189f0 +MxResult Act2Actor::VTable0x94(LegoPathActor*, MxBool) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10018a20 +MxResult Act2Actor::WaitForAnimation() +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10018c30 +void Act2Actor::VTable0x70(float p_und) +{ + // TODO +} + +// STUB: LEGO1 0x10019280 +void Act2Actor::SetWorldSpeed(MxFloat p_worldSpeed) +{ + // TODO +} + +// STUB: LEGO1 0x100195a0 +MxS32 Act2Actor::VTable0xa0() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1001a180 +MxS32 Act2Actor::VTable0x68(Vector3&, Vector3&, Vector3&) +{ + // TODO + return 0; +} diff --git a/LEGO1/lego/legoomni/src/actors/act3actor.cpp b/LEGO1/lego/legoomni/src/actors/act3actor.cpp new file mode 100644 index 00000000..5ae24f14 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/act3actor.cpp @@ -0,0 +1,23 @@ +#include "act3actor.h" + +DECOMP_SIZE_ASSERT(Act3Actor, 0x178) + +// STUB: LEGO1 0x1003fa50 +Act3Actor::Act3Actor() +{ + m_unk0x1c = 0; +} + +// STUB: LEGO1 0x1003fb70 +MxU32 Act3Actor::VTable0x90(float, Matrix4&) +{ + // TODO + return FALSE; +} + +// STUB: LEGO1 0x1003fd90 +MxResult Act3Actor::VTable0x94(LegoPathActor*, MxBool) +{ + // TODO + return 0; +} diff --git a/LEGO1/lego/legoomni/src/actors/ambulance.cpp b/LEGO1/lego/legoomni/src/actors/ambulance.cpp new file mode 100644 index 00000000..d793503b --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/ambulance.cpp @@ -0,0 +1,130 @@ +#include "ambulance.h" + +#include "ambulancemissionstate.h" +#include "decomp.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legovariables.h" +#include "legoworld.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "mxvariabletable.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(Ambulance, 0x184) + +// FUNCTION: LEGO1 0x10035ee0 +Ambulance::Ambulance() +{ + this->m_unk0x168 = 0; + this->m_unk0x16a = -1; + this->m_state = NULL; + this->m_unk0x16c = 0; + this->m_unk0x174 = -1; + this->m_unk0x16e = 0; + this->m_unk0x178 = -1; + this->m_unk0x170 = 0; + this->m_unk0x172 = 0; + this->m_unk0x13c = 40.0; + this->m_unk0x17c = 1.0; +} + +// FUNCTION: LEGO1 0x10035f90 +void Ambulance::Destroy(MxBool p_fromDestructor) +{ +} + +// FUNCTION: LEGO1 0x10036150 +Ambulance::~Ambulance() +{ + ControlManager()->Unregister(this); + TickleManager()->UnregisterClient(this); +} + +// FUNCTION: LEGO1 0x100361d0 +MxResult Ambulance::Create(MxDSAction& p_dsAction) +{ + MxResult result = IslePathActor::Create(p_dsAction); + + if (result == SUCCESS) { + m_world = CurrentWorld(); + + if (m_world) { + m_world->Add(this); + } + + m_state = (AmbulanceMissionState*) GameState()->GetState("AmbulanceMissionState"); + if (!m_state) { + m_state = new AmbulanceMissionState(); + m_state->SetUnknown0x08(0); + GameState()->RegisterState(m_state); + } + } + + VariableTable()->SetVariable(g_varAMBULFUEL, "1.0"); + m_unk0x17c = 1.0; + m_time = Timer()->GetTime(); + + return result; +} + +// STUB: LEGO1 0x10036300 +void Ambulance::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x10036420 +MxLong Ambulance::Notify(MxParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10036860 +MxU32 Ambulance::VTable0xdc(MxType19NotificationParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10036ce0 +MxU32 Ambulance::VTable0xcc() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10036e60 +void Ambulance::FUN_10036e60() +{ + // TODO +} + +// STUB: LEGO1 0x10036e90 +void Ambulance::VTable0xe4() +{ + // TODO +} + +// STUB: LEGO1 0x10036f90 +MxU32 Ambulance::VTable0xd4(LegoControlManagerEvent& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10037060 +void Ambulance::FUN_10037060() +{ + // TODO +} + +// STUB: LEGO1 0x10037160 +MxResult Ambulance::Tickle() +{ + // TODO + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/actors/bike.cpp b/LEGO1/lego/legoomni/src/actors/bike.cpp new file mode 100644 index 00000000..e6be2228 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/bike.cpp @@ -0,0 +1,65 @@ +#include "bike.h" + +#include "isle_actions.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(Bike, 0x164) + +// FUNCTION: LEGO1 0x10076670 +Bike::Bike() +{ + this->m_unk0x13c = 20.0; + this->m_unk0x150 = 3.0; + this->m_unk0x148 = 1; +} + +// FUNCTION: LEGO1 0x100768f0 +MxResult Bike::Create(MxDSAction& p_dsAction) +{ + MxResult result = IslePathActor::Create(p_dsAction); + m_world = CurrentWorld(); + + if (m_world) { + m_world->Add(this); + } + + return result; +} + +// FUNCTION: LEGO1 0x10076920 +void Bike::VTable0xe4() +{ + IslePathActor::VTable0xe4(); + GameState()->SetCurrentArea(LegoGameState::Area::e_bike); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_BikeDashboard_Bitmap); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_BikeArms_Ctl); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_BikeHorn_Ctl); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_BikeHorn_Sound); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_BikeInfo_Ctl); + ControlManager()->Unregister(this); +} + +// STUB: LEGO1 0x100769a0 +MxU32 Bike::VTable0xcc() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10076aa0 +MxU32 Bike::VTable0xd4(LegoControlManagerEvent& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10076b60 +void Bike::FUN_10076b60() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp b/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp new file mode 100644 index 00000000..22f9e696 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/bumpbouy.cpp @@ -0,0 +1,21 @@ +#include "bumpbouy.h" + +DECOMP_SIZE_ASSERT(BumpBouy, 0x174) + +// STUB: LEGO1 0x10027220 +BumpBouy::BumpBouy() +{ +} + +// STUB: LEGO1 0x10027360 +BumpBouy::~BumpBouy() +{ + // TODO +} + +// STUB: LEGO1 0x10027400 +MxLong BumpBouy::Notify(MxParam& p_param) +{ + // TODO + return 0; +} diff --git a/LEGO1/lego/legoomni/src/actors/doors.cpp b/LEGO1/lego/legoomni/src/actors/doors.cpp new file mode 100644 index 00000000..d4aedd7c --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/doors.cpp @@ -0,0 +1,22 @@ +#include "doors.h" + +DECOMP_SIZE_ASSERT(Doors, 0x1f8) + +// STUB: LEGO1 0x10066100 +MxResult Doors::VTable0x94(LegoPathActor* p_actor, MxBool p_bool) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10066250 +void Doors::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x100664e0 +void Doors::ParseAction(char*) +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp b/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp new file mode 100644 index 00000000..3331d82f --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/dunebuggy.cpp @@ -0,0 +1,58 @@ +#include "dunebuggy.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(DuneBuggy, 0x16c) + +// FUNCTION: LEGO1 0x10067bb0 +DuneBuggy::DuneBuggy() +{ + this->m_unk0x13c = 25.0; + this->m_unk0x164 = 1.0; +} + +// STUB: LEGO1 0x10067e30 +MxResult DuneBuggy::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10067ec0 +void DuneBuggy::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x10067fa0 +void DuneBuggy::VTable0xe4() +{ + // TODO +} + +// STUB: LEGO1 0x10068060 +MxU32 DuneBuggy::VTable0xcc() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x100681b0 +MxU32 DuneBuggy::VTable0xd4(LegoControlManagerEvent& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10068270 +MxU32 DuneBuggy::VTable0xdc(MxType19NotificationParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10068350 +void DuneBuggy::FUN_10068350() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/actors/helicopter.cpp b/LEGO1/lego/legoomni/src/actors/helicopter.cpp new file mode 100644 index 00000000..0bc064b5 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/helicopter.cpp @@ -0,0 +1,400 @@ +#include "helicopter.h" + +#include "act1state.h" +#include "act3.h" +#include "act3_actions.h" +#include "helicopterstate.h" +#include "isle.h" +#include "isle_actions.h" +#include "jukebox.h" +#include "jukebox_actions.h" +#include "legoanimationmanager.h" +#include "legocameracontroller.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(Helicopter, 0x230) +DECOMP_SIZE_ASSERT(Mx3DPointFloat, 0x14) +DECOMP_SIZE_ASSERT(Mx4DPointFloat, 0x18) +DECOMP_SIZE_ASSERT(MxMatrix, 0x48) + +// FUNCTION: LEGO1 0x10001e60 +Helicopter::Helicopter() +{ + m_unk0x13c = 60; +} + +// FUNCTION: LEGO1 0x10003230 +Helicopter::~Helicopter() +{ + ControlManager()->Unregister(this); + IslePathActor::Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100032c0 +MxResult Helicopter::Create(MxDSAction& p_dsAction) +{ + MxResult result = IslePathActor::Create(p_dsAction); + LegoWorld* world = CurrentWorld(); + SetWorld(world); + if (world->IsA("Act3")) { + ((Act3*) GetWorld())->SetUnknown420c(this); + } + world = GetWorld(); + if (world) { + world->Add(this); + } + GetState(); + return result; +} + +// FUNCTION: LEGO1 0x10003320 +void Helicopter::GetState() +{ + m_state = (HelicopterState*) GameState()->GetState("HelicopterState"); + if (!m_state) { + m_state = (HelicopterState*) GameState()->CreateState("HelicopterState"); + } +} + +// FUNCTION: LEGO1 0x10003360 +void Helicopter::VTable0xe4() +{ + if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { + SpawnPlayer( + LegoGameState::e_unk40, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + } + + IslePathActor::VTable0xe4(); + + if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { + GameState()->SetCurrentArea(LegoGameState::e_copter); + if (CurrentActor() && CurrentActor()->IsA("IslePathActor")) { + CurrentActor()->SpawnPlayer( + LegoGameState::e_unk55, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + } + } + + m_state->SetUnknown8(0); + RemoveFromCurrentWorld(m_script, IsleScript::c_HelicopterDashboard_Bitmap); + RemoveFromCurrentWorld(m_script, IsleScript::c_HelicopterArms_Ctl); + RemoveFromCurrentWorld(m_script, IsleScript::c_Helicopter_TakeOff_Ctl); + RemoveFromCurrentWorld(m_script, IsleScript::c_Helicopter_Land_Ctl); + RemoveFromCurrentWorld(m_script, Act3Script::c_Helicopter_Pizza_Ctl); + RemoveFromCurrentWorld(m_script, Act3Script::c_Helicopter_Donut_Ctl); + RemoveFromCurrentWorld(m_script, Act3Script::c_Helicopter_Info_Ctl); + RemoveFromCurrentWorld(m_script, 0x1d); + RemoveFromCurrentWorld(m_script, 0x1e); + RemoveFromCurrentWorld(m_script, 0x1f); + AnimationManager()->FUN_1005f6d0(TRUE); + ControlManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x10003480 +MxU32 Helicopter::VTable0xcc() +{ + if (!FUN_1003ef60()) { + return 1; + } + + if (!m_world) { + m_world = CurrentWorld(); + } + + AnimationManager()->FUN_1005f6d0(FALSE); + + if (CurrentActor()) { + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + } + + switch (GameState()->GetCurrentAct()) { + case LegoGameState::e_act1: + m_script = *g_isleScript; + AnimationManager()->FUN_10064670(NULL); + SpawnPlayer( + LegoGameState::e_unk41, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_copter); + FUN_10015820(TRUE, 0); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, TRUE); + SetState(4); + PlayMusic(JukeboxScript::c_Jail_Music); + break; + case LegoGameState::e_act2: + m_script = *g_act2mainScript; + break; + case LegoGameState::e_act3: + m_script = *g_act3Script; + break; + } + + VTable0xe0(); + InvokeAction(Extra::ActionType::e_start, m_script, IsleScript::c_HelicopterDashboard, NULL); + GetCurrentAction().SetObjectId(-1); + ControlManager()->Register(this); + return 1; +} + +// FUNCTION: LEGO1 0x100035e0 +MxU32 Helicopter::VTable0xd4(LegoControlManagerEvent& p_param) +{ + MxU32 ret = 0; + MxAtomId script; + + switch (GameState()->GetCurrentAct()) { + case LegoGameState::e_act1: + script = *g_isleScript; + break; + case LegoGameState::e_act2: + script = *g_act2mainScript; + break; + case LegoGameState::e_act3: + script = *g_act3Script; + break; + } + + if (p_param.GetUnknown0x28() == 1) { + switch (p_param.GetClickedObjectId()) { + case IsleScript::c_HelicopterArms_Ctl: + if (*g_act3Script == script) { + ((Act3*) CurrentWorld())->SetUnknown4270(2); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + else if (m_state->GetUnkown8() != 0) { + break; + } + VTable0xe4(); + GameState()->SetCurrentArea(LegoGameState::e_unk66); + ret = 1; + break; + case IsleScript::c_Helicopter_TakeOff_Ctl: { + if (*g_act3Script == script) { + break; + } + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + if (m_state->GetUnkown8() == 0) { + state->SetUnknown18(4); + m_state->SetUnknown8(1); + m_world->RemovePathActor(this); + InvokeAction(Extra::ActionType::e_start, script, IsleScript::c_HelicopterTakeOff_Anim, NULL); + SetState(0); + } + ret = 1; + break; + } + case IsleScript::c_Helicopter_Land_Ctl: + if (*g_act3Script == script) { + break; + } + if (m_state->GetUnkown8() == 2) { + m_state->SetUnknown8(3); + m_world->RemovePathActor(this); + InvokeAction(Extra::ActionType::e_start, script, IsleScript::c_HelicopterLand_Anim, NULL); + SetState(4); + } + ret = 1; + break; + case Act3Script::c_Helicopter_Pizza_Ctl: + if (*g_act3Script != script) { + break; + } + ret = 1; + /* fall through */ + case Act3Script::c_Helicopter_Donut_Ctl: + if (*g_act3Script != script) { + break; + } + if (m_world && m_world->GetCamera()) { + Mx3DPointFloat loc, dir, lookat; + loc = m_world->GetCamera()->GetWorldLocation(); + dir = m_world->GetCamera()->GetWorldDirection(); + lookat = dir; + float scale = 3; + lookat.Mul(scale); + lookat.Add(&loc); + Mx3DPointFloat v68, v7c, v90(0, 1, 0), va4; + v68 = m_world->GetCamera()->GetWorldUp(); + va4.EqualsCross(&v68, &dir); + v7c.EqualsCross(&va4, &v90); + if (ret) { + if (((Act3*) m_world)->FUN_100727e0(m_controller, loc, dir, v7c)) { + break; + } + else if (((Act3*) m_world)->FUN_10072980(m_controller, loc, dir, v7c)) { + break; + } + } + } + ret = 1; + break; + /* case Act3Script::c_Helicopter_Info_Ctl: */ + case IsleScript::c_Helicopter_Info_Ctl: + if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { + ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::e_infomain); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + VTable0xe4(); + } + ret = 1; + break; + case 0x1d: + ret = 1; + break; + } + } + return ret; +} + +// FUNCTION: LEGO1 0x10003c20 +MxU32 Helicopter::VTable0xd8(LegoEndAnimNotificationParam& p_param) +{ + MxU32 ret = 0; + + switch (m_state->GetUnkown8()) { + case 1: { + if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { + ((Act1State*) GameState()->GetState("Act1State"))->SetUnknown18(4); + SpawnPlayer( + LegoGameState::e_unk42, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + } + else { + SpawnPlayer( + LegoGameState::e_unk49, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + } + + m_state->SetUnknown8(2); + + MxMatrix matrix; + matrix.SetIdentity(); + + float s = sin(0.5235987901687622); // PI / 6, 30 deg + float c = cos(0.5235987901687622); // PI / 6, 30 deg + + float matrixCopy[4][4]; + memcpy(matrixCopy, matrix.GetData(), sizeof(matrixCopy)); + for (MxS32 i = 0; i < 4; i++) { + matrix.GetData()[i][1] = matrixCopy[i][1] * c - matrixCopy[i][2] * s; + matrix.GetData()[i][2] = matrixCopy[i][2] * c + matrixCopy[i][1] * s; + } + + Vector3 at(matrix[3]), dir(matrix[2]), up(matrix[1]); + m_world->GetCamera()->SetWorldTransform(at, dir, up); + FUN_10010c30(); + ret = 1; + break; + } + case 3: { + MxMatrix matrix; + matrix.SetIdentity(); + + Vector3 at(matrix[3]), dir(matrix[2]), up(matrix[1]); + at[1] = 1.25; + m_world->GetCamera()->SetWorldTransform(at, dir, up); + + if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { + ((Act1State*) GameState()->GetState("Act1State"))->SetUnknown18(0); + SpawnPlayer( + LegoGameState::e_unk41, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + } + else { + SpawnPlayer( + LegoGameState::e_unk48, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + } + + m_state->SetUnknown8(0); + ret = 1; + break; + } + } + + return ret; +} + +// FUNCTION: LEGO1 0x10003e90 +void Helicopter::VTable0x74(Matrix4& p_transform) +{ + if (m_userNavFlag) { + m_roi->FUN_100a46b0(p_transform); + FUN_10010c30(); + } + else { + m_roi->FUN_100a58f0(p_transform); + m_roi->VTable0x14(); + if (m_cameraFlag) { + FUN_10010c30(); + } + } +} + +// FUNCTION: LEGO1 0x10003ee0 +void Helicopter::VTable0x70(float p_float) +{ + MxU32 state = m_state->GetUnkown8(); + switch (state) { + default: + LegoPathActor::VTable0x70(p_float); + return; + case 4: + case 5: + float f = m_unk0x1f0 - p_float + 3000; + if (f >= 0) { + float f2 = f / 3000 + 1; + if (f2 < 0) { + f2 = 0; + } + if (1.0f < f2) { + f2 = 1.0f; + } + Vector3 v(m_unk0x160[3]); + MxMatrix mat; + Vector3 v2(m_unk0x1a8[3]); + float* loc = m_unk0x1a8[3]; + mat.SetIdentity(); + float fa[4]; + Vector4 v3(fa); + if (m_unk0x1f4.FUN_100040a0(v3, f2) == SUCCESS) { + mat.FromQuaternion(v3); + } + v2.SetVector(loc); + v2.Sub(&v); + v2.Mul(f2); + v2.Add(&v); + m_world->GetCamera()->FUN_100123e0(mat, 0); + } + else { + if (state == 4) { + ((Act3*) m_world)->FUN_10073400(); + } + else { + ((Act3*) m_world)->FUN_10073430(); + } + LegoPathActor::m_state = 4; + } + } +} diff --git a/LEGO1/lego/legoomni/src/actors/isleactor.cpp b/LEGO1/lego/legoomni/src/actors/isleactor.cpp new file mode 100644 index 00000000..a09c62d7 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/isleactor.cpp @@ -0,0 +1,57 @@ +#include "isleactor.h" + +#include "legoentity.h" +#include "legoworld.h" +#include "misc.h" +#include "mxnotificationparam.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(IsleActor, 0x7c) + +// FUNCTION: LEGO1 0x1002c780 +MxResult IsleActor::Create(MxDSAction& p_dsAction) +{ + MxResult result = LegoEntity::Create(p_dsAction); + + if (result == SUCCESS) { + m_world = CurrentWorld(); + + if (!m_world) { + result = FAILURE; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1002c7b0 +MxLong IsleActor::Notify(MxParam& p_param) +{ + MxLong result = 0; + + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationType0: + result = VTable0x6c(); + break; + case c_notificationEndAction: + result = HandleEndAction((MxEndActionNotificationParam&) p_param); + break; + case c_notificationButtonUp: + result = HandleButtonUp((MxNotificationParam&) p_param); + break; + case c_notificationButtonDown: + result = HandleButtonDown((MxNotificationParam&) p_param); + break; + case c_notificationType11: + result = VTable0x68(); + break; + case c_notificationEndAnim: + result = VTable0x70(); + break; + case c_notificationType19: + result = VTable0x80(p_param); + break; + } + + return result; +} diff --git a/LEGO1/lego/legoomni/src/actors/islepathactor.cpp b/LEGO1/lego/legoomni/src/actors/islepathactor.cpp new file mode 100644 index 00000000..02411891 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/islepathactor.cpp @@ -0,0 +1,586 @@ +#include "islepathactor.h" + +#include "3dmanager/lego3dmanager.h" +#include "isle_actions.h" +#include "jukebox_actions.h" +#include "legoanimationmanager.h" +#include "legonavcontroller.h" +#include "legopathboundary.h" +#include "legoutils.h" +#include "legovehiclebuildstate.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxbackgroundaudiomanager.h" +#include "mxnotificationparam.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(IslePathActor, 0x160) +DECOMP_SIZE_ASSERT(IslePathActor::SpawnLocation, 0x38) + +// GLOBAL: LEGO1 0x10102b28 +IslePathActor::SpawnLocation g_spawnLocations[IslePathActor::c_LOCATIONS_NUM]; + +// FUNCTION: LEGO1 0x1001a200 +IslePathActor::IslePathActor() +{ + m_world = NULL; + m_unk0x13c = 6.0; + m_unk0x15c = 1.0; + m_unk0x158 = 0; +} + +// FUNCTION: LEGO1 0x1001a280 +MxResult IslePathActor::Create(MxDSAction& p_dsAction) +{ + return MxEntity::Create(p_dsAction); +} + +// FUNCTION: LEGO1 0x1001a2a0 +void IslePathActor::Destroy(MxBool p_fromDestructor) +{ + if (!p_fromDestructor) { + LegoPathActor::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x1001a2c0 +MxLong IslePathActor::Notify(MxParam& p_param) +{ + MxLong ret = 0; + + switch (((MxNotificationParam&) p_param).GetType()) { + case c_notificationType0: + ret = VTable0xd0(); + break; + case c_notificationType11: + ret = VTable0xcc(); + break; + case c_notificationClick: + ret = VTable0xd4((LegoControlManagerEvent&) p_param); + break; + case c_notificationEndAnim: + ret = VTable0xd8((LegoEndAnimNotificationParam&) p_param); + break; + case c_notificationType19: + ret = VTable0xdc((MxType19NotificationParam&) p_param); + break; + } + + return ret; +} + +// FUNCTION: LEGO1 0x1001a350 +void IslePathActor::VTable0xe0() +{ + m_roi->SetVisibility(FALSE); + if (CurrentActor() != this) { + m_unk0x15c = NavController()->GetMaxLinearVel(); + m_unk0x158 = CurrentActor(); + if (m_unk0x158) { + m_unk0x158->ResetWorldTransform(FALSE); + m_unk0x158->SetUserNavFlag(FALSE); + } + } + + AnimationManager()->FUN_10061010(FALSE); + if (!m_cameraFlag) { + ResetWorldTransform(TRUE); + SetUserNavFlag(TRUE); + + NavController()->ResetLinearVel(m_unk0x13c); + + SetCurrentActor(this); + FUN_1001b660(); + FUN_10010c30(); + } +} + +// STUB: LEGO1 0x1001a3f0 +void IslePathActor::VTable0xe4() +{ + // TODO +} + +// FUNCTION: LEGO1 0x1001a700 +void IslePathActor::RegisterSpawnLocations() +{ + g_spawnLocations[0] = SpawnLocation( + LegoGameState::e_pizzeriaExterior, + g_isleScript, + 0, + "int35", + 2, + 0.6, + 4, + 0.4, + 0x2a, + JukeboxScript::c_Quiet_Audio + ); + g_spawnLocations[1] = SpawnLocation( + LegoGameState::e_unk23, + g_isleScript, + 0, + "edg00_49", + 1, + 0.43, + 2, + 0.6, + 0x27, + JukeboxScript::c_Quiet_Audio + ); + g_spawnLocations[2] = SpawnLocation( + LegoGameState::e_unk24, + g_isleScript, + 0, + "edg00_191", + 2, + 0.5, + 0, + 0.55, + 0x26, + JukeboxScript::c_Quiet_Audio + ); + g_spawnLocations[3] = SpawnLocation( + LegoGameState::e_unk4, + g_isleScript, + 0, + "int46", + 0, + 0.5, + 2, + 0.5, + 0x10, + JukeboxScript::c_InformationCenter_Music + ); + g_spawnLocations[4] = SpawnLocation( + LegoGameState::e_jetraceExterior, + g_isleScript, + 0, + "EDG00_46", + 0, + 0.95, + 2, + 0.19, + 0x17, + JukeboxScript::c_Beach_Music + ); + g_spawnLocations[5] = SpawnLocation( + LegoGameState::e_unk17, + g_isleScript, + 0, + "EDG00_46", + 3, + 0.625, + 2, + 0.03, + 0x18, + JukeboxScript::c_Beach_Music + ); + g_spawnLocations[6] = SpawnLocation( + LegoGameState::e_jetrace2, + g_isleScript, + 0, + "EDG10_63", + 0, + 0.26, + 1, + 0.01, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[7] = SpawnLocation( + LegoGameState::e_carraceExterior, + g_isleScript, + 0, + "INT15", + 5, + 0.65, + 1, + 0.68, + 0x33, + JukeboxScript::c_CentralNorthRoad_Music + ); + g_spawnLocations[8] = SpawnLocation( + LegoGameState::e_unk20, + g_isleScript, + 0, + "INT16", + 4, + 0.1, + 2, + 0, + 0x34, + JukeboxScript::c_CentralNorthRoad_Music + ); + g_spawnLocations[9] = SpawnLocation( + LegoGameState::e_unk21, + g_isleScript, + 0, + "INT62", + 2, + 0.1, + 3, + 0.7, + 0x36, + JukeboxScript::c_CentralNorthRoad_Music + ); + g_spawnLocations[10] = SpawnLocation( + LegoGameState::e_garageExterior, + g_isleScript, + 0, + "INT24", + 0, + 0.55, + 2, + 0.71, + 0x08, + JukeboxScript::c_GarageArea_Music + ); + g_spawnLocations[11] = SpawnLocation( + LegoGameState::e_unk28, + g_isleScript, + 0, + "INT24", + 2, + 0.73, + 4, + 0.71, + 0x0a, + JukeboxScript::c_GarageArea_Music + ); + g_spawnLocations[12] = SpawnLocation( + LegoGameState::e_hospitalExterior, + g_isleScript, + 0, + "INT19", + 0, + 0.85, + 1, + 0.28, + 0, + JukeboxScript::c_Hospital_Music + ); + g_spawnLocations[13] = SpawnLocation( + LegoGameState::e_unk31, + g_isleScript, + 0, + "EDG02_28", + 3, + 0.37, + 1, + 0.52, + 0x0c, + JukeboxScript::c_Hospital_Music + ); + g_spawnLocations[14] = SpawnLocation( + LegoGameState::e_policeExterior, + g_isleScript, + 0, + "INT33", + 0, + 0.88, + 2, + 0.74, + 0x22, + JukeboxScript::c_PoliceStation_Music + ); + g_spawnLocations[15] = SpawnLocation( + LegoGameState::e_unk33, + g_isleScript, + 0, + "EDG02_64", + 2, + 0.24, + 0, + 0.84, + 0x23, + JukeboxScript::c_PoliceStation_Music + ); + g_spawnLocations[16] = SpawnLocation( + LegoGameState::e_unk40, + g_isleScript, + 0, + "edg02_51", + 2, + 0.63, + 3, + 0.01, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[17] = SpawnLocation( + LegoGameState::e_unk41, + g_isleScript, + 0, + "edg02_51", + 2, + 0.63, + 0, + 0.4, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[18] = SpawnLocation( + LegoGameState::e_unk43, + g_isleScript, + 0, + "edg02_35", + 2, + 0.8, + 0, + 0.2, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[19] = SpawnLocation( + LegoGameState::e_unk44, + g_isleScript, + 0, + "EDG03_01", + 2, + 0.25, + 0, + 0.75, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[20] = SpawnLocation( + LegoGameState::e_unk45, + g_isleScript, + 0, + "edg10_70", + 3, + 0.25, + 0, + 0.7, + 0x44, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[21] = SpawnLocation( + LegoGameState::e_unk42, + g_isleScript, + 0, + "inv_05", + 2, + 0.75, + 0, + 0.19, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[22] = SpawnLocation( + LegoGameState::e_unk48, + g_act3Script, + 0, + "edg02_51", + 2, + 0.63, + 0, + 0.4, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[23] = SpawnLocation( + LegoGameState::e_unk49, + g_act3Script, + 0, + "inv_05", + 2, + 0.75, + 0, + 0.19, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[24] = SpawnLocation( + LegoGameState::e_unk50, + g_act2mainScript, + 0, + "EDG02_51", + 0, + 0.64, + 1, + 0.37, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[25] = SpawnLocation( + LegoGameState::e_unk51, + g_isleScript, + 0, + "edg02_32", + 0, + 0.5, + 2, + 0.5, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[26] = SpawnLocation( + LegoGameState::e_unk52, + g_isleScript, + 0, + "edg02_19", + 2, + 0.5, + 0, + 0.5, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[27] = SpawnLocation( + LegoGameState::e_unk54, + g_isleScript, + 0, + "int36", + 0, + 0.2, + 4, + 0.4, + 0, + JukeboxScript::c_noneJukebox + ); + g_spawnLocations[28] = SpawnLocation( + LegoGameState::e_unk55, + g_isleScript, + 0, + "edg02_50", + 2, + 0.8, + 1, + 0.3, + 0, + JukeboxScript::c_noneJukebox + ); +} + +// FUNCTION: LEGO1 0x1001b2a0 +// FUNCTION: BETA10 0x100369c6 +void IslePathActor::SpawnPlayer(LegoGameState::Area p_area, MxBool p_und, MxU8 p_flags) +{ + MxS16 i; + + for (i = 0; i < c_LOCATIONS_NUM && g_spawnLocations[i].m_area != p_area; i++) { + } + + assert(i != c_LOCATIONS_NUM); + + if (i != c_LOCATIONS_NUM) { + LegoWorld* world = FindWorld(*g_spawnLocations[i].m_script, g_spawnLocations[i].m_entityId); + assert(world); + + if (m_world != NULL) { + m_world->RemovePathActor(this); + m_world->Remove(this); + VideoManager()->Get3DManager()->Remove(*m_roi); + } + + m_world = world; + + if (p_und) { + VTable0xe0(); + } + + m_world->PlaceActor( + this, + g_spawnLocations[i].m_name, + g_spawnLocations[i].m_src, + g_spawnLocations[i].m_srcScale, + g_spawnLocations[i].m_dest, + g_spawnLocations[i].m_destScale + ); + + if (GameState()->GetActorId() != m_actorId) { + m_world->Add(this); + } + + LegoVehicleBuildState* state = NULL; + + if (p_flags & c_spawnBit1) { + MxBool und = FALSE; + IsleScript::Script anim; + + switch (g_spawnLocations[i].m_unk0x30) { + case 0x00: + case 0x44: + break; + case 0x0a: + state = (LegoVehicleBuildState*) GameState()->GetState("LegoDuneCarBuildState"); + anim = IsleScript::c_igs008na_RunAnim; + break; + case 0x18: + state = (LegoVehicleBuildState*) GameState()->GetState("LegoJetskiBuildState"); + anim = IsleScript::c_ijs006sn_RunAnim; + break; + case 0x23: + state = (LegoVehicleBuildState*) GameState()->GetState("LegoCopterBuildState"); + anim = IsleScript::c_ips002ro_RunAnim; + break; + case 0x34: + state = (LegoVehicleBuildState*) GameState()->GetState("LegoRaceCarBuildState"); + anim = IsleScript::c_irt007in_RunAnim; + break; + default: + und = TRUE; + break; + } + + if (state != NULL && state->m_unk0x4d && !state->m_unk0x4e) { + if (AnimationManager()->FUN_10060dc0(anim, NULL, TRUE, FALSE, NULL, FALSE, TRUE, TRUE, TRUE) == + SUCCESS) { + state->m_unk0x4e = TRUE; + und = FALSE; + } + } + + if (und) { + FUN_1003ecc0(this, 0, g_spawnLocations[i].m_unk0x30, TRUE); + } + } + + if (m_cameraFlag) { + FUN_1003eda0(); + } + + if (p_flags & c_playMusic && g_spawnLocations[i].m_music != JukeboxScript::c_noneJukebox) { + MxDSAction action; + action.SetAtomId(*g_jukeboxScript); + action.SetObjectId(g_spawnLocations[i].m_music); + BackgroundAudioManager()->PlayMusic(action, 5, 4); + } + } +} + +// FUNCTION: LEGO1 0x1001b5b0 +void IslePathActor::VTable0xec(MxMatrix p_transform, LegoPathBoundary* p_boundary, MxBool p_reset) +{ + if (m_world) { + m_world->RemovePathActor(this); + m_world->Remove(this); + VideoManager()->Get3DManager()->GetLego3DView()->Remove(*m_roi); + } + + m_world = CurrentWorld(); + if (p_reset) { + VTable0xe0(); + } + + m_world->AddPathActor(this); + p_boundary->AddActor(this); + if (m_actorId != GameState()->GetActorId()) { + m_world->Add(this); + } + + m_roi->FUN_100a58f0(p_transform); + if (m_cameraFlag) { + FUN_1003eda0(); + FUN_10010c30(); + } +} + +// STUB: LEGO1 0x1001b660 +void IslePathActor::FUN_1001b660() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/actors/jetski.cpp b/LEGO1/lego/legoomni/src/actors/jetski.cpp new file mode 100644 index 00000000..8ac6924b --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/jetski.cpp @@ -0,0 +1,50 @@ +#include "jetski.h" + +DECOMP_SIZE_ASSERT(Jetski, 0x164) + +// FUNCTION: LEGO1 0x1007e3b0 +Jetski::Jetski() +{ + this->m_unk0x13c = 25.0; + this->m_unk0x150 = 2.0; + this->m_unk0x148 = 1; +} + +// STUB: LEGO1 0x1007e630 +MxResult Jetski::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x1007e680 +void Jetski::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x1007e6f0 +void Jetski::VTable0xe4() +{ + // TODO +} + +// STUB: LEGO1 0x1007e750 +MxU32 Jetski::VTable0xcc() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1007e8e0 +MxU32 Jetski::VTable0xd4(LegoControlManagerEvent& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1007e990 +void Jetski::FUN_1007e990() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/actors/jukeboxentity.cpp b/LEGO1/lego/legoomni/src/actors/jukeboxentity.cpp new file mode 100644 index 00000000..ade45933 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/jukeboxentity.cpp @@ -0,0 +1,133 @@ +#include "jukeboxentity.h" + +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "jukebox_actions.h" +#include "jukeboxstate.h" +#include "legogamestate.h" +#include "legoutils.h" +#include "misc.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxnotificationparam.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(JukeBoxEntity, 0x6c) + +// FUNCTION: LEGO1 0x10085bc0 +JukeBoxEntity::JukeBoxEntity() +{ + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x10085dd0 +JukeBoxEntity::~JukeBoxEntity() +{ + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x10085e40 +MxLong JukeBoxEntity::Notify(MxParam& p_param) +{ + if (((MxNotificationParam&) p_param).GetType() == c_notificationType11) { + if (!FUN_1003ef60()) { + return 1; + } + + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + ((Isle*) FindWorld(*g_isleScript, 0))->SetDestLocation(LegoGameState::e_jukeboxw); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + return 1; + } + + return 0; +} + +// FUNCTION: LEGO1 0x10085ed0 +void JukeBoxEntity::StartAction() +{ + MxDSAction action; + BackgroundAudioManager()->Stop(); + JukeBoxState* state = (JukeBoxState*) GameState()->GetState("JukeBoxState"); + state->SetActive(TRUE); + + switch (state->GetState()) { + case 0: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_npz001bd_RunAnim, NULL); + GameState()->SetUnknown0x41c(JukeboxScript::c_JBMusic1); + break; + case 1: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_npz006bd_RunAnim, NULL); + GameState()->SetUnknown0x41c(JukeboxScript::c_JBMusic2); + break; + case 2: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_npz003bd_RunAnim, NULL); + GameState()->SetUnknown0x41c(JukeboxScript::c_JBMusic3); + break; + case 3: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_npz002bd_RunAnim, NULL); + GameState()->SetUnknown0x41c(JukeboxScript::c_JBMusic4); + break; + case 4: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_npz007bd_RunAnim, NULL); + GameState()->SetUnknown0x41c(JukeboxScript::c_JBMusic5); + break; + case 5: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_npz004bd_RunAnim, NULL); + GameState()->SetUnknown0x41c(JukeboxScript::c_JBMusic6); + break; + } + + action.SetAtomId(*g_jukeboxScript); + action.SetObjectId(GameState()->GetUnknown0x41c()); + + m_audioEnabled = BackgroundAudioManager()->GetEnabled(); + if (!m_audioEnabled) { + BackgroundAudioManager()->Enable(TRUE); + } + + BackgroundAudioManager()->PlayMusic(action, 5, 4); +} + +// FUNCTION: LEGO1 0x100860f0 +void JukeBoxEntity::StopAction(JukeboxScript::Script p_script) +{ + JukeBoxState* state = (JukeBoxState*) GameState()->GetState("JukeBoxState"); + + if (state && state->IsActive()) { + switch (p_script) { + case JukeboxScript::c_JBMusic1: + state->SetActive(FALSE); + InvokeAction(Extra::e_stop, *g_isleScript, IsleScript::c_npz001bd_RunAnim, NULL); + break; + case JukeboxScript::c_JBMusic2: + state->SetActive(FALSE); + InvokeAction(Extra::e_stop, *g_isleScript, IsleScript::c_npz006bd_RunAnim, NULL); + break; + case JukeboxScript::c_JBMusic3: + state->SetActive(FALSE); + InvokeAction(Extra::e_stop, *g_isleScript, IsleScript::c_npz003bd_RunAnim, NULL); + break; + case JukeboxScript::c_JBMusic4: + state->SetActive(FALSE); + InvokeAction(Extra::e_stop, *g_isleScript, IsleScript::c_npz002bd_RunAnim, NULL); + break; + case JukeboxScript::c_JBMusic5: + state->SetActive(FALSE); + InvokeAction(Extra::e_stop, *g_isleScript, IsleScript::c_npz007bd_RunAnim, NULL); + break; + case JukeboxScript::c_JBMusic6: + state->SetActive(FALSE); + InvokeAction(Extra::e_stop, *g_isleScript, IsleScript::c_npz004bd_RunAnim, NULL); + break; + } + + BackgroundAudioManager()->Enable(IsBackgroundAudioEnabled()); + } +} diff --git a/LEGO1/lego/legoomni/src/actors/motorcycle.cpp b/LEGO1/lego/legoomni/src/actors/motorcycle.cpp new file mode 100644 index 00000000..68ce7950 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/motorcycle.cpp @@ -0,0 +1,58 @@ +#include "motocycle.h" + +DECOMP_SIZE_ASSERT(Motocycle, 0x16c) + +// FUNCTION: LEGO1 0x100357b0 +Motocycle::Motocycle() +{ + this->m_unk0x13c = 40.0; + this->m_unk0x150 = 1.75; + this->m_unk0x148 = 1; + this->m_unk0x164 = 1.0; +} + +// STUB: LEGO1 0x10035a40 +MxResult Motocycle::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10035ad0 +void Motocycle::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x10035bc0 +void Motocycle::VTable0xe4() +{ + // TODO +} + +// STUB: LEGO1 0x10035c50 +MxU32 Motocycle::VTable0xcc() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10035d70 +MxU32 Motocycle::VTable0xd4(LegoControlManagerEvent& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10035df0 +MxU32 Motocycle::VTable0xdc(MxType19NotificationParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10035e10 +void Motocycle::FUN_10035e10() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/actors/pizza.cpp b/LEGO1/lego/legoomni/src/actors/pizza.cpp new file mode 100644 index 00000000..57ab17df --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/pizza.cpp @@ -0,0 +1,69 @@ +#include "pizza.h" + +#include "mxmisc.h" +#include "mxticklemanager.h" + +DECOMP_SIZE_ASSERT(Pizza, 0x9c) + +// FUNCTION: LEGO1 0x10037ef0 +Pizza::Pizza() +{ + m_unk0x7c = 0; + m_unk0x80 = 0; + m_skateboard = NULL; + m_unk0x88 = 0; + m_unk0x8c = -1; + m_unk0x98 = 0; + m_unk0x90 = 0x80000000; +} + +// FUNCTION: LEGO1 0x10038100 +Pizza::~Pizza() +{ + TickleManager()->UnregisterClient(this); +} + +// STUB: LEGO1 0x10038170 +MxResult Pizza::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x100382b0 +void Pizza::FUN_100382b0() +{ +} + +// STUB: LEGO1 0x10038380 +void Pizza::FUN_10038380() +{ +} + +// STUB: LEGO1 0x100383f0 +undefined4 Pizza::VTable0x68() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x100384f0 +undefined4 Pizza::VTable0x80(MxParam&) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x100388a0 +MxResult Pizza::Tickle() +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10038b10 +undefined4 Pizza::HandleEndAction(MxEndActionNotificationParam&) +{ + // TODO + return 0; +} diff --git a/LEGO1/lego/legoomni/src/actors/pizzeria.cpp b/LEGO1/lego/legoomni/src/actors/pizzeria.cpp new file mode 100644 index 00000000..2346914b --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/pizzeria.cpp @@ -0,0 +1,43 @@ +#include "pizzeria.h" + +#include "legogamestate.h" +#include "misc.h" + +DECOMP_SIZE_ASSERT(Pizzeria, 0x84) + +// FUNCTION: LEGO1 0x100179c0 +MxResult Pizzeria::Create(MxDSAction& p_dsAction) +{ + MxResult result = IsleActor::Create(p_dsAction); + + if (result == SUCCESS) { + Init(); + } + + return result; +} + +// FUNCTION: LEGO1 0x100179f0 +void Pizzeria::Init() +{ + LegoGameState* gameState = GameState(); + PizzeriaState* pizzeriaState = (PizzeriaState*) gameState->GetState("PizzeriaState"); + if (pizzeriaState == NULL) { + pizzeriaState = (PizzeriaState*) gameState->CreateState("PizzeriaState"); + } + m_pizzeriaState = pizzeriaState; + + gameState = GameState(); + PizzaMissionState* pizzaMissionState = (PizzaMissionState*) gameState->GetState("PizzaMissionState"); + if (pizzaMissionState == NULL) { + pizzaMissionState = (PizzaMissionState*) gameState->CreateState("PizzaMissionState"); + } + m_pizzaMissionState = pizzaMissionState; +} + +// STUB: LEGO1 0x10017a50 +undefined4 Pizzeria::VTable0x68() +{ + // TODO + return 0; +} diff --git a/LEGO1/lego/legoomni/src/actors/racecar.cpp b/LEGO1/lego/legoomni/src/actors/racecar.cpp new file mode 100644 index 00000000..3907a7d0 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/racecar.cpp @@ -0,0 +1,33 @@ +#include "racecar.h" + +#include "legocontrolmanager.h" +#include "misc.h" + +DECOMP_SIZE_ASSERT(RaceCar, 0x164) + +// FUNCTION: LEGO1 0x10028200 +RaceCar::RaceCar() +{ + m_unk0x13c = 40.0; +} + +// FUNCTION: LEGO1 0x10028420 +RaceCar::~RaceCar() +{ + ControlManager()->Unregister(this); + VTable0xe4(); +} + +// STUB: LEGO1 0x10028490 +MxResult RaceCar::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x100284d0 +MxU32 RaceCar::VTable0xcc() +{ + // TODO + return 0; +} diff --git a/LEGO1/lego/legoomni/src/actors/radio.cpp b/LEGO1/lego/legoomni/src/actors/radio.cpp new file mode 100644 index 00000000..a04523b1 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/radio.cpp @@ -0,0 +1,164 @@ +#include "radio.h" + +#include "isle_actions.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoworld.h" +#include "misc.h" +#include "mxactionnotificationparam.h" +#include "mxbackgroundaudiomanager.h" +#include "mxcontrolpresenter.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "radiostate.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(Radio, 0x10) + +// FUNCTION: LEGO1 0x1002c850 +Radio::Radio() +{ + NotificationManager()->Register(this); + ControlManager()->Register(this); + + m_unk0x0c = TRUE; + CreateRadioState(); +} + +// FUNCTION: LEGO1 0x1002c990 +Radio::~Radio() +{ + if (m_state->IsActive()) { + BackgroundAudioManager()->Stop(); + m_state->SetActive(FALSE); + } + + ControlManager()->Unregister(this); + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x1002ca30 +MxLong Radio::Notify(MxParam& p_param) +{ + MxLong result = 0; + + if (m_unk0x0c) { + switch (((MxNotificationParam&) p_param).GetType()) { + case c_notificationEndAction: + result = HandleEndAction((MxEndActionNotificationParam&) p_param); + break; + case c_notificationClick: + result = HandleClick((LegoControlManagerEvent&) p_param); + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1002ca70 +void Radio::Play() +{ + if (!m_state->IsActive()) { + CurrentWorld(); + + MxDSAction action; + action.SetObjectId(m_state->FUN_1002d090()); + action.SetAtomId(*g_jukeboxScript); + action.SetLoopCount(1); + + m_audioEnabled = BackgroundAudioManager()->GetEnabled(); + if (!m_audioEnabled) { + BackgroundAudioManager()->Enable(TRUE); + } + + BackgroundAudioManager()->PlayMusic(action, 3, 4); + m_state->SetActive(TRUE); + } +} + +// FUNCTION: LEGO1 0x1002cb70 +void Radio::Stop() +{ + if (m_state->IsActive()) { + LegoWorld* world = CurrentWorld(); + + MxControlPresenter* presenter = (MxControlPresenter*) world->Find(world->GetAtom(), IsleScript::c_Radio_Ctl); + + if (presenter) { + presenter->VTable0x6c(0); + } + + BackgroundAudioManager()->Stop(); + BackgroundAudioManager()->Enable(m_audioEnabled); + m_state->SetActive(FALSE); + } +} + +// FUNCTION: LEGO1 0x1002cbc0 +MxLong Radio::HandleClick(LegoControlManagerEvent& p_param) +{ + MxDSAction action; // Unused + MxS32 objectId = p_param.GetClickedObjectId(); + + if (objectId == IsleScript::c_Radio_Ctl) { + if (m_state->IsActive()) { + Stop(); + } + else { + Play(); + } + + if (CurrentWorld()) { +#ifdef COMPAT_MODE + MxNotificationParam param(c_notificationEndAction, this); + CurrentWorld()->Notify(param); +#else + CurrentWorld()->Notify(MxNotificationParam(c_notificationType0, this)); +#endif + } + + return 1; + } + + return 0; +} + +// FUNCTION: LEGO1 0x1002ccc0 +MxLong Radio::HandleEndAction(MxEndActionNotificationParam& p_param) +{ + if (m_state->IsActive() && + m_state->FUN_1002d0c0(p_param.GetAction()->GetAtomId(), p_param.GetAction()->GetObjectId())) { + + MxDSAction action; + action.SetAtomId(*g_jukeboxScript); + action.SetObjectId(m_state->FUN_1002d090()); + action.SetLoopCount(1); + + BackgroundAudioManager()->PlayMusic(action, 3, 4); + return 1; + } + + return 0; +} + +// FUNCTION: LEGO1 0x1002cdc0 +void Radio::Initialize(MxBool p_und) +{ + if (m_unk0x0c != p_und) { + m_unk0x0c = p_und; + CreateRadioState(); + } +} + +// FUNCTION: LEGO1 0x1002cde0 +void Radio::CreateRadioState() +{ + LegoGameState* gameState = GameState(); + RadioState* state = (RadioState*) gameState->GetState("RadioState"); + if (state == NULL) { + state = (RadioState*) gameState->CreateState("RadioState"); + } + + m_state = state; +} diff --git a/LEGO1/lego/legoomni/src/actors/skateboard.cpp b/LEGO1/lego/legoomni/src/actors/skateboard.cpp new file mode 100644 index 00000000..352e0bba --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/skateboard.cpp @@ -0,0 +1,165 @@ +#include "skateboard.h" + +#include "act1state.h" +#include "decomp.h" +#include "isle.h" +#include "isle_actions.h" +#include "jukebox_actions.h" +#include "legoanimationmanager.h" +#include "legocontrolmanager.h" +#include "legoutils.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstillpresenter.h" +#include "mxtransitionmanager.h" +#include "pizza.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(SkateBoard, 0x168) + +// FUNCTION: LEGO1 0x1000fd40 +SkateBoard::SkateBoard() +{ + m_unk0x160 = FALSE; + m_unk0x13c = 15.0; + m_unk0x150 = 3.5; + m_unk0x148 = 1; + + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x1000ff80 +SkateBoard::~SkateBoard() +{ + ControlManager()->Unregister(this); + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x10010000 +MxResult SkateBoard::Create(MxDSAction& p_dsAction) +{ + MxResult result = IslePathActor::Create(p_dsAction); + + if (result == SUCCESS) { + m_world = CurrentWorld(); + m_world->Add(this); + + Pizza* pizza = (Pizza*) CurrentWorld()->Find(*g_isleScript, IsleScript::c_Pizza_Actor); + if (pizza) { + pizza->SetSkateboard(this); + } + } + + return result; +} + +// FUNCTION: LEGO1 0x10010050 +void SkateBoard::VTable0xe4() +{ + if (m_act1state->m_unk0x018 == 3) { + Pizza* pizza = (Pizza*) CurrentWorld()->Find(*g_isleScript, IsleScript::c_Pizza_Actor); + pizza->FUN_10038380(); + pizza->FUN_100382b0(); + m_unk0x160 = FALSE; + } + + IslePathActor::VTable0xe4(); + GameState()->m_currentArea = LegoGameState::Area::e_skateboard; + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_SkateArms_Ctl); + RemoveFromCurrentWorld(*g_isleScript, IsleScript::c_SkatePizza_Bitmap); + ControlManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x100100e0 +MxU32 SkateBoard::VTable0xcc() +{ + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + + if (!FUN_1003ef60() && state->m_unk0x018 != 3) { + return 1; + } + + FUN_10015820(TRUE, 0); + + ((Isle*) CurrentWorld())->SetDestLocation(LegoGameState::Area::e_skateboard); + TransitionManager()->StartTransition(MxTransitionManager::TransitionType::e_mosaic, 50, FALSE, TRUE); + + if (GameState()->GetActorId() != CurrentActor()->GetActorId()) { + if (!CurrentActor()->IsA("SkateBoard")) { + CurrentActor()->VTable0xe4(); + } + } + + if (!CurrentActor()->IsA("SkateBoard")) { + VTable0xe0(); + InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_SkateDashboard, NULL); + GetCurrentAction().SetObjectId(-1); + ControlManager()->Register(this); + } + + FUN_10010270(m_unk0x160); + + Vector3 position = m_roi->GetWorldPosition(); + AnimationManager()->FUN_10064670(&position); + AnimationManager()->FUN_10064740(&position); + return 1; +} + +// FUNCTION: LEGO1 0x10010230 +MxU32 SkateBoard::VTable0xd4(LegoControlManagerEvent& p_param) +{ + MxU32 result = 0; + + if (p_param.GetUnknown0x28() == 1 && p_param.GetClickedObjectId() == IsleScript::c_SkateArms_Ctl) { + VTable0xe4(); + GameState()->m_currentArea = LegoGameState::Area::e_unk66; + result = 1; + } + + return result; +} + +// FUNCTION: LEGO1 0x10010270 +// FUNCTION: BETA10 0x100f5366 +void SkateBoard::FUN_10010270(MxBool p_enable) +{ + m_act1state = (Act1State*) GameState()->GetState("Act1State"); + if (!m_act1state) { + m_act1state = (Act1State*) GameState()->CreateState("Act1State"); + } + + MxStillPresenter* presenter = (MxStillPresenter*) m_world->Find(*g_isleScript, IsleScript::c_SkatePizza_Bitmap); + if (presenter) { + presenter->Enable(p_enable); + } + else if (m_unk0x160) { + NotificationManager()->Send(this, MxNotificationParam(c_notificationType0, NULL)); + } +} + +// FUNCTION: LEGO1 0x100104f0 +// FUNCTION: BETA10 0x100f5472 +MxU32 SkateBoard::VTable0xd0() +{ + FUN_10010270(m_unk0x160); + return 1; +} + +// FUNCTION: LEGO1 0x10010510 +void SkateBoard::FUN_10010510() +{ + if (m_act1state->m_unk0x018 != 3) { + PlayMusic(JukeboxScript::c_BeachBlvd_Music); + + if (!m_act1state->m_unk0x022) { + m_act1state->m_unk0x022 = TRUE; + + MxMatrix mat(CurrentActor()->GetROI()->GetLocal2World()); + mat.TranslateBy(mat[2][0] * 2.5, mat[2][1] + 0.2, mat[2][2] * 2.5); + + AnimationManager() + ->FUN_10060dc0(IsleScript::c_sns008in_RunAnim, &mat, TRUE, FALSE, NULL, FALSE, TRUE, TRUE, TRUE); + } + } +} diff --git a/LEGO1/lego/legoomni/src/actors/towtrack.cpp b/LEGO1/lego/legoomni/src/actors/towtrack.cpp new file mode 100644 index 00000000..2b087966 --- /dev/null +++ b/LEGO1/lego/legoomni/src/actors/towtrack.cpp @@ -0,0 +1,83 @@ +#include "towtrack.h" + +DECOMP_SIZE_ASSERT(TowTrack, 0x180) + +// FUNCTION: LEGO1 0x1004c720 +TowTrack::TowTrack() +{ + this->m_unk0x168 = 0; + this->m_unk0x16a = -1; + this->m_unk0x164 = 0; + this->m_unk0x16c = 0; + this->m_unk0x170 = -1; + this->m_unk0x16e = 0; + this->m_unk0x174 = -1; + this->m_unk0x13c = 40.0; + this->m_unk0x178 = 1.0; +} + +// STUB: LEGO1 0x1004c9e0 +MxResult TowTrack::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x1004cb10 +void TowTrack::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x1004cc80 +MxLong TowTrack::Notify(MxParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1004cd30 +MxU32 TowTrack::VTable0xd8(LegoEndAnimNotificationParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1004d330 +MxU32 TowTrack::VTable0xdc(MxType19NotificationParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1004d690 +MxU32 TowTrack::VTable0xcc() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1004d8f0 +void TowTrack::VTable0xe4() +{ + // TODO +} + +// STUB: LEGO1 0x1004d9e0 +MxU32 TowTrack::VTable0xd4(LegoControlManagerEvent& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1004dab0 +void TowTrack::FUN_1004dab0() +{ + // TODO +} + +// STUB: LEGO1 0x1004dad0 +void TowTrack::FUN_1004dad0() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/audio/lego3dwavepresenter.cpp b/LEGO1/lego/legoomni/src/audio/lego3dwavepresenter.cpp new file mode 100644 index 00000000..b60f3ded --- /dev/null +++ b/LEGO1/lego/legoomni/src/audio/lego3dwavepresenter.cpp @@ -0,0 +1,48 @@ +#include "lego3dwavepresenter.h" + +#include "mxomni.h" + +DECOMP_SIZE_ASSERT(Lego3DWavePresenter, 0xa0) + +// FUNCTION: LEGO1 0x1004a7c0 +MxResult Lego3DWavePresenter::AddToManager() +{ + MxResult result = MxWavePresenter::AddToManager(); + MxWavePresenter::Init(); + + if (MxOmni::IsSound3D()) { + m_is3d = TRUE; + } + + return result; +} + +// FUNCTION: LEGO1 0x1004a7f0 +void Lego3DWavePresenter::Destroy() +{ + MxWavePresenter::Destroy(); + MxWavePresenter::Init(); + + if (MxOmni::IsSound3D()) { + m_is3d = TRUE; + } +} + +// STUB: LEGO1 0x1004a810 +void Lego3DWavePresenter::StartingTickle() +{ + if (MxOmni::IsSound3D()) { + m_is3d = TRUE; + } + + MxWavePresenter::StartingTickle(); + + // TODO +} + +// STUB: LEGO1 0x1004a8b0 +void Lego3DWavePresenter::StreamingTickle() +{ + MxWavePresenter::StreamingTickle(); + // TODO +} diff --git a/LEGO1/lego/legoomni/src/audio/legocachesoundmanager.cpp b/LEGO1/lego/legoomni/src/audio/legocachesoundmanager.cpp new file mode 100644 index 00000000..e611484b --- /dev/null +++ b/LEGO1/lego/legoomni/src/audio/legocachesoundmanager.cpp @@ -0,0 +1,178 @@ +#include "legocachesoundmanager.h" + +#include "legoworld.h" +#include "misc.h" + +DECOMP_SIZE_ASSERT(LegoCacheSoundEntry, 0x08) +DECOMP_SIZE_ASSERT(LegoCacheSoundManager, 0x20) + +// FUNCTION: LEGO1 0x1003cf20 +LegoCacheSoundManager::~LegoCacheSoundManager() +{ + LegoCacheSound* sound; + + while (!m_set.empty()) { + sound = (*m_set.begin()).GetSound(); + m_set.erase(m_set.begin()); + sound->FUN_10006b80(); + delete sound; + } + + while (!m_list.empty()) { + sound = (*m_list.begin()).GetSound(); + m_list.erase(m_list.begin()); + sound->FUN_10006b80(); + // DECOMP: delete should not be inlined here + delete sound; + } +} + +// FUNCTION: LEGO1 0x1003d050 +MxResult LegoCacheSoundManager::Tickle() +{ +#ifdef COMPAT_MODE + Set100d6b4c::iterator setIter; + for (setIter = m_set.begin(); setIter != m_set.end(); setIter++) { +#else + for (Set100d6b4c::iterator setIter = m_set.begin(); setIter != m_set.end(); setIter++) { +#endif + LegoCacheSound* sound = (*setIter).GetSound(); + if (sound->GetUnk0x58()) { + sound->FUN_10006be0(); + } + } + + List100d6b4c::iterator listIter = m_list.begin(); + while (listIter != m_list.end()) { + LegoCacheSound* sound = (*listIter).GetSound(); + + if (sound->GetUnk0x58()) { + sound->FUN_10006be0(); + listIter++; + } + else { + sound->FUN_10006b80(); + m_list.erase(listIter++); + delete sound; + } + } + + return SUCCESS; +} + +// STUB: LEGO1 0x1003d170 +LegoCacheSound* LegoCacheSoundManager::FUN_1003d170(const char* p_key) +{ + // TODO + char* x = new char[strlen(p_key) + 1]; + strcpy(x, p_key); + + Set100d6b4c::iterator setIter; + for (setIter = m_set.begin(); setIter != m_set.end(); setIter++) { + if (!strcmpi((*setIter).GetName(), x)) { + return (*setIter).GetSound(); + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x1003d290 +LegoCacheSound* LegoCacheSoundManager::FUN_1003d290(LegoCacheSound* p_sound) +{ + Set100d6b4c::iterator it = m_set.find(LegoCacheSoundEntry(p_sound)); + if (it != m_set.end()) { + LegoCacheSound* sound = (*it).GetSound(); + + if (sound->GetUnk0x58()) { + m_list.push_back(LegoCacheSoundEntry(p_sound)); + return p_sound; + } + else { + delete p_sound; + return sound; + } + } + + m_set.insert(LegoCacheSoundEntry(p_sound)); + LegoWorld* world = CurrentWorld(); + if (world) { + world->Add(p_sound); + } + + return p_sound; +} + +// FUNCTION: LEGO1 0x1003dae0 +LegoCacheSound* LegoCacheSoundManager::FUN_1003dae0(const char* p_one, const char* p_two, MxBool p_three) +{ + // DECOMP: Second parameter is LegoRoi::m_name (0xe4) + return FUN_1003db10(FUN_1003d170(p_one), p_two, p_three); +} + +// FUNCTION: LEGO1 0x1003db10 +LegoCacheSound* LegoCacheSoundManager::FUN_1003db10(LegoCacheSound* p_one, const char* p_two, MxBool p_three) +{ + if (!p_one) { + return NULL; + } + + if (p_one->GetUnk0x58()) { + LegoCacheSound* result = p_one->FUN_10006960(); + + if (result) { + LegoCacheSound* t = FUN_1003d290(result); + t->FUN_10006a30(p_two, p_three); + return t; + } + } + else { + p_one->FUN_10006a30(p_two, p_three); + return p_one; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x1003dc40 +void LegoCacheSoundManager::FUN_1003dc40(LegoCacheSound** p_und) +{ + // Called during LegoWorld::Destroy like this: + // SoundManager()->GetCacheSoundManager()->FUN_1003dc40(&sound); + // LegoCacheSound*& p_sound? + +#ifdef COMPAT_MODE + Set100d6b4c::iterator setIter; + for (setIter = m_set.begin(); setIter != m_set.end(); setIter++) { +#else + for (Set100d6b4c::iterator setIter = m_set.begin(); setIter != m_set.end(); setIter++) { +#endif + if ((*setIter).GetSound() == *p_und) { + (*p_und)->FUN_10006b80(); + + delete *p_und; + m_set.erase(setIter); + return; + } + } + +#ifdef COMPAT_MODE + List100d6b4c::iterator listIter; + for (listIter = m_list.begin();; listIter++) { +#else + for (List100d6b4c::iterator listIter = m_list.begin();; listIter++) { +#endif + if (listIter == m_list.end()) { + return; + } + + LegoCacheSound* sound = (*listIter).GetSound(); + if (sound == *p_und) { + (*p_und)->FUN_10006b80(); + + delete sound; + m_list.erase(listIter); + return; + } + } +} diff --git a/LEGO1/lego/legoomni/src/audio/legocachsound.cpp b/LEGO1/lego/legoomni/src/audio/legocachsound.cpp new file mode 100644 index 00000000..7d4f565c --- /dev/null +++ b/LEGO1/lego/legoomni/src/audio/legocachsound.cpp @@ -0,0 +1,161 @@ +#include "legocachsound.h" + +#include "legosoundmanager.h" +#include "misc.h" +#include "mxomni.h" + +DECOMP_SIZE_ASSERT(LegoCacheSound, 0x88) + +// FUNCTION: LEGO1 0x100064d0 +LegoCacheSound::LegoCacheSound() +{ + Init(); +} + +// STUB: LEGO1 0x10006630 +LegoCacheSound::~LegoCacheSound() +{ + // TODO + Destroy(); +} + +// FUNCTION: LEGO1 0x100066d0 +void LegoCacheSound::Init() +{ + m_dsBuffer = NULL; + m_unk0x40 = NULL; + m_unk0x58 = 0; + memset(&m_unk0x59, 0, sizeof(m_unk0x59)); + m_unk0x6a = FALSE; + m_unk0x70 = 0; + m_isLooping = TRUE; + m_unk0x6c = 79; + m_unk0x84 = 0; +} + +// STUB: LEGO1 0x10006710 +MxResult LegoCacheSound::FUN_10006710() +{ + // TODO + DSBUFFERDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (MxOmni::IsSound3D()) { + desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D; + } + else { + desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; + } + + if (SoundManager()->GetDirectSound()->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) { + return FAILURE; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10006920 +void LegoCacheSound::Destroy() +{ + if (m_dsBuffer) { + m_dsBuffer->Stop(); + m_dsBuffer->Release(); + m_dsBuffer = NULL; + } + + delete m_unk0x40; + Init(); +} + +// STUB: LEGO1 0x10006960 +LegoCacheSound* LegoCacheSound::FUN_10006960() +{ + // TODO + return NULL; +} + +// STUB: LEGO1 0x10006a30 +MxResult LegoCacheSound::FUN_10006a30(const char* p_str, MxBool) +{ + // TODO + // gets param2 from FUN_1003db10 + if (!m_unk0x40 && !m_unk0x44) { + return FAILURE; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10006b80 +void LegoCacheSound::FUN_10006b80() +{ + DWORD dwStatus; + + m_dsBuffer->GetStatus(&dwStatus); + if (dwStatus) { + m_dsBuffer->Stop(); + } + + m_unk0x58 = 0; + m_unk0x6a = FALSE; + + m_unk0x10.FUN_10011ca0(); + if (m_string0x74.GetLength() != 0) { + m_string0x74 = ""; + } +} + +// FUNCTION: LEGO1 0x10006be0 +void LegoCacheSound::FUN_10006be0() +{ + if (!m_isLooping) { + DWORD dwStatus; + m_dsBuffer->GetStatus(&dwStatus); + + if (m_unk0x70) { + if (dwStatus == 0) { + return; + } + + m_unk0x70 = 0; + } + + if (dwStatus == 0) { + m_dsBuffer->Stop(); + m_unk0x10.FUN_10011ca0(); + if (m_string0x74.GetLength() != 0) { + m_string0x74 = ""; + } + + m_unk0x58 = 0; + return; + } + } + + if (m_string0x74.GetLength() != 0 && !m_unk0x84) { + if (!m_unk0x10.FUN_100118e0(m_dsBuffer)) { + if (m_unk0x6a) { + return; + } + + m_dsBuffer->Stop(); + m_unk0x6a = TRUE; + } + else if (m_unk0x6a) { + m_dsBuffer->Play(0, 0, m_isLooping); + m_unk0x6a = FALSE; + } + } +} + +// FUNCTION: LEGO1 0x10006cb0 +void LegoCacheSound::FUN_10006cb0(undefined4 p_und1, undefined4 p_und2) +{ + m_unk0x10.FUN_10011cf0(p_und1, p_und2); +} + +// FUNCTION: LEGO1 0x10006cd0 +void LegoCacheSound::FUN_10006cd0(undefined4, undefined4) +{ +} diff --git a/LEGO1/lego/legoomni/src/audio/legoloadcachesoundpresenter.cpp b/LEGO1/lego/legoomni/src/audio/legoloadcachesoundpresenter.cpp new file mode 100644 index 00000000..59ca793b --- /dev/null +++ b/LEGO1/lego/legoomni/src/audio/legoloadcachesoundpresenter.cpp @@ -0,0 +1,88 @@ +#include "legoloadcachesoundpresenter.h" + +#include "legocachesoundmanager.h" +#include "legocachsound.h" +#include "legosoundmanager.h" +#include "misc.h" +#include "mxdssubscriber.h" +#include "mxstreamchunk.h" +#include "mxwavepresenter.h" + +DECOMP_SIZE_ASSERT(LegoLoadCacheSoundPresenter, 0x90) + +// FUNCTION: LEGO1 0x10018340 +LegoLoadCacheSoundPresenter::LegoLoadCacheSoundPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x10018480 +LegoLoadCacheSoundPresenter::~LegoLoadCacheSoundPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100184e0 +void LegoLoadCacheSoundPresenter::Init() +{ + this->m_unk0x70 = NULL; + this->m_unk0x78 = 0; + this->m_unk0x7c = 0; +} + +// FUNCTION: LEGO1 0x100184f0 +void LegoLoadCacheSoundPresenter::Destroy(MxBool p_fromDestructor) +{ + delete[] this->m_unk0x70; + MxWavePresenter::Destroy(p_fromDestructor); +} + +// FUNCTION: LEGO1 0x10018510 +void LegoLoadCacheSoundPresenter::ReadyTickle() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk) { + WaveFormat* header = (WaveFormat*) chunk->GetData(); + m_unk0x78 = 0; + + MxU8* data = new MxU8[header->m_dataSize]; + m_unk0x70 = data; + m_unk0x74 = data; + + m_cacheSound = new LegoCacheSound; + memcpy(&m_pcmWaveFormat, &header->m_pcmWaveFormat, sizeof(m_pcmWaveFormat)); + + m_subscriber->FreeDataChunk(chunk); + ProgressTickleState(e_streaming); + } +} + +// STUB: LEGO1 0x100185f0 +void LegoLoadCacheSoundPresenter::StreamingTickle() +{ + // TODO + EndAction(); +} + +// FUNCTION: LEGO1 0x100186f0 +void LegoLoadCacheSoundPresenter::DoneTickle() +{ + if (m_unk0x7c != 0) { + EndAction(); + } +} + +// FUNCTION: LEGO1 0x10018700 +MxResult LegoLoadCacheSoundPresenter::PutData() +{ + m_criticalSection.Enter(); + + if (m_currentTickleState == e_done) { + m_cacheSound = SoundManager()->GetCacheSoundManager()->FUN_1003d290(m_cacheSound); + m_unk0x7c = 1; + } + + m_criticalSection.Leave(); + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp b/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp new file mode 100644 index 00000000..942f8040 --- /dev/null +++ b/LEGO1/lego/legoomni/src/audio/legosoundmanager.cpp @@ -0,0 +1,104 @@ +#include "legosoundmanager.h" + +#include "legocachesoundmanager.h" +#include "mxautolock.h" +#include "mxomni.h" + +DECOMP_SIZE_ASSERT(LegoSoundManager, 0x44) + +// FUNCTION: LEGO1 0x100298a0 +LegoSoundManager::LegoSoundManager() +{ + Init(); +} + +// FUNCTION: LEGO1 0x10029940 +LegoSoundManager::~LegoSoundManager() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100299a0 +void LegoSoundManager::Init() +{ + m_cacheSoundManager = NULL; + m_listener = NULL; +} + +// FUNCTION: LEGO1 0x100299b0 +void LegoSoundManager::Destroy(MxBool p_fromDestructor) +{ + delete m_cacheSoundManager; + Init(); + + if (!p_fromDestructor) { + MxSoundManager::Destroy(); + } +} + +// FUNCTION: LEGO1 0x100299f0 +MxResult LegoSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) +{ + MxBool locked = FALSE; + MxResult result = FAILURE; + + if (MxSoundManager::Create(10, FALSE) == SUCCESS) { + m_criticalSection.Enter(); + locked = TRUE; + + if (MxOmni::IsSound3D()) { + if (m_dsBuffer->QueryInterface(IID_IDirectSound3DListener, (LPVOID*) &m_listener) != DS_OK) { + goto done; + } + + MxOmni* omni = MxOmni::GetInstance(); + LPDIRECTSOUND sound; + + if (omni && omni->GetSoundManager() && (sound = omni->GetSoundManager()->GetDirectSound())) { + DSCAPS caps; + memset(&caps, 0, sizeof(DSCAPS)); + caps.dwSize = sizeof(DSCAPS); + + if (sound->GetCaps(&caps) == S_OK && caps.dwMaxHw3DAllBuffers == 0) { + m_listener->SetDistanceFactor(0.026315790f, 0); + m_listener->SetRolloffFactor(10, 0); + } + } + } + + m_cacheSoundManager = new LegoCacheSoundManager; + result = SUCCESS; + } + +done: + if (result != SUCCESS) { + Destroy(); + } + + if (locked) { + m_criticalSection.Leave(); + } + + return result; +} + +// FUNCTION: LEGO1 0x1002a390 +void LegoSoundManager::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x1002a3a0 +MxResult LegoSoundManager::Tickle() +{ + MxSoundManager::Tickle(); + + AUTOLOCK(m_criticalSection); + return m_cacheSoundManager->Tickle(); +} + +// STUB: LEGO1 0x1002a410 +void LegoSoundManager::FUN_1002a410(const float* p_pos, const float* p_dir, const float* p_up, const float* p_vel) +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/audio/legounknown100d5778.cpp b/LEGO1/lego/legoomni/src/audio/legounknown100d5778.cpp new file mode 100644 index 00000000..3ff57585 --- /dev/null +++ b/LEGO1/lego/legoomni/src/audio/legounknown100d5778.cpp @@ -0,0 +1,90 @@ +#include "legounknown100d5778.h" + +#include "legocharactermanager.h" +#include "misc.h" +#include "mxomni.h" + +DECOMP_SIZE_ASSERT(LegoUnknown100d5778, 0x30) + +// FUNCTION: LEGO1 0x10011630 +LegoUnknown100d5778::LegoUnknown100d5778() +{ + Init(); +} + +// FUNCTION: LEGO1 0x10011670 +LegoUnknown100d5778::~LegoUnknown100d5778() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x10011680 +void LegoUnknown100d5778::Init() +{ + m_dsBuffer = NULL; + m_unk0x0c = NULL; + m_unk0x10 = 0; + m_unk0x18 = 0; + m_unk0x14 = FALSE; + m_unk0x15 = FALSE; + m_unk0x2c = 79; +} + +// STUB: LEGO1 0x100116a0 +MxResult LegoUnknown100d5778::FUN_100116a0(LPDIRECTSOUND p_dsound, undefined4, undefined4 p_unk0x2c) +{ + m_unk0x2c = p_unk0x2c; + + if (MxOmni::IsSound3D()) { + p_dsound->QueryInterface(IID_IDirectSoundBuffer, (LPVOID*) &m_dsBuffer); + if (m_dsBuffer == NULL) { + return FAILURE; + } + + // TODO + } + + // TODO + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10011880 +void LegoUnknown100d5778::Destroy() +{ + if (m_dsBuffer) { + m_dsBuffer->Release(); + m_dsBuffer = NULL; + } + + if (m_unk0x14 && m_unk0x0c && CharacterManager()) { + if (m_unk0x15) { + CharacterManager()->FUN_10083db0(m_unk0x0c); + } + else { + CharacterManager()->FUN_10083f10(m_unk0x0c); + } + } + + Init(); +} + +// STUB: LEGO1 0x100118e0 +undefined4 LegoUnknown100d5778::FUN_100118e0(LPDIRECTSOUNDBUFFER p_dsBuffer) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10011ca0 +void LegoUnknown100d5778::FUN_10011ca0() +{ + // TODO +} + +// STUB: LEGO1 0x10011cf0 +MxS32 LegoUnknown100d5778::FUN_10011cf0(undefined4, undefined4) +{ + // TODO + return 0; +} diff --git a/LEGO1/lego/legoomni/src/audio/mxbackgroundaudiomanager.cpp b/LEGO1/lego/legoomni/src/audio/mxbackgroundaudiomanager.cpp new file mode 100644 index 00000000..d10888ff --- /dev/null +++ b/LEGO1/lego/legoomni/src/audio/mxbackgroundaudiomanager.cpp @@ -0,0 +1,340 @@ +#include "mxbackgroundaudiomanager.h" + +#include "legomain.h" +#include "misc.h" +#include "mxaudiopresenter.h" +#include "mxcompositepresenter.h" +#include "mxdssound.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxpresenter.h" +#include "mxstreamer.h" +#include "mxticklemanager.h" +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(MxBackgroundAudioManager, 0x150) + +// FUNCTION: LEGO1 0x1007ea90 +MxBackgroundAudioManager::MxBackgroundAudioManager() +{ + NotificationManager()->Register(this); + m_unk0xa0 = 0; + m_unk0x138 = 0; + m_unk0x13c = 0; + m_unk0x140 = 0; + m_targetVolume = 0; + m_unk0x148 = 0; + m_enabled = FALSE; +} + +// FUNCTION: LEGO1 0x1007ec20 +MxBackgroundAudioManager::~MxBackgroundAudioManager() +{ + TickleManager()->UnregisterClient(this); + NotificationManager()->Unregister(this); + DestroyMusic(); +} + +// FUNCTION: LEGO1 0x1007ece0 +MxResult MxBackgroundAudioManager::Create(MxAtomId& p_script, MxU32 p_frequencyMS) +{ + MxResult result = OpenMusic(p_script); + + if (result == SUCCESS) { + TickleManager()->RegisterClient(this, p_frequencyMS); + m_enabled = TRUE; + } + + return result; +} + +// FUNCTION: LEGO1 0x1007ed20 +MxResult MxBackgroundAudioManager::OpenMusic(MxAtomId& p_script) +{ + if (m_script.GetInternal()) { + DestroyMusic(); + } + + MxResult result = FAILURE; + + if (Streamer()->Open(p_script.GetInternal(), 0)) { + m_script = p_script; + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x1007ed70 +void MxBackgroundAudioManager::DestroyMusic() +{ + if (m_script.GetInternal()) { + MxDSAction ds; + ds.SetAtomId(m_script); + ds.SetUnknown24(-2); + DeleteObject(ds); + Streamer()->Close(m_script.GetInternal()); + m_enabled = FALSE; + } +} + +// FUNCTION: LEGO1 0x1007ee40 +MxResult MxBackgroundAudioManager::Tickle() +{ + switch (m_unk0x13c) { + case MxPresenter::e_starting: + FadeInOrFadeOut(); + break; + case MxPresenter::e_streaming: + FUN_1007ee70(); + break; + case MxPresenter::e_repeating: + FUN_1007ef40(); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1007ee70 +void MxBackgroundAudioManager::FUN_1007ee70() +{ + if (m_unk0xa0 && m_unk0xa0->GetAction()) { + DeleteObject(*m_unk0x138->GetAction()); + } + + if (m_unk0x138) { + m_unk0xa0 = m_unk0x138; + m_action1 = m_action2; + m_unk0x138 = NULL; + m_action2.SetObjectId(-1); + m_action2.SetAtomId(MxAtomId()); + m_unk0x13c = 0; + } +} + +// FUNCTION: LEGO1 0x1007ef40 +void MxBackgroundAudioManager::FUN_1007ef40() +{ + MxS32 compare, volume; + + if (m_unk0xa0 == NULL) { + if (m_unk0x138) { + if (m_unk0x148 != 0) { + compare = 30; + } + else { + compare = m_targetVolume; + } + + volume = m_unk0x138->GetVolume(); + if (volume < compare) { + if (m_unk0x140 + m_unk0x138->GetVolume() <= compare) { + compare = m_unk0x140 + m_unk0x138->GetVolume(); + } + + m_unk0x138->SetVolume(compare); + } + else { + m_unk0x138->SetVolume(compare); + m_unk0xa0 = m_unk0x138; + m_action1 = m_action2; + m_unk0x138 = NULL; + m_action2.SetObjectId(-1); + m_action2.SetAtomId(MxAtomId()); + m_unk0x13c = 0; + } + } + } + else if (m_unk0xa0->GetAction() != NULL) { + if (m_unk0xa0->GetVolume() == 0) { + DeleteObject(*m_unk0xa0->GetAction()); + } + else { + if (m_unk0xa0->GetVolume() - m_unk0x140 > 0) { + volume = m_unk0xa0->GetVolume() - m_unk0x140; + } + else { + volume = 0; + } + + m_unk0xa0->SetVolume(volume); + } + } +} + +// FUNCTION: LEGO1 0x1007f0e0 +void MxBackgroundAudioManager::FadeInOrFadeOut() +{ + MxS32 volume, compare; + + if (m_unk0xa0 != NULL) { + volume = m_unk0xa0->GetVolume(); + + if (m_unk0x148 != 0) { + compare = 30; + } + else { + compare = m_targetVolume; + } + + if (volume < compare) { + volume = Min(volume + m_unk0x140, compare); + m_unk0xa0->SetVolume(volume); + } + else if (compare < volume) { + volume = Max(volume - m_unk0x140, compare); + m_unk0xa0->SetVolume(volume); + } + else { + m_unk0xa0->SetVolume(volume); + m_unk0x13c = 0; + } + } + else { + m_unk0x13c = 0; + } +} + +// FUNCTION: LEGO1 0x1007f170 +MxLong MxBackgroundAudioManager::Notify(MxParam& p_param) +{ + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationStartAction: + StartAction(p_param); + return 1; + case c_notificationEndAction: + StopAction(p_param); + return 1; + } + return 0; +} + +// FUNCTION: LEGO1 0x1007f1b0 +void MxBackgroundAudioManager::StartAction(MxParam& p_param) +{ + // TODO: the sender is most likely a MxAudioPresenter? + m_unk0x138 = (MxAudioPresenter*) ((MxNotificationParam&) p_param).GetSender(); + m_action2.SetAtomId(m_unk0x138->GetAction()->GetAtomId()); + m_action2.SetObjectId(m_unk0x138->GetAction()->GetObjectId()); + m_targetVolume = ((MxDSSound*) (m_unk0x138->GetAction()))->GetVolume(); + m_unk0x138->SetVolume(0); +} + +// FUNCTION: LEGO1 0x1007f200 +void MxBackgroundAudioManager::StopAction(MxParam& p_param) +{ + if (((MxNotificationParam&) p_param).GetSender() == m_unk0xa0) { + m_unk0xa0 = NULL; + m_action1.SetAtomId(MxAtomId()); + m_action1.SetObjectId(-1); + } + else if (((MxNotificationParam&) p_param).GetSender() == m_unk0x138) { + m_unk0x138 = NULL; + m_action2.SetAtomId(MxAtomId()); + m_action2.SetObjectId(-1); + } + + Lego()->HandleEndAction(p_param); +} + +// FUNCTION: LEGO1 0x1007f2f0 +MxResult MxBackgroundAudioManager::PlayMusic(MxDSAction& p_action, undefined4 p_unk0x140, undefined4 p_unk0x13c) +{ + if (!m_enabled) { + return SUCCESS; + } + + if (m_action2.GetObjectId() == -1 && m_action1.GetObjectId() != p_action.GetObjectId()) { + MxDSAction action; + action.SetAtomId(GetCurrentAction().GetAtomId()); + action.SetObjectId(GetCurrentAction().GetObjectId()); + action.SetUnknown24(GetCurrentAction().GetUnknown24()); + + m_action2.SetAtomId(p_action.GetAtomId()); + m_action2.SetObjectId(p_action.GetObjectId()); + m_action2.SetUnknown84(this); + m_action2.SetOrigin(this); + + MxResult result = Start(&m_action2); + + GetCurrentAction().SetAtomId(action.GetAtomId()); + GetCurrentAction().SetObjectId(action.GetObjectId()); + GetCurrentAction().SetUnknown24(action.GetUnknown24()); + + if (result == SUCCESS) { + m_unk0x13c = p_unk0x13c; + m_unk0x140 = p_unk0x140; + } + + return result; + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x1007f470 +void MxBackgroundAudioManager::Stop() +{ + if (m_action2.GetObjectId() != -1) { + DeleteObject(m_action2); + } + + m_unk0x138 = 0; + m_action2.SetAtomId(MxAtomId()); + m_action2.SetObjectId(-1); + + if (m_action1.GetObjectId() != -1) { + DeleteObject(m_action1); + } + + m_unk0xa0 = 0; + m_action1.SetAtomId(MxAtomId()); + m_unk0x148 = 0; + m_action1.SetObjectId(-1); + m_unk0x13c = 0; +} + +// FUNCTION: LEGO1 0x1007f570 +void MxBackgroundAudioManager::LowerVolume() +{ + if (m_unk0x148 == 0) { + if (m_unk0x13c == 0) { + m_unk0x13c = 2; + } + m_unk0x140 = 20; + } + m_unk0x148++; +} + +// FUNCTION: LEGO1 0x1007f5b0 +void MxBackgroundAudioManager::RaiseVolume() +{ + if (m_unk0x148 != 0) { + m_unk0x148--; + if (m_unk0x148 == 0) { + if (m_unk0x13c == 0) { + m_unk0x13c = 2; + } + m_unk0x140 = 10; + } + } +} + +// FUNCTION: LEGO1 0x1007f5f0 +void MxBackgroundAudioManager::Enable(MxBool p_enable) +{ + if (this->m_enabled != p_enable) { + this->m_enabled = p_enable; + + if (!p_enable) { + Stop(); + } + } +} + +// FUNCTION: LEGO1 0x1007f650 +void MxBackgroundAudioManager::Init() +{ + this->m_unk0xa0 = 0; + this->m_unk0x13c = 0; +} diff --git a/LEGO1/lego/legoomni/src/build/buildingentity.cpp b/LEGO1/lego/legoomni/src/build/buildingentity.cpp new file mode 100644 index 00000000..7986a589 --- /dev/null +++ b/LEGO1/lego/legoomni/src/build/buildingentity.cpp @@ -0,0 +1,29 @@ +#include "buildingentity.h" + +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxnotificationparam.h" + +DECOMP_SIZE_ASSERT(BuildingEntity, 0x68) + +// FUNCTION: LEGO1 0x10014e20 +BuildingEntity::BuildingEntity() +{ + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x10015030 +BuildingEntity::~BuildingEntity() +{ + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x100150a0 +MxLong BuildingEntity::Notify(MxParam& p_param) +{ + if (((MxNotificationParam&) p_param).GetType() == c_notificationType11) { + return VTable0x50(p_param); + } + + return 0; +} diff --git a/LEGO1/lego/legoomni/src/build/helicopterstate.cpp b/LEGO1/lego/legoomni/src/build/helicopterstate.cpp new file mode 100644 index 00000000..1a9ca3fa --- /dev/null +++ b/LEGO1/lego/legoomni/src/build/helicopterstate.cpp @@ -0,0 +1,3 @@ +#include "helicopterstate.h" + +DECOMP_SIZE_ASSERT(HelicopterState, 0x0c) diff --git a/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp b/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp new file mode 100644 index 00000000..5d2c1259 --- /dev/null +++ b/LEGO1/lego/legoomni/src/build/legobuildingmanager.cpp @@ -0,0 +1,725 @@ +#include "legobuildingmanager.h" + +#include "3dmanager/lego3dmanager.h" +#include "legocachesoundmanager.h" +#include "legoentity.h" +#include "legopathboundary.h" +#include "legosoundmanager.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "misc/legostorage.h" +#include "mxmisc.h" +#include "mxticklemanager.h" +#include "mxtimer.h" + +DECOMP_SIZE_ASSERT(LegoBuildingManager, 0x30) +DECOMP_SIZE_ASSERT(LegoBuildingInfo, 0x2c) +DECOMP_SIZE_ASSERT(LegoBuildingManager::AnimEntry, 0x14) + +// GLOBAL: LEGO1 0x100f3410 +const char* g_buildingInfoHausName[5] = { + "haus1", + "haus4", + "haus5", + "haus6", + "haus7", +}; + +// clang-format off +// GLOBAL: LEGO1 0x100f3428 +float g_buildingInfoDownshiftScale[16] = { + 0.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, +}; + +// GLOBAL: LEGO1 0x100f3468 +MxU8 g_buildingInfoDownshift[16] = { + 5, 5, 5, 5, + 3, 5, 5, 5, + 3, 5, 5, 5, + 5, 5, 5, 5, +}; + +// GLOBAL: LEGO1 0x100f3478 +LegoBuildingInfo g_buildingInfoInit[16] = { + { + NULL, "infocen", + 4, 0, 1, + -1, -1, 0x00, + 8.99999f, + "edg02_74", + 84.79617f, 9.0f, -10.2189f, + NULL, + }, + { + NULL, "policsta", + 4, 0, 1, + -1, -1, 0x10, + 0.999992f, + "int33", + 67.28488, 1.0f, -85.3917, + NULL, + }, + { + NULL, "Jail", + 4, 0, 1, + -1, -1, 0x10, + 0.0f, + "edg02_50", + 93.245659f, 0.0f, -48.7773f, + NULL, + }, + { + NULL, "races", + 4, 0, 1, + -1, -1, 0x10, + 0.0f, + "int14", + -21.7321f, 0.0f, 11.23354f, + NULL, + }, + { + NULL, "medcntr", + 4, 0, 1, + -1, -1, 0x10, + 3.99071f, + "edg02_27", + 86.020737f, 4.0f, 31.35498f, + NULL, + }, + { + NULL, "gas", + 4, 0, 1, + -1, -1, 0x10, + 0.0f, + "int24", + 26.32025f, 0.0f, -2.28938f, + NULL, + }, + { + NULL, "beach", + 4, 0, 1, + -1, -1, 0x10, + -1.8125f, + "edg00_46", + 14.375f, -1.3125f, -56.75f, + NULL, + }, + { + NULL, "racef", + 4, 0, 1, + -1, -1, 0x10, + 0.0f, + "edg03_03", + -4.15951f, 0.0f, 5.2003198f, + NULL, + }, + { + NULL, "racej", + 4, 0, 1, + -1, -1, 0x10, + 0.0f, + "edg03_03", + -4.15951f, 0.0f, 5.2003198f, + NULL, + }, + { + NULL, "Store", + 4, 0, 1, + -1, -1, 0x3e, + 2.0f, + "edg02_60", + -49.4744f, 2.0f, -56.6276f, + NULL, + }, + { + NULL, "Bank", + 4, 0, 1, + -1, -1, 0x3e, + 0.0f, + "edg02_36", + 18.53531f, 0.0f, -16.6053f, + NULL, + }, + { + NULL, "Post", + 4, 0, 1, + -1, -1, 0x3e, + 0.0f, + "edg02_58", + -33.5413f, 0.0f, -55.1791f, + NULL, + }, + { + NULL, "haus1", + 4, 0, 1, + -1, -1, 0x3f, + 7.0625f, + "int11", + -62.7827f, 7.0f, -45.2215f, + NULL, + }, + { + NULL, "haus2", + 4, 0, 1, + -1, -1, 0x3e, + 8.0f, + "int07", + -69.2376f, 8.0f, -6.8008099f, + NULL, + }, + { + NULL, "haus3", + 4, 0, 1, + -1, -1, 0x3e, + 7.0f, + "edg01_24", + -69.0596f, 7.0f, -24.4928f, + NULL, + }, + { + NULL, "Pizza", + 4, 0, 1, + -1, -1, 0x10, + 0.0f, + "int37", + -17.9438f, 0.0f, -46.827999f, + NULL, + }, +}; +// clang-format on + +// GLOBAL: LEGO1 0x100f3738 +MxU32 g_buildingCycle1Length = 6; + +// GLOBAL: LEGO1 0x100f373c +MxU32 g_cycleLengthOffset1 = 0x3c; + +// GLOBAL: LEGO1 0x100f3740 +MxU32 g_cycleLengthOffset3 = 0x42; + +// clang-format off +// GLOBAL: LEGO1 0x100f3788 +MxU32 g_buildingEntityId[16] = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x46, 0x49, 0x4c, + 0x4f, 0x52, 0x55, 0x00, +}; +// clang-format on + +// GLOBAL: LEGO1 0x100f37c8 +char* LegoBuildingManager::g_customizeAnimFile = NULL; + +// GLOBAL: LEGO1 0x100f37cc +MxS32 g_buildingManagerConfig = 1; + +// GLOBAL: LEGO1 0x10104c30 +LegoBuildingInfo g_buildingInfo[16]; + +// GLOBAL: LEGO1 0x100f3748 +MxS32 g_buildingCycle2Length[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0}; + +// FUNCTION: LEGO1 0x1002f8b0 +void LegoBuildingManager::configureLegoBuildingManager(MxS32 p_buildingManagerConfig) +{ + g_buildingManagerConfig = p_buildingManagerConfig; +} + +// FUNCTION: LEGO1 0x1002f8c0 +LegoBuildingManager::LegoBuildingManager() +{ + Init(); +} + +// FUNCTION: LEGO1 0x1002f960 +LegoBuildingManager::~LegoBuildingManager() +{ + delete g_customizeAnimFile; +} + +// FUNCTION: LEGO1 0x1002f9d0 +void LegoBuildingManager::Init() +{ + for (MxS32 i = 0; i < sizeOfArray(g_buildingInfo); i++) { + g_buildingInfo[i] = g_buildingInfoInit[i]; + } + + m_nextVariant = 0; + m_unk0x09 = 0; + m_numEntries = 0; + m_sound = NULL; + m_unk0x28 = FALSE; +} + +// FUNCTION: LEGO1 0x1002fa00 +// FUNCTION: BETA10 0x10063ad1 +void LegoBuildingManager::FUN_1002fa00() +{ + MxS32 i; + LegoWorld* world = CurrentWorld(); + + for (i = 0; i < sizeOfArray(g_buildingInfo); i++) { + UpdatePosition(i, world); + } + + if (g_buildingManagerConfig <= 1) { + LegoEntity* entity = (LegoEntity*) world->Find("MxEntity", g_buildingInfoHausName[0]); + if (entity) { + entity->GetROI()->SetVisibility(TRUE); + m_unk0x09 = 0; + } + } + else { + for (i = 0; i < sizeOfArray(g_buildingInfoHausName); i++) { + LegoEntity* entity = (LegoEntity*) world->Find("MxEntity", g_buildingInfoHausName[i]); + if (entity) { + entity->GetROI()->SetVisibility(m_nextVariant == i); + } + } + } + + m_unk0x09 = 0; +} + +// FUNCTION: LEGO1 0x1002fa90 +// FUNCTION: BETA10 0x10063b88 +void LegoBuildingManager::UpdatePosition(MxS32 p_index, LegoWorld* p_world) +{ + LegoEntity* entity = (LegoEntity*) p_world->Find("MxEntity", g_buildingInfo[p_index].m_hausName); + + if (entity) { + entity->SetType(LegoEntity::e_building); + g_buildingInfo[p_index].m_entity = entity; + LegoROI* roi = entity->GetROI(); + AdjustHeight(p_index); + MxMatrix mat = roi->GetLocal2World(); + mat[3][1] = g_buildingInfo[p_index].m_unk0x014; + roi->FUN_100a46b0(mat); + VideoManager()->Get3DManager()->Moved(*roi); + } +} + +// FUNCTION: LEGO1 0x1002fb30 +void LegoBuildingManager::FUN_1002fb30() +{ + MxU32 i; + + for (i = 0; i < sizeOfArray(g_buildingInfo); i++) { + g_buildingInfo[i].m_entity = NULL; + } + + m_unk0x09 = 0; + + for (i = 0; i < m_numEntries; i++) { + delete m_entries[i]; + } + + m_numEntries = 0; +} + +// FUNCTION: LEGO1 0x1002fb80 +// FUNCTION: BETA10 0x10063cae +MxResult LegoBuildingManager::Write(LegoStorage* p_storage) +{ + MxResult result = FAILURE; + + for (MxS32 i = 0; i < sizeOfArray(g_buildingInfo); i++) { + LegoBuildingInfo* info = &g_buildingInfo[i]; + + if (p_storage->Write(&info->m_cycle1, sizeof(info->m_cycle1)) != SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_cycle2, sizeof(info->m_cycle2)) != SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_cycle3, sizeof(info->m_cycle3)) != SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_initialUnk0x11, sizeof(info->m_initialUnk0x11)) != SUCCESS) { + goto done; + } + } + + if (p_storage->Write(&m_nextVariant, sizeof(m_nextVariant)) != SUCCESS) { + goto done; + } + + result = SUCCESS; + +done: + return result; +} + +// FUNCTION: LEGO1 0x1002fc10 +// FUNCTION: BETA10 0x10063dde +MxResult LegoBuildingManager::Read(LegoStorage* p_storage) +{ + MxResult result = FAILURE; + + for (MxS32 i = 0; i < sizeOfArray(g_buildingInfo); i++) { + LegoBuildingInfo* info = &g_buildingInfo[i]; + + if (p_storage->Read(&info->m_cycle1, sizeof(info->m_cycle1)) != SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_cycle2, sizeof(info->m_cycle2)) != SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_cycle3, sizeof(info->m_cycle3)) != SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_unk0x11, sizeof(info->m_unk0x11)) != SUCCESS) { + goto done; + } + + info->m_initialUnk0x11 = info->m_unk0x11; + AdjustHeight(i); + } + + if (p_storage->Read(&m_nextVariant, sizeof(m_nextVariant)) != SUCCESS) { + goto done; + } + + if (g_buildingManagerConfig <= 1) { + m_nextVariant = 0; + } + + result = SUCCESS; + +done: + return result; +} + +// FUNCTION: LEGO1 0x1002fcc0 +// FUNCTION: BETA10 0x10063f1a +void LegoBuildingManager::AdjustHeight(MxS32 p_index) +{ + if (g_buildingInfo[p_index].m_unk0x11 > 0) { + float value = g_buildingInfoDownshift[p_index] - g_buildingInfo[p_index].m_unk0x11; + g_buildingInfo[p_index].m_unk0x014 = + g_buildingInfoInit[p_index].m_unk0x014 - value * g_buildingInfoDownshiftScale[p_index]; + } + else if (g_buildingInfo[p_index].m_unk0x11 == 0) { + float value = g_buildingInfoDownshift[p_index] - g_buildingInfo[p_index].m_unk0x11; + g_buildingInfo[p_index].m_unk0x014 = + g_buildingInfoInit[p_index].m_unk0x014 - value * g_buildingInfoDownshiftScale[p_index]; + + if (g_buildingInfo[p_index].m_entity != NULL) { + LegoROI* roi = g_buildingInfo[p_index].m_entity->GetROI(); + if (roi != NULL) { + roi->SetVisibility(FALSE); + } + } + } + else { + g_buildingInfo[p_index].m_unk0x014 = g_buildingInfoInit[p_index].m_unk0x014; + } +} + +// FUNCTION: LEGO1 0x1002fd70 +// FUNCTION: BETA10 0x10063fc9 +LegoBuildingInfo* LegoBuildingManager::GetInfo(LegoEntity* p_entity) +{ + MxS32 i; + + for (i = 0; i < sizeOfArray(g_buildingInfo); i++) { + if (g_buildingInfo[i].m_entity == p_entity) { + break; + } + } + + if (i < sizeOfArray(g_buildingInfo)) { + return &g_buildingInfo[i]; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x1002fdb0 +// FUNCTION: BETA10 0x10064101 +MxBool LegoBuildingManager::IncrementVariant(LegoEntity* p_entity) +{ + if (g_buildingManagerConfig <= 1) { + return TRUE; + } + + LegoBuildingInfo* info = GetInfo(p_entity); + + if (info != NULL && info->m_flags & LegoBuildingInfo::c_bit1 && info->m_unk0x11 == -1) { + LegoROI* roi = p_entity->GetROI(); + if (++m_nextVariant >= sizeOfArray(g_buildingInfoHausName)) { + m_nextVariant = 0; + } + + roi->SetVisibility(FALSE); + info->m_hausName = g_buildingInfoHausName[m_nextVariant]; + UpdatePosition(12, CurrentWorld()); + + if (info->m_entity != NULL) { + info->m_entity->GetROI()->SetVisibility(TRUE); + } + + return TRUE; + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x1002fe40 +// FUNCTION: BETA10 0x100641d3 +MxBool LegoBuildingManager::FUN_1002fe40(LegoEntity* p_entity) +{ + MxBool result = FALSE; + LegoBuildingInfo* info = GetInfo(p_entity); + + if (info != NULL && info->m_flags & LegoBuildingInfo::c_bit2) { + info->m_cycle1++; + + if (info->m_cycle1 >= g_buildingCycle1Length) { + info->m_cycle1 = 0; + } + + result = TRUE; + } + + return result; +} + +// FUNCTION: LEGO1 0x1002fe80 +// FUNCTION: BETA10 0x10064242 +MxBool LegoBuildingManager::FUN_1002fe80(LegoEntity* p_entity) +{ + MxBool result = FALSE; + LegoBuildingInfo* info = GetInfo(p_entity); + + if (info != NULL && info->m_flags & LegoBuildingInfo::c_bit3) { + info->m_cycle2++; + + if (info->m_cycle2 >= g_buildingCycle2Length[info - g_buildingInfo]) { + info->m_cycle2 = 0; + } + + result = TRUE; + } + + return result; +} + +// FUNCTION: LEGO1 0x1002fed0 +// FUNCTION: BETA10 0x100642c2 +MxBool LegoBuildingManager::FUN_1002fed0(LegoEntity* p_entity) +{ + MxBool result = FALSE; + LegoBuildingInfo* info = GetInfo(p_entity); + + if (info != NULL && info->m_flags & LegoBuildingInfo::c_bit4) { + info->m_cycle3++; + + if (info->m_cycle3 > 3) { + info->m_cycle3 = 0; + } + + result = TRUE; + } + + return result; +} + +// FUNCTION: LEGO1 0x1002ff00 +// FUNCTION: BETA10 0x1006432d +MxU32 LegoBuildingManager::GetBuildingEntityId(LegoEntity* p_entity) +{ + LegoBuildingInfo* info = GetInfo(p_entity); + + if (info != NULL && info->m_flags & LegoBuildingInfo::c_bit3) { + return g_buildingEntityId[info - g_buildingInfo] + info->m_cycle2; + } + + return 0; +} + +// FUNCTION: LEGO1 0x1002ff40 +// FUNCTION: BETA10 0x10064398 +MxU32 LegoBuildingManager::FUN_1002ff40(LegoEntity* p_entity, MxBool p_state) +{ + LegoBuildingInfo* info = GetInfo(p_entity); + + if (info == NULL || !(info->m_flags & LegoBuildingInfo::c_bit2)) { + return 0; + } + + if (p_state) { + return info->m_cycle3 + g_cycleLengthOffset3; + } + + if (info != NULL) { + return info->m_cycle1 + g_cycleLengthOffset1; + } + + return 0; +} + +// FUNCTION: LEGO1 0x1002ff90 +void LegoBuildingManager::SetCustomizeAnimFile(const char* p_value) +{ + if (g_customizeAnimFile != NULL) { + delete[] g_customizeAnimFile; + } + + if (p_value != NULL) { + g_customizeAnimFile = new char[strlen(p_value) + 1]; + + if (g_customizeAnimFile != NULL) { + strcpy(g_customizeAnimFile, p_value); + } + } + else { + g_customizeAnimFile = NULL; + } +} + +// FUNCTION: LEGO1 0x10030000 +MxBool LegoBuildingManager::FUN_10030000(LegoEntity* p_entity) +{ + LegoBuildingInfo* info = GetInfo(p_entity); + + if (info == NULL) { + return FALSE; + } + + return FUN_10030030(info - g_buildingInfo); +} + +// STUB: LEGO1 0x10030030 +MxBool LegoBuildingManager::FUN_10030030(MxS32 p_index) +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x10030110 +MxBool LegoBuildingManager::FUN_10030110(LegoBuildingInfo* p_data) +{ + for (MxS32 i = 0; i < sizeOfArray(g_buildingInfo); i++) { + if (&g_buildingInfo[i] == p_data) { + return FUN_10030030(i); + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10030150 +void LegoBuildingManager::ScheduleAnimation(LegoEntity* p_entity, MxU32 p_length, MxBool p_haveSound, MxBool p_unk0x28) +{ + m_world = CurrentWorld(); + + if (p_haveSound) { + m_sound = SoundManager()->GetCacheSoundManager()->FUN_1003d170("bcrash"); + m_sound->FUN_10006cb0(35, 60); + } + + if (m_numEntries == 0) { + m_unk0x28 = p_unk0x28; + TickleManager()->RegisterClient(this, 50); + } + + AnimEntry* entry = m_entries[m_numEntries] = new AnimEntry; + m_numEntries++; + + entry->m_entity = p_entity; + entry->m_roi = p_entity->GetROI(); + entry->m_time = Timer()->GetTime() + p_length + 1000; + entry->m_unk0x0c = entry->m_roi->GetLocal2World()[3][1]; + entry->m_muted = p_haveSound == FALSE; + FUN_100307b0(p_entity, -2); +} + +// STUB: LEGO1 0x10030220 +MxResult LegoBuildingManager::Tickle() +{ + // WIP, included some of this to understand the AnimEntry array. + LegoTime time = Timer()->GetTime(); + + if (m_numEntries != 0) { + if (m_numEntries > 0) { + for (MxS32 i = 0; i < m_numEntries; i++) { + AnimEntry* entry = m_entries[i]; + if (entry->m_time <= time) { + // Code to animate and play sounds + } + } + } + } + else { + TickleManager()->UnregisterClient(this); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10030590 +// FUNCTION: BETA10 0x1006474c +void LegoBuildingManager::FUN_10030590() +{ + for (MxS32 i = 0; i < sizeOfArray(g_buildingInfo); i++) { + g_buildingInfo[i].m_unk0x11 = -1; + g_buildingInfo[i].m_initialUnk0x11 = -1; + AdjustHeight(i); + + if (g_buildingInfo[i].m_entity != NULL) { + LegoROI* roi = g_buildingInfo[i].m_entity->GetROI(); + MxMatrix mat = roi->GetLocal2World(); + mat[3][1] = g_buildingInfo[i].m_unk0x014; + roi->FUN_100a46b0(mat); + VideoManager()->Get3DManager()->Moved(*roi); + } + } +} + +// STUB: LEGO1 0x10030630 +MxResult LegoBuildingManager::FUN_10030630() +{ + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10030790 +LegoBuildingInfo* LegoBuildingManager::GetInfoArray(MxS32& p_length) +{ + if (m_unk0x09 == 0) { + FUN_10030630(); + } + + p_length = sizeOfArray(g_buildingInfo); + return g_buildingInfo; +} + +// FUNCTION: LEGO1 0x100307b0 +void LegoBuildingManager::FUN_100307b0(LegoEntity* p_entity, MxS32 p_adjust) +{ + LegoBuildingInfo* info = GetInfo(p_entity); + + if (info != NULL) { + if (info->m_unk0x11 < 0) { + info->m_unk0x11 = g_buildingInfoDownshift[info - g_buildingInfo]; + } + + if (info->m_unk0x11 > 0) { + info->m_unk0x11 += p_adjust; + if (info->m_unk0x11 <= 1 && p_adjust < 0) { + info->m_unk0x11 = 0; + } + } + } +} + +// FUNCTION: LEGO1 0x10030800 +void LegoBuildingManager::FUN_10030800() +{ + for (MxS32 i = 0; i < sizeOfArray(g_buildingInfo); i++) { + g_buildingInfo[i].m_initialUnk0x11 = g_buildingInfo[i].m_unk0x11; + } +} diff --git a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp new file mode 100644 index 00000000..90d06155 --- /dev/null +++ b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp @@ -0,0 +1,63 @@ +#include "legocarbuild.h" + +DECOMP_SIZE_ASSERT(LegoCarBuild, 0x34c) + +// STUB: LEGO1 0x100226d0 +LegoCarBuild::LegoCarBuild() +{ + // TODO +} + +// FUNCTION: LEGO1 0x10022930 +MxBool LegoCarBuild::VTable0x5c() +{ + return TRUE; +} + +// STUB: LEGO1 0x10022a80 +LegoCarBuild::~LegoCarBuild() +{ + // TODO +} + +// STUB: LEGO1 0x10022b70 +MxResult LegoCarBuild::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x100238b0 +MxResult LegoCarBuild::Tickle() +{ + // TODO + + return 0; +} + +// STUB: LEGO1 0x10024050 +MxLong LegoCarBuild::Notify(MxParam& p_param) +{ + // TODO + + return 0; +} + +// STUB: LEGO1 0x100242c0 +void LegoCarBuild::ReadyWorld() +{ + // TODO +} + +// STUB: LEGO1 0x100256c0 +void LegoCarBuild::Enable(MxBool p_enable) +{ + // TODO +} + +// STUB: LEGO1 0x10025e70 +MxBool LegoCarBuild::VTable0x64() +{ + // TODO + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/build/legovehiclebuildstate.cpp b/LEGO1/lego/legoomni/src/build/legovehiclebuildstate.cpp new file mode 100644 index 00000000..2e5df9ef --- /dev/null +++ b/LEGO1/lego/legoomni/src/build/legovehiclebuildstate.cpp @@ -0,0 +1,22 @@ +#include "legovehiclebuildstate.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(LegoVehicleBuildState, 0x50) + +// FUNCTION: LEGO1 0x10025f30 +LegoVehicleBuildState::LegoVehicleBuildState(char* p_classType) +{ + this->m_className = p_classType; + this->m_unk0x4c = 0; + this->m_unk0x4d = FALSE; + this->m_unk0x4e = FALSE; + this->m_placedPartCount = 0; +} + +// STUB: LEGO1 0x10026120 +MxResult LegoVehicleBuildState::Serialize(LegoFile* p_legoFile) +{ + // TODO + return LegoState::Serialize(p_legoFile); +} diff --git a/LEGO1/lego/legoomni/src/common/animstate.cpp b/LEGO1/lego/legoomni/src/common/animstate.cpp new file mode 100644 index 00000000..24a0bf12 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/animstate.cpp @@ -0,0 +1,46 @@ +#include "animstate.h" + +DECOMP_SIZE_ASSERT(AnimState, 0x1c) +DECOMP_SIZE_ASSERT(ModelInfo, 0x30) +DECOMP_SIZE_ASSERT(AnimInfo, 0x30) + +// FUNCTION: LEGO1 0x10064ff0 +AnimState::AnimState() +{ + m_unk0x0c = 0; + m_unk0x10 = NULL; + m_unk0x14 = 0; + m_unk0x18 = NULL; +} + +// STUB: LEGO1 0x10065150 +AnimState::~AnimState() +{ + // TODO +} + +// STUB: LEGO1 0x100651d0 +void AnimState::FUN_100651d0(MxU32, AnimInfo*, MxU32&) +{ + // TODO +} + +// STUB: LEGO1 0x10065240 +void AnimState::FUN_10065240(MxU32, AnimInfo*, MxU32) +{ + // TODO +} + +// STUB: LEGO1 0x100652d0 +MxResult AnimState::Serialize(LegoFile* p_legoFile) +{ + // TODO + return LegoState::Serialize(p_legoFile); +} + +// STUB: LEGO1 0x100654f0 +MxBool AnimState::SetFlag() +{ + // TODO + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp new file mode 100644 index 00000000..607a0595 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legoactioncontrolpresenter.cpp @@ -0,0 +1,100 @@ +#include "legoactioncontrolpresenter.h" + +#include "define.h" +#include "extra.h" +#include "legomain.h" +#include "legoutils.h" +#include "mxcompositepresenter.h" +#include "mxdssubscriber.h" +#include "mxmediapresenter.h" +#include "mxmisc.h" +#include "mxstreamchunk.h" +#include "mxticklemanager.h" +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(LegoActionControlPresenter, 0x68) + +// FUNCTION: LEGO1 0x10043ce0 +void LegoActionControlPresenter::ReadyTickle() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk) { + ParseExtra(); + ProgressTickleState(e_starting); + + m_subscriber->FreeDataChunk(chunk); + if (m_compositePresenter) { + if (m_action->GetDuration() == -1 || m_action->GetFlags() & 1) { + m_compositePresenter->VTable0x60(this); + } + } + } +} + +// FUNCTION: LEGO1 0x10043d40 +void LegoActionControlPresenter::RepeatingTickle() +{ + if (IsEnabled()) { + if (m_unk0x50 == 0) { + ParseExtra(); + } + + InvokeAction(m_unk0x50, MxAtomId(m_unk0x54.GetData(), e_lowerCase2), m_unk0x64, NULL); + ProgressTickleState(e_done); + } +} + +// FUNCTION: LEGO1 0x10043df0 +MxResult LegoActionControlPresenter::AddToManager() +{ + MxResult result = FAILURE; + + if (TickleManager()) { + result = SUCCESS; + TickleManager()->RegisterClient(this, 100); + } + + return result; +} + +// FUNCTION: LEGO1 0x10043e20 +void LegoActionControlPresenter::Destroy(MxBool p_fromDestructor) +{ + if (TickleManager()) { + TickleManager()->UnregisterClient(this); + } + + if (!p_fromDestructor) { + MxMediaPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x10043e50 +void LegoActionControlPresenter::ParseExtra() +{ + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[1024]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char output[1024]; + if (KeyValueStringParse(output, g_strACTION, extraCopy)) { + m_unk0x50 = MatchActionString(strtok(output, g_parseExtraTokens)); + + if (m_unk0x50 != Extra::ActionType::e_exit) { + MakeSourceName(extraCopy, strtok(NULL, g_parseExtraTokens)); + + m_unk0x54 = extraCopy; + m_unk0x54.ToLowerCase(); + if (m_unk0x50 != Extra::ActionType::e_run) { + m_unk0x64 = atoi(strtok(NULL, g_parseExtraTokens)); + } + } + } + } +} diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp new file mode 100644 index 00000000..812d9d93 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -0,0 +1,1871 @@ +#include "legoanimationmanager.h" + +#include "anim/legoanim.h" +#include "animstate.h" +#include "define.h" +#include "islepathactor.h" +#include "legoanimmmpresenter.h" +#include "legoanimpresenter.h" +#include "legocharactermanager.h" +#include "legoendanimnotificationparam.h" +#include "legoextraactor.h" +#include "legogamestate.h" +#include "legomain.h" +#include "legonavcontroller.h" +#include "legoroilist.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "mxutilities.h" +#include "viewmanager/viewmanager.h" + +#include + +DECOMP_SIZE_ASSERT(LegoAnimationManager, 0x500) +DECOMP_SIZE_ASSERT(LegoAnimationManager::Character, 0x18) +DECOMP_SIZE_ASSERT(LegoAnimationManager::Vehicle, 0x08) +DECOMP_SIZE_ASSERT(LegoAnimationManager::Extra, 0x18) +DECOMP_SIZE_ASSERT(LegoTranInfo, 0x78) + +// GLOBAL: LEGO1 0x100d8b28 +MxU8 g_unk0x100d8b28[] = {0, 1, 2, 4, 8, 16}; + +// GLOBAL: LEGO1 0x100f6d20 +LegoAnimationManager::Vehicle g_vehicles[] = { + {"bikebd", 0, FALSE}, + {"bikepg", 0, FALSE}, + {"bikerd", 0, FALSE}, + {"bikesy", 0, FALSE}, + {"motoni", 0, FALSE}, + {"motola", 0, FALSE}, + {"board", 0, FALSE} +}; + +// GLOBAL: LEGO1 0x100f7048 +LegoAnimationManager::Character g_characters[47] = { + {"pepper", FALSE, 6, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 1}, + {"mama", FALSE, -1, 0, FALSE, FALSE, FALSE, 1500, 20000, FALSE, 0, 2}, + {"papa", FALSE, -1, 0, FALSE, FALSE, FALSE, 1500, 20000, FALSE, 0, 3}, + {"nick", FALSE, 4, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 20, 4}, + {"laura", FALSE, 5, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 20, 5}, + {"brickstr", FALSE, -1, 0, FALSE, FALSE, FALSE, 1000, 20000, FALSE, 0, 6}, + {"studs", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"rhoda", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"valerie", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"snap", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"pt", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"mg", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"bu", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"ml", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"nu", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"na", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"cl", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"en", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"re", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"ro", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"d1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"d2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"d3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"d4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l5", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l6", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"b1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"b2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"b3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"b4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"cm", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"gd", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"rd", FALSE, 2, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 9}, + {"pg", FALSE, 1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 8}, + {"bd", FALSE, 0, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 100, 7}, + {"sy", FALSE, 3, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 100, 10}, + {"gn", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"df", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"bs", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"lt", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"st", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"bm", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"jk", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0} +}; + +// GLOBAL: LEGO1 0x100f74b0 +float g_unk0x100f74b0[6][3] = { + {10.0f, -1.0f, 1.0f}, + {7.0f, 144.0f, 100.0f}, + {5.0f, 100.0f, 36.0f}, + {3.0f, 36.0f, 25.0f}, + {1.0f, 25.0f, 16.0f}, + {-1.0f, 16.0f, 2.0f} +}; + +// GLOBAL: LEGO1 0x100f74f8 +MxS32 g_legoAnimationManagerConfig = 1; + +// GLOBAL: LEGO1 0x100f7500 +float g_unk0x100f7500 = 0.1f; + +// GLOBAL: LEGO1 0x100f7504 +MxS32 g_unk0x100f7504 = 0; + +// FUNCTION: LEGO1 0x1005eb50 +void LegoAnimationManager::configureLegoAnimationManager(MxS32 p_legoAnimationManagerConfig) +{ + g_legoAnimationManagerConfig = p_legoAnimationManagerConfig; +} + +// FUNCTION: LEGO1 0x1005eb60 +// FUNCTION: BETA10 0x1003f940 +LegoAnimationManager::LegoAnimationManager() +{ + m_unk0x1c = 0; + m_animState = NULL; + m_unk0x424 = NULL; + + Init(); + + NotificationManager()->Register(this); + TickleManager()->RegisterClient(this, 10); +} + +// FUNCTION: LEGO1 0x1005ed30 +// FUNCTION: BETA10 0x1003fa27 +LegoAnimationManager::~LegoAnimationManager() +{ + TickleManager()->UnregisterClient(this); + + FUN_10061010(FALSE); + + for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { + LegoROI* roi = m_extras[i].m_roi; + + if (roi != NULL) { + LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); + + if (actor != NULL && actor->GetController() != NULL && CurrentWorld() != NULL) { + CurrentWorld()->RemovePathActor(actor); + actor->SetController(NULL); + } + + CharacterManager()->FUN_10083db0(roi); + } + } + + if (m_tranInfoList != NULL) { + delete m_tranInfoList; + } + + if (m_tranInfoList2 != NULL) { + delete m_tranInfoList2; + } + + DeleteAnimations(); + + if (m_unk0x424 != NULL) { + FUN_10063aa0(); + delete m_unk0x424; + } + + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x1005ee80 +// FUNCTION: BETA10 0x1003fbc0 +void LegoAnimationManager::Reset(MxBool p_und) +{ + m_unk0x402 = FALSE; + + if (p_und && m_animState != NULL) { + m_animState->SetFlag(); + } + + MxBool suspended = m_suspended; + Suspend(); + + if (m_tranInfoList != NULL) { + delete m_tranInfoList; + } + + if (m_tranInfoList2 != NULL) { + delete m_tranInfoList2; + } + + DeleteAnimations(); + Init(); + + m_suspended = suspended; + m_unk0x428 = m_unk0x3a; + m_unk0x429 = m_unk0x400; + m_unk0x42a = m_unk0x402; +} + +// FUNCTION: LEGO1 0x1005ef10 +// FUNCTION: BETA10 0x1003fc7a +void LegoAnimationManager::Suspend() +{ + m_animState = (AnimState*) GameState()->GetState("AnimState"); + if (m_animState == NULL) { + m_animState = (AnimState*) GameState()->CreateState("AnimState"); + } + + if (m_scriptIndex == 0) { + m_animState->FUN_10065240(m_animCount, m_anims, m_lastExtraCharacterId); + } + + if (!m_suspended) { + m_suspended = TRUE; + m_unk0x428 = m_unk0x3a; + m_unk0x429 = m_unk0x400; + m_unk0x42a = m_unk0x402; + m_unk0x402 = FALSE; + + FUN_10061010(FALSE); + + MxS32 i; + for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { + LegoROI* roi = m_extras[i].m_roi; + + if (roi != NULL) { + LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); + + if (actor != NULL && actor->GetController() != NULL) { + actor->GetController()->RemoveActor(actor); + actor->SetController(NULL); + } + + CharacterManager()->FUN_10083db0(roi); + } + + if (m_extras[i].m_unk0x14) { + m_extras[i].m_unk0x14 = FALSE; + + MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId; + if (vehicleId >= 0) { + g_vehicles[vehicleId].m_unk0x05 = FALSE; + + LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name); + if (roi != NULL) { + roi->SetVisibility(FALSE); + } + } + } + + m_extras[i].m_roi = NULL; + m_extras[i].m_characterId = -1; + m_extras[i].m_unk0x10 = -1.0f; + } + + m_unk0x18 = 0; + m_unk0x1a = FALSE; + m_unk0x3a = FALSE; + m_unk0x400 = FALSE; + m_unk0x414 = 0; + m_unk0x401 = FALSE; + + for (i = 0; i < (MxS32) sizeOfArray(g_characters); i++) { + g_characters[i].m_unk0x04 = FALSE; + } + } +} + +// FUNCTION: LEGO1 0x1005f0b0 +// FUNCTION: BETA10 0x1003fefe +void LegoAnimationManager::Resume() +{ + if (m_suspended) { + m_unk0x408 = m_unk0x40c = m_unk0x404 = Timer()->GetTime(); + m_unk0x410 = 5000; + m_unk0x3a = m_unk0x428; + m_unk0x400 = m_unk0x429; + m_unk0x402 = m_unk0x42a; + m_suspended = FALSE; + } +} + +// FUNCTION: LEGO1 0x1005f130 +// FUNCTION: BETA10 0x1003ffb7 +void LegoAnimationManager::Init() +{ + m_unk0x402 = FALSE; + m_scriptIndex = -1; + m_animCount = 0; + m_anims = NULL; + m_unk0x18 = 0; + m_unk0x1a = FALSE; + m_tranInfoList = NULL; + m_tranInfoList2 = NULL; + m_unk0x41c = g_legoAnimationManagerConfig <= 1 ? 10 : 20; + + MxS32 i; + for (i = 0; i < (MxS32) sizeOfArray(m_unk0x28); i++) { + m_unk0x28[i] = NULL; + m_unk0x30[i] = 0; + } + + for (i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { + m_extras[i].m_roi = NULL; + m_extras[i].m_characterId = -1; + m_extras[i].m_unk0x10 = -1.0f; + m_extras[i].m_unk0x14 = FALSE; + } + + m_unk0x38 = FALSE; + m_unk0x39 = FALSE; + m_unk0x3a = TRUE; + m_lastExtraCharacterId = 0; + m_unk0x400 = FALSE; + m_unk0x414 = 0; + m_numAllowedExtras = 5; + m_unk0x0e = 0; + m_unk0x10 = 0; + m_unk0x401 = FALSE; + m_suspended = FALSE; + m_unk0x430 = FALSE; + m_unk0x42c = NULL; + m_unk0x408 = m_unk0x40c = m_unk0x404 = Timer()->GetTime(); + m_unk0x410 = 5000; + + for (i = 0; i < (MxS32) sizeOfArray(g_characters); i++) { + g_characters[i].m_active = FALSE; + g_characters[i].m_unk0x04 = FALSE; + } + + for (i = 0; i < (MxS32) sizeOfArray(g_vehicles); i++) { + g_vehicles[i].m_unk0x04 = FALSE; + g_vehicles[i].m_unk0x05 = FALSE; + } + + if (m_unk0x424 != NULL) { + FUN_10063aa0(); + delete m_unk0x424; + } + + m_unk0x424 = new LegoROIList(); +} + +// FUNCTION: LEGO1 0x1005f6d0 +// FUNCTION: BETA10 0x100401e7 +void LegoAnimationManager::FUN_1005f6d0(MxBool p_unk0x400) +{ + if (m_suspended) { + m_unk0x429 = p_unk0x400; + } + else { + m_unk0x400 = p_unk0x400; + + if (!p_unk0x400) { + PurgeExtra(TRUE); + } + } +} + +// FUNCTION: LEGO1 0x1005f700 +// FUNCTION: BETA10 0x1004024c +void LegoAnimationManager::FUN_1005f700(MxBool p_unk0x3a) +{ + if (m_suspended) { + m_unk0x428 = p_unk0x3a; + } + else { + m_unk0x3a = p_unk0x3a; + } +} + +// FUNCTION: LEGO1 0x1005f720 +MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex) +{ + MxResult result = FAILURE; + MxS32 i, j, k; + + if (m_scriptIndex != p_scriptIndex) { + if (m_tranInfoList != NULL) { + delete m_tranInfoList; + m_tranInfoList = NULL; + } + + if (m_tranInfoList2 != NULL) { + delete m_tranInfoList2; + m_tranInfoList2 = NULL; + } + + for (i = 0; i < (MxS32) sizeOfArray(m_unk0x28); i++) { + m_unk0x28[i] = NULL; + m_unk0x30[i] = 0; + } + + m_unk0x38 = FALSE; + m_unk0x39 = FALSE; + m_unk0x430 = FALSE; + m_unk0x42c = NULL; + + for (j = 0; j < (MxS32) sizeOfArray(g_characters); j++) { + g_characters[j].m_active = FALSE; + } + + m_animState = (AnimState*) GameState()->GetState("AnimState"); + if (m_animState == NULL) { + m_animState = (AnimState*) GameState()->CreateState("AnimState"); + } + + if (m_scriptIndex == 0) { + m_animState->FUN_10065240(m_animCount, m_anims, m_lastExtraCharacterId); + } + + DeleteAnimations(); + + LegoFile file; + + if (p_scriptIndex == -1) { + result = SUCCESS; + goto done; + } + + char filename[128]; + char path[1024]; + sprintf(filename, "lego\\data\\%sinf.dta", Lego()->GetScriptName(p_scriptIndex)); + sprintf(path, "%s", MxOmni::GetHD()); + + if (path[strlen(path) - 1] != '\\') { + strcat(path, "\\"); + } + + strcat(path, filename); + + if (_access(path, 4)) { + sprintf(path, "%s", MxOmni::GetCD()); + + if (path[strlen(path) - 1] != '\\') { + strcat(path, "\\"); + } + + strcat(path, filename); + + if (_access(path, 4)) { + goto done; + } + } + + if (file.Open(path, LegoFile::c_read) == FAILURE) { + goto done; + } + + MxU32 version; + if (file.Read(&version, sizeof(version)) == FAILURE) { + goto done; + } + + if (version != 3) { + OmniError("World animation version mismatch", 0); + goto done; + } + + if (file.Read(&m_animCount, sizeof(m_animCount)) == FAILURE) { + goto done; + } + + m_anims = new AnimInfo[m_animCount]; + memset(m_anims, 0, m_animCount * sizeof(*m_anims)); + + for (j = 0; j < m_animCount; j++) { + if (ReadAnimInfo(&file, &m_anims[j]) == FAILURE) { + goto done; + } + + m_anims[j].m_unk0x28 = GetCharacterIndex(m_anims[j].m_name + strlen(m_anims[j].m_name) - 2); + m_anims[j].m_unk0x29 = FALSE; + + for (k = 0; k < 3; k++) { + m_anims[j].m_unk0x2a[k] = -1; + } + + if (m_anims[j].m_unk0x08 == -1) { + for (MxS32 l = 0; l < m_anims[j].m_modelCount; l++) { + MxS32 index = GetCharacterIndex(m_anims[j].m_models[l].m_name); + + if (index >= 0) { + g_characters[index].m_active = TRUE; + } + } + } + + MxS32 count = 0; + for (MxS32 m = 0; m < m_anims[j].m_modelCount; m++) { + MxU32 n; + + if (FindVehicle(m_anims[j].m_models[m].m_name, n) && m_anims[j].m_models[m].m_unk0x2c) { + m_anims[j].m_unk0x2a[count++] = n; + if (count > 3) { + break; + } + } + } + } + + m_scriptIndex = p_scriptIndex; + m_tranInfoList = new LegoTranInfoList(); + m_tranInfoList2 = new LegoTranInfoList(); + + FUN_100617c0(-1, m_unk0x0e, m_unk0x10); + + result = SUCCESS; + m_unk0x402 = TRUE; + + if (m_suspended) { + m_unk0x428 = m_unk0x3a; + m_unk0x429 = m_unk0x400; + m_unk0x42a = TRUE; + m_unk0x3a = FALSE; + m_unk0x400 = FALSE; + m_unk0x402 = FALSE; + } + + if (p_scriptIndex == 0) { + m_animState->FUN_100651d0(m_animCount, m_anims, m_lastExtraCharacterId); + } + } + +done: + if (result == FAILURE) { + DeleteAnimations(); + } + + return result; +} + +// FUNCTION: LEGO1 0x10060140 +MxBool LegoAnimationManager::FindVehicle(const char* p_name, MxU32& p_index) +{ + for (MxS32 i = 0; i < sizeOfArray(g_vehicles); i++) { + if (!strcmpi(p_name, g_vehicles[i].m_name)) { + p_index = i; + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10060180 +MxResult LegoAnimationManager::ReadAnimInfo(LegoFile* p_file, AnimInfo* p_info) +{ + MxResult result = FAILURE; + MxU8 length; + MxS32 i, j; + + if (p_file->Read(&length, sizeof(length)) == FAILURE) { + goto done; + } + + p_info->m_name = new char[length + 1]; + if (p_file->Read(p_info->m_name, length) == FAILURE) { + goto done; + } + + p_info->m_name[length] = 0; + if (p_file->Read(&p_info->m_objectId, sizeof(p_info->m_objectId)) == FAILURE) { + goto done; + } + + if (p_file->Read(&p_info->m_unk0x08, sizeof(p_info->m_unk0x08)) == FAILURE) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x0a, sizeof(p_info->m_unk0x0a)) == FAILURE) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x0b, sizeof(p_info->m_unk0x0b)) == FAILURE) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x0c, sizeof(p_info->m_unk0x0c)) == FAILURE) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x0d, sizeof(p_info->m_unk0x0d)) == FAILURE) { + goto done; + } + + for (i = 0; i < (MxS32) sizeOfArray(p_info->m_unk0x10); i++) { + if (p_file->Read(&p_info->m_unk0x10[i], sizeof(*p_info->m_unk0x10)) != SUCCESS) { + goto done; + } + } + + if (p_file->Read(&p_info->m_modelCount, sizeof(p_info->m_modelCount)) == FAILURE) { + goto done; + } + + p_info->m_models = new ModelInfo[p_info->m_modelCount]; + memset(p_info->m_models, 0, p_info->m_modelCount * sizeof(*p_info->m_models)); + + for (j = 0; j < p_info->m_modelCount; j++) { + if (ReadModelInfo(p_file, &p_info->m_models[j]) == FAILURE) { + goto done; + } + } + + result = SUCCESS; + +done: + return result; +} + +// FUNCTION: LEGO1 0x10060310 +MxResult LegoAnimationManager::ReadModelInfo(LegoFile* p_file, ModelInfo* p_info) +{ + MxResult result = FAILURE; + MxU8 length; + + if (p_file->Read(&length, 1) == FAILURE) { + goto done; + } + + p_info->m_name = new char[length + 1]; + if (p_file->Read(p_info->m_name, length) == FAILURE) { + goto done; + } + + p_info->m_name[length] = 0; + if (p_file->Read(&p_info->m_unk0x04, sizeof(p_info->m_unk0x04)) == FAILURE) { + goto done; + } + + if (p_file->Read(p_info->m_location, sizeof(p_info->m_location)) != SUCCESS) { + goto done; + } + if (p_file->Read(p_info->m_direction, sizeof(p_info->m_direction)) != SUCCESS) { + goto done; + } + if (p_file->Read(p_info->m_up, sizeof(p_info->m_up)) != SUCCESS) { + goto done; + } + if (p_file->Read(&p_info->m_unk0x2c, sizeof(p_info->m_unk0x2c)) == FAILURE) { + goto done; + } + + result = SUCCESS; + +done: + return result; +} + +// FUNCTION: LEGO1 0x100603c0 +void LegoAnimationManager::DeleteAnimations() +{ + MxBool suspended = m_suspended; + + if (m_anims != NULL) { + for (MxS32 i = 0; i < m_animCount; i++) { + delete m_anims[i].m_name; + + if (m_anims[i].m_models != NULL) { + for (MxS32 j = 0; j < m_anims[i].m_modelCount; j++) { + delete m_anims[i].m_models[j].m_name; + } + + delete m_anims[i].m_models; + } + } + + delete m_anims; + } + + Init(); + m_suspended = suspended; +} + +// FUNCTION: LEGO1 0x10060570 +// FUNCTION: BETA10 0x10041463 +void LegoAnimationManager::FUN_10060570(MxBool p_unk0x1a) +{ + m_unk0x39 = FALSE; + m_unk0x430 = FALSE; + m_unk0x42c = NULL; + + if (m_unk0x1a != p_unk0x1a && (m_unk0x1a = p_unk0x1a)) { + do { + if (FUN_100605e0(m_unk0x18, TRUE, NULL, TRUE, NULL, FALSE, TRUE, TRUE, TRUE) != FAILURE) { + return; + } + + m_unk0x18++; + } while (m_unk0x18 < m_animCount); + + m_unk0x1a = FALSE; + m_unk0x18 = 0; + } +} + +// FUNCTION: LEGO1 0x100605e0 +// FUNCTION: BETA10 0x1004152b +MxResult LegoAnimationManager::FUN_100605e0( + MxU32 p_index, + MxBool p_unk0x0a, + MxMatrix* p_matrix, + MxBool p_bool1, + LegoROI* p_roi, + MxBool p_bool2, + MxBool p_bool3, + MxBool p_bool4, + MxBool p_bool5 +) +{ + MxResult result = FAILURE; + + if (m_scriptIndex != -1 && p_index < m_animCount && m_tranInfoList != NULL) { + PurgeExtra(FALSE); + FUN_10062770(); + + MxDSAction action; + AnimInfo& animInfo = m_anims[p_index]; + + if (!p_bool1) { + if (m_unk0x39 || !animInfo.m_unk0x29) { + return FAILURE; + } + + if (FUN_100623a0(animInfo)) { + return FAILURE; + } + + if (FUN_10062710(animInfo)) { + return FAILURE; + } + } + + FUN_10062580(animInfo); + + LegoTranInfo* tranInfo = new LegoTranInfo(); + tranInfo->m_animInfo = &animInfo; + tranInfo->m_index = ++m_unk0x1c; + tranInfo->m_unk0x10 = 0; + tranInfo->m_unk0x08 = p_roi; + tranInfo->m_unk0x12 = m_anims[p_index].m_unk0x08; + tranInfo->m_unk0x14 = p_unk0x0a; + tranInfo->m_objectId = animInfo.m_objectId; + tranInfo->m_unk0x15 = p_bool2; + + if (p_matrix != NULL) { + tranInfo->m_unk0x0c = new MxMatrix(*p_matrix); + } + + tranInfo->m_unk0x1c = m_unk0x28; + tranInfo->m_unk0x20 = m_unk0x30; + tranInfo->m_unk0x28 = p_bool3; + tranInfo->m_unk0x29 = p_bool4; + + if (m_tranInfoList != NULL) { + m_tranInfoList->Append(tranInfo); + } + + char buf[256]; + sprintf(buf, "%s:%d", g_strANIMMAN_ID, tranInfo->m_index); + + action.SetAtomId(*Lego()->GetScriptAtom(m_scriptIndex)); + action.SetObjectId(animInfo.m_objectId); + action.SetUnknown24(-1); + action.AppendExtra(strlen(buf) + 1, buf); + + if (StartActionIfUnknown0x13c(action) == SUCCESS) { + BackgroundAudioManager()->LowerVolume(); + tranInfo->m_flags |= LegoTranInfo::c_bit2; + animInfo.m_unk0x22++; + m_unk0x404 = Timer()->GetTime(); + + if (p_bool5) { + FUN_100648f0(tranInfo, m_unk0x404); + } + else if (p_unk0x0a) { + IslePathActor* actor = CurrentActor(); + + if (actor != NULL) { + actor->SetState(4); + actor->SetWorldSpeed(0.0f); + } + } + + m_unk0x39 = TRUE; + result = SUCCESS; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100609f0 +// FUNCTION: BETA10 0x10041a38 +MxResult LegoAnimationManager::FUN_100609f0(MxU32 p_objectId, MxMatrix* p_matrix, MxBool p_und1, MxBool p_und2) +{ + MxResult result = FAILURE; + MxDSAction action; + + PurgeExtra(FALSE); + + LegoTranInfo* info = new LegoTranInfo(); + info->m_animInfo = NULL; + info->m_index = ++m_unk0x1c; + info->m_unk0x10 = 0; + info->m_unk0x08 = NULL; + info->m_unk0x12 = -1; + info->m_unk0x14 = FALSE; + info->m_objectId = p_objectId; + + if (p_matrix != NULL) { + info->m_unk0x0c = new MxMatrix(*p_matrix); + } + + FUN_10062770(); + + info->m_unk0x1c = m_unk0x28; + info->m_unk0x20 = m_unk0x30; + info->m_unk0x28 = p_und1; + info->m_unk0x29 = p_und2; + + if (m_tranInfoList != NULL) { + m_tranInfoList->Append(info); + } + + char buf[256]; + sprintf(buf, "%s:%d", g_strANIMMAN_ID, info->m_index); + + action.SetAtomId(*Lego()->GetScriptAtom(m_scriptIndex)); + action.SetObjectId(p_objectId); + action.SetUnknown24(-1); + action.AppendExtra(strlen(buf) + 1, buf); + + if (StartActionIfUnknown0x13c(action) == SUCCESS) { + BackgroundAudioManager()->LowerVolume(); + info->m_flags |= LegoTranInfo::c_bit2; + m_unk0x39 = TRUE; + m_unk0x404 = Timer()->GetTime(); + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x10060d00 +MxResult LegoAnimationManager::StartEntityAction(MxDSAction& p_dsAction, LegoEntity* p_entity) +{ + MxResult result = FAILURE; + LegoROI* roi = p_entity->GetROI(); + + if (p_entity->GetType() == LegoEntity::e_character) { + LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); + + if (actor) { + LegoPathController* controller = actor->GetController(); + + if (controller) { + controller->RemoveActor(actor); + actor->SetController(NULL); + + for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { + if (m_extras[i].m_roi == roi) { + MxS32 characterId = m_extras[i].m_characterId; + g_characters[characterId].m_unk0x07 = TRUE; + MxS32 vehicleId = g_characters[characterId].m_vehicleId; + + if (vehicleId >= 0) { + g_vehicles[vehicleId].m_unk0x05 = FALSE; + } + break; + } + } + } + } + } + + if (LegoOmni::GetInstance()->StartActionIfUnknown0x13c(p_dsAction) == SUCCESS) { + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x10060dc0 +// FUNCTION: BETA10 0x10041f2c +MxResult LegoAnimationManager::FUN_10060dc0( + IsleScript::Script p_objectId, + MxMatrix* p_matrix, + MxBool p_param3, + MxBool p_param4, + LegoROI* p_roi, + MxBool p_param6, + MxBool p_param7, + MxBool p_param8, + MxBool p_param9 +) +{ + MxResult result = FAILURE; + MxBool found = FALSE; + + if (!Lego()->m_unk0x13c) { + return SUCCESS; + } + + for (MxS32 i = 0; i < m_animCount; i++) { + if (m_anims[i].m_objectId == p_objectId) { + found = TRUE; + MxBool unk0x0a; + + switch (p_param4) { + case FALSE: + unk0x0a = m_anims[i].m_unk0x0a; + break; + case TRUE: + unk0x0a = TRUE; + break; + default: + unk0x0a = FALSE; + break; + } + + result = FUN_100605e0(i, unk0x0a, p_matrix, p_param3, p_roi, p_param6, p_param7, p_param8, p_param9); + break; + } + } + + if (!found && p_param3 != FALSE) { + result = FUN_100609f0(p_objectId, p_matrix, p_param7, p_param8); + } + + return result; +} + +// FUNCTION: LEGO1 0x10061010 +// FUNCTION: BETA10 0x100422cc +void LegoAnimationManager::FUN_10061010(MxBool p_und) +{ + MxBool unk0x39 = FALSE; + + FUN_10064b50(-1); + + if (m_tranInfoList != NULL) { + LegoTranInfoListCursor cursor(m_tranInfoList); + LegoTranInfo* tranInfo; + + while (cursor.Next(tranInfo)) { + if (tranInfo->m_presenter != NULL) { + // TODO: Match + MxU32 flags = tranInfo->m_flags; + + if (tranInfo->m_unk0x14 && tranInfo->m_unk0x12 != -1 && p_und) { + LegoAnim* anim; + + if (tranInfo->m_presenter->GetPresenter() != NULL && + (anim = tranInfo->m_presenter->GetPresenter()->GetAnimation()) != NULL && + anim->GetScene() != NULL) { + if (flags & LegoTranInfo::c_bit2) { + BackgroundAudioManager()->RaiseVolume(); + tranInfo->m_flags &= ~LegoTranInfo::c_bit2; + } + + tranInfo->m_presenter->FUN_1004b840(); + tranInfo->m_unk0x14 = FALSE; + } + else { + tranInfo->m_presenter->FUN_1004b8c0(); + tranInfo->m_unk0x14 = FALSE; + unk0x39 = TRUE; + } + } + else { + if (flags & LegoTranInfo::c_bit2) { + BackgroundAudioManager()->RaiseVolume(); + tranInfo->m_flags &= ~LegoTranInfo::c_bit2; + } + + tranInfo->m_presenter->FUN_1004b840(); + } + } + else { + if (m_tranInfoList2 != NULL) { + LegoTranInfoListCursor cursor(m_tranInfoList2); + + if (!cursor.Find(tranInfo)) { + m_tranInfoList2->Append(tranInfo); + } + } + + unk0x39 = TRUE; + } + } + } + + m_unk0x39 = unk0x39; + m_unk0x404 = Timer()->GetTime(); +} + +// FUNCTION: LEGO1 0x10061530 +void LegoAnimationManager::FUN_10061530() +{ + if (m_tranInfoList2 != NULL) { + LegoTranInfoListCursor cursor(m_tranInfoList2); + LegoTranInfo* tranInfo; + + while (cursor.Next(tranInfo)) { + LegoTranInfoListCursor cursor2(m_tranInfoList); + + if (cursor2.Find(tranInfo)) { + if (tranInfo->m_presenter != NULL) { + if (tranInfo->m_flags & LegoTranInfo::c_bit2) { + BackgroundAudioManager()->RaiseVolume(); + tranInfo->m_flags &= ~LegoTranInfo::c_bit2; + } + + tranInfo->m_presenter->FUN_1004b840(); + cursor.Detach(); + } + } + else { + cursor.Detach(); + } + } + } +} + +// FUNCTION: LEGO1 0x100617c0 +// FUNCTION: BETA10 0x1004240b +MxResult LegoAnimationManager::FUN_100617c0(MxS32 p_unk0x08, MxU16& p_unk0x0e, MxU16& p_unk0x10) +{ + MxResult result = FAILURE; + MxU16 unk0x0e = 0; + MxU16 unk0x10 = 0; + MxBool success = FALSE; + + if (p_unk0x08 == -1) { + MxS32 i; + + for (i = 0; i < m_animCount; i++) { + if (m_anims[i].m_unk0x08 == p_unk0x08) { + unk0x0e = i; + success = TRUE; + break; + } + } + + if (success) { + for (; i < m_animCount && m_anims[i].m_unk0x08 == p_unk0x08; i++) { + unk0x10 = i; + } + } + } + else { + MxS32 i; + + for (i = 0; m_animCount > i && m_anims[i].m_unk0x08 != -1; i++) { + if (m_anims[i].m_unk0x08 == p_unk0x08) { + unk0x0e = i; + success = TRUE; + break; + } + } + + if (success) { + for (; i < m_animCount && m_anims[i].m_unk0x08 == p_unk0x08; i++) { + unk0x10 = i; + } + } + } + + if (success) { + p_unk0x0e = unk0x0e; + p_unk0x10 = unk0x10; + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x100618f0 +// FUNCTION: BETA10 0x100425f0 +LegoTranInfo* LegoAnimationManager::GetTranInfo(MxU32 p_index) +{ + if (m_tranInfoList != NULL) { + LegoTranInfoListCursor cursor(m_tranInfoList); + LegoTranInfo* tranInfo; + + while (cursor.Next(tranInfo)) { + if (tranInfo->m_index == p_index) { + return tranInfo; + } + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x100619f0 +// FUNCTION: BETA10 0x100426b1 +MxLong LegoAnimationManager::Notify(MxParam& p_param) +{ + if (((MxNotificationParam&) p_param).GetSender() == this) { + if (((MxNotificationParam&) p_param).GetType() == c_notificationEndAnim) { + FUN_100605e0(m_unk0x18, TRUE, NULL, TRUE, NULL, FALSE, TRUE, TRUE, TRUE); + } + } + else if (((MxNotificationParam&) p_param).GetType() == c_notificationEndAnim && m_tranInfoList != NULL) { + LegoTranInfoListCursor cursor(m_tranInfoList); + LegoTranInfo* tranInfo; + + MxU32 index = ((LegoEndAnimNotificationParam&) p_param).GetIndex(); + MxBool found = FALSE; + + while (cursor.Next(tranInfo)) { + if (tranInfo->m_index == index) { + if (m_unk0x430 && m_unk0x42c == tranInfo) { + FUN_10064b50(-1); + } + + if (tranInfo->m_flags & LegoTranInfo::c_bit2) { + BackgroundAudioManager()->RaiseVolume(); + } + + m_unk0x39 = FALSE; + m_unk0x404 = Timer()->GetTime(); + + found = TRUE; + cursor.Detach(); + delete tranInfo; + + for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { + LegoROI* roi = m_extras[i].m_roi; + + if (roi != NULL) { + LegoExtraActor* actor = CharacterManager()->GetActor(roi->GetName()); + + if (actor != NULL) { + actor->Restart(); + } + } + } + + break; + } + } + + if (m_unk0x1a && found) { + m_unk0x18++; + + if (m_animCount <= m_unk0x18) { + m_unk0x1a = FALSE; + } + else { + LegoEndAnimNotificationParam param(c_notificationEndAnim, this, 0); + NotificationManager()->Send(this, param); + } + } + } + + return 0; +} + +// FUNCTION: LEGO1 0x10061cc0 +// FUNCTION: BETA10 0x1004293c +MxResult LegoAnimationManager::Tickle() +{ + FUN_10061530(); + + if (!m_unk0x402) { + return SUCCESS; + } + + IslePathActor* actor = CurrentActor(); + LegoROI* roi; + + if (actor == NULL || (roi = actor->GetROI()) == NULL) { + return SUCCESS; + } + + if (m_unk0x401) { + for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { + LegoROI* roi = m_extras[i].m_roi; + + if (roi != NULL && m_extras[i].m_unk0x0d) { + LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); + + if (actor != NULL && actor->GetController() != NULL) { + actor->GetController()->RemoveActor(actor); + actor->SetController(NULL); + } + + CharacterManager()->FUN_10083db0(roi); + + if (m_extras[i].m_unk0x14) { + m_extras[i].m_unk0x14 = FALSE; + + MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId; + if (vehicleId >= 0) { + g_vehicles[vehicleId].m_unk0x05 = FALSE; + + LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name); + if (roi != NULL) { + roi->SetVisibility(FALSE); + } + } + } + + m_extras[i].m_roi = NULL; + g_characters[m_extras[i].m_characterId].m_unk0x04 = FALSE; + g_characters[m_extras[i].m_characterId].m_unk0x07 = FALSE; + m_extras[i].m_characterId = -1; + m_extras[i].m_unk0x0d = FALSE; + m_unk0x414--; + } + } + + m_unk0x401 = FALSE; + } + + MxLong time = Timer()->GetTime(); + float speed = actor->GetWorldSpeed(); + + FUN_10064b50(time); + + if (!m_unk0x39 && time - m_unk0x404 > 10000 && speed < g_unk0x100f74b0[0][0] && speed > g_unk0x100f74b0[5][0]) { + LegoPathBoundary* boundary = actor->GetBoundary(); + + Mx3DPointFloat position(roi->GetWorldPosition()); + Mx3DPointFloat direction(roi->GetWorldDirection()); + + MxU8 unk0x0c = 0; + MxU8 actorId = GameState()->GetActorId(); + + if (actorId <= 5) { + unk0x0c = g_unk0x100d8b28[actorId]; + } + + for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { + LegoROI* roi = m_extras[i].m_roi; + + if (roi != NULL) { + MxU16 result = FUN_10062110(roi, direction, position, boundary, speed, unk0x0c, m_extras[i].m_unk0x14); + + if (result) { + MxMatrix mat; + mat = roi->GetLocal2World(); + + if (FUN_100605e0(result & USHRT_MAX, FALSE, &mat, TRUE, roi, FALSE, TRUE, TRUE, TRUE) == SUCCESS) { + m_unk0x404 = time; + return SUCCESS; + } + } + } + } + } + + if (time - m_unk0x40c > 1000) { + FUN_10063d10(); + m_unk0x40c = time; + } + + if (time - m_unk0x408 < m_unk0x410) { + return SUCCESS; + } + + m_unk0x410 = (rand() * 10000 / SHRT_MAX) + 5000; + m_unk0x408 = time; + + if (time - m_unk0x404 > 10000) { + AddExtra(-1, FALSE); + } + + double elapsedSeconds = VideoManager()->GetElapsedSeconds(); + + if (elapsedSeconds < 1.0 && elapsedSeconds > 0.01) { + g_unk0x100f7500 = (g_unk0x100f7500 * 2.0 + elapsedSeconds) / 3.0; + + if (elapsedSeconds > 0.2 && m_numAllowedExtras > 2) { + m_numAllowedExtras--; + } + else if (g_unk0x100f7500 < 0.16 && m_numAllowedExtras < m_unk0x41c) { + m_numAllowedExtras++; + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10062110 +// FUNCTION: BETA10 0x10042f41 +MxU16 LegoAnimationManager::FUN_10062110( + LegoROI* p_roi, + Vector3& p_direction, + Vector3& p_position, + LegoPathBoundary* p_boundary, + float p_speed, + MxU8 p_unk0x0c, + MxBool p_unk0x14 +) +{ + LegoPathActor* actor = (LegoPathActor*) p_roi->GetEntity(); + + if (actor != NULL && actor->GetBoundary() == p_boundary && actor->GetState() == 0) { + if (GetViewManager()->FUN_100a6150(p_roi->GetWorldBoundingBox())) { + Mx3DPointFloat direction(p_roi->GetWorldDirection()); + + if (direction.Dot(&direction, &p_direction) > 0.707) { + Mx3DPointFloat position(p_roi->GetWorldPosition()); + + // TODO: Fix call + ((Vector3&) position).Sub(&p_position); + float len = position.LenSquared(); + float min, max; + + for (MxU32 i = 0; i < sizeOfArray(g_unk0x100f74b0); i++) { + if (g_unk0x100f74b0[i][0] < p_speed) { + max = g_unk0x100f74b0[i][1]; + min = g_unk0x100f74b0[i][2]; + break; + } + } + + if (len < max && len > min) { + MxS8 index = GetCharacterIndex(p_roi->GetName()); + + for (MxU16 i = m_unk0x0e; i <= m_unk0x10; i++) { + if (m_anims[i].m_unk0x28 == index && m_anims[i].m_unk0x0c & p_unk0x0c && m_anims[i].m_unk0x29) { + MxS32 vehicleId = g_characters[index].m_vehicleId; + if (vehicleId >= 0) { + MxBool found = FALSE; + + for (MxS32 j = 0; j < (MxS32) sizeOfArray(m_anims[i].m_unk0x2a); j++) { + if (m_anims[i].m_unk0x2a[j] == vehicleId) { + found = TRUE; + break; + } + } + + if (p_unk0x14 != found) { + continue; + } + } + + MxU16 result = i; + MxU16 unk0x22 = m_anims[i].m_unk0x22; + + for (i = i + 1; i <= m_unk0x10; i++) { + if (m_anims[i].m_unk0x28 == index && m_anims[i].m_unk0x0c & p_unk0x0c && + m_anims[i].m_unk0x29 && m_anims[i].m_unk0x22 < unk0x22) { + result = i; + unk0x22 = m_anims[i].m_unk0x22; + } + } + + return result; + } + } + } + } + } + } + + return 0; +} + +// FUNCTION: LEGO1 0x10062360 +// FUNCTION: BETA10 0x100432dd +MxS8 LegoAnimationManager::GetCharacterIndex(const char* p_name) +{ + MxS8 i; + + for (i = 0; i < sizeOfArray(g_characters); i++) { + if (!strnicmp(p_name, g_characters[i].m_name, 2)) { + return i; + } + } + + return -1; +} + +// FUNCTION: LEGO1 0x100623a0 +// FUNCTION: BETA10 0x10043342 +MxBool LegoAnimationManager::FUN_100623a0(AnimInfo& p_info) +{ + LegoWorld* world = CurrentWorld(); + + if (world != NULL) { + LegoEntityList* entityList = world->GetEntityList(); + + if (entityList != NULL) { + Mx3DPointFloat position(p_info.m_unk0x10[0], p_info.m_unk0x10[1], p_info.m_unk0x10[2]); + float und = p_info.m_unk0x10[3]; + + LegoEntityListCursor cursor(entityList); + LegoEntity* entity; + IslePathActor* actor = CurrentActor(); + + while (cursor.Next(entity)) { + if (entity != actor && entity->IsA("LegoPathActor")) { + LegoROI* roi = entity->GetROI(); + + if (roi->GetVisibility() && FUN_10062650(position, und, roi)) { + if (!ModelExists(p_info, roi->GetName())) { + return TRUE; + } + } + } + } + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10062520 +// FUNCTION: BETA10 0x100434bf +MxBool LegoAnimationManager::ModelExists(AnimInfo& p_info, const char* p_name) +{ + ModelInfo* models = p_info.m_models; + MxU8 modelCount = p_info.m_modelCount; + + if (models != NULL && modelCount) { + for (MxU8 i = 0; i < modelCount; i++) { + if (!strcmpi(models[i].m_name, p_name)) { + return TRUE; + } + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10062580 +// FUNCTION: BETA10 0x10043552 +void LegoAnimationManager::FUN_10062580(AnimInfo& p_info) +{ + ModelInfo* models = p_info.m_models; + MxU8 modelCount = p_info.m_modelCount; + + if (models != NULL && modelCount) { + for (MxU8 i = 0; i < modelCount; i++) { + LegoPathActor* actor = CharacterManager()->GetActor(models[i].m_name); + + if (actor) { + LegoPathController* controller = actor->GetController(); + + if (controller) { + controller->RemoveActor(actor); + actor->SetController(NULL); + + for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { + if (m_extras[i].m_roi == actor->GetROI()) { + MxS32 characterId = m_extras[i].m_characterId; + g_characters[characterId].m_unk0x07 = TRUE; + MxS32 vehicleId = g_characters[characterId].m_vehicleId; + + if (vehicleId >= 0) { + g_vehicles[vehicleId].m_unk0x05 = FALSE; + } + break; + } + } + } + } + } + } +} + +// FUNCTION: LEGO1 0x10062650 +// FUNCTION: BETA10 0x100436e2 +MxBool LegoAnimationManager::FUN_10062650(Vector3& p_position, float p_und, LegoROI* p_roi) +{ + if (p_roi != NULL) { + Mx3DPointFloat position(p_position); + + // TODO: Fix call + ((Vector3&) position).Sub(p_roi->GetWorldPosition()); + + float len = position.LenSquared(); + if (len <= 0.0f) { + return TRUE; + } + + len = sqrt(len); + if (p_roi->GetWorldBoundingSphere().Radius() + p_und >= len) { + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10062710 +// FUNCTION: BETA10 0x10043787 +MxBool LegoAnimationManager::FUN_10062710(AnimInfo& p_info) +{ + MxU8 und = 0; + MxU8 actorId = GameState()->GetActorId(); + + if (actorId <= 5) { + und = g_unk0x100d8b28[actorId]; + } + + if (!(und & p_info.m_unk0x0c)) { + return TRUE; + } + + if (ModelExists(p_info, GameState()->GetActorName())) { + return TRUE; + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10062770 +// FUNCTION: BETA10 0x1004381a +void LegoAnimationManager::FUN_10062770() +{ + if (!m_unk0x38) { + LegoWorld* world = CurrentWorld(); + + if (world != NULL) { + m_unk0x28[1] = (MxPresenter*) world->Find("MxSoundPresenter", "TransitionSound1"); + m_unk0x28[0] = (MxPresenter*) world->Find("MxSoundPresenter", "TransitionSound2"); + m_unk0x30[1] = 200; + m_unk0x30[0] = 750; + m_unk0x38 = TRUE; + } + } +} + +// FUNCTION: LEGO1 0x100627d0 +// FUNCTION: BETA10 0x1004389d +void LegoAnimationManager::PurgeExtra(MxBool p_und) +{ + ViewManager* viewManager = GetViewManager(); + + if (p_und || viewManager != NULL) { + MxLong time = Timer()->GetTime(); + + for (MxS32 i = 0; i < (MxS32) sizeOfArray(m_extras); i++) { + LegoROI* roi = m_extras[i].m_roi; + + if (roi != NULL) { + MxU16 prefix = *(MxU16*) roi->GetName(); + MxLong und = ((m_numAllowedExtras - 2) * 280000 / 18) + 20000; + MxBool maOrPa = prefix == TWOCC('m', 'a') || prefix == TWOCC('p', 'a'); + + if ((p_und && !maOrPa) || + (g_characters[m_extras[i].m_characterId].m_unk0x10 >= 0 && time - m_extras[i].m_unk0x08 > und && + CharacterManager()->GetRefCount(roi) == 1 && + !viewManager->FUN_100a6150(roi->GetWorldBoundingBox()))) { + m_unk0x414--; + + LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); + if (actor != NULL && actor->GetController() != NULL) { + actor->GetController()->RemoveActor(actor); + actor->SetController(NULL); + } + + CharacterManager()->FUN_10083db0(roi); + + if (m_extras[i].m_unk0x14) { + m_extras[i].m_unk0x14 = FALSE; + + MxS32 vehicleId = g_characters[m_extras[i].m_characterId].m_vehicleId; + if (vehicleId >= 0) { + g_vehicles[vehicleId].m_unk0x05 = FALSE; + + LegoROI* roi = Lego()->FindROI(g_vehicles[vehicleId].m_name); + if (roi != NULL) { + roi->SetVisibility(FALSE); + } + } + } + + m_extras[i].m_roi = NULL; + g_characters[m_extras[i].m_characterId].m_unk0x04 = FALSE; + g_characters[m_extras[i].m_characterId].m_unk0x07 = FALSE; + m_extras[i].m_characterId = -1; + } + } + } + } +} + +// FUNCTION: LEGO1 0x100629b0 +// FUNCTION: BETA10 0x10043c10 +void LegoAnimationManager::AddExtra(MxS32 p_location, MxBool p_und) +{ + LegoLocation::Boundary* boundary = NULL; + + if (p_und || (!m_unk0x39 && m_unk0x400)) { + LegoWorld* world = CurrentWorld(); + + if (world != NULL) { + PurgeExtra(FALSE); + + IslePathActor* actor = CurrentActor(); + if (actor == NULL || actor->GetWorldSpeed() <= 20.0f) { + MxU32 i; + for (i = 0; i < m_numAllowedExtras && m_extras[i].m_roi != NULL; i++) { + } + + if (i != m_numAllowedExtras) { + MxU8 und = rand() % 2 != 0 ? 1 : 2; + MxBool bool1, bool2; + + switch (g_unk0x100f7504 % 4) { + case 0: + bool1 = FALSE; + bool2 = FALSE; + break; + case 1: + bool1 = FALSE; + bool2 = TRUE; + break; + default: + bool1 = TRUE; + bool2 = FALSE; + break; + } + + if (p_location < 0) { + boundary = new LegoLocation::Boundary; + + if (!FUN_10064120(boundary, und == 2, bool2)) { + delete boundary; + boundary = NULL; + } + } + else { + LegoLocation* location = LegoNavController::GetLocation(p_location); + + if (location != NULL) { + if (location->m_boundaryA.m_unk0x10 || FUN_10063fb0(&location->m_boundaryA, world)) { + boundary = &location->m_boundaryA; + } + else if (location->m_boundaryB.m_unk0x10 || FUN_10063fb0(&location->m_boundaryB, world)) { + boundary = &location->m_boundaryB; + } + } + + bool1 = FALSE; + } + + if (boundary != NULL) { + for (i = 0; i < m_numAllowedExtras; i++) { + if (m_extras[i].m_roi == NULL) { + m_lastExtraCharacterId++; + + if (m_lastExtraCharacterId >= sizeOfArray(g_characters)) { + m_lastExtraCharacterId = 0; + } + + MxU32 characterIdStart = m_lastExtraCharacterId; + + MxBool active; + if (bool1) { + active = TRUE; + } + else { + active = rand() % 100 < 50; + } + + tryNextCharacter: + if (g_characters[m_lastExtraCharacterId].m_unk0x09 && + g_characters[m_lastExtraCharacterId].m_unk0x08 && + !g_characters[m_lastExtraCharacterId].m_unk0x04 && + g_characters[m_lastExtraCharacterId].m_active == active) { + if (!CharacterManager()->FUN_10083b20(g_characters[m_lastExtraCharacterId].m_name + )) { + m_extras[i].m_roi = CharacterManager()->GetROI( + g_characters[m_lastExtraCharacterId].m_name, + TRUE + ); + + LegoExtraActor* actor = + CharacterManager()->GetActor(g_characters[m_lastExtraCharacterId].m_name); + + switch (g_unk0x100f7504++ % 4) { + case 0: + actor->SetUnknown0x0c(und != 1 ? 1 : 2); + break; + case 1: { + actor->SetUnknown0x0c(und); + MxS32 src = boundary->m_src; + boundary->m_src = boundary->m_dest; + boundary->m_dest = src; + break; + } + default: + actor->SetUnknown0x0c(und); + break; + } + + if (world->PlaceActor( + actor, + boundary->m_name, + boundary->m_src, + boundary->m_srcScale, + boundary->m_dest, + boundary->m_destScale + ) == SUCCESS) { + MxS32 vehicleId = g_characters[m_lastExtraCharacterId].m_vehicleId; + if (vehicleId >= 0) { + g_vehicles[vehicleId].m_unk0x04 = + rand() % 100 < g_characters[m_lastExtraCharacterId].m_unk0x15; + } + + if (FUN_10063b90( + world, + actor, + CharacterManager()->FUN_10085180(m_extras[i].m_roi), + m_lastExtraCharacterId + )) { + m_extras[i].m_unk0x14 = TRUE; + g_vehicles[vehicleId].m_unk0x05 = TRUE; + } + else { + m_extras[i].m_unk0x14 = FALSE; + } + + float speed; + if (m_extras[i].m_unk0x14) { + speed = ((float) (rand() * 1.5) / 32767.0f) + 0.9; + } + else { + speed = ((float) (rand() * 1.4) / 32767.0f) + 0.6; + } + + actor->SetWorldSpeed(speed); + + m_extras[i].m_characterId = m_lastExtraCharacterId; + g_characters[m_lastExtraCharacterId].m_unk0x04 = TRUE; + m_extras[i].m_unk0x08 = Timer()->GetTime(); + m_extras[i].m_unk0x10 = -1; + m_extras[i].m_unk0x0d = FALSE; + m_unk0x414++; + return; + } + else { + CharacterManager()->FUN_10083db0(m_extras[i].m_roi); + m_extras[i].m_roi = NULL; + continue; + } + } + } + + m_lastExtraCharacterId++; + + if (m_lastExtraCharacterId >= sizeOfArray(g_characters)) { + m_lastExtraCharacterId = 0; + } + + if (m_lastExtraCharacterId == characterIdStart) { + return; + } + + goto tryNextCharacter; + } + } + } + } + } + } + } +} + +// STUB: LEGO1 0x10063270 +void LegoAnimationManager::FUN_10063270(LegoROIList*, LegoAnimPresenter*) +{ + // TODO +} + +// FUNCTION: LEGO1 0x10063780 +void LegoAnimationManager::FUN_10063780(LegoROIList* p_list) +{ + if (p_list != NULL && m_unk0x424 != NULL) { + LegoROIListCursor cursor(p_list); + LegoROI* roi; + + while (cursor.Next(roi)) { + const char* name = roi->GetName(); + + if (CharacterManager()->Exists(name)) { + m_unk0x424->Append(roi); + cursor.Detach(); + } + } + } +} + +// FUNCTION: LEGO1 0x10063aa0 +void LegoAnimationManager::FUN_10063aa0() +{ + LegoROIListCursor cursor(m_unk0x424); + LegoROI* roi; + + while (cursor.Next(roi)) { + CharacterManager()->FUN_10083db0(roi); + } +} + +// STUB: LEGO1 0x10063b90 +// FUNCTION: BETA10 0x10044d46 +MxBool LegoAnimationManager::FUN_10063b90( + LegoWorld* p_world, + LegoExtraActor* p_actor, + MxU8 p_unk0x14, + MxU32 p_characterId +) +{ + // TODO + return TRUE; +} + +// STUB: LEGO1 0x10063d10 +// FUNCTION: BETA10 0x10045034 +void LegoAnimationManager::FUN_10063d10() +{ + // TODO +} + +// STUB: LEGO1 0x10063fb0 +// FUNCTION: BETA10 0x100452a7 +MxBool LegoAnimationManager::FUN_10063fb0(LegoLocation::Boundary* p_boundary, LegoWorld* p_world) +{ + // TODO + return TRUE; +} + +// STUB: LEGO1 0x10064120 +// FUNCTION: BETA10 0x100454f5 +MxBool LegoAnimationManager::FUN_10064120(LegoLocation::Boundary* p_boundary, MxBool, MxBool) +{ + // TODO + return TRUE; +} + +// STUB: LEGO1 0x10064670 +void LegoAnimationManager::FUN_10064670(Vector3*) +{ + // TODO +} + +// STUB: LEGO1 0x10064740 +void LegoAnimationManager::FUN_10064740(Vector3*) +{ + // TODO +} + +// STUB: LEGO1 0x100648f0 +// FUNCTION: BETA10 0x10045daf +void LegoAnimationManager::FUN_100648f0(LegoTranInfo*, MxLong) +{ + // TODO +} + +// STUB: LEGO1 0x10064b50 +// FUNCTION: BETA10 0x10045f14 +void LegoAnimationManager::FUN_10064b50(MxLong p_time) +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp new file mode 100644 index 00000000..0a3e882b --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legoanimmmpresenter.cpp @@ -0,0 +1,485 @@ +#include "legoanimmmpresenter.h" + +#include "3dmanager/lego3dmanager.h" +#include "decomp.h" +#include "define.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legoanimpresenter.h" +#include "legoendanimnotificationparam.h" +#include "legotraninfo.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxautolock.h" +#include "mxdsmultiaction.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxobjectfactory.h" +#include "mxtimer.h" +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(LegoAnimMMPresenter, 0x74) + +// FUNCTION: LEGO1 0x1004a8d0 +LegoAnimMMPresenter::LegoAnimMMPresenter() +{ + m_presenter = NULL; + m_animmanId = 0; + m_unk0x59 = 0; + m_tranInfo = NULL; + m_unk0x54 = 0; + m_unk0x64 = NULL; + m_unk0x68 = NULL; + m_roiMap = NULL; + m_roiMapSize = 0; + m_unk0x58 = e_unk0; +} + +// FUNCTION: LEGO1 0x1004aa60 +LegoAnimMMPresenter::~LegoAnimMMPresenter() +{ + if (VideoManager() != NULL) { + VideoManager()->UnregisterPresenter(*this); + } + + delete m_unk0x68; + + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x1004aaf0 +MxResult LegoAnimMMPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + + MxResult result = FAILURE; + MxDSActionList* actions = ((MxDSMultiAction*) p_action)->GetActionList(); + MxObjectFactory* factory = ObjectFactory(); + MxDSActionListCursor cursor(actions); + MxDSAction* action; + + if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) { + cursor.Head(); + + while (cursor.Current(action)) { + MxBool success = FALSE; + const char* presenterName; + MxPresenter* presenter = NULL; + + cursor.Next(); + + if (m_action->GetFlags() & MxDSAction::c_looping) { + action->SetFlags(action->GetFlags() | MxDSAction::c_looping); + } + else if (m_action->GetFlags() & MxDSAction::c_bit3) { + action->SetFlags(action->GetFlags() | MxDSAction::c_bit3); + } + + presenterName = PresenterNameDispatch(*action); + presenter = (MxPresenter*) factory->Create(presenterName); + + if (presenter && presenter->AddToManager() == SUCCESS) { + presenter->SetCompositePresenter(this); + if (presenter->StartAction(p_controller, action) == SUCCESS) { + presenter->SetTickleState(MxPresenter::e_idle); + + if (presenter->IsA("LegoAnimPresenter") || presenter->IsA("LegoLoopingAnimPresenter")) { + m_presenter = (LegoAnimPresenter*) presenter; + } + success = TRUE; + } + } + + if (success) { + action->SetOrigin(this); + m_list.push_back(presenter); + } + else if (presenter) { + delete presenter; + } + } + + m_unk0x64 = CurrentWorld(); + if (m_unk0x64) { + m_unk0x64->Add(this); + } + VideoManager()->RegisterPresenter(*this); + + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x1004aec0 +// FUNCTION: BETA10 0x1004c01a +void LegoAnimMMPresenter::EndAction() +{ + if (m_tranInfo != NULL && m_tranInfo->m_unk0x15 && m_tranInfo->m_unk0x1c != NULL && + m_tranInfo->m_unk0x1c[1] != NULL) { + m_tranInfo->m_unk0x1c[1]->Enable(FALSE); + m_tranInfo->m_unk0x1c[1]->Enable(TRUE); + } + + m_tranInfo = NULL; + + LegoEndAnimNotificationParam param(c_notificationEndAnim, NULL, m_animmanId); + if (m_animmanId != 0) { + NotificationManager()->Send(AnimationManager(), param); + } + + if (m_action != NULL) { + MxCompositePresenter::EndAction(); + + if (m_unk0x64 != NULL) { + m_unk0x64->Remove(this); + } + } +} + +// FUNCTION: LEGO1 0x1004b140 +// FUNCTION: BETA10 0x1004c197 +void LegoAnimMMPresenter::ReadyTickle() +{ + ParseExtra(); + + if (m_tranInfo != NULL && m_tranInfo->m_unk0x15 && m_tranInfo->m_unk0x1c != NULL && + m_tranInfo->m_unk0x1c[0] != NULL) { + m_tranInfo->m_unk0x1c[0]->Enable(FALSE); + m_tranInfo->m_unk0x1c[0]->Enable(TRUE); + } + + if (m_tranInfo != NULL && m_tranInfo->m_unk0x0c != NULL) { + m_presenter->VTable0xa0(*m_tranInfo->m_unk0x0c); + } + + if (m_presenter != NULL) { + m_presenter->SetTickleState(e_ready); + } + + ProgressTickleState(e_starting); +} + +// FUNCTION: LEGO1 0x1004b1c0 +// FUNCTION: BETA10 0x1004c2cc +void LegoAnimMMPresenter::StartingTickle() +{ + if (m_presenter == NULL || m_presenter->GetCurrentTickleState() == e_idle) { + if (m_tranInfo != NULL && m_tranInfo->m_unk0x08 != NULL) { + m_presenter->FUN_1006b140(m_tranInfo->m_unk0x08); + } + + m_unk0x50 = Timer()->GetTime(); + ProgressTickleState(e_streaming); + } +} + +// FUNCTION: LEGO1 0x1004b220 +// FUNCTION: BETA10 0x1004c372 +void LegoAnimMMPresenter::StreamingTickle() +{ + if (FUN_1004b450()) { + ProgressTickleState(e_repeating); + } +} + +// FUNCTION: LEGO1 0x1004b250 +// FUNCTION: BETA10 0x1004c3a4 +void LegoAnimMMPresenter::RepeatingTickle() +{ + if (m_presenter == NULL) { + ProgressTickleState(e_freezing); + } + else if (m_list.size() <= 1) { + if (m_list.front() == m_presenter) { + m_presenter->SetTickleState(e_done); + ProgressTickleState(e_freezing); + } + else { + ProgressTickleState(e_freezing); + } + } +} + +// FUNCTION: LEGO1 0x1004b2c0 +// FUNCTION: BETA10 0x1004c469 +void LegoAnimMMPresenter::DoneTickle() +{ + // Empty +} + +// FUNCTION: LEGO1 0x1004b2d0 +// FUNCTION: BETA10 0x1004c47f +MxLong LegoAnimMMPresenter::Notify(MxParam& p_param) +{ + AUTOLOCK(m_criticalSection); + + if (((MxNotificationParam&) p_param).GetType() == c_notificationEndAction && + ((MxNotificationParam&) p_param).GetSender() == m_presenter) { + m_presenter = NULL; + } + + return MxCompositePresenter::Notify(p_param); +} + +// FUNCTION: LEGO1 0x1004b360 +void LegoAnimMMPresenter::VTable0x60(MxPresenter* p_presenter) +{ + if (m_presenter == p_presenter && ((MxU8) p_presenter->GetCurrentTickleState() == MxPresenter::e_streaming || + (MxU8) p_presenter->GetCurrentTickleState() == MxPresenter::e_done)) { + p_presenter->SetTickleState(MxPresenter::e_idle); + } +} + +// FUNCTION: LEGO1 0x1004b390 +// FUNCTION: BETA10 0x1004c5be +void LegoAnimMMPresenter::ParseExtra() +{ + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[1024]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char output[1024]; + if (KeyValueStringParse(output, g_strANIMMAN_ID, extraCopy)) { + char* token = strtok(output, g_parseExtraTokens); + m_animmanId = atoi(token); + m_tranInfo = AnimationManager()->GetTranInfo(m_animmanId); + + if (m_tranInfo != NULL) { + m_unk0x59 = m_tranInfo->m_unk0x10; + m_tranInfo->m_presenter = this; + } + } + } +} + +// FUNCTION: LEGO1 0x1004b450 +// FUNCTION: BETA10 0x1004c71d +MxBool LegoAnimMMPresenter::FUN_1004b450() +{ + MxBool result = FALSE; + MxLong time = Timer()->GetTime() - m_unk0x50; + + switch (m_unk0x58) { + case e_unk0: + if (!FUN_1004b530(time)) { + break; + } + m_unk0x58 = e_unk1; + case e_unk1: + if (!FUN_1004b570(time)) { + break; + } + m_unk0x58 = e_unk2; + case e_unk2: + if (!FUN_1004b580(time)) { + break; + } + m_unk0x58 = e_unk3; + case e_unk3: + if (!FUN_1004b5b0(time)) { + break; + } + m_unk0x58 = e_unk4; + case e_unk4: + if (!FUN_1004b600(time)) { + break; + } + m_unk0x58 = e_unk5; + case e_unk5: + if (!FUN_1004b610(time)) { + break; + } + m_unk0x58 = e_unk6; + case e_unk6: + if (!FUN_1004b6b0(time)) { + break; + } + m_unk0x58 = e_unk7; + case e_unk7: + FUN_1004b6d0(time); + result = TRUE; + } + + return result; +} + +// FUNCTION: LEGO1 0x1004b530 +// FUNCTION: BETA10 0x1004c8c4 +MxBool LegoAnimMMPresenter::FUN_1004b530(MxLong p_time) +{ + if (m_presenter != NULL) { + m_presenter->FUN_1006afc0(m_unk0x68, 0); + m_roiMap = m_presenter->GetROIMap(m_roiMapSize); + m_roiMapSize++; + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1004b570 +// FUNCTION: BETA10 0x1004c9cc +MxBool LegoAnimMMPresenter::FUN_1004b570(MxLong p_time) +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x1004b580 +// FUNCTION: BETA10 0x1004ca3f +MxBool LegoAnimMMPresenter::FUN_1004b580(MxLong p_time) +{ + switch (m_unk0x59) { + case 0: + if (m_tranInfo != NULL && m_tranInfo->m_unk0x15 != FALSE && m_tranInfo->m_unk0x20 != NULL && + m_tranInfo->m_unk0x20[0] > p_time) { + return FALSE; + } + break; + case 1: + case 2: + case 3: + case 4: + case 5: + break; + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1004b5b0 +// FUNCTION: BETA10 0x1004cb09 +MxBool LegoAnimMMPresenter::FUN_1004b5b0(MxLong p_time) +{ + switch (m_unk0x59) { + case 0: + if (m_roiMap != NULL && m_unk0x68 != NULL) { + for (MxU32 i = 0; i < m_roiMapSize; i++) { + LegoROI* roi = m_roiMap[i]; + + if (roi != NULL) { + roi->WrappedSetLocalTransform(m_unk0x68[i]); + } + } + } + break; + case 1: + case 2: + case 3: + case 4: + case 5: + break; + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1004b600 +// FUNCTION: BETA10 0x1004cbfb +MxBool LegoAnimMMPresenter::FUN_1004b600(MxLong p_time) +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x1004b610 +// FUNCTION: BETA10 0x1004cc6e +MxBool LegoAnimMMPresenter::FUN_1004b610(MxLong p_time) +{ + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + if ((*it)->IsA("LegoAnimPresenter") || (*it)->IsA("LegoLoopingAnimPresenter")) { + (*it)->SetTickleState(e_streaming); + } + else { + (*it)->SetTickleState(e_ready); + } + } + + m_action->SetUnknown90(Timer()->GetTime()); + + if (m_compositePresenter != NULL) { + m_compositePresenter->VTable0x60(this); + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1004b6b0 +// FUNCTION: BETA10 0x1004cdc5 +MxBool LegoAnimMMPresenter::FUN_1004b6b0(MxLong p_time) +{ + if (m_presenter != NULL && m_presenter->GetCurrentTickleState() != e_idle) { + return FALSE; + } + + m_unk0x54 = p_time; + return TRUE; +} + +// FUNCTION: LEGO1 0x1004b6d0 +// FUNCTION: BETA10 0x1004ce18 +MxBool LegoAnimMMPresenter::FUN_1004b6d0(MxLong p_time) +{ + LegoROI* viewROI = VideoManager()->GetViewROI(); + IslePathActor* actor = CurrentActor(); + + if (m_tranInfo != NULL && m_tranInfo->m_unk0x14 && m_tranInfo->m_unk0x12 != -1 && actor != NULL) { + if (m_unk0x64 != NULL) { + undefined4 und = 1; + + if (m_presenter != NULL) { + m_unk0x64->RemovePathActor(actor); + + if (m_tranInfo->m_unk0x29) { + Mx3DPointFloat position, direction; + + position = viewROI->GetWorldPosition(); + direction = viewROI->GetWorldDirection(); + position[1] -= 1.25; + + und = m_unk0x64->FUN_1001fb70(actor, m_presenter, position, direction); + } + else { + und = 0; + } + } + + if (und != 0) { + viewROI->WrappedSetLocalTransform(m_tranInfo->m_unk0x2c); + VideoManager()->Get3DManager()->Moved(*viewROI); + m_unk0x64->AddPathActor(actor); + } + + if (m_tranInfo->m_unk0x29) { + actor->VTable0xa8(); + } + } + + actor->SetState(0); + } + + return TRUE; +} + +// STUB: LEGO1 0x1004b840 +void LegoAnimMMPresenter::FUN_1004b840() +{ + // TODO +} + +// FUNCTION: LEGO1 0x1004b8b0 +// FUNCTION: BETA10 0x1004d104 +MxBool LegoAnimMMPresenter::FUN_1004b8b0() +{ + return m_tranInfo != NULL ? m_tranInfo->m_unk0x28 : TRUE; +} + +// STUB: LEGO1 0x1004b8c0 +void LegoAnimMMPresenter::FUN_1004b8c0() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp b/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp new file mode 100644 index 00000000..c66dd269 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp @@ -0,0 +1,151 @@ +#include "legobackgroundcolor.h" + +#include "3dmanager/lego3dmanager.h" +#include "decomp.h" +#include "legoutils.h" +#include "legovideomanager.h" +#include "misc.h" + +#include + +DECOMP_SIZE_ASSERT(LegoBackgroundColor, 0x30) + +// GLOBAL: LEGO1 0x100f3fb0 +// STRING: LEGO1 0x100f3a18 +const char* g_delimiter = " \t"; + +// GLOBAL: LEGO1 0x100f3fb4 +// STRING: LEGO1 0x100f3bf0 +const char* g_set = "set"; + +// GLOBAL: LEGO1 0x100f3fb8 +// STRING: LEGO1 0x100f0cdc +const char* g_reset = "reset"; + +// FUNCTION: LEGO1 0x1003bfb0 +LegoBackgroundColor::LegoBackgroundColor(const char* p_key, const char* p_value) +{ + m_key = p_key; + m_key.ToUpperCase(); + SetValue(p_value); +} + +// FUNCTION: LEGO1 0x1003c070 +void LegoBackgroundColor::SetValue(const char* p_colorString) +{ + m_value = p_colorString; + m_value.ToLowerCase(); + + LegoVideoManager* videomanager = VideoManager(); + if (!videomanager || !p_colorString) { + return; + } + + float convertedR, convertedG, convertedB; + char* colorStringCopy = strcpy(new char[strlen(p_colorString) + 1], p_colorString); + char* colorStringSplit = strtok(colorStringCopy, g_delimiter); + + if (!strcmp(colorStringSplit, g_set)) { + colorStringSplit = strtok(0, g_delimiter); + if (colorStringSplit) { + m_h = (float) (atoi(colorStringSplit) * 0.01); + } + colorStringSplit = strtok(0, g_delimiter); + if (colorStringSplit) { + m_s = (float) (atoi(colorStringSplit) * 0.01); + } + colorStringSplit = strtok(0, g_delimiter); + if (colorStringSplit) { + m_v = (float) (atoi(colorStringSplit) * 0.01); + } + + ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB); + videomanager->SetSkyColor(convertedR, convertedG, convertedB); + } + else if (!strcmp(colorStringSplit, g_reset)) { + ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB); + videomanager->SetSkyColor(convertedR, convertedG, convertedB); + } + + delete[] colorStringCopy; +} + +// FUNCTION: LEGO1 0x1003c230 +void LegoBackgroundColor::ToggleDayNight(MxBool p_sun) +{ + char buffer[30]; + + if (p_sun) { + m_s += 0.1; + if (m_s > 0.9) { + m_s = 1.0; + } + } + else { + m_s -= 0.1; + if (m_s < 0.1) { + m_s = 0.1; + } + } + + sprintf(buffer, "set %d %d %d", (MxU32) (m_h * 100.0f), (MxU32) (m_s * 100.0f), (MxU32) (m_v * 100.0f)); + m_value = buffer; + + float convertedR, convertedG, convertedB; + ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB); + VideoManager()->SetSkyColor(convertedR, convertedG, convertedB); + SetLightColor(convertedR, convertedG, convertedB); +} + +// FUNCTION: LEGO1 0x1003c330 +void LegoBackgroundColor::ToggleSkyColor() +{ + char buffer[30]; + + m_h += 0.05; + if (m_h > 1.0) { + m_h -= 1.0; + } + + sprintf(buffer, "set %d %d %d", (MxU32) (m_h * 100.0f), (MxU32) (m_s * 100.0f), (MxU32) (m_v * 100.0f)); + m_value = buffer; + + float convertedR, convertedG, convertedB; + ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB); + VideoManager()->SetSkyColor(convertedR, convertedG, convertedB); + SetLightColor(convertedR, convertedG, convertedB); +} + +// FUNCTION: LEGO1 0x1003c400 +void LegoBackgroundColor::SetLightColor(float p_r, float p_g, float p_b) +{ + if (!VideoManager()->GetVideoParam().Flags().GetF2bit0()) { + // TODO: Computed constants based on what? + p_r *= 4.3478260869565215; + p_g *= 1.5873015873015872; + p_b *= 1.1764705882352942; + + if (p_r > 1.0) { + p_r = 1.0; + } + + if (p_g > 1.0) { + p_g = 1.0; + } + + if (p_b > 1.0) { + p_b = 1.0; + } + + VideoManager()->Get3DManager()->GetLego3DView()->SetLightColor(FALSE, p_r, p_g, p_b); + VideoManager()->Get3DManager()->GetLego3DView()->SetLightColor(TRUE, p_r, p_g, p_b); + } +} + +// FUNCTION: LEGO1 0x1003c4b0 +void LegoBackgroundColor::SetLightColor() +{ + float convertedR, convertedG, convertedB; + ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB); + SetLightColor(convertedR, convertedG, convertedB); +} diff --git a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp new file mode 100644 index 00000000..891a6471 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp @@ -0,0 +1,911 @@ +#include "legocharactermanager.h" + +#include "3dmanager/lego3dmanager.h" +#include "legoanimactor.h" +#include "legocharacters.h" +#include "legoextraactor.h" +#include "legogamestate.h" +#include "legovariables.h" +#include "legovideomanager.h" +#include "misc.h" +#include "misc/legocontainer.h" +#include "misc/legostorage.h" +#include "mxmisc.h" +#include "mxvariabletable.h" +#include "realtime/realtime.h" +#include "roi/legolod.h" +#include "viewmanager/viewmanager.h" + +#include + +DECOMP_SIZE_ASSERT(LegoCharacter, 0x08) +DECOMP_SIZE_ASSERT(LegoCharacterManager, 0x08) + +// GLOBAL: LEGO1 0x100fc4e4 +char* LegoCharacterManager::g_customizeAnimFile = NULL; + +// GLOBAL: LEGO1 0x100fc4d8 +MxU32 g_unk0x100fc4d8 = 50; + +// GLOBAL: LEGO1 0x100fc4dc +MxU32 g_unk0x100fc4dc = 66; + +// GLOBAL: LEGO1 0x100fc4e8 +MxU32 g_unk0x100fc4e8 = 0; + +// GLOBAL: LEGO1 0x100fc4ec +MxU32 g_unk0x100fc4ec = 2; + +// GLOBAL: LEGO1 0x100fc4f0 +MxU32 g_unk0x100fc4f0 = 0; + +// GLOBAL: LEGO1 0x10104f20 +LegoCharacterInfo g_characterInfo[66]; + +// FUNCTION: LEGO1 0x10082a20 +LegoCharacterManager::LegoCharacterManager() +{ + m_characters = new LegoCharacterMap(); + Init(); + + m_customizeAnimFile = new CustomizeAnimFileVariable("CUSTOMIZE_ANIM_FILE"); + VariableTable()->SetVariable(m_customizeAnimFile); +} + +// FUNCTION: LEGO1 0x10083180 +// FUNCTION: BETA10 0x10073dad +LegoCharacterManager::~LegoCharacterManager() +{ + LegoCharacter* character = NULL; + LegoCharacterMap::iterator it; + + for (it = m_characters->begin(); it != m_characters->end(); it++) { + character = (*it).second; + + RemoveROI(character->m_roi); + + delete[] (*it).first; + delete (*it).second; + } + + delete m_characters; + delete[] g_customizeAnimFile; +} + +// FUNCTION: LEGO1 0x10083270 +void LegoCharacterManager::Init() +{ + for (MxS32 i = 0; i < sizeOfArray(g_characterInfo); i++) { + g_characterInfo[i] = g_characterInfoInit[i]; + } +} + +// FUNCTION: LEGO1 0x100832a0 +void LegoCharacterManager::FUN_100832a0() +{ + for (MxS32 i = 0; i < sizeOfArray(g_characterInfo); i++) { + LegoCharacterInfo* info = GetInfo(g_characterInfo[i].m_name); + + if (info != NULL) { + LegoExtraActor* actor = info->m_actor; + + if (actor != NULL && actor->IsA("LegoExtraActor")) { + LegoROI* roi = g_characterInfo[i].m_roi; + MxU32 refCount = GetRefCount(roi); + + while (refCount != 0) { + FUN_10083db0(roi); + refCount = GetRefCount(roi); + } + } + } + } +} + +// FUNCTION: LEGO1 0x10083310 +MxResult LegoCharacterManager::Write(LegoStorage* p_storage) +{ + MxResult result = FAILURE; + + for (MxS32 i = 0; i < sizeOfArray(g_characterInfo); i++) { + LegoCharacterInfo* info = &g_characterInfo[i]; + + if (p_storage->Write(&info->m_unk0x0c, sizeof(info->m_unk0x0c)) != SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_unk0x10, sizeof(info->m_unk0x10)) != SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_unk0x14, sizeof(info->m_unk0x14)) != SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_parts[c_infohatPart].m_unk0x08, sizeof(info->m_parts[c_infohatPart].m_unk0x08)) != + SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_parts[c_infohatPart].m_unk0x14, sizeof(info->m_parts[c_infohatPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + if (p_storage->Write( + &info->m_parts[c_infogronPart].m_unk0x14, + sizeof(info->m_parts[c_infogronPart].m_unk0x14) + ) != SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_parts[c_armlftPart].m_unk0x14, sizeof(info->m_parts[c_armlftPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_parts[c_armrtPart].m_unk0x14, sizeof(info->m_parts[c_armrtPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_parts[c_leglftPart].m_unk0x14, sizeof(info->m_parts[c_leglftPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + if (p_storage->Write(&info->m_parts[c_legrtPart].m_unk0x14, sizeof(info->m_parts[c_legrtPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + } + + result = SUCCESS; + +done: + return result; +} + +// FUNCTION: LEGO1 0x100833f0 +MxResult LegoCharacterManager::Read(LegoStorage* p_storage) +{ + MxResult result = FAILURE; + + for (MxS32 i = 0; i < sizeOfArray(g_characterInfo); i++) { + LegoCharacterInfo* info = &g_characterInfo[i]; + + if (p_storage->Read(&info->m_unk0x0c, sizeof(info->m_unk0x0c)) != SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_unk0x10, sizeof(info->m_unk0x10)) != SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_unk0x14, sizeof(info->m_unk0x14)) != SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_parts[c_infohatPart].m_unk0x08, sizeof(info->m_parts[c_infohatPart].m_unk0x08)) != + SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_parts[c_infohatPart].m_unk0x14, sizeof(info->m_parts[c_infohatPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + if (p_storage->Read( + &info->m_parts[c_infogronPart].m_unk0x14, + sizeof(info->m_parts[c_infogronPart].m_unk0x14) + ) != SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_parts[c_armlftPart].m_unk0x14, sizeof(info->m_parts[c_armlftPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_parts[c_armrtPart].m_unk0x14, sizeof(info->m_parts[c_armrtPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_parts[c_leglftPart].m_unk0x14, sizeof(info->m_parts[c_leglftPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + if (p_storage->Read(&info->m_parts[c_legrtPart].m_unk0x14, sizeof(info->m_parts[c_legrtPart].m_unk0x14)) != + SUCCESS) { + goto done; + } + } + + result = SUCCESS; + +done: + return result; +} + +// FUNCTION: LEGO1 0x10083500 +LegoROI* LegoCharacterManager::GetROI(const char* p_key, MxBool p_createEntity) +{ + LegoCharacter* character = NULL; + LegoCharacterMap::iterator it = m_characters->find(const_cast(p_key)); + + if (it != m_characters->end()) { + character = (*it).second; + character->AddRef(); + } + + if (character == NULL) { + LegoROI* roi = CreateROI(p_key); + + if (roi == NULL) { + goto done; + } + + roi->SetVisibility(FALSE); + + if (roi != NULL) { + character = new LegoCharacter(roi); + char* key = new char[strlen(p_key) + 1]; + + if (key != NULL) { + strcpy(key, p_key); + (*m_characters)[key] = character; + VideoManager()->Get3DManager()->Add(*roi); + } + } + } + else { + VideoManager()->Get3DManager()->Remove(*character->m_roi); + VideoManager()->Get3DManager()->Add(*character->m_roi); + } + +done: + if (character != NULL) { + if (p_createEntity && character->m_roi->GetEntity() == NULL) { + LegoExtraActor* actor = new LegoExtraActor(); + + actor->SetROI(character->m_roi, FALSE, FALSE); + actor->SetType(LegoEntity::e_character); + actor->SetFlag(LegoActor::c_bit2); + GetInfo(p_key)->m_actor = actor; + } + + return character->m_roi; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10083b20 +// FUNCTION: BETA10 0x10074608 +MxBool LegoCharacterManager::FUN_10083b20(const char* p_key) +{ + LegoCharacter* character = NULL; + LegoCharacterMap::iterator it = m_characters->find(const_cast(p_key)); + + if (it != m_characters->end()) { + return TRUE; + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10083bc0 +MxU32 LegoCharacterManager::GetRefCount(LegoROI* p_roi) +{ + LegoCharacterMap::iterator it; + + for (it = m_characters->begin(); it != m_characters->end(); it++) { + LegoCharacter* character = (*it).second; + LegoROI* roi = character->m_roi; + + if (roi == p_roi) { + return character->m_refCount; + } + } + + return 0; +} + +// FUNCTION: LEGO1 0x10083c30 +// FUNCTION: BETA10 0x10074701 +void LegoCharacterManager::FUN_10083c30(const char* p_name) +{ + LegoCharacter* character = NULL; + LegoCharacterMap::iterator it = m_characters->find(const_cast(p_name)); + + if (it != m_characters->end()) { + character = (*it).second; + + if (character->RemoveRef() == 0) { + LegoCharacterInfo* info = GetInfo(p_name); + LegoEntity* entity = character->m_roi->GetEntity(); + + if (entity != NULL) { + entity->SetROI(NULL, FALSE, FALSE); + } + + RemoveROI(character->m_roi); + + delete[] (*it).first; + delete (*it).second; + + m_characters->erase(it); + + if (info != NULL) { + if (info->m_actor != NULL) { + info->m_actor->ClearFlag(LegoEntity::c_bit2); + delete info->m_actor; + } + else if (entity != NULL && entity->GetFlagsIsSet(LegoEntity::c_bit2)) { + entity->ClearFlag(LegoEntity::c_bit2); + delete entity; + } + + info->m_roi = NULL; + info->m_actor = NULL; + } + } + } +} + +// FUNCTION: LEGO1 0x10083db0 +void LegoCharacterManager::FUN_10083db0(LegoROI* p_roi) +{ + LegoCharacter* character = NULL; + LegoCharacterMap::iterator it; + + for (it = m_characters->begin(); it != m_characters->end(); it++) { + character = (*it).second; + + if (character->m_roi == p_roi) { + if (character->RemoveRef() == 0) { + LegoCharacterInfo* info = GetInfo(character->m_roi->GetName()); + LegoEntity* entity = character->m_roi->GetEntity(); + + if (entity != NULL) { + entity->SetROI(NULL, FALSE, FALSE); + } + + RemoveROI(character->m_roi); + + delete[] (*it).first; + delete (*it).second; + + m_characters->erase(it); + + if (info != NULL) { + if (info->m_actor != NULL) { + info->m_actor->ClearFlag(LegoEntity::c_bit2); + delete info->m_actor; + } + else if (entity != NULL && entity->GetFlagsIsSet(LegoEntity::c_bit2)) { + entity->ClearFlag(LegoEntity::c_bit2); + delete entity; + } + + info->m_roi = NULL; + info->m_actor = NULL; + } + } + + return; + } + } +} + +// FUNCTION: LEGO1 0x10083f10 +void LegoCharacterManager::FUN_10083f10(LegoROI* p_roi) +{ + LegoCharacter* character = NULL; + LegoCharacterMap::iterator it; + + for (it = m_characters->begin(); it != m_characters->end(); it++) { + character = (*it).second; + + if (character->m_roi == p_roi) { + if (character->RemoveRef() == 0) { + LegoEntity* entity = character->m_roi->GetEntity(); + + if (entity != NULL) { + entity->SetROI(NULL, FALSE, FALSE); + } + + RemoveROI(character->m_roi); + + delete[] (*it).first; + delete (*it).second; + + m_characters->erase(it); + + if (entity != NULL && entity->GetFlagsIsSet(LegoEntity::c_bit2)) { + entity->ClearFlag(LegoEntity::c_bit2); + delete entity; + } + } + + return; + } + } +} + +// FUNCTION: LEGO1 0x10084010 +void LegoCharacterManager::RemoveROI(LegoROI* p_roi) +{ + VideoManager()->Get3DManager()->Remove(*p_roi); +} + +// FUNCTION: LEGO1 0x10084030 +LegoROI* LegoCharacterManager::CreateROI(const char* p_key) +{ + MxBool success = FALSE; + LegoROI* roi = NULL; + BoundingSphere boundingSphere; + BoundingBox boundingBox; + MxMatrix mat; + CompoundObject* comp; + MxS32 i; + + Tgl::Renderer* renderer = VideoManager()->GetRenderer(); + ViewLODListManager* lodManager = GetViewLODListManager(); + LegoTextureContainer* textureContainer = TextureContainer(); + LegoCharacterInfo* info = GetInfo(p_key); + + if (info == NULL) { + goto done; + } + + if (!strcmpi(p_key, "pep")) { + LegoCharacterInfo* pepper = GetInfo("pepper"); + + info->m_unk0x0c = pepper->m_unk0x0c; + info->m_unk0x10 = pepper->m_unk0x10; + info->m_unk0x14 = pepper->m_unk0x14; + + for (i = 0; i < sizeOfArray(info->m_parts); i++) { + info->m_parts[i] = pepper->m_parts[i]; + } + } + + roi = new LegoROI(renderer); + roi->SetName(p_key); + + boundingSphere.Center()[0] = g_characterLODs[c_topLOD].m_boundingSphere[0]; + boundingSphere.Center()[1] = g_characterLODs[c_topLOD].m_boundingSphere[1]; + boundingSphere.Center()[2] = g_characterLODs[c_topLOD].m_boundingSphere[2]; + boundingSphere.Radius() = g_characterLODs[c_topLOD].m_boundingSphere[3]; + roi->SetBoundingSphere(boundingSphere); + + boundingBox.Min()[0] = g_characterLODs[c_topLOD].m_boundingBox[0]; + boundingBox.Min()[1] = g_characterLODs[c_topLOD].m_boundingBox[1]; + boundingBox.Min()[2] = g_characterLODs[c_topLOD].m_boundingBox[2]; + boundingBox.Max()[0] = g_characterLODs[c_topLOD].m_boundingBox[3]; + boundingBox.Max()[1] = g_characterLODs[c_topLOD].m_boundingBox[4]; + boundingBox.Max()[2] = g_characterLODs[c_topLOD].m_boundingBox[5]; + roi->SetUnknown0x80(boundingBox); + + comp = new CompoundObject(); + roi->SetComp(comp); + + for (i = 0; i < sizeOfArray(g_characterLODs) - 1; i++) { + char lodName[256]; + LegoCharacterInfo::Part& part = info->m_parts[i]; + + const char* parentName; + if (i == 0 || i == 1) { + parentName = part.m_unk0x04[part.m_unk0x00[part.m_unk0x08]]; + } + else { + parentName = g_characterLODs[i + 1].m_parentName; + } + + ViewLODList* lodList = lodManager->Lookup(parentName); + MxS32 lodSize = lodList->Size(); + sprintf(lodName, "%s%d", p_key, i); + ViewLODList* dupLodList = lodManager->Create(lodName, lodSize); + + for (MxS32 j = 0; j < lodSize; j++) { + LegoLOD* lod = (LegoLOD*) (*lodList)[j]; + LegoLOD* clone = lod->Clone(renderer); + dupLodList->PushBack(clone); + } + + lodList->Release(); + lodList = dupLodList; + + LegoROI* childROI = new LegoROI(renderer, lodList); + lodList->Release(); + + childROI->SetName(g_characterLODs[i + 1].m_name); + childROI->SetParentROI(roi); + + BoundingSphere childBoundingSphere; + childBoundingSphere.Center()[0] = g_characterLODs[i + 1].m_boundingSphere[0]; + childBoundingSphere.Center()[1] = g_characterLODs[i + 1].m_boundingSphere[1]; + childBoundingSphere.Center()[2] = g_characterLODs[i + 1].m_boundingSphere[2]; + childBoundingSphere.Radius() = g_characterLODs[i + 1].m_boundingSphere[3]; + childROI->SetBoundingSphere(childBoundingSphere); + + BoundingBox childBoundingBox; + childBoundingBox.Min()[0] = g_characterLODs[i + 1].m_boundingBox[0]; + childBoundingBox.Min()[1] = g_characterLODs[i + 1].m_boundingBox[1]; + childBoundingBox.Min()[2] = g_characterLODs[i + 1].m_boundingBox[2]; + childBoundingBox.Max()[0] = g_characterLODs[i + 1].m_boundingBox[3]; + childBoundingBox.Max()[1] = g_characterLODs[i + 1].m_boundingBox[4]; + childBoundingBox.Max()[2] = g_characterLODs[i + 1].m_boundingBox[5]; + childROI->SetUnknown0x80(childBoundingBox); + + CalcLocalTransform( + Mx3DPointFloat(g_characterLODs[i + 1].m_position), + Mx3DPointFloat(g_characterLODs[i + 1].m_direction), + Mx3DPointFloat(g_characterLODs[i + 1].m_up), + mat + ); + childROI->WrappedSetLocalTransform(mat); + + if (g_characterLODs[i + 1].m_flags & LegoCharacterLOD::c_flag1 && + (i != 0 || part.m_unk0x00[part.m_unk0x08] != 0)) { + + LegoTextureInfo* textureInfo = textureContainer->Get(part.m_unk0x10[part.m_unk0x0c[part.m_unk0x14]]); + + if (textureInfo != NULL) { + childROI->FUN_100a9210(textureInfo); + childROI->FUN_100a9170(1.0F, 1.0F, 1.0F, 0.0F); + } + } + else if (g_characterLODs[i + 1].m_flags & LegoCharacterLOD::c_flag2 || (i == 0 && part.m_unk0x00[part.m_unk0x08] == 0)) { + LegoFloat red, green, blue, alpha; + childROI->FUN_100a9bf0(part.m_unk0x10[part.m_unk0x0c[part.m_unk0x14]], red, green, blue, alpha); + childROI->FUN_100a9170(red, green, blue, alpha); + } + + comp->push_back(childROI); + } + + CalcLocalTransform( + Mx3DPointFloat(g_characterLODs[c_topLOD].m_position), + Mx3DPointFloat(g_characterLODs[c_topLOD].m_direction), + Mx3DPointFloat(g_characterLODs[c_topLOD].m_up), + mat + ); + roi->WrappedSetLocalTransform(mat); + + info->m_roi = roi; + success = TRUE; + +done: + if (!success && roi != NULL) { + delete roi; + roi = NULL; + } + + return roi; +} + +// FUNCTION: LEGO1 0x100849a0 +// FUNCTION: BETA10 0x10075b51 +MxBool LegoCharacterManager::FUN_100849a0(LegoROI* p_roi, LegoTextureInfo* p_textureInfo) +{ + LegoResult result = SUCCESS; + LegoROI* head = FindChildROI(p_roi, g_characterLODs[c_headLOD].m_name); + + if (head != NULL) { + char lodName[256]; + + ViewLODList* lodList = GetViewLODListManager()->Lookup(g_characterLODs[c_headLOD].m_parentName); + MxS32 lodSize = lodList->Size(); + sprintf(lodName, "%s%s%d", p_roi->GetName(), "head", g_unk0x100fc4e8++); + ViewLODList* dupLodList = GetViewLODListManager()->Create(lodName, lodSize); + + Tgl::Renderer* renderer = VideoManager()->GetRenderer(); + + if (p_textureInfo == NULL) { + LegoCharacterInfo* info = GetInfo(p_roi->GetName()); + LegoCharacterInfo::Part& part = info->m_parts[c_headPart]; + p_textureInfo = TextureContainer()->Get(part.m_unk0x10[part.m_unk0x0c[part.m_unk0x14]]); + } + + for (MxS32 i = 0; i < lodSize; i++) { + LegoLOD* lod = (LegoLOD*) (*lodList)[i]; + LegoLOD* clone = lod->Clone(renderer); + + if (p_textureInfo != NULL) { + clone->FUN_100aad70(p_textureInfo); + } + + dupLodList->PushBack(clone); + } + + lodList->Release(); + lodList = dupLodList; + + if (head->GetUnknown0xe0() >= 0) { + VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->FUN_100a66a0(head); + } + + head->SetLODList(lodList); + lodList->Release(); + } + + return head != NULL; +} + +// FUNCTION: LEGO1 0x10084c00 +MxBool LegoCharacterManager::Exists(const char* p_key) +{ + for (MxU32 i = 0; i < sizeOfArray(g_characterInfo); i++) { + if (!strcmpi(g_characterInfo[i].m_name, p_key)) { + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10084c40 +LegoExtraActor* LegoCharacterManager::GetActor(const char* p_key) +{ + LegoCharacterInfo* info = GetInfo(p_key); + + if (info != NULL) { + return info->m_actor; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10084c60 +LegoCharacterInfo* LegoCharacterManager::GetInfo(const char* p_key) +{ + MxU32 i; + + for (i = 0; i < sizeOfArray(g_characterInfo); i++) { + if (!strcmpi(g_characterInfo[i].m_name, p_key)) { + break; + } + } + + if (i < sizeOfArray(g_characterInfo)) { + return &g_characterInfo[i]; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10084cb0 +LegoCharacterInfo* LegoCharacterManager::GetInfo(LegoROI* p_roi) +{ + MxU32 i; + + for (i = 0; i < sizeOfArray(g_characterInfo); i++) { + if (g_characterInfo[i].m_roi == p_roi) { + break; + } + } + + if (i < sizeOfArray(g_characterInfo)) { + return &g_characterInfo[i]; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10084cf0 +// FUNCTION: BETA10 0x10075fe2 +LegoROI* LegoCharacterManager::FindChildROI(LegoROI* p_roi, const char* p_name) +{ + const CompoundObject* comp = p_roi->GetComp(); + +#ifdef COMPAT_MODE + for (CompoundObject::const_iterator it = comp->begin(); !(it == comp->end()); it++) { +#else + for (CompoundObject::iterator it = comp->begin(); !(it == comp->end()); it++) { +#endif + LegoROI* roi = (LegoROI*) *it; + + if (!strcmpi(p_name, roi->GetName())) { + return roi; + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10084ec0 +MxBool LegoCharacterManager::SwitchHat(LegoROI* p_roi) +{ + LegoCharacterInfo* info = GetInfo(p_roi->GetName()); + + if (info == NULL) { + return FALSE; + } + + LegoCharacterInfo::Part& part = info->m_parts[c_infohatPart]; + + part.m_unk0x08++; + MxU8 unk0x00 = part.m_unk0x00[part.m_unk0x08]; + + if (unk0x00 == 0xff) { + part.m_unk0x08 = 0; + unk0x00 = part.m_unk0x00[part.m_unk0x08]; + } + + LegoROI* childROI = FindChildROI(p_roi, g_characterLODs[c_infohatLOD].m_name); + + if (childROI != NULL) { + char lodName[256]; + + ViewLODList* lodList = GetViewLODListManager()->Lookup(part.m_unk0x04[unk0x00]); + MxS32 lodSize = lodList->Size(); + sprintf(lodName, "%s%d", p_roi->GetName(), g_unk0x100fc4ec++); + ViewLODList* dupLodList = GetViewLODListManager()->Create(lodName, lodSize); + + Tgl::Renderer* renderer = VideoManager()->GetRenderer(); + LegoFloat red, green, blue, alpha; + LegoROI::FUN_100a9bf0(part.m_unk0x10[part.m_unk0x0c[part.m_unk0x14]], red, green, blue, alpha); + + for (MxS32 i = 0; i < lodSize; i++) { + LegoLOD* lod = (LegoLOD*) (*lodList)[i]; + LegoLOD* clone = lod->Clone(renderer); + clone->FUN_100aacb0(red, green, blue, alpha); + dupLodList->PushBack(clone); + } + + lodList->Release(); + lodList = dupLodList; + + if (childROI->GetUnknown0xe0() >= 0) { + VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->FUN_100a66a0(childROI); + } + + childROI->SetLODList(lodList); + lodList->Release(); + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x10085140 +MxU32 LegoCharacterManager::FUN_10085140(LegoROI* p_roi, MxBool p_und) +{ + LegoCharacterInfo* info = GetInfo(p_roi); + + if (p_und) { + return info->m_unk0x14 + g_unk0x100fc4dc; + } + + if (info != NULL) { + return info->m_unk0x0c + g_unk0x100fc4d8; + } + + return 0; +} + +// FUNCTION: LEGO1 0x10085180 +// FUNCTION: BETA10 0x100768c5 +MxU8 LegoCharacterManager::FUN_10085180(LegoROI* p_roi) +{ + LegoCharacterInfo* info = GetInfo(p_roi); + + if (info != NULL) { + return info->m_unk0x14; + } + + return 0; +} + +// FUNCTION: LEGO1 0x100851a0 +void LegoCharacterManager::SetCustomizeAnimFile(const char* p_value) +{ + if (g_customizeAnimFile != NULL) { + delete[] g_customizeAnimFile; + } + + if (p_value != NULL) { + g_customizeAnimFile = new char[strlen(p_value) + 1]; + + if (g_customizeAnimFile != NULL) { + strcpy(g_customizeAnimFile, p_value); + } + } + else { + g_customizeAnimFile = NULL; + } +} + +// FUNCTION: LEGO1 0x10085210 +LegoROI* LegoCharacterManager::FUN_10085210(const char* p_name, const char* p_lodName, MxBool p_createEntity) +{ + LegoROI* roi = NULL; + + MxMatrix mat; + Tgl::Renderer* renderer = VideoManager()->GetRenderer(); + ViewLODListManager* lodManager = GetViewLODListManager(); + LegoTextureContainer* textureContainer = TextureContainer(); + ViewLODList* lodList = lodManager->Lookup(p_lodName); + + if (lodList == NULL || lodList->Size() == 0) { + return NULL; + } + + roi = new LegoROI(renderer, lodList); + + const char* name; + char buf[20]; + + if (p_name != NULL) { + name = p_name; + } + else { + sprintf(buf, "autoROI_%d", g_unk0x100fc4f0++); + name = buf; + } + + roi->SetName(name); + lodList->Release(); + + if (roi != NULL && FUN_10085870(roi) != SUCCESS) { + delete roi; + roi = NULL; + } + + if (roi != NULL) { + roi->SetVisibility(FALSE); + + LegoCharacter* character = new LegoCharacter(roi); + char* key = new char[strlen(name) + 1]; + + if (key != NULL) { + strcpy(key, name); + (*m_characters)[key] = character; + VideoManager()->Get3DManager()->Add(*roi); + + if (p_createEntity && roi->GetEntity() == NULL) { + LegoEntity* entity = new LegoEntity(); + + entity->SetROI(roi, FALSE, FALSE); + entity->SetType(LegoEntity::e_unk4); + entity->SetFlag(LegoActor::c_bit2); + } + } + } + + return roi; +} + +// FUNCTION: LEGO1 0x10085870 +MxResult LegoCharacterManager::FUN_10085870(LegoROI* p_roi) +{ + MxResult result = FAILURE; + + BoundingSphere boundingSphere; + BoundingBox boundingBox; + + const Tgl::MeshBuilder* meshBuilder = ((ViewLOD*) p_roi->GetLOD(0))->GetMeshBuilder(); + + if (meshBuilder != NULL) { + float min[3], max[3]; + + FILLVEC3(min, 88888.0); + FILLVEC3(max, -88888.0); + meshBuilder->GetBoundingBox(min, max); + + float center[3]; + center[0] = (min[0] + max[0]) / 2.0f; + center[1] = (min[1] + max[1]) / 2.0f; + center[2] = (min[2] + max[2]) / 2.0f; + SET3(boundingSphere.Center(), center); + + float radius[3]; + VMV3(radius, max, min); + boundingSphere.Radius() = sqrt(NORMSQRD3(radius)) / 2.0; + + p_roi->SetBoundingSphere(boundingSphere); + + SET3(boundingBox.Min(), min); + SET3(boundingBox.Max(), max); + + p_roi->SetUnknown0x80(boundingBox); + + p_roi->VTable0x14(); + + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x10085a80 +LegoROI* LegoCharacterManager::FUN_10085a80(const char* p_name, const char* p_lodName, MxBool p_createEntity) +{ + return FUN_10085210(p_name, p_lodName, p_createEntity); +} diff --git a/LEGO1/lego/legoomni/src/common/legocharacters.cpp b/LEGO1/lego/legoomni/src/common/legocharacters.cpp new file mode 100644 index 00000000..d80b49c8 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legocharacters.cpp @@ -0,0 +1,1232 @@ +#include "legocharacters.h" + +DECOMP_SIZE_ASSERT(LegoCharacterInfo, 0x108) +DECOMP_SIZE_ASSERT(LegoCharacterInfo::Part, 0x18) +DECOMP_SIZE_ASSERT(LegoCharacterLOD, 0x58) + +// Unclear whether g_characterLODs[0] (top) is its own global, see: LegoCharacterManager::CreateROI + +// GLOBAL: LEGO1 0x100da3b0 +LegoCharacterLOD g_characterLODs[] = { + {"top", "top", 0, 0.000267, 0.780808, -0.01906, 0.951612, -0.461166, -0.002794, -0.299442, 0.4617, + 1.56441, 0.261321, 0, 0, 0, 0, 0, 1, 0, 1, 0}, + {"body", "body", LegoCharacterLOD::c_flag1, + 0.00158332, 0.401828, -0.00048697, + 0.408071, -0.287507, 0.150419, + -0.147452, 0.289219, 0.649774, + 0.14258, -0.00089, 0.436353, + 0.007277, 0, 0, + 1, 0, 1, + 0}, + {"infohat", "infohat", LegoCharacterLOD::c_flag2, + 0, -0.00938, -0.01955, + 0.35, -0.231822, -0.140237, + -0.320954, 0.234149, 0.076968, + 0.249083, 0.000191, 1.519793, + 0.001767, 0, 0, + 1, 0, 1, + 0}, + {"infogron", "infogron", LegoCharacterLOD::c_flag2, + 0, 0.11477, 0.00042, + 0.26, -0.285558, -0.134391, + -0.142231, 0.285507, 0.152986, + 0.143071, -0.00089, 0.436353, + 0.007277, 0, 0, + 1, 0, 1, + 0}, + {"head", "head", LegoCharacterLOD::c_flag1, + 0, -0.03006, 0, + 0.3, -0.189506, -0.209665, + -0.189824, 0.189532, 0.228822, + 0.194945, -0.00105, 1.293115, + 0.001781, 0, 0, + 1, 0, 1, + 0}, + {"arm-lft", "arm-lft", LegoCharacterLOD::c_flag2, + -0.06815, -0.0973747, 0.0154655, + 0.237, -0.137931, -0.282775, + -0.105316, 0.000989, 0.100221, + 0.140759, -0.225678, 0.963312, + 0.023286, -0.003031, -0.017187, + 0.999848, 0.173622, 0.984658, + 0.017453}, + {"arm-rt", "arm-rt", LegoCharacterLOD::c_flag2, + 0.0680946, -0.097152, 0.0152722, + 0.237, 0.00141, -0.289604, + -0.100831, 0.138786, 0.09291, + 0.145437, 0.223494, 0.963583, + 0.018302, 0, 0, + 1, -0.173648, 0.984808, + 0}, + {"claw-lft", "claw-lft", LegoCharacterLOD::c_flag2, + 0.000773381, -0.101422, -0.0237761, + 0.15, -0.089838, -0.246208, + -0.117735, 0.091275, 0.000263, + 0.07215, -0.341869, 0.700355, + 0.092779, 0.000001, 0.000003, + 1, 0.190812, 0.981627, + -0.000003}, + {"claw-rt", "claw-lft", LegoCharacterLOD::c_flag2, + 0.000773381, -0.101422, -0.0237761, + 0.15, -0.095016, -0.245349, + -0.117979, 0.086528, 0.00067, + 0.069743, 0.343317, 0.69924, + 0.096123, 0.00606, -0.034369, + 0.999391, -0.190704, 0.981027, + 0.034894}, + {"leg-lft", "leg", LegoCharacterLOD::c_flag2, + 0.00433584, -0.177404, -0.0313928, + 0.33, -0.129782, -0.440428, + -0.184207, 0.13817, 0.118415, + 0.122607, -0.156339, 0.436087, + 0.006822, 0, 0, + 1, 0, 1, + 0}, + {"leg-rt", "leg", LegoCharacterLOD::c_flag2, + 0.00433584, -0.177404, -0.0313928, + 0.33, -0.132864, -0.437138, + -0.183944, 0.134614, 0.12043, + 0.121888, 0.151154, 0.436296, + 0.007373, 0, 0, + 1, 0, 1, + 0} +}; + +// GLOBAL: LEGO1 0x100da778 +MxU8 g_unk0x100da778[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0xff}; + +// GLOBAL: LEGO1 0x100da790 +MxU8 g_unk0x100da790[] = {21, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0xff}; + +// GLOBAL: LEGO1 0x100da7a8 +MxU8 g_unk0x100da7a8[] = {22, 0xff}; + +// GLOBAL: LEGO1 0x100da7ac +MxU8 g_unk0x100da7ac[] = {20, 0xff}; + +// GLOBAL: LEGO1 0x100da7b0 +MxU8 g_unk0x100da7b0[] = {0, 1, 2, 3, 4, 5, 6, 7, 0xff}; + +// GLOBAL: LEGO1 0x100da7c0 +MxU8 g_unk0x100da7c0[] = {0, 1, 2, 3, 4, 5, 6, 7, 0xff}; + +// GLOBAL: LEGO1 0x100da7d0 +MxU8 g_unk0x100da7d0[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0xff}; + +// GLOBAL: LEGO1 0x100da7e0 +MxU8 g_unk0x100da7e0[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 27, 0xff}; + +// GLOBAL: LEGO1 0x100da800 +MxU8 g_unk0x100da800[] = {0, 1, 2, 3, 4, 5, 6, 7, 0xff}; + +// GLOBAL: LEGO1 0x100da810 +MxU8 g_unk0x100da810[] = {0, 1, 2, 3, 4, 5, 6, 7, 0xff}; + +// GLOBAL: LEGO1 0x100da820 +MxU8 g_unk0x100da820[] = {0, 1, 2, 3, 4, 5, 6, 7, 0xff}; + +// GLOBAL: LEGO1 0x100da830 +MxU8 g_unk0x100da830[] = {0, 1, 2, 3, 4, 5, 6, 7, 0xff}; + +// GLOBAL: LEGO1 0x100da840 +MxU8 g_unk0x100da840[] = {0, 1, 2, 3, 4, 5, 6, 7, 0xff}; + +// GLOBAL: LEGO1 0x100f7f78 +const char* g_unk0x100f7f78[] = {"baseball", "chef", "cap", "cophat", "helmet", "ponytail", "pageboy", "shrthair", + "bald", "flower", "cboyhat", "cuphat", "cathat", "backbcap", "pizhat", "caprc", + "capch", "capdb", "capjs", "capmd", "sheet", "phat", "icap", NULL}; + +// GLOBAL: LEGO1 0x100f7fd8 +const char* g_unk0x100f7fd8[] = + {"body", "bodyred", "bodyblck", "bodywhte", "bodyyllw", "bodyblue", "bodygren", "bodybrwn"}; + +// GLOBAL: LEGO1 0x100f7ff8 +const char* g_unk0x100f7ff8[] = {"peprchst.gif", "mamachst.gif", "papachst.gif", "nickchst.gif", "norachst.gif", + "infochst.gif", "shftchst.gif", "rac1chst.gif", "rac2chst.gif", "bth1chst.gif", + "bth2chst.gif", "mech.gif", "polkadot.gif", "bowtie.gif", "postchst.gif", + "vest.gif", "doctor.gif", "copchest.gif", "l.gif", "e.gif", + "g.gif", "o.gif", "fruit.gif", "flowers.gif", "construct.gif", + "paint.gif", "l6.gif", "unkchst.gif"}; + +// GLOBAL: LEGO1 0x100f8068 +const char* g_unk0x100f8068[] = { + "peprface.gif", + "mamaface.gif", + "papaface.gif", + "nickface.gif", + "noraface.gif", + "infoface.gif", + "shftface.gif", + "dogface.gif", + "womanshd.gif", + "smileshd.gif", + "woman.gif", + "smile.gif", + "mustache.gif", + "black.gif" +}; + +// GLOBAL: LEGO1 0x100f80a0 +const char* g_unk0x100f80a0[] = + {"lego white", "lego black", "lego yellow", "lego red", "lego blue", "lego brown", "lego lt grey", "lego green"}; + +// GLOBAL: LEGO1 0x100f80c0 +LegoCharacterInfo g_characterInfoInit[] = { + {"pepper", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 0}, + {g_unk0x100da790, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"mama", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 1}, + {g_unk0x100da778, g_unk0x100f7f78, 1, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 1}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"papa", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 2, g_unk0x100da7e0, g_unk0x100f7ff8, 2}, + {g_unk0x100da778, g_unk0x100f7f78, 1, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"nick", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 2, g_unk0x100da7e0, g_unk0x100f7ff8, 3}, + {g_unk0x100da778, g_unk0x100f7f78, 3, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"laura", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 2, g_unk0x100da7e0, g_unk0x100f7ff8, 4}, + {g_unk0x100da778, g_unk0x100f7f78, 3, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 4}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"infoman", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 5}, + {g_unk0x100da7a8, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 5}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"brickstr", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 6}, + {g_unk0x100da778, g_unk0x100f7f78, 13, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 6}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"studs", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 7}, + {g_unk0x100da778, g_unk0x100f7f78, 4, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 7}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"rhoda", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 5, g_unk0x100da7e0, g_unk0x100f7ff8, 8}, + {g_unk0x100da778, g_unk0x100f7f78, 4, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 8}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"valerie", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 9}, + {g_unk0x100da778, g_unk0x100f7f78, 5, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 8}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}}}, + {"snap", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 10}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 9}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}}}, + {"pt", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 5, g_unk0x100da7e0, g_unk0x100f7ff8, 11}, + {g_unk0x100da778, g_unk0x100f7f78, 6, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 8}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"mg", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 12}, + {g_unk0x100da778, g_unk0x100f7f78, 6, g_unk0x100da7c0, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 10}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"bu", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 13}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 5}}}, + {"ml", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 5, g_unk0x100da7e0, g_unk0x100f7ff8, 14}, + {g_unk0x100da778, g_unk0x100f7f78, 2, g_unk0x100da7c0, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 12}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"nu", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 5, g_unk0x100da7e0, g_unk0x100f7ff8, 11}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 7}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"na", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 15}, + {g_unk0x100da778, g_unk0x100f7f78, 10, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 8}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}}}, + {"cl", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 16}, + {g_unk0x100da778, g_unk0x100f7f78, 19, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 12}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"en", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 16}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"re", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 16}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"ro", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 2, g_unk0x100da7e0, g_unk0x100f7ff8, 17}, + {g_unk0x100da778, g_unk0x100f7f78, 3, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 9}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"d1", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 5, g_unk0x100da7e0, g_unk0x100f7ff8, 11}, + {g_unk0x100da778, g_unk0x100f7f78, 15, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"d2", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 5, g_unk0x100da7e0, g_unk0x100f7ff8, 11}, + {g_unk0x100da778, g_unk0x100f7f78, 16, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"d3", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 5, g_unk0x100da7e0, g_unk0x100f7ff8, 11}, + {g_unk0x100da778, g_unk0x100f7f78, 17, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"d4", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 5, g_unk0x100da7e0, g_unk0x100f7ff8, 11}, + {g_unk0x100da778, g_unk0x100f7f78, 18, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"l1", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 18}, + {g_unk0x100da778, g_unk0x100f7f78, 5, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"l2", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 19}, + {g_unk0x100da778, g_unk0x100f7f78, 6, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 12}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"l3", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 20}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"l4", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 21}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"l5", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 26}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 12}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"l6", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 26}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"b1", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 12}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"b2", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {g_unk0x100da778, g_unk0x100f7f78, 5, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 10}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"b3", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"b4", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 9}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"cm", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 4, g_unk0x100da7e0, g_unk0x100f7ff8, 22}, + {g_unk0x100da778, g_unk0x100f7f78, 9, g_unk0x100da7c0, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 8}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}}}, + {"gd", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 6}}}, + {"rd", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 7}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 9}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 7}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 7}}}, + {"pg", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {g_unk0x100da778, g_unk0x100f7f78, 5, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}}}, + {"bd", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 6}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 12}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"sy", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {g_unk0x100da778, g_unk0x100f7f78, 5, g_unk0x100da7c0, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 10}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"gn", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 6, g_unk0x100da7e0, g_unk0x100f7ff8, 13}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 9}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 5}}}, + {"df", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 5, g_unk0x100da7e0, g_unk0x100f7ff8, 23}, + {g_unk0x100da778, g_unk0x100f7f78, 6, g_unk0x100da7c0, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 8}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 6}}}, + {"bs", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 10}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 7}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}}}, + {"lt", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 10}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}}}, + {"st", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 9}, + {g_unk0x100da778, g_unk0x100f7f78, 5, g_unk0x100da7c0, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 10}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}}}, + {"bm", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 24}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 7}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"jk", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 24}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 9}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"ghost", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {g_unk0x100da7ac, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 13}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"ghost01", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {g_unk0x100da7ac, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 13}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"ghost02", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {g_unk0x100da7ac, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 13}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"ghost03", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {g_unk0x100da7ac, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 13}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"ghost04", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {g_unk0x100da7ac, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 13}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"ghost05", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {g_unk0x100da7ac, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 13}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 0}}}, + {"hg", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {g_unk0x100da778, g_unk0x100f7f78, 8, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 8}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}}}, + {"pntgy", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 7}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}}}, + {"pep", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 0}, + {g_unk0x100da790, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"cop01", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 2, g_unk0x100da7e0, g_unk0x100f7ff8, 17}, + {g_unk0x100da778, g_unk0x100f7f78, 3, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 9}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"actor_01", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {g_unk0x100da778, g_unk0x100f7f78, 5, g_unk0x100da7c0, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 10}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"actor_02", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 6}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 12}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 1}}}, + {"actor_03", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 1}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 1}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 6}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 6}}}, + {"actor_04", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 1, g_unk0x100da7e0, g_unk0x100f7ff8, 12}, + {g_unk0x100da778, g_unk0x100f7f78, 6, g_unk0x100da7c0, g_unk0x100f80a0, 5}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 10}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 4}}}, + {"actor_05", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 4, g_unk0x100da7e0, g_unk0x100f7ff8, 22}, + {g_unk0x100da778, g_unk0x100f7f78, 9, g_unk0x100da7c0, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 8}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}}}, + {"btmncycl", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {g_unk0x100da778, g_unk0x100f7f78, 5, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 0}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 3}}}, + {"cboycycl", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 3, g_unk0x100da7e0, g_unk0x100f7ff8, 10}, + {g_unk0x100da778, g_unk0x100f7f78, 7, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 7}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 11}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 2}}}, + {"boatman", + NULL, + NULL, + 0, + 0, + 0, + {{g_unk0x100da7b0, g_unk0x100f7fd8, 0, g_unk0x100da840, g_unk0x100f80a0, 3}, + {g_unk0x100da778, g_unk0x100f7f78, 0, g_unk0x100da7c0, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da830, g_unk0x100f80a0, 7}, + {NULL, NULL, 0, g_unk0x100da7d0, g_unk0x100f8068, 9}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da800, g_unk0x100f80a0, 3}, + {NULL, NULL, 0, g_unk0x100da820, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da810, g_unk0x100f80a0, 2}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 7}, + {NULL, NULL, 0, g_unk0x100da840, g_unk0x100f80a0, 7}}} +}; diff --git a/LEGO1/lego/legoomni/src/common/legofullscreenmovie.cpp b/LEGO1/lego/legoomni/src/common/legofullscreenmovie.cpp new file mode 100644 index 00000000..c95cb40e --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legofullscreenmovie.cpp @@ -0,0 +1,44 @@ +#include "legofullscreenmovie.h" + +#include "decomp.h" +#include "legovideomanager.h" +#include "misc.h" +#include "mxtypes.h" + +DECOMP_SIZE_ASSERT(LegoFullScreenMovie, 0x24) + +// GLOBAL: LEGO1 0x100f3fbc +// STRING: LEGO1 0x100f3be8 +const char* g_strEnable = "enable"; + +// GLOBAL: LEGO1 0x100f3fc0 +// STRING: LEGO1 0x100f3bf4 +const char* g_strDisable = "disable"; + +// FUNCTION: LEGO1 0x1003c500 +LegoFullScreenMovie::LegoFullScreenMovie(const char* p_key, const char* p_value) +{ + m_key = p_key; + m_key.ToUpperCase(); + SetValue(p_value); +} + +// FUNCTION: LEGO1 0x1003c5c0 +void LegoFullScreenMovie::SetValue(const char* p_option) +{ + m_value = p_option; + m_value.ToLowerCase(); + + LegoVideoManager* videomanager = VideoManager(); + if (videomanager) { + if (!strcmp(m_value.GetData(), g_strEnable)) { + videomanager->EnableFullScreenMovie(TRUE); + return; + } + + if (!strcmp(m_value.GetData(), g_strDisable)) { + videomanager->EnableFullScreenMovie(FALSE); + return; + } + } +} diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp new file mode 100644 index 00000000..101a3e6a --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp @@ -0,0 +1,1221 @@ +#include "legogamestate.h" + +#include "3dmanager/lego3dmanager.h" +#include "act1state.h" +#include "act2main_actions.h" +#include "act3_actions.h" +#include "carrace_actions.h" +#include "carracer_actions.h" +#include "copter_actions.h" +#include "define.h" +#include "dunebuggy.h" +#include "dunecar_actions.h" +#include "elevbott_actions.h" +#include "garage_actions.h" +#include "helicopter.h" +#include "histbook_actions.h" +#include "hospital_actions.h" +#include "infocenterstate.h" +#include "infodoor_actions.h" +#include "infomain_actions.h" +#include "infoscor_actions.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "jetrace_actions.h" +#include "jetracer_actions.h" +#include "jetski.h" +#include "jetski_actions.h" +#include "jukebox_actions.h" +#include "jukeboxw_actions.h" +#include "legoanimationmanager.h" +#include "legobackgroundcolor.h" +#include "legobuildingmanager.h" +#include "legocharactermanager.h" +#include "legofullscreenmovie.h" +#include "legomain.h" +#include "legonavcontroller.h" +#include "legoplantmanager.h" +#include "legostate.h" +#include "legoutils.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxnotificationparam.h" +#include "mxobjectfactory.h" +#include "mxstring.h" +#include "mxutilities.h" +#include "mxvariabletable.h" +#include "police_actions.h" +#include "racecar.h" +#include "racecar_actions.h" +#include "regbook_actions.h" +#include "roi/legoroi.h" +#include "scripts.h" +#include "sndanim_actions.h" + +#include + +DECOMP_SIZE_ASSERT(LegoGameState::Username, 0x0e) +DECOMP_SIZE_ASSERT(LegoGameState::ScoreItem, 0x2c) +DECOMP_SIZE_ASSERT(LegoGameState::History, 0x374) +DECOMP_SIZE_ASSERT(LegoGameState, 0x430) +DECOMP_SIZE_ASSERT(ColorStringStruct, 0x08) + +// GLOBAL: LEGO1 0x100f3e40 +// STRING: LEGO1 0x100f3e3c +const char* g_fileExtensionGS = ".GS"; + +// GLOBAL: LEGO1 0x100f3e44 +// STRING: LEGO1 0x100f3e30 +const char* g_playersGSI = "Players.gsi"; + +// GLOBAL: LEGO1 0x100f3e48 +// STRING: LEGO1 0x100f3e24 +const char* g_historyGSI = "History.gsi"; + +// This is a pointer to the end of the global variable name table, which has +// the text "END_OF_VARIABLES" in it. +// TODO: make g_endOfVariables reference the actual end of the variable array. +// GLOBAL: LEGO1 0x100f3e50 +// STRING: LEGO1 0x100f3e00 +const char* g_endOfVariables = "END_OF_VARIABLES"; + +// GLOBAL: LEGO1 0x100f3e58 +ColorStringStruct g_colorSaveData[43] = { + {"c_dbbkfny0", "lego red"}, {"c_dbbkxly0", "lego white"}, // dunebuggy back fender, dunebuggy back axle + {"c_chbasey0", "lego black"}, {"c_chbacky0", "lego black"}, // copter base, copter back + {"c_chdishy0", "lego white"}, {"c_chhorny0", "lego black"}, // copter dish, copter horn + {"c_chljety1", "lego black"}, {"c_chrjety1", "lego black"}, // copter left jet, copter right jet + {"c_chmidly0", "lego black"}, {"c_chmotry0", "lego blue"}, // copter middle, copter motor + {"c_chsidly0", "lego black"}, {"c_chsidry0", "lego black"}, // copter side left, copter side right + {"c_chstuty0", "lego black"}, {"c_chtaily0", "lego black"}, // copter ???, copter tail + {"c_chwindy1", "lego black"}, {"c_dbfbrdy0", "lego red"}, // copter ???, dunebuggy ??? + {"c_dbflagy0", "lego yellow"}, {"c_dbfrfny4", "lego red"}, // dunebuggy flag, dunebuggy front fender + {"c_dbfrxly0", "lego white"}, {"c_dbhndly0", "lego white"}, // dunebuggy front axle, dunebuggy handlebar + {"c_dbltbry0", "lego white"}, {"c_jsdashy0", "lego white"}, // dunebuggy ???, jetski dash + {"c_jsexhy0", "lego black"}, {"c_jsfrnty5", "lego black"}, // jetski exhaust, jetski front + {"c_jshndly0", "lego red"}, {"c_jslsidy0", "lego black"}, // jetski handlebar, jetski left side + {"c_jsrsidy0", "lego black"}, {"c_jsskiby0", "lego red"}, // jetski right side, jetski ??? + {"c_jswnshy5", "lego white"}, {"c_rcbacky6", "lego green"}, // jetski windshield, racecar back + {"c_rcedgey0", "lego green"}, {"c_rcfrmey0", "lego red"}, // racecar edge, racecar frame + {"c_rcfrnty6", "lego green"}, {"c_rcmotry0", "lego white"}, // racecar front, racecar motor + {"c_rcsidey0", "lego green"}, {"c_rcstery0", "lego white"}, // racecar side, racecar steering wheel + {"c_rcstrpy0", "lego yellow"}, {"c_rctailya", "lego white"}, // racecar stripe, racecar tail + {"c_rcwhl1y0", "lego white"}, {"c_rcwhl2y0", "lego white"}, // racecar wheels 1, racecar wheels 2 + {"c_jsbasey0", "lego white"}, {"c_chblady0", "lego black"}, // jetski base, copter blades + {"c_chseaty0", "lego white"}, // copter seat +}; + +// NOTE: This offset = the end of the variables table, the last entry +// in that table is a special entry, the string "END_OF_VARIABLES" +extern const char* g_endOfVariables; + +// FUNCTION: LEGO1 0x10039550 +LegoGameState::LegoGameState() +{ + SetColors(); + SetROIHandlerFunction(); + + m_stateCount = 0; + m_actorId = 0; + m_savePath = NULL; + m_stateArray = NULL; + m_unk0x41c = JukeboxScript::c_noneJukebox; + m_currentArea = e_undefined; + m_previousArea = e_undefined; + m_unk0x42c = e_undefined; + m_playerCount = 0; + m_isDirty = FALSE; + m_loadedAct = e_actNotFound; + SetCurrentAct(e_act1); + + m_backgroundColor = new LegoBackgroundColor("backgroundcolor", "set 56 54 68"); + VariableTable()->SetVariable(m_backgroundColor); + + m_tempBackgroundColor = new LegoBackgroundColor("tempBackgroundColor", "set 56 54 68"); + VariableTable()->SetVariable(m_tempBackgroundColor); + + m_fullScreenMovie = new LegoFullScreenMovie("fsmovie", "disable"); + VariableTable()->SetVariable(m_fullScreenMovie); + + VariableTable()->SetVariable("lightposition", "2"); + SerializeScoreHistory(1); +} + +// FUNCTION: LEGO1 0x10039720 +LegoGameState::~LegoGameState() +{ + LegoROI::FUN_100a9d30(NULL); + + if (m_stateCount) { + for (MxS16 i = 0; i < m_stateCount; i++) { + LegoState* state = m_stateArray[i]; + if (state) { + delete state; + } + } + + delete[] m_stateArray; + } + + delete[] m_savePath; +} + +// FUNCTION: LEGO1 0x10039780 +void LegoGameState::SetActor(MxU8 p_actorId) +{ + if (p_actorId) { + m_actorId = p_actorId; + } + + IslePathActor* oldActor = CurrentActor(); + SetCurrentActor(NULL); + + IslePathActor* newActor = new IslePathActor(); + const char* actorName = LegoActor::GetActorName(m_actorId); + LegoROI* roi = CharacterManager()->GetROI(actorName, FALSE); + MxDSAction action; + + action.SetAtomId(*g_isleScript); + action.SetObjectId(100000); + newActor->Create(action); + newActor->SetActorId(p_actorId); + newActor->SetROI(roi, FALSE, FALSE); + + if (oldActor) { + newActor->GetROI()->FUN_100a58f0(oldActor->GetROI()->GetLocal2World()); + newActor->SetBoundary(oldActor->GetBoundary()); + delete oldActor; + } + + newActor->ClearFlag(0x02); + SetCurrentActor(newActor); +} + +// FUNCTION: LEGO1 0x10039910 +void LegoGameState::RemoveActor() +{ + IslePathActor* actor = CurrentActor(); + SetCurrentActor(NULL); + delete actor; + m_actorId = 0; +} + +// FUNCTION: LEGO1 0x10039940 +void LegoGameState::ResetROI() +{ + if (m_actorId) { + IslePathActor* actor = CurrentActor(); + + if (actor) { + LegoROI* roi = actor->GetROI(); + + if (roi) { + VideoManager()->Get3DManager()->GetLego3DView()->Remove(*roi); + VideoManager()->Get3DManager()->GetLego3DView()->Add(*roi); + } + } + } +} + +// FUNCTION: LEGO1 0x10039980 +MxResult LegoGameState::Save(MxULong p_slot) +{ + InfocenterState* infocenterState = (InfocenterState*) GameState()->GetState("InfocenterState"); + + if (!infocenterState || !infocenterState->HasRegistered()) { + return SUCCESS; + } + + MxResult result = FAILURE; + LegoFile fileStorage; + MxVariableTable* variableTable = VariableTable(); + MxS16 count = 0; + MxU32 i; + MxS32 j; + MxU16 area; + + MxString savePath; + GetFileSavePath(&savePath, p_slot); + + if (fileStorage.Open(savePath.GetData(), LegoFile::c_write) == FAILURE) { + goto done; + } + + Write(&fileStorage, 0x1000c); + Write(&fileStorage, m_unk0x24); + Write(&fileStorage, (MxU16) m_currentAct); + Write(&fileStorage, m_actorId); + + for (i = 0; i < sizeOfArray(g_colorSaveData); i++) { + if (WriteVariable(&fileStorage, variableTable, g_colorSaveData[i].m_targetName) == FAILURE) { + goto done; + } + } + + if (WriteVariable(&fileStorage, variableTable, "backgroundcolor") == FAILURE) { + goto done; + } + if (WriteVariable(&fileStorage, variableTable, "lightposition") == FAILURE) { + goto done; + } + + WriteEndOfVariables(&fileStorage); + CharacterManager()->Write(&fileStorage); + PlantManager()->Write(&fileStorage); + result = BuildingManager()->Write(&fileStorage); + + for (j = 0; j < m_stateCount; j++) { + if (m_stateArray[j]->IsSerializable()) { + count++; + } + } + + Write(&fileStorage, count); + + for (j = 0; j < m_stateCount; j++) { + if (m_stateArray[j]->IsSerializable()) { + m_stateArray[j]->Serialize(&fileStorage); + } + } + + area = m_unk0x42c; + Write(&fileStorage, (MxU16) area); + SerializeScoreHistory(2); + m_isDirty = FALSE; + +done: + return result; +} + +// FUNCTION: LEGO1 0x10039bf0 +MxResult LegoGameState::DeleteState() +{ + MxS16 stateCount = m_stateCount; + LegoState** stateArray = m_stateArray; + + m_stateCount = 0; + m_stateArray = NULL; + + for (MxS32 count = 0; count < stateCount; count++) { + if (!stateArray[count]->SetFlag() && stateArray[count]->IsSerializable()) { + delete stateArray[count]; + } + else { + RegisterState(stateArray[count]); + stateArray[count] = NULL; + } + } + + delete[] stateArray; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10039c60 +MxResult LegoGameState::Load(MxULong p_slot) +{ + MxResult result = FAILURE; + LegoFile fileStorage; + MxVariableTable* variableTable = VariableTable(); + + MxString savePath; + GetFileSavePath(&savePath, p_slot); + + if (fileStorage.Open(savePath.GetData(), LegoFile::c_read) == FAILURE) { + goto done; + } + + MxU32 version, status; + MxS16 count, area, act; + const char* lightPosition; + + Read(&fileStorage, &version); + + if (version != 0x1000c) { + OmniError("Saved game version mismatch", 0); + goto done; + } + + Read(&fileStorage, &m_unk0x24); + + Read(&fileStorage, &act); + SetCurrentAct((Act) act); + + Read(&fileStorage, &m_actorId); + if (m_actorId) { + SetActor(m_actorId); + } + + do { + status = ReadVariable(&fileStorage, variableTable); + if (status == 1) { + goto done; + } + } while (status != 2); + + m_backgroundColor->SetLightColor(); + lightPosition = VariableTable()->GetVariable("lightposition"); + + if (lightPosition) { + SetLightPosition(atoi(lightPosition)); + } + + if (CharacterManager()->Read(&fileStorage) == FAILURE) { + goto done; + } + if (PlantManager()->Read(&fileStorage) == FAILURE) { + goto done; + } + if (BuildingManager()->Read(&fileStorage) == FAILURE) { + goto done; + } + if (DeleteState() != SUCCESS) { + goto done; + } + + char stateName[80]; + Read(&fileStorage, &count); + + if (count) { + for (MxS16 i = 0; i < count; i++) { + MxS16 stateNameLength; + Read(&fileStorage, &stateNameLength); + Read(&fileStorage, stateName, (MxULong) stateNameLength); + stateName[stateNameLength] = 0; + + LegoState* state = GetState(stateName); + if (!state) { + state = CreateState(stateName); + + if (!state) { + goto done; + } + } + + state->Serialize(&fileStorage); + } + } + + Read(&fileStorage, &area); + + if (m_currentAct == 0) { + m_unk0x42c = e_undefined; + } + else { + m_unk0x42c = (Area) area; + } + + result = SUCCESS; + m_isDirty = FALSE; + +done: + if (result != SUCCESS) { + OmniError("Game state loading was not successful!", 0); + } + + return result; +} + +// FUNCTION: LEGO1 0x10039f00 +void LegoGameState::SetSavePath(char* p_savePath) +{ + if (m_savePath != NULL) { + delete[] m_savePath; + } + + if (p_savePath) { + m_savePath = new char[strlen(p_savePath) + 1]; + strcpy(m_savePath, p_savePath); + } + else { + m_savePath = NULL; + } +} + +// FUNCTION: LEGO1 0x10039f70 +MxResult LegoGameState::WriteVariable(LegoStorage* p_storage, MxVariableTable* p_from, const char* p_variableName) +{ + MxResult result = FAILURE; + const char* variableValue = p_from->GetVariable(p_variableName); + + if (variableValue) { + MxU8 length = strlen(p_variableName); + if (p_storage->Write(&length, sizeof(length)) == SUCCESS) { + if (p_storage->Write(p_variableName, length) == SUCCESS) { + length = strlen(variableValue); + if (p_storage->Write(&length, sizeof(length)) == SUCCESS) { + result = p_storage->Write(variableValue, length); + } + } + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1003a020 +MxResult LegoGameState::WriteEndOfVariables(LegoStorage* p_storage) +{ + MxU8 len = strlen(g_endOfVariables); + + if (p_storage->Write(&len, sizeof(len)) == SUCCESS) { + return p_storage->Write(g_endOfVariables, len); + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x1003a080 +MxS32 LegoGameState::ReadVariable(LegoStorage* p_storage, MxVariableTable* p_to) +{ + MxS32 result = 1; + MxU8 length; + + if (p_storage->Read(&length, sizeof(length)) == SUCCESS) { + char nameBuffer[256]; + if (p_storage->Read(nameBuffer, length) == SUCCESS) { + nameBuffer[length] = '\0'; + if (strcmp(nameBuffer, g_endOfVariables) == 0) { + // 2 -> "This was the last entry, done reading." + result = 2; + } + else { + if (p_storage->Read(&length, sizeof(length)) == SUCCESS) { + char valueBuffer[256]; + if (p_storage->Read(valueBuffer, length) == SUCCESS) { + valueBuffer[length] = '\0'; + p_to->SetVariable(nameBuffer, valueBuffer); + result = SUCCESS; + } + } + } + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1003a170 +void LegoGameState::GetFileSavePath(MxString* p_outPath, MxU8 p_slotn) +{ + char baseForSlot[2] = "0"; + char path[1024] = ""; + + // Save path base + if (m_savePath != NULL) { + strcpy(path, m_savePath); + } + + // Slot: "G0", "G1", ... + strcat(path, "\\G"); + baseForSlot[0] += p_slotn; + strcat(path, baseForSlot); + + // Extension: ".GS" + strcat(path, g_fileExtensionGS); + *p_outPath = MxString(path); +} + +// FUNCTION: LEGO1 0x1003a2e0 +void LegoGameState::SerializePlayersInfo(MxS16 p_flags) +{ + LegoFile fileStorage; + MxString playersGSI = MxString(m_savePath); + + playersGSI += "\\"; + playersGSI += g_playersGSI; + + if (fileStorage.Open(playersGSI.GetData(), p_flags) == SUCCESS) { + if (fileStorage.IsReadMode()) { + Read(&fileStorage, &m_playerCount); + } + else if (fileStorage.IsWriteMode()) { + Write(&fileStorage, m_playerCount); + } + + for (MxS16 i = 0; i < m_playerCount; i++) { + m_players[i].ReadWrite(&fileStorage); + } + } +} + +// FUNCTION: LEGO1 0x1003a3f0 +MxResult LegoGameState::AddPlayer(Username& p_player) +{ + MxString from, to; + + if (m_playerCount == 9) { + GetFileSavePath(&from, 8); + DeleteFile(from.GetData()); + m_playerCount--; + } + + for (MxS16 i = m_playerCount; i > 0; i--) { + m_players[i] = m_players[i - 1]; + GetFileSavePath(&from, i - 1); + GetFileSavePath(&to, i); + MoveFile(from.GetData(), to.GetData()); + } + + m_playerCount++; + m_players[0].Set(p_player); + m_unk0x24 = m_history.m_unk0x372; + m_history.m_unk0x372 = m_unk0x24 + 1; + m_history.WriteScoreHistory(); + SetCurrentAct(e_act1); + + return DeleteState(); +} + +// FUNCTION: LEGO1 0x1003a540 +void LegoGameState::SwitchPlayer(MxS16 p_playerId) +{ + if (p_playerId > 0) { + MxString from, temp, to; + + GetFileSavePath(&from, p_playerId); + GetFileSavePath(&temp, 36); + + Username selectedName(m_players[p_playerId]); + + MoveFile(from.GetData(), temp.GetData()); + + for (MxS16 i = p_playerId; i > 0; i--) { + m_players[i] = m_players[i - 1]; + GetFileSavePath(&from, i - 1); + GetFileSavePath(&to, i); + MoveFile(from.GetData(), to.GetData()); + } + + m_players[0] = selectedName; + GetFileSavePath(&from, 0); + MoveFile(temp.GetData(), from.GetData()); + } + + if (Load(0) != SUCCESS) { + Init(); + } +} + +// FUNCTION: LEGO1 0x1003a6e0 +MxS16 LegoGameState::FindPlayer(Username& p_player) +{ + for (MxS16 i = 0; i < m_playerCount; i++) { + if (memcmp(&m_players[i], &p_player, sizeof(p_player)) == 0) { + return i; + } + } + + return -1; +} + +// FUNCTION: LEGO1 0x1003a720 +void LegoGameState::StopArea(Area p_area) +{ + if (p_area == e_previousArea) { + p_area = m_previousArea; + } + + switch (p_area) { + case e_isle: + InvokeAction(Extra::e_stop, *g_isleScript, IsleScript::c__Isle, NULL); + InvokeAction(Extra::e_close, *g_isleScript, IsleScript::c__Isle, NULL); + InvokeAction(Extra::e_close, *g_sndAnimScript, SndanimScript::c_SoundAndAnim_Action, NULL); + break; + case e_infomain: + InvokeAction(Extra::e_stop, *g_infomainScript, InfomainScript::c__InfoMain, NULL); + InvokeAction(Extra::e_close, *g_infomainScript, InfomainScript::c__InfoMain, NULL); + break; + case e_infodoor: + InvokeAction(Extra::e_stop, *g_infodoorScript, InfodoorScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_infodoorScript, InfodoorScript::c__StartUp, NULL); + break; + case e_elevbott: + InvokeAction(Extra::e_stop, *g_elevbottScript, ElevbottScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_elevbottScript, ElevbottScript::c__StartUp, NULL); + break; + case e_elevride: + case e_elevride2: + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevRide_Background_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevRide_Info_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevRide_Two_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevRide_Three_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Meter1_3_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Meter2_3_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Meter3_1_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Meter3_2_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Meter2_1_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Meter1_2_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Meter3_Bitmap, *g_isleScript, 0); + break; + case e_elevopen: + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevOpen_Background_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevOpen_LeftArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevOpen_RightArrow_Ctl, *g_isleScript, 0); + break; + case e_seaview: + RemoveFromWorld(*g_isleScript, IsleScript::c_SeaView_Background_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_SeaView_LeftArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_SeaView_RightArrow_Ctl, *g_isleScript, 0); + break; + case e_observe: + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Background_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_LeftArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_RightArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Plane_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Sun_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Moon_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_SkyColor_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_LCab_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_RCab_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_GlobeRArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_GlobeLArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe1_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe2_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe3_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe4_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe5_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Globe6_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Draw1_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Observe_Draw2_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_Radio_Ctl, *g_isleScript, 0); + break; + case e_elevdown: + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevDown_Background_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevDown_LeftArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevDown_RightArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_ElevDown_Elevator_Ctl, *g_isleScript, 0); + break; + case e_regbook: + InvokeAction(Extra::e_stop, *g_regbookScript, RegbookScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_regbookScript, RegbookScript::c__StartUp, NULL); + break; + case e_infoscor: + InvokeAction(Extra::e_stop, *g_infoscorScript, InfoscorScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_infoscorScript, InfoscorScript::c__StartUp, NULL); + break; + case e_jetrace: + InvokeAction(Extra::e_stop, *g_jetraceScript, JetraceScript::c__JetRace_World, NULL); + InvokeAction(Extra::e_close, *g_jetraceScript, JetraceScript::c__JetRace_World, NULL); + InvokeAction(Extra::e_close, *g_jetracerScript, 0, NULL); + break; + case e_carrace: + InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c__CarRace_World, NULL); + InvokeAction(Extra::e_close, *g_carraceScript, CarraceScript::c__CarRace_World, NULL); + InvokeAction(Extra::e_close, *g_carracerScript, CarracerScript::c_nrt002pz_Anim, NULL); + break; + case e_garage: + Lego()->RemoveWorld(*g_garageScript, 0); + InvokeAction(Extra::e_stop, *g_garageScript, GarageScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_garageScript, GarageScript::c__StartUp, NULL); + break; + case e_garadoor: + RemoveFromWorld(*g_isleScript, IsleScript::c_GaraDoor_Background_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_GaraDoor_LeftArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_GaraDoor_RightArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_GaraDoor_Door_Ctl, *g_isleScript, 0); + break; + case e_hospital: + InvokeAction(Extra::e_stop, *g_hospitalScript, HospitalScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_hospitalScript, HospitalScript::c__StartUp, NULL); + break; + case e_police: + InvokeAction(Extra::e_stop, *g_policeScript, PoliceScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_policeScript, PoliceScript::c__StartUp, NULL); + break; + case e_polidoor: + RemoveFromWorld(*g_isleScript, IsleScript::c_PoliDoor_Background_Bitmap, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_PoliDoor_LeftArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_PoliDoor_RightArrow_Ctl, *g_isleScript, 0); + RemoveFromWorld(*g_isleScript, IsleScript::c_PoliDoor_Door_Ctl, *g_isleScript, 0); + break; + case e_copterbuild: + InvokeAction(Extra::e_stop, *g_jukeboxScript, JukeboxScript::c_HelicopterBuild_Movie, NULL); + InvokeAction(Extra::e_stop, *g_copterScript, CopterScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_copterScript, CopterScript::c__StartUp, NULL); + break; + case e_dunecarbuild: + InvokeAction(Extra::e_stop, *g_jukeboxScript, JukeboxScript::c_DuneCarBuild_Movie, NULL); + InvokeAction(Extra::e_stop, *g_dunecarScript, DunecarScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_dunecarScript, DunecarScript::c__StartUp, NULL); + break; + case e_jetskibuild: + InvokeAction(Extra::e_stop, *g_jukeboxScript, JukeboxScript::c_JetskiBuild_Movie, NULL); + InvokeAction(Extra::e_stop, *g_jetskiScript, JetskiScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_jetskiScript, JetskiScript::c__StartUp, NULL); + break; + case e_racecarbuild: + InvokeAction(Extra::e_stop, *g_jukeboxScript, JukeboxScript::c_RaceCarBuild_Movie, NULL); + InvokeAction(Extra::e_stop, *g_racecarScript, RacecarScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_racecarScript, RacecarScript::c__StartUp, NULL); + break; + case e_act2main: + if (m_currentArea != 2) { + InvokeAction(Extra::e_stop, *g_act2mainScript, Act2mainScript::c__Act2Main, NULL); + InvokeAction(Extra::e_close, *g_act2mainScript, Act2mainScript::c__Act2Main, NULL); + } + break; + case e_act3script: + if (m_currentArea != 2) { + InvokeAction(Extra::e_stop, *g_act3Script, Act3Script::c__Act3, NULL); + InvokeAction(Extra::e_close, *g_act3Script, Act3Script::c__Act3, NULL); + } + break; + case e_jukeboxw: + InvokeAction(Extra::e_stop, *g_jukeboxwScript, JukeboxwScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_jukeboxwScript, JukeboxwScript::c__StartUp, NULL); + break; + case e_histbook: + InvokeAction(Extra::e_disable, *g_histbookScript, HistbookScript::c__StartUp, NULL); + InvokeAction(Extra::e_stop, *g_histbookScript, HistbookScript::c__StartUp, NULL); + InvokeAction(Extra::e_close, *g_histbookScript, HistbookScript::c__StartUp, NULL); + break; + } +} + +inline void LoadIsle() +{ + LegoWorld* world = FindWorld(*g_isleScript, 0); + if (world != NULL) { + if (!world->GetUnknown0xd0().empty()) { + NotificationManager()->Send(world, MxNotificationParam(c_notificationType20, NULL)); + } + } + else { + InvokeAction(Extra::ActionType::e_opendisk, *g_isleScript, IsleScript::c__Isle, NULL); + } +} + +// FUNCTION: LEGO1 0x1003b060 +void LegoGameState::SwitchArea(Area p_area) +{ + m_previousArea = m_currentArea; + m_currentArea = p_area; + + FUN_10015820(TRUE, LegoOmni::c_disableInput | LegoOmni::c_disable3d); + BackgroundAudioManager()->Stop(); + AnimationManager()->Suspend(); + VideoManager()->SetUnk0x554(FALSE); + + switch (p_area) { + case e_isle: + InvokeAction(Extra::ActionType::e_opendisk, *g_isleScript, IsleScript::c__Isle, NULL); + break; + case e_infomain: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_infomainScript, InfomainScript::c__InfoMain, NULL); + break; + case e_infodoor: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_infodoorScript, InfodoorScript::c__StartUp, NULL); + break; + case e_unk4: + case e_jetrace2: + case e_jetraceExterior: + case e_unk17: + case e_carraceExterior: + case e_unk20: + case e_unk21: + case e_pizzeriaExterior: + case e_garageExterior: + case e_hospitalExterior: + case e_unk31: + case e_policeExterior: + case e_bike: + case e_dunecar: + case e_motocycle: + case e_copter: + case e_skateboard: + case e_jetski: + case e_unk66: + LoadIsle(); + break; + case e_elevbott: + InvokeAction(Extra::ActionType::e_opendisk, *g_elevbottScript, ElevbottScript::c__StartUp, NULL); + break; + case e_elevride: + case e_elevride2: + LoadIsle(); + InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_ElevRide, NULL); + break; + case e_elevopen: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_ElevOpen, NULL); + break; + case e_seaview: + InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_SeaView, NULL); + break; + case e_observe: + InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_Observe, NULL); + break; + case e_elevdown: + InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_ElevDown, NULL); + break; + case e_regbook: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_regbookScript, RegbookScript::c__StartUp, NULL); + break; + case e_infoscor: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_infoscorScript, InfoscorScript::c__StartUp, NULL); + break; + case e_jetrace: + if (m_previousArea == e_infomain) { + m_currentArea = e_jetrace2; + LoadIsle(); + } + else { + InvokeAction(Extra::ActionType::e_opendisk, *g_jetraceScript, JetraceScript::c__JetRace_World, NULL); + } + break; + case e_carrace: + if (m_previousArea == e_infomain) { + m_currentArea = e_carraceExterior; + LoadIsle(); + } + else { + InvokeAction(Extra::ActionType::e_opendisk, *g_carraceScript, CarraceScript::c__CarRace_World, NULL); + } + break; + case e_garage: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_garageScript, GarageScript::c__StartUp, NULL); + break; + case e_garadoor: + LoadIsle(); + VariableTable()->SetVariable("VISIBILITY", "Hide Gas"); + CurrentActor()->ResetWorldTransform(FALSE); + NavController()->UpdateLocation(59); // LCAMZG1 in g_cameraLocations + VideoManager()->Get3DManager()->SetFrustrum(90, 0.1f, 250.0f); + InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_GaraDoor, NULL); + break; + case e_unk28: { + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + LoadIsle(); + + if (state->GetUnknown18() == 7) { + VideoManager()->Get3DManager()->SetFrustrum(90, 0.1f, 250.0f); + } + else { + SetCameraControllerFromIsle(); + CurrentActor()->ResetWorldTransform(TRUE); + AnimationManager()->Resume(); + } + + CurrentActor()->SpawnPlayer( + p_area, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + break; + } + case e_hospital: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_hospitalScript, HospitalScript::c__StartUp, NULL); + break; + case e_unk33: + LoadIsle(); + SetCameraControllerFromIsle(); + CurrentActor()->ResetWorldTransform(TRUE); + AnimationManager()->Resume(); + CurrentActor()->SpawnPlayer( + p_area, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + break; + case e_police: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_policeScript, PoliceScript::c__StartUp, NULL); + break; + case e_polidoor: + LoadIsle(); + InvokeAction(Extra::ActionType::e_start, *g_isleScript, IsleScript::c_PoliDoor, NULL); + break; + case e_copterbuild: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_copterScript, CopterScript::c__StartUp, NULL); + break; + case e_dunecarbuild: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_dunecarScript, DunecarScript::c__StartUp, NULL); + break; + case e_jetskibuild: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_jetskiScript, JetskiScript::c__StartUp, NULL); + break; + case e_racecarbuild: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_racecarScript, RacecarScript::c__StartUp, NULL); + break; + case e_act2main: { + LegoWorld* act2main = FindWorld(*g_act2mainScript, 0); + + if (act2main == NULL) { + InvokeAction(Extra::ActionType::e_opendisk, *g_act2mainScript, Act2mainScript::c__Act2Main, NULL); + } + else { + act2main->Enable(TRUE); + } + + break; + } + case e_act3script: { + LegoWorld* act3 = FindWorld(*g_act3Script, 0); + + if (act3 == NULL) { + InvokeAction(Extra::ActionType::e_opendisk, *g_act3Script, Act3Script::c__Act3, NULL); + } + else { + act3->Enable(TRUE); + } + + break; + } + case e_jukeboxw: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_jukeboxwScript, JukeboxwScript::c__StartUp, NULL); + break; + case e_unk54: + LoadIsle(); + break; + case e_histbook: + VideoManager()->SetUnk0x554(TRUE); + InvokeAction(Extra::ActionType::e_opendisk, *g_histbookScript, HistbookScript::c__StartUp, NULL); + break; + default: + break; + } +} + +// FUNCTION: LEGO1 0x1003ba90 +void LegoGameState::SetColors() +{ + MxVariableTable* variableTable = VariableTable(); + + for (MxS32 i = 0; i < sizeOfArray(g_colorSaveData); i++) { + variableTable->SetVariable(g_colorSaveData[i].m_targetName, g_colorSaveData[i].m_colorName); + } +} + +// FUNCTION: LEGO1 0x1003bac0 +void LegoGameState::SetROIHandlerFunction() +{ + LegoROI::FUN_100a9d30(&ROIHandlerFunction); +} + +// FUNCTION: LEGO1 0x1003bad0 +MxBool ROIHandlerFunction(const char* p_input, char* p_output, MxU32 p_copyLen) +{ + if (p_output != NULL && p_copyLen != 0 && + (strnicmp(p_input, "INDIR-F-", strlen("INDIR-F-")) == 0 || + strnicmp(p_input, "INDIR-G-", strlen("INDIR-F-")) == 0)) { + + char buf[256]; + sprintf(buf, "c_%s", &p_input[strlen("INDIR-F-")]); + + const char* value = VariableTable()->GetVariable(buf); + if (value != NULL) { + strncpy(p_output, value, p_copyLen); + p_output[p_copyLen - 1] = '\0'; + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x1003bbb0 +LegoState* LegoGameState::GetState(const char* p_stateName) +{ + for (MxS32 i = 0; i < m_stateCount; ++i) { + if (m_stateArray[i]->IsA(p_stateName)) { + return m_stateArray[i]; + } + } + return NULL; +} + +// FUNCTION: LEGO1 0x1003bc00 +LegoState* LegoGameState::CreateState(const char* p_stateName) +{ + LegoState* newState = (LegoState*) ObjectFactory()->Create(p_stateName); + RegisterState(newState); + + return newState; +} + +// FUNCTION: LEGO1 0x1003bc30 +void LegoGameState::RegisterState(LegoState* p_state) +{ + MxS32 targetIndex; + for (targetIndex = 0; targetIndex < m_stateCount; ++targetIndex) { + if (m_stateArray[targetIndex]->IsA(p_state->ClassName())) { + break; + } + } + + if (targetIndex == m_stateCount) { + LegoState** newBuffer = new LegoState*[m_stateCount + 1]; + + if (m_stateCount != 0) { + memcpy(newBuffer, m_stateArray, m_stateCount * sizeof(LegoState*)); + delete[] m_stateArray; + } + + newBuffer[m_stateCount++] = p_state; + m_stateArray = newBuffer; + return; + } + + delete m_stateArray[targetIndex]; + m_stateArray[targetIndex] = p_state; +} + +// FUNCTION: LEGO1 0x1003bd00 +void LegoGameState::Init() +{ + m_backgroundColor->SetValue("set 56 54 68"); + m_backgroundColor->SetLightColor(); + m_tempBackgroundColor->SetValue("set 56 54 68"); + VariableTable()->SetVariable("lightposition", "2"); + SetLightPosition(2); + PlantManager()->Init(); + BuildingManager()->Init(); + CharacterManager()->Init(); + AnimationManager()->Reset(TRUE); + SetColors(); + RemoveActor(); + DeleteState(); + m_isDirty = FALSE; + FindLoadedAct(); + SetCurrentAct(e_act1); + + if (m_loadedAct == e_act1) { + Isle* isle = (Isle*) FindWorld(*g_isleScript, 0); + + Helicopter* copter = (Helicopter*) isle->Find(*g_copterScript, CopterScript::c_Helicopter_Actor); + if (copter) { + isle->RemovePathActor(copter); + isle->VTable0x6c(copter); + delete copter; + } + + DuneBuggy* dunebuggy = (DuneBuggy*) isle->Find(*g_dunecarScript, DunecarScript::c_DuneBugy_Actor); + if (dunebuggy) { + isle->RemovePathActor(dunebuggy); + isle->VTable0x6c(dunebuggy); + delete dunebuggy; + } + + Jetski* jetski = (Jetski*) isle->Find(*g_jetskiScript, JetskiScript::c_Jetski_Actor); + if (jetski) { + isle->RemovePathActor(jetski); + isle->VTable0x6c(jetski); + delete jetski; + } + + RaceCar* racecar = (RaceCar*) isle->Find(*g_racecarScript, RacecarScript::c_RaceCar_Actor); + if (racecar) { + isle->RemovePathActor(racecar); + isle->VTable0x6c(racecar); + delete racecar; + } + } + + m_unk0x42c = e_undefined; +} + +// FUNCTION: LEGO1 0x1003c670 +LegoGameState::Username::Username() +{ + memset(m_letters, -1, sizeof(m_letters)); +} + +// FUNCTION: LEGO1 0x1003c690 +MxResult LegoGameState::Username::ReadWrite(LegoStorage* p_storage) +{ + if (p_storage->IsReadMode()) { + for (MxS16 i = 0; i < 7; i++) { + p_storage->Read(&m_letters[i], sizeof(m_letters[i])); + } + } + else if (p_storage->IsWriteMode()) { + for (MxS16 i = 0; i < 7; i++) { + MxS16 letter = m_letters[i]; + p_storage->Write(&letter, sizeof(letter)); + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1003c710 +LegoGameState::Username& LegoGameState::Username::operator=(const Username& p_other) +{ + memcpy(m_letters, p_other.m_letters, sizeof(m_letters)); + return *this; +} + +// FUNCTION: LEGO1 0x1003c830 +LegoGameState::History::History() +{ + m_count = 0; + m_unk0x372 = 0; +} + +// STUB: LEGO1 0x1003c870 +void LegoGameState::History::WriteScoreHistory() +{ + // TODO +} + +// STUB: LEGO1 0x1003ccf0 +void LegoGameState::History::FUN_1003ccf0(LegoFile&) +{ + // TODO +} + +// FUNCTION: LEGO1 0x1003cdd0 +void LegoGameState::SerializeScoreHistory(MxS16 p_flags) +{ + LegoFile stream; + MxString savePath(m_savePath); + savePath += "\\"; + savePath += g_historyGSI; + + if (p_flags == LegoFile::c_write) { + m_history.WriteScoreHistory(); + } + + if (stream.Open(savePath.GetData(), p_flags) == SUCCESS) { + m_history.FUN_1003ccf0(stream); + } +} + +// FUNCTION: LEGO1 0x1003cea0 +void LegoGameState::SetCurrentAct(Act p_currentAct) +{ + m_currentAct = p_currentAct; +} + +// FUNCTION: LEGO1 0x1003ceb0 +void LegoGameState::FindLoadedAct() +{ + if (FindWorld(*g_isleScript, 0)) { + m_loadedAct = e_act1; + } + else if (FindWorld(*g_act2mainScript, 0)) { + m_loadedAct = e_act2; + } + else if (FindWorld(*g_act3Script, 0)) { + m_loadedAct = e_act3; + } + else { + m_loadedAct = e_actNotFound; + } +} diff --git a/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp b/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp new file mode 100644 index 00000000..46926705 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legoobjectfactory.cpp @@ -0,0 +1,135 @@ +#include "legoobjectfactory.h" + +#include "act2actor.h" +#include "act2brick.h" +#include "carrace.h" +#include "decomp.h" +#include "dunebuggy.h" +#include "elevatorbottom.h" +#include "gasstation.h" +#include "gasstationstate.h" +#include "helicopter.h" +#include "helicopterstate.h" +#include "historybook.h" +#include "hospital.h" +#include "hospitalstate.h" +#include "infocenter.h" +#include "infocenterdoor.h" +#include "infocenterstate.h" +#include "isle.h" +#include "jetskirace.h" +#include "lego3dwavepresenter.h" +#include "legoact2.h" +#include "legoact2state.h" +#include "legoactioncontrolpresenter.h" +#include "legoactor.h" +#include "legoactorpresenter.h" +#include "legoanimactor.h" +#include "legoanimpresenter.h" +#include "legocarbuild.h" +#include "legocarbuildanimpresenter.h" +#include "legocarraceactor.h" +#include "legoentity.h" +#include "legoentitypresenter.h" +#include "legoflctexturepresenter.h" +#include "legohideanimpresenter.h" +#include "legojetski.h" +#include "legojetskiraceactor.h" +#include "legoloadcachesoundpresenter.h" +#include "legolocomotionanimpresenter.h" +#include "legoloopinganimpresenter.h" +#include "legomodelpresenter.h" +#include "legopalettepresenter.h" +#include "legopartpresenter.h" +#include "legopathactor.h" +#include "legopathpresenter.h" +#include "legophonemepresenter.h" +#include "legoracecar.h" +#include "legotexturepresenter.h" +#include "legoworld.h" +#include "legoworldpresenter.h" +#include "mxcontrolpresenter.h" +#include "mxvideopresenter.h" +#include "pizza.h" +#include "pizzamissionstate.h" +#include "police.h" +#include "policestate.h" +#include "registrationbook.h" +#include "score.h" +#include "scorestate.h" +#include "skateboard.h" +// #include "act2genactor.h" +#include "act2policestation.h" +#include "act3.h" +#include "act3state.h" +#include "ambulance.h" +#include "ambulancemissionstate.h" +#include "bike.h" +#include "doors.h" +#include "jetski.h" +#include "legoanimmmpresenter.h" +#include "motocycle.h" +#include "racecar.h" +#include "towtrack.h" +#include "towtrackmissionstate.h" +// #include "act3cop.h" +// #include "act3brickster.h" +#include "act1state.h" +#include "act3actor.h" +#include "act3shark.h" +#include "animstate.h" +#include "beachhouseentity.h" +#include "bumpbouy.h" +#include "carracestate.h" +#include "caveentity.h" +#include "gasstationentity.h" +#include "hospitalentity.h" +#include "infocenterentity.h" +#include "jailentity.h" +#include "jetskiracestate.h" +#include "jukebox.h" +#include "jukeboxentity.h" +#include "jukeboxstate.h" +#include "mxcompositemediapresenter.h" +#include "pizzeria.h" +#include "pizzeriastate.h" +#include "policeentity.h" +#include "raceskel.h" +#include "racestandsentity.h" +#include "radiostate.h" + +// TODO: Before HospitalState, add all of the different LegoVehicleBuildState's + +// TODO: Uncomment once we have all the relevant types ready +// DECOMP_SIZE_ASSERT(LegoObjectFactory, 0x1c8); + +// FUNCTION: LEGO1 0x10006e40 +LegoObjectFactory::LegoObjectFactory() +{ +#define X(V) this->m_id##V = MxAtomId(#V, e_exact); + FOR_LEGOOBJECTFACTORY_OBJECTS(X) +#undef X +} + +// FUNCTION: LEGO1 0x10009a90 +MxCore* LegoObjectFactory::Create(const char* p_name) +{ + MxAtomId atom(p_name, e_exact); + +#define X(V) \ + if (this->m_id##V == atom) { \ + return new V; \ + } \ + else + FOR_LEGOOBJECTFACTORY_OBJECTS(X) +#undef X + { + return MxObjectFactory::Create(p_name); + } +} + +// FUNCTION: LEGO1 0x1000fb30 +void LegoObjectFactory::Destroy(MxCore* p_object) +{ + delete p_object; +} diff --git a/LEGO1/lego/legoomni/src/common/legophoneme.cpp b/LEGO1/lego/legoomni/src/common/legophoneme.cpp new file mode 100644 index 00000000..55da20c9 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legophoneme.cpp @@ -0,0 +1,62 @@ +#include "legophoneme.h" + +DECOMP_SIZE_ASSERT(LegoPhoneme, 0x20) + +// FUNCTION: LEGO1 0x10044e50 +LegoPhoneme::~LegoPhoneme() +{ +} + +// FUNCTION: LEGO1 0x10044eb0 +undefined4 LegoPhoneme::VTable0x00() +{ + return m_unk0x14; +} + +// FUNCTION: LEGO1 0x10044ec0 +void LegoPhoneme::VTable0x04(undefined4 p_unk0x14) +{ + m_unk0x14 = p_unk0x14; +} + +// FUNCTION: LEGO1 0x10044ed0 +LegoTextureInfo* LegoPhoneme::VTable0x08() +{ + return m_unk0x18; +} + +// FUNCTION: LEGO1 0x10044ee0 +void LegoPhoneme::VTable0x0c(LegoTextureInfo* p_unk0x18) +{ + m_unk0x18 = p_unk0x18; +} + +// FUNCTION: LEGO1 0x10044ef0 +LegoTextureInfo* LegoPhoneme::VTable0x10() +{ + return m_unk0x1c; +} + +// FUNCTION: LEGO1 0x10044f00 +void LegoPhoneme::VTable0x14(LegoTextureInfo* p_unk0x1c) +{ + m_unk0x1c = p_unk0x1c; +} + +// FUNCTION: LEGO1 0x10044f10 +void LegoPhoneme::VTable0x18() +{ +} + +// FUNCTION: LEGO1 0x10044f20 +void LegoPhoneme::Init() +{ + m_unk0x14 = 0; + m_unk0x18 = NULL; + m_unk0x1c = NULL; +} + +// FUNCTION: LEGO1 0x10044f30 +void LegoPhoneme::VTable0x20(undefined4) +{ +} diff --git a/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp new file mode 100644 index 00000000..3e7aeed8 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp @@ -0,0 +1,103 @@ +#include "legoplantmanager.h" + +#include "legoentity.h" + +DECOMP_SIZE_ASSERT(LegoPlantManager, 0x2c) + +// GLOBAL: LEGO1 0x100f3188 +char* LegoPlantManager::g_customizeAnimFile = NULL; + +// FUNCTION: LEGO1 0x10026220 +LegoPlantManager::LegoPlantManager() +{ + Init(); +} + +// STUB: LEGO1 0x100262c0 +LegoPlantManager::~LegoPlantManager() +{ + // TODO +} + +// STUB: LEGO1 0x10026330 +void LegoPlantManager::Init() +{ + // TODO +} + +// STUB: LEGO1 0x10026360 +void LegoPlantManager::FUN_10026360(MxS32 p_scriptIndex) +{ + // TODO +} + +// STUB: LEGO1 0x100263a0 +void LegoPlantManager::FUN_100263a0(undefined4 p_und) +{ + // TODO +} + +// STUB: LEGO1 0x10026720 +void LegoPlantManager::Write(LegoStorage* p_storage) +{ + // TODO +} + +// STUB: LEGO1 0x100267b0 +MxResult LegoPlantManager::Read(LegoStorage* p_storage) +{ + return SUCCESS; +} + +// STUB: LEGO1 0x100269e0 +MxBool LegoPlantManager::FUN_100269e0(LegoEntity* p_entity) +{ + // TODO + return FALSE; +} + +// STUB: LEGO1 0x10026ba0 +MxU32 LegoPlantManager::FUN_10026ba0(LegoEntity*, MxBool) +{ + // TODO + return 0; +} + +// FUNCTION: LEGO1 0x10026be0 +void LegoPlantManager::SetCustomizeAnimFile(const char* p_value) +{ + if (g_customizeAnimFile != NULL) { + delete[] g_customizeAnimFile; + } + + if (p_value != NULL) { + g_customizeAnimFile = new char[strlen(p_value) + 1]; + + if (g_customizeAnimFile != NULL) { + strcpy(g_customizeAnimFile, p_value); + } + } + else { + g_customizeAnimFile = NULL; + } +} + +// STUB: LEGO1 0x10026c50 +void LegoPlantManager::FUN_10026c50(LegoEntity* p_entity) +{ + // TODO +} + +// STUB: LEGO1 0x10026e00 +MxResult LegoPlantManager::Tickle() +{ + // TODO + + return 0; +} + +// STUB: LEGO1 0x10027120 +void LegoPlantManager::FUN_10027120() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/common/legostate.cpp b/LEGO1/lego/legoomni/src/common/legostate.cpp new file mode 100644 index 00000000..a8c2cc6b --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legostate.cpp @@ -0,0 +1,59 @@ +#include "legostate.h" + +#include + +DECOMP_SIZE_ASSERT(LegoState, 0x08) +DECOMP_SIZE_ASSERT(LegoState::Playlist, 0x0c) + +// FUNCTION: LEGO1 0x10014d00 +MxU32 LegoState::Playlist::Next() +{ + MxU32 objectId; + + switch (m_mode) { + case e_loop: + objectId = m_objectIds[m_nextIndex]; + if (m_nextIndex - m_length == -1) { + m_nextIndex = 0; + } + else { + m_nextIndex++; + } + break; + + case e_once: + objectId = m_objectIds[m_nextIndex]; + if (m_length > m_nextIndex + 1) { + m_nextIndex++; + } + break; + + case e_random: + m_nextIndex = rand() % m_length; + objectId = m_objectIds[m_nextIndex]; + break; + + case e_loopSkipFirst: + objectId = m_objectIds[m_nextIndex]; + if (m_nextIndex - m_length == -1) { + m_nextIndex = 1; + } + else { + m_nextIndex++; + } + } + + return objectId; +} + +// FUNCTION: LEGO1 0x10014de0 +MxBool LegoState::Playlist::Contains(MxU32 p_objectId) +{ + for (MxS16 i = 0; i < m_length; i++) { + if (m_objectIds[i] == p_objectId) { + return TRUE; + } + } + + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp b/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp new file mode 100644 index 00000000..51775a03 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp @@ -0,0 +1,218 @@ +#include "legotextureinfo.h" + +#include "legovideomanager.h" +#include "misc.h" +#include "misc/legoimage.h" +#include "misc/legotexture.h" +#include "mxdirectx/mxdirect3d.h" +#include "tgl/d3drm/impl.h" + +DECOMP_SIZE_ASSERT(LegoTextureInfo, 0x10) + +// FUNCTION: LEGO1 0x10065bf0 +LegoTextureInfo::LegoTextureInfo() +{ + m_name = NULL; + m_surface = NULL; + m_palette = NULL; + m_texture = NULL; +} + +// FUNCTION: LEGO1 0x10065c00 +LegoTextureInfo::~LegoTextureInfo() +{ + if (m_name) { + delete[] m_name; + m_name = NULL; + } + + if (m_palette) { + m_palette->Release(); + m_palette = NULL; + } + + if (m_surface) { + m_surface->Release(); + m_surface = NULL; + } + + if (m_texture) { + m_texture->Release(); + m_texture = NULL; + } +} + +// FUNCTION: LEGO1 0x10065c60 +LegoTextureInfo* LegoTextureInfo::Create(const char* p_name, LegoTexture* p_texture) +{ + LegoTextureInfo* textureInfo = new LegoTextureInfo(); + + if (p_name == NULL || p_texture == NULL) { + return NULL; + } + + if (p_name) { + textureInfo->m_name = new char[strlen(p_name) + 1]; + strcpy(textureInfo->m_name, p_name); + } + + LPDIRECTDRAW pDirectDraw = VideoManager()->GetDirect3D()->DirectDraw(); + LegoImage* image = p_texture->GetImage(); + + DDSURFACEDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + desc.dwWidth = image->GetWidth(); + desc.dwHeight = image->GetHeight(); + desc.ddsCaps.dwCaps = DDCAPS_OVERLAYCANTCLIP | DDCAPS_OVERLAY; + desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); + desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8; + desc.ddpfPixelFormat.dwRGBBitCount = 8; + + MxS32 i; + LegoU8* bits; + MxU8* surface; + + if (pDirectDraw->CreateSurface(&desc, &textureInfo->m_surface, NULL) != DD_OK) { + goto done; + } + + bits = image->GetBits(); + + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) != DD_OK) { + goto done; + } + + surface = (MxU8*) desc.lpSurface; + if (desc.dwWidth == desc.lPitch) { + memcpy(surface, bits, desc.dwWidth * desc.dwHeight); + } + else { + for (i = 0; i < desc.dwHeight; i++) { + *(MxU32*) surface = *(MxU32*) bits; + surface += desc.lPitch; + bits += desc.dwWidth; + } + } + + textureInfo->m_surface->Unlock(desc.lpSurface); + + PALETTEENTRY entries[256]; + memset(entries, 0, sizeof(entries)); + + for (i = 0; i < sizeOfArray(entries); i++) { + if (i < image->GetCount()) { + entries[i].peFlags = 0; + entries[i].peRed = image->GetPaletteEntry(i).GetRed(); + entries[i].peGreen = image->GetPaletteEntry(i).GetGreen(); + entries[i].peBlue = image->GetPaletteEntry(i).GetBlue(); + } + else { + entries[i].peFlags = 0x80; + } + } + + if (pDirectDraw->CreatePalette(DDPCAPS_ALLOW256 | DDPCAPS_8BIT, entries, &textureInfo->m_palette, NULL) != DD_OK) { + goto done; + } + + textureInfo->m_surface->SetPalette(textureInfo->m_palette); + + if (((TglImpl::RendererImpl*) VideoManager()->GetRenderer()) + ->CreateTextureFromSurface(textureInfo->m_surface, &textureInfo->m_texture) != D3DRM_OK) { + goto done; + } + + textureInfo->m_texture->SetAppData((DWORD) textureInfo); + return textureInfo; + +done: + if (textureInfo->m_name != NULL) { + delete[] textureInfo->m_name; + textureInfo->m_name = NULL; + } + + if (textureInfo->m_palette != NULL) { + textureInfo->m_palette->Release(); + textureInfo->m_palette = NULL; + } + + if (textureInfo->m_surface != NULL) { + textureInfo->m_surface->Release(); + textureInfo->m_surface = NULL; + } + + if (textureInfo != NULL) { + delete textureInfo; + } + + return NULL; +} + +// STUB: LEGO1 0x10065f60 +BOOL LegoTextureInfo::SetGroupTexture(Tgl::Mesh* pMesh, LegoTextureInfo* p_textureInfo) +{ + TglImpl::MeshImpl::MeshData* data = ((TglImpl::MeshImpl*) pMesh)->ImplementationData(); + data->groupMesh->SetGroupTexture(data->groupIndex, p_textureInfo->m_texture); + return TRUE; +} + +// FUNCTION: LEGO1 0x10065f90 +BOOL LegoTextureInfo::GetGroupTexture(Tgl::Mesh* pMesh, LegoTextureInfo*& p_textureInfo) +{ + TglImpl::MeshImpl::MeshData* data = ((TglImpl::MeshImpl*) pMesh)->ImplementationData(); + + IDirect3DRMMesh* mesh = data->groupMesh; + D3DRMGROUPINDEX id = data->groupIndex; + LPDIRECT3DRMTEXTURE returnPtr = NULL; + LPDIRECT3DRMTEXTURE2 texture = NULL; + + if (mesh->GetGroupTexture(id, &returnPtr) == D3DRM_OK) { + if (returnPtr->QueryInterface(IID_IDirect3DRMTexture2, (LPVOID*) &texture) == D3DRM_OK) { + p_textureInfo = (LegoTextureInfo*) texture->GetAppData(); + + texture->Release(); + returnPtr->Release(); + } + + return TRUE; + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10066010 +LegoResult LegoTextureInfo::FUN_10066010(LegoU8* p_bits) +{ + if (m_surface != NULL && m_texture != NULL) { + DDSURFACEDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (m_surface->Lock(NULL, &desc, 0, NULL) == DD_OK) { + MxU8* surface = (MxU8*) desc.lpSurface; + LegoU8* bits = p_bits; + + if (desc.dwWidth == desc.lPitch) { + memcpy(desc.lpSurface, p_bits, desc.dwWidth * desc.dwHeight); + } + else { + for (MxS32 i = 0; i < desc.dwHeight; i++) { + memcpy(surface, bits, desc.dwWidth); + surface += desc.lPitch; + bits += desc.dwWidth; + } + } + + m_surface->Unlock(desc.lpSurface); + m_texture->Changed(TRUE, FALSE); + return SUCCESS; + } + } + + return FAILURE; +} diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp new file mode 100644 index 00000000..07cdde5b --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -0,0 +1,568 @@ +#include "legoutils.h" + +#include "3dmanager/lego3dmanager.h" +#include "act1state.h" +#include "anim/legoanim.h" +#include "islepathactor.h" +#include "legoanimpresenter.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "legonamedtexture.h" +#include "legosoundmanager.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "legoworldlist.h" +#include "misc.h" +#include "misc/legotree.h" +#include "mxdsaction.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstreamer.h" +#include "mxtypes.h" +#include "mxutilities.h" +#include "mxvariabletable.h" +#include "realtime/realtime.h" +#include "scripts.h" + +#include +#include +#include + +// FUNCTION: LEGO1 0x1003dd70 +LegoROI* PickROI(MxLong p_a, MxLong p_b) +{ + return (LegoROI*) VideoManager()->Get3DManager()->GetLego3DView()->Pick(p_a, p_b); +} + +// STUB: LEGO1 0x1003ddc0 +LegoEntity* PickEntity(MxLong, MxLong) +{ + // TODO + return NULL; +} + +// FUNCTION: LEGO1 0x1003df90 +MxS16 CountTotalTreeNodes(LegoTreeNode* p_node) +{ + MxS16 result = 1; + + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + result += CountTotalTreeNodes(p_node->GetChild(i)); + } + + return result; +} + +// FUNCTION: LEGO1 0x1003dfd0 +LegoTreeNode* GetTreeNode(LegoTreeNode* p_node, MxU32 p_index) +{ + LegoTreeNode* result = NULL; + + if (p_index == 0) { + result = p_node; + } + else { + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + MxS16 count = CountTotalTreeNodes(p_node->GetChild(i)); + if (p_index > count) { + p_index -= count; + } + else { + result = GetTreeNode(p_node->GetChild(i), p_index - 1); + break; + } + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1003e050 +void FUN_1003e050(LegoAnimPresenter* p_presenter) +{ + MxMatrix viewMatrix; + LegoTreeNode* rootNode = p_presenter->GetAnimation()->GetRoot(); + LegoAnimNodeData* camData = NULL; + LegoAnimNodeData* targetData = NULL; + MxS16 nodesCount = CountTotalTreeNodes(rootNode); + + MxFloat cam; + for (MxS16 i = 0; i < nodesCount; i++) { + if (camData && targetData) { + break; + } + + LegoAnimNodeData* data = (LegoAnimNodeData*) GetTreeNode(rootNode, i)->GetData(); + + if (!strnicmp(data->GetName(), "CAM", strlen("CAM"))) { + camData = data; + cam = atof(&data->GetName()[strlen(data->GetName()) - 2]); + } + else if (!strcmpi(data->GetName(), "TARGET")) { + targetData = data; + } + } + + MxMatrix matrixCam; + MxMatrix matrixTarget; + matrixCam.SetIdentity(); + matrixTarget.SetIdentity(); + + camData->CreateLocalTransform(0.0f, matrixCam); + targetData->CreateLocalTransform(0.0f, matrixTarget); + + Mx3DPointFloat dir; + dir[0] = matrixTarget[3][0] - matrixCam[3][0]; + dir[1] = matrixTarget[3][1] - matrixCam[3][1]; + dir[2] = matrixTarget[3][2] - matrixCam[3][2]; + dir.Unitize(); + + CalcLocalTransform(matrixCam[3], dir, matrixCam[1], viewMatrix); + + LegoVideoManager* video = VideoManager(); + LegoROI* roi = video->GetViewROI(); + Lego3DView* view = video->Get3DManager()->GetLego3DView(); + + roi->WrappedSetLocalTransform(viewMatrix); + view->Moved(*roi); + FUN_1003eda0(); + video->Get3DManager()->SetFrustrum(cam, 0.1, 250.0); +} + +// FUNCTION: LEGO1 0x1003e300 +Extra::ActionType MatchActionString(const char* p_str) +{ + Extra::ActionType result = Extra::ActionType::e_unknown; + + if (!strcmpi("openram", p_str)) { + result = Extra::ActionType::e_openram; + } + else if (!strcmpi("opendisk", p_str)) { + result = Extra::ActionType::e_opendisk; + } + else if (!strcmpi("close", p_str)) { + result = Extra::ActionType::e_close; + } + else if (!strcmpi("start", p_str)) { + result = Extra::ActionType::e_start; + } + else if (!strcmpi("stop", p_str)) { + result = Extra::ActionType::e_stop; + } + else if (!strcmpi("run", p_str)) { + result = Extra::ActionType::e_run; + } + else if (!strcmpi("exit", p_str)) { + result = Extra::ActionType::e_exit; + } + else if (!strcmpi("enable", p_str)) { + result = Extra::ActionType::e_enable; + } + else if (!strcmpi("disable", p_str)) { + result = Extra::ActionType::e_disable; + } + else if (!strcmpi("notify", p_str)) { + result = Extra::ActionType::e_notify; + } + + return result; +} + +MxBool CheckIfEntityExists(MxBool p_enable, const char* p_filename, MxS32 p_entityId); +void NotifyEntity(const char* p_filename, MxS32 p_entityId, LegoEntity* p_sender); + +// FUNCTION: LEGO1 0x1003e430 +void InvokeAction(Extra::ActionType p_actionId, const MxAtomId& p_pAtom, MxS32 p_targetEntityId, LegoEntity* p_sender) +{ + MxDSAction action; + action.SetAtomId(p_pAtom); + action.SetObjectId(p_targetEntityId); + + switch (p_actionId) { + case Extra::ActionType::e_opendisk: + if (!CheckIfEntityExists(TRUE, p_pAtom.GetInternal(), p_targetEntityId)) { + Streamer()->Open(p_pAtom.GetInternal(), MxStreamer::e_diskStream); + Start(&action); + } + break; + case Extra::ActionType::e_openram: + if (!CheckIfEntityExists(TRUE, p_pAtom.GetInternal(), p_targetEntityId)) { + Streamer()->Open(p_pAtom.GetInternal(), MxStreamer::e_RAMStream); + Start(&action); + } + break; + case Extra::ActionType::e_close: + action.SetUnknown24(-2); + DeleteObject(action); + Streamer()->Close(p_pAtom.GetInternal()); + break; + case Extra::ActionType::e_start: + if (!CheckIfEntityExists(TRUE, p_pAtom.GetInternal(), p_targetEntityId)) { + Start(&action); + } + break; + case Extra::ActionType::e_stop: + action.SetUnknown24(-2); + if (!RemoveFromCurrentWorld(p_pAtom, p_targetEntityId)) { + DeleteObject(action); + } + break; + case Extra::ActionType::e_run: + _spawnl(0, "\\lego\\sources\\main\\main.exe", "\\lego\\sources\\main\\main.exe", "/script", &p_pAtom, 0); + break; + case Extra::ActionType::e_exit: + Lego()->SetExit(TRUE); + break; + case Extra::ActionType::e_enable: + CheckIfEntityExists(TRUE, p_pAtom.GetInternal(), p_targetEntityId); + break; + case Extra::ActionType::e_disable: + CheckIfEntityExists(FALSE, p_pAtom.GetInternal(), p_targetEntityId); + break; + case Extra::ActionType::e_notify: + NotifyEntity(p_pAtom.GetInternal(), p_targetEntityId, p_sender); + break; + } +} + +// FUNCTION: LEGO1 0x1003e670 +MxBool CheckIfEntityExists(MxBool p_enable, const char* p_filename, MxS32 p_entityId) +{ + LegoWorld* world = FindWorld(MxAtomId(p_filename, e_lowerCase2), p_entityId); + + if (world) { + world->Enable(p_enable); + return TRUE; + } + else { + return FALSE; + } +} + +// FUNCTION: LEGO1 0x1003e700 +void NotifyEntity(const char* p_filename, MxS32 p_entityId, LegoEntity* p_sender) +{ + MxAtomId atom(p_filename, e_lowerCase2); + LegoEntity* entity = FindWorld(atom, p_entityId); + + if (entity == NULL) { + LegoWorldListCursor cursor(Lego()->GetWorldList()); + LegoWorld* world; + + while (cursor.Next(world)) { + entity = (LegoEntity*) world->Find(atom, p_entityId); + + if (entity != NULL) { + break; + } + } + } + + if (entity != NULL) { + NotificationManager()->Send(entity, MxNotificationParam(c_notificationType0, p_sender)); + } +} + +// FUNCTION: LEGO1 0x1003eab0 +void SetCameraControllerFromIsle() +{ + InputManager()->SetCamera(FindWorld(*g_isleScript, 0)->GetCamera()); +} + +// FUNCTION: LEGO1 0x1003eae0 +void ConvertHSVToRGB(float p_h, float p_s, float p_v, float* p_rOut, float* p_bOut, float* p_gOut) +{ + double calc; + double p; + MxLong hueIndex; + double v9; + double v12; + double v13; + + double sDbl = p_s; + + if (p_s > 0.5f) { + calc = (1.0f - p_v) * p_s + p_v; + } + else { + calc = (p_v + 1.0) * sDbl; + } + if (calc <= 0.0) { + *p_gOut = 0.0f; + *p_bOut = 0.0f; + *p_rOut = 0.0f; + return; + } + p = p_s * 2.0f - calc; + hueIndex = p_h * 6.0; + v9 = (p_h * 6.0 - (float) hueIndex) * ((calc - p) / calc) * calc; + v12 = p + v9; + v13 = calc - v9; + switch (hueIndex) { + case 0: + *p_rOut = calc; + *p_bOut = v12; + *p_gOut = p; + break; + case 1: + *p_rOut = v13; + *p_bOut = calc; + *p_gOut = p; + break; + case 2: + *p_rOut = p; + *p_bOut = calc; + *p_gOut = v12; + break; + case 3: + *p_rOut = p; + *p_bOut = v13; + *p_gOut = calc; + break; + case 4: + *p_rOut = v12; + *p_bOut = p; + *p_gOut = calc; + break; + case 5: + *p_rOut = calc; + *p_bOut = p; + *p_gOut = v13; + break; + case 6: + *p_rOut = calc; + *p_bOut = p; + *p_gOut = v13; + break; + default: + return; + } +} + +// STUB: LEGO1 0x1003ecc0 +// FUNCTION: BETA10 0x100d4b38 +void FUN_1003ecc0(IslePathActor* p_actor, undefined4, undefined4, MxBool) +{ + // TODO +} + +// FUNCTION: LEGO1 0x1003eda0 +// FUNCTION: BETA10 0x100d4bf4 +void FUN_1003eda0() +{ + Mx3DPointFloat vec; + vec.Clear(); + + LegoROI* viewROI = VideoManager()->GetViewROI(); + if (viewROI) { + viewROI->FUN_100a5a30(vec); + SoundManager()->FUN_1002a410( + viewROI->GetWorldPosition(), + viewROI->GetWorldDirection(), + viewROI->GetWorldUp(), + viewROI->GetWorldVelocity() + ); + } +} + +// FUNCTION: LEGO1 0x1003ee00 +MxBool RemoveFromCurrentWorld(const MxAtomId& p_atomId, MxS32 p_id) +{ + LegoWorld* world = CurrentWorld(); + + if (world) { + MxCore* object = world->Find(p_atomId, p_id); + + if (object) { + world->Remove(object); + + if (!object->IsA("MxPresenter")) { + delete object; + } + else { + if (((MxPresenter*) object)->GetAction()) { + FUN_100b7220(((MxPresenter*) object)->GetAction(), MxDSAction::c_world, FALSE); + } + + ((MxPresenter*) object)->EndAction(); + } + + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x1003ee80 +MxBool RemoveFromWorld(MxAtomId& p_entityAtom, MxS32 p_entityId, MxAtomId& p_worldAtom, MxS32 p_worldEntityId) +{ + LegoWorld* world = FindWorld(p_worldAtom, p_worldEntityId); + + if (world) { + MxCore* object = world->Find(p_entityAtom, p_entityId); + + if (object) { + world->Remove(object); + + if (!object->IsA("MxPresenter")) { + delete object; + } + else { + if (((MxPresenter*) object)->GetAction()) { + FUN_100b7220(((MxPresenter*) object)->GetAction(), MxDSAction::c_world, FALSE); + } + + ((MxPresenter*) object)->EndAction(); + } + + return TRUE; + } + } + + return FALSE; +} + +// STUB: LEGO1 0x1003ef00 +void FUN_1003ef00(MxBool) +{ + // TODO (something related to animation manager) +} + +// FUNCTION: LEGO1 0x1003ef40 +void SetAppCursor(WPARAM p_wparam) +{ + PostMessageA(MxOmni::GetInstance()->GetWindowHandle(), 0x5400, p_wparam, 0); +} + +// FUNCTION: LEGO1 0x1003ef60 +MxBool FUN_1003ef60() +{ + Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); + + if (GameState()->m_currentArea != LegoGameState::e_elevride && + GameState()->m_currentArea != LegoGameState::e_elevride2 && + GameState()->m_currentArea != LegoGameState::e_elevopen && + GameState()->m_currentArea != LegoGameState::e_seaview && + GameState()->m_currentArea != LegoGameState::e_observe && + GameState()->m_currentArea != LegoGameState::e_elevdown && + GameState()->m_currentArea != LegoGameState::e_garadoor && + GameState()->m_currentArea != LegoGameState::e_polidoor) { + + if (CurrentActor() == NULL || !CurrentActor()->IsA("TowTrack")) { + if (CurrentActor() == NULL || !CurrentActor()->IsA("Ambulance")) { + MxU32 unk0x18 = act1State->GetUnknown18(); + + if (unk0x18 != 10 && unk0x18 != 8 && unk0x18 != 3) { + return TRUE; + } + } + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x1003f050 +MxS32 UpdateLightPosition(MxS32 p_increase) +{ + MxS32 lightPosition = atoi(VariableTable()->GetVariable("lightposition")); + + // Only ever increases by 1 irrespective of p_increase + if (p_increase > 0) { + lightPosition += 1; + if (lightPosition > 5) { + lightPosition = 5; + } + } + else { + lightPosition -= 1; + if (lightPosition < 0) { + lightPosition = 0; + } + } + + SetLightPosition(lightPosition); + + char lightPositionBuffer[32]; + sprintf(lightPositionBuffer, "%d", lightPosition); + + VariableTable()->SetVariable("lightposition", lightPositionBuffer); + + return lightPosition; +} + +// FUNCTION: LEGO1 0x1003f0d0 +void SetLightPosition(MxS32 p_index) +{ + float lights[6][6] = { + {1.0, 0.0, 0.0, -150.0, 50.0, -50.0}, + {0.809, -0.588, 0.0, -75.0, 50.0, -50.0}, + {0.0, -1.0, 0.0, 0.0, 150.0, -150.0}, + {-0.309, -0.951, 0.0, 25.0, 50.0, -50.0}, + {-0.809, -0.588, 0.0, 75.0, 50.0, -50.0}, + {-1.0, 0.0, 0.0, 150.0, 50.0, -50.0} + }; + + Mx3DPointFloat up(1.0, 0.0, 0.0); + Mx3DPointFloat direction; + Mx3DPointFloat position; + + Tgl::FloatMatrix4 matrix; + Matrix4 in(matrix); + MxMatrix transform; + + if (p_index < 0) { + p_index = 0; + } + else if (p_index > 5) { + p_index = 5; + } + + direction = lights[p_index]; + position = &lights[p_index][3]; + + CalcLocalTransform(position, direction, up, transform); + SETMAT4(in, transform); + + VideoManager()->Get3DManager()->GetLego3DView()->SetLightTransform(FALSE, matrix); + VideoManager()->Get3DManager()->GetLego3DView()->SetLightTransform(TRUE, matrix); +} + +// FUNCTION: LEGO1 0x1003f3b0 +LegoNamedTexture* ReadNamedTexture(LegoFile* p_file) +{ + LegoTexture* texture = NULL; + LegoNamedTexture* namedTexture = NULL; + MxString string; + + p_file->ReadString(string); + + texture = new LegoTexture(); + if (texture != NULL) { + if (texture->Read(p_file, 0) != SUCCESS) { + delete texture; + return namedTexture; + } + + namedTexture = new LegoNamedTexture(string.GetData(), texture); + if (namedTexture == NULL) { + delete texture; + } + } + + return namedTexture; +} + +// STUB: LEGO1 0x1003f540 +void FUN_1003f540(LegoFile* p_file, const char* p_filename) +{ +} + +// FUNCTION: LEGO1 0x1003f8a0 +void WriteNamedTexture(LegoFile* p_file, LegoNamedTexture* p_texture) +{ + p_file->WriteString(*p_texture->GetName()); + p_texture->GetTexture()->Write(p_file); +} diff --git a/LEGO1/lego/legoomni/src/common/legovariables.cpp b/LEGO1/lego/legoomni/src/common/legovariables.cpp new file mode 100644 index 00000000..7dc427b8 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/legovariables.cpp @@ -0,0 +1,160 @@ +#include "legovariables.h" + +#include "3dmanager/lego3dmanager.h" +#include "legobuildingmanager.h" +#include "legocharactermanager.h" +#include "legogamestate.h" +#include "legonavcontroller.h" +#include "legoplantmanager.h" +#include "legovideomanager.h" +#include "misc.h" +#include "roi/legoroi.h" + +DECOMP_SIZE_ASSERT(VisibilityVariable, 0x24) +DECOMP_SIZE_ASSERT(CameraLocationVariable, 0x24) +DECOMP_SIZE_ASSERT(CursorVariable, 0x24) +DECOMP_SIZE_ASSERT(WhoAmIVariable, 0x24) +DECOMP_SIZE_ASSERT(CustomizeAnimFileVariable, 0x24) + +// GLOBAL: LEGO1 0x100f39bc +// STRING: LEGO1 0x100f39a0 +const char* g_varAMBULFUEL = "ambulFUEL"; + +// GLOBAL: LEGO1 0x100f3a40 +// STRING: LEGO1 0x100f3808 +const char* g_varVISIBILITY = "VISIBILITY"; + +// GLOBAL: LEGO1 0x100f3a44 +// STRING: LEGO1 0x100f3a30 +const char* g_varCAMERALOCATION = "CAMERA_LOCATION"; + +// GLOBAL: LEGO1 0x100f3a48 +// STRING: LEGO1 0x100f3a28 +const char* g_varCURSOR = "CURSOR"; + +// GLOBAL: LEGO1 0x100f3a4c +// STRING: LEGO1 0x100f3a1c +const char* g_varWHOAMI = "WHO_AM_I"; + +// GLOBAL: LEGO1 0x100f3a50 +// STRING: LEGO1 0x100f3a18 +const char* g_delimiter2 = " \t"; + +// GLOBAL: LEGO1 0x100f3a54 +// STRING: LEGO1 0x100f3a10 +const char* g_varHIDE = "HIDE"; + +// GLOBAL: LEGO1 0x100f3a58 +// STRING: LEGO1 0x100f3a08 +const char* g_varSHOW = "SHOW"; + +// GLOBAL: LEGO1 0x100f3a5c +// STRING: LEGO1 0x100f3a00 +const char* g_papa = "Papa"; + +// GLOBAL: LEGO1 0x100f3a60 +// STRING: LEGO1 0x100f39f8 +const char* g_mama = "Mama"; + +// GLOBAL: LEGO1 0x100f3a64 +// STRING: LEGO1 0x100f39f0 +const char* g_pepper = "Pepper"; + +// GLOBAL: LEGO1 0x100f3a68 +// STRING: LEGO1 0x100f39e8 +const char* g_nick = "Nick"; + +// GLOBAL: LEGO1 0x100f3a6c +// STRING: LEGO1 0x100f39e0 +const char* g_laura = "Laura"; + +// FUNCTION: LEGO1 0x10037d00 +// FUNCTION: BETA10 0x100d5620 +void VisibilityVariable::SetValue(const char* p_value) +{ + MxVariable::SetValue(p_value); + + if (p_value) { + char* instruction = strtok(m_value.GetData(), g_delimiter2); + char* name = strtok(NULL, g_delimiter2); + MxBool show; + + if (!strcmpi(instruction, g_varHIDE)) { + show = FALSE; + } + else if (!strcmpi(instruction, g_varSHOW)) { + show = TRUE; + } + else { + return; + } + + LegoROI* roi = FindROI(name); + if (roi) { + roi->SetVisibility(show); + } + } +} + +// FUNCTION: LEGO1 0x10037d80 +void CameraLocationVariable::SetValue(const char* p_value) +{ + char buffer[256]; + MxVariable::SetValue(p_value); + + strcpy(buffer, p_value); + + char* location = strtok(buffer, ","); + NavController()->UpdateLocation(location); + + location = strtok(NULL, ","); + if (location) { + MxFloat pov = (MxFloat) atof(location); + VideoManager()->Get3DManager()->SetFrustrum(pov, 0.1f, 250.0f); + } +} + +// FUNCTION: LEGO1 0x10037e30 +void CursorVariable::SetValue(const char* p_value) +{ +} + +// FUNCTION: LEGO1 0x10037e40 +void WhoAmIVariable::SetValue(const char* p_value) +{ + MxVariable::SetValue(p_value); + + if (!strcmpi(p_value, g_papa)) { + GameState()->SetActorId(3); + } + else if (!strcmpi(p_value, g_mama)) { + GameState()->SetActorId(2); + } + else if (!strcmpi(p_value, g_pepper)) { + GameState()->SetActorId(1); + } + else if (!strcmpi(p_value, g_nick)) { + GameState()->SetActorId(4); + } + else if (!strcmpi(p_value, g_laura)) { + GameState()->SetActorId(5); + } +} + +// FUNCTION: LEGO1 0x10085aa0 +CustomizeAnimFileVariable::CustomizeAnimFileVariable(const char* p_key) +{ + m_key = p_key; + m_key.ToUpperCase(); +} + +// FUNCTION: LEGO1 0x10085b50 +void CustomizeAnimFileVariable::SetValue(const char* p_value) +{ + // STRING: LEGO1 0x100fc4f4 + if (strcmp(m_key.GetData(), "CUSTOMIZE_ANIM_FILE") == 0) { + CharacterManager()->SetCustomizeAnimFile(p_value); + PlantManager()->SetCustomizeAnimFile(p_value); + BuildingManager()->SetCustomizeAnimFile(p_value); + } +} diff --git a/LEGO1/lego/legoomni/src/common/misc.cpp b/LEGO1/lego/legoomni/src/common/misc.cpp new file mode 100644 index 00000000..bf77f5e8 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/misc.cpp @@ -0,0 +1,213 @@ +#include "misc.h" + +#include "3dmanager/lego3dmanager.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "legovideomanager.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "roi/legoroi.h" +#include "scripts.h" + +// GLOBAL: LEGO1 0x100f4c58 +MxBool g_isWorldActive = TRUE; + +// FUNCTION: LEGO1 0x10015700 +LegoOmni* Lego() +{ + return LegoOmni::GetInstance(); +} + +// FUNCTION: LEGO1 0x10015710 +LegoSoundManager* SoundManager() +{ + return LegoOmni::GetInstance()->GetSoundManager(); +} + +// FUNCTION: LEGO1 0x10015720 +LegoVideoManager* VideoManager() +{ + return LegoOmni::GetInstance()->GetVideoManager(); +} + +// FUNCTION: LEGO1 0x10015730 +MxBackgroundAudioManager* BackgroundAudioManager() +{ + return LegoOmni::GetInstance()->GetBackgroundAudioManager(); +} + +// FUNCTION: LEGO1 0x10015740 +LegoInputManager* InputManager() +{ + return LegoOmni::GetInstance()->GetInputManager(); +} + +// FUNCTION: LEGO1 0x10015750 +LegoControlManager* ControlManager() +{ + return LegoOmni::GetInstance()->GetInputManager()->GetControlManager(); +} + +// FUNCTION: LEGO1 0x10015760 +LegoGameState* GameState() +{ + return LegoOmni::GetInstance()->GetGameState(); +} + +// FUNCTION: LEGO1 0x10015770 +LegoAnimationManager* AnimationManager() +{ + return LegoOmni::GetInstance()->GetAnimationManager(); +} + +// FUNCTION: LEGO1 0x10015780 +LegoNavController* NavController() +{ + return LegoOmni::GetInstance()->GetNavController(); +} + +// FUNCTION: LEGO1 0x10015790 +IslePathActor* CurrentActor() +{ + return LegoOmni::GetInstance()->GetCurrentActor(); +} + +// FUNCTION: LEGO1 0x100157a0 +LegoWorld* CurrentWorld() +{ + return LegoOmni::GetInstance()->GetCurrentWorld(); +} + +// FUNCTION: LEGO1 0x100157b0 +LegoCharacterManager* CharacterManager() +{ + return LegoOmni::GetInstance()->GetCharacterManager(); +} + +// FUNCTION: LEGO1 0x100157c0 +ViewManager* GetViewManager() +{ + return VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager(); +} + +// FUNCTION: LEGO1 0x100157e0 +LegoPlantManager* PlantManager() +{ + return LegoOmni::GetInstance()->GetLegoPlantManager(); +} + +// FUNCTION: LEGO1 0x100157f0 +LegoBuildingManager* BuildingManager() +{ + return LegoOmni::GetInstance()->GetLegoBuildingManager(); +} + +// FUNCTION: LEGO1 0x10015800 +LegoTextureContainer* TextureContainer() +{ + return LegoOmni::GetInstance()->GetTextureContainer(); +} + +// FUNCTION: LEGO1 0x10015810 +ViewLODListManager* GetViewLODListManager() +{ + return LegoOmni::GetInstance()->GetViewLODListManager(); +} + +// FUNCTION: LEGO1 0x10015820 +void FUN_10015820(MxBool p_disable, MxU16 p_flags) +{ + LegoOmni::GetInstance()->FUN_1005b4f0(p_disable, p_flags); +} + +// FUNCTION: LEGO1 0x10015840 +LegoROI* FindROI(const char* p_name) +{ + return LegoOmni::GetInstance()->FindROI(p_name); +} + +// FUNCTION: LEGO1 0x10015860 +void SetROIVisible(const char* p_name, MxBool p_visible) +{ + LegoROI* roi = FindROI(p_name); + + if (roi) { + roi->SetVisibility(p_visible); + } +} + +// FUNCTION: LEGO1 0x10015880 +void SetCurrentActor(IslePathActor* p_currentActor) +{ + LegoOmni::GetInstance()->SetCurrentActor(p_currentActor); +} + +// FUNCTION: LEGO1 0x10015890 +// FUNCTION: BETA10 0x100e4d80 +MxResult StartActionIfUnknown0x13c(MxDSAction& p_dsAction) +{ + return LegoOmni::GetInstance()->StartActionIfUnknown0x13c(p_dsAction); +} + +// FUNCTION: LEGO1 0x100158b0 +void DeleteAction() +{ + LegoOmni::GetInstance()->DeleteAction(); +} + +// FUNCTION: LEGO1 0x100158c0 +LegoWorld* FindWorld(const MxAtomId& p_atom, MxS32 p_entityid) +{ + return LegoOmni::GetInstance()->FindWorld(p_atom, p_entityid); +} + +// FUNCTION: LEGO1 0x100158e0 +MxDSAction& GetCurrentAction() +{ + return LegoOmni::GetInstance()->GetCurrentAction(); +} + +// FUNCTION: LEGO1 0x100158f0 +void SetCurrentWorld(LegoWorld* p_world) +{ + LegoOmni::GetInstance()->SetCurrentWorld(p_world); +} + +// FUNCTION: LEGO1 0x10015900 +MxTransitionManager* TransitionManager() +{ + return LegoOmni::GetInstance()->GetTransitionManager(); +} + +// FUNCTION: LEGO1 0x10015910 +void PlayMusic(JukeboxScript::Script p_script) +{ + MxDSAction action; + action.SetAtomId(*g_jukeboxScript); + action.SetObjectId(p_script); + + LegoOmni::GetInstance()->GetBackgroundAudioManager()->PlayMusic(action, 5, 4); +} + +// FUNCTION: LEGO1 0x100159c0 +void SetIsWorldActive(MxBool p_isWorldActive) +{ + if (!p_isWorldActive) { + LegoOmni::GetInstance()->GetInputManager()->SetCamera(NULL); + } + g_isWorldActive = p_isWorldActive; +} + +// FUNCTION: LEGO1 0x100159e0 +void DeleteObjects(MxAtomId* p_id, MxS32 p_first, MxS32 p_last) +{ + MxDSAction action; + + action.SetAtomId(*p_id); + action.SetUnknown24(-2); + + for (MxS32 first = p_first, last = p_last; first <= last; first++) { + action.SetObjectId(first); + DeleteObject(action); + } +} diff --git a/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp b/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp new file mode 100644 index 00000000..36027f8e --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/mxcompositemediapresenter.cpp @@ -0,0 +1,181 @@ +#include "mxcompositemediapresenter.h" + +#include "legosoundmanager.h" +#include "legovideomanager.h" +#include "misc.h" +#include "mxautolock.h" +#include "mxdsmultiaction.h" +#include "mxmediapresenter.h" +#include "mxmisc.h" +#include "mxobjectfactory.h" +#include "mxtimer.h" + +DECOMP_SIZE_ASSERT(MxCompositeMediaPresenter, 0x50) + +// FUNCTION: LEGO1 0x10073ea0 +MxCompositeMediaPresenter::MxCompositeMediaPresenter() +{ + m_unk0x4c = 0; + m_unk0x4e = FALSE; + VideoManager()->RegisterPresenter(*this); +} + +// FUNCTION: LEGO1 0x10074020 +MxCompositeMediaPresenter::~MxCompositeMediaPresenter() +{ + VideoManager()->UnregisterPresenter(*this); +} + +// FUNCTION: LEGO1 0x10074090 +MxResult MxCompositeMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + + MxResult result = FAILURE; + MxDSActionList* actions = ((MxDSMultiAction*) p_action)->GetActionList(); + MxDSActionListCursor cursor(actions); + MxDSAction* action; + + if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) { + cursor.Head(); + + while (cursor.Current(action)) { + MxBool success = FALSE; + const char* presenterName; + MxPresenter* presenter = NULL; + + cursor.Next(); + + if (m_action->GetFlags() & MxDSAction::c_looping) { + action->SetFlags(action->GetFlags() | MxDSAction::c_looping); + } + else if (m_action->GetFlags() & MxDSAction::c_bit3) { + action->SetFlags(action->GetFlags() | MxDSAction::c_bit3); + } + + presenterName = PresenterNameDispatch(*action); + presenter = (MxPresenter*) ObjectFactory()->Create(presenterName); + + if (presenter && presenter->AddToManager() == SUCCESS) { + presenter->SetCompositePresenter(this); + if (presenter->StartAction(p_controller, action) == SUCCESS) { + presenter->SetTickleState(e_idle); + + if (presenter->IsA("MxVideoPresenter")) { + VideoManager()->UnregisterPresenter(*presenter); + } + else if (presenter->IsA("MxAudioPresenter")) { + SoundManager()->UnregisterPresenter(*presenter); + } + + success = TRUE; + } + } + + if (success) { + action->SetOrigin(this); + m_list.push_back(presenter); + } + else if (presenter) { + delete presenter; + } + } + + if (!m_compositePresenter) { + SetTickleState(e_ready); + MxLong time = Timer()->GetTime(); + m_action->SetUnknown90(time); + } + + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x100742e0 +void MxCompositeMediaPresenter::StartingTickle() +{ + AUTOLOCK(m_criticalSection); + + if (!m_unk0x4e) { + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + if ((*it)->GetCurrentTickleState() < e_streaming) { + (*it)->Tickle(); + + if ((*it)->GetCurrentTickleState() == e_streaming || + ((*it)->GetAction() && (*it)->GetAction()->GetStartTime())) { + m_unk0x4c++; + } + } + } + + if (m_list.size() == m_unk0x4c) { + m_unk0x4e = TRUE; + m_unk0x4c = 0; + + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + if (!(*it)->GetAction()->GetStartTime()) { + m_unk0x4c++; + } + } + } + } + else { + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + if (!(*it)->GetAction()->GetStartTime() && ((MxMediaPresenter*) *it)->CurrentChunk() && + !((*it)->GetAction()->GetFlags() & MxDSAction::c_bit9)) { + (*it)->Tickle(); + (*it)->GetAction()->SetFlags((*it)->GetAction()->GetFlags() | MxDSAction::c_bit9); + m_unk0x4c--; + } + } + + if (!m_unk0x4c) { + ProgressTickleState(e_streaming); + MxLong time = Timer()->GetTime(); + m_action->SetUnknown90(time); + } + } +} + +// FUNCTION: LEGO1 0x10074470 +MxResult MxCompositeMediaPresenter::Tickle() +{ + AUTOLOCK(m_criticalSection); + + switch (m_currentTickleState) { + case e_ready: + ProgressTickleState(e_starting); + case e_starting: + StartingTickle(); + break; + case e_streaming: + case e_repeating: + case e_freezing: + case e_done: { + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + (*it)->Tickle(); + } + break; + } + default: + break; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10074540 +MxResult MxCompositeMediaPresenter::PutData() +{ + AUTOLOCK(m_criticalSection); + + if (m_currentTickleState >= e_streaming && m_currentTickleState <= e_done) { + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + (*it)->PutData(); + } + } + + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp b/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp new file mode 100644 index 00000000..5c2eec3d --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/mxcontrolpresenter.cpp @@ -0,0 +1,321 @@ +#include "mxcontrolpresenter.h" + +#include "define.h" +#include "legocontrolmanager.h" +#include "mxdsmultiaction.h" +#include "mxmisc.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "mxutilities.h" +#include "mxvideopresenter.h" + +DECOMP_SIZE_ASSERT(MxControlPresenter, 0x5c) + +// FUNCTION: LEGO1 0x10043f50 +MxControlPresenter::MxControlPresenter() +{ + this->m_unk0x4c = 0; + this->m_unk0x4e = -1; + this->m_unk0x50 = FALSE; + this->m_unk0x52 = 0; + this->m_unk0x58 = 0; + this->m_unk0x54 = 0; +} + +// FUNCTION: LEGO1 0x10043fd0 +void MxControlPresenter::RepeatingTickle() +{ + // empty +} + +// FUNCTION: LEGO1 0x10043fe0 +MxBool MxControlPresenter::VTable0x64(undefined4 p_undefined) +{ + return m_unk0x50; +} + +// FUNCTION: LEGO1 0x10043ff0 +void MxControlPresenter::VTable0x68(MxBool p_unk0x50) +{ + m_unk0x50 = p_unk0x50; +} + +// FUNCTION: LEGO1 0x10044110 +MxControlPresenter::~MxControlPresenter() +{ + if (m_unk0x58) { + delete m_unk0x58; + } +} + +// FUNCTION: LEGO1 0x10044180 +MxResult MxControlPresenter::AddToManager() +{ + m_unk0x4e = 0; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10044190 +MxResult MxControlPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) +{ + MxResult result = MxCompositePresenter::StartAction(p_controller, p_action); + + FUN_100b7220(m_action, MxDSAction::c_world | MxDSAction::c_looping, TRUE); + ParseExtra(); + + MxS16 i = 0; + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + (*it)->Enable((m_unk0x4c != 3 || m_unk0x4e) && IsEnabled() ? m_unk0x4e == i : FALSE); + i++; + } + + if (m_unk0x4c == 3) { + MxDSAction* action = (*m_list.begin())->GetAction(); + action->SetFlags(action->GetFlags() | MxDSAction::c_bit11); + } + + TickleManager()->RegisterClient(this, 200); + + return result; +} + +// FUNCTION: LEGO1 0x10044260 +void MxControlPresenter::EndAction() +{ + if (m_action) { + m_unk0x50 = TRUE; + MxCompositePresenter::EndAction(); + } +} + +// FUNCTION: LEGO1 0x10044270 +MxBool MxControlPresenter::FUN_10044270(MxS32 p_x, MxS32 p_y, MxVideoPresenter* p_presenter) +{ + if (m_unk0x4c == 3) { + MxVideoPresenter* frontPresenter = (MxVideoPresenter*) m_list.front(); + + if (p_presenter == frontPresenter || frontPresenter->GetDisplayZ() < p_presenter->GetDisplayZ()) { + if (p_presenter->VTable0x7c()) { + MxS32 height = frontPresenter->GetHeight(); + MxS32 width = frontPresenter->GetWidth(); + + if (frontPresenter->GetLocation().GetX() <= p_x && + p_x < width - 1 + frontPresenter->GetLocation().GetX() && + frontPresenter->GetLocation().GetY() <= p_y && + p_y < height - 1 + frontPresenter->GetLocation().GetY()) { + MxU8* start; + + if (frontPresenter->GetAlphaMask() == NULL) { + start = frontPresenter->GetBitmap()->GetStart( + p_x - frontPresenter->GetLocation().GetX(), + p_y - frontPresenter->GetLocation().GetY() + ); + } + else { + start = NULL; + } + + m_unk0x56 = 0; + if (m_unk0x58 == NULL) { + if (*start != 0) { + m_unk0x56 = 1; + } + } + else { + for (MxS16 i = 1; i <= *m_unk0x58; i++) { + if (m_unk0x58[i] == *start) { + m_unk0x56 = i; + break; + } + } + } + + if (m_unk0x56) { + return TRUE; + } + } + } + } + } + else { + if (ContainsPresenter(m_list, p_presenter)) { + if (m_unk0x4c == 2) { + MxS32 width = p_presenter->GetWidth(); + MxS32 height = p_presenter->GetHeight(); + + if (m_unk0x52 == 2 && m_unk0x54 == 2) { + MxS16 val; + if (p_x < p_presenter->GetLocation().GetX() + width / 2) { + val = 3; + if (p_y < p_presenter->GetLocation().GetY() + height / 2) { + val = 1; + } + m_unk0x56 = val; + return TRUE; + } + + val = 4; + if (p_y < p_presenter->GetLocation().GetY() + height / 2) { + val = 2; + } + + m_unk0x56 = val; + return TRUE; + } + } + else { + m_unk0x56 = -1; + } + + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10044480 +MxBool MxControlPresenter::FUN_10044480(LegoControlManagerEvent* p_event, MxPresenter* p_presenter) +{ + if (IsEnabled()) { + switch (p_event->GetType()) { + case c_notificationButtonUp: + if (m_unk0x4c == 0 || m_unk0x4c == 2 || m_unk0x4c == 3) { + p_event->SetClickedObjectId(m_action->GetObjectId()); + p_event->SetClickedAtom(m_action->GetAtomId().GetInternal()); + VTable0x6c(0); + p_event->SetType(c_notificationClick); + p_event->SetUnknown0x28(m_unk0x4e); + return TRUE; + } + break; + case c_notificationButtonDown: + if (FUN_10044270(p_event->GetX(), p_event->GetY(), (MxVideoPresenter*) p_presenter)) { + p_event->SetClickedObjectId(m_action->GetObjectId()); + p_event->SetClickedAtom(m_action->GetAtomId().GetInternal()); + VTable0x6c(m_unk0x56); + p_event->SetType(c_notificationClick); + p_event->SetUnknown0x28(m_unk0x4e); + return TRUE; + } + break; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10044540 +void MxControlPresenter::VTable0x6c(MxS16 p_val) +{ + if (p_val == -1) { + if ((MxS16) ((MxDSMultiAction*) m_action)->GetActionList()->GetCount() - m_unk0x4e == 1) { + m_unk0x4e = 0; + } + else { + m_unk0x4e++; + } + } + else { + m_unk0x4e = p_val; + } + + m_action->SetUnknown90(Timer()->GetTime()); + + MxS16 i = 0; + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + (*it)->Enable(((m_unk0x4c == 3 && m_unk0x4e == 0) || !IsEnabled()) ? FALSE : m_unk0x4e == i); + i++; + } +} + +// FUNCTION: LEGO1 0x10044610 +void MxControlPresenter::ReadyTickle() +{ + MxPresenter::ParseExtra(); + TickleManager()->UnregisterClient(this); + ProgressTickleState(e_repeating); +} + +// FUNCTION: LEGO1 0x10044640 +void MxControlPresenter::ParseExtra() +{ + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[256]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char output[256]; + if (KeyValueStringParse(output, g_strSTYLE, extraCopy)) { + char* str = strtok(output, g_parseExtraTokens); + + if (!strcmpi(str, g_strTOGGLE)) { + m_unk0x4c = 1; + } + else if (!strcmpi(str, g_strGRID)) { + m_unk0x4c = 2; + m_unk0x52 = atoi(strtok(NULL, g_parseExtraTokens)); + m_unk0x54 = atoi(strtok(NULL, g_parseExtraTokens)); + } + else if (!strcmpi(str, g_strMAP)) { + m_unk0x4c = 3; + str = strtok(NULL, g_parseExtraTokens); + + if (str) { + MxS16 count = atoi(str); + m_unk0x58 = new MxS16[count + 1]; + *m_unk0x58 = count; + + for (MxS16 i = 1; i <= count; i++) { + m_unk0x58[i] = atoi(strtok(NULL, g_parseExtraTokens)); + } + } + } + else { + m_unk0x4c = 0; + } + } + + if (KeyValueStringParse(output, g_strVISIBILITY, extraCopy)) { + if (!strcmpi(output, "FALSE")) { + Enable(FALSE); + } + } + } +} + +// FUNCTION: LEGO1 0x10044820 +void MxControlPresenter::Enable(MxBool p_enable) +{ + if (MxPresenter::IsEnabled() != p_enable) { + MxPresenter::Enable(p_enable); + + MxS16 i = 0; + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + if (i == m_unk0x4e) { + (*it)->Enable((m_unk0x4c != 3 || i != 0) ? p_enable : 0); + break; + } + + i++; + } + + if (!p_enable) { + m_unk0x4e = 0; + } + } +} + +// FUNCTION: LEGO1 0x100448a0 +MxBool MxControlPresenter::HasTickleStatePassed(TickleState p_tickleState) +{ + MxCompositePresenterList::iterator it = m_list.begin(); + for (MxS16 i = m_unk0x4e; i > 0; i--, it++) { + } + + return (*it)->HasTickleStatePassed(p_tickleState); +} diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp new file mode 100644 index 00000000..90a37ef2 --- /dev/null +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -0,0 +1,603 @@ +#include "mxtransitionmanager.h" + +#include "legoinputmanager.h" +#include "legoutils.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxbackgroundaudiomanager.h" +#include "mxdisplaysurface.h" +#include "mxmisc.h" +#include "mxparam.h" +#include "mxticklemanager.h" +#include "mxvideopresenter.h" + +DECOMP_SIZE_ASSERT(MxTransitionManager, 0x900) + +// GLOBAL: LEGO1 0x100f4378 +RECT g_fullScreenRect = {0, 0, 640, 480}; + +// FUNCTION: LEGO1 0x1004b8d0 +MxTransitionManager::MxTransitionManager() +{ + m_animationTimer = 0; + m_transitionType = e_notTransitioning; + m_ddSurface = NULL; + m_waitIndicator = NULL; + m_copyBuffer = NULL; + m_copyFlags.m_bit0 = FALSE; + m_unk0x28.m_bit0 = FALSE; + m_unk0x24 = 0; +} + +// FUNCTION: LEGO1 0x1004ba00 +MxTransitionManager::~MxTransitionManager() +{ + delete[] m_copyBuffer; + + if (m_waitIndicator != NULL) { + delete m_waitIndicator->GetAction(); + delete m_waitIndicator; + } + + TickleManager()->UnregisterClient(this); +} + +// FUNCTION: LEGO1 0x1004baa0 +MxResult MxTransitionManager::GetDDrawSurfaceFromVideoManager() // vtable+0x14 +{ + LegoVideoManager* videoManager = VideoManager(); + this->m_ddSurface = videoManager->GetDisplaySurface()->GetDirectDrawSurface2(); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1004bac0 +MxResult MxTransitionManager::Tickle() +{ + if (this->m_animationSpeed + this->m_systemTime > timeGetTime()) { + return SUCCESS; + } + + this->m_systemTime = timeGetTime(); + + switch (this->m_transitionType) { + case e_noAnimation: + NoTransition(); + break; + case e_dissolve: + DissolveTransition(); + break; + case e_mosaic: + MosaicTransition(); + break; + case e_wipeDown: + WipeDownTransition(); + break; + case e_windows: + WindowsTransition(); + break; + case e_broken: + BrokenTransition(); + break; + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1004bb70 +MxResult MxTransitionManager::StartTransition( + TransitionType p_animationType, + MxS32 p_speed, + MxBool p_doCopy, + MxBool p_playMusicInAnim +) +{ + if (this->m_transitionType == e_notTransitioning) { + if (!p_playMusicInAnim) { + MxBackgroundAudioManager* backgroundAudioManager = BackgroundAudioManager(); + backgroundAudioManager->Stop(); + } + + this->m_transitionType = p_animationType; + + m_copyFlags.m_bit0 = p_doCopy; + + if (m_copyFlags.m_bit0 && m_waitIndicator != NULL) { + m_waitIndicator->Enable(TRUE); + + MxDSAction* action = m_waitIndicator->GetAction(); + action->SetLoopCount(10000); + action->SetFlags(action->GetFlags() | MxDSAction::c_bit10); + } + + MxU32 time = timeGetTime(); + this->m_systemTime = time; + + this->m_animationSpeed = p_speed; + + MxTickleManager* tickleManager = TickleManager(); + tickleManager->RegisterClient(this, p_speed); + + LegoInputManager* inputManager = InputManager(); + inputManager->SetUnknown88(TRUE); + inputManager->SetUnknown336(FALSE); + + LegoVideoManager* videoManager = VideoManager(); + videoManager->SetRender3D(FALSE); + + SetAppCursor(1); + return SUCCESS; + } + return FAILURE; +} + +// FUNCTION: LEGO1 0x1004bc30 +void MxTransitionManager::EndTransition(MxBool p_notifyWorld) +{ + if (m_transitionType != e_notTransitioning) { + m_transitionType = e_notTransitioning; + + m_copyFlags.m_bit0 = FALSE; + + TickleManager()->UnregisterClient(this); + + if (p_notifyWorld) { + LegoWorld* world = CurrentWorld(); + + if (world) { +#ifdef COMPAT_MODE + { + MxNotificationParam param(c_notificationTransitioned, this); + world->Notify(param); + } +#else + world->Notify(MxNotificationParam(c_notificationTransitioned, this)); +#endif + } + } + } +} + +// FUNCTION: LEGO1 0x1004bcf0 +void MxTransitionManager::NoTransition() +{ + LegoVideoManager* videoManager = VideoManager(); + videoManager->GetDisplaySurface()->ClearScreen(); + EndTransition(TRUE); +} + +// FUNCTION: LEGO1 0x1004bd10 +void MxTransitionManager::DissolveTransition() +{ + // If the animation is finished + if (m_animationTimer == 40) { + m_animationTimer = 0; + EndTransition(TRUE); + return; + } + + // If we are starting the animation + if (m_animationTimer == 0) { + // Generate the list of columns in order... + MxS32 i; + for (i = 0; i < 640; i++) { + m_columnOrder[i] = i; + } + + // ...then shuffle the list (to ensure that we hit each column once) + for (i = 0; i < 640; i++) { + MxS32 swap = rand() % 640; + MxU16 t = m_columnOrder[i]; + m_columnOrder[i] = m_columnOrder[swap]; + m_columnOrder[swap] = t; + } + + // For each scanline, pick a random X offset + for (i = 0; i < 480; i++) { + m_randomShift[i] = rand() % 640; + } + } + + // Run one tick of the animation + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + if (res == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + + for (MxS32 col = 0; col < 640; col++) { + // Select 16 columns on each tick + if (m_animationTimer * 16 > m_columnOrder[col]) { + continue; + } + + if (m_animationTimer * 16 + 15 < m_columnOrder[col]) { + continue; + } + + for (MxS32 row = 0; row < 480; row++) { + // Shift the chosen column a different amount at each scanline. + // We use the same shift for that scanline each time. + // By the end, every pixel gets hit. + MxS32 xShift = (m_randomShift[row] + col) % 640; + + // Set the chosen pixel to black + if (ddsd.ddpfPixelFormat.dwRGBBitCount == 8) { + MxU8* surf = (MxU8*) ddsd.lpSurface + ddsd.lPitch * row + xShift; + *surf = 0; + } + else { + MxU8* surf = (MxU8*) ddsd.lpSurface + ddsd.lPitch * row + xShift * 2; + *(MxU16*) surf = 0; + } + } + } + + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + + if (VideoManager()->GetVideoParam().Flags().GetFlipSurfaces()) { + LPDIRECTDRAWSURFACE surf = VideoManager()->GetDisplaySurface()->GetDirectDrawSurface1(); + surf->BltFast(0, 0, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT); + } + + m_animationTimer++; + } +} + +// FUNCTION: LEGO1 0x1004bed0 +void MxTransitionManager::MosaicTransition() +{ + if (m_animationTimer == 16) { + m_animationTimer = 0; + EndTransition(TRUE); + return; + } + else { + if (m_animationTimer == 0) { + + // Same init/shuffle steps as the dissolve transition, except that + // we are using big blocky pixels and only need 64 columns. + MxS32 i; + for (i = 0; i < 64; i++) { + m_columnOrder[i] = i; + } + + for (i = 0; i < 64; i++) { + MxS32 swap = rand() % 64; + MxU16 t = m_columnOrder[i]; + m_columnOrder[i] = m_columnOrder[swap]; + m_columnOrder[swap] = t; + } + + // The same is true here. We only need 48 rows. + for (i = 0; i < 48; i++) { + m_randomShift[i] = rand() % 64; + } + } + + // Run one tick of the animation + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL); + if (res == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + res = m_ddSurface->Lock(NULL, &ddsd, 1, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + + for (MxS32 col = 0; col < 64; col++) { + // Select 4 columns on each tick + if (m_animationTimer * 4 > m_columnOrder[col]) { + continue; + } + + if (m_animationTimer * 4 + 3 < m_columnOrder[col]) { + continue; + } + + for (MxS32 row = 0; row < 48; row++) { + // To do the mosaic effect, we subdivide the 640x480 surface into + // 10x10 pixel blocks. At the chosen block, we sample the top-leftmost + // color and set the other 99 pixels to that value. + + // First, get the offset of the 10x10 block that we will sample for this row. + MxS32 xShift = 10 * ((m_randomShift[row] + col) % 64); + + // Combine xShift with this value to target the correct location in the buffer. + MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + + // Seek to the sample position. + MxU8* source = (MxU8*) ddsd.lpSurface + 10 * row * ddsd.lPitch + bytesPerPixel * xShift; + + // Sample byte or word depending on display mode. + MxU32 sample = bytesPerPixel == 1 ? *source : *(MxU16*) source; + + // For each of the 10 rows in the 10x10 square: + for (MxS32 k = 10 * row; k < 10 * row + 10; k++) { + if (ddsd.ddpfPixelFormat.dwRGBBitCount == 8) { + // Optimization: If the pixel is only one byte, we can use memset + MxU8* pos = ((MxU8*) ddsd.lpSurface + k * ddsd.lPitch + xShift); + memset(pos, sample, 10); + } + else { + // Need to double xShift because it measures pixels not bytes + MxU16* pos = (MxU16*) ((MxU8*) ddsd.lpSurface + k * ddsd.lPitch + 2 * xShift); + + for (MxS32 tt = 0; tt < 10; tt++) { + pos[tt] = sample; + } + } + } + } + } + + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + + if (VideoManager()->GetVideoParam().Flags().GetFlipSurfaces()) { + LPDIRECTDRAWSURFACE surf = VideoManager()->GetDisplaySurface()->GetDirectDrawSurface1(); + surf->BltFast(0, 0, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT); + } + + m_animationTimer++; + } + } +} + +// FUNCTION: LEGO1 0x1004c170 +void MxTransitionManager::WipeDownTransition() +{ + // If the animation is finished + if (m_animationTimer == 240) { + m_animationTimer = 0; + EndTransition(TRUE); + return; + } + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + if (res == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + + // For each of the 240 animation ticks, blank out two scanlines + // starting at the top of the screen. + // (dwRGBBitCount / 8) will tell how many bytes are used per pixel. + MxU8* line = (MxU8*) ddsd.lpSurface + 2 * ddsd.lPitch * m_animationTimer; + memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8); + + line += ddsd.lPitch; + memset(line, 0, 640 * ddsd.ddpfPixelFormat.dwRGBBitCount / 8); + + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + + m_animationTimer++; + } +} + +// FUNCTION: LEGO1 0x1004c270 +void MxTransitionManager::WindowsTransition() +{ + if (m_animationTimer == 240) { + m_animationTimer = 0; + EndTransition(TRUE); + return; + } + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + if (res == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + + MxU8* line = (MxU8*) ddsd.lpSurface + m_animationTimer * ddsd.lPitch; + + MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + MxS32 bytesPerLine = bytesPerPixel * 640; + + memset(line, 0, bytesPerLine); + + for (MxS32 i = m_animationTimer + 1; i < 480 - m_animationTimer; i++) { + line += ddsd.lPitch; + + memset(line + m_animationTimer * bytesPerPixel, 0, bytesPerPixel); + memset(line + 640 + (-1 - m_animationTimer) * bytesPerPixel, 0, bytesPerPixel); + } + + line += ddsd.lPitch; + memset(line, 0, bytesPerLine); + + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + + m_animationTimer++; + } +} + +// FUNCTION: LEGO1 0x1004c3e0 +void MxTransitionManager::BrokenTransition() +{ + // This function has no actual animation logic. + // It also never calls EndTransition to + // properly terminate the transition, so + // the game just hangs forever. + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + if (res == DDERR_SURFACELOST) { + m_ddSurface->Restore(); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + } +} + +// FUNCTION: LEGO1 0x1004c470 +void MxTransitionManager::SetWaitIndicator(MxVideoPresenter* p_waitIndicator) +{ + // End current wait indicator + if (m_waitIndicator != NULL) { + m_waitIndicator->GetAction()->SetFlags(m_waitIndicator->GetAction()->GetFlags() & ~MxDSAction::c_world); + m_waitIndicator->EndAction(); + m_waitIndicator = NULL; + } + + // Check if we were given a new wait indicator + if (p_waitIndicator != NULL) { + // Setup the new wait indicator + m_waitIndicator = p_waitIndicator; + + LegoVideoManager* videoManager = VideoManager(); + videoManager->UnregisterPresenter(*m_waitIndicator); + + if (m_waitIndicator->GetCurrentTickleState() < MxPresenter::e_streaming) { + m_waitIndicator->Tickle(); + } + } + else { + // Disable copy rect + m_copyFlags.m_bit0 = FALSE; + } +} + +// FUNCTION: LEGO1 0x1004c4d0 +void MxTransitionManager::SubmitCopyRect(LPDDSURFACEDESC p_ddsc) +{ + // Check if the copy rect is setup + if (m_copyFlags.m_bit0 == FALSE || m_waitIndicator == NULL || m_copyBuffer == NULL) { + return; + } + + // Copy the copy rect onto the surface + MxU8* dst; + + MxU32 bytesPerPixel = p_ddsc->ddpfPixelFormat.dwRGBBitCount / 8; + + const MxU8* src = (const MxU8*) m_copyBuffer; + + MxS32 copyPitch; + copyPitch = ((m_copyRect.right - m_copyRect.left) + 1) * bytesPerPixel; + + MxS32 y; + dst = (MxU8*) p_ddsc->lpSurface + (p_ddsc->lPitch * m_copyRect.top) + (bytesPerPixel * m_copyRect.left); + + for (y = 0; y < m_copyRect.bottom - m_copyRect.top + 1; ++y) { + memcpy(dst, src, copyPitch); + src += copyPitch; + dst += p_ddsc->lPitch; + } + + // Free the copy buffer + delete[] m_copyBuffer; + m_copyBuffer = NULL; +} + +// FUNCTION: LEGO1 0x1004c580 +void MxTransitionManager::SetupCopyRect(LPDDSURFACEDESC p_ddsc) +{ + // Check if the copy rect is setup + if (m_copyFlags.m_bit0 == FALSE || m_waitIndicator == NULL) { + return; + } + + // Tickle wait indicator + m_waitIndicator->Tickle(); + + // Check if wait indicator has started + if (m_waitIndicator->GetCurrentTickleState() >= MxPresenter::e_streaming) { + // Setup the copy rect + MxU32 copyPitch = (p_ddsc->ddpfPixelFormat.dwRGBBitCount / 8) * + (m_copyRect.right - m_copyRect.left + 1); // This uses m_copyRect, seemingly erroneously + MxU32 bytesPerPixel = p_ddsc->ddpfPixelFormat.dwRGBBitCount / 8; + + m_copyRect.left = m_waitIndicator->GetLocation().GetX(); + m_copyRect.top = m_waitIndicator->GetLocation().GetY(); + + MxS32 height = m_waitIndicator->GetHeight(); + MxS32 width = m_waitIndicator->GetWidth(); + + m_copyRect.right = m_copyRect.left + width - 1; + m_copyRect.bottom = m_copyRect.top + height - 1; + + // Allocate the copy buffer + const MxU8* src = + (const MxU8*) p_ddsc->lpSurface + m_copyRect.top * p_ddsc->lPitch + bytesPerPixel * m_copyRect.left; + + m_copyBuffer = new MxU8[bytesPerPixel * width * height]; + if (!m_copyBuffer) { + return; + } + + // Copy into the copy buffer + MxU8* dst = m_copyBuffer; + + for (MxS32 i = 0; i < (m_copyRect.bottom - m_copyRect.top + 1); i++) { + memcpy(dst, src, copyPitch); + src += p_ddsc->lPitch; + dst += copyPitch; + } + } + + // Setup display surface + if ((m_waitIndicator->GetAction()->GetFlags() & MxDSAction::c_bit5) != 0) { + MxDisplaySurface* displaySurface = VideoManager()->GetDisplaySurface(); + MxBool und = FALSE; + displaySurface->VTable0x2c( + p_ddsc, + m_waitIndicator->GetBitmap(), + 0, + 0, + m_waitIndicator->GetLocation().GetX(), + m_waitIndicator->GetLocation().GetY(), + m_waitIndicator->GetWidth(), + m_waitIndicator->GetHeight(), + und + ); + } + else { + MxDisplaySurface* displaySurface = VideoManager()->GetDisplaySurface(); + displaySurface->VTable0x24( + p_ddsc, + m_waitIndicator->GetBitmap(), + 0, + 0, + m_waitIndicator->GetLocation().GetX(), + m_waitIndicator->GetLocation().GetY(), + m_waitIndicator->GetWidth(), + m_waitIndicator->GetHeight() + ); + } +} diff --git a/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp b/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp new file mode 100644 index 00000000..a7ca2c20 --- /dev/null +++ b/LEGO1/lego/legoomni/src/control/legocontrolmanager.cpp @@ -0,0 +1,203 @@ +#include "legocontrolmanager.h" + +#include "legoeventnotificationparam.h" +#include "legovideomanager.h" +#include "misc.h" +#include "mxcontrolpresenter.h" +#include "mxdsaction.h" +#include "mxmisc.h" +#include "mxpresenter.h" +#include "mxticklemanager.h" + +DECOMP_SIZE_ASSERT(LegoControlManager, 0x60) +DECOMP_SIZE_ASSERT(LegoControlManagerEvent, 0x2c) + +// FUNCTION: LEGO1 0x10028520 +LegoControlManager::LegoControlManager() +{ + m_presenterList = NULL; + m_unk0x08 = 0; + m_unk0x0c = 0; + m_unk0x10 = FALSE; + m_unk0x14 = NULL; + TickleManager()->RegisterClient(this, 10); +} + +// FUNCTION: LEGO1 0x10028d60 +LegoControlManager::~LegoControlManager() +{ + TickleManager()->UnregisterClient(this); +} + +// FUNCTION: LEGO1 0x10028df0 +void LegoControlManager::FUN_10028df0(MxPresenterList* p_presenterList) +{ + m_presenterList = p_presenterList; + g_unk0x100f31b0 = -1; + g_unk0x100f31b4 = NULL; +} + +// FUNCTION: LEGO1 0x10028e10 +void LegoControlManager::Register(MxCore* p_listener) +{ + m_notifyList.Append(p_listener); +} + +// FUNCTION: LEGO1 0x10028ea0 +void LegoControlManager::Unregister(MxCore* p_listener) +{ + LegoNotifyListCursor cursor(&m_notifyList); + if (cursor.Find(p_listener)) { + cursor.Detach(); + } +} + +// FUNCTION: LEGO1 0x10029210 +MxBool LegoControlManager::FUN_10029210(LegoEventNotificationParam& p_param, MxPresenter* p_presenter) +{ + if (m_presenterList != NULL && m_presenterList->GetCount() != 0) { + m_unk0x14 = p_presenter; + + if (p_param.GetType() == c_notificationButtonUp || p_param.GetType() == c_notificationButtonDown) { + m_event.SetType(p_param.GetType()); + m_event.SetSender(p_param.GetSender()); + m_event.SetModifier(p_param.GetModifier()); + m_event.SetX(p_param.GetX()); + m_event.SetY(p_param.GetY()); + m_event.SetKey(p_param.GetKey()); + + if (p_param.GetType() == c_notificationButtonUp) { + if (m_unk0x10 == TRUE) { + m_unk0x10 = FALSE; + return TRUE; + } + + if (g_unk0x100f31b0 != -1 && g_unk0x100f31b4 != NULL) { + if (m_unk0x08 == 2) { + return FUN_10029750(); + } + else { + m_unk0x0c = 1; + return TRUE; + } + } + } + else if (p_param.GetType() == c_notificationButtonDown) { + if (m_unk0x0c == 1) { + m_unk0x10 = TRUE; + return TRUE; + } + else { + return FUN_10029630(); + } + } + } + + return FALSE; + } + else { + g_unk0x100f31b0 = -1; + g_unk0x100f31b4 = NULL; + + return FALSE; + } +} + +// FUNCTION: LEGO1 0x100292e0 +void LegoControlManager::FUN_100292e0() +{ + LegoNotifyListCursor cursor(&m_notifyList); + MxCore* target; + + cursor.Head(); + while (cursor.Current(target)) { + cursor.Next(); + target->Notify(m_event); + } +} + +// STUB: LEGO1 0x100293c0 +void LegoControlManager::FUN_100293c0(undefined4, const char*, undefined2) +{ +} + +// FUNCTION: LEGO1 0x100294e0 +MxControlPresenter* LegoControlManager::FUN_100294e0(MxS32 p_x, MxS32 p_y) +{ + if (m_presenterList) { + MxPresenterListCursor cursor(m_presenterList); + MxPresenter* control; + MxVideoPresenter* presenter = (MxVideoPresenter*) VideoManager()->GetPresenterAt(p_x, p_y); + + if (presenter) { + while (cursor.Next(control)) { + if (((MxControlPresenter*) control)->FUN_10044270(p_x, p_y, presenter)) { + return (MxControlPresenter*) control; + } + } + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10029600 +MxResult LegoControlManager::Tickle() +{ + if (m_unk0x08 == 2 && m_unk0x0c == 1) { + m_event.SetType(c_notificationButtonUp); + FUN_10029750(); + return 0; + } + else if (m_unk0x08 == 1) { + m_unk0x08 = 2; + } + return 0; +} + +// FUNCTION: LEGO1 0x10029630 +MxBool LegoControlManager::FUN_10029630() +{ + MxPresenterListCursor cursor(m_presenterList); + MxPresenter* presenter; + + while (cursor.Next(presenter)) { + if (((MxControlPresenter*) presenter)->FUN_10044480(&m_event, m_unk0x14)) { + g_unk0x100f31b0 = m_event.GetClickedObjectId(); + g_unk0x100f31b4 = m_event.GetClickedAtom(); + FUN_100292e0(); + m_unk0x08 = 1; + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10029750 +MxBool LegoControlManager::FUN_10029750() +{ + MxPresenterListCursor cursor(m_presenterList); + MxPresenter* presenter; + + while (cursor.Next(presenter)) { + if (presenter->GetAction() && presenter->GetAction()->GetObjectId() == g_unk0x100f31b0 && + presenter->GetAction()->GetAtomId().GetInternal() == g_unk0x100f31b4) { + if (((MxControlPresenter*) presenter)->FUN_10044480(&m_event, m_unk0x14)) { + FUN_100292e0(); + } + + g_unk0x100f31b0 = -1; + g_unk0x100f31b4 = NULL; + + m_unk0x08 = 0; + m_unk0x0c = 0; + + return TRUE; + } + } + + g_unk0x100f31b0 = -1; + g_unk0x100f31b4 = NULL; + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/control/legometerpresenter.cpp b/LEGO1/lego/legoomni/src/control/legometerpresenter.cpp new file mode 100644 index 00000000..d6dd5dd8 --- /dev/null +++ b/LEGO1/lego/legoomni/src/control/legometerpresenter.cpp @@ -0,0 +1,100 @@ +#include "legometerpresenter.h" + +#include "decomp.h" +#include "define.h" +#include "mxbitmap.h" +#include "mxdsaction.h" +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(LegoMeterPresenter, 0x94) + +// FUNCTION: LEGO1 0x10043430 +LegoMeterPresenter::LegoMeterPresenter() +{ + m_layout = 0; + m_unk0x6c = 0; + m_unk0x84 = 0; + m_type = 1; + SetBit1(FALSE); +} + +// FUNCTION: LEGO1 0x10043780 +LegoMeterPresenter::~LegoMeterPresenter() +{ + delete m_unk0x6c; +} + +// FUNCTION: LEGO1 0x10043800 +void LegoMeterPresenter::ParseExtra() +{ + MxStillPresenter::ParseExtra(); + + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[256]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char output[256]; + if (KeyValueStringParse(extraCopy, g_strTYPE, output)) { + if (!strcmpi(output, g_strLEFT_TO_RIGHT)) { + m_layout = 0; + } + else if (!strcmpi(output, g_strRIGHT_TO_LEFT)) { + m_layout = 1; + } + else if (!strcmpi(output, g_strBOTTOM_TO_TOP)) { + m_layout = 2; + } + else if (!strcmpi(output, g_strTOP_TO_BOTTOM)) { + m_layout = 3; + } + } + + if (KeyValueStringParse(extraCopy, g_strFILLER_INDEX, output)) { + m_type = atoi(output); + } + + if (KeyValueStringParse(extraCopy, g_strVARIABLE, output)) { + m_variable = output; + } + else { + EndAction(); + } + } + else { + EndAction(); + } +} + +// FUNCTION: LEGO1 0x10043990 +void LegoMeterPresenter::StreamingTickle() +{ + MxStillPresenter::StreamingTickle(); + m_unk0x6c = new MxU8[m_frameBitmap->GetBmiStride() * m_frameBitmap->GetBmiHeightAbs()]; + if (m_unk0x6c == NULL) { + EndAction(); + } + + memcpy(m_unk0x6c, m_frameBitmap->GetImage(), m_frameBitmap->GetBmiStride() * m_frameBitmap->GetBmiHeightAbs()); + + m_unk0x88 = 0; + m_unk0x8a = 0; + m_unk0x8c = m_frameBitmap->GetBmiWidth() - 1; + m_unk0x8e = m_frameBitmap->GetBmiHeightAbs() - 1; +} + +// FUNCTION: LEGO1 0x10043a30 +void LegoMeterPresenter::RepeatingTickle() +{ + FUN_10043a50(); + MxStillPresenter::RepeatingTickle(); +} + +// STUB: LEGO1 0x10043a50 +void LegoMeterPresenter::FUN_10043a50() +{ +} diff --git a/LEGO1/lego/legoomni/src/entity/act2brick.cpp b/LEGO1/lego/legoomni/src/entity/act2brick.cpp new file mode 100644 index 00000000..fa1408aa --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/act2brick.cpp @@ -0,0 +1,38 @@ +#include "act2brick.h" + +DECOMP_SIZE_ASSERT(Act2Brick, 0x194) + +// STUB: LEGO1 0x1007a2b0 +Act2Brick::Act2Brick() +{ + // TODO +} + +// STUB: LEGO1 0x1007a470 +Act2Brick::~Act2Brick() +{ + // TODO +} + +// STUB: LEGO1 0x1007a750 +MxResult Act2Brick::VTable0x94(LegoPathActor* p_actor, MxBool p_bool) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1007a7f0 +MxResult Act2Brick::Tickle() +{ + // TODO + + return SUCCESS; +} + +// STUB: LEGO1 0x1007a8c0 +MxLong Act2Brick::Notify(MxParam& p_param) +{ + // TODO + + return 0; +} diff --git a/LEGO1/lego/legoomni/src/entity/act2policestation.cpp b/LEGO1/lego/legoomni/src/entity/act2policestation.cpp new file mode 100644 index 00000000..a8636335 --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/act2policestation.cpp @@ -0,0 +1,11 @@ +#include "act2policestation.h" + +DECOMP_SIZE_ASSERT(Act2PoliceStation, 0x68) + +// STUB: LEGO1 0x1004e0e0 +MxLong Act2PoliceStation::Notify(MxParam& p_param) +{ + // TODO + + return 0; +} diff --git a/LEGO1/lego/legoomni/src/entity/legoactor.cpp b/LEGO1/lego/legoomni/src/entity/legoactor.cpp new file mode 100644 index 00000000..6c455909 --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legoactor.cpp @@ -0,0 +1,146 @@ +#include "legoactor.h" + +#include "define.h" +#include "legocachesoundmanager.h" +#include "legosoundmanager.h" +#include "misc.h" +#include "mxutilities.h" +#include "roi/legoroi.h" + +DECOMP_SIZE_ASSERT(LegoActor, 0x78) + +// GLOBAL: LEGO1 0x100f32d0 +const char* g_actorNames[] = {"none", "pepper", "mama", "papa", "nick", "laura", "The_Brickster!"}; + +// FUNCTION: LEGO1 0x1002d110 +LegoActor::LegoActor() +{ + m_unk0x68 = 0.0f; + m_sound = NULL; + m_unk0x70 = 0.0f; + m_unk0x10 = 0; + m_actorId = 0; +} + +// FUNCTION: LEGO1 0x1002d320 +LegoActor::~LegoActor() +{ + if (m_sound) { + m_sound->FUN_10006b80(); + } +} + +// FUNCTION: LEGO1 0x1002d390 +void LegoActor::ParseAction(char* p_extra) +{ + MxFloat speed = 0.0F; + char value[256]; + value[0] = '\0'; + + if (KeyValueStringParse(value, g_strATTACH_CAMERA, p_extra)) { + GetROI()->SetVisibility(FALSE); + + if (value[0]) { + Mx3DPointFloat location(0.0F, 0.0F, 0.0F); + Mx3DPointFloat direction(0.0F, 0.0F, 1.0F); + Mx3DPointFloat up(0.0F, 1.0F, 0.0F); + + char* token = strtok(value, g_parseExtraTokens); + if (token != NULL) { + location[0] = atof(token); + } + + token = strtok(NULL, g_parseExtraTokens); + if (token != NULL) { + location[1] = atof(token); + } + + token = strtok(NULL, g_parseExtraTokens); + if (token != NULL) { + location[2] = atof(token); + } + + token = strtok(NULL, g_parseExtraTokens); + if (token != NULL) { + direction[0] = atof(token); + } + + token = strtok(NULL, g_parseExtraTokens); + if (token != NULL) { + direction[1] = atof(token); + } + + token = strtok(NULL, g_parseExtraTokens); + if (token != NULL) { + direction[2] = atof(token); + } + + token = strtok(NULL, g_parseExtraTokens); + if (token != NULL) { + up[0] = atof(token); + } + + token = strtok(NULL, g_parseExtraTokens); + if (token != NULL) { + up[1] = atof(token); + } + + token = strtok(NULL, g_parseExtraTokens); + if (token != NULL) { + up[2] = atof(token); + } + + SetWorldTransform(location, direction, up); + } + else { + ResetWorldTransform(TRUE); + } + } + + if (KeyValueStringParse(value, g_strSPEED, p_extra)) { + speed = atof(value); + SetWorldSpeed(speed); + } + + if (KeyValueStringParse(value, g_strSOUND, p_extra)) { + m_sound = SoundManager()->GetCacheSoundManager()->FUN_1003dae0(value, GetROI()->GetName(), TRUE); + } + + if (KeyValueStringParse(value, g_strMUTE, p_extra)) { + FUN_1002d6e0(TRUE); + } + + if (KeyValueStringParse(value, g_strVISIBILITY, p_extra)) { + GetROI()->SetVisibility(strcmpi(value, "FALSE") != 0); + } +} + +// FUNCTION: LEGO1 0x1002d660 +const char* LegoActor::GetActorName(MxU8 p_id) +{ + return g_actorNames[p_id]; +} + +// FUNCTION: LEGO1 0x1002d670 +void LegoActor::SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2) +{ + if (p_roi) { + const char* name = p_roi->GetName(); + + for (MxU32 i = 1; i <= sizeOfArray(g_actorNames) - 1; i++) { + if (!strcmpi(name, g_actorNames[i])) { + m_type = e_character; + m_actorId = i; + break; + } + } + } + + LegoEntity::SetROI(p_roi, p_bool1, p_bool2); +} + +// STUB: LEGO1 0x1002d6e0 +void LegoActor::FUN_1002d6e0(MxBool) +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/entity/legoactorpresenter.cpp b/LEGO1/lego/legoomni/src/entity/legoactorpresenter.cpp new file mode 100644 index 00000000..40273e1c --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legoactorpresenter.cpp @@ -0,0 +1,44 @@ +#include "legoactorpresenter.h" + +#include "legoentity.h" +#include "misc.h" + +DECOMP_SIZE_ASSERT(LegoActorPresenter, 0x50) + +// FUNCTION: LEGO1 0x10076c30 +void LegoActorPresenter::ReadyTickle() +{ + if (CurrentWorld()) { + m_entity = (LegoEntity*) CreateEntity("LegoActor"); + if (m_entity) { + SetEntityLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp()); + m_entity->Create(*m_action); + } + ProgressTickleState(e_starting); + } +} + +// FUNCTION: LEGO1 0x10076c90 +void LegoActorPresenter::StartingTickle() +{ + if (m_entity->GetROI()) { + ProgressTickleState(e_streaming); + ParseExtra(); + } +} + +// FUNCTION: LEGO1 0x10076cc0 +void LegoActorPresenter::ParseExtra() +{ + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[512]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + m_entity->ParseAction(extraCopy); + } +} diff --git a/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp new file mode 100644 index 00000000..6025f614 --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legocameracontroller.cpp @@ -0,0 +1,205 @@ +#include "legocameracontroller.h" + +#include "3dmanager/lego3dmanager.h" +#include "legoinputmanager.h" +#include "legonotify.h" +#include "legosoundmanager.h" +#include "legovideomanager.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxtimer.h" +#include "realtime/realtime.h" +#include "roi/legoroi.h" + +#include + +DECOMP_SIZE_ASSERT(LegoCameraController, 0xc8) + +// FUNCTION: LEGO1 0x10011d50 +LegoCameraController::LegoCameraController() +{ + SetWorldTransform(Mx3DPointFloat(0, 0, 0), Mx3DPointFloat(0, 0, 1), Mx3DPointFloat(0, 1, 0)); +} + +// FUNCTION: LEGO1 0x10011f70 +LegoCameraController::~LegoCameraController() +{ + if (InputManager()) { + if (InputManager()->GetCamera() == this) { + InputManager()->ClearCamera(); + } + } +} + +// FUNCTION: LEGO1 0x10011ff0 +MxResult LegoCameraController::Create() +{ + InputManager()->SetCamera(this); + return LegoPointOfViewController::Create(VideoManager()->Get3DManager()->GetLego3DView()); +} + +// FUNCTION: LEGO1 0x10012020 +MxLong LegoCameraController::Notify(MxParam& p_param) +{ + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationDragEnd: { + if ((((LegoEventNotificationParam&) p_param).GetModifier()) & LegoEventNotificationParam::c_lButtonState) { + OnLButtonDown(MxPoint32( + ((LegoEventNotificationParam&) p_param).GetX(), + ((LegoEventNotificationParam&) p_param).GetY() + )); + } + else if ((((LegoEventNotificationParam&) p_param).GetModifier()) & LegoEventNotificationParam::c_rButtonState) { + OnRButtonDown(MxPoint32( + ((LegoEventNotificationParam&) p_param).GetX(), + ((LegoEventNotificationParam&) p_param).GetY() + )); + } + } break; + case c_notificationDragStart: { + OnMouseMove( + ((LegoEventNotificationParam&) p_param).GetModifier(), + MxPoint32(((LegoEventNotificationParam&) p_param).GetX(), ((LegoEventNotificationParam&) p_param).GetY()) + ); + } break; + case c_notificationDrag: { + if (((((LegoEventNotificationParam&) p_param).GetModifier()) & LegoEventNotificationParam::c_lButtonState) == + 0) { + OnLButtonUp(MxPoint32( + ((LegoEventNotificationParam&) p_param).GetX(), + ((LegoEventNotificationParam&) p_param).GetY() + )); + } + else if (((((LegoEventNotificationParam&) p_param).GetModifier()) & LegoEventNotificationParam::c_rButtonState) == 0) { + OnRButtonUp(MxPoint32( + ((LegoEventNotificationParam&) p_param).GetX(), + ((LegoEventNotificationParam&) p_param).GetY() + )); + } + } break; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100121b0 +void LegoCameraController::OnLButtonDown(MxPoint32 p_point) +{ + LeftDown(p_point.GetX(), p_point.GetY()); +} + +// FUNCTION: LEGO1 0x100121d0 +void LegoCameraController::OnLButtonUp(MxPoint32 p_point) +{ + LeftUp(p_point.GetX(), p_point.GetY()); +} + +// FUNCTION: LEGO1 0x100121f0 +void LegoCameraController::OnRButtonDown(MxPoint32 p_point) +{ + RightDown(p_point.GetX(), p_point.GetY()); +} + +// FUNCTION: LEGO1 0x10012210 +void LegoCameraController::OnRButtonUp(MxPoint32 p_point) +{ + RightUp(p_point.GetX(), p_point.GetY()); +} + +// FUNCTION: LEGO1 0x10012230 +void LegoCameraController::OnMouseMove(MxU8 p_modifier, MxPoint32 p_point) +{ + if (p_modifier & c_lButtonState) { + LeftDrag(p_point.GetX(), p_point.GetY()); + } + else if (p_modifier & c_rButtonState) { + RightDrag(p_point.GetX(), p_point.GetY()); + } +} + +// FUNCTION: LEGO1 0x10012260 +void LegoCameraController::SetWorldTransform(const Vector3& p_at, const Vector3& p_dir, const Vector3& p_up) +{ + CalcLocalTransform(p_at, p_dir, p_up, m_matrix1); + m_matrix2 = m_matrix1; +} + +// STUB: LEGO1 0x10012290 +void LegoCameraController::FUN_10012290(float) +{ +} + +// STUB: LEGO1 0x10012320 +void LegoCameraController::FUN_10012320(MxFloat) +{ + // TODO +} + +// FUNCTION: LEGO1 0x100123e0 +void LegoCameraController::FUN_100123e0(const Matrix4& p_transform, MxU32 p_und) +{ + if (m_lego3DView != NULL) { + ViewROI* pov = m_lego3DView->GetPointOfView(); + + if (pov != NULL) { + MxMatrix mat; + + if (p_und) { + MXM4(mat, m_matrix1, p_transform); + } + else { + mat = p_transform; + } + + ((TimeROI*) pov)->FUN_100a9b40(mat, Timer()->GetTime()); + pov->WrappedSetLocalTransform(mat); + m_lego3DView->Moved(*pov); + + SoundManager()->FUN_1002a410( + pov->GetWorldPosition(), + pov->GetWorldDirection(), + pov->GetWorldUp(), + pov->GetWorldVelocity() + ); + } + } +} + +// FUNCTION: LEGO1 0x10012740 +Mx3DPointFloat LegoCameraController::GetWorldUp() +{ + if (m_lego3DView && m_lego3DView->GetPointOfView()) { + Mx3DPointFloat vec; + vec = m_lego3DView->GetPointOfView()->GetWorldUp(); + return Mx3DPointFloat(vec[0], vec[1], vec[2]); + } + else { + return Mx3DPointFloat(0, 0, 0); + } +} + +// FUNCTION: LEGO1 0x100127f0 +Mx3DPointFloat LegoCameraController::GetWorldLocation() +{ + if (m_lego3DView && m_lego3DView->GetPointOfView()) { + Mx3DPointFloat vec; + vec = m_lego3DView->GetPointOfView()->GetWorldPosition(); + return Mx3DPointFloat(vec[0], vec[1] - m_entityOffsetUp, vec[2]); + } + else { + return Mx3DPointFloat(0, 0, 0); + } +} + +// FUNCTION: LEGO1 0x100128a0 +Mx3DPointFloat LegoCameraController::GetWorldDirection() +{ + if (m_lego3DView && m_lego3DView->GetPointOfView()) { + Mx3DPointFloat vec; + vec = m_lego3DView->GetPointOfView()->GetWorldDirection(); + return Mx3DPointFloat(vec[0], vec[1], vec[2]); + } + else { + return Mx3DPointFloat(0, 0, 0); + } +} diff --git a/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp b/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp new file mode 100644 index 00000000..d724f763 --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legocarraceactor.cpp @@ -0,0 +1,85 @@ +#include "legocarraceactor.h" + +#include "mxmisc.h" +#include "mxvariabletable.h" + +DECOMP_SIZE_ASSERT(LegoCarRaceActor, 0x1a0) + +// GLOBAL: LEGO1 0x100f7af0 +// STRING: LEGO1 0x100f7ae4 +const char* g_fuel = "FUEL"; + +// STUB: LEGO1 0x100141a0 +MxU32 LegoCarRaceActor::VTable0x90(float, Matrix4&) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1005d650 +MxResult LegoCarRaceActor::VTable0x94(LegoPathActor* p_actor, MxBool p_bool) +{ + // TODO + return 0; +} + +// FUNCTION: LEGO1 0x10080350 +LegoCarRaceActor::LegoCarRaceActor() +{ + m_unk0x08 = 1.0f; + m_unk0x70 = 0.0f; + m_unk0x0c = 0; + m_unk0x13c = 0.0f; + m_unk0x68 = 1.0f; + m_unk0x1c = 0; + m_unk0x10 = 0.65f; + m_unk0x14 = 0.03f; + m_unk0x18 = 0.6f; + m_unk0x140 = 0.1f; + m_unk0x150 = -5.0f; + m_unk0x148 = 1; + VariableTable()->SetVariable(g_fuel, "0.8"); +} + +// STUB: LEGO1 0x10080590 +void LegoCarRaceActor::FUN_10080590() +{ +} + +// STUB: LEGO1 0x10080740 +void LegoCarRaceActor::VTable0x1c() +{ +} + +// STUB: LEGO1 0x10081830 +MxU32 LegoCarRaceActor::VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 +) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10081d10 +void LegoCarRaceActor::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x10081d20 +void LegoCarRaceActor::VTable0x98() +{ + // TODO +} + +// STUB: LEGO1 0x10081d30 +MxResult LegoCarRaceActor::WaitForAnimation() +{ + // TODO + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/entity/legoentity.cpp b/LEGO1/lego/legoomni/src/entity/legoentity.cpp new file mode 100644 index 00000000..192fc804 --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legoentity.cpp @@ -0,0 +1,385 @@ +#include "legoentity.h" + +#include "3dmanager/lego3dmanager.h" +#include "define.h" +#include "legobuildingmanager.h" +#include "legocameracontroller.h" +#include "legocharactermanager.h" +#include "legoeventnotificationparam.h" +#include "legogamestate.h" +#include "legoplantmanager.h" +#include "legoutils.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxutilities.h" +#include "realtime/realtime.h" + +DECOMP_SIZE_ASSERT(LegoEntity, 0x68) + +// FUNCTION: LEGO1 0x100105f0 +void LegoEntity::Init() +{ + m_worldLocation.Fill(0); + m_worldDirection.Fill(0); + m_worldSpeed = 0; + m_roi = NULL; + m_cameraFlag = FALSE; + m_filename = NULL; + m_unk0x10 = 0; + m_flags = 0; + m_actionType = Extra::ActionType::e_unknown; + m_targetEntityId = -1; + m_type = e_unk4; +} + +// FUNCTION: LEGO1 0x10010650 +void LegoEntity::ResetWorldTransform(MxBool p_cameraFlag) +{ + LegoWorld* world = CurrentWorld(); + + if (world != NULL && world->GetCamera() != NULL) { + m_cameraFlag = p_cameraFlag; + + if (m_cameraFlag) { + world->GetCamera()->SetEntity(this); + world->GetCamera()->SetWorldTransform( + Mx3DPointFloat(0.0F, 1.25F, 0.0F), + Mx3DPointFloat(0.0F, 0.0F, 1.0F), + Mx3DPointFloat(0.0F, 1.0F, 0.0F) + ); + } + else { + if (world->GetCamera()->GetEntity() == this) { + world->GetCamera()->SetEntity(NULL); + world->GetCamera()->SetWorldTransform( + Mx3DPointFloat(0.0F, 0.0F, 0.0F), + Mx3DPointFloat(0.0F, 0.0F, 1.0F), + Mx3DPointFloat(0.0F, 1.0F, 0.0F) + ); + } + } + } +} + +// FUNCTION: LEGO1 0x10010790 +void LegoEntity::SetWorldTransform(const Vector3& p_location, const Vector3& p_direction, const Vector3& p_up) +{ + LegoWorld* world = CurrentWorld(); + + if (world != NULL && world->GetCamera() != NULL) { + m_cameraFlag = TRUE; + world->GetCamera()->SetEntity(this); + world->GetCamera()->SetWorldTransform(p_location, p_direction, p_up); + } +} + +// FUNCTION: LEGO1 0x100107e0 +MxResult LegoEntity::Create(MxDSAction& p_dsAction) +{ + m_mxEntityId = p_dsAction.GetObjectId(); + m_atom = p_dsAction.GetAtomId(); + SetWorld(); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10010810 +void LegoEntity::Destroy(MxBool p_fromDestructor) +{ + if (m_roi) { + if (m_flags & c_bit1) { + if (m_roi->GetEntity() == this) { + m_roi->SetEntity(NULL); + } + + CharacterManager()->FUN_10083db0(m_roi); + } + else { + VideoManager()->Get3DManager()->GetLego3DView()->Remove(*m_roi); + delete m_roi; + } + } + + delete[] m_filename; + Init(); +} + +// FUNCTION: LEGO1 0x10010880 +void LegoEntity::SetWorld() +{ + LegoWorld* world = CurrentWorld(); + + if (world != NULL && world != (LegoWorld*) this) { + world->Add(this); + } +} + +// FUNCTION: LEGO1 0x100108a0 +void LegoEntity::SetROI(LegoROI* p_roi, MxBool p_bool1, MxBool p_bool2) +{ + m_roi = p_roi; + + if (m_roi != NULL) { + if (p_bool2) { + MxMatrix mat; + CalcLocalTransform( + Mx3DPointFloat(m_worldLocation[0], m_worldLocation[1], m_worldLocation[2]), + Mx3DPointFloat(m_worldDirection[0], m_worldDirection[1], m_worldDirection[2]), + Mx3DPointFloat(m_worldUp[0], m_worldUp[1], m_worldUp[2]), + mat + ); + + m_roi->FUN_100a46b0(mat); + } + + m_roi->SetEntity(this); + VideoManager()->Get3DManager()->GetLego3DView()->Moved(*m_roi); + + if (p_bool1) { + ClearFlag(c_bit1); + } + else { + SetFlag(c_bit1); + } + } +} + +// FUNCTION: LEGO1 0x100109b0 +void LegoEntity::SetLocation(const Vector3& p_location, const Vector3& p_direction, const Vector3& p_up, MxBool p_und) +{ + Mx3DPointFloat direction; + Mx3DPointFloat up; + + direction = p_direction; + direction.Unitize(); + + up = p_up; + up.Unitize(); + + m_worldLocation = p_location; + m_worldDirection = direction; + m_worldUp = up; + + if (m_roi != NULL) { + MxMatrix mat; + CalcLocalTransform( + Mx3DPointFloat(p_location[0], p_location[1], p_location[2]), + Mx3DPointFloat(direction[0], direction[1], direction[2]), + Mx3DPointFloat(up[0], up[1], up[2]), + mat + ); + + m_roi->FUN_100a46b0(mat); + VideoManager()->Get3DManager()->GetLego3DView()->Moved(*m_roi); + + if (p_und) { + FUN_10010c30(); + } + } +} + +// FUNCTION: LEGO1 0x10010c30 +void LegoEntity::FUN_10010c30() +{ + LegoWorld* world = CurrentWorld(); + + if (m_cameraFlag && world && world->GetCamera() && m_roi) { + world->GetCamera()->FUN_100123e0(m_roi->GetLocal2World(), 1); + } +} + +// FUNCTION: LEGO1 0x10010c60 +Mx3DPointFloat LegoEntity::GetWorldDirection() +{ + if (m_roi != NULL) { + m_worldDirection = + Mx3DPointFloat(m_roi->GetWorldDirection()[0], m_roi->GetWorldDirection()[1], m_roi->GetWorldDirection()[2]); + } + + return m_worldDirection; +} + +// FUNCTION: LEGO1 0x10010cf0 +Mx3DPointFloat LegoEntity::GetWorldUp() +{ + if (m_roi != NULL) { + m_worldUp = Mx3DPointFloat(m_roi->GetWorldUp()[0], m_roi->GetWorldUp()[1], m_roi->GetWorldUp()[2]); + } + + return m_worldUp; +} + +// FUNCTION: LEGO1 0x10010d80 +Mx3DPointFloat LegoEntity::GetWorldPosition() +{ + if (m_roi != NULL) { + m_worldLocation = + Mx3DPointFloat(m_roi->GetWorldPosition()[0], m_roi->GetWorldPosition()[1], m_roi->GetWorldPosition()[2]); + } + + return m_worldLocation; +} + +// FUNCTION: LEGO1 0x10010e10 +void LegoEntity::ParseAction(char* p_extra) +{ + char copy[1024]; + char actionValue[1024]; + strcpy(copy, p_extra); + + if (KeyValueStringParse(actionValue, g_strACTION, copy)) { + m_actionType = MatchActionString(strtok(actionValue, g_parseExtraTokens)); + + if (m_actionType != Extra::ActionType::e_exit) { + char* token = strtok(NULL, g_parseExtraTokens); + + m_filename = new char[strlen(token) + 1]; + strcpy(m_filename, token); + + if (m_actionType != Extra::ActionType::e_run) { + m_targetEntityId = atoi(strtok(NULL, g_parseExtraTokens)); + } + } + } +} + +// FUNCTION: LEGO1 0x10010f10 +void LegoEntity::VTable0x34(MxBool p_und) +{ + if (!GetUnknown0x10IsSet(c_altBit1)) { + MxU32 objectId = 0; + const LegoChar* roiName = m_roi->GetName(); + + switch (m_type) { + case e_character: + objectId = CharacterManager()->FUN_10085140(m_roi, p_und); + break; + case e_unk1: + break; + case e_plant: + objectId = PlantManager()->FUN_10026ba0(this, p_und); + break; + case e_building: + objectId = BuildingManager()->FUN_1002ff40(this, p_und); + break; + } + + if (objectId) { + MxDSAction action; + action.SetAtomId(MxAtomId(CharacterManager()->GetCustomizeAnimFile(), e_lowerCase2)); + action.SetObjectId(objectId); + action.AppendExtra(strlen(roiName) + 1, roiName); + Start(&action); + } + } +} + +// STUB: LEGO1 0x10011070 +void LegoEntity::VTable0x38() +{ + // TODO +} + +// FUNCTION: LEGO1 0x10011300 +void LegoEntity::VTable0x3c() +{ + switch (m_type) { + case e_character: + CharacterManager()->SwitchHat(m_roi); + break; + case e_unk1: + break; + case e_plant: + PlantManager()->FUN_100269e0(this); + break; + case e_building: + BuildingManager()->IncrementVariant(this); + break; + } + + VTable0x34(FALSE); + VTable0x38(); +} + +// STUB: LEGO1 0x10011360 +void LegoEntity::VTable0x40() +{ + // TODO +} + +// STUB: LEGO1 0x100113c0 +void LegoEntity::VTable0x44() +{ + // TODO +} + +// STUB: LEGO1 0x10011420 +void LegoEntity::VTable0x48(LegoROI* p_roi) +{ + // TODO +} + +// STUB: LEGO1 0x10011470 +void LegoEntity::VTable0x4c() +{ + // TODO +} + +// FUNCTION: LEGO1 0x100114e0 +void LegoEntity::SetType(MxU8 p_type) +{ + m_type = p_type; +} + +// FUNCTION: LEGO1 0x100114f0 +MxLong LegoEntity::Notify(MxParam& p_param) +{ + LegoEventNotificationParam& param = (LegoEventNotificationParam&) p_param; + + if (param.GetNotification() != c_notificationType11) { + return 0; + } + + if (m_actionType != Extra::e_unknown) { + InvokeAction(m_actionType, MxAtomId(m_filename, e_lowerCase2), m_targetEntityId, this); + } + else { + switch (GameState()->GetActorId()) { + case 1: + if (GameState()->GetCurrentAct() != LegoGameState::e_act2 && + GameState()->GetCurrentAct() != LegoGameState::e_act3) { + VTable0x3c(); + } + break; + case 2: + VTable0x40(); + break; + case 3: + VTable0x44(); + break; + case 4: + VTable0x48(param.GetROI()); + break; + case 5: + VTable0x4c(); + break; + case 6: + switch (m_type) { + case e_character: + case e_unk1: + break; + case e_plant: + PlantManager()->FUN_10026c50(this); + break; + case e_building: + BuildingManager()->FUN_10030000(this); + break; + case e_unk4: + break; + } + } + } + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/entity/legoentitypresenter.cpp b/LEGO1/lego/legoomni/src/entity/legoentitypresenter.cpp new file mode 100644 index 00000000..a755bb2f --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legoentitypresenter.cpp @@ -0,0 +1,106 @@ +#include "legoentitypresenter.h" + +#include "islepathactor.h" +#include "legovideomanager.h" +#include "misc.h" + +DECOMP_SIZE_ASSERT(LegoEntityPresenter, 0x50) + +// FUNCTION: LEGO1 0x10053440 +LegoEntityPresenter::LegoEntityPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100535c0 +void LegoEntityPresenter::Init() +{ + m_entity = NULL; +} + +// FUNCTION: LEGO1 0x100535d0 +LegoEntityPresenter::~LegoEntityPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x10053630 +undefined4 LegoEntityPresenter::SetEntity(LegoEntity* p_entity) +{ + m_entity = p_entity; + return 0; +} + +// FUNCTION: LEGO1 0x10053640 +void LegoEntityPresenter::Destroy(MxBool p_fromDestructor) +{ + if (VideoManager()) { + VideoManager()->UnregisterPresenter(*this); + } + + Init(); +} + +// FUNCTION: LEGO1 0x10053670 +void LegoEntityPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x10053680 +MxResult LegoEntityPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) +{ + MxResult result = MxCompositePresenter::StartAction(p_controller, p_action); + + if (VideoManager()) { + VideoManager()->RegisterPresenter(*this); + } + + return result; +} + +// FUNCTION: LEGO1 0x100536c0 +void LegoEntityPresenter::ReadyTickle() +{ + if (CurrentWorld()) { + m_entity = (LegoEntity*) MxPresenter::CreateEntity("LegoEntity"); + if (m_entity) { + m_entity->Create(*m_action); + m_entity->SetLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp(), TRUE); + ParseExtra(); + } + ProgressTickleState(e_starting); + } +} + +// FUNCTION: LEGO1 0x10053720 +void LegoEntityPresenter::RepeatingTickle() +{ + if (m_list.empty()) { + EndAction(); + } +} + +// FUNCTION: LEGO1 0x10053730 +void LegoEntityPresenter::SetEntityLocation(const Vector3& p_location, const Vector3& p_direction, const Vector3& p_up) +{ + if (m_entity) { + m_entity->SetLocation(p_location, p_direction, p_up, TRUE); + } +} + +// FUNCTION: LEGO1 0x10053750 +void LegoEntityPresenter::ParseExtra() +{ + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[512]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + m_entity->ParseAction(extraCopy); + } +} diff --git a/LEGO1/lego/legoomni/src/entity/legojetski.cpp b/LEGO1/lego/legoomni/src/entity/legojetski.cpp new file mode 100644 index 00000000..3656e1c7 --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legojetski.cpp @@ -0,0 +1,84 @@ +#include "legojetski.h" + +#include "mxmisc.h" +#include "mxnotificationmanager.h" + +DECOMP_SIZE_ASSERT(LegoJetski, 0x1dc) + +// FUNCTION: LEGO1 0x100136f0 +void LegoJetski::FUN_100136f0(float p_worldSpeed) +{ + if (p_worldSpeed < 0) { + LegoCarRaceActor::m_unk0x0c = 2; + m_unk0x13c = 0; + SetWorldSpeed(0); + } + else { + m_unk0x13c = p_worldSpeed; + } +} + +// FUNCTION: LEGO1 0x10013820 +LegoJetski::LegoJetski() +{ + NotificationManager()->Register(this); +} + +// STUB: LEGO1 0x10013e70 +MxLong LegoJetski::Notify(MxParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10014110 +void LegoJetski::ParseAction(char*) +{ + // TODO +} + +// STUB: LEGO1 0x10014120 +void LegoJetski::SetWorldSpeed(MxFloat p_worldSpeed) +{ + // TODO +} + +// STUB: LEGO1 0x10014140 +MxU32 LegoJetski::VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 +) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10014180 +void LegoJetski::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x100141b0 +MxResult LegoJetski::VTable0x94(LegoPathActor* p_actor, MxBool p_bool) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x100141c0 +void LegoJetski::VTable0x98() +{ + // TODO +} + +// STUB: LEGO1 0x10014200 +MxResult LegoJetski::WaitForAnimation() +{ + // TODO + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/entity/legojetskiraceactor.cpp b/LEGO1/lego/legoomni/src/entity/legojetskiraceactor.cpp new file mode 100644 index 00000000..654c00b1 --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legojetskiraceactor.cpp @@ -0,0 +1,51 @@ +#include "legojetskiraceactor.h" + +DECOMP_SIZE_ASSERT(LegoJetskiRaceActor, 0x1a8) + +// STUB: LEGO1 0x10014220 +void LegoJetskiRaceActor::VTable0x1c() +{ + // TODO +} + +// FUNCTION: LEGO1 0x10080ef0 +LegoJetskiRaceActor::LegoJetskiRaceActor() +{ + m_unk0x10 = 0.95f; + m_unk0x14 = 0.04f; + m_unk0x18 = 0.5f; + m_unk0x150 = 1.5f; +} + +// STUB: LEGO1 0x10081fc0 +MxU32 LegoJetskiRaceActor::VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 +) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x100822c0 +void LegoJetskiRaceActor::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x100822d0 +void LegoJetskiRaceActor::VTable0x98() +{ + // TODO +} + +// STUB: LEGO1 0x100822e0 +MxResult LegoJetskiRaceActor::WaitForAnimation() +{ + // TODO + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/entity/legolocations.cpp b/LEGO1/lego/legoomni/src/entity/legolocations.cpp new file mode 100644 index 00000000..68627a5d --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legolocations.cpp @@ -0,0 +1,975 @@ +#include "legolocations.h" + +DECOMP_SIZE_ASSERT(LegoLocation, 0x60) +DECOMP_SIZE_ASSERT(LegoLocation::Boundary, 0x18) + +// GLOBAL: LEGO1 0x100f4c60 +LegoLocation g_locations[] = { + {0, + "look at origin from z=-8", + 0, + 1.25, + -8, + 0, + 0, + 1, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + FALSE}, + {1, + "LCAMBA1", + 0.852546, + 1.25, + -17.078703, + 0.990515, + 0, + -0.137405, + 0, + 1, + 0, + {"EDG02_13", 2, 0.75, 0, 0.25, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 10240}, + {2, + "LCAMBA2", + 3.505301, + 1.25, + -27.955006, + -0.002102, + 0, + 0.999998, + 0, + 1, + 0, + {"EDG02_37", 2, 0.75, 0, 0.25, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 5120}, + {3, + "LCAMBA3", + -7.472569, + 1.25, + -16.129034, + 1, + 0, + 0.000926, + 0, + 1, + 0, + {"EDG02_26", 0, 0.75, 2, 0.25, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 5120}, + {4, + "LCAMBA4", + 38.55205, + 1.25, + -16.129, + -0.999997, + 0, + 0.002449, + 0, + 1, + 0, + {"EDG00_146", 0, 0.5, 2, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 7680}, + {5, + "LCAMCA1", + -36.778473, + -1.996432, + 30.392212, + 0.001013, + 0, + -0.999999, + 0, + 1, + 0, + {"INT01", 2, 0.5, 6, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {6, + "LCAMCA2", + -36.774277, + -1.996432, + 24.695135, + -0.305789, + 0.001457, + 0.952098, + 0.000446, + 0.999999, + -0.001387, + {"EDG00_104", 0, 0.5, 2, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {7, + "LCAMCA3", + -36.888363, + 0.5625, + 33.169434, + -0.091475, + -0.001896, + 0.995806, + -0.000173, + 0.999998, + 0.001888, + {"EDG02_58", 2, 0.25, 0, 0.75, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {8, + "LCAMGS1", + 27.647768, + 1.25, + -4.07201, + 0, + 0, + 1, + 0, + 1, + 0, + {"EDG02_40", 2, 0.25, 0, 0.25, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 17920}, + {9, + "LCAMGS2", + 25.153421, + 1.25, + 6.101026, + 0, + 0, + -1, + 0, + 1, + 0, + {"INT19", 1, 0.75, 0, 0.75, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {10, + "LCAMGS3", + 29.506308, + 1.25, + -1.23529, + -1, + 0, + 0, + 0, + 1, + 0, + {"EDG00_74", 0, 0.5, 2, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {11, + "LCAMHO1", + 84.22306, + 4.78298, + 29.150623, + 0.779248, + 0, + -0.626715, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 12800}, + {12, + "LCAMHO2", + 90.92687, + 4.78298, + 23.340658, + -0.983254, + 0, + 0.182241, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {13, + "LCAMHO3", + 87.66666, + 4.829471, + 20.905437, + 0.841755, + -0.006868, + 0.539817, + 0.005781, + 0.999976, + 0.003708, + {"EDG02_27", 1, 0.89, 2, 0.89, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {14, + "LCAMHO4", + 86.33506, + 4.814447, + 20.489912, + 0.948965, + 0.035898, + 0.313331, + -0.034088, + 0.999355, + -0.011255, + {"EDG02_27", 1, 0.89, 2, 0.89, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 25600}, + {15, + "LCAMIC1", + 80.11602, + 10.193289, + -17.946644, + 0.664706, + 0, + 0.747105, + 0, + 1, + 0, + {"EDG00_69", 2, 0.5, 0, 0.5, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {16, + "LCAMIC2", + 86.31804, + 10.193289, + -11.24872, + -0.936663, + 0, + -0.350231, + 0, + 1, + 0, + {"EDG02_66", 2, 0.5, 0, 0.5, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {17, + "LCAMIC3", + 86.82608, + 10.193289, + -4.398705, + 0.466761, + 0, + -0.884383, + 0, + 1, + 0, + {"EDG02_68", 0, 0.5, 2, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 5120}, + {18, + "LCAMJA1", + 95.05279, + 1.318484, + -46.451622, + 0.93196, + 0.006837, + 0.362497, + -0.006372, + 0.999977, + -0.002478, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 25600}, + {19, + "LCAMJA2", + 97.214066, + 1.318484, + -49.035267, + -0.892783, + -0.012109, + 0.450324, + -0.010811, + 0.999927, + 0.005453, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {20, + "LCAMJA3", + 94.12146, + 1.25, + -48.242523, + -1, + 0, + -0.000415, + 0, + 1, + 0, + {"INT33", 1, 0.9, 3, 0.9, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {21, + "LCAMJA4", + 95.58649, + 1.17483, + -43.42485, + 0.137268, + 0.010506, + -0.990478, + -0.001442, + 0.999945, + 0.010407, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {22, + "LCAMJA5", + 91.586105, + 1.17483, + -48.882996, + 0.702508, + 0.010117, + 0.711604, + -0.007107, + 0.999949, + -0.007199, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {23, + "LCAMJS1", + 9.885858, + 0.154871, + -54.080086, + 0.573803, + -0.001138, + -0.818993, + 0.000653, + 0.999999, + -0.000932, + {"INT26", 0, 0.5, 3, 0.5, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 25600}, + {24, + "LCAMJS2", + 14.753909, + 0.125, + -55.5238, + -0.789437, + 0, + -0.613832, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 25600}, + {25, + "LCAMJS3", + 12.373611, + 0.925977, + -64.69941, + 0.114162, + 0, + 0.993462, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 25600}, + {26, + "LCAMJS4", + 27.136557, + 1.125, + -41.8613, + -0.187784, + -0.001389, + -0.982209, + -0.000261, + 0.999999, + -0.001364, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {27, + "LCAMMT1", + -63.277508, + 15.25, + 23.717245, + -0.985194, + 0, + 0.171445, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 12800}, + {28, + "LCAMMT2", + -58.28056, + 15.25, + 22.75, + 0.829409, + 0, + -0.558642, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {29, + "LCAMPK1", + 39.875, + 1.25, + -1, + 0.587492, + 0, + -0.80923, + 0, + 1, + 0, + {"EDG00_83", 0, 0.9, 2, 0.9, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 12800}, + {30, + "LCAMPK2", + 63.75, + 1.25, + 15.5625, + -0.968277, + 0, + -0.249878, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {31, + "LCAMPK4", + 49.5625, + 1.25, + 0, + -0.480011, + 0, + -0.877262, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 6400}, + {32, + "LCAMPO1", + -24.38507, + 1.25, + -55.71749, + -1, + 0, + 0.000066, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 5120}, + {33, + "LCAMPO2", + -41.35899, + 1.790912, + -56.728477, + 0.967347, + 0, + 0.253455, + 0, + 1, + 0, + {"EDG00_191", 0, 0.5, 2, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {34, + "LCAMPS1", + 63.1466, + 2.25, + -81.58665, + 0.860361, + 0, + -0.509685, + 0, + 1, + 0, + {"EDG02_40", 0, 0.5, 2, 0.5, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 6400}, + {35, + "LCAMPS2", + 70.99095, + 2.25, + -87.82898, + -0.746009, + 0, + 0.665936, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 6400}, + {36, + "LCAMPS3", + 73.92391, + 2.25, + -71.65845, + -0.480404, + 0, + -0.877047, + 0, + 1, + 0, + {"EDG02_66", 1, 0.15, 2, 0.15, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 6400}, + {37, + "LCAMPS4", + 61.471172, + 1.829919, + -74.37842, + 0.812146, + 0, + -0.583455, + 0, + 1, + 0, + {"EDG02_40", 0, 0.5, 2, 0.5, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {38, + "LCAMPZ1", + -19.517637, + 1.25, + -44.645412, + -0.582251, + 0, + 0.813009, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 20480}, + {39, + "LCAMPZ2", + -21.870003, + 1.25, + -41.47747, + 0.310142, + 0, + 0.95069, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 23040}, + {40, + "LCAMPZ3", + -21.860731, + 1.25, + -41.47234, + 0.877738, + 0, + -0.479141, + 0, + 1, + 0, + {"EDG00_24", 0, 0.9, 2, 0.9, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 25600}, + {41, + "LCAMPZ4", + -20.492962, + 1.25, + -43.951485, + 0, + 0, + 1, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + FALSE}, + {42, + "LCAMPZ5", + -11.0625, + 1.25, + -45.75, + -0.998358, + 0, + -0.057283, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 12800}, + {43, + "LCAMPZ6", + -14.837131, + 1.25, + -41.580185, + -0.485221, + 0, + 0.874392, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {44, + "LCAMPZ7", + -22.17942, + 1.25, + -41.132347, + 0.697186, + 0, + 0.716891, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {45, + "LCAMRA1", + -68.90462, + 10.238018, + -15.521397, + -0.150999, + -0.051266, + -0.987204, + -0.007751, + 0.998685, + -0.050677, + {"EDG00_03", 1, 0.5, 3, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {46, + "LCAMRA2", + -67.931305, + 7.883309, + -28.911201, + -0.596641, + -0.000131, + 0.802509, + -0.000078, + 1, + 0.000105, + {"EDG01_17", 0, 0.5, 3, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 6400}, + {47, + "LCAMRA3", + -57.06778, + 7.883309, + -45.567757, + -0.982252, + -0.000114, + 0.187564, + -0.000112, + 1, + 0.000021, + {"EDG01_40", 2, 0.5, 0, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {48, + "LCAMRA4", + -72.23135, + 7.912604, + -45.26192, + 0.993571, + -0.036148, + -0.10728, + 0.035939, + 0.999346, + -0.00388, + {"EDG01_27", 0, 0.5, 2, 0.5, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 6400}, + {49, + "LCAMRA5", + -84.27638, + 4.683791, + -52.99282, + 0.976109, + -0.025475, + -0.215783, + 0.024875, + 0.999675, + -0.005499, + {"EDG01_08", 2, 0.7, 0, 0.7, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 6400}, + {50, + "LCAMRA6", + -86.96998, + 5.265254, + -16.33013, + -0.999696, + 0.000378, + -0.024655, + 0.000378, + 1, + 0.000009, + {"EDG01_13", 1, 0.2, 0, 0.2, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {51, + "LCAMRT1", + -11.308265, + 1.25, + 9.629765, + 1, + 0, + 0, + 0, + 1, + 0, + {"EDG03_10", 0, 0.5, 2, 0.5, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 20480}, + {52, + "LCAMRT2", + -2.950222, + 1.25, + 12.345603, + 0.816763, + 0, + -0.576974, + 0, + 1, + 0, + {"EDG03_10", 0, 0.5, 2, 0.5, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 25600}, + {53, + "LCAMRT3", + -0.87654, + 1.25, + 11.844613, + 0.006162, + 0, + -0.999981, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 25600}, + {54, + "LCAMRT4", + 0.4375, + 1.25, + 7, + -0.748454, + 0, + -0.663187, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + FALSE}, + {55, + "LCAMRT5", + -27.213715, + 1.25, + 13.280918, + -0.670318, + 0, + -0.742074, + 0, + 1, + 0, + {"EDG03_05", 1, 0.5, 2, 0.5, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {56, + "LCAMRT6", + -21.811115, + 1.25, + 9.006517, + 0.97496, + 0, + 0.222379, + 0, + 1, + 0, + {"EDG03_10", 0, 0.5, 2, 0.5, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 15360}, + {57, + "LCAMST1", + -40.1615, + 2.02756, + -56.701893, + -0.958601, + 0, + -0.284751, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 5120}, + {58, + "LCAMST2", + -48.750553, + 2.703701, + -55.472034, + -0.032008, + 0, + -0.999488, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {59, + "LCAMZG1", + 31.694365, + 1.25, + -2.814015, + -0.650445, + 0, + 0.759553, + 0, + 1, + 0, + {"INT22", 0, 0.4, 2, 0.4, TRUE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {60, + "LCAMZI1", + 93.37283, + 10.1875, + -10.382307, + 0, + 0, + 1, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + FALSE}, + {61, + "LCAMZI2", + 93.37283, + 19.4375, + -10.382307, + 0, + 0, + 1, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + FALSE}, + {62, + "LCAMZIE", + 93.375, + 19.4375, + -10.375, + 0.967075, + -0.254493, + 0, + 0.254493, + 0.967075, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {63, + "LCAMZIN", + 93.37283, + 19.4375, + -10.382307, + 0, + -0.254006, + 0.967203, + 0, + 0.967203, + 0.254006, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {64, + "LCAMZIS", + 93.37283, + 19.4375, + -10.382307, + 0, + -0.254982, + -0.966946, + 0, + 0.966946, + -0.254982, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {65, + "LCAMZIW", + 93.375, + 19.4375, + -10.375, + -0.967075, + -0.254493, + 0, + -0.254493, + 0.967075, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {66, + "LCAMZP1", + 73.70144, + 2.25, + -88.91317, + -0.911398, + 0, + 0.411526, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {67, + "LCAMRT7", + -1.170637, + 1.25, + 5.082029, + -1, + 0, + -0.000599, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 0}, + {68, + "LCAMJS5", + -1.734375, + -0.625, + -61.8125, + -0.454574, + 0, + -0.890709, + 0, + 1, + 0, + {NULL, 0, 0, 0, 0, FALSE}, + {NULL, 0, 0, 0, 0, FALSE}, + 25600}, + {69, "overhead", 0, 135, 0, 0, -1, 0, 0, 0, 1, {NULL, 0, 0, 0, 0, FALSE}, {NULL, 0, 0, 0, 0, FALSE}, 0} +}; diff --git a/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp new file mode 100644 index 00000000..d3d940d3 --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp @@ -0,0 +1,772 @@ +#include "legonavcontroller.h" + +#include "3dmanager/lego3dmanager.h" +#include "infocenterstate.h" +#include "legoanimationmanager.h" +#include "legocameracontroller.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legolocations.h" +#include "legomain.h" +#include "legosoundmanager.h" +#include "legoutils.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxtimer.h" +#include "mxtransitionmanager.h" +#include "mxutilities.h" +#include "realtime/realtime.h" +#include "realtime/realtimeview.h" + +#include + +DECOMP_SIZE_ASSERT(LegoNavController, 0x70) + +////////////////////////////////////////////////////////////////////// + +#ifndef M_PI +#define M_PI 3.1416 +#endif +#ifdef DTOR +#undef DTOR +#endif +#define DTOR(angle) ((angle) * M_PI / 180.) + +////////////////////////////////////////////////////////////////////// + +// GLOBAL: LEGO1 0x100f4c28 +int LegoNavController::g_defdeadZone = 40; + +// GLOBAL: LEGO1 0x100f4c2c +float LegoNavController::g_defzeroThreshold = 0.001f; + +// GLOBAL: LEGO1 0x100f4c30 +float LegoNavController::g_defmaxLinearVel = 40.0f; + +// GLOBAL: LEGO1 0x100f4c34 +float LegoNavController::g_defmaxRotationalVel = 20.0f; + +// GLOBAL: LEGO1 0x100f4c38 +float LegoNavController::g_defmaxLinearAccel = 15.0f; + +// GLOBAL: LEGO1 0x100f4c3c +float LegoNavController::g_defmaxRotationalAccel = 30.0f; + +// GLOBAL: LEGO1 0x100f4c40 +float LegoNavController::g_defminLinearAccel = 4.0f; + +// GLOBAL: LEGO1 0x100f4c44 +float LegoNavController::g_defminRotationalAccel = 15.0f; + +// GLOBAL: LEGO1 0x100f4c48 +float LegoNavController::g_defmaxLinearDeccel = 50.0f; + +// GLOBAL: LEGO1 0x100f4c4c +float LegoNavController::g_defmaxRotationalDeccel = 50.0f; + +// GLOBAL: LEGO1 0x100f4c50 +float LegoNavController::g_defrotSensitivity = 0.4f; + +// GLOBAL: LEGO1 0x100f4c54 +MxBool LegoNavController::g_defuseRotationalVel = FALSE; + +// GLOBAL: LEGO1 0x100f66a0 +MxBool g_unk0x100f66a0 = FALSE; + +// GLOBAL: LEGO1 0x100f66a4 +MxBool g_unk0x100f66a4 = FALSE; + +// GLOBAL: LEGO1 0x100f66b0 +undefined4 g_unk0x100f66b0 = 0; + +// GLOBAL: LEGO1 0x100f66b4 +undefined4 g_unk0x100f66b4 = 0; + +// GLOBAL: LEGO1 0x100f66bc +undefined4 g_unk0x100f66bc = 2; + +// GLOBAL: LEGO1 0x100f66c0 +char g_debugPassword[] = "OGEL"; + +// GLOBAL: LEGO1 0x100f66c8 +char* g_currentInput = g_debugPassword; + +// GLOBAL: LEGO1 0x100f66d0 +MxBool g_musicEnabled = TRUE; + +// GLOBAL: LEGO1 0x100f66d4 +undefined4 g_unk0x100f66d4 = 1; + +// FUNCTION: LEGO1 0x10054ac0 +LegoNavController::LegoNavController() +{ + SetToDefaultParams(); + + m_linearVel = 0.0f; + m_rotationalVel = 0.0f; + m_targetLinearVel = 0.0f; + m_targetRotationalVel = 0.0f; + m_linearAccel = 0.0f; + m_rotationalAccel = 0.0f; + m_trackDefault = FALSE; + m_unk0x5d = FALSE; + m_unk0x6c = FALSE; + m_unk0x64 = 0.0f; + m_unk0x68 = 0.0f; + m_unk0x60 = 0.0f; + + m_lastTime = Timer()->GetTime(); + + InputManager()->Register(this); +} + +// FUNCTION: LEGO1 0x10054c30 +LegoNavController::~LegoNavController() +{ + InputManager()->UnRegister(this); +} + +// FUNCTION: LEGO1 0x10054ca0 +void LegoNavController::SetControlMax(int p_hMax, int p_vMax) +{ + m_hMax = p_hMax; + m_vMax = p_vMax; + + if (VideoManager()->GetVideoParam().Flags().GetFullScreen()) { + m_hMax = 640; + m_vMax = 480; + } +} + +// FUNCTION: LEGO1 0x10054cd0 +void LegoNavController::SetToDefaultParams() +{ + m_deadZone = g_defdeadZone; + m_zeroThreshold = g_defzeroThreshold; + m_maxRotationalAccel = g_defmaxRotationalAccel; + m_maxLinearAccel = g_defmaxLinearAccel; + m_minRotationalAccel = g_defminRotationalAccel; + m_minLinearAccel = g_defminLinearAccel; + m_maxRotationalDeccel = g_defmaxRotationalDeccel; + m_maxLinearDeccel = g_defmaxLinearDeccel; + m_maxRotationalVel = g_defmaxRotationalVel; + m_maxLinearVel = g_defmaxLinearVel; + m_useRotationalVel = g_defuseRotationalVel; + m_rotSensitivity = g_defrotSensitivity; +} + +// FUNCTION: LEGO1 0x10054d40 +void LegoNavController::GetDefaults( + int* p_dz, + float* p_lv, + float* p_rv, + float* p_la, + float* p_ra, + float* p_ld, + float* p_rd, + float* p_lmina, + float* p_rmina, + float* p_rs, + MxBool* p_urs +) +{ + *p_dz = g_defdeadZone; + *p_lv = g_defmaxLinearVel; + *p_rv = g_defmaxRotationalVel; + *p_la = g_defmaxLinearAccel; + *p_ra = g_defmaxRotationalAccel; + *p_ld = g_defmaxLinearDeccel; + *p_rd = g_defmaxRotationalDeccel; + *p_lmina = g_defminLinearAccel; + *p_rmina = g_defminRotationalAccel; + *p_rs = g_defrotSensitivity; + *p_urs = g_defuseRotationalVel; +} + +// FUNCTION: LEGO1 0x10054dd0 +void LegoNavController::SetDefaults( + int p_dz, + float p_lv, + float p_rv, + float p_la, + float p_ra, + float p_ld, + float p_rd, + float p_lmina, + float p_rmina, + float p_rs, + MxBool p_urs +) +{ + g_defdeadZone = p_dz; + g_defmaxLinearVel = p_lv; + g_defmaxRotationalVel = p_rv; + g_defmaxLinearAccel = p_la; + g_defmaxRotationalAccel = p_ra; + g_defmaxLinearDeccel = p_ld; + g_defmaxRotationalDeccel = p_rd; + g_defminLinearAccel = p_lmina; + g_defminRotationalAccel = p_rmina; + g_defrotSensitivity = p_rs; + g_defuseRotationalVel = p_urs; +} + +// FUNCTION: LEGO1 0x10054e40 +void LegoNavController::SetTargets(int p_hPos, int p_vPos, MxBool p_accel) +{ + if (m_trackDefault != FALSE) { + SetToDefaultParams(); + } + + if (p_accel != FALSE) { + m_targetRotationalVel = CalculateNewTargetVel(p_hPos, m_hMax / 2, m_maxRotationalVel); + m_targetLinearVel = CalculateNewTargetVel(m_vMax - p_vPos, m_vMax / 2, m_maxLinearVel); + m_rotationalAccel = CalculateNewAccel(p_hPos, m_hMax / 2, m_maxRotationalAccel, (int) m_minRotationalAccel); + m_linearAccel = CalculateNewAccel(m_vMax - p_vPos, m_vMax / 2, m_maxLinearAccel, (int) m_minLinearAccel); + } + else { + m_targetRotationalVel = 0; + m_targetLinearVel = 0; + m_linearAccel = m_maxLinearDeccel; + m_rotationalAccel = m_maxRotationalDeccel; + } +} + +// FUNCTION: LEGO1 0x10054f10 +float LegoNavController::CalculateNewTargetVel(int p_pos, int p_center, float p_max) +{ + float newVel; + int diff = p_pos - p_center; + + if (diff > m_deadZone) { + newVel = (diff - m_deadZone) * p_max / (p_center - m_deadZone); + } + else if (diff < -m_deadZone) { + newVel = (diff + m_deadZone) * p_max / (p_center - m_deadZone); + } + else { + newVel = 0.0; + } + + return newVel; +} + +// FUNCTION: LEGO1 0x10054f90 +float LegoNavController::CalculateNewAccel(int p_pos, int p_center, float p_max, int p_min) +{ + float newAccel; + int diff = p_pos - p_center; + + newAccel = Abs(diff) * p_max / p_center; + + if (newAccel < p_min) { + newAccel = (float) p_min; + } + + return newAccel; +} + +// FUNCTION: LEGO1 0x10054fe0 +float LegoNavController::CalculateNewVel(float p_targetVel, float p_currentVel, float p_accel, float p_time) +{ + float newVel = p_currentVel; + + float velDiff = p_targetVel - p_currentVel; + int vSign = velDiff > 0 ? 1 : -1; + + if (Abs(velDiff) > m_zeroThreshold) { + float deltaVel = p_accel * p_time; + newVel = p_currentVel + (deltaVel * vSign); + + if (vSign > 0) { + newVel = Min(newVel, p_targetVel); + } + else { + newVel = Max(newVel, p_targetVel); + } + } + + return newVel; +} + +// FUNCTION: LEGO1 0x10055080 +MxBool LegoNavController::CalculateNewPosDir( + const Vector3& p_curPos, + const Vector3& p_curDir, + Vector3& p_newPos, + Vector3& p_newDir, + const Vector3* p_und +) +{ + if (!g_isWorldActive) { + return FALSE; + } + + MxBool changed = FALSE; + MxBool und = FALSE; + + MxTime currentTime = Timer()->GetTime(); + float deltaTime = (currentTime - m_lastTime) / 1000.0; + m_lastTime = currentTime; + + if (ProcessKeyboardInput() == FAILURE) { + ProcessJoystickInput(und); + } + + if (m_useRotationalVel) { + m_rotationalVel = CalculateNewVel(m_targetRotationalVel, m_rotationalVel, m_rotationalAccel * 40.0f, deltaTime); + } + else { + m_rotationalVel = m_targetRotationalVel; + } + + m_linearVel = CalculateNewVel(m_targetLinearVel, m_linearVel, m_linearAccel, deltaTime); + + if (und || (Abs(m_rotationalVel) > m_zeroThreshold) || (Abs(m_linearVel) > m_zeroThreshold)) { + float rot_mat[3][3]; + Mx3DPointFloat delta_pos, new_dir, new_pos; + + if (m_linearVel < -(m_maxLinearVel * 0.4f)) { + m_linearVel = -(m_maxLinearVel * 0.4f); + } + + VXS3(delta_pos, p_curDir, m_linearVel * deltaTime); + VPV3(p_newPos, p_curPos, delta_pos); + + float delta_rad; + if (m_useRotationalVel) { + delta_rad = DTOR(m_rotationalVel * deltaTime); + } + else { + delta_rad = DTOR(m_rotationalVel * m_rotSensitivity); + } + + if (p_und != NULL && (*p_und)[1] < 0.0f) { + delta_rad = -delta_rad; + } + + IDENTMAT3(rot_mat); + rot_mat[0][0] = rot_mat[2][2] = cos(delta_rad); + rot_mat[0][2] = rot_mat[2][0] = sin(delta_rad); + rot_mat[0][2] *= -1.0f; + VXM3(p_newDir, p_curDir, rot_mat); + + changed = TRUE; + } + + if (m_unk0x5d) { + float rot_mat[3][3]; + Mx3DPointFloat delta_pos, new_pos, new_dir; + + if (changed) { + SET3(new_pos, p_newPos); + SET3(new_dir, p_newDir); + } + else { + SET3(new_pos, p_curPos); + SET3(new_dir, p_curDir); + } + + if (m_unk0x64 != 0.0f) { + delta_pos[0] = new_dir[0] * m_unk0x64; + delta_pos[1] = new_dir[1] * m_unk0x64; + delta_pos[2] = new_dir[2] * m_unk0x64; + } + else { + FILLVEC3(delta_pos, 0.0f); + } + + delta_pos[1] += m_unk0x60; + VPV3(p_newPos, new_pos, delta_pos); + + if (m_unk0x68 != 0.0f) { + float delta_rad = DTOR(m_unk0x68); + IDENTMAT3(rot_mat); + rot_mat[0][0] = rot_mat[2][2] = cos(delta_rad); + rot_mat[0][2] = rot_mat[2][0] = sin(delta_rad); + rot_mat[0][2] *= -1.0f; + VXM3(p_newDir, new_dir, rot_mat); + } + else { + SET3(p_newDir, new_dir); + } + + m_unk0x60 = m_unk0x64 = m_unk0x68 = 0.0f; + m_unk0x5d = FALSE; + changed = TRUE; + } + + return changed; +} + +// FUNCTION: LEGO1 0x10055500 +MxResult LegoNavController::UpdateLocation(const char* p_location) +{ + MxResult result = FAILURE; + + for (MxS32 i = 0; i < (MxS32) sizeOfArray(g_locations); i++) { + if (!strcmpi(p_location, g_locations[i].m_name)) { + MxMatrix mat; + LegoROI* viewROI = VideoManager()->GetViewROI(); + + CalcLocalTransform(g_locations[i].m_position, g_locations[i].m_direction, g_locations[i].m_up, mat); + + Mx3DPointFloat vec; + vec.Clear(); + + viewROI->FUN_100a5a30(vec); + viewROI->WrappedSetLocalTransform(mat); + VideoManager()->Get3DManager()->Moved(*viewROI); + + SoundManager()->FUN_1002a410( + viewROI->GetWorldPosition(), + viewROI->GetWorldDirection(), + viewROI->GetWorldUp(), + viewROI->GetWorldVelocity() + ); + + result = SUCCESS; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x10055620 +MxResult LegoNavController::UpdateLocation(MxU32 p_location) +{ + MxResult result = FAILURE; + + if (p_location < sizeOfArray(g_locations)) { + MxMatrix mat; + LegoROI* viewROI = VideoManager()->GetViewROI(); + + CalcLocalTransform( + g_locations[p_location].m_position, + g_locations[p_location].m_direction, + g_locations[p_location].m_up, + mat + ); + + Mx3DPointFloat vec; + vec.Clear(); + + viewROI->FUN_100a5a30(vec); + viewROI->WrappedSetLocalTransform(mat); + VideoManager()->Get3DManager()->Moved(*viewROI); + + SoundManager()->FUN_1002a410( + viewROI->GetWorldPosition(), + viewROI->GetWorldDirection(), + viewROI->GetWorldUp(), + viewROI->GetWorldVelocity() + ); + + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x10055720 +// FUNCTION: BETA10 0x1009c259 +LegoLocation* LegoNavController::GetLocation(MxU32 p_location) +{ + if (p_location < sizeOfArray(g_locations)) { + return &g_locations[p_location]; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10055750 +MxResult LegoNavController::ProcessJoystickInput(MxBool& p_und) +{ + LegoOmni* instance = LegoOmni::GetInstance(); + + if (instance->GetInputManager()) { + MxS32 joystickX; + MxS32 joystickY; + DWORD buttonState; + MxS32 povPosition; + + if (instance->GetInputManager() + ->GetJoystickState((MxU32*) &joystickX, (MxU32*) &joystickY, &buttonState, (MxU32*) &povPosition) != + FAILURE) { + MxU32 yVal = (joystickY * m_vMax) / 100; + MxU32 xVal = (joystickX * m_hMax) / 100; + + if (joystickX <= 45 || joystickX >= 55 || joystickY <= 45 || joystickY >= 55) { + m_targetLinearVel = CalculateNewTargetVel(m_vMax - yVal, m_vMax / 2, m_maxLinearVel); + m_linearAccel = CalculateNewAccel(m_vMax - yVal, m_vMax / 2, m_maxLinearAccel, (int) m_minLinearAccel); + m_targetRotationalVel = CalculateNewTargetVel(xVal, m_hMax / 2, m_maxRotationalVel); + m_rotationalAccel = + CalculateNewAccel(xVal, m_hMax / 2, m_maxRotationalAccel, (int) m_minRotationalAccel); + } + else { + m_targetRotationalVel = 0.0; + m_targetLinearVel = 0.0; + m_linearAccel = m_maxLinearDeccel; + m_rotationalAccel = m_maxRotationalDeccel; + } + + if (povPosition >= 0) { + LegoWorld* world = CurrentWorld(); + + if (world && world->GetCamera()) { + world->GetCamera()->FUN_10012320(DTOR(povPosition)); + p_und = TRUE; + } + } + + return SUCCESS; + } + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x100558b0 +MxResult LegoNavController::ProcessKeyboardInput() +{ + MxBool bool1 = FALSE; + MxBool bool2 = FALSE; + LegoInputManager* inputManager = LegoOmni::GetInstance()->GetInputManager(); + MxU32 keyFlags; + + if (inputManager == NULL || inputManager->FUN_1005c160(keyFlags) == FAILURE) { + return FAILURE; + } + + if (keyFlags == 0) { + if (m_unk0x6c) { + m_targetRotationalVel = 0.0; + m_targetLinearVel = 0.0; + m_rotationalAccel = m_maxRotationalDeccel; + m_linearAccel = m_maxLinearDeccel; + m_unk0x6c = FALSE; + } + + return FAILURE; + } + + m_unk0x6c = TRUE; + + MxS32 hMax; + if ((keyFlags & LegoInputManager::c_leftOrRight) == LegoInputManager::c_left) { + hMax = 0; + } + else if ((keyFlags & LegoInputManager::c_leftOrRight) == LegoInputManager::c_right) { + hMax = m_hMax; + } + else { + m_targetRotationalVel = 0.0; + m_rotationalAccel = m_maxRotationalDeccel; + bool1 = TRUE; + } + + MxS32 vMax; + if ((keyFlags & LegoInputManager::c_upOrDown) == LegoInputManager::c_up) { + vMax = 0; + } + else if ((keyFlags & LegoInputManager::c_upOrDown) == LegoInputManager::c_down) { + vMax = m_vMax; + } + else { + m_targetLinearVel = 0.0; + m_linearAccel = m_maxLinearDeccel; + bool2 = TRUE; + } + + MxFloat val = keyFlags & 0x10 ? 1.0f : 4.0f; + MxFloat val2 = keyFlags & 0x10 ? 1.0f : 2.0f; + + if (!bool1) { + m_targetRotationalVel = CalculateNewTargetVel(hMax, m_hMax / 2, m_maxRotationalVel); + m_rotationalAccel = + CalculateNewAccel(hMax, m_hMax / 2, m_maxRotationalAccel / val, (int) (m_minRotationalAccel / val2)); + } + + if (!bool2) { + m_targetLinearVel = CalculateNewTargetVel(m_vMax - vMax, m_vMax / 2, m_maxLinearVel); + m_linearAccel = + CalculateNewAccel(m_vMax - vMax, m_vMax / 2, m_maxLinearAccel / val, (int) (m_minLinearAccel / val2)); + } + + return SUCCESS; +} + +// STUB: LEGO1 0x10055a60 +MxLong LegoNavController::Notify(MxParam& p_param) +{ + if (((MxNotificationParam&) p_param).GetType() == c_notificationKeyPress) { + m_unk0x5d = TRUE; + + switch (((LegoEventNotificationParam&) p_param).GetKey()) { + case VK_PAUSE: + if (Lego()->IsTimerRunning()) { + Lego()->StopTimer(); + } + else { + Lego()->StartTimer(); + } + break; + case VK_ESCAPE: { + LegoWorld* currentWorld = CurrentWorld(); + + if (currentWorld) { + InfocenterState* infocenterState = (InfocenterState*) GameState()->GetState("InfocenterState"); + if (infocenterState && infocenterState->GetUnknown0x74() != 8 && currentWorld->VTable0x64()) { + BackgroundAudioManager()->Stop(); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + infocenterState->SetUnknown0x74(8); + } + } + break; + } + case VK_SPACE: + AnimationManager()->FUN_10061010(TRUE); + break; + case 'Z': + // TODO + break; + case 'k': + case 'm': + // TODO + break; + case '{': { + InfocenterState* infocenterState = (InfocenterState*) GameState()->GetState("InfocenterState"); + if (infocenterState && infocenterState->HasRegistered()) { + GameState()->Save(0); + } + break; + } + default: + // Check if the the key is part of the debug password + if (!*g_currentInput) { + // password "protected" debug shortcuts + switch (((LegoEventNotificationParam&) p_param).GetKey()) { + case VK_TAB: + VideoManager()->ToggleFPS(g_unk0x100f66d4); + if (g_unk0x100f66d4 == 0) { + g_unk0x100f66d4 = 1; + m_unk0x5d = FALSE; + break; + } + else { + g_unk0x100f66d4 = 0; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + // TODO + break; + case 'A': + if (g_unk0x100f66b0 == 1) { + Lego()->SetUnknown13c(TRUE); + AnimationManager()->FUN_10060570(1); + g_unk0x100f66b0 = 0; + } + else { + LegoWorld* world = CurrentWorld(); + if (world) { + MxDSAction action; + action.SetObjectId(1); + action.SetAtomId(world->GetAtom()); + LegoOmni::GetInstance()->Start(&action); + } + } + break; + case 'C': + g_unk0x100f66a4 = TRUE; + break; + case 'D': + m_unk0x60 = -1.0; + break; + case 'F': + RealtimeView::SetUserMaxLOD(0.0); + break; + case 'G': + g_unk0x100f66b4 = 1; + break; + case 'H': + RealtimeView::SetUserMaxLOD(5.0); + break; + case 'I': + // TODO + break; + case 'J': + // TODO + break; + case 'K': + // TODO + break; + case 'L': + g_unk0x100f66a0 = TRUE; + break; + case 'M': + // TODO + break; + case 'N': + if (VideoManager()) { + VideoManager()->SetRender3D(!VideoManager()->GetRender3D()); + } + break; + case 'P': + // TODO + break; + case 'S': + BackgroundAudioManager()->Enable(!g_musicEnabled); + break; + case 'U': + m_unk0x60 = 1.0; + break; + case 'V': + // TODO + case 'W': + // TODO + break; + case 'X': + RealtimeView::SetUserMaxLOD(3.6); + break; + case 'j': + // TODO + break; + case 'o': + GameState()->SetActorId(6); + break; + case 0xbd: + g_unk0x100f66bc = 1; + break; + default: + m_unk0x5d = FALSE; + break; + } + } + else { + if (*g_currentInput == ((LegoEventNotificationParam&) p_param).GetKey()) { + g_currentInput++; + break; + } + else { + g_currentInput = g_debugPassword; + break; + } + } + break; + } + } + + return 0; +} diff --git a/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp b/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp new file mode 100644 index 00000000..0575056d --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legopovcontroller.cpp @@ -0,0 +1,217 @@ +#include "3dmanager/lego3dview.h" +#include "legoentity.h" +#include "legomain.h" +#include "legonavcontroller.h" +#include "legopointofviewcontroller.h" +#include "legosoundmanager.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "realtime/realtime.h" +#include "roi/legoroi.h" + +DECOMP_SIZE_ASSERT(LegoMouseController, 0x20) +DECOMP_SIZE_ASSERT(LegoPointOfViewController, 0x38) + +// GLOBAL: LEGO1 0x100f75ac +MxBool g_unk0x100f75ac = FALSE; + +////////////////////////////////////////////////////////////////////// + +// FUNCTION: LEGO1 0x10065550 +LegoMouseController::LegoMouseController() +{ + m_isButtonDown = FALSE; +} + +// FUNCTION: LEGO1 0x100655d0 +LegoMouseController::~LegoMouseController() +{ +} + +// FUNCTION: LEGO1 0x10065620 +void LegoMouseController::LeftDown(int p_x, int p_y) +{ + m_isButtonDown = TRUE; + m_buttonX = p_x; + m_buttonY = p_y; +} + +// FUNCTION: LEGO1 0x10065640 +void LegoMouseController::LeftUp(int p_x, int p_y) +{ + m_isButtonDown = FALSE; + m_buttonX = p_x; + m_buttonY = p_y; +} + +// FUNCTION: LEGO1 0x10065660 +void LegoMouseController::LeftDrag(int p_x, int p_y) +{ + m_buttonX = p_x; + m_buttonY = p_y; +} + +// FUNCTION: LEGO1 0x10065680 +void LegoMouseController::RightDown(int p_x, int p_y) +{ + m_isButtonDown = TRUE; + m_buttonX = p_x; + m_buttonY = p_y; +} + +// FUNCTION: LEGO1 0x100656a0 +void LegoMouseController::RightUp(int p_x, int p_y) +{ + m_isButtonDown = FALSE; + m_buttonX = p_x; + m_buttonY = p_y; +} + +// FUNCTION: LEGO1 0x100656c0 +void LegoMouseController::RightDrag(int p_x, int p_y) +{ + m_buttonX = p_x; + m_buttonY = p_y; +} + +////////////////////////////////////////////////////////////////////// + +// FUNCTION: LEGO1 0x100656e0 +LegoPointOfViewController::LegoPointOfViewController() +{ + m_lego3DView = NULL; + m_entity = NULL; + m_nav = NULL; + // m_entityOffsetUp is a temporary kludge. It should be replaced + // by 3D camera offset and position stored in the entity since each + // entity may have a different best viewpoint. + m_entityOffsetUp = 0.0; +} + +// FUNCTION: LEGO1 0x10065770 +LegoPointOfViewController::~LegoPointOfViewController() +{ + TickleManager()->UnregisterClient(this); + if (m_nav) { + delete m_nav; + m_nav = NULL; + } +} + +// FUNCTION: LEGO1 0x100657f0 +MxResult LegoPointOfViewController::Create(Lego3DView* p_lego3DView) +{ + m_lego3DView = p_lego3DView; + m_nav = new LegoNavController(); + LegoOmni::GetInstance()->SetNavController(m_nav); + m_nav->SetTrackDefaultParams(TRUE); + TickleManager()->RegisterClient(this, 10); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100658a0 +void LegoPointOfViewController::OnViewSize(int p_width, int p_height) +{ + m_nav->SetControlMax(p_width, p_height); +} + +// FUNCTION: LEGO1 0x100658c0 +void LegoPointOfViewController::LeftDown(int p_x, int p_y) +{ + LegoMouseController::LeftDown(p_x, p_y); + AffectPointOfView(); +} + +// FUNCTION: LEGO1 0x100658e0 +void LegoPointOfViewController::LeftDrag(int p_x, int p_y) +{ + LegoMouseController::LeftDrag(p_x, p_y); + AffectPointOfView(); +} + +// FUNCTION: LEGO1 0x10065900 +void LegoPointOfViewController::AffectPointOfView() +{ + m_nav->SetTargets(GetButtonX(), GetButtonY(), GetIsButtonDown()); +} + +// FUNCTION: LEGO1 0x10065930 +MxResult LegoPointOfViewController::Tickle() +{ + ViewROI* pov = m_lego3DView->GetPointOfView(); + + if (pov != NULL && m_nav != NULL && m_entity == NULL) { + Mx3DPointFloat newDir, newPos; + + Vector3 pos(pov->GetWorldPosition()); + Vector3 dir(pov->GetWorldDirection()); + + if (m_nav->CalculateNewPosDir(pos, dir, newPos, newDir, NULL)) { + MxMatrix mat; + + CalcLocalTransform(newPos, newDir, pov->GetWorldUp(), mat); + ((TimeROI*) pov)->FUN_100a9b40(mat, Timer()->GetTime()); + pov->WrappedSetLocalTransform(mat); + m_lego3DView->Moved(*pov); + + SoundManager()->FUN_1002a410( + pov->GetWorldPosition(), + pov->GetWorldDirection(), + pov->GetWorldUp(), + pov->GetWorldVelocity() + ); + + g_unk0x100f75ac = FALSE; + } + else { + if (g_unk0x100f75ac == FALSE) { + Mx3DPointFloat vel; + + vel.Clear(); + pov->FUN_100a5a30(vel); + + SoundManager()->FUN_1002a410( + pov->GetWorldPosition(), + pov->GetWorldDirection(), + pov->GetWorldUp(), + pov->GetWorldVelocity() + ); + + g_unk0x100f75ac = TRUE; + } + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10065ae0 +void LegoPointOfViewController::SetEntity(LegoEntity* p_entity) +{ + TickleManager()->UnregisterClient(this); + m_entity = p_entity; + + ViewROI* pov = m_lego3DView->GetPointOfView(); + + if (m_entity != NULL && pov != NULL) { + MxMatrix mat; + + CalcLocalTransform( + Mx3DPointFloat( + m_entity->GetWorldPosition()[0], + m_entity->GetWorldPosition()[1] + m_entityOffsetUp, + m_entity->GetWorldPosition()[2] + ), + m_entity->GetWorldDirection(), + m_entity->GetWorldUp(), + mat + ); + + pov->WrappedSetLocalTransform(mat); + } + else { + TickleManager()->RegisterClient(this, 10); + } +} diff --git a/LEGO1/lego/legoomni/src/entity/legoworld.cpp b/LEGO1/lego/legoomni/src/entity/legoworld.cpp new file mode 100644 index 00000000..0455f1a7 --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legoworld.cpp @@ -0,0 +1,831 @@ +#include "legoworld.h" + +#include "anim/legoanim.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legoanimpresenter.h" +#include "legobuildingmanager.h" +#include "legocachesoundmanager.h" +#include "legocameracontroller.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legolocomotionanimpresenter.h" +#include "legomain.h" +#include "legonavcontroller.h" +#include "legoplantmanager.h" +#include "legosoundmanager.h" +#include "legoutils.h" +#include "legovideomanager.h" +#include "misc.h" +#include "mxactionnotificationparam.h" +#include "mxcontrolpresenter.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxnotificationparam.h" +#include "mxticklemanager.h" +#include "mxutilities.h" +#include "viewmanager/viewmanager.h" + +DECOMP_SIZE_ASSERT(LegoWorld, 0xf8) +DECOMP_SIZE_ASSERT(LegoEntityList, 0x18) +DECOMP_SIZE_ASSERT(LegoEntityListCursor, 0x10) +DECOMP_SIZE_ASSERT(LegoCacheSoundList, 0x18) +DECOMP_SIZE_ASSERT(LegoCacheSoundListCursor, 0x10) + +// FUNCTION: LEGO1 0x1001ca40 +LegoWorld::LegoWorld() : m_list0x68(TRUE) +{ + m_startupTicks = e_four; + m_cameraController = NULL; + m_entityList = NULL; + m_cacheSoundList = NULL; + m_destroyed = FALSE; + m_hideAnimPresenter = NULL; + m_worldStarted = FALSE; + + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x1001d670 +MxBool LegoWorld::VTable0x5c() +{ + return FALSE; +} + +// FUNCTION: LEGO1 0x1001d680 +MxBool LegoWorld::VTable0x64() +{ + return FALSE; +} + +// FUNCTION: LEGO1 0x1001dfa0 +LegoWorld::~LegoWorld() +{ + Destroy(TRUE); + + TickleManager()->UnregisterClient(this); + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x1001e0b0 +MxResult LegoWorld::Create(MxDSAction& p_dsAction) +{ + MxEntity::Create(p_dsAction); + + m_entityList = new LegoEntityList(TRUE); + + if (!m_entityList) { + return FAILURE; + } + + m_cacheSoundList = new LegoCacheSoundList(TRUE); + + if (!m_cacheSoundList) { + return FAILURE; + } + + if (!VTable0x54()) { + return FAILURE; + } + + if (p_dsAction.GetFlags() & MxDSAction::c_enabled) { + if (CurrentWorld()) { + CurrentWorld()->Enable(FALSE); + } + + SetCurrentWorld(this); + ControlManager()->FUN_10028df0(&m_controlPresenters); + } + + SetIsWorldActive(TRUE); + m_scriptIndex = -1; + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1001e9d0 +void LegoWorld::Destroy(MxBool p_fromDestructor) +{ + m_destroyed = TRUE; + + if (CurrentWorld() == this) { + ControlManager()->FUN_10028df0(NULL); + SetCurrentWorld(NULL); + } + + m_list0x68.DeleteAll(); + + if (m_cameraController) { + delete m_cameraController; + m_cameraController = NULL; + } + + MxPresenterListCursor animPresenterCursor(&m_animPresenters); + MxPresenter* presenter; + + while (animPresenterCursor.First(presenter)) { + animPresenterCursor.Detach(); + + MxDSAction* action = presenter->GetAction(); + if (action) { + if (presenter->IsA("LegoLocomotionAnimPresenter")) { + LegoLocomotionAnimPresenter* animPresenter = (LegoLocomotionAnimPresenter*) presenter; + + animPresenter->DecrementUnknown0xd4(); + if (animPresenter->GetUnknown0xd4() == 0) { + FUN_100b7220(action, MxDSAction::c_world, FALSE); + presenter->EndAction(); + } + } + else { + FUN_100b7220(action, MxDSAction::c_world, FALSE); + presenter->EndAction(); + } + } + } + + while (!m_set0xa8.empty()) { + MxCoreSet::iterator it = m_set0xa8.begin(); + MxCore* object = *it; + m_set0xa8.erase(it); + + if (object->IsA("MxPresenter")) { + MxPresenter* presenter = (MxPresenter*) object; + MxDSAction* action = presenter->GetAction(); + + if (action) { + FUN_100b7220(action, MxDSAction::c_world, FALSE); + presenter->EndAction(); + } + } + else { + delete object; + } + } + + MxPresenterListCursor controlPresenterCursor(&m_controlPresenters); + + while (controlPresenterCursor.First(presenter)) { + controlPresenterCursor.Detach(); + + MxDSAction* action = presenter->GetAction(); + if (action) { + FUN_100b7220(action, MxDSAction::c_world, FALSE); + presenter->EndAction(); + } + } + + if (m_scriptIndex != -1 && m_set0xd0.empty()) { + PlantManager()->FUN_100263a0(m_scriptIndex); + BuildingManager()->FUN_1002fb30(); + } + + if (m_entityList) { + LegoEntityListCursor cursor(m_entityList); + LegoEntity* entity; + + while (cursor.First(entity)) { + cursor.Detach(); + + if (!(entity->GetFlags() & LegoEntity::c_bit2)) { + delete entity; + } + } + + delete m_entityList; + m_entityList = NULL; + } + + if (m_cacheSoundList) { + LegoCacheSoundListCursor cursor(m_cacheSoundList); + LegoCacheSound* sound; + + while (cursor.First(sound)) { + cursor.Detach(); + SoundManager()->GetCacheSoundManager()->FUN_1003dc40(&sound); + } + + delete m_cacheSoundList; + m_cacheSoundList = NULL; + } + + while (!m_roiList.empty()) { + LegoROI* roi = m_roiList.front(); + m_roiList.pop_front(); + delete roi; + } + + if (!p_fromDestructor) { + LegoEntity::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x1001f5e0 +MxLong LegoWorld::Notify(MxParam& p_param) +{ + MxLong ret = 0; + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationEndAction: { + MxPresenter* presenter = (MxPresenter*) ((MxEndActionNotificationParam&) p_param).GetSender(); + Remove(presenter); + ret = 1; + break; + } + case c_notificationNewPresenter: + TickleManager()->RegisterClient(this, 100); + break; + } + return ret; +} + +// FUNCTION: LEGO1 0x1001f630 +LegoCameraController* LegoWorld::VTable0x54() +{ + MxBool success = FALSE; + + if (!VideoManager()) { + goto done; + } + if (!(m_cameraController = new LegoCameraController())) { + goto done; + } + if (m_cameraController->Create() != SUCCESS) { + goto done; + } + + m_cameraController->OnViewSize( + VideoManager()->GetVideoParam().GetRect().GetWidth(), + VideoManager()->GetVideoParam().GetRect().GetHeight() + ); + + success = TRUE; + +done: + if (!success) { + if (m_cameraController) { + delete m_cameraController; + m_cameraController = NULL; + } + } + + return m_cameraController; +} + +// FUNCTION: LEGO1 0x1001f720 +// FUNCTION: BETA10 0x100da24b +MxResult LegoWorld::PlaceActor( + LegoPathActor* p_actor, + const char* p_name, + MxS32 p_src, + float p_srcScale, + MxS32 p_dest, + float p_destScale +) +{ + LegoPathControllerListCursor cursor(&m_list0x68); + LegoPathController* controller; + + while (cursor.Next(controller)) { + if (controller->FUN_10045c20(p_actor, p_name, p_src, p_srcScale, p_dest, p_destScale) == SUCCESS) { + return SUCCESS; + } + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x1001fa70 +MxResult LegoWorld::AddPathActor(LegoPathActor* p_actor) +{ + LegoPathControllerListCursor cursor(&m_list0x68); + LegoPathController* controller; + + while (cursor.Next(controller)) { + if (controller->AddActor(p_actor) == SUCCESS) { + return SUCCESS; + } + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x1001fb70 +MxResult LegoWorld::FUN_1001fb70( + LegoPathActor* p_actor, + LegoAnimPresenter* p_presenter, + Vector3& p_position, + Vector3& p_direction +) +{ + LegoPathControllerListCursor cursor(&m_list0x68); + LegoPathController* controller; + + while (cursor.Next(controller)) { + if (controller->FUN_10046050(p_actor, p_presenter, p_position, p_direction) == SUCCESS) { + return SUCCESS; + } + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x1001fc80 +void LegoWorld::RemovePathActor(LegoPathActor* p_actor) +{ + LegoPathControllerListCursor cursor(&m_list0x68); + LegoPathController* controller; + + while (cursor.Next(controller)) { + if (controller->RemoveActor(p_actor) == SUCCESS) { + break; + } + } +} + +// FUNCTION: LEGO1 0x1001fda0 +// FUNCTION: BETA10 0x100da621 +void LegoWorld::FUN_1001fda0(LegoAnimPresenter* p_presenter) +{ + LegoPathControllerListCursor cursor(&m_list0x68); + LegoPathController* controller; + + while (cursor.Next(controller)) { + controller->FUN_100468f0(p_presenter); + } +} + +// FUNCTION: LEGO1 0x1001fe90 +// FUNCTION: BETA10 0x100da6b5 +void LegoWorld::FUN_1001fe90(LegoAnimPresenter* p_presenter) +{ + LegoPathControllerListCursor cursor(&m_list0x68); + LegoPathController* controller; + + while (cursor.Next(controller)) { + controller->FUN_10046930(p_presenter); + } +} + +// FUNCTION: LEGO1 0x1001ff80 +void LegoWorld::AddPath(LegoPathController* p_controller) +{ + p_controller->FUN_10046bb0(this); + m_list0x68.Append(p_controller); +} + +// FUNCTION: LEGO1 0x10020020 +LegoPathBoundary* LegoWorld::FindPathBoundary(const char* p_name) +{ + LegoPathControllerListCursor cursor(&m_list0x68); + LegoPathController* controller; + + while (cursor.Next(controller)) { + LegoPathBoundary* boundary = controller->GetPathBoundary(p_name); + + if (boundary) { + return boundary; + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10020120 +MxResult LegoWorld::GetCurrPathInfo(LegoPathBoundary** p_boundaries, MxS32& p_numL) +{ + LegoPathControllerListCursor cursor(&m_list0x68); + LegoPathController* controller; + + cursor.Next(controller); + + if (!controller) { + return FAILURE; + } + + return controller->FUN_10046b30(*p_boundaries, p_numL); +} + +// FUNCTION: LEGO1 0x10020220 +void LegoWorld::Add(MxCore* p_object) +{ + if (p_object && !p_object->IsA("LegoWorld") && !p_object->IsA("LegoWorldPresenter")) { + if (p_object->IsA("LegoAnimPresenter")) { + LegoAnimPresenter* animPresenter = (LegoAnimPresenter*) p_object; + + if (!strcmpi(animPresenter->GetAction()->GetObjectName(), "ConfigAnimation")) { + FUN_1003e050(animPresenter); + animPresenter->GetAction()->SetDuration(animPresenter->GetAnimation()->GetDuration()); + } + } + + if (p_object->IsA("MxControlPresenter")) { + MxPresenterListCursor cursor(&m_controlPresenters); + + if (cursor.Find((MxPresenter*) p_object)) { + return; + } + + m_controlPresenters.Append((MxPresenter*) p_object); + } + else if (p_object->IsA("MxEntity")) { + LegoEntityListCursor cursor(m_entityList); + + if (cursor.Find((LegoEntity*) p_object)) { + return; + } + + m_entityList->Append((LegoEntity*) p_object); + } + else if (p_object->IsA("LegoLocomotionAnimPresenter") || p_object->IsA("LegoHideAnimPresenter") || p_object->IsA("LegoLoopingAnimPresenter")) { + MxPresenterListCursor cursor(&m_animPresenters); + + if (cursor.Find((MxPresenter*) p_object)) { + return; + } + + ((MxPresenter*) p_object)->SendToCompositePresenter(Lego()); + m_animPresenters.Append(((MxPresenter*) p_object)); + + if (p_object->IsA("LegoHideAnimPresenter")) { + m_hideAnimPresenter = (LegoHideAnimPresenter*) p_object; + } + } + else if (p_object->IsA("LegoCacheSound")) { + LegoCacheSoundListCursor cursor(m_cacheSoundList); + + if (cursor.Find((LegoCacheSound*) p_object)) { + return; + } + + m_cacheSoundList->Append((LegoCacheSound*) p_object); + } + else { + if (m_set0xa8.find(p_object) == m_set0xa8.end()) { + m_set0xa8.insert(p_object); + } + } + + if (!m_set0xd0.empty() && p_object->IsA("MxPresenter")) { + if (((MxPresenter*) p_object)->IsEnabled()) { + ((MxPresenter*) p_object)->Enable(FALSE); + m_set0xd0.insert(p_object); + } + } + } +} + +// FUNCTION: LEGO1 0x10020f10 +void LegoWorld::Remove(MxCore* p_object) +{ + if (p_object) { + MxCoreSet::iterator it; + + if (p_object->IsA("MxControlPresenter")) { + MxPresenterListCursor cursor(&m_controlPresenters); + + if (cursor.Find((MxControlPresenter*) p_object)) { + cursor.Detach(); + ((MxControlPresenter*) p_object)->GetAction()->SetOrigin(Lego()); + ((MxControlPresenter*) p_object)->VTable0x68(TRUE); + } + } + else if (p_object->IsA("LegoLocomotionAnimPresenter") || p_object->IsA("LegoHideAnimPresenter") || p_object->IsA("LegoLoopingAnimPresenter")) { + MxPresenterListCursor cursor(&m_animPresenters); + + if (cursor.Find((MxPresenter*) p_object)) { + cursor.Detach(); + } + + if (p_object->IsA("LegoHideAnimPresenter")) { + m_hideAnimPresenter = NULL; + } + } + else if (p_object->IsA("MxEntity")) { + if (p_object->IsA("LegoPathActor")) { + RemovePathActor((LegoPathActor*) p_object); + } + + if (m_entityList) { + LegoEntityListCursor cursor(m_entityList); + + if (cursor.Find((LegoEntity*) p_object)) { + cursor.Detach(); + } + } + } + else if (p_object->IsA("LegoCacheSound")) { + LegoCacheSoundListCursor cursor(m_cacheSoundList); + + if (cursor.Find((LegoCacheSound*) p_object)) { + cursor.Detach(); + } + } + else { + it = m_set0xa8.find(p_object); + if (it != m_set0xa8.end()) { + m_set0xa8.erase(it); + } + } + + it = m_set0xd0.find(p_object); + if (it != m_set0xd0.end()) { + m_set0xd0.erase(it); + } + } +} + +// FUNCTION: LEGO1 0x100213a0 +MxCore* LegoWorld::Find(const char* p_class, const char* p_name) +{ + if (!strcmp(p_class, "MxControlPresenter")) { + MxPresenterListCursor cursor(&m_controlPresenters); + MxPresenter* presenter; + + while (cursor.Next(presenter)) { + MxDSAction* action = presenter->GetAction(); + if (!strcmp(action->GetObjectName(), p_name)) { + return presenter; + } + } + + return NULL; + } + else if (!strcmp(p_class, "MxEntity")) { + LegoEntityListCursor cursor(m_entityList); + LegoEntity* entity; + + while (cursor.Next(entity)) { + if (!p_name) { + return entity; + } + + LegoROI* roi = entity->GetROI(); + if (roi && !strcmpi(roi->GetName(), p_name)) { + return entity; + } + } + + return NULL; + } + else if (!strcmp(p_class, "LegoAnimPresenter")) { + MxPresenterListCursor cursor(&m_animPresenters); + MxPresenter* presenter; + + while (cursor.Next(presenter)) { + if (!strcmpi(((LegoAnimPresenter*) presenter)->GetActionObjectName(), p_name)) { + return presenter; + } + } + + return NULL; + } + else { + for (MxCoreSet::iterator it = m_set0xa8.begin(); it != m_set0xa8.end(); it++) { + if ((*it)->IsA(p_class) && (*it)->IsA("MxPresenter")) { + MxPresenter* presenter = (MxPresenter*) *it; + MxDSAction* action = presenter->GetAction(); + + if (!strcmp(action->GetObjectName(), p_name)) { + return *it; + } + } + } + + return NULL; + } +} + +// FUNCTION: LEGO1 0x10021790 +MxCore* LegoWorld::Find(const MxAtomId& p_atom, MxS32 p_entityId) +{ + LegoEntityListCursor entityCursor(m_entityList); + LegoEntity* entity; + + while (entityCursor.Next(entity)) { + if (entity->GetAtom() == p_atom && entity->GetEntityId() == p_entityId) { + return entity; + } + } + + MxPresenterListCursor controlPresenterCursor(&m_controlPresenters); + MxPresenter* presenter; + + while (controlPresenterCursor.Next(presenter)) { + MxDSAction* action = presenter->GetAction(); + + if (action->GetAtomId() == p_atom && action->GetObjectId() == p_entityId) { + return presenter; + } + } + + MxPresenterListCursor animPresenterCursor(&m_animPresenters); + + while (animPresenterCursor.Next(presenter)) { + MxDSAction* action = presenter->GetAction(); + + if (action && action->GetAtomId() == p_atom && action->GetObjectId() == p_entityId) { + return presenter; + } + } + + for (MxCoreSet::iterator it = m_set0xa8.begin(); it != m_set0xa8.end(); it++) { + MxCore* core = *it; + + if (core->IsA("MxPresenter")) { + MxPresenter* presenter = (MxPresenter*) *it; + MxDSAction* action = presenter->GetAction(); + + if (action->GetAtomId() == p_atom && action->GetObjectId() == p_entityId) { + return *it; + } + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10021a70 +void LegoWorld::Enable(MxBool p_enable) +{ + if (p_enable && !m_set0xd0.empty()) { + if (CurrentWorld() != this) { + if (CurrentWorld()) { + AnimationManager()->FUN_10061010(FALSE); + CurrentWorld()->Enable(FALSE); + + LegoEntityListCursor cursor(m_entityList); + LegoEntity* entity; + + while (cursor.Next(entity)) { + if (entity->GetROI()) { + entity->GetROI()->SetEntity(entity); + GetViewManager()->Add(entity->GetROI()); + } + } + } + + while (!m_set0xd0.empty()) { + MxCoreSet::iterator it = m_set0xd0.begin(); + + if ((*it)->IsA("MxPresenter")) { + ((MxPresenter*) *it)->Enable(TRUE); + } + else if ((*it)->IsA("LegoPathController")) { + ((LegoPathController*) *it)->Enable(TRUE); + } + + m_set0xd0.erase(it); + } + + SetCurrentWorld(this); + ControlManager()->FUN_10028df0(&m_controlPresenters); + InputManager()->SetCamera(m_cameraController); + + if (m_cameraController) { + InputManager()->Register(m_cameraController->GetNavController()); + Lego()->SetNavController(m_cameraController->GetNavController()); + } + + if (m_scriptIndex != -1) { + PlantManager()->FUN_10026360(m_scriptIndex); + AnimationManager()->LoadScriptInfo(m_scriptIndex); + BuildingManager()->FUN_1002fa00(); + AnimationManager()->Resume(); + } + + GameState()->ResetROI(); + SetIsWorldActive(TRUE); + } + } + else if (!p_enable && m_set0xd0.empty()) { + MxPresenter* presenter; + LegoPathController* controller; + IslePathActor* actor = CurrentActor(); + + if (actor) { + RemovePathActor(actor); + } + + AnimationManager()->Reset(FALSE); + m_set0xd0.insert(this); + + if (m_scriptIndex != -1) { + PlantManager()->FUN_100263a0(m_scriptIndex); + BuildingManager()->FUN_1002fb30(); + } + + MxPresenterListCursor controlPresenterCursor(&m_controlPresenters); + + while (controlPresenterCursor.Next(presenter)) { + if (presenter->IsEnabled()) { + m_set0xd0.insert(presenter); + presenter->Enable(FALSE); + } + } + + for (MxCoreSet::iterator it = m_set0xa8.begin(); it != m_set0xa8.end(); it++) { + if ((*it)->IsA("LegoActionControlPresenter") || + ((*it)->IsA("MxPresenter") && ((MxPresenter*) *it)->IsEnabled())) { + m_set0xd0.insert(*it); + ((MxPresenter*) *it)->Enable(FALSE); + } + } + + if (CurrentWorld() && CurrentWorld() == this) { + ControlManager()->FUN_10028df0(NULL); + Lego()->SetCurrentWorld(NULL); + } + + if (InputManager()->GetCamera() == m_cameraController) { + InputManager()->ClearCamera(); + } + + if (m_cameraController) { + InputManager()->UnRegister(m_cameraController->GetNavController()); + + if (NavController() == m_cameraController->GetNavController()) { + Lego()->SetNavController(NULL); + } + } + + LegoPathControllerListCursor pathControllerCursor(&m_list0x68); + + while (pathControllerCursor.Next(controller)) { + controller->Enable(FALSE); + m_set0xd0.insert(controller); + } + + GetViewManager()->RemoveAll(NULL); + } +} + +// FUNCTION: LEGO1 0x10022080 +MxResult LegoWorld::Tickle() +{ + if (!m_worldStarted) { + switch (m_startupTicks) { + case e_start: + m_worldStarted = TRUE; + SetAppCursor(0); + ReadyWorld(); + return TRUE; + case e_two: + if (PresentersPending()) { + break; + } + default: + m_startupTicks--; + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x100220e0 +MxBool LegoWorld::PresentersPending() +{ + MxPresenterListCursor controlPresenterCursor(&m_controlPresenters); + MxPresenter* presenter; + + while (controlPresenterCursor.Next(presenter)) { + if (presenter->IsEnabled() && !presenter->HasTickleStatePassed(MxPresenter::e_starting)) { + return TRUE; + } + } + + MxPresenterListCursor animPresenterCursor(&m_animPresenters); + + while (animPresenterCursor.Next(presenter)) { + if (presenter->IsEnabled()) { + if (presenter->IsA("LegoLocomotionAnimPresenter")) { + if (!presenter->HasTickleStatePassed(MxPresenter::e_ready)) { + return TRUE; + } + } + else { + if (!presenter->HasTickleStatePassed(MxPresenter::e_starting)) { + return TRUE; + } + } + } + } + + for (MxCoreSet::iterator it = m_set0xa8.begin(); it != m_set0xa8.end(); it++) { + if ((*it)->IsA("MxPresenter")) { + presenter = (MxPresenter*) *it; + + if (presenter->IsEnabled() && !presenter->HasTickleStatePassed(MxPresenter::e_starting)) { + return TRUE; + } + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10022340 +void LegoWorld::ReadyWorld() +{ + TickleManager()->UnregisterClient(this); +} diff --git a/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp new file mode 100644 index 00000000..a4e5902b --- /dev/null +++ b/LEGO1/lego/legoomni/src/entity/legoworldpresenter.cpp @@ -0,0 +1,444 @@ +#include "legoworldpresenter.h" + +#include "define.h" +#include "legoactorpresenter.h" +#include "legoanimationmanager.h" +#include "legobuildingmanager.h" +#include "legoentity.h" +#include "legomain.h" +#include "legomodelpresenter.h" +#include "legopartpresenter.h" +#include "legoplantmanager.h" +#include "legotexturepresenter.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "modeldb/modeldb.h" +#include "mxactionnotificationparam.h" +#include "mxautolock.h" +#include "mxdsactionlist.h" +#include "mxdschunk.h" +#include "mxdsmediaaction.h" +#include "mxdsmultiaction.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxobjectfactory.h" +#include "mxpresenter.h" +#include "mxstl/stlcompat.h" +#include "mxutilities.h" + +#include + +DECOMP_SIZE_ASSERT(LegoWorldPresenter, 0x54) + +// GLOBAL: LEGO1 0x100f75d4 +MxS32 g_legoWorldPresenterQuality = 1; + +// GLOBAL: LEGO1 0x100f75d8 +MxLong g_wdbOffset = 0; + +// FUNCTION: LEGO1 0x100665b0 +void LegoWorldPresenter::configureLegoWorldPresenter(MxS32 p_legoWorldPresenterQuality) +{ + g_legoWorldPresenterQuality = p_legoWorldPresenterQuality; +} + +// FUNCTION: LEGO1 0x100665c0 +LegoWorldPresenter::LegoWorldPresenter() +{ + m_unk0x50 = 50000; +} + +// FUNCTION: LEGO1 0x10066770 +LegoWorldPresenter::~LegoWorldPresenter() +{ + MxBool result = FALSE; + if (m_entity) { + MxS32 scriptIndex = ((LegoWorld*) m_entity)->GetScriptIndex(); + PlantManager()->FUN_10026360(scriptIndex); + AnimationManager()->LoadScriptInfo(scriptIndex); + BuildingManager()->FUN_1002fa00(); + result = ((LegoWorld*) m_entity)->VTable0x5c(); + } + + if (result == FALSE) { + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + } + + if (m_entity) { + NotificationManager()->Send(m_entity, MxNotificationParam(c_notificationNewPresenter, NULL)); + } +} + +// FUNCTION: LEGO1 0x10066870 +MxResult LegoWorldPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + + MxResult result = FAILURE; + MxDSActionList* actions = ((MxDSMultiAction*) p_action)->GetActionList(); + MxObjectFactory* factory = ObjectFactory(); + MxDSActionListCursor cursor(actions); + MxDSAction* action; + + if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) { + cursor.Head(); + + while (cursor.Current(action)) { + MxBool success = FALSE; + const char* presenterName; + MxPresenter* presenter = NULL; + + cursor.Next(); + + if (m_action->GetFlags() & MxDSAction::c_looping) { + action->SetFlags(action->GetFlags() | MxDSAction::c_looping); + } + else if (m_action->GetFlags() & MxDSAction::c_bit3) { + action->SetFlags(action->GetFlags() | MxDSAction::c_bit3); + } + + presenterName = PresenterNameDispatch(*action); + presenter = (MxPresenter*) factory->Create(presenterName); + + if (presenter && presenter->AddToManager() == SUCCESS) { + presenter->SetCompositePresenter(this); + if (presenter->StartAction(p_controller, action) == SUCCESS) { + presenter->SetTickleState(e_idle); + success = TRUE; + } + } + + if (success) { + action->SetOrigin(this); + m_list.push_back(presenter); + } + else if (presenter) { + delete presenter; + } + } + + VideoManager()->RegisterPresenter(*this); + + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x10066a50 +void LegoWorldPresenter::ReadyTickle() +{ + m_entity = (LegoEntity*) MxPresenter::CreateEntity("LegoWorld"); + if (m_entity) { + m_entity->Create(*m_action); + Lego()->AddWorld((LegoWorld*) m_entity); + SetEntityLocation(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp()); + } + + ParseExtra(); + ProgressTickleState(e_starting); +} + +// FUNCTION: LEGO1 0x10066ac0 +void LegoWorldPresenter::StartingTickle() +{ + if (m_action->IsA("MxDSSerialAction")) { + MxPresenter* presenter = *m_list.begin(); + if (presenter->GetCurrentTickleState() == e_idle) { + presenter->SetTickleState(e_ready); + } + } + else { + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + if ((*it)->GetCurrentTickleState() == e_idle) { + (*it)->SetTickleState(e_ready); + } + } + } + + ProgressTickleState(e_streaming); +} + +// FUNCTION: LEGO1 0x10066b40 +MxResult LegoWorldPresenter::LoadWorld(char* p_worldName, LegoWorld* p_world) +{ + char wdbPath[512]; + sprintf(wdbPath, "%s", MxOmni::GetHD()); + + if (wdbPath[strlen(wdbPath) - 1] != '\\') { + strcat(wdbPath, "\\"); + } + + strcat(wdbPath, "lego\\data\\world.wdb"); + + if (access(wdbPath, 4) != 0) { + sprintf(wdbPath, "%s", MxOmni::GetCD()); + + if (wdbPath[strlen(wdbPath) - 1] != '\\') { + strcat(wdbPath, "\\"); + } + + strcat(wdbPath, "lego\\data\\world.wdb"); + + if (access(wdbPath, 4) != 0) { + return FAILURE; + } + } + + ModelDbWorld* worlds = NULL; + MxS32 numWorlds, i, j; + MxU32 size; + MxU8* buff; + FILE* wdbFile = fopen(wdbPath, "rb"); + + if (wdbFile == NULL) { + return FAILURE; + } + + ReadModelDbWorlds(wdbFile, worlds, numWorlds); + + for (i = 0; i < numWorlds; i++) { + if (!strcmpi(worlds[i].m_worldName, p_worldName)) { + break; + } + } + + if (i == numWorlds) { + return FAILURE; + } + + if (g_wdbOffset == 0) { + if (fread(&size, sizeof(size), 1, wdbFile) != 1) { + return FAILURE; + } + + buff = new MxU8[size]; + if (fread(buff, size, 1, wdbFile) != 1) { + return FAILURE; + } + + MxDSChunk chunk; + chunk.SetLength(size); + chunk.SetData(buff); + + LegoTexturePresenter texturePresenter; + if (texturePresenter.Read(chunk) == SUCCESS) { + texturePresenter.Store(); + } + + delete[] buff; + + if (fread(&size, sizeof(size), 1, wdbFile) != 1) { + return FAILURE; + } + + buff = new MxU8[size]; + if (fread(buff, size, 1, wdbFile) != 1) { + return FAILURE; + } + + chunk.SetLength(size); + chunk.SetData(buff); + + LegoPartPresenter partPresenter; + if (partPresenter.Read(chunk) == SUCCESS) { + partPresenter.Store(); + } + + delete[] buff; + + g_wdbOffset = ftell(wdbFile); + } + else { + if (fseek(wdbFile, g_wdbOffset, SEEK_SET) != 0) { + return FAILURE; + } + } + + ModelDbPartListCursor cursor(worlds[i].m_partList); + ModelDbPart* part; + + while (cursor.Next(part)) { + if (GetViewLODListManager()->Lookup(part->m_roiName.GetData()) == NULL && + FUN_10067360(*part, wdbFile) != SUCCESS) { + return FAILURE; + } + } + + for (j = 0; j < worlds[i].m_numModels; j++) { + if (!strnicmp(worlds[i].m_models[j].m_modelName, "isle", 4)) { + switch (g_legoWorldPresenterQuality) { + case 0: + if (strcmpi(worlds[i].m_models[j].m_modelName, "isle_lo")) { + continue; + } + break; + case 1: + if (strcmpi(worlds[i].m_models[j].m_modelName, "isle")) { + continue; + } + break; + case 2: + if (strcmpi(worlds[i].m_models[j].m_modelName, "isle_hi")) { + continue; + } + } + } + else if (g_legoWorldPresenterQuality <= 1 && !strnicmp(worlds[i].m_models[j].m_modelName, "haus", 4)) { + if (worlds[i].m_models[j].m_modelName[4] == '3') { + if (FUN_100674b0(worlds[i].m_models[j], wdbFile, p_world) != SUCCESS) { + return FAILURE; + } + + if (FUN_100674b0(worlds[i].m_models[j - 2], wdbFile, p_world) != SUCCESS) { + return FAILURE; + } + + if (FUN_100674b0(worlds[i].m_models[j - 1], wdbFile, p_world) != SUCCESS) { + return FAILURE; + } + } + + continue; + } + + if (FUN_100674b0(worlds[i].m_models[j], wdbFile, p_world) != SUCCESS) { + return FAILURE; + } + } + + FreeModelDbWorlds(worlds, numWorlds); + fclose(wdbFile); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10067360 +MxResult LegoWorldPresenter::FUN_10067360(ModelDbPart& p_part, FILE* p_wdbFile) +{ + MxResult result; + MxU8* buff = new MxU8[p_part.m_partDataLength]; + + fseek(p_wdbFile, p_part.m_partDataOffset, 0); + if (fread(buff, p_part.m_partDataLength, 1, p_wdbFile) != 1) { + return FAILURE; + } + + MxDSChunk chunk; + chunk.SetLength(p_part.m_partDataLength); + chunk.SetData(buff); + + LegoPartPresenter partPresenter; + result = partPresenter.Read(chunk); + + if (result == SUCCESS) { + partPresenter.Store(); + } + + delete[] buff; + return result; +} + +// FUNCTION: LEGO1 0x100674b0 +MxResult LegoWorldPresenter::FUN_100674b0(ModelDbModel& p_model, FILE* p_wdbFile, LegoWorld* p_world) +{ + MxU8* buff = new MxU8[p_model.m_unk0x04]; + + fseek(p_wdbFile, p_model.m_unk0x08, 0); + if (fread(buff, p_model.m_unk0x04, 1, p_wdbFile) != 1) { + return FAILURE; + } + + MxDSChunk chunk; + chunk.SetLength(p_model.m_unk0x04); + chunk.SetData(buff); + + MxDSAction action; + MxAtomId atom; + action.SetLocation(p_model.m_location); + action.SetDirection(p_model.m_direction); + action.SetUp(p_model.m_up); + + MxU32 objectId = m_unk0x50; + m_unk0x50++; + action.SetObjectId(objectId); + + action.SetAtomId(atom); + + LegoEntity* createdEntity = NULL; + + if (!strcmp(p_model.m_presenterName, "LegoActorPresenter")) { + LegoActorPresenter presenter; + presenter.SetAction(&action); + LegoEntity* entity = (LegoEntity*) presenter.CreateEntity("LegoActor"); + presenter.SetInternalEntity(entity); + presenter.SetEntityLocation(p_model.m_location, p_model.m_direction, p_model.m_up); + entity->Create(action); + } + else if (!strcmp(p_model.m_presenterName, "LegoEntityPresenter")) { + LegoEntityPresenter presenter; + presenter.SetAction(&action); + createdEntity = (LegoEntity*) presenter.CreateEntity("LegoEntity"); + presenter.SetInternalEntity(createdEntity); + presenter.SetEntityLocation(p_model.m_location, p_model.m_direction, p_model.m_up); + createdEntity->Create(action); + } + + LegoModelPresenter modelPresenter; + + if (createdEntity != NULL) { + action.SetLocation(Mx3DPointFloat(0.0, 0.0, 0.0)); + action.SetUp(Mx3DPointFloat(0.0, 0.0, 1.0)); + action.SetDirection(Mx3DPointFloat(0.0, 1.0, 0.0)); + } + + modelPresenter.SetAction(&action); + modelPresenter.FUN_1007ff70(chunk, createdEntity, p_model.m_unk0x34, p_world); + delete[] buff; + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10067a70 +void LegoWorldPresenter::VTable0x60(MxPresenter* p_presenter) +{ + MxCompositePresenter::VTable0x60(p_presenter); + MxDSAction* action = p_presenter->GetAction(); + + if (action->GetDuration() != -1 && (action->GetFlags() & MxDSAction::c_looping) == 0) { + if (!action->IsA("MxDSMediaAction")) { + return; + } + + if (((MxDSMediaAction*) action)->GetSustainTime() != -1) { + return; + } + } + + if (!p_presenter->IsA("LegoAnimPresenter") && !p_presenter->IsA("MxControlPresenter") && + !p_presenter->IsA("MxCompositePresenter")) { + p_presenter->SendToCompositePresenter(Lego()); + ((LegoWorld*) m_entity)->Add(p_presenter); + } +} + +// FUNCTION: LEGO1 0x10067b00 +void LegoWorldPresenter::ParseExtra() +{ + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[1024]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char output[1024]; + if (KeyValueStringParse(output, g_strWORLD, extraCopy)) { + char* worldKey = strtok(output, g_parseExtraTokens); + LoadWorld(worldKey, (LegoWorld*) m_entity); + ((LegoWorld*) m_entity)->SetScriptIndex(Lego()->GetScriptIndex(worldKey)); + } + } +} diff --git a/LEGO1/lego/legoomni/src/gasstation/gasstationentity.cpp b/LEGO1/lego/legoomni/src/gasstation/gasstationentity.cpp new file mode 100644 index 00000000..cb15b026 --- /dev/null +++ b/LEGO1/lego/legoomni/src/gasstation/gasstationentity.cpp @@ -0,0 +1,39 @@ +#include "gasstationentity.h" + +#include "act1state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(GasStationEntity, 0x68) + +// FUNCTION: LEGO1 0x100151d0 +MxLong GasStationEntity::VTable0x50(MxParam& p_param) +{ + if (FUN_1003ef60()) { + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + + if (state->GetUnknown18() != 8) { + state->SetUnknown18(0); + + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->SetDestLocation(LegoGameState::Area::e_garage); + + AnimationManager()->FUN_10061010(FALSE); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + } + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/gasstation/gasstationstate.cpp b/LEGO1/lego/legoomni/src/gasstation/gasstationstate.cpp new file mode 100644 index 00000000..613a74eb --- /dev/null +++ b/LEGO1/lego/legoomni/src/gasstation/gasstationstate.cpp @@ -0,0 +1,37 @@ +#include "gasstationstate.h" + +DECOMP_SIZE_ASSERT(GasStationState, 0x24) + +// FUNCTION: LEGO1 0x10005eb0 +GasStationState::GasStationState() +{ + m_unk0x18 = 0; + m_unk0x1a = 0; + m_unk0x1c = 0; + m_unk0x1e = 0; + m_unk0x20 = 0; + + undefined4* unk0x08 = m_unk0x08; + unk0x08[0] = -1; + unk0x08[1] = -1; + unk0x08[2] = -1; +} + +// STUB: LEGO1 0x10006300 +MxResult GasStationState::Serialize(LegoFile* p_legoFile) +{ + // TODO + return LegoState::Serialize(p_legoFile); +} + +// STUB: LEGO1 0x10006430 +void GasStationState::FUN_10006430(undefined4) +{ + // TODO +} + +// STUB: LEGO1 0x10006490 +void GasStationState::FUN_10006490() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/hospital/ambulancemissionstate.cpp b/LEGO1/lego/legoomni/src/hospital/ambulancemissionstate.cpp new file mode 100644 index 00000000..860bd0f0 --- /dev/null +++ b/LEGO1/lego/legoomni/src/hospital/ambulancemissionstate.cpp @@ -0,0 +1,27 @@ +#include "ambulancemissionstate.h" + +DECOMP_SIZE_ASSERT(AmbulanceMissionState, 0x24) + +// FUNCTION: LEGO1 0x100373a0 +AmbulanceMissionState::AmbulanceMissionState() +{ + m_unk0x10 = 0; + m_unk0x12 = 0; + m_unk0x14 = 0; + m_unk0x08 = 0; + m_unk0x16 = 0; + m_unk0x0c = 0; + m_unk0x18 = 0; + m_score1 = 0; + m_score2 = 0; + m_score3 = 0; + m_score4 = 0; + m_score5 = 0; +} + +// STUB: LEGO1 0x10037440 +MxResult AmbulanceMissionState::Serialize(LegoFile* p_legoFile) +{ + // TODO + return LegoState::Serialize(p_legoFile); +} diff --git a/LEGO1/lego/legoomni/src/hospital/hospitalentity.cpp b/LEGO1/lego/legoomni/src/hospital/hospitalentity.cpp new file mode 100644 index 00000000..9b2f4eb0 --- /dev/null +++ b/LEGO1/lego/legoomni/src/hospital/hospitalentity.cpp @@ -0,0 +1,39 @@ +#include "hospitalentity.h" + +#include "act1state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(HospitalEntity, 0x68) + +// FUNCTION: LEGO1 0x10015270 +MxLong HospitalEntity::VTable0x50(MxParam& p_param) +{ + if (FUN_1003ef60()) { + Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); + + if (act1State->GetUnknown18() != 10) { + act1State->SetUnknown18(0); + + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->SetDestLocation(LegoGameState::Area::e_hospital); + + AnimationManager()->FUN_10061010(FALSE); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + } + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/hospital/hospitalstate.cpp b/LEGO1/lego/legoomni/src/hospital/hospitalstate.cpp new file mode 100644 index 00000000..da61f0fb --- /dev/null +++ b/LEGO1/lego/legoomni/src/hospital/hospitalstate.cpp @@ -0,0 +1,49 @@ +#include "hospitalstate.h" + +DECOMP_SIZE_ASSERT(HospitalState, 0x18) + +// FUNCTION: LEGO1 0x10076370 +HospitalState::HospitalState() +{ + m_unk0x0c = 0; + m_unk0x0e = 0; + m_unk0x10 = 0; + m_unk0x12 = 0; + m_unk0x14 = 0; + m_unk0x16 = 0; +} + +// FUNCTION: LEGO1 0x10076530 +MxResult HospitalState::Serialize(LegoFile* p_legoFile) +{ + LegoState::Serialize(p_legoFile); + + if (p_legoFile->IsWriteMode()) { + // A write variable needs to be used here, otherwise + // the compiler aggresively optimizes the function + MxS16 write; + + write = m_unk0x0c; + p_legoFile->Write(&write, sizeof(m_unk0x0c)); + write = m_unk0x0e; + p_legoFile->Write(&write, sizeof(m_unk0x0e)); + write = m_unk0x10; + p_legoFile->Write(&write, sizeof(m_unk0x10)); + write = m_unk0x12; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + write = m_unk0x14; + p_legoFile->Write(&write, sizeof(m_unk0x14)); + write = m_unk0x16; + p_legoFile->Write(&write, sizeof(m_unk0x16)); + } + else if (p_legoFile->IsReadMode()) { + p_legoFile->Read(&m_unk0x0c, sizeof(m_unk0x0c)); + p_legoFile->Read(&m_unk0x0e, sizeof(m_unk0x0e)); + p_legoFile->Read(&m_unk0x10, sizeof(m_unk0x10)); + p_legoFile->Read(&m_unk0x12, sizeof(m_unk0x12)); + p_legoFile->Read(&m_unk0x14, sizeof(m_unk0x14)); + p_legoFile->Read(&m_unk0x16, sizeof(m_unk0x16)); + } + + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/infocenter/infocenterentity.cpp b/LEGO1/lego/legoomni/src/infocenter/infocenterentity.cpp new file mode 100644 index 00000000..4c89044e --- /dev/null +++ b/LEGO1/lego/legoomni/src/infocenter/infocenterentity.cpp @@ -0,0 +1,60 @@ +#include "infocenterentity.h" + +#include "act1state.h" +#include "act2main_actions.h" +#include "act3.h" +#include "act3_actions.h" +#include "act3state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoact2.h" +#include "legoact2state.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(InfoCenterEntity, 0x68) + +// FUNCTION: LEGO1 0x100150c0 +MxLong InfoCenterEntity::VTable0x50(MxParam& p_param) +{ + switch (GameState()->GetCurrentAct()) { + case LegoGameState::Act::e_act1: { + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->FUN_10033350(); + isle->SetDestLocation(LegoGameState::Area::e_infomain); + + Act1State* act1state = (Act1State*) GameState()->GetState("Act1State"); + act1state->SetUnknown18(0); + break; + } + case LegoGameState::Act::e_act2: { + LegoAct2* act2 = (LegoAct2*) FindWorld(*g_act2mainScript, Act2mainScript::c__Act2Main); + act2->SetUnknown0x1150(2); + + LegoAct2State* act2state = (LegoAct2State*) GameState()->GetState("LegoAct2State"); + if (act2state) { + act2state->SetUnknown0x0c(0); + } + break; + } + case LegoGameState::Act::e_act3: + Act3* act3 = (Act3*) FindWorld(*g_act3Script, Act3Script::c__Act3); + act3->SetUnknown4270(2); + break; + } + + AnimationManager()->FUN_10061010(FALSE); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/infocenter/infocenterstate.cpp b/LEGO1/lego/legoomni/src/infocenter/infocenterstate.cpp new file mode 100644 index 00000000..0fd99839 --- /dev/null +++ b/LEGO1/lego/legoomni/src/infocenter/infocenterstate.cpp @@ -0,0 +1,133 @@ +#include "infocenterstate.h" + +#include "infocenter.h" +#include "infomain_actions.h" +#include "mxstillpresenter.h" + +DECOMP_SIZE_ASSERT(InfocenterState, 0x94) + +// GLOBAL: LEGO1 0x100f76a8 +InfomainScript::Script g_exitDialogueAct1[14] = { + InfomainScript::c_iic019in_RunAnim, + InfomainScript::c_iic020in_RunAnim, + InfomainScript::c_iic021in_RunAnim, + InfomainScript::c_iic022in_RunAnim, + InfomainScript::c_iic023in_RunAnim, + InfomainScript::c_iic024in_RunAnim, + InfomainScript::c_iic025in_RunAnim, + InfomainScript::c_iic026in_RunAnim, + InfomainScript::c_iic027in_RunAnim, + InfomainScript::c_iica28in_RunAnim, + InfomainScript::c_iicb28in_RunAnim, + InfomainScript::c_iicc28in_RunAnim, + InfomainScript::c_iic029in_RunAnim, + InfomainScript::c_iic032in_RunAnim +}; + +// GLOBAL: LEGO1 0x100f76e0 +InfomainScript::Script g_exitDialogueAct23[6] = { + InfomainScript::c_iic027in_RunAnim, + InfomainScript::c_iic029in_RunAnim, + InfomainScript::c_iic048in_RunAnim, + InfomainScript::c_iic056in_RunAnim, + InfomainScript::c_iicx23in_RunAnim + // Zero-terminated +}; + +// GLOBAL: LEGO1 0x100f76f8 +InfomainScript::Script g_returnDialogueAct1[6] = { + InfomainScript::c_iicx26in_RunAnim, + InfomainScript::c_iic033in_RunAnim, + InfomainScript::c_iic034in_RunAnim, + InfomainScript::c_iic035in_RunAnim, + InfomainScript::c_iic036in_RunAnim + // Zero-terminated +}; + +// GLOBAL: LEGO1 0x100f7710 +InfomainScript::Script g_returnDialogueAct2[4] = { + InfomainScript::c_iic048in_RunAnim, + InfomainScript::c_iic049in_RunAnim, + InfomainScript::c_iic050in_RunAnim, + // Zero-terminated +}; + +// GLOBAL: LEGO1 0x100f7720 +InfomainScript::Script g_returnDialogueAct3[4] = { + InfomainScript::c_iic055in_RunAnim, + InfomainScript::c_iic056in_RunAnim, + InfomainScript::c_iic057in_RunAnim, + InfomainScript::c_iic058in_RunAnim +}; + +// GLOBAL: LEGO1 0x100f7730 +InfomainScript::Script g_leaveDialogueAct1[4] = { + InfomainScript::c_iic039in_PlayWav, + InfomainScript::c_iic040in_PlayWav, + InfomainScript::c_iic041in_PlayWav, + InfomainScript::c_iic042in_PlayWav +}; + +// GLOBAL: LEGO1 0x100f7740 +InfomainScript::Script g_leaveDialogueAct2[4] = { + InfomainScript::c_iic051in_PlayWav, + InfomainScript::c_iic052in_PlayWav, + InfomainScript::c_iic053in_PlayWav, + InfomainScript::c_iic054in_PlayWav +}; + +// GLOBAL: LEGO1 0x100f7750 +InfomainScript::Script g_leaveDialogueAct3[4] = { + InfomainScript::c_iic059in_PlayWav, + InfomainScript::c_iic060in_PlayWav, + InfomainScript::c_iic061in_PlayWav, + // Zero-terminated +}; + +// GLOBAL: LEGO1 0x100f7760 +InfomainScript::Script g_bricksterDialogue[2] = { + InfomainScript::c_sbleh2br_PlayWav, + InfomainScript::c_snshahbr_PlayWav +}; + +// FUNCTION: LEGO1 0x10071600 +InfocenterState::InfocenterState() +{ + m_exitDialogueAct1 = LegoState::Playlist((MxU32*) g_exitDialogueAct1, sizeOfArray(g_exitDialogueAct1)); + m_exitDialogueAct23 = LegoState::Playlist((MxU32*) g_exitDialogueAct23, sizeOfArray(g_exitDialogueAct23) - 1); + + m_returnDialogue[LegoGameState::e_act1] = + LegoState::Playlist((MxU32*) g_returnDialogueAct1, sizeOfArray(g_returnDialogueAct1) - 1); + + m_returnDialogue[LegoGameState::e_act2] = + LegoState::Playlist((MxU32*) g_returnDialogueAct2, sizeOfArray(g_returnDialogueAct2) - 1); + + m_returnDialogue[LegoGameState::e_act3] = + LegoState::Playlist((MxU32*) g_returnDialogueAct3, sizeOfArray(g_returnDialogueAct3)); + + m_leaveDialogue[LegoGameState::e_act1] = + LegoState::Playlist((MxU32*) g_leaveDialogueAct1, sizeOfArray(g_leaveDialogueAct1)); + + m_leaveDialogue[LegoGameState::e_act2] = + LegoState::Playlist((MxU32*) g_leaveDialogueAct2, sizeOfArray(g_leaveDialogueAct2)); + + m_leaveDialogue[LegoGameState::e_act3] = + LegoState::Playlist((MxU32*) g_leaveDialogueAct3, sizeOfArray(g_leaveDialogueAct3) - 1); + + m_bricksterDialogue = LegoState::Playlist((MxU32*) g_bricksterDialogue, sizeOfArray(g_bricksterDialogue)); + + memset(m_letters, 0, sizeof(m_letters)); +} + +// FUNCTION: LEGO1 0x10071920 +InfocenterState::~InfocenterState() +{ + MxS16 i = 0; + do { + if (GetNameLetter(i) != NULL) { + delete GetNameLetter(i)->GetAction(); + delete GetNameLetter(i); + } + i++; + } while (i < GetMaxNameLength()); +} diff --git a/LEGO1/lego/legoomni/src/infocenter/scorestate.cpp b/LEGO1/lego/legoomni/src/infocenter/scorestate.cpp new file mode 100644 index 00000000..e1b3522c --- /dev/null +++ b/LEGO1/lego/legoomni/src/infocenter/scorestate.cpp @@ -0,0 +1,16 @@ +#include "scorestate.h" + +DECOMP_SIZE_ASSERT(ScoreState, 0x0c) + +// FUNCTION: LEGO1 0x1000de20 +MxBool ScoreState::IsSerializable() +{ + return FALSE; +} + +// FUNCTION: LEGO1 0x1000de30 +MxBool ScoreState::SetFlag() +{ + m_playCubeTutorial = TRUE; + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp new file mode 100644 index 00000000..9149835d --- /dev/null +++ b/LEGO1/lego/legoomni/src/input/legoinputmanager.cpp @@ -0,0 +1,587 @@ +#include "legoinputmanager.h" + +#include "legocameracontroller.h" +#include "legocontrolmanager.h" +#include "legomain.h" +#include "legoutils.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxautolock.h" +#include "roi/legoroi.h" + +DECOMP_SIZE_ASSERT(LegoInputManager, 0x338) +DECOMP_SIZE_ASSERT(LegoNotifyList, 0x18) +DECOMP_SIZE_ASSERT(LegoNotifyListCursor, 0x10) +DECOMP_SIZE_ASSERT(LegoEventQueue, 0x18) + +// GLOBAL: LEGO1 0x100f31b0 +MxS32 g_unk0x100f31b0 = -1; + +// GLOBAL: LEGO1 0x100f31b4 +const char* g_unk0x100f31b4 = NULL; + +// GLOBAL: LEGO1 0x100f67b8 +MxBool g_unk0x100f67b8 = TRUE; + +// FUNCTION: LEGO1 0x1005b790 +LegoInputManager::LegoInputManager() +{ + m_keyboardNotifyList = NULL; + m_world = NULL; + m_camera = NULL; + m_eventQueue = NULL; + m_unk0x80 = FALSE; + m_autoDragTimerID = 0; + m_x = 0; + m_y = 0; + m_controlManager = NULL; + m_unk0x81 = FALSE; + m_unk0x88 = FALSE; + m_directInput = NULL; + m_directInputDevice = NULL; + m_unk0x94 = FALSE; + m_unk0x195 = 0; + m_joyid = -1; + m_joystickIndex = -1; + m_useJoystick = FALSE; + m_unk0x335 = FALSE; + m_unk0x336 = FALSE; + m_unk0x74 = 0x19; + m_autoDragTime = 1000; +} + +// FUNCTION: LEGO1 0x1005b8b0 +MxResult LegoInputManager::Tickle() +{ + ProcessEvents(); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1005b8f0 +LegoInputManager::~LegoInputManager() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x1005b960 +MxResult LegoInputManager::Create(HWND p_hwnd) +{ + MxResult result = SUCCESS; + + m_controlManager = new LegoControlManager; + + if (!m_keyboardNotifyList) { + m_keyboardNotifyList = new LegoNotifyList; + } + + if (!m_eventQueue) { + m_eventQueue = new LegoEventQueue; + } + + CreateAndAcquireKeyboard(p_hwnd); + GetJoystickId(); + + if (!m_keyboardNotifyList || !m_eventQueue || !m_directInputDevice) { + Destroy(); + result = FAILURE; + } + + return result; +} + +// FUNCTION: LEGO1 0x1005bfe0 +void LegoInputManager::Destroy() +{ + ReleaseDX(); + + if (m_keyboardNotifyList) { + delete m_keyboardNotifyList; + } + m_keyboardNotifyList = NULL; + + if (m_eventQueue) { + delete m_eventQueue; + } + m_eventQueue = NULL; + + if (m_controlManager) { + delete m_controlManager; + } +} + +// FUNCTION: LEGO1 0x1005c030 +void LegoInputManager::CreateAndAcquireKeyboard(HWND p_hwnd) +{ + HINSTANCE hinstance = (HINSTANCE) GetWindowLong(p_hwnd, GWL_HINSTANCE); + HRESULT hresult = DirectInputCreate(hinstance, 0x500, &m_directInput, NULL); // 0x500 for DX5 + + if (hresult == DI_OK) { + HRESULT createdeviceresult = m_directInput->CreateDevice(GUID_SysKeyboard, &m_directInputDevice, NULL); + if (createdeviceresult == DI_OK) { + m_directInputDevice->SetCooperativeLevel(p_hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); + m_directInputDevice->SetDataFormat(&c_dfDIKeyboard); + m_directInputDevice->Acquire(); + } + } +} + +// FUNCTION: LEGO1 0x1005c0a0 +void LegoInputManager::ReleaseDX() +{ + if (m_directInputDevice != NULL) { + m_directInputDevice->Unacquire(); + m_directInputDevice->Release(); + m_directInputDevice = NULL; + } + + if (m_directInput != NULL) { + m_directInput->Release(); + m_directInput = NULL; + } +} + +// FUNCTION: LEGO1 0x1005c0f0 +void LegoInputManager::FUN_1005c0f0() +{ + m_unk0x94 = FALSE; + + if (m_directInputDevice) { + HRESULT hr = m_directInputDevice->GetDeviceState(sizeOfArray(m_unk0x95), &m_unk0x95); + + if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) { + if (m_directInputDevice->Acquire() == S_OK) { + hr = m_directInputDevice->GetDeviceState(sizeOfArray(m_unk0x95), &m_unk0x95); + } + } + + if (hr == S_OK) { + m_unk0x94 = TRUE; + } + } +} + +// FUNCTION: LEGO1 0x1005c160 +MxResult LegoInputManager::FUN_1005c160(MxU32& p_keyFlags) +{ + FUN_1005c0f0(); + + if (!m_unk0x94) { + return FAILURE; + } + + if (g_unk0x100f67b8) { + if (m_unk0x95[DIK_LEFT] & 0x80 && GetAsyncKeyState(VK_LEFT) == 0) { + m_unk0x95[DIK_LEFT] = 0; + } + + if (m_unk0x95[DIK_RIGHT] & 0x80 && GetAsyncKeyState(VK_RIGHT) == 0) { + m_unk0x95[DIK_RIGHT] = 0; + } + } + + MxU32 keyFlags = 0; + + if ((m_unk0x95[DIK_NUMPAD8] | m_unk0x95[DIK_UP]) & 0x80) { + keyFlags |= c_up; + } + + if ((m_unk0x95[DIK_NUMPAD2] | m_unk0x95[DIK_DOWN]) & 0x80) { + keyFlags |= c_down; + } + + if ((m_unk0x95[DIK_NUMPAD4] | m_unk0x95[DIK_LEFT]) & 0x80) { + keyFlags |= c_left; + } + + if ((m_unk0x95[DIK_NUMPAD6] | m_unk0x95[DIK_RIGHT]) & 0x80) { + keyFlags |= c_right; + } + + if ((m_unk0x95[DIK_LCONTROL] | m_unk0x95[DIK_RCONTROL]) & 0x80) { + keyFlags |= c_bit5; + } + + p_keyFlags = keyFlags; + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1005c240 +MxResult LegoInputManager::GetJoystickId() +{ + JOYINFOEX joyinfoex; + + if (m_useJoystick != FALSE) { + MxS32 joyid = m_joystickIndex; + if (joyid >= 0) { + joyinfoex.dwSize = 0x34; + joyinfoex.dwFlags = 0xFF; + + if (joyGetPosEx(joyid, &joyinfoex) == JOYERR_NOERROR && + joyGetDevCaps(joyid, &m_joyCaps, 0x194) == JOYERR_NOERROR) { + m_joyid = joyid; + return SUCCESS; + } + } + + for (joyid = JOYSTICKID1; joyid < 16; joyid++) { + joyinfoex.dwSize = 0x34; + joyinfoex.dwFlags = 0xFF; + if (joyGetPosEx(joyid, &joyinfoex) == JOYERR_NOERROR && + joyGetDevCaps(joyid, &m_joyCaps, 0x194) == JOYERR_NOERROR) { + m_joyid = joyid; + return SUCCESS; + } + } + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x1005c320 +MxResult LegoInputManager::GetJoystickState( + MxU32* p_joystickX, + MxU32* p_joystickY, + DWORD* p_buttonsState, + MxU32* p_povPosition +) +{ + if (m_useJoystick != FALSE) { + if (m_joyid < 0 && GetJoystickId() == -1) { + m_useJoystick = FALSE; + return FAILURE; + } + + JOYINFOEX joyinfoex; + joyinfoex.dwSize = 0x34; + joyinfoex.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNBUTTONS; + MxU32 capabilities = m_joyCaps.wCaps; + + if ((capabilities & JOYCAPS_HASPOV) != 0) { + joyinfoex.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNPOV | JOY_RETURNBUTTONS; + + if ((capabilities & JOYCAPS_POVCTS) != 0) { + joyinfoex.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNPOV | JOY_RETURNBUTTONS | JOY_RETURNPOVCTS; + } + } + + MMRESULT mmresult = joyGetPosEx(m_joyid, &joyinfoex); + + if (mmresult == MMSYSERR_NOERROR) { + *p_buttonsState = joyinfoex.dwButtons; + MxU32 xmin = m_joyCaps.wXmin; + MxU32 ymax = m_joyCaps.wYmax; + MxU32 ymin = m_joyCaps.wYmin; + MxS32 ydiff = ymax - ymin; + *p_joystickX = ((joyinfoex.dwXpos - xmin) * 100) / (m_joyCaps.wXmax - xmin); + *p_joystickY = ((joyinfoex.dwYpos - m_joyCaps.wYmin) * 100) / ydiff; + if ((m_joyCaps.wCaps & (JOYCAPS_POV4DIR | JOYCAPS_POVCTS)) != 0) { + if (joyinfoex.dwPOV == JOY_POVCENTERED) { + *p_povPosition = (MxU32) -1; + return SUCCESS; + } + *p_povPosition = joyinfoex.dwPOV / 100; + return SUCCESS; + } + else { + *p_povPosition = (MxU32) -1; + return SUCCESS; + } + } + } + return FAILURE; +} + +// FUNCTION: LEGO1 0x1005c470 +void LegoInputManager::Register(MxCore* p_notify) +{ + AUTOLOCK(m_criticalSection); + + LegoNotifyListCursor cursor(m_keyboardNotifyList); + if (!cursor.Find(p_notify)) { + m_keyboardNotifyList->Append(p_notify); + } +} + +// FUNCTION: LEGO1 0x1005c5c0 +void LegoInputManager::UnRegister(MxCore* p_notify) +{ + AUTOLOCK(m_criticalSection); + + LegoNotifyListCursor cursor(m_keyboardNotifyList); + if (cursor.Find(p_notify)) { + cursor.Detach(); + } +} + +// FUNCTION: LEGO1 0x1005c700 +void LegoInputManager::SetCamera(LegoCameraController* p_camera) +{ + m_camera = p_camera; +} + +// FUNCTION: LEGO1 0x1005c710 +void LegoInputManager::ClearCamera() +{ + m_camera = NULL; +} + +// FUNCTION: LEGO1 0x1005c720 +void LegoInputManager::SetWorld(LegoWorld* p_world) +{ + m_world = p_world; +} + +// FUNCTION: LEGO1 0x1005c730 +void LegoInputManager::ClearWorld() +{ + m_world = NULL; +} + +// FUNCTION: LEGO1 0x1005c740 +void LegoInputManager::QueueEvent(NotificationId p_id, MxU8 p_modifier, MxLong p_x, MxLong p_y, MxU8 p_key) +{ + LegoEventNotificationParam param = LegoEventNotificationParam(p_id, NULL, p_modifier, p_x, p_y, p_key); + + if (((!m_unk0x88) || ((m_unk0x335 && (param.GetType() == c_notificationButtonDown)))) || + ((m_unk0x336 && (p_key == ' ')))) { + ProcessOneEvent(param); + } +} + +// FUNCTION: LEGO1 0x1005c820 +void LegoInputManager::ProcessEvents() +{ + AUTOLOCK(m_criticalSection); + + LegoEventNotificationParam event; + while (m_eventQueue->Dequeue(event)) { + if (ProcessOneEvent(event)) { + break; + } + } +} + +// FUNCTION: LEGO1 0x1005c9c0 +MxBool LegoInputManager::ProcessOneEvent(LegoEventNotificationParam& p_param) +{ + MxBool processRoi; + + if (p_param.GetType() == c_notificationKeyPress) { + if (!Lego()->IsTimerRunning() || p_param.GetKey() == 0x13) { + if (p_param.GetKey() == 0x10) { + if (m_unk0x195) { + m_unk0x80 = FALSE; + p_param.SetType(c_notificationDrag); + + if (m_camera) { + m_camera->Notify(p_param); + } + } + + m_unk0x195 = !m_unk0x195; + return TRUE; + } + + LegoNotifyListCursor cursor(m_keyboardNotifyList); + MxCore* target; + + while (cursor.Next(target)) { + if (target->Notify(p_param) != 0) { + return TRUE; + } + } + } + } + else { + if (!Lego()->IsTimerRunning()) { + processRoi = TRUE; + + if (m_unk0x335 != 0) { + if (p_param.GetType() == c_notificationButtonDown) { + LegoEventNotificationParam notification(c_notificationKeyPress, NULL, 0, 0, 0, ' '); + LegoNotifyListCursor cursor(m_keyboardNotifyList); + MxCore* target; + + while (cursor.Next(target)) { + if (target->Notify(notification) != 0) { + return TRUE; + } + } + } + + return TRUE; + } + + if (m_unk0x195 && p_param.GetType() == c_notificationButtonDown) { + m_unk0x195 = 0; + return TRUE; + } + + if (m_world != NULL && m_world->Notify(p_param) != 0) { + return TRUE; + } + + if (p_param.GetType() == c_notificationButtonDown) { + MxPresenter* presenter = VideoManager()->GetPresenterAt(p_param.GetX(), p_param.GetY()); + + if (presenter) { + if (presenter->GetDisplayZ() < 0) { + processRoi = FALSE; + + if (m_controlManager->FUN_10029210(p_param, presenter)) { + return TRUE; + } + } + else { + LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY()); + + if (roi == NULL && m_controlManager->FUN_10029210(p_param, presenter)) { + return TRUE; + } + } + } + } + else if (p_param.GetType() == c_notificationButtonUp) { + if (g_unk0x100f31b0 != -1 || m_controlManager->GetUnknown0x10() || + m_controlManager->GetUnknown0x0c() == 1) { + MxBool result = m_controlManager->FUN_10029210(p_param, NULL); + StopAutoDragTimer(); + + m_unk0x80 = FALSE; + m_unk0x81 = FALSE; + return result; + } + } + + if (FUN_1005cdf0(p_param)) { + if (processRoi && p_param.GetType() == c_notificationType11) { + LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY()); + p_param.SetROI(roi); + + if (roi && roi->GetVisibility()) { + for (OrientableROI* parent = roi->GetParentROI(); parent; parent = parent->GetParentROI()) { + roi = (LegoROI*) parent; + } + + LegoEntity* entity = roi->GetEntity(); + if (entity && entity->Notify(p_param) != 0) { + return TRUE; + } + } + } + + if (m_camera && m_camera->Notify(p_param) != 0) { + return TRUE; + } + } + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x1005cdf0 +MxBool LegoInputManager::FUN_1005cdf0(LegoEventNotificationParam& p_param) +{ + MxBool result = FALSE; + + switch (p_param.GetNotification()) { + case c_notificationButtonUp: + StopAutoDragTimer(); + + if (m_unk0x80) { + p_param.SetType(c_notificationDrag); + result = TRUE; + } + else if (m_unk0x81) { + p_param.SetX(m_x); + p_param.SetY(m_y); + p_param.SetType(c_notificationType11); + result = TRUE; + } + + m_unk0x80 = FALSE; + m_unk0x81 = FALSE; + break; + case c_notificationButtonDown: + m_x = p_param.GetX(); + m_y = p_param.GetY(); + m_unk0x80 = FALSE; + m_unk0x81 = TRUE; + StartAutoDragTimer(); + break; + case c_notificationMouseMove: + if (m_unk0x195) { + p_param.SetModifier(LegoEventNotificationParam::c_lButtonState); + } + + if ((m_unk0x195 || m_unk0x81) && p_param.GetModifier() & LegoEventNotificationParam::c_lButtonState) { + if (!m_unk0x80) { + if (m_unk0x195) { + m_x = p_param.GetX(); + m_y = p_param.GetY(); + } + + MxS32 diffX = p_param.GetX() - m_x; + MxS32 diffY = p_param.GetY() - m_y; + + if (m_unk0x195 || (diffX * diffX) + (diffY * diffY) > m_unk0x74) { + StopAutoDragTimer(); + m_unk0x80 = TRUE; + p_param.SetType(c_notificationDragEnd); + result = TRUE; + p_param.SetX(m_x); + p_param.SetY(m_y); + } + } + else { + p_param.SetType(c_notificationDragStart); + result = TRUE; + } + } + break; + case c_notificationTimer: + if (p_param.GetModifier() == m_autoDragTimerID) { + StopAutoDragTimer(); + + if (m_unk0x81) { + m_unk0x80 = TRUE; + p_param.SetX(m_x); + p_param.SetY(m_y); + p_param.SetModifier(LegoEventNotificationParam::c_lButtonState); + p_param.SetType(c_notificationDragEnd); + result = TRUE; + } + else { + m_unk0x80 = FALSE; + } + } + break; + } + + return result; +} + +// FUNCTION: LEGO1 0x1005cfb0 +void LegoInputManager::StartAutoDragTimer() +{ + m_autoDragTimerID = ::SetTimer(LegoOmni::GetInstance()->GetWindowHandle(), 1, m_autoDragTime, NULL); +} + +// FUNCTION: LEGO1 0x1005cfd0 +void LegoInputManager::StopAutoDragTimer() +{ + if (m_autoDragTimerID) { + ::KillTimer(LegoOmni::GetInstance()->GetWindowHandle(), m_autoDragTimerID); + } +} + +// FUNCTION: LEGO1 0x1005cff0 +void LegoInputManager::EnableInputProcessing() +{ + m_unk0x88 = FALSE; + g_unk0x100f31b0 = -1; + g_unk0x100f31b4 = NULL; +} diff --git a/LEGO1/lego/legoomni/src/isle/beachhouseentity.cpp b/LEGO1/lego/legoomni/src/isle/beachhouseentity.cpp new file mode 100644 index 00000000..5e11a4bd --- /dev/null +++ b/LEGO1/lego/legoomni/src/isle/beachhouseentity.cpp @@ -0,0 +1,36 @@ +#include "beachhouseentity.h" + +#include "act1state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(BeachHouseEntity, 0x68) + +// FUNCTION: LEGO1 0x100153b0 +MxLong BeachHouseEntity::VTable0x50(MxParam& p_param) +{ + if (FUN_1003ef60()) { + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + state->SetUnknown18(0); + + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->SetDestLocation(LegoGameState::Area::e_jetskibuild); + + AnimationManager()->FUN_10061010(FALSE); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/isle/jukeboxstate.cpp b/LEGO1/lego/legoomni/src/isle/jukeboxstate.cpp new file mode 100644 index 00000000..7efc9695 --- /dev/null +++ b/LEGO1/lego/legoomni/src/isle/jukeboxstate.cpp @@ -0,0 +1,9 @@ +#include "jukeboxstate.h" + +DECOMP_SIZE_ASSERT(JukeBoxState, 0x10) + +// FUNCTION: LEGO1 0x1000f300 +MxBool JukeBoxState::IsSerializable() +{ + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/isle/radiostate.cpp b/LEGO1/lego/legoomni/src/isle/radiostate.cpp new file mode 100644 index 00000000..5927a94b --- /dev/null +++ b/LEGO1/lego/legoomni/src/isle/radiostate.cpp @@ -0,0 +1,103 @@ +#include "radiostate.h" + +#include "jukebox.h" +#include "jukebox_actions.h" +#include "mxmisc.h" +#include "mxtimer.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(RadioState, 0x30) + +// GLOBAL: LEGO1 0x100f3218 +JukeboxScript::Script g_unk0x100f3218[6] = { + JukeboxScript::c_sns002ra_Audio, + JukeboxScript::c_sns001ja_Audio, + JukeboxScript::c_snsc01js_Audio, + JukeboxScript::c_snsb01js_Audio, + JukeboxScript::c_snsa01js_Audio, + JukeboxScript::c_sns009ra_Audio +}; + +// GLOBAL: LEGO1 0x100f3230 +JukeboxScript::Script g_unk0x100f3230[14] = { + JukeboxScript::c_ham035ra_Audio, + JukeboxScript::c_ham039ra_Audio, + JukeboxScript::c_sns005ra_Audio, + JukeboxScript::c_sns078pa_Audio, + JukeboxScript::c_ham036ra_Audio, + JukeboxScript::c_sns006ra_Audio, + JukeboxScript::c_sns013ra_Audio, + JukeboxScript::c_sns004ra_Audio, + JukeboxScript::c_sns079pa_Audio, + JukeboxScript::c_sns007ra_Audio, + JukeboxScript::c_sns008ra_Audio, + JukeboxScript::c_hpz037ma_Audio, + JukeboxScript::c_sns003ra_Audio, + JukeboxScript::c_sns010ra_Audio, +}; + +// GLOBAL: LEGO1 0x100f3268 +JukeboxScript::Script g_unk0x100f3268[9] = { + JukeboxScript::c_CentralRoads_Music, + JukeboxScript::c_BeachBlvd_Music, + JukeboxScript::c_ResidentalArea_Music, + JukeboxScript::c_Radio1_Music, + JukeboxScript::c_Radio2_Music, + JukeboxScript::c_Radio3_Music, + JukeboxScript::c_Radio4_Music, + JukeboxScript::c_Radio5_Music, + JukeboxScript::c_Radio6_Music, +}; + +// FUNCTION: LEGO1 0x1002ce10 +RadioState::RadioState() +{ + srand(Timer()->GetTime()); + + MxS32 random = rand(); + m_unk0x2c = random % 3; + + m_unk0x08[0] = LegoState::Playlist((MxU32*) g_unk0x100f3218, sizeof(g_unk0x100f3218) / sizeof(g_unk0x100f3218[0])); + m_unk0x08[0].SetUnknown0x08(rand() % (sizeof(g_unk0x100f3218) / sizeof(g_unk0x100f3218[0]))); + + m_unk0x08[1] = LegoState::Playlist((MxU32*) g_unk0x100f3230, sizeof(g_unk0x100f3230) / sizeof(g_unk0x100f3230[0])); + m_unk0x08[1].SetUnknown0x08(rand() % (sizeof(g_unk0x100f3230) / sizeof(g_unk0x100f3230[0]))); + + m_unk0x08[2] = LegoState::Playlist((MxU32*) g_unk0x100f3268, sizeof(g_unk0x100f3268) / sizeof(g_unk0x100f3268[0])); + m_unk0x08[2].SetUnknown0x08(rand() % (sizeof(g_unk0x100f3268) / sizeof(g_unk0x100f3268[0]))); + + m_active = FALSE; +} + +// FUNCTION: LEGO1 0x1002cf50 +MxBool RadioState::IsSerializable() +{ + return FALSE; +} + +// FUNCTION: LEGO1 0x1002d090 +MxU32 RadioState::FUN_1002d090() +{ + if (m_unk0x2c == 2) { + m_unk0x2c = 0; + } + else { + m_unk0x2c++; + } + + return m_unk0x08[m_unk0x2c].Next(); +} + +// FUNCTION: LEGO1 0x1002d0c0 +MxBool RadioState::FUN_1002d0c0(const MxAtomId& p_atom, MxU32 p_objectId) +{ + if (*g_jukeboxScript == p_atom) { + for (MxS16 i = 0; i < 3; i++) { + if (m_unk0x08[i].Contains(p_objectId)) { + return TRUE; + } + } + } + + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/main/legomain.cpp b/LEGO1/lego/legoomni/src/main/legomain.cpp new file mode 100644 index 00000000..7b559faa --- /dev/null +++ b/LEGO1/lego/legoomni/src/main/legomain.cpp @@ -0,0 +1,593 @@ +#include "legomain.h" + +#include "3dmanager/lego3dmanager.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legobuildingmanager.h" +#include "legocharactermanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legoobjectfactory.h" +#include "legoplantmanager.h" +#include "legosoundmanager.h" +#include "legoutils.h" +#include "legovariables.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "legoworldlist.h" +#include "misc.h" +#include "misc/legocontainer.h" +#include "mxactionnotificationparam.h" +#include "mxautolock.h" +#include "mxbackgroundaudiomanager.h" +#include "mxdisplaysurface.h" +#include "mxdsfile.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxomnicreateflags.h" +#include "mxomnicreateparam.h" +#include "mxstreamer.h" +#include "mxticklemanager.h" +#include "mxtransitionmanager.h" +#include "mxvariabletable.h" +#include "scripts.h" +#include "viewmanager/viewmanager.h" + +DECOMP_SIZE_ASSERT(LegoOmni, 0x140) +DECOMP_SIZE_ASSERT(LegoOmni::ScriptContainer, 0x1c) +DECOMP_SIZE_ASSERT(LegoWorldList, 0x18) +DECOMP_SIZE_ASSERT(LegoWorldListCursor, 0x10) + +// GLOBAL: LEGO1 0x100f6718 +// STRING: LEGO1 0x100f6710 +const char* g_current = "current"; + +// FUNCTION: LEGO1 0x10058a00 +LegoOmni::LegoOmni() +{ + Init(); +} + +// FUNCTION: LEGO1 0x10058b50 +LegoOmni::~LegoOmni() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x10058bd0 +void LegoOmni::Init() +{ + MxOmni::Init(); + m_scripts = NULL; + m_inputManager = NULL; + m_viewLODListManager = NULL; + m_textureContainer = NULL; + m_worldList = NULL; + m_currentWorld = NULL; + m_exit = FALSE; + m_currentActor = NULL; + m_characterManager = NULL; + m_plantManager = NULL; + m_gameState = NULL; + m_animationManager = NULL; + m_buildingManager = NULL; + m_bkgAudioManager = NULL; + m_unk0x13c = TRUE; + m_transitionManager = NULL; +} + +// FUNCTION: LEGO1 0x10058c30 +void LegoOmni::Destroy() +{ + AUTOLOCK(m_criticalSection); + + m_notificationManager->Unregister(this); + + if (m_worldList) { + delete m_worldList; + m_worldList = NULL; + } + + if (m_gameState) { + delete m_gameState; + m_gameState = NULL; + } + + if (m_animationManager) { + delete m_animationManager; + m_animationManager = NULL; + } + + if (m_characterManager) { + delete m_characterManager; + m_characterManager = NULL; + } + + if (m_plantManager) { + delete m_plantManager; + m_plantManager = NULL; + } + + if (m_buildingManager) { + delete m_buildingManager; + m_buildingManager = NULL; + } + + if (m_textureContainer) { + m_textureContainer->Clear(); + delete m_textureContainer; + m_textureContainer = NULL; + } + + if (m_viewLODListManager) { + delete m_viewLODListManager; + m_viewLODListManager = NULL; + } + + if (m_inputManager) { + delete m_inputManager; + m_inputManager = NULL; + } + + LegoPathController::Reset(); + + if (m_bkgAudioManager) { + m_bkgAudioManager->Stop(); + delete m_bkgAudioManager; + m_bkgAudioManager = NULL; + } + + if (m_transitionManager) { + delete m_transitionManager; + m_transitionManager = NULL; + } + + m_action.ClearAtom(); + DestroyScripts(); + + if (m_scripts) { + delete[] m_scripts; + } + + MxOmni::Destroy(); +} + +// FUNCTION: LEGO1 0x10058e70 +MxResult LegoOmni::Create(MxOmniCreateParam& p_param) +{ + MxResult result = FAILURE; + AUTOLOCK(m_criticalSection); + + p_param.CreateFlags().CreateObjectFactory(FALSE); + p_param.CreateFlags().CreateVideoManager(FALSE); + p_param.CreateFlags().CreateSoundManager(FALSE); + p_param.CreateFlags().CreateTickleManager(FALSE); + + if (!(m_tickleManager = new MxTickleManager())) { + goto done; + } + + if (MxOmni::Create(p_param) != SUCCESS) { + goto done; + } + + if (!(m_objectFactory = new LegoObjectFactory())) { + goto done; + } + + if (!(m_soundManager = new LegoSoundManager()) || m_soundManager->Create(10, 0) != SUCCESS) { + delete m_soundManager; + m_soundManager = NULL; + goto done; + } + + if (!(m_videoManager = new LegoVideoManager()) || + m_videoManager->Create(p_param.GetVideoParam(), 100, 0) != SUCCESS) { + delete m_videoManager; + m_videoManager = NULL; + goto done; + } + + if (!(m_inputManager = new LegoInputManager()) || m_inputManager->Create(p_param.GetWindowHandle()) != SUCCESS) { + delete m_inputManager; + m_inputManager = NULL; + goto done; + } + + m_viewLODListManager = new ViewLODListManager(); + m_textureContainer = new LegoTextureContainer(); + m_textureContainer->SetOwnership(FALSE); + LegoPathController::Init(); + + m_characterManager = new LegoCharacterManager(); + m_plantManager = new LegoPlantManager(); + m_animationManager = new LegoAnimationManager(); + m_buildingManager = new LegoBuildingManager(); + m_gameState = new LegoGameState(); + m_worldList = new LegoWorldList(TRUE); + + if (!m_viewLODListManager || !m_textureContainer || !m_worldList || !m_characterManager || !m_plantManager || + !m_animationManager || !m_buildingManager) { + goto done; + } + + MxVariable* variable; + + if (!(variable = new VisibilityVariable())) { + goto done; + } + m_variableTable->SetVariable(variable); + + if (!(variable = new CameraLocationVariable())) { + goto done; + } + m_variableTable->SetVariable(variable); + + if (!(variable = new CursorVariable())) { + goto done; + } + m_variableTable->SetVariable(variable); + + if (!(variable = new WhoAmIVariable())) { + goto done; + } + m_variableTable->SetVariable(variable); + + CreateScripts(); + IslePathActor::RegisterSpawnLocations(); + result = RegisterScripts(); + + if (result != SUCCESS) { + goto done; + } + + if (!(m_bkgAudioManager = new MxBackgroundAudioManager())) { + goto done; + } + + if (!(m_transitionManager = new MxTransitionManager())) { + goto done; + } + + if (m_transitionManager->GetDDrawSurfaceFromVideoManager() != SUCCESS) { + goto done; + } + + m_notificationManager->Register(this); + SetAppCursor(1); + m_gameState->SetCurrentAct(LegoGameState::e_act1); + + result = SUCCESS; + +done: + return result; +} + +// FUNCTION: LEGO1 0x1005a5f0 +MxResult LegoOmni::RegisterScripts() +{ + m_scripts = new ScriptContainer[19]; + + if (!m_scripts) { + return FAILURE; + } + + m_scripts[0] = ScriptContainer(); + m_scripts[1] = ScriptContainer(0, "ACT1", g_isleScript); + m_scripts[2] = ScriptContainer(1, "IMAIN", g_infomainScript); + m_scripts[3] = ScriptContainer(2, "ICUBE", g_infoscorScript); + m_scripts[4] = ScriptContainer(3, "IREG", g_regbookScript); + m_scripts[5] = ScriptContainer(4, "IELEV", g_elevbottScript); + m_scripts[6] = ScriptContainer(5, "IISLE", g_infodoorScript); + m_scripts[7] = ScriptContainer(6, "HOSP", g_hospitalScript); + m_scripts[8] = ScriptContainer(7, "POLICE", g_policeScript); + m_scripts[9] = ScriptContainer(8, "GMAIN", g_garageScript); + m_scripts[10] = ScriptContainer(9, "BLDH", g_copterScript); + m_scripts[11] = ScriptContainer(10, "BLDD", g_dunecarScript); + m_scripts[12] = ScriptContainer(11, "BLDJ", g_jetskiScript); + m_scripts[13] = ScriptContainer(12, "BLDR", g_racecarScript); + m_scripts[14] = ScriptContainer(13, "RACC", g_carraceScript); + m_scripts[15] = ScriptContainer(14, "RACJ", g_jetraceScript); + m_scripts[16] = ScriptContainer(15, "ACT2", g_act2mainScript); + m_scripts[17] = ScriptContainer(16, "ACT3", g_act3Script); + m_scripts[18] = ScriptContainer(17, "TEST", g_testScript); + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1005ac90 +void LegoOmni::CreateInstance() +{ + MxOmni::DestroyInstance(); + MxOmni::SetInstance(new LegoOmni()); +} + +// FUNCTION: LEGO1 0x1005ad10 +LegoOmni* LegoOmni::GetInstance() +{ + return (LegoOmni*) MxOmni::GetInstance(); +} + +// FUNCTION: LEGO1 0x1005ad20 +void LegoOmni::AddWorld(LegoWorld* p_world) +{ + m_worldList->Append(p_world); +} + +// FUNCTION: LEGO1 0x1005adb0 +void LegoOmni::DeleteWorld(LegoWorld* p_world) +{ + if (m_worldList) { + LegoWorldListCursor cursor(m_worldList); + + if (cursor.Find(p_world)) { + cursor.Detach(); + + if (m_currentWorld == p_world) { + m_currentWorld = NULL; + } + + delete p_world; + } + } +} + +// FUNCTION: LEGO1 0x1005af10 +void LegoOmni::RemoveWorld(const MxAtomId& p_atom, MxLong p_objectId) +{ + if (m_worldList) { + LegoWorldListCursor a(m_worldList); + LegoWorldListCursor b(m_worldList); + LegoWorld* world; + + a.Head(); + while (a.Current(world)) { + b = a; + b.Next(); + + if ((p_objectId == -1 || world->GetEntityId() == p_objectId) && + (!p_atom.GetInternal() || world->GetAtom() == p_atom)) { + a.Detach(); + delete world; + } + + a = b; + } + } +} + +// FUNCTION: LEGO1 0x1005b0c0 +LegoWorld* LegoOmni::FindWorld(const MxAtomId& p_atom, MxS32 p_entityid) +{ + if (m_worldList) { + LegoWorldListCursor cursor(m_worldList); + LegoWorld* world; + + while (cursor.Next(world)) { + if ((p_entityid == -1 || world->GetEntityId() == p_entityid) && + (!p_atom.GetInternal() || world->GetAtom() == p_atom)) { + return world; + } + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x1005b1d0 +void LegoOmni::DeleteObject(MxDSAction& p_dsAction) +{ + if (p_dsAction.GetAtomId().GetInternal() != NULL) { + LegoWorld* world = FindWorld(p_dsAction.GetAtomId(), p_dsAction.GetObjectId()); + if (world) { + DeleteWorld(world); + return; + } + + if (m_currentWorld != NULL) { + MxCore* entity = m_currentWorld->Find(p_dsAction.GetAtomId(), p_dsAction.GetObjectId()); + if (entity) { + m_currentWorld->Remove(entity); + + if (entity->IsA("MxPresenter")) { + Streamer()->FUN_100b98f0(((MxPresenter*) entity)->GetAction()); + ((MxPresenter*) entity)->EndAction(); + } + else { + delete entity; + } + return; + } + } + } + MxOmni::DeleteObject(p_dsAction); +} + +// FUNCTION: LEGO1 0x1005b270 +LegoROI* LegoOmni::FindROI(const char* p_name) +{ + ViewManager* viewManager = GetVideoManager()->Get3DManager()->GetLego3DView()->GetViewManager(); + const CompoundObject& rois = viewManager->GetROIs(); + + if (p_name != NULL && *p_name != '\0' && rois.size() > 0) { + for (CompoundObject::const_iterator it = rois.begin(); it != rois.end(); it++) { + LegoROI* roi = (LegoROI*) *it; + const char* name = roi->GetName(); + + if (name != NULL) { + if (!strcmpi(name, p_name)) { + return roi; + } + } + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x1005b2f0 +MxEntity* LegoOmni::AddToWorld(const char* p_id, MxS32 p_entityId, MxPresenter* p_presenter) +{ + LegoWorld* world = NULL; + + if (strcmpi(p_id, g_current)) { + world = FindWorld(MxAtomId(p_id, e_lowerCase2), p_entityId); + } + else { + world = this->m_currentWorld; + } + + if (world != NULL) { + world->Add(p_presenter); + } + + return world; +} + +// FUNCTION: LEGO1 0x1005b3a0 +void LegoOmni::NotifyCurrentEntity(const MxNotificationParam& p_param) +{ + if (m_currentWorld) { + NotificationManager()->Send(m_currentWorld, p_param); + } +} + +// FUNCTION: LEGO1 0x1005b3c0 +MxBool LegoOmni::DoesEntityExist(MxDSAction& p_dsAction) +{ + if (MxOmni::DoesEntityExist(p_dsAction)) { + if (FindWorld(p_dsAction.GetAtomId(), p_dsAction.GetObjectId()) == NULL) { + return TRUE; + } + } + return FALSE; +} + +// FUNCTION: LEGO1 0x1005b400 +MxS32 LegoOmni::GetCurrPathInfo(LegoPathBoundary** p_path, MxS32& p_value) +{ + if (::CurrentWorld() == NULL) { + return FAILURE; + } + + return ::CurrentWorld()->GetCurrPathInfo(p_path, p_value); +} + +// FUNCTION: LEGO1 0x1005b430 +const char* LegoOmni::GetScriptName(MxU32 p_index) +{ + for (MxS32 i = 0; i < 19; i++) { + if (m_scripts[i].m_index == p_index) { + return m_scripts[i].m_key; + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x1005b460 +MxAtomId* LegoOmni::GetScriptAtom(MxU32 p_index) +{ + for (MxS32 i = 0; i < 19; i++) { + if (m_scripts[i].m_index == p_index) { + return m_scripts[i].m_atomId; + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x1005b490 +MxS32 LegoOmni::GetScriptIndex(const char* p_key) +{ + for (MxS32 i = 0; i < 19; i++) { + if ((MxS32) &m_scripts[i] != -4 && !strcmpi(m_scripts[i].GetKey(), p_key)) { + return m_scripts[i].GetIndex(); + } + } + + return -1; +} + +// FUNCTION: LEGO1 0x1005b4f0 +void LegoOmni::FUN_1005b4f0(MxBool p_disable, MxU16 p_flags) +{ + if (p_disable) { + if (p_flags & c_disableInput) { + m_inputManager->DisableInputProcessing(); + } + + if (p_flags & c_disable3d) { + ((LegoVideoManager*) m_videoManager)->SetRender3D(FALSE); + } + + if (p_flags & c_clearScreen) { + m_videoManager->GetDisplaySurface()->ClearScreen(); + } + } + else { + m_inputManager->EnableInputProcessing(); + ((LegoVideoManager*) m_videoManager)->SetRender3D(TRUE); + ((LegoVideoManager*) m_videoManager)->UpdateView(0, 0, 0, 0); + } +} + +// FUNCTION: LEGO1 0x1005b560 +void LegoOmni::CreateBackgroundAudio() +{ + if (m_bkgAudioManager) { + m_bkgAudioManager->Create(*g_jukeboxScript, 100); + } +} + +// FUNCTION: LEGO1 0x1005b580 +MxResult LegoOmni::Start(MxDSAction* p_dsAction) +{ + MxResult result = MxOmni::Start(p_dsAction); + this->m_action.SetAtomId(p_dsAction->GetAtomId()); + this->m_action.SetObjectId(p_dsAction->GetObjectId()); + this->m_action.SetUnknown24(p_dsAction->GetUnknown24()); + return result; +} + +// FUNCTION: LEGO1 0x1005b5c0 +void LegoOmni::DeleteAction() +{ + if (m_action.GetObjectId() != -1) { + DeleteObject(m_action); + m_action.SetObjectId(-1); + } +} + +// FUNCTION: LEGO1 0x1005b5f0 +MxLong LegoOmni::Notify(MxParam& p_param) +{ + MxBool isCD = FALSE; + + if (((MxNotificationParam&) p_param).GetType() == c_notificationEndAction && + ((MxActionNotificationParam&) p_param).GetAction()->GetAtomId() == *g_nocdSourceName) { + isCD = TRUE; + } + + MxLong result = MxOmni::Notify(p_param); + if (isCD) { + // Exit the game if nocd.si ended + CloseMainWindow(); + } + + return result; +} + +// FUNCTION: LEGO1 0x1005b640 +void LegoOmni::StartTimer() +{ + MxOmni::StartTimer(); + SetAppCursor(2); +} + +// FUNCTION: LEGO1 0x1005b650 +void LegoOmni::StopTimer() +{ + MxOmni::StopTimer(); + SetAppCursor(0); +} diff --git a/LEGO1/lego/legoomni/src/main/scripts.cpp b/LEGO1/lego/legoomni/src/main/scripts.cpp new file mode 100644 index 00000000..32c3f86e --- /dev/null +++ b/LEGO1/lego/legoomni/src/main/scripts.cpp @@ -0,0 +1,189 @@ +#include "scripts.h" + +#include "mxatom.h" + +// GLOBAL: LEGO1 0x100f451c +MxAtomId* g_copterScript = NULL; + +// GLOBAL: LEGO1 0x100f4520 +MxAtomId* g_dunecarScript = NULL; + +// GLOBAL: LEGO1 0x100f4524 +MxAtomId* g_jetskiScript = NULL; + +// GLOBAL: LEGO1 0x100f4528 +MxAtomId* g_racecarScript = NULL; + +// GLOBAL: LEGO1 0x100f452c +MxAtomId* g_carraceScript = NULL; + +// GLOBAL: LEGO1 0x100f4530 +MxAtomId* g_carracerScript = NULL; + +// GLOBAL: LEGO1 0x100f4534 +MxAtomId* g_jetraceScript = NULL; + +// GLOBAL: LEGO1 0x100f4538 +MxAtomId* g_jetracerScript = NULL; + +// GLOBAL: LEGO1 0x100f453c +MxAtomId* g_isleScript = NULL; + +// GLOBAL: LEGO1 0x100f4540 +MxAtomId* g_elevbottScript = NULL; + +// GLOBAL: LEGO1 0x100f4544 +MxAtomId* g_infodoorScript = NULL; + +// GLOBAL: LEGO1 0x100f4548 +MxAtomId* g_infomainScript = NULL; + +// GLOBAL: LEGO1 0x100f454c +MxAtomId* g_infoscorScript = NULL; + +// GLOBAL: LEGO1 0x100f4550 +MxAtomId* g_regbookScript = NULL; + +// GLOBAL: LEGO1 0x100f4554 +MxAtomId* g_histbookScript = NULL; + +// GLOBAL: LEGO1 0x100f4558 +MxAtomId* g_hospitalScript = NULL; + +// GLOBAL: LEGO1 0x100f455c +MxAtomId* g_policeScript = NULL; + +// GLOBAL: LEGO1 0x100f4560 +MxAtomId* g_garageScript = NULL; + +// GLOBAL: LEGO1 0x100f4564 +MxAtomId* g_act2mainScript = NULL; + +// GLOBAL: LEGO1 0x100f4568 +MxAtomId* g_act3Script = NULL; + +// GLOBAL: LEGO1 0x100f456c +MxAtomId* g_jukeboxScript = NULL; + +// GLOBAL: LEGO1 0x100f4570 +MxAtomId* g_pz5Script = NULL; + +// GLOBAL: LEGO1 0x100f4574 +MxAtomId* g_introScript = NULL; + +// GLOBAL: LEGO1 0x100f4578 +MxAtomId* g_testScript = NULL; + +// GLOBAL: LEGO1 0x100f457c +MxAtomId* g_jukeboxwScript = NULL; + +// GLOBAL: LEGO1 0x100f4580 +MxAtomId* g_sndAnimScript = NULL; + +// GLOBAL: LEGO1 0x100f4584 +MxAtomId* g_creditsScript = NULL; + +// GLOBAL: LEGO1 0x100f4588 +MxAtomId* g_nocdSourceName = NULL; + +// FUNCTION: LEGO1 0x100528e0 +void CreateScripts() +{ + g_copterScript = new MxAtomId("\\lego\\scripts\\build\\copter", e_lowerCase2); + g_dunecarScript = new MxAtomId("\\lego\\scripts\\build\\dunecar", e_lowerCase2); + g_jetskiScript = new MxAtomId("\\lego\\scripts\\build\\jetski", e_lowerCase2); + g_racecarScript = new MxAtomId("\\lego\\scripts\\build\\racecar", e_lowerCase2); + g_carraceScript = new MxAtomId("\\lego\\scripts\\race\\carrace", e_lowerCase2); + g_carracerScript = new MxAtomId("\\lego\\scripts\\race\\carracer", e_lowerCase2); + g_jetraceScript = new MxAtomId("\\lego\\scripts\\race\\jetrace", e_lowerCase2); + g_jetracerScript = new MxAtomId("\\lego\\scripts\\race\\jetracer", e_lowerCase2); + g_isleScript = new MxAtomId("\\lego\\scripts\\isle\\isle", e_lowerCase2); + g_elevbottScript = new MxAtomId("\\lego\\scripts\\infocntr\\elevbott", e_lowerCase2); + g_infodoorScript = new MxAtomId("\\lego\\scripts\\infocntr\\infodoor", e_lowerCase2); + g_infomainScript = new MxAtomId("\\lego\\scripts\\infocntr\\infomain", e_lowerCase2); + g_infoscorScript = new MxAtomId("\\lego\\scripts\\infocntr\\infoscor", e_lowerCase2); + g_regbookScript = new MxAtomId("\\lego\\scripts\\infocntr\\regbook", e_lowerCase2); + g_histbookScript = new MxAtomId("\\lego\\scripts\\infocntr\\histbook", e_lowerCase2); + g_hospitalScript = new MxAtomId("\\lego\\scripts\\hospital\\hospital", e_lowerCase2); + g_policeScript = new MxAtomId("\\lego\\scripts\\police\\police", e_lowerCase2); + g_garageScript = new MxAtomId("\\lego\\scripts\\garage\\garage", e_lowerCase2); + g_act2mainScript = new MxAtomId("\\lego\\scripts\\act2\\act2main", e_lowerCase2); + g_act3Script = new MxAtomId("\\lego\\scripts\\act3\\act3", e_lowerCase2); + g_jukeboxScript = new MxAtomId("\\lego\\scripts\\isle\\jukebox", e_lowerCase2); + g_pz5Script = new MxAtomId("\\lego\\scripts\\isle\\pz5", e_lowerCase2); + g_introScript = new MxAtomId("\\lego\\scripts\\intro", e_lowerCase2); + g_testScript = new MxAtomId("\\lego\\scripts\\test\\test", e_lowerCase2); + g_jukeboxwScript = new MxAtomId("\\lego\\scripts\\isle\\jukeboxw", e_lowerCase2); + g_sndAnimScript = new MxAtomId("\\lego\\scripts\\sndanim", e_lowerCase2); + g_creditsScript = new MxAtomId("\\lego\\scripts\\credits", e_lowerCase2); + g_nocdSourceName = new MxAtomId("\\lego\\scripts\\nocd", e_lowerCase2); +} + +// FUNCTION: LEGO1 0x100530c0 +void DestroyScripts() +{ + delete g_copterScript; + delete g_dunecarScript; + delete g_jetskiScript; + delete g_racecarScript; + delete g_carraceScript; + delete g_carracerScript; + delete g_jetraceScript; + delete g_jetracerScript; + delete g_isleScript; + delete g_elevbottScript; + delete g_infodoorScript; + delete g_infomainScript; + delete g_infoscorScript; + delete g_regbookScript; + delete g_histbookScript; + delete g_hospitalScript; + delete g_policeScript; + delete g_garageScript; + delete g_act2mainScript; + delete g_act3Script; + delete g_jukeboxScript; + delete g_pz5Script; + delete g_introScript; + delete g_testScript; + delete g_jukeboxwScript; + delete g_sndAnimScript; + delete g_creditsScript; + delete g_nocdSourceName; + + g_copterScript = NULL; + g_dunecarScript = NULL; + g_jetskiScript = NULL; + g_racecarScript = NULL; + g_carraceScript = NULL; + g_carracerScript = NULL; + g_jetraceScript = NULL; + g_jetracerScript = NULL; + g_isleScript = NULL; + g_elevbottScript = NULL; + g_infodoorScript = NULL; + g_infomainScript = NULL; + g_infoscorScript = NULL; + g_regbookScript = NULL; + g_histbookScript = NULL; + g_hospitalScript = NULL; + g_policeScript = NULL; + g_garageScript = NULL; + g_act2mainScript = NULL; + g_act3Script = NULL; + g_jukeboxScript = NULL; + g_pz5Script = NULL; + g_introScript = NULL; + g_testScript = NULL; + g_testScript = NULL; + g_jukeboxwScript = NULL; + g_sndAnimScript = NULL; + g_creditsScript = NULL; + g_nocdSourceName = NULL; +} + +// FUNCTION: LEGO1 0x10053430 +const char* GetNoCD_SourceName() +{ + return g_nocdSourceName->GetInternal(); +} diff --git a/LEGO1/lego/legoomni/src/notify/legoeventnotificationparam.cpp b/LEGO1/lego/legoomni/src/notify/legoeventnotificationparam.cpp new file mode 100644 index 00000000..dd7b0fb5 --- /dev/null +++ b/LEGO1/lego/legoomni/src/notify/legoeventnotificationparam.cpp @@ -0,0 +1,5 @@ +#include "legoeventnotificationparam.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(LegoEventNotificationParam, 0x20) diff --git a/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp new file mode 100644 index 00000000..70c73fe2 --- /dev/null +++ b/LEGO1/lego/legoomni/src/paths/legoanimactor.cpp @@ -0,0 +1,220 @@ +#include "legoanimactor.h" + +#include "anim/legoanim.h" +#include "define.h" +#include "legolocomotionanimpresenter.h" +#include "legopathboundary.h" +#include "legoworld.h" +#include "misc.h" +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(LegoAnimActor, 0x174) +DECOMP_SIZE_ASSERT(LegoAnimActorStruct, 0x20) + +// FUNCTION: LEGO1 0x1001bf80 +LegoAnimActorStruct::LegoAnimActorStruct(float p_unk0x00, LegoAnim* p_AnimTreePtr, LegoROI** p_roiMap, MxU32 p_numROIs) +{ + m_unk0x00 = p_unk0x00; + m_AnimTreePtr = p_AnimTreePtr; + m_roiMap = p_roiMap; + m_numROIs = p_numROIs; +} + +// FUNCTION: LEGO1 0x1001c0a0 +LegoAnimActorStruct::~LegoAnimActorStruct() +{ + for (MxU16 i = 0; i < m_unk0x10.size(); i++) { + delete m_unk0x10[i]; + } +} + +// FUNCTION: LEGO1 0x1001c130 +float LegoAnimActorStruct::GetDuration() +{ + return m_AnimTreePtr->GetDuration(); +} + +// FUNCTION: LEGO1 0x1001c140 +LegoAnimActor::~LegoAnimActor() +{ + for (MxS32 i = 0; i < m_animMaps.size(); i++) { + if (m_animMaps[i]) { + delete m_animMaps[i]; + } + } +} + +// FUNCTION: LEGO1 0x1001c1f0 +MxResult LegoAnimActor::FUN_1001c1f0(float& p_und) +{ + float duration = (float) m_animMaps[m_curAnim]->m_AnimTreePtr->GetDuration(); + p_und = m_actorTime - duration * ((MxS32) (m_actorTime / duration)); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1001c240 +void LegoAnimActor::VTable0x74(Matrix4& p_transform) +{ + float und; + LegoPathActor::VTable0x74(p_transform); + + if (m_curAnim >= 0) { + FUN_1001c1f0(und); + FUN_1001c360(und, p_transform); + } +} + +// FUNCTION: LEGO1 0x1001c290 +void LegoAnimActor::VTable0x70(float p_float) +{ + if (m_lastTime == 0) { + m_lastTime = p_float - 1.0f; + } + + if (m_state == 0 && !m_userNavFlag && m_worldSpeed <= 0) { + if (m_curAnim >= 0) { + MxMatrix matrix(m_unk0xec); + float f; + FUN_1001c1f0(f); + FUN_1001c360(f, matrix); + } + + m_lastTime = m_actorTime = p_float; + } + else { + LegoPathActor::VTable0x70(p_float); + } +} + +// FUNCTION: LEGO1 0x1001c360 +MxResult LegoAnimActor::FUN_1001c360(float p_und, Matrix4& p_transform) +{ + if (p_und >= 0) { + LegoROI** roiMap = m_animMaps[m_curAnim]->m_roiMap; + MxU32 numROIs = m_animMaps[m_curAnim]->m_numROIs; + + if (!m_boundary->GetFlag0x10()) { + MxU32 i; + m_roi->SetVisibility(FALSE); + + for (i = 0; i < numROIs; i++) { + LegoROI* roi = roiMap[i]; + + if (roi != NULL && m_roi != roi) { + roi->SetVisibility(FALSE); + } + } + } + else { + LegoTreeNode* root = m_animMaps[m_curAnim]->m_AnimTreePtr->GetRoot(); + m_roi->SetVisibility(TRUE); + + for (MxU32 i = 0; i < numROIs; i++) { + LegoROI* roi = roiMap[i]; + + if (roi != NULL && m_roi != roi) { + roi->SetVisibility(TRUE); + } + } + + for (MxS32 j = 0; j < root->GetNumChildren(); j++) { + LegoROI::FUN_100a8e80(root->GetChild(j), p_transform, p_und, roiMap); + } + + if (m_cameraFlag) { + FUN_10010c30(); + } + } + + return SUCCESS; + } + else { + return FAILURE; + } +} + +// FUNCTION: LEGO1 0x1001c450 +MxResult LegoAnimActor::FUN_1001c450(LegoAnim* p_animTreePtr, float p_unk0x00, LegoROI** p_roiMap, MxU32 p_numROIs) +{ + LegoAnimActorStruct* laas = new LegoAnimActorStruct(p_unk0x00, p_animTreePtr, p_roiMap, p_numROIs); + + for (vector::iterator it = m_animMaps.begin(); it != m_animMaps.end(); it++) { + if (p_unk0x00 < (*it)->m_unk0x00) { + m_animMaps.insert(it, laas); + SetWorldSpeed(m_worldSpeed); + return SUCCESS; + } + } + + m_animMaps.push_back(laas); + SetWorldSpeed(m_worldSpeed); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1001c800 +void LegoAnimActor::ClearMaps() +{ + for (MxU32 i = 0; i < m_animMaps.size(); i++) { + delete m_animMaps[i]; + } + + m_animMaps.clear(); + m_curAnim = -1; +} + +// FUNCTION: LEGO1 0x1001c870 +void LegoAnimActor::SetWorldSpeed(MxFloat p_worldSpeed) +{ + if (p_worldSpeed < 0) { + m_worldSpeed = 0; + } + else { + m_worldSpeed = p_worldSpeed; + } + + if (m_animMaps.size() > 0) { + m_curAnim = 0; + + if (m_worldSpeed >= m_animMaps[m_animMaps.size() - 1]->m_unk0x00) { + m_curAnim = m_animMaps.size() - 1; + } + else { + for (MxU32 i = 0; i < m_animMaps.size(); i++) { + if (m_worldSpeed <= m_animMaps[i]->m_unk0x00) { + m_curAnim = i; + break; + } + } + } + } +} + +// FUNCTION: LEGO1 0x1001c920 +void LegoAnimActor::ParseAction(char* p_extra) +{ + LegoPathActor::ParseAction(p_extra); + + LegoWorld* world = CurrentWorld(); + char value[256]; + + if (world) { + if (KeyValueStringParse(value, g_strANIMATION, p_extra)) { + char* token = strtok(value, g_parseExtraTokens); + + while (token) { + LegoLocomotionAnimPresenter* presenter = + (LegoLocomotionAnimPresenter*) world->Find("LegoAnimPresenter", token); + + if (presenter != NULL) { + token = strtok(NULL, g_parseExtraTokens); + + if (token) { + presenter->FUN_1006d680(this, atof(token)); + } + } + + token = strtok(NULL, g_parseExtraTokens); + } + } + } +} diff --git a/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp new file mode 100644 index 00000000..a88ca7b3 --- /dev/null +++ b/LEGO1/lego/legoomni/src/paths/legoextraactor.cpp @@ -0,0 +1,442 @@ +#include "legoextraactor.h" + +#include "anim/legoanim.h" +#include "legocachesoundmanager.h" +#include "legolocomotionanimpresenter.h" +#include "legopathboundary.h" +#include "legosoundmanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxtimer.h" + +DECOMP_SIZE_ASSERT(LegoExtraActor, 0x1dc) + +// GLOBAL: LEGO1 0x100f31d0 +LegoWorld* g_unk0x100f31d0 = NULL; + +// GLOBAL: LEGO1 0x100f31d4 +LegoLocomotionAnimPresenter* m_assAnimP = NULL; + +// GLOBAL: LEGO1 0x100f31d8 +LegoLocomotionAnimPresenter* m_disAnimP = NULL; + +// GLOBAL: LEGO1 0x100f31dc +MxS32 g_unk0x100f31dc = 0; + +// GLOBAL: LEGO1 0x10104c18 +Mx3DPointFloat g_unk0x10104c18 = Mx3DPointFloat(0.0f, 2.5f, 0.0f); + +// FUNCTION: LEGO1 0x1002a500 +LegoExtraActor::LegoExtraActor() +{ + m_unk0x70 = 0.0f; + m_scheduledTime = 0; + m_unk0x0c = 0; + m_unk0x0e = 0; + m_whichAnim = 0; + m_assAnim = NULL; + m_disAnim = NULL; + m_unk0x15 = 0; +} + +// FUNCTION: LEGO1 0x1002a6b0 +LegoExtraActor::~LegoExtraActor() +{ + delete m_assAnim; + delete m_disAnim; +} + +// FUNCTION: LEGO1 0x1002a720 +MxU32 LegoExtraActor::VTable0x90(float p_time, Matrix4& p_transform) +{ + switch (m_state & 0xff) { + case 0: + case 1: + return TRUE; + case 2: + m_scheduledTime = p_time + 2000.0f; + m_state = 3; + m_actorTime += (p_time - m_lastTime) * m_worldSpeed; + m_lastTime = p_time; + return FALSE; + case 3: { + Vector3 positionRef(p_transform[3]); + p_transform = m_roi->GetLocal2World(); + + if (p_time < m_scheduledTime) { + Mx3DPointFloat position; + position = positionRef; + positionRef.Clear(); + + switch (m_axis) { + case e_posz: { + p_transform.RotateZ(0.7f); + break; + } + case e_negz: { + p_transform.RotateZ(-0.7f); + break; + } + case e_posx: { + p_transform.RotateX(0.7f); + break; + } + case e_negx: { + p_transform.RotateX(-0.7f); + break; + } + } + + positionRef = position; + m_actorTime += (p_time - m_lastTime) * m_worldSpeed; + m_lastTime = p_time; + VTable0x74(p_transform); + return FALSE; + } + else { + m_state = 0; + m_scheduledTime = 0.0f; + ((Vector3&) positionRef).Sub(&g_unk0x10104c18); // TODO: Fix call + m_roi->FUN_100a58f0(p_transform); + return TRUE; + } + } + + default: + return FALSE; + } +} + +// FUNCTION: LEGO1 0x1002aa90 +void LegoExtraActor::VTable0xa4(MxU8& p_und1, MxS32& p_und2) +{ + switch (m_unk0x0c) { + case 1: + p_und1 = 1; + p_und2 = 1; + break; + case 2: + p_und1 = 0; + p_und2 = 1; + break; + default: + p_und1 = 1; + p_und2 = rand() % p_und2 + 1; + break; + } +} + +// FUNCTION: LEGO1 0x1002aae0 +MxResult LegoExtraActor::VTable0xc8() +{ + LegoPathBoundary* oldEdge = m_boundary; + Vector3 rightRef(m_unk0xec[0]); + Vector3 upRef(m_unk0xec[1]); + Vector3 dirRef(m_unk0xec[2]); + Vector3 positionRef(m_unk0xec[3]); + + // TODO: Fix call + ((Vector3&) dirRef).Mul(-1.0f); + rightRef.EqualsCross(&upRef, &dirRef); + + if (m_boundary == m_destEdge->m_faceA) { + m_boundary = (LegoPathBoundary*) m_destEdge->m_faceB; + } + else { + m_boundary = (LegoPathBoundary*) m_destEdge->m_faceA; + } + + if (!m_boundary) { + m_boundary = oldEdge; + } + + LegoPathActor::WaitForAnimation(); + return SUCCESS; +} + +inline void LegoExtraActor::FUN_1002ad8a() +{ + LegoWorld* w = CurrentWorld(); + + if (g_unk0x100f31d0 != w) { + g_unk0x100f31d0 = w; + m_assAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsAss01"); + m_disAnimP = (LegoLocomotionAnimPresenter*) w->Find("LegoAnimPresenter", "BNsDis01"); + } + + if (!m_assAnim) { + MxS32 index = 0; + m_assAnimP->FUN_1006d680(this, -20.0f); + + for (MxS32 i = 0; i < m_animMaps.size(); i++) { + if (m_animMaps[i]->GetUnknown0x00() == -20.0f) { + m_assAnim = new LegoAnimActorStruct(*m_animMaps[i]); + break; + } + } + } + + if (!m_disAnim) { + MxS32 index = 0; + m_disAnimP->FUN_1006d680(this, -21.0f); + + for (MxS32 i = 0; i < m_animMaps.size(); i++) { + if (m_animMaps[i]->GetUnknown0x00() == -21.0f) { + m_disAnim = new LegoAnimActorStruct(*m_animMaps[i]); + break; + } + } + } +} + +// FUNCTION: LEGO1 0x1002aba0 +MxResult LegoExtraActor::VTable0x94(LegoPathActor* p_actor, MxBool p_bool) +{ + if (p_actor->GetState() != 0 || m_state != 0) { + return FAILURE; + } + + if (p_bool) { + if (m_unk0x15 != 0) { + return FAILURE; + } + + m_unk0x15 = 100; + VTable0xc8(); + } + else { + MxU32 b = FALSE; + + if (++g_unk0x100f31dc % 2 == 0) { + MxMatrix matrix(p_actor->GetROI()->GetLocal2World()); + MxMatrix matrix2(m_roi->GetLocal2World()); + + m_unk0x18 = matrix2; + Vector3 positionRef(matrix2[3]); + Mx3DPointFloat dir(matrix[2]); + + // TODO: Fix calls + ((Mx3DPointFloat&) dir).Mul(2.0f); + ((Vector3&) positionRef).Add(&dir); + + for (MxS32 i = 0; i < m_boundary->GetNumEdges(); i++) { + Mx4DPointFloat* normal = m_boundary->GetEdgeNormal(i); + + if (positionRef.Dot(normal, &positionRef) + (*normal)[3] < -0.001) { + b = TRUE; + break; + } + } + + if (!b) { + m_roi->FUN_100a58f0(matrix2); + m_roi->VTable0x14(); + FUN_1002ad8a(); + SoundManager()->GetCacheSoundManager()->FUN_1003dae0("crash5", m_roi->GetName(), FALSE); + m_scheduledTime = Timer()->GetTime() + m_disAnim->GetDuration(); + m_prevWorldSpeed = m_worldSpeed; + VTable0xc4(); + SetWorldSpeed(0); + m_whichAnim = 1; + m_state = 0x101; + } + } + + if (b) { + LegoROI* roi = m_roi; + SoundManager()->GetCacheSoundManager()->FUN_1003dae0("crash5", m_roi->GetName(), FALSE); + VTable0xc4(); + m_state = 0x102; + Mx3DPointFloat dir = p_actor->GetWorldDirection(); + MxMatrix matrix3 = MxMatrix(roi->GetLocal2World()); + Vector3 positionRef(matrix3[3]); + ((Vector3&) positionRef).Add(&g_unk0x10104c18); + roi->FUN_100a58f0(matrix3); + +#ifdef COMPAT_MODE + float dotX, dotZ; + { + Mx3DPointFloat tmp(1.0f, 0, 0); + dotX = dir.Dot(&dir, &tmp); + Mx3DPointFloat tmp2(0, 0, 1.0f); + dotZ = dir.Dot(&dir, &tmp2); + } +#else + float dotX = dir.Dot(&dir, &Mx3DPointFloat(1.0f, 0, 0)); + float dotZ = dir.Dot(&dir, &Mx3DPointFloat(0, 0, 1.0f)); +#endif + + if (abs(dotZ) < abs(dotX)) { + m_axis = dotX > 0.0 ? e_posz : e_negz; + } + else { + m_axis = dotZ > 0.0 ? e_posx : e_negx; + } + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1002b290 +MxResult LegoExtraActor::WaitForAnimation() +{ + LegoPathBoundary* oldBoundary = m_boundary; + MxResult result = LegoPathActor::WaitForAnimation(); + + if (m_boundary != oldBoundary) { + MxU32 b = FALSE; + LegoAnimPresenterSet& set = m_boundary->GetPresenters(); + + for (LegoAnimPresenterSet::iterator it = set.begin(); it != set.end(); it++) { + MxU32 roiMapSize; + if ((*it)->GetROIMap(roiMapSize)) { + b = TRUE; + break; + } + } + + if (b) { + m_unk0x0e = 1; + m_prevWorldSpeed = GetWorldSpeed(); + SetWorldSpeed(0); + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1002b370 +void LegoExtraActor::Restart() +{ + if (m_unk0x0e != 0) { + MxU32 b = FALSE; + LegoAnimPresenterSet& set = m_boundary->GetPresenters(); + + for (LegoAnimPresenterSet::iterator it = set.begin(); it != set.end(); it++) { + MxU32 roiMapSize; + if ((*it)->GetROIMap(roiMapSize)) { + b = TRUE; + break; + } + } + + if (!b) { + SetWorldSpeed(m_prevWorldSpeed); + m_unk0x0e = 0; + } + } +} + +// FUNCTION: LEGO1 0x1002b440 +void LegoExtraActor::VTable0x70(float p_time) +{ + LegoAnimActorStruct* laas = NULL; + + switch (m_whichAnim) { + case 0: + LegoAnimActor::VTable0x70(p_time); + break; + case 1: + if (m_scheduledTime < p_time) { + m_whichAnim = 2; + m_state = 0x101; + m_scheduledTime = m_assAnim->GetDuration() + p_time; + break; + } + else { + laas = m_disAnim; + break; + } + case 2: + if (m_scheduledTime < p_time) { + m_whichAnim = 0; + m_state = 0; + SetWorldSpeed(m_prevWorldSpeed); + m_roi->FUN_100a58f0(m_unk0x18); + m_lastTime = p_time; + break; + } + else { + laas = m_assAnim; + break; + } + } + + if (laas) { + float duration2, duration; + duration = laas->GetDuration(); + duration2 = p_time - (m_scheduledTime - duration); + + if (duration2 < 0) { + duration2 = 0; + } + else if (duration2 > duration) { + duration2 = duration; + } + + MxMatrix matrix(m_roi->GetLocal2World()); + LegoTreeNode* root = laas->m_AnimTreePtr->GetRoot(); + MxS32 count = root->GetNumChildren(); + + for (MxS32 i = 0; i < count; i++) { + LegoROI::FUN_100a8e80(root->GetChild(i), matrix, duration2, laas->m_roiMap); + } + } +} + +// FUNCTION: LEGO1 0x1002b5d0 +void LegoExtraActor::VTable0x74(Matrix4& p_transform) +{ + if (m_whichAnim == 0) { + LegoAnimActor::VTable0x74(p_transform); + } +} + +// FUNCTION: LEGO1 0x1002b5f0 +void LegoExtraActor::SetWorldSpeed(MxFloat p_worldSpeed) +{ + if (m_curAnim == 0 && p_worldSpeed > 0) { + VTable0xc4(); + } + LegoAnimActor::SetWorldSpeed(p_worldSpeed); +} + +// FUNCTION: LEGO1 0x1002b630 +void LegoExtraActor::VTable0xc4() +{ + if (m_curAnim != 0) { + return; + } + + if (m_worldSpeed > -0.001 || m_worldSpeed < 0.001) { + MxU16 name = *((MxU16*) m_roi->GetName()); + MxBool b = name == TWOCC('m', 'a') || name == TWOCC('p', 'a'); + + if (b) { + float duration = m_animMaps[m_curAnim]->GetDuration(); + MxMatrix matrix(m_unk0xec); + LegoAnimActor::FUN_1001c360(duration, matrix); + } + } +} + +// FUNCTION: LEGO1 0x1002b6f0 +MxS32 LegoExtraActor::VTable0x68(Vector3& p_point1, Vector3& p_point2, Vector3& p_point3) +{ + return LegoPathActor::VTable0x68(p_point1, p_point2, p_point3); +} + +// STUB: LEGO1 0x1002b980 +MxU32 LegoExtraActor::VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 +) +{ + return 0; +} diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp new file mode 100644 index 00000000..a893ba53 --- /dev/null +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -0,0 +1,496 @@ +#include "legopathactor.h" + +#include "geom/legounkown100db7f4.h" +#include "legocachesoundmanager.h" +#include "legocameracontroller.h" +#include "legonavcontroller.h" +#include "legopathboundary.h" +#include "legosoundmanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxtimer.h" +#include "mxvariabletable.h" + +#include + +DECOMP_SIZE_ASSERT(LegoPathActor, 0x154) + +#ifndef M_PI +#define M_PI 3.1416 +#endif +#ifdef DTOR +#undef DTOR +#endif +#define DTOR(angle) ((angle) * M_PI / 180.) + +// GLOBAL: LEGO1 0x100f3304 +// STRING: LEGO1 0x100f32f4 +const char* g_strHIT_WALL_SOUND = "HIT_WALL_SOUND"; + +// GLOBAL: LEGO1 0x100f3308 +MxLong g_unk0x100f3308 = 0; + +// FUNCTION: LEGO1 0x1002d700 +LegoPathActor::LegoPathActor() +{ + m_boundary = NULL; + m_actorTime = 0; + m_lastTime = 0; + m_unk0x7c = 0; + m_userNavFlag = FALSE; + m_state = 0; + m_unk0x134 = NULL; + m_controller = NULL; + m_unk0xe8 = 0; + m_unk0x148 = 0; + m_unk0x14c = 0; + m_unk0x140 = 0.0099999998f; + m_unk0x144 = 0.80000001f; + m_unk0x150 = 2.0f; +} + +// STUB: LEGO1 0x1002d820 +LegoPathActor::~LegoPathActor() +{ + if (m_unk0x134) { + delete m_unk0x134; + } +} + +// FUNCTION: LEGO1 0x1002d8d0 +MxResult LegoPathActor::VTable0x80(Vector3& p_point1, Vector3& p_point2, Vector3& p_point3, Vector3& p_point4) +{ + Mx3DPointFloat p1, p2, p3; + + p1 = p_point3; + ((Vector3&) p1).Sub(&p_point1); + m_BADuration = p1.LenSquared(); + + if (m_BADuration > 0.0f) { + m_BADuration = sqrtf(m_BADuration); + p2 = p_point2; + p3 = p_point4; + m_unk0x8c.FUN_1009a140(p_point1, p2, p_point3, p3); + m_BADuration /= 0.001; + return SUCCESS; + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x1002d9c0 +// FUNCTION: BETA10 0x100ae9da +MxResult LegoPathActor::VTable0x88( + LegoPathBoundary* p_boundary, + float p_time, + LegoEdge& p_srcEdge, + float p_srcScale, + LegoUnknown100db7f4& p_destEdge, + float p_destScale +) +{ + Vector3* v1 = p_srcEdge.GetOpposingPoint(p_boundary); + Vector3* v2 = p_srcEdge.GetPoint(p_boundary); + Vector3* v3 = p_destEdge.GetOpposingPoint(p_boundary); + Vector3* v4 = p_destEdge.GetPoint(p_boundary); + + Mx3DPointFloat p1, p2, p3, p4, p5; + + p1 = *v2; + ((Vector3&) p1).Sub(v1); + ((Vector3&) p1).Mul(p_srcScale); + ((Vector3&) p1).Add(v1); + + p2 = *v4; + ((Vector3&) p2).Sub(v3); + ((Vector3&) p2).Mul(p_destScale); + ((Vector3&) p2).Add(v3); + + m_boundary = p_boundary; + m_destEdge = &p_destEdge; + m_unk0xe4 = p_destScale; + m_unk0x7c = 0; + m_lastTime = p_time; + m_actorTime = p_time; + p_destEdge.FUN_1002ddc0(*p_boundary, p3); + + p4 = p2; + ((Vector3&) p4).Sub(&p1); + p4.Unitize(); + + MxMatrix matrix; + Vector3 pos(matrix[3]); + Vector3 dir(matrix[2]); + Vector3 up(matrix[1]); + Vector3 right(matrix[0]); + + matrix.SetIdentity(); + pos = p1; + dir = p4; + up = *m_boundary->GetUnknown0x14(); + + if (!m_cameraFlag || !m_userNavFlag) { + ((Vector3&) dir).Mul(-1.0f); + } + + right.EqualsCross(&up, &dir); + m_roi->FUN_100a46b0(matrix); + + if (!m_cameraFlag || !m_userNavFlag) { + p5.EqualsCross(p_boundary->GetUnknown0x14(), &p3); + p5.Unitize(); + + if (VTable0x80(p1, p4, p2, p5) == SUCCESS) { + m_boundary->AddActor(this); + } + else { + return FAILURE; + } + } + else { + m_boundary->AddActor(this); + FUN_10010c30(); + } + + m_unk0xec = m_roi->GetLocal2World(); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1002de10 +MxResult LegoPathActor::VTable0x84( + LegoPathBoundary* p_boundary, + float p_time, + Vector3& p_p1, + Vector3& p_p4, + LegoUnknown100db7f4& p_destEdge, + float p_destScale +) +{ + Vector3* v3 = p_destEdge.GetOpposingPoint(p_boundary); + Vector3* v4 = p_destEdge.GetPoint(p_boundary); + + Mx3DPointFloat p2, p3, p5; + + p2 = *v4; + ((Vector3&) p2).Sub(v3); + ((Vector3&) p2).Mul(p_destScale); + ((Vector3&) p2).Add(v3); + + m_boundary = p_boundary; + m_destEdge = &p_destEdge; + m_unk0xe4 = p_destScale; + m_unk0x7c = 0; + m_lastTime = p_time; + m_actorTime = p_time; + p_destEdge.FUN_1002ddc0(*p_boundary, p3); + + MxMatrix matrix; + Vector3 pos(matrix[3]); + Vector3 dir(matrix[2]); + Vector3 up(matrix[1]); + Vector3 right(matrix[0]); + + matrix.SetIdentity(); + pos = p_p1; + dir = p_p4; + up = *m_boundary->GetUnknown0x14(); + + if (!m_cameraFlag || !m_userNavFlag) { + ((Vector3&) dir).Mul(-1.0f); + } + + right.EqualsCross(&up, &dir); + m_roi->FUN_100a46b0(matrix); + + if (!m_cameraFlag || !m_userNavFlag) { + p5.EqualsCross(p_boundary->GetUnknown0x14(), &p3); + p5.Unitize(); + + if (VTable0x80(p_p1, p_p4, p2, p5) == SUCCESS) { + m_boundary->AddActor(this); + } + else { + return FAILURE; + } + } + else { + m_boundary->AddActor(this); + FUN_10010c30(); + } + + m_unk0xec = m_roi->GetLocal2World(); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1002e100 +MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) +{ + if (m_userNavFlag && m_state == 0) { + m_lastTime = p_time; + + Mx3DPointFloat p1, p2, p3, p4, p5; + p5 = Vector3(m_roi->GetWorldDirection()); + p4 = Vector3(m_roi->GetWorldPosition()); + + LegoNavController* nav = NavController(); + m_worldSpeed = nav->GetLinearVel(); + + if (nav->CalculateNewPosDir(p4, p5, p2, p1, m_boundary->GetUnknown0x14())) { + Mx3DPointFloat p6; + p6 = p2; + + m_unk0xe9 = m_boundary->Intersect(m_roi->GetWorldBoundingSphere().Radius(), p4, p2, p3, m_destEdge); + if (m_unk0xe9 == -1) { + return -1; + } + + if (m_unk0xe9 != 0) { + p2 = p3; + } + + MxS32 result = VTable0x68(p4, p2, p3); + + if (result > 0) { + p2 = p4; + m_unk0xe9 = 0; + result = 0; + } + else { + m_boundary->FUN_100575b0(p4, p2, this); + } + + LegoPathBoundary* oldBoundary = m_boundary; + + if (m_unk0xe9 != 0) { + WaitForAnimation(); + + if (m_boundary == oldBoundary) { + MxLong time = Timer()->GetTime(); + + if (time - g_unk0x100f3308 > 1000) { + g_unk0x100f3308 = time; + const char* var = VariableTable()->GetVariable(g_strHIT_WALL_SOUND); + + if (var && var[0] != 0) { + SoundManager()->GetCacheSoundManager()->FUN_1003dae0(var, NULL, FALSE); + } + } + + m_worldSpeed *= m_unk0x144; + nav->SetLinearVel(m_worldSpeed); + Mx3DPointFloat p7(p2); + ((Vector3&) p7).Sub(&p6); + + if (p7.Unitize() == 0) { + float f = sqrt(p1.LenSquared()) * m_unk0x140; + ((Vector3&) p7).Mul(f); + ((Vector3&) p1).Add(&p7); + } + } + } + + p_transform.SetIdentity(); + + Vector3 right(p_transform[0]); + Vector3 up(p_transform[1]); + Vector3 dir(p_transform[2]); + Vector3 pos(p_transform[3]); + + dir = p1; + up = *m_boundary->GetUnknown0x14(); + right.EqualsCross(&up, &dir); + right.Unitize(); + dir.EqualsCross(&right, &up); + pos = p2; + return result; + } + } + else if (p_time >= 0 && m_worldSpeed > 0) { + float f = (m_BADuration - m_unk0x7c) / m_worldSpeed + m_lastTime; + + if (f < p_time) { + m_unk0x7c = m_BADuration; + m_unk0xe9 = 1; + } + else { + f = p_time; + m_unk0x7c += (f - m_lastTime) * m_worldSpeed; + m_unk0xe9 = 0; + } + + m_actorTime += (f - m_lastTime) * m_worldSpeed; + m_lastTime = f; + p_transform.SetIdentity(); + + if (m_userNavFlag) { + m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUnknown0x14(), 0); + } + else { + m_unk0x8c.FUN_1009a1e0(m_unk0x7c / m_BADuration, p_transform, *m_boundary->GetUnknown0x14(), 1); + } + + Vector3 pos1(p_transform[3]); + Vector3 pos2(m_unk0xec[3]); + Mx3DPointFloat p1; + + if (VTable0x68(pos2, pos1, p1) > 0) { + m_lastTime = p_time; + return 1; + } + else { + m_boundary->FUN_100575b0(pos2, pos1, this); + pos2 = pos1; + + if (m_unk0xe9 != 0) { + WaitForAnimation(); + } + + return 0; + } + } + + return -1; +} + +// FUNCTION: LEGO1 0x1002e740 +void LegoPathActor::VTable0x74(Matrix4& p_transform) +{ + if (m_userNavFlag) { + m_roi->WrappedSetLocalTransform(p_transform); + FUN_10010c30(); + } + else { + m_roi->WrappedSetLocalTransform(p_transform); + m_roi->VTable0x14(); + + if (m_cameraFlag) { + FUN_10010c30(); + } + } +} + +// FUNCTION: LEGO1 0x1002e790 +void LegoPathActor::VTable0x70(float p_time) +{ + MxMatrix transform; + MxU32 b = FALSE; + + while (m_lastTime < p_time) { + if (m_state != 0 && !VTable0x90(p_time, transform)) { + return; + } + + if (VTable0x8c(p_time, transform) != 0) { + break; + } + + m_unk0xec = transform; + b = TRUE; + + if (m_unk0xe9 != 0) { + break; + } + } + + if (m_userNavFlag && m_unk0x148) { + LegoNavController* nav = NavController(); + float vel = (nav->GetLinearVel() > 0) + ? -(nav->GetRotationalVel() / (nav->GetMaxLinearVel() * m_unk0x150) * nav->GetLinearVel()) + : 0; + + if ((MxS32) vel != m_unk0x14c) { + m_unk0x14c = vel; + LegoWorld* world = CurrentWorld(); + + if (world) { + world->GetCamera()->FUN_10012290(DTOR(m_unk0x14c)); + } + } + } + + if (b) { + VTable0x74(transform); + } +} + +// STUB: LEGO1 0x1002e8b0 +void LegoPathActor::VTable0x98() +{ + // TODO +} + +// FUNCTION: LEGO1 0x1002e8d0 +// FUNCTION: BETA10 0x100b1010 +MxU32 LegoPathActor::VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 +) +{ + LegoAnimPresenterSet& laps = p_boundary->GetPresenters(); + + for (LegoAnimPresenterSet::iterator itap = laps.begin(); itap != laps.end(); itap++) { + if ((*itap)->VTable0x94(p_v1, p_v2, p_f1, p_f2, p_v3)) { + return 1; + } + } + + LegoPathActorSet& plpas = p_boundary->GetActors(); + LegoPathActorSet lpas(plpas); + + for (LegoPathActorSet::iterator itpa = lpas.begin(); itpa != lpas.end(); itpa++) { + if (plpas.find(*itpa) != plpas.end()) { + LegoPathActor* actor = *itpa; + + if (this != actor && !(actor->GetState() & 0x100)) { + LegoROI* roi = actor->GetROI(); + + if (roi != NULL && (roi->GetVisibility() || actor->GetCameraFlag())) { + if (roi->FUN_100a9410(p_v1, p_v2, p_f1, p_f2, p_v3, m_unk0xe8 != 0 && actor->m_unk0xe8 != 0)) { + VTable0x94(actor, TRUE); + actor->VTable0x94(this, FALSE); + return 2; + } + } + } + } + } + + return 0; +} + +// STUB: LEGO1 0x1002ebe0 +MxS32 LegoPathActor::VTable0x68(Vector3&, Vector3&, Vector3&) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1002f020 +void LegoPathActor::ParseAction(char* p_extra) +{ + LegoActor::ParseAction(p_extra); +} + +// STUB: LEGO1 0x1002f1b0 +MxResult LegoPathActor::WaitForAnimation() +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x1002f650 +void LegoPathActor::VTable0xa4(MxU8&, MxS32&) +{ + // TODO +} + +// STUB: LEGO1 0x1002f700 +void LegoPathActor::VTable0xa8() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp new file mode 100644 index 00000000..0ed91f6f --- /dev/null +++ b/LEGO1/lego/legoomni/src/paths/legopathboundary.cpp @@ -0,0 +1,73 @@ +#include "legopathboundary.h" + +#include "decomp.h" +#include "legopathactor.h" + +DECOMP_SIZE_ASSERT(LegoPathBoundary, 0x74) + +// FUNCTION: LEGO1 0x10056a70 +// FUNCTION: BETA10 0x100b1360 +LegoPathBoundary::LegoPathBoundary() +{ +} + +// FUNCTION: LEGO1 0x10057260 +// FUNCTION: BETA10 0x100b140d +LegoPathBoundary::~LegoPathBoundary() +{ + for (LegoPathActorSet::iterator it = m_actors.begin(); !(it == m_actors.end()); it++) { + (*it)->SetBoundary(NULL); + } + + m_actors.erase(m_actors.begin(), m_actors.end()); +} + +// FUNCTION: LEGO1 0x100573f0 +// FUNCTION: BETA10 0x100b1536 +MxResult LegoPathBoundary::AddActor(LegoPathActor* p_actor) +{ + m_actors.insert(p_actor); + p_actor->SetBoundary(this); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100574a0 +// FUNCTION: BETA10 0x100b156f +MxResult LegoPathBoundary::RemoveActor(LegoPathActor* p_actor) +{ + m_actors.erase(p_actor); + return SUCCESS; +} + +// STUB: LEGO1 0x100575b0 +void LegoPathBoundary::FUN_100575b0(Vector3& p_point1, Vector3& p_point2, LegoPathActor* p_actor) +{ +} + +// STUB: LEGO1 0x10057950 +MxU32 LegoPathBoundary::Intersect( + float p_scale, + Vector3& p_point1, + Vector3& p_point2, + Vector3& p_point3, + LegoEdge*& p_edge +) +{ + return 0; +} + +// STUB: LEGO1 0x10057fe0 +// FUNCTION: BETA10 0x100b2220 +MxU32 LegoPathBoundary::FUN_10057fe0(LegoAnimPresenter* p_presenter) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x100586e0 +// FUNCTION: BETA10 0x100b22d1 +MxU32 LegoPathBoundary::FUN_100586e0(LegoAnimPresenter* p_presenter) +{ + // TODO + return 0; +} diff --git a/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp new file mode 100644 index 00000000..a5f1797d --- /dev/null +++ b/LEGO1/lego/legoomni/src/paths/legopathcontroller.cpp @@ -0,0 +1,729 @@ +#include "legopathcontroller.h" + +#include "legopathstruct.h" +#include "misc/legostorage.h" +#include "mxmisc.h" +#include "mxticklemanager.h" +#include "mxtimer.h" + +DECOMP_SIZE_ASSERT(LegoPathController, 0x40) +DECOMP_SIZE_ASSERT(LegoPathCtrlEdge, 0x40) +DECOMP_SIZE_ASSERT(LegoPathController::CtrlBoundary, 0x08) +DECOMP_SIZE_ASSERT(LegoPathController::CtrlEdge, 0x08) + +// GLOBAL: LEGO1 0x100d7cc8 +MxU32 g_unk0x100d7cc8[] = {2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 0}; + +// GLOBAL: LEGO1 0x100d7d08 +MxU32 g_unk0x100d7d08[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +// GLOBAL: LEGO1 0x100f42e8 +LegoPathController::CtrlBoundary* g_ctrlBoundariesA = NULL; + +// GLOBAL: LEGO1 0x100f42ec +LegoPathController::CtrlEdge* g_ctrlEdgesA = NULL; + +// GLOBAL: LEGO1 0x100f42f0 +const char* g_unk0x100f42f0[] = { + "edg03_21", + "edg03_23", + "edg03_30", + "edg03_31", + "edg03_39", + "edg03_40", + "edg03_91", + "edg03_92", + "edg03_99", + "edg03_100", + "edg03_112", + "edg03_113", + "edg10_61", + "edg10_62", + "edg10_55", + "edg10_58" +}; + +// GLOBAL: LEGO1 0x100f4330 +const char* g_unk0x100f4330[] = { + "edg03_06", + "edg03_21", + "edg03_30", + "edg03_148", + "edg03_39", + "edg03_91", + "edg03_99", + "edg03_112", + "edg03_800", + "edg03_135" +}; + +// GLOBAL: LEGO1 0x100f4358 +LegoPathController::CtrlBoundary* g_ctrlBoundariesB = NULL; + +// GLOBAL: LEGO1 0x100f435c +LegoPathController::CtrlEdge* g_ctrlEdgesB = NULL; + +// FUNCTION: LEGO1 0x10044f40 +// FUNCTION: BETA10 0x100b6860 +LegoPathController::LegoPathController() +{ + m_boundaries = NULL; + m_edges = NULL; + m_unk0x10 = NULL; + m_structs = NULL; + m_numL = 0; + m_numE = 0; + m_numN = 0; + m_numT = 0; +} + +// FUNCTION: LEGO1 0x10045880 +// FUNCTION: BETA10 0x100b6959 +MxResult LegoPathController::Create(MxU8* p_data, const Vector3& p_location, const MxAtomId& p_trigger) +{ + MxResult result = FAILURE; + LegoMemory storage(p_data); + + if ((result = Read(&storage)) == SUCCESS) { + MxS32 i; + + for (i = 0; i < m_numT; i++) { + m_structs[i].SetAtomId(p_trigger); + } + + for (i = 0; i < m_numN; i++) { + // TODO: Fix call + ((Vector3&) m_unk0x10[i]).Add(&p_location); + } + + for (i = 0; i < m_numL; i++) { + LegoPathBoundary& boundary = m_boundaries[i]; + MxS32 j; + + for (j = 0; j < sizeOfArray(g_unk0x100f42f0); j++) { + if (!strcmpi(g_unk0x100f42f0[j], boundary.GetName())) { + g_ctrlBoundariesA[j].m_controller = this; + g_ctrlBoundariesA[j].m_boundary = &boundary; + + MxU32 edge = g_unk0x100d7cc8[j]; + g_ctrlEdgesA[j].m_controller = this; + g_ctrlEdgesA[j].m_edge = boundary.GetEdges()[edge]; + } + } + + for (j = 0; j < sizeOfArray(g_unk0x100f4330); j++) { + if (!strcmpi(g_unk0x100f4330[j], boundary.GetName())) { + g_ctrlBoundariesB[j].m_controller = this; + g_ctrlBoundariesB[j].m_boundary = &boundary; + g_ctrlEdgesB[j].m_controller = this; + g_ctrlEdgesB[j].m_edge = boundary.GetEdges()[g_unk0x100d7d08[j]]; + } + } + } + + TickleManager()->RegisterClient(this, 10); + } + + if (result != SUCCESS) { + Destroy(); + } + + return result; +} + +// FUNCTION: LEGO1 0x10045b20 +// FUNCTION: BETA10 0x100b6b8a +void LegoPathController::Destroy() +{ + TickleManager()->UnregisterClient(this); + + if (m_boundaries != NULL) { + delete[] m_boundaries; + } + m_boundaries = NULL; + m_numL = 0; + + if (m_unk0x10 != NULL) { + delete[] m_unk0x10; + } + m_unk0x10 = NULL; + m_numN = 0; + + if (m_structs != NULL) { + delete[] m_structs; + } + m_structs = NULL; + m_numT = 0; + + if (m_edges != NULL) { + delete[] m_edges; + } + m_edges = NULL; + m_numE = 0; + + MxS32 j; + for (j = 0; j < sizeOfArray(g_unk0x100f42f0); j++) { + if (g_ctrlBoundariesA[j].m_controller == this) { + g_ctrlBoundariesA[j].m_controller = NULL; + g_ctrlBoundariesA[j].m_boundary = NULL; + } + + if (g_ctrlEdgesA[j].m_controller == this) { + g_ctrlEdgesA[j].m_controller = NULL; + g_ctrlEdgesA[j].m_edge = NULL; + } + } + + for (j = 0; j < sizeOfArray(g_unk0x100f4330); j++) { + if (g_ctrlBoundariesB[j].m_controller == this) { + g_ctrlBoundariesB[j].m_controller = NULL; + g_ctrlBoundariesB[j].m_boundary = NULL; + } + + if (g_ctrlEdgesB[j].m_controller == this) { + g_ctrlEdgesB[j].m_controller = NULL; + g_ctrlEdgesB[j].m_edge = NULL; + } + } +} + +// FUNCTION: LEGO1 0x10045c10 +// FUNCTION: BETA10 0x100b6d60 +MxResult LegoPathController::Tickle() +{ + FUN_10046970(); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10045c20 +// FUNCTION: BETA10 0x100b6d80 +MxResult LegoPathController::FUN_10045c20( + LegoPathActor* p_actor, + const char* p_name, + MxS32 p_src, + float p_srcScale, + MxS32 p_dest, + float p_destScale +) +{ + if (p_actor->GetController() != NULL) { + p_actor->GetController()->RemoveActor(p_actor); + p_actor->SetController(NULL); + } + + LegoPathBoundary* pBoundary = GetPathBoundary(p_name); + LegoEdge* pSrcE = pBoundary->GetEdges()[p_src]; + LegoEdge* pDestE = pBoundary->GetEdges()[p_dest]; + float time = Timer()->GetTime(); + + if (p_actor->VTable0x88(pBoundary, time, *pSrcE, p_srcScale, (LegoUnknown100db7f4&) *pDestE, p_destScale) != + SUCCESS) { + return FAILURE; + } + + p_actor->SetController(this); + m_actors.insert(p_actor); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10046050 +// FUNCTION: BETA10 0x100b6f35 +MxResult LegoPathController::FUN_10046050( + LegoPathActor* p_actor, + LegoAnimPresenter* p_presenter, + Vector3& p_position, + Vector3& p_direction +) +{ + LegoPathBoundary* boundary = NULL; + float time = Timer()->GetTime(); + + if (p_actor->GetController() != NULL) { + p_actor->GetController()->RemoveActor(p_actor); + p_actor->SetController(NULL); + } + + for (MxS32 i = 0; i < m_numL; i++) { + LegoPathBoundary& b = m_boundaries[i]; + LegoAnimPresenterSet& presenters = b.GetPresenters(); + LegoAnimPresenter* presenter = p_presenter; + + if (presenters.find(presenter) != presenters.end()) { + MxS32 j; + + for (j = 0; j < b.GetNumEdges(); j++) { + Mx4DPointFloat normal(*b.GetEdgeNormal(j)); + + if (p_position.Dot(&p_position, &normal) + normal[3] < 0.0f) { + break; + } + } + + if (b.GetNumEdges() == j) { + if (boundary != NULL) { + return FAILURE; + } + + boundary = &b; + } + } + } + + if (boundary == NULL) { + return FAILURE; + } + + for (MxS32 j = 0; j < boundary->GetNumEdges(); j++) { + LegoUnknown100db7f4* edge = (LegoUnknown100db7f4*) boundary->GetEdges()[j]; + + if (edge->GetMask0x03()) { + Mx3DPointFloat vec; + + if (((LegoUnknown100db7f4*) edge->GetClockwiseEdge(boundary))->FUN_1002ddc0(*boundary, vec) == SUCCESS && + vec.Dot(&vec, &p_direction) < 0.0f) { + edge = + (LegoUnknown100db7f4*) edge->GetCounterclockwiseEdge(boundary)->GetCounterclockwiseEdge(boundary); + } + + if (!edge->GetMask0x03()) { + return FAILURE; + } + + if (p_actor->VTable0x84(boundary, time, p_position, p_direction, *edge, 0.5f) == SUCCESS) { + p_actor->SetController(this); + m_actors.insert(p_actor); + return SUCCESS; + } + } + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x100466a0 +// FUNCTION: BETA10 0x100b71fe +MxResult LegoPathController::AddActor(LegoPathActor* p_actor) +{ + if (p_actor->GetController() != NULL) { + p_actor->GetController()->RemoveActor(p_actor); + p_actor->SetController(NULL); + } + + m_actors.insert(p_actor); + p_actor->SetController(this); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10046770 +// FUNCTION: BETA10 0x100b7264 +MxResult LegoPathController::RemoveActor(LegoPathActor* p_actor) +{ + MxResult result = FAILURE; + + p_actor->VTable0xc4(); + m_actors.erase(p_actor); + + for (MxS32 i = 0; i < m_numL; i++) { + if (m_boundaries[i].RemoveActor(p_actor) == SUCCESS) { + result = SUCCESS; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100468f0 +// FUNCTION: BETA10 0x100b72f7 +void LegoPathController::FUN_100468f0(LegoAnimPresenter* p_presenter) +{ + for (MxS32 i = 0; i < m_numL; i++) { + if (!(m_boundaries[i].m_flags & LegoWEGEdge::c_bit3)) { + m_boundaries[i].FUN_10057fe0(p_presenter); + } + } +} + +// FUNCTION: LEGO1 0x10046930 +// FUNCTION: BETA10 0x100b737b +void LegoPathController::FUN_10046930(LegoAnimPresenter* p_presenter) +{ + for (MxS32 i = 0; i < m_numL; i++) { + m_boundaries[i].FUN_100586e0(p_presenter); + } +} + +// FUNCTION: LEGO1 0x10046970 +// FUNCTION: BETA10 0x100b73d8 +void LegoPathController::FUN_10046970() +{ + float time = Timer()->GetTime(); + + LegoPathActorSet lpas(m_actors); + + for (LegoPathActorSet::iterator itpa = lpas.begin(); itpa != lpas.end(); itpa++) { + LegoPathActor* actor = *itpa; + + if (m_actors.find(actor) != m_actors.end()) { + if (!((MxU8) actor->GetState() & LegoPathActor::c_bit3)) { + actor->VTable0x70(time); + } + } + } +} + +// FUNCTION: LEGO1 0x10046b30 +MxResult LegoPathController::FUN_10046b30(LegoPathBoundary*& p_boundaries, MxS32& p_numL) +{ + p_boundaries = m_boundaries; + p_numL = m_numL; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10046b50 +// FUNCTION: BETA10 0x100b7531 +LegoPathBoundary* LegoPathController::GetPathBoundary(const char* p_name) +{ + for (MxS32 i = 0; i < m_numL; i++) { + if (!strcmpi(m_boundaries[i].GetName(), p_name)) { + return &m_boundaries[i]; + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10046bb0 +// FUNCTION: BETA10 0x100b75bc +void LegoPathController::FUN_10046bb0(LegoWorld* p_world) +{ + for (MxS32 i = 0; i < m_numT; i++) { + m_structs[i].SetWorld(p_world); + } +} + +// FUNCTION: LEGO1 0x10046be0 +// FUNCTION: BETA10 0x100b7614 +void LegoPathController::Enable(MxBool p_enable) +{ + if (p_enable) { + TickleManager()->RegisterClient(this, 10); + } + else { + TickleManager()->UnregisterClient(this); + } +} + +// FUNCTION: LEGO1 0x10046c10 +// FUNCTION: BETA10 0x100b767a +MxResult LegoPathController::Init() +{ + if (g_ctrlBoundariesA != NULL || g_ctrlEdgesA != NULL || g_ctrlBoundariesB != NULL || g_ctrlEdgesB != NULL) { + return FAILURE; + } + + g_ctrlBoundariesA = new CtrlBoundary[sizeOfArray(g_unk0x100f42f0)]; + g_ctrlEdgesA = new CtrlEdge[sizeOfArray(g_unk0x100f42f0)]; + g_ctrlBoundariesB = new CtrlBoundary[sizeOfArray(g_unk0x100f4330)]; + g_ctrlEdgesB = new CtrlEdge[sizeOfArray(g_unk0x100f4330)]; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10046de0 +// FUNCTION: BETA10 0x100b779e +MxResult LegoPathController::Reset() +{ + if (g_ctrlBoundariesA == NULL || g_ctrlEdgesA == NULL) { + return FAILURE; + } + + delete[] g_ctrlBoundariesA; + delete[] g_ctrlEdgesA; + delete[] g_ctrlBoundariesB; + delete[] g_ctrlEdgesB; + g_ctrlBoundariesA = NULL; + g_ctrlEdgesA = NULL; + g_ctrlBoundariesB = NULL; + g_ctrlEdgesB = NULL; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10046e50 +// FUNCTION: BETA10 0x100b781f +MxResult LegoPathController::Read(LegoStorage* p_storage) +{ + if (p_storage->Read(&m_numT, sizeof(m_numT)) != SUCCESS) { + return FAILURE; + } + if (m_numT > 0) { + m_structs = new LegoPathStruct[m_numT]; + } + + if (p_storage->Read(&m_numN, sizeof(m_numN)) != SUCCESS) { + return FAILURE; + } + if (m_numN > 0) { + m_unk0x10 = new Mx3DPointFloat[m_numN]; + } + + if (p_storage->Read(&m_numE, sizeof(m_numE)) != SUCCESS) { + return FAILURE; + } + if (m_numE > 0) { + m_edges = new LegoPathCtrlEdge[m_numE]; + } + + if (p_storage->Read(&m_numL, sizeof(m_numL)) != SUCCESS) { + return FAILURE; + } + if (m_numL > 0) { + m_boundaries = new LegoPathBoundary[m_numL]; + } + + if (m_numT > 0 && ReadStructs(p_storage) != SUCCESS) { + return FAILURE; + } + + if (m_numN > 0) { + for (MxS32 i = 0; i < m_numN; i++) { + if (ReadVector(p_storage, m_unk0x10[i]) != SUCCESS) { + return FAILURE; + } + } + } + + if (m_numE > 0 && ReadEdges(p_storage) != SUCCESS) { + return FAILURE; + } + + if (m_numL > 0 && ReadBoundaries(p_storage) != SUCCESS) { + return FAILURE; + } + + for (MxS32 j = 0; j < m_numE; j++) { + m_pfsE.insert(&m_edges[j]); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10047b30 +// FUNCTION: BETA10 0x100b7cd6 +MxResult LegoPathController::ReadStructs(LegoStorage* p_storage) +{ + for (MxS32 i = 0; i < m_numT; i++) { + MxU8 length = 0; + + if (p_storage->Read(&length, sizeof(length)) != SUCCESS) { + return FAILURE; + } + + if (length > 0) { + m_structs[i].m_name = new char[length + 1]; + + if (p_storage->Read(m_structs[i].m_name, length) != SUCCESS) { + return FAILURE; + } + + m_structs[i].m_name[length] = '\0'; + } + + if (p_storage->Read(&m_structs[i].m_unk0x08, sizeof(m_structs[i].m_unk0x08)) != SUCCESS) { + return FAILURE; + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10047c10 +// FUNCTION: BETA10 0x100b7df3 +MxResult LegoPathController::ReadEdges(LegoStorage* p_storage) +{ + for (MxS32 i = 0; i < m_numE; i++) { + LegoPathCtrlEdge& edge = m_edges[i]; + MxU16 s; + + if (p_storage->Read(&edge.m_flags, sizeof(edge.m_flags)) != SUCCESS) { + return FAILURE; + } + + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + edge.m_pointA = &m_unk0x10[s]; + + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + edge.m_pointB = &m_unk0x10[s]; + + if (edge.m_flags & LegoUnknown100db7f4::c_bit3) { + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + edge.m_faceA = &m_boundaries[s]; + + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + edge.m_ccwA = &m_edges[s]; + + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + edge.m_cwA = &m_edges[s]; + } + + if (edge.m_flags & LegoUnknown100db7f4::c_bit4) { + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + edge.m_faceB = &m_boundaries[s]; + + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + edge.m_ccwB = &m_edges[s]; + + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + edge.m_cwB = &m_edges[s]; + } + + if (ReadVector(p_storage, edge.m_unk0x28) != SUCCESS) { + return FAILURE; + } + + if (p_storage->Read(&edge.m_unk0x3c, sizeof(edge.m_unk0x3c)) != SUCCESS) { + return FAILURE; + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10047e90 +// FUNCTION: BETA10 0x100b8293 +MxResult LegoPathController::ReadBoundaries(LegoStorage* p_storage) +{ + for (MxS32 i = 0; i < m_numL; i++) { + LegoPathBoundary& boundary = m_boundaries[i]; + MxU8 numE; + MxU16 s; + MxU8 j; + + if (p_storage->Read(&numE, sizeof(numE)) != SUCCESS) { + return FAILURE; + } + + boundary.m_edgeNormals = new Mx4DPointFloat[numE]; + + LegoEdge** edges = new LegoEdge*[numE]; + boundary.SetEdges(edges, numE); + + for (j = 0; j < numE; j++) { + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + + edges[j] = &m_edges[s]; + } + + if (p_storage->Read(&boundary.m_flags, sizeof(boundary.m_flags)) != SUCCESS) { + return FAILURE; + } + + if (p_storage->Read(&boundary.m_unk0x0d, sizeof(boundary.m_unk0x0d)) != SUCCESS) { + return FAILURE; + } + + MxU8 length; + if (p_storage->Read(&length, sizeof(length)) != SUCCESS) { + return FAILURE; + } + + if (length > 0) { + boundary.m_name = new char[length + 1]; + + if (p_storage->Read(boundary.m_name, length) != SUCCESS) { + return FAILURE; + } + + boundary.m_name[length] = '\0'; + } + + if (ReadVector(p_storage, boundary.m_unk0x14) != SUCCESS) { + return FAILURE; + } + + for (j = 0; j < numE; j++) { + if (ReadVector(p_storage, boundary.m_edgeNormals[j]) != SUCCESS) { + return FAILURE; + } + } + + if (ReadVector(p_storage, boundary.m_unk0x30) != SUCCESS) { + return FAILURE; + } + + if (p_storage->Read(&boundary.m_unk0x44, sizeof(boundary.m_unk0x44)) != SUCCESS) { + return FAILURE; + } + + if (p_storage->Read(&boundary.m_unk0x48, sizeof(boundary.m_unk0x48)) != SUCCESS) { + return FAILURE; + } + + if (boundary.m_unk0x48 > 0) { + boundary.m_unk0x50 = new Mx3DPointFloat; + boundary.m_unk0x4c = new LegoWEGEdge::Path[boundary.m_unk0x48]; + + for (j = 0; j < boundary.m_unk0x48; j++) { + if (p_storage->Read(&s, sizeof(s)) != SUCCESS) { + return FAILURE; + } + + boundary.m_unk0x4c[j].m_unk0x00 = &m_structs[s]; + + if (p_storage->Read(&boundary.m_unk0x4c[j].m_unk0x04, sizeof(boundary.m_unk0x4c[j].m_unk0x04)) != + SUCCESS) { + return FAILURE; + } + + if (p_storage->Read(&boundary.m_unk0x4c[j].m_unk0x08, sizeof(boundary.m_unk0x4c[j].m_unk0x08)) != + SUCCESS) { + return FAILURE; + } + } + + if (ReadVector(p_storage, *boundary.m_unk0x50) != SUCCESS) { + return FAILURE; + } + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100482b0 +// FUNCTION: BETA10 0x100b8864 +MxResult LegoPathController::ReadVector(LegoStorage* p_storage, Mx3DPointFloat& p_vec) +{ + if (p_storage->Read(p_vec.GetData(), sizeof(float) * 3) != SUCCESS) { + return FAILURE; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100482e0 +// FUNCTION: BETA10 0x100b88a1 +MxResult LegoPathController::ReadVector(LegoStorage* p_storage, Mx4DPointFloat& p_vec) +{ + if (p_storage->Read(p_vec.GetData(), sizeof(float) * 4) != SUCCESS) { + return FAILURE; + } + + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/paths/legopathpresenter.cpp b/LEGO1/lego/legoomni/src/paths/legopathpresenter.cpp new file mode 100644 index 00000000..f5cb137b --- /dev/null +++ b/LEGO1/lego/legoomni/src/paths/legopathpresenter.cpp @@ -0,0 +1,136 @@ +#include "legopathpresenter.h" + +#include "define.h" +#include "legopathcontroller.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxautolock.h" +#include "mxdssubscriber.h" +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(LegoPathPresenter, 0x54) + +// FUNCTION: LEGO1 0x100448d0 +LegoPathPresenter::LegoPathPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x10044ab0 +void LegoPathPresenter::Init() +{ +} + +// FUNCTION: LEGO1 0x10044ac0 +LegoPathPresenter::~LegoPathPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x10044b40 +MxResult LegoPathPresenter::AddToManager() +{ + MxResult status = FAILURE; + + if (VideoManager()) { + VideoManager()->RegisterPresenter(*this); + status = SUCCESS; + } + + return status; +} + +// FUNCTION: LEGO1 0x10044b70 +void LegoPathPresenter::Destroy(MxBool p_fromDestructor) +{ + if (VideoManager()) { + VideoManager()->UnregisterPresenter(*this); + } + + { + AUTOLOCK(m_criticalSection); + Init(); + } + + if (!p_fromDestructor) { + MxMediaPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x10044c10 +void LegoPathPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x10044c20 +void LegoPathPresenter::ReadyTickle() +{ + LegoWorld* world = CurrentWorld(); + + if (world) { + MxStreamChunk* chunk = m_subscriber->PopData(); + + if (chunk) { + LegoPathController* controller = new LegoPathController(); + + if (controller == NULL) { + EndAction(); + } + else { + ParseExtra(); + + controller->Create(chunk->GetData(), m_action->GetLocation(), m_trigger); + world->AddPath(controller); + + m_subscriber->FreeDataChunk(chunk); + ProgressTickleState(MxPresenter::e_starting); + } + } + } +} + +// FUNCTION: LEGO1 0x10044d00 +void LegoPathPresenter::StreamingTickle() +{ + MxStreamChunk* chunk = m_subscriber->PopData(); + + if (chunk) { + if (chunk->GetChunkFlags() & DS_CHUNK_END_OF_STREAM) { + ProgressTickleState(e_repeating); + } + + m_subscriber->FreeDataChunk(chunk); + } +} + +// FUNCTION: LEGO1 0x10044d40 +void LegoPathPresenter::RepeatingTickle() +{ + if (this->m_action->GetDuration() == -1) { + return; + } + + EndAction(); +} + +// FUNCTION: LEGO1 0x10044d60 +void LegoPathPresenter::ParseExtra() +{ + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[256], output[256]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + strupr(extraCopy); + + if (KeyValueStringParse(output, g_strTRIGGERS_SOURCE, extraCopy) != FALSE) { + m_trigger = MxAtomId(output, e_lowerCase2); + } + } +} diff --git a/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp b/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp new file mode 100644 index 00000000..2cbf51c4 --- /dev/null +++ b/LEGO1/lego/legoomni/src/paths/legopathstruct.cpp @@ -0,0 +1,11 @@ +#include "legopathstruct.h" + +DECOMP_SIZE_ASSERT(LegoPathStructBase, 0x0c) +DECOMP_SIZE_ASSERT(LegoPathStruct, 0x14) + +// STUB: LEGO1 0x1001b700 +// FUNCTION: BETA10 0x100c26c5 +void LegoPathStruct::VTable0x04(undefined4, undefined4, undefined4) +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/pizzeria/pizzamissionstate.cpp b/LEGO1/lego/legoomni/src/pizzeria/pizzamissionstate.cpp new file mode 100644 index 00000000..dac374c5 --- /dev/null +++ b/LEGO1/lego/legoomni/src/pizzeria/pizzamissionstate.cpp @@ -0,0 +1,22 @@ +#include "pizzamissionstate.h" + +DECOMP_SIZE_ASSERT(PizzaMissionStateEntry, 0x20) +DECOMP_SIZE_ASSERT(PizzaMissionState, 0xb0) + +// STUB: LEGO1 0x100393c0 +MxResult PizzaMissionState::Serialize(LegoFile* p_legoFile) +{ + // TODO + return LegoState::Serialize(p_legoFile); +} + +// FUNCTION: LEGO1 0x10039510 +PizzaMissionStateEntry* PizzaMissionState::GetState(MxU8 p_id) +{ + for (MxS16 i = 0; i < 5; i++) { + if (m_state[i].m_id == p_id) { + return m_state + i; + } + } + return NULL; +} diff --git a/LEGO1/lego/legoomni/src/pizzeria/pizzeriastate.cpp b/LEGO1/lego/legoomni/src/pizzeria/pizzeriastate.cpp new file mode 100644 index 00000000..41f9d029 --- /dev/null +++ b/LEGO1/lego/legoomni/src/pizzeria/pizzeriastate.cpp @@ -0,0 +1,16 @@ +#include "pizzeriastate.h" + +DECOMP_SIZE_ASSERT(PizzeriaState, 0x58) + +// STUB: LEGO1 0x10017af0 +PizzeriaState::PizzeriaState() +{ + // TODO +} + +// STUB: LEGO1 0x10017da0 +MxResult PizzeriaState::Serialize(LegoFile* p_legoFile) +{ + // TODO + return LegoState::Serialize(p_legoFile); +} diff --git a/LEGO1/lego/legoomni/src/police/policeentity.cpp b/LEGO1/lego/legoomni/src/police/policeentity.cpp new file mode 100644 index 00000000..936d3859 --- /dev/null +++ b/LEGO1/lego/legoomni/src/police/policeentity.cpp @@ -0,0 +1,39 @@ +#include "policeentity.h" + +#include "act1state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(PoliceEntity, 0x68) + +// FUNCTION: LEGO1 0x10015310 +MxLong PoliceEntity::VTable0x50(MxParam& p_param) +{ + if (FUN_1003ef60()) { + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + + if (state->GetUnknown18() != 10) { + state->SetUnknown18(0); + + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->SetDestLocation(LegoGameState::Area::e_police); + + AnimationManager()->FUN_10061010(FALSE); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + } + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/police/policestate.cpp b/LEGO1/lego/legoomni/src/police/policestate.cpp new file mode 100644 index 00000000..c0a6e716 --- /dev/null +++ b/LEGO1/lego/legoomni/src/police/policestate.cpp @@ -0,0 +1,70 @@ +#include "policestate.h" + +#include "islepathactor.h" +#include "misc.h" +#include "mxdsaction.h" +#include "mxmisc.h" +#include "police.h" +#include "police_actions.h" +#include "scripts.h" + +#include + +DECOMP_SIZE_ASSERT(PoliceState, 0x10) + +// FUNCTION: LEGO1 0x1005e7c0 +PoliceState::PoliceState() +{ + m_unk0x0c = 0; + m_policeScript = (rand() % 2 == 0) ? PoliceScript::c_nps002la_RunAnim : PoliceScript::c_nps001ni_RunAnim; +} + +// FUNCTION: LEGO1 0x1005e990 +MxResult PoliceState::Serialize(LegoFile* p_legoFile) +{ + LegoState::Serialize(p_legoFile); + + if (p_legoFile->IsReadMode()) { + p_legoFile->Read(&m_policeScript, sizeof(m_policeScript)); + } + else { + PoliceScript::Script policeScript = m_policeScript; + p_legoFile->Write(&policeScript, sizeof(m_policeScript)); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1005ea40 +void PoliceState::FUN_1005ea40() +{ + PoliceScript::Script policeScript; + + if (m_unk0x0c == 1) { + return; + } + + switch (CurrentActor()->GetActorId()) { + case 4: + policeScript = PoliceScript::c_nps002la_RunAnim; + m_policeScript = policeScript; + break; + case 5: + policeScript = PoliceScript::c_nps001ni_RunAnim; + m_policeScript = policeScript; + break; + default: + policeScript = m_policeScript; + m_policeScript = policeScript == PoliceScript::c_nps002la_RunAnim ? PoliceScript::c_nps001ni_RunAnim + : PoliceScript::c_nps002la_RunAnim; + } + + { + MxDSAction action; + action.SetObjectId(policeScript); + action.SetAtomId(*g_policeScript); + Start(&action); + } + + m_unk0x0c = 1; +} diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp new file mode 100644 index 00000000..b45ff7ea --- /dev/null +++ b/LEGO1/lego/legoomni/src/race/carrace.cpp @@ -0,0 +1,58 @@ +#include "carrace.h" + +DECOMP_SIZE_ASSERT(CarRace, 0x154) + +// FUNCTION: LEGO1 0x10016a90 +CarRace::CarRace() +{ + this->m_unk0x150 = 0; + this->m_unk0x130 = MxRect32(0x16c, 0x154, 0x1ec, 0x15e); +} + +// STUB: LEGO1 0x10016ce0 +MxResult CarRace::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10016dd0 +void CarRace::ReadyWorld() +{ + // TODO +} + +// STUB: LEGO1 0x10016f60 +undefined4 CarRace::VTable0x74(undefined4) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x100170e0 +undefined4 CarRace::VTable0x70(undefined4) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10017650 +undefined4 CarRace::VTable0x6c(undefined4) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x100177e0 +undefined4 CarRace::VTable0x78(undefined4) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10017900 +MxBool CarRace::VTable0x64() +{ + // TODO + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/race/jetskirace.cpp b/LEGO1/lego/legoomni/src/race/jetskirace.cpp new file mode 100644 index 00000000..a976724d --- /dev/null +++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp @@ -0,0 +1,38 @@ +#include "jetskirace.h" + +DECOMP_SIZE_ASSERT(JetskiRace, 0x144) + +// STUB: LEGO1 0x100162c0 +MxResult JetskiRace::Create(MxDSAction& p_dsAction) +{ + return SUCCESS; +} + +// STUB: LEGO1 0x100163b0 +void JetskiRace::ReadyWorld() +{ +} + +// STUB: LEGO1 0x10016520 +undefined4 JetskiRace::VTable0x74(undefined4) +{ + return 0; +} + +// STUB: LEGO1 0x100165a0 +undefined4 JetskiRace::VTable0x6c(undefined4) +{ + return 0; +} + +// STUB: LEGO1 0x100166a0 +undefined4 JetskiRace::VTable0x70(undefined4) +{ + return 0; +} + +// STUB: LEGO1 0x10016a10 +MxBool JetskiRace::VTable0x64() +{ + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/race/legorace.cpp b/LEGO1/lego/legoomni/src/race/legorace.cpp new file mode 100644 index 00000000..034d3af8 --- /dev/null +++ b/LEGO1/lego/legoomni/src/race/legorace.cpp @@ -0,0 +1,89 @@ +#include "legorace.h" + +#include "mxmisc.h" +#include "mxnotificationmanager.h" + +DECOMP_SIZE_ASSERT(LegoRace, 0x144) + +// FUNCTION: LEGO1 0x1000dab0 +undefined4 LegoRace::VTable0x78(undefined4) +{ + return 0; +} + +// STUB: LEGO1 0x1000dac0 +void LegoRace::VTable0x7c(undefined4, undefined4) +{ + // TODO +} + +// FUNCTION: LEGO1 0x1000dae0 +MxBool LegoRace::VTable0x5c() +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x10015aa0 +LegoRace::LegoRace() +{ + this->m_unk0xf8 = 0; + this->m_unk0xfc = 0; + this->m_unk0x100 = 0; + this->m_unk0x104 = 0; + this->m_unk0x108 = 0; + this->m_unk0x10c = 0; + this->m_unk0x140 = 0; + this->m_unk0x110 = 0; + this->m_unk0x114 = 0; + this->m_unk0x118 = 0; + this->m_unk0x128 = 0; + this->m_unk0x12c = 0; + this->m_unk0x120 = 0; + this->m_unk0x124 = 0; + this->m_unk0x11c = 0; + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x10015b70 +undefined4 LegoRace::VTable0x70(undefined4) +{ + return 0; +} + +// FUNCTION: LEGO1 0x10015b80 +undefined4 LegoRace::VTable0x74(undefined4) +{ + return 0; +} + +// FUNCTION: LEGO1 0x10015b90 +MxBool LegoRace::VTable0x64() +{ + return FALSE; +} + +// STUB: LEGO1 0x10015ce0 +MxResult LegoRace::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10015d40 +LegoRace::~LegoRace() +{ + // TODO +} + +// STUB: LEGO1 0x10015e00 +MxLong LegoRace::Notify(MxParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10015ed0 +void LegoRace::Enable(MxBool p_enable) +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/race/legoraceactor.cpp b/LEGO1/lego/legoomni/src/race/legoraceactor.cpp new file mode 100644 index 00000000..77f2a785 --- /dev/null +++ b/LEGO1/lego/legoomni/src/race/legoraceactor.cpp @@ -0,0 +1,49 @@ +#include "legoraceactor.h" + +DECOMP_SIZE_ASSERT(LegoRaceActor, 0x180) + +// STUB: LEGO1 0x10014190 +void LegoRaceActor::VTable0x74(Matrix4& p_transform) +{ + // TODO +} + +// FUNCTION: LEGO1 0x100145d0 +LegoRaceActor::LegoRaceActor() +{ + m_unk0x70 = 0; + m_unk0x08 = 0; +} + +// STUB: LEGO1 0x10014cb0 +void LegoRaceActor::SetWorldSpeed(MxFloat p_worldSpeed) +{ + // TODO +} + +// STUB: LEGO1 0x10014cc0 +MxS32 LegoRaceActor::VTable0x68(Vector3&, Vector3&, Vector3&) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10014cd0 +void LegoRaceActor::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x10014ce0 +MxU32 LegoRaceActor::VTable0x90(float, Matrix4&) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10014cf0 +MxResult LegoRaceActor::VTable0x94(LegoPathActor* p_actor, MxBool p_bool) +{ + // TODO + return 0; +} diff --git a/LEGO1/lego/legoomni/src/race/legoracecar.cpp b/LEGO1/lego/legoomni/src/race/legoracecar.cpp new file mode 100644 index 00000000..ccd28cd8 --- /dev/null +++ b/LEGO1/lego/legoomni/src/race/legoracecar.cpp @@ -0,0 +1,104 @@ +#include "legoracecar.h" + +#include "mxmisc.h" +#include "mxnotificationmanager.h" + +DECOMP_SIZE_ASSERT(LegoRaceCar, 0x200) + +// FUNCTION: LEGO1 0x10012950 +LegoRaceCar::LegoRaceCar() +{ + m_unk0x54 = 0; + m_unk0x70 = 0; + m_unk0x74 = 0; + m_unk0x5c.Clear(); + m_unk0x58 = 0; + m_unk0x78 = 0; + m_unk0x7c = 0; + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x10012ea0 +void LegoRaceCar::FUN_10012ea0(float p_worldSpeed) +{ + if (p_worldSpeed < 0) { + LegoCarRaceActor::m_unk0x0c = 2; + m_unk0x13c = 0; + SetWorldSpeed(0); + } + else { + m_unk0x13c = p_worldSpeed; + } +} + +// STUB: LEGO1 0x10012ff0 +void LegoRaceCar::FUN_10012ff0(float) +{ + // TODO +} + +// STUB: LEGO1 0x10013130 +MxBool LegoRaceCar::FUN_10013130(float) +{ + // TODO + return TRUE; +} + +// STUB: LEGO1 0x10014280 +MxLong LegoRaceCar::Notify(MxParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x100144d0 +void LegoRaceCar::ParseAction(char*) +{ + // TODO +} + +// STUB: LEGO1 0x100144e0 +void LegoRaceCar::SetWorldSpeed(MxFloat p_worldSpeed) +{ + // TODO +} + +// STUB: LEGO1 0x100144f0 +MxU32 LegoRaceCar::VTable0x6c( + LegoPathBoundary* p_boundary, + Vector3& p_v1, + Vector3& p_v2, + float p_f1, + float p_f2, + Vector3& p_v3 +) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10014530 +void LegoRaceCar::VTable0x70(float p_float) +{ + // TODO +} + +// STUB: LEGO1 0x10014540 +MxResult LegoRaceCar::VTable0x94(LegoPathActor* p_actor, MxBool p_bool) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10014550 +void LegoRaceCar::VTable0x98() +{ + // TODO +} + +// STUB: LEGO1 0x10014580 +MxResult LegoRaceCar::WaitForAnimation() +{ + // TODO + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/race/legoracemap.cpp b/LEGO1/lego/legoomni/src/race/legoracemap.cpp new file mode 100644 index 00000000..9af2bff4 --- /dev/null +++ b/LEGO1/lego/legoomni/src/race/legoracemap.cpp @@ -0,0 +1,21 @@ +#include "legoracemap.h" + +#include "legocontrolmanager.h" +#include "misc.h" + +DECOMP_SIZE_ASSERT(LegoRaceMap, 0x1b4) + +// FUNCTION: LEGO1 0x1005d0d0 +LegoRaceMap::LegoRaceMap() +{ + m_unk0x08 = FALSE; + m_unk0x0c = NULL; + m_unk0x10 = 0; + ControlManager()->Register(this); +} + +// FUNCTION: LEGO1 0x1005d4b0 +void LegoRaceMap::FUN_1005d4b0() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/race/raceskel.cpp b/LEGO1/lego/legoomni/src/race/raceskel.cpp new file mode 100644 index 00000000..5ef950e2 --- /dev/null +++ b/LEGO1/lego/legoomni/src/race/raceskel.cpp @@ -0,0 +1,9 @@ +#include "raceskel.h" + +DECOMP_SIZE_ASSERT(RaceSkel, 0x178) + +// STUB: LEGO1 0x100719b0 +RaceSkel::RaceSkel() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/race/racestandsentity.cpp b/LEGO1/lego/legoomni/src/race/racestandsentity.cpp new file mode 100644 index 00000000..91d9a07f --- /dev/null +++ b/LEGO1/lego/legoomni/src/race/racestandsentity.cpp @@ -0,0 +1,36 @@ +#include "racestandsentity.h" + +#include "act1state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(RaceStandsEntity, 0x68) + +// FUNCTION: LEGO1 0x10015450 +MxLong RaceStandsEntity::VTable0x50(MxParam& p_param) +{ + if (FUN_1003ef60()) { + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + state->SetUnknown18(0); + + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->SetDestLocation(LegoGameState::Area::e_racecarbuild); + + AnimationManager()->FUN_10061010(FALSE); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/race/racestate.cpp b/LEGO1/lego/legoomni/src/race/racestate.cpp new file mode 100644 index 00000000..897190f7 --- /dev/null +++ b/LEGO1/lego/legoomni/src/race/racestate.cpp @@ -0,0 +1,33 @@ +#include "racestate.h" + +DECOMP_SIZE_ASSERT(RaceStateEntry, 0x06) + +// TODO: Must be 0x2c but current structure is incorrect +// DECOMP_SIZE_ASSERT(RaceState, 0x2c) + +// STUB: LEGO1 0x10015f30 +RaceState::RaceState() +{ + // TODO +} + +// STUB: LEGO1 0x10016140 +MxResult RaceState::Serialize(LegoFile* p_legoFile) +{ + // TODO + return LegoState::Serialize(p_legoFile); +} + +// FUNCTION: LEGO1 0x10016280 +RaceStateEntry* RaceState::GetState(MxU8 p_id) +{ + for (MxS16 i = 0;; i++) { + if (i >= 5) { + return NULL; + } + + if (m_state[i].m_id == p_id) { + return m_state + i; + } + } +} diff --git a/LEGO1/lego/legoomni/src/towtrack/towtrackmissionstate.cpp b/LEGO1/lego/legoomni/src/towtrack/towtrackmissionstate.cpp new file mode 100644 index 00000000..bbf080ff --- /dev/null +++ b/LEGO1/lego/legoomni/src/towtrack/towtrackmissionstate.cpp @@ -0,0 +1,73 @@ +#include "towtrackmissionstate.h" + +DECOMP_SIZE_ASSERT(TowTrackMissionState, 0x28) + +// FUNCTION: LEGO1 0x1004dd30 +TowTrackMissionState::TowTrackMissionState() +{ + m_unk0x12 = 0; + m_unk0x14 = 0; + m_unk0x16 = 0; + m_unk0x08 = 0; + m_unk0x18 = 0; + m_unk0x0c = 0; + m_unk0x1a = 0; + m_unk0x10 = 0; + m_score1 = 0; + m_score2 = 0; + m_score3 = 0; + m_score4 = 0; + m_score5 = 0; +} + +// FUNCTION: LEGO1 0x1004dde0 +MxResult TowTrackMissionState::Serialize(LegoFile* p_legoFile) +{ + LegoState::Serialize(p_legoFile); + + if (p_legoFile->IsReadMode()) { + p_legoFile->Read(&m_unk0x12, sizeof(m_unk0x12)); + p_legoFile->Read(&m_unk0x14, sizeof(m_unk0x14)); + p_legoFile->Read(&m_unk0x16, sizeof(m_unk0x16)); + p_legoFile->Read(&m_unk0x18, sizeof(m_unk0x18)); + p_legoFile->Read(&m_unk0x1a, sizeof(m_unk0x1a)); + p_legoFile->Read(&m_score1, sizeof(m_score1)); + p_legoFile->Read(&m_score2, sizeof(m_score2)); + p_legoFile->Read(&m_score3, sizeof(m_score3)); + p_legoFile->Read(&m_score4, sizeof(m_score4)); + p_legoFile->Read(&m_score5, sizeof(m_score5)); + } + else if (p_legoFile->IsWriteMode()) { + MxU16 write = m_unk0x12; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + + write = m_unk0x14; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + + write = m_unk0x16; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + + write = m_unk0x18; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + + write = m_unk0x1a; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + + write = m_score1; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + + write = m_score2; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + + write = m_score3; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + + write = m_score4; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + + write = m_score5; + p_legoFile->Write(&write, sizeof(m_unk0x12)); + } + + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp new file mode 100644 index 00000000..747cbf4e --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -0,0 +1,1157 @@ +#include "legoanimpresenter.h" + +#include "3dmanager/lego3dmanager.h" +#include "anim/legoanim.h" +#include "define.h" +#include "legoanimationmanager.h" +#include "legoanimmmpresenter.h" +#include "legocameracontroller.h" +#include "legocharactermanager.h" +#include "legoendanimnotificationparam.h" +#include "legopathboundary.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "mxautolock.h" +#include "mxcompositepresenter.h" +#include "mxdsanim.h" +#include "mxdssubscriber.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstreamchunk.h" +#include "mxtimer.h" +#include "mxutilities.h" +#include "mxvariabletable.h" +#include "mxvideomanager.h" +#include "realtime/realtime.h" +#include "viewmanager/viewmanager.h" + +DECOMP_SIZE_ASSERT(LegoAnimPresenter, 0xbc) + +// FUNCTION: LEGO1 0x10068420 +LegoAnimPresenter::LegoAnimPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x10068670 +LegoAnimPresenter::~LegoAnimPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100686f0 +void LegoAnimPresenter::Init() +{ + m_anim = NULL; + m_roiMap = NULL; + m_roiMapSize = 0; + m_unk0x74 = NULL; + m_unk0x70 = NULL; + m_unk0x78 = NULL; + m_flags = 0; + m_unk0xa8.Clear(); + m_unk0xa4 = 0; + m_currentWorld = NULL; + m_unk0x95 = FALSE; + m_worldId = -1; + m_substMap = NULL; + m_worldAtom.Clear(); + m_unk0x9c = 0; + m_unk0x8c = NULL; + m_unk0x90 = NULL; + m_unk0x94 = 0; + m_unk0x96 = TRUE; + m_unk0xa0 = NULL; +} + +// FUNCTION: LEGO1 0x10068770 +// FUNCTION: BETA10 0x1004e833 +void LegoAnimPresenter::Destroy(MxBool p_fromDestructor) +{ + { + AUTOLOCK(m_criticalSection); + + if (m_anim != NULL) { + delete m_anim; + } + + if (m_roiMap != NULL) { + delete[] m_roiMap; + } + + if (m_unk0x70 != NULL) { + delete m_unk0x70; + } + + if (m_unk0x74 != NULL) { + FUN_1006aa60(); + delete m_unk0x74; + } + + if (m_unk0x78 != NULL) { + delete m_unk0x78; + } + + if (m_substMap != NULL) { + MxVariableTable* variableTable = VariableTable(); + + for (LegoAnimSubstMap::iterator it = m_substMap->begin(); it != m_substMap->end(); it++) { + variableTable->SetVariable((*it).first, ""); + + delete[] const_cast((*it).first); + delete[] const_cast((*it).second); + } + + delete m_substMap; + } + + if (m_unk0x90 != NULL) { + for (MxS32 i = 0; i < m_unk0x94; i++) { + if (m_unk0x90[i] != NULL) { + delete[] m_unk0x90[i]; + } + } + + delete[] m_unk0x90; + } + + if (m_unk0x8c != NULL) { + delete[] m_unk0x8c; + } + + if (m_unk0xa0 != NULL) { + delete m_unk0xa0; // TODO + } + + Init(); + } + + if (!p_fromDestructor) { + MxVideoPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x10068fb0 +MxResult LegoAnimPresenter::CreateAnim(MxStreamChunk* p_chunk) +{ + MxResult result = FAILURE; + LegoMemory storage(p_chunk->GetData()); + MxS32 magicSig; + LegoS32 parseScene = 0; + MxS32 val3; + + if (storage.Read(&magicSig, sizeof(magicSig)) != SUCCESS || magicSig != 0x11) { + goto done; + } + if (storage.Read(&m_unk0xa4, sizeof(m_unk0xa4)) != SUCCESS) { + goto done; + } + if (storage.Read(&m_unk0xa8[0], sizeof(m_unk0xa8[0])) != SUCCESS) { + goto done; + } + if (storage.Read(&m_unk0xa8[1], sizeof(m_unk0xa8[1])) != SUCCESS) { + goto done; + } + if (storage.Read(&m_unk0xa8[2], sizeof(m_unk0xa8[2])) != SUCCESS) { + goto done; + } + if (storage.Read(&parseScene, sizeof(parseScene)) != SUCCESS) { + goto done; + } + if (storage.Read(&val3, sizeof(val3)) != SUCCESS) { + goto done; + } + + m_anim = new LegoAnim(); + if (!m_anim) { + goto done; + } + + if (m_anim->Read(&storage, parseScene) != SUCCESS) { + goto done; + } + + result = SUCCESS; + +done: + if (result != SUCCESS) { + delete m_anim; + Init(); + } + + return result; +} + +// FUNCTION: LEGO1 0x10069150 +LegoChar* LegoAnimPresenter::FUN_10069150(const LegoChar* p_und1) +{ + LegoChar* str; + + if (LegoCharacterManager::Exists(p_und1 + 1)) { + str = new LegoChar[strlen(p_und1)]; + + if (str != NULL) { + strcpy(str, p_und1 + 1); + } + } + else { + LegoChar buffer[32]; + sprintf(buffer, "%d", m_action->GetUnknown24()); + str = new LegoChar[strlen(p_und1) + strlen(buffer) + strlen(GetActionObjectName()) + 1]; + + if (str != NULL) { + strcpy(str, p_und1); + strcat(str, buffer); + strcat(str, GetActionObjectName()); + } + } + + return str; +} + +// FUNCTION: LEGO1 0x100692b0 +void LegoAnimPresenter::FUN_100692b0() +{ + m_unk0x74 = new LegoROIList(); + + if (m_unk0x74) { + LegoU32 numActors = m_anim->GetNumActors(); + + for (LegoU32 i = 0; i < numActors; i++) { + LegoChar* str = FUN_100697c0(m_anim->GetActorName(i), NULL); + undefined4 unk0x04 = m_anim->GetActorUnknown0x04(i); + LegoROI* roi = NULL; + + if (unk0x04 == 2) { + LegoChar* src; + if (str[0] == '*') { + src = str + 1; + } + else { + src = str; + } + + roi = CharacterManager()->GetROI(src, TRUE); + + if (roi != NULL && str[0] == '*') { + roi->SetVisibility(FALSE); + } + } + else if (unk0x04 == 4) { + LegoChar* baseName = new LegoChar[strlen(str)]; + strcpy(baseName, str + 1); + strlwr(baseName); + + LegoChar* und = FUN_10069150(str); + roi = CharacterManager()->FUN_10085a80(und, baseName, TRUE); + + if (roi != NULL) { + roi->SetVisibility(FALSE); + } + + delete[] baseName; + delete[] und; + } + else if (unk0x04 == 3) { + LegoChar* lodName = new LegoChar[strlen(str)]; + strcpy(lodName, str + 1); + + for (LegoChar* i = &lodName[strlen(lodName) - 1]; i > lodName; i--) { + if ((*i < '0' || *i > '9') && *i != '_') { + break; + } + + *i = '\0'; + } + + strlwr(lodName); + + LegoChar* und = FUN_10069150(str); + roi = CharacterManager()->FUN_10085210(und, lodName, TRUE); + + if (roi != NULL) { + roi->SetVisibility(FALSE); + } + + delete[] lodName; + delete[] und; + } + + if (roi != NULL) { + m_unk0x74->Append(roi); + } + + delete[] str; + } + } +} + +// FUNCTION: LEGO1 0x100695c0 +void LegoAnimPresenter::FUN_100695c0() +{ + m_unk0x70 = new LegoROIList(); + + if (m_unk0x70) { + const CompoundObject& rois = VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->GetROIs(); + LegoU32 numActors = m_anim->GetNumActors(); + + for (LegoU32 i = 0; i < numActors; i++) { + if (FUN_100698b0(rois, m_anim->GetActorName(i)) == FALSE) { + undefined4 unk0x04 = m_anim->GetActorUnknown0x04(i); + + if (unk0x04 == 5 || unk0x04 == 6) { + LegoChar lodName[256]; + const LegoChar* actorName = m_anim->GetActorName(i); + + LegoU32 len = strlen(actorName); + strcpy(lodName, actorName); + + for (LegoChar* i = &lodName[len - 1]; isdigit(*i) || *i == '_'; i--) { + *i = '\0'; + } + + strlwr(lodName); + + CharacterManager()->FUN_10085210(actorName, lodName, FALSE); + FUN_100698b0(rois, actorName); + } + } + } + } +} + +// FUNCTION: LEGO1 0x100697c0 +LegoChar* LegoAnimPresenter::FUN_100697c0(const LegoChar* p_und1, const LegoChar* p_und2) +{ + const LegoChar* str = p_und1; + const char* var = VariableTable()->GetVariable(p_und1); + + if (*var) { + str = var; + } + + LegoU32 len = strlen(str) + (p_und2 ? strlen(p_und2) : 0) + 2; + LegoChar* result = new LegoChar[len]; + + if (result != NULL) { + *result = '\0'; + + if (p_und2) { + strcpy(result, p_und2); + strcat(result, ":"); + } + + strcat(result, str); + } + + return result; +} + +// FUNCTION: LEGO1 0x100698b0 +LegoBool LegoAnimPresenter::FUN_100698b0(const CompoundObject& p_rois, const LegoChar* p_und2) +{ + LegoBool result = FALSE; + + LegoChar* str; + if (*(str = FUN_100697c0(p_und2, NULL)) == '*') { + LegoChar* tmp = FUN_10069150(str); + delete[] str; + str = tmp; + } + + if (str != NULL && *str != '\0' && p_rois.size() > 0) { + for (CompoundObject::const_iterator it = p_rois.begin(); it != p_rois.end(); it++) { + LegoROI* roi = (LegoROI*) *it; + const char* name = roi->GetName(); + + if (name != NULL) { + if (!strcmpi(name, str)) { + m_unk0x70->Append(roi); + result = TRUE; + break; + } + } + } + } + + delete[] str; + return result; +} + +// FUNCTION: LEGO1 0x100699e0 +LegoROI* LegoAnimPresenter::FUN_100699e0(const LegoChar* p_und) +{ + LegoROIListCursor cursor(m_unk0x70); + LegoROI* roi; + + while (cursor.Next(roi)) { + LegoChar* und = FUN_100697c0(roi->GetName(), NULL); + + if (und != NULL && !strcmpi(und, p_und)) { + delete[] und; + return roi; + } + + delete[] und; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10069b10 +void LegoAnimPresenter::FUN_10069b10() +{ + LegoAnimStructMap map; + + if (m_unk0x8c != NULL) { + memset(m_unk0x8c, 0, m_unk0x94 * sizeof(*m_unk0x8c)); + } + + FUN_1006a3c0(map, m_anim->GetRoot(), NULL); + + if (m_roiMap != NULL) { + delete[] m_roiMap; + m_roiMapSize = 0; + } + + m_roiMapSize = 0; + m_roiMap = new LegoROI*[map.size() + 1]; + memset(m_roiMap, 0, (map.size() + 1) * sizeof(*m_roiMap)); + + for (LegoAnimStructMap::iterator it = map.begin(); it != map.end();) { + MxU32 index = (*it).second.m_index; + m_roiMap[index] = (*it).second.m_roi; + + if (m_roiMap[index]->GetName() != NULL) { + for (MxS32 i = 0; i < m_unk0x94; i++) { + if (m_unk0x8c[i] == NULL && m_unk0x90[i] != NULL) { + if (!strcmpi(m_unk0x90[i], m_roiMap[index]->GetName())) { + m_unk0x8c[i] = m_roiMap[index]; + break; + } + } + } + } + + delete[] const_cast((*it).first); + it++; + m_roiMapSize++; + } +} + +// FUNCTION: LEGO1 0x1006a3c0 +void LegoAnimPresenter::FUN_1006a3c0(LegoAnimStructMap& p_map, LegoTreeNode* p_node, LegoROI* p_roi) +{ + LegoROI* roi = p_roi; + LegoChar* und = NULL; + LegoChar* und2 = NULL; + LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); + const LegoChar* name = data->GetName(); + + if (name != NULL && *name != '-') { + if (*name == '*') { + name = und2 = FUN_10069150(name); + } + + und = FUN_100697c0(name, p_roi != NULL ? p_roi->GetName() : NULL); + + if (p_roi == NULL) { + roi = FUN_100699e0(und); + + if (roi != NULL) { + FUN_1006a4f0(p_map, data, und, roi); + } + else { + data->SetUnknown0x20(0); + } + } + else { + LegoROI* child = p_roi->FindChildROI(name, p_roi); + + if (child != NULL) { + FUN_1006a4f0(p_map, data, und, child); + } + else { + if (FUN_100699e0(name) != NULL) { + FUN_1006a3c0(p_map, p_node, NULL); + delete[] und; + delete[] und2; + return; + } + } + } + } + + delete[] und; + delete[] und2; + + MxS32 count = p_node->GetNumChildren(); + for (MxS32 i = 0; i < count; i++) { + FUN_1006a3c0(p_map, p_node->GetChild(i), roi); + } +} + +// FUNCTION: LEGO1 0x1006a4f0 +void LegoAnimPresenter::FUN_1006a4f0( + LegoAnimStructMap& p_map, + LegoAnimNodeData* p_data, + const LegoChar* p_und, + LegoROI* p_roi +) +{ + LegoAnimStructMap::iterator it; + + it = p_map.find(p_und); + if (it == p_map.end()) { + LegoAnimStruct animStruct; + animStruct.m_index = p_map.size() + 1; + animStruct.m_roi = p_roi; + + p_data->SetUnknown0x20(animStruct.m_index); + + LegoChar* und = new LegoChar[strlen(p_und) + 1]; + strcpy(und, p_und); + + p_map[und] = animStruct; + } + else { + p_data->SetUnknown0x20((*it).second.m_index); + } +} + +// FUNCTION: LEGO1 0x1006aa60 +// FUNCTION: BETA10 0x1004feee +void LegoAnimPresenter::FUN_1006aa60() +{ + LegoROIListCursor cursor(m_unk0x74); + LegoROI* roi; + + while (cursor.Next(roi)) { + const char* name = roi->GetName(); + + if (m_unk0x96 || !CharacterManager()->Exists(name)) { + CharacterManager()->FUN_10083c30(name); + } + } +} + +// FUNCTION: LEGO1 0x1006ab70 +void LegoAnimPresenter::FUN_1006ab70() +{ + if (m_unk0x96) { + AnimationManager()->FUN_10063270(m_unk0x74, this); + } + else { + AnimationManager()->FUN_10063780(m_unk0x74); + } +} + +// FUNCTION: LEGO1 0x1006aba0 +LegoBool LegoAnimPresenter::FUN_1006aba0() +{ + return FUN_1006abb0(m_anim->GetRoot(), 0); +} + +// FUNCTION: LEGO1 0x1006abb0 +MxBool LegoAnimPresenter::FUN_1006abb0(LegoTreeNode* p_node, LegoROI* p_roi) +{ + MxBool result = FALSE; + LegoROI* roi = p_roi; + LegoChar* und = NULL; + const LegoChar* name = ((LegoAnimNodeData*) p_node->GetData())->GetName(); + MxS32 i, count; + + if (name != NULL && *name != '-') { + und = FUN_100697c0(name, p_roi != NULL ? p_roi->GetName() : NULL); + + if (p_roi == NULL) { + roi = FUN_100699e0(und); + + if (roi == NULL) { + goto done; + } + } + else { + LegoROI* child = p_roi->FindChildROI(name, p_roi); + + if (child == NULL) { + if (FUN_100699e0(name) != NULL) { + if (FUN_1006abb0(p_node, NULL)) { + result = TRUE; + } + } + + goto done; + } + } + } + + count = p_node->GetNumChildren(); + for (i = 0; i < count; i++) { + if (!FUN_1006abb0(p_node->GetChild(i), roi)) { + goto done; + } + } + + result = TRUE; + +done: + if (und != NULL) { + delete[] und; + } + + return result; +} + +// FUNCTION: LEGO1 0x1006ac90 +// FUNCTION: BETA10 0x1005022e +void LegoAnimPresenter::SubstituteVariables() +{ + if (m_substMap != NULL) { + MxVariableTable* variableTable = VariableTable(); + + for (LegoAnimSubstMap::iterator it = m_substMap->begin(); it != m_substMap->end(); it++) { + variableTable->SetVariable((*it).first, (*it).second); + } + } +} + +// FUNCTION: LEGO1 0x1006ad30 +void LegoAnimPresenter::PutFrame() +{ + if (m_currentTickleState == e_streaming) { + MxLong time; + + if (m_action->GetStartTime() <= m_action->GetElapsedTime()) { + time = m_action->GetElapsedTime() - m_action->GetStartTime(); + } + else { + time = 0; + } + + FUN_1006b9a0(m_anim, time, m_unk0x78); + + if (m_unk0x8c != NULL && m_currentWorld != NULL && m_currentWorld->GetCamera() != NULL) { + for (MxS32 i = 0; i < m_unk0x94; i++) { + if (m_unk0x8c[i] != NULL) { + MxMatrix mat(m_unk0x8c[i]->GetLocal2World()); + + Vector3 pos(mat[0]); + Vector3 dir(mat[1]); + Vector3 up(mat[2]); + Vector3 und(mat[3]); + + float possqr = sqrt(pos.LenSquared()); + float dirsqr = sqrt(dir.LenSquared()); + float upsqr = sqrt(up.LenSquared()); + + up = und; + +#ifdef COMPAT_MODE + Mx3DPointFloat location = m_currentWorld->GetCamera()->GetWorldLocation(); + ((Vector3&) up).Sub(&location); +#else + ((Vector3&) up).Sub(&m_currentWorld->GetCamera()->GetWorldLocation()); +#endif + ((Vector3&) dir).Div(dirsqr); + pos.EqualsCross(&dir, &up); + pos.Unitize(); + up.EqualsCross(&pos, &dir); + ((Vector3&) pos).Mul(possqr); + ((Vector3&) dir).Mul(dirsqr); + ((Vector3&) up).Mul(upsqr); + + m_unk0x8c[i]->FUN_100a58f0(mat); + m_unk0x8c[i]->VTable0x14(); + } + } + } + } +} + +// FUNCTION: LEGO1 0x1006afc0 +// FUNCTION: BETA10 0x1005059a +MxResult LegoAnimPresenter::FUN_1006afc0(MxMatrix*& p_matrix, float p_und) +{ + MxU32 length = m_roiMapSize + 1; + p_matrix = new MxMatrix[length]; + + MxS32 i; + for (i = 1; i < length; i++) { + if (m_roiMap[i] != NULL) { + p_matrix[i] = m_roiMap[i]->GetLocal2World(); + } + } + + FUN_1006b900(m_anim, p_und, m_unk0x78); + + for (i = 1; i < length; i++) { + MxMatrix mat; + + if (m_roiMap[i] != NULL) { + mat = p_matrix[i]; + p_matrix[i] = m_roiMap[i]->GetLocal2World(); + m_roiMap[i]->FUN_100a58f0(mat); + } + } + + return SUCCESS; +} + +// STUB: LEGO1 0x1006b140 +// FUNCTION: BETA10 0x100507e0 +MxResult LegoAnimPresenter::FUN_1006b140(LegoROI* p_roi) +{ + // TODO + return FAILURE; +} + +// FUNCTION: LEGO1 0x1006b550 +void LegoAnimPresenter::ReadyTickle() +{ + m_currentWorld = CurrentWorld(); + + if (m_currentWorld) { + MxStreamChunk* chunk = m_subscriber->PeekData(); + + if (chunk && chunk->GetTime() + m_action->GetStartTime() <= m_action->GetElapsedTime()) { + chunk = m_subscriber->PopData(); + MxResult result = CreateAnim(chunk); + m_subscriber->FreeDataChunk(chunk); + + if (result == SUCCESS) { + ProgressTickleState(e_starting); + ParseExtra(); + } + else { + EndAction(); + } + } + } +} + +// FUNCTION: LEGO1 0x1006b5e0 +// FUNCTION: BETA10 0x10050b85 +void LegoAnimPresenter::StartingTickle() +{ + SubstituteVariables(); + FUN_100692b0(); + FUN_100695c0(); + + if (m_flags & c_mustSucceed && !FUN_1006aba0()) { + goto done; + } + + FUN_10069b10(); + FUN_1006c8a0(TRUE); + + if (m_unk0x78 == NULL) { + if (fabs(m_action->GetDirection().GetX()) >= 0.00000047683716F || + fabs(m_action->GetDirection().GetY()) >= 0.00000047683716F || + fabs(m_action->GetDirection().GetZ()) >= 0.00000047683716F) { + m_unk0x78 = new MxMatrix(); + CalcLocalTransform(m_action->GetLocation(), m_action->GetDirection(), m_action->GetUp(), *m_unk0x78); + } + else if (m_roiMap != NULL) { + LegoROI* roi = m_roiMap[1]; + + if (roi != NULL) { + MxMatrix mat; + mat = roi->GetLocal2World(); + m_unk0x78 = new MxMatrix(mat); + } + } + } + + if ((m_action->GetDuration() == -1 || ((MxDSMediaAction*) m_action)->GetSustainTime() == -1) && + m_compositePresenter) { + m_compositePresenter->VTable0x60(this); + } + else { + m_action->SetUnknown90(Timer()->GetTime()); + } + + ProgressTickleState(e_streaming); + + if (m_compositePresenter && m_compositePresenter->IsA("LegoAnimMMPresenter")) { + m_unk0x96 = ((LegoAnimMMPresenter*) m_compositePresenter)->FUN_1004b8b0(); + m_compositePresenter->VTable0x60(this); + } + + VTable0x8c(); + +done: + if (m_unk0x70 != NULL) { + delete m_unk0x70; + m_unk0x70 = NULL; + } +} + +// FUNCTION: LEGO1 0x1006b840 +void LegoAnimPresenter::StreamingTickle() +{ + if (m_subscriber->PeekData()) { + MxStreamChunk* chunk = m_subscriber->PopData(); + m_subscriber->FreeDataChunk(chunk); + } + + if (m_unk0x95) { + ProgressTickleState(e_done); + if (m_compositePresenter) { + if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { + m_compositePresenter->VTable0x60(this); + } + } + } + else { + if (m_action->GetElapsedTime() > m_anim->GetDuration() + m_action->GetStartTime()) { + m_unk0x95 = TRUE; + } + } +} + +// FUNCTION: LEGO1 0x1006b8c0 +void LegoAnimPresenter::DoneTickle() +{ + MxVideoPresenter::DoneTickle(); +} + +// FUNCTION: LEGO1 0x1006b8d0 +MxResult LegoAnimPresenter::AddToManager() +{ + return MxVideoPresenter::AddToManager(); +} + +// FUNCTION: LEGO1 0x1006b8e0 +void LegoAnimPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x1006b8f0 +const char* LegoAnimPresenter::GetActionObjectName() +{ + return m_action->GetObjectName(); +} + +// FUNCTION: LEGO1 0x1006b900 +// FUNCTION: BETA10 0x100510d8 +void LegoAnimPresenter::FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) +{ + LegoTreeNode* root = p_anim->GetRoot(); + MxMatrix mat; + LegoAnimNodeData* data = (LegoAnimNodeData*) root->GetData(); + + if (p_matrix != NULL) { + mat = *p_matrix; + } + else { + LegoROI* roi = m_roiMap[data->GetUnknown0x20()]; + + if (roi != NULL) { + mat = roi->GetLocal2World(); + } + else { + mat.SetIdentity(); + } + } + + LegoROI::FUN_100a8fd0(root, mat, p_time, m_roiMap); +} + +// FUNCTION: LEGO1 0x1006b9a0 +void LegoAnimPresenter::FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix) +{ + LegoTreeNode* root = p_anim->GetRoot(); + MxMatrix mat; + LegoAnimNodeData* data = (LegoAnimNodeData*) root->GetData(); + + if (p_matrix != NULL) { + mat = *p_matrix; + } + else { + LegoROI* roi = m_roiMap[data->GetUnknown0x20()]; + + if (roi != NULL) { + mat = roi->GetLocal2World(); + } + else { + mat.SetIdentity(); + } + } + + if (p_anim->GetScene() != NULL) { + MxMatrix transform(mat); + p_anim->GetScene()->FUN_1009f490(p_time, transform); + + if (m_currentWorld != NULL && m_currentWorld->GetCamera() != NULL) { + m_currentWorld->GetCamera()->FUN_100123e0(transform, 0); + } + } + + LegoROI::FUN_100a8e80(root, mat, p_time, m_roiMap); +} + +// FUNCTION: LEGO1 0x1006bac0 +// FUNCTION: BETA10 0x100512e1 +void LegoAnimPresenter::ParseExtra() +{ + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[256]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char output[256]; + if (KeyValueStringParse(NULL, g_strFROM_PARENT, extraCopy) && m_compositePresenter != NULL) { + m_compositePresenter->GetAction()->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + } + } + + if (KeyValueStringParse(output, g_strHIDE_ON_STOP, extraCopy)) { + m_flags |= c_hideOnStop; + } + + if (KeyValueStringParse(output, g_strMUST_SUCCEED, extraCopy)) { + m_flags |= c_mustSucceed; + } + + if (KeyValueStringParse(output, g_strSUBST, extraCopy)) { + m_substMap = new LegoAnimSubstMap(); + + char* substToken = output; + char *key, *value; + + while ((key = strtok(substToken, g_parseExtraTokens))) { + substToken = NULL; + + if ((value = strtok(NULL, g_parseExtraTokens))) { + char* keyCopy = new char[strlen(key) + 1]; + strcpy(keyCopy, key); + char* valueCopy = new char[strlen(value) + 1]; + strcpy(valueCopy, value); + (*m_substMap)[keyCopy] = valueCopy; + } + } + } + + if (KeyValueStringParse(output, g_strWORLD, extraCopy)) { + char* token = strtok(output, g_parseExtraTokens); + m_worldAtom = MxAtomId(token, e_lowerCase2); + + token = strtok(NULL, g_parseExtraTokens); + m_worldId = atoi(token); + } + + if (KeyValueStringParse(output, g_strPTATCAM, extraCopy)) { + list tmp; + + if (m_unk0x90 != NULL) { + for (MxS32 i = 0; i < m_unk0x94; i++) { + if (m_unk0x90[i] != NULL) { + // (modernization) critical bug: wrong free + delete[] m_unk0x90; + } + } + + delete[] m_unk0x90; + m_unk0x90 = NULL; + } + + if (m_unk0x8c != NULL) { + delete[] m_unk0x8c; + m_unk0x8c = NULL; + } + + char* token = strtok(output, g_parseExtraTokens); + while (token != NULL) { + char* valueCopy = new char[strlen(token) + 1]; + strcpy(valueCopy, token); + tmp.push_back(valueCopy); + token = strtok(NULL, g_parseExtraTokens); + } + + m_unk0x94 = tmp.size(); + if (m_unk0x94 != 0) { + m_unk0x8c = new LegoROI*[m_unk0x94]; + m_unk0x90 = new char*[m_unk0x94]; + memset(m_unk0x8c, 0, sizeof(*m_unk0x8c) * m_unk0x94); + memset(m_unk0x90, 0, sizeof(*m_unk0x90) * m_unk0x94); + + MxS32 i = 0; + for (list::iterator it = tmp.begin(); it != tmp.end(); it++, i++) { + m_unk0x90[i] = *it; + } + } + } + } +} + +// FUNCTION: LEGO1 0x1006c570 +// FUNCTION: BETA10 0x10051ab3 +void LegoAnimPresenter::VTable0xa0(Matrix4& p_matrix) +{ + if (m_unk0x78 != NULL) { + delete m_unk0x78; + } + + m_unk0x78 = new MxMatrix(p_matrix); +} + +// FUNCTION: LEGO1 0x1006c620 +MxResult LegoAnimPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) +{ + MxResult result = MxVideoPresenter::StartAction(p_controller, p_action); + m_displayZ = 0; + return result; +} + +// FUNCTION: LEGO1 0x1006c640 +// FUNCTION: BETA10 0x10051b7a +void LegoAnimPresenter::EndAction() +{ + undefined4 unused; // required for match + + if (m_action == NULL) { + return; + } + + LegoWorld* world = CurrentWorld(); + + if (world != NULL) { + LegoEndAnimNotificationParam param(c_notificationEndAnim, NULL, 0); + NotificationManager()->Send(world, param); + } + + if (m_anim != NULL) { + FUN_1006b9a0(m_anim, m_anim->GetDuration(), m_unk0x78); + } + + if (m_roiMapSize != 0 && m_roiMap != NULL && m_roiMap[1] != NULL && m_flags & c_hideOnStop) { + for (MxS16 i = 1; i <= m_roiMapSize; i++) { + if (m_roiMap[i] != NULL) { + m_roiMap[i]->SetVisibility(FALSE); + } + } + } + + FUN_1006c8a0(FALSE); + FUN_1006ab70(); + VTable0x90(); + + if (m_currentWorld != NULL) { + m_currentWorld->Remove(this); + } + + MxVideoPresenter::EndAction(); +} + +// FUNCTION: LEGO1 0x1006c7d0 +// FUNCTION: BETA10 0x10051e07 +void LegoAnimPresenter::VTable0x8c() +{ + if (m_unk0x78) { + m_unk0xa8.Add((*m_unk0x78)[3]); + } + else { + m_unk0xa8.Add(&m_action->GetLocation()); + } + + if (m_currentWorld == NULL) { + m_currentWorld = m_worldId != -1 ? FindWorld(m_worldAtom, m_worldId) : CurrentWorld(); + } + + if (m_currentWorld) { + m_currentWorld->FUN_1001fda0(this); + if (!m_compositePresenter || !m_compositePresenter->IsA("LegoAnimMMPresenter")) { + m_currentWorld->Add(this); + } + } +} + +// FUNCTION: LEGO1 0x1006c860 +// FUNCTION: BETA10 0x10051f45 +void LegoAnimPresenter::VTable0x90() +{ + if (m_currentWorld != NULL) { + m_currentWorld->FUN_1001fe90(this); + + if (m_compositePresenter != NULL && m_compositePresenter->IsA("LegoAnimMMPresenter")) { + return; + } + + m_currentWorld->Remove(this); + } +} + +// FUNCTION: LEGO1 0x1006c8a0 +void LegoAnimPresenter::FUN_1006c8a0(MxBool p_bool) +{ + if (m_roiMapSize != 0 && m_roiMap != NULL) { + for (MxU32 i = 1; i <= m_roiMapSize; i++) { + LegoEntity* entity = m_roiMap[i]->GetEntity(); + + if (entity != NULL) { + if (p_bool) { + entity->SetUnknown0x10Flag(LegoEntity::c_altBit1); + } + else { + entity->ClearUnknown0x10Flag(LegoEntity::c_altBit1); + } + } + } + } +} + +// FUNCTION: LEGO1 0x1006c8f0 +// FUNCTION: BETA10 0x1005206c +MxU32 LegoAnimPresenter::VTable0x94(Vector3& p_vec1, Vector3& p_vec2, float p_f1, float p_f2, Vector3& p_vec3) +{ + Mx3DPointFloat a, b; + + b = p_vec2; + ((Vector3&) b).Mul(p_f1); + ((Vector3&) b).Add(&p_vec1); + + a = b; + ((Vector3&) a).Sub(&m_unk0xa8); + + float len = a.LenSquared(); + if (len <= 0.0f) { + return TRUE; + } + + if (m_unk0xa4 + p_f2 >= sqrt(len) && m_roiMapSize != 0 && m_roiMap != NULL) { + for (MxU32 i = 1; i <= m_roiMapSize; i++) { + if (m_roiMap[i]->GetLODCount() != 0 && + m_roiMap[i]->FUN_100a9410(p_vec1, p_vec2, p_f1, p_f2, p_vec3, FALSE)) { + return TRUE; + } + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x1006ca50 +// FUNCTION: BETA10 0x100521d0 +MxResult LegoAnimPresenter::VTable0x98(LegoPathBoundary* p_boundary) +{ + for (MxU32 i = 1; i <= m_roiMapSize; i++) { + LegoEntity* entity = m_roiMap[i]->GetEntity(); + + if (entity != NULL) { + p_boundary->AddActor((LegoPathActor*) entity); + } + } + + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/video/legocarbuildanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legocarbuildanimpresenter.cpp new file mode 100644 index 00000000..d759364b --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legocarbuildanimpresenter.cpp @@ -0,0 +1,45 @@ +#include "legocarbuildanimpresenter.h" + +DECOMP_SIZE_ASSERT(LegoCarBuildAnimPresenter, 0x150) + +// STUB: LEGO1 0x10078400 +LegoCarBuildAnimPresenter::LegoCarBuildAnimPresenter() +{ + // TODO +} + +// STUB: LEGO1 0x10078500 +void LegoCarBuildAnimPresenter::RepeatingTickle() +{ + // TODO +} + +// STUB: LEGO1 0x10078680 +LegoCarBuildAnimPresenter::~LegoCarBuildAnimPresenter() +{ + // TODO +} + +// STUB: LEGO1 0x10078790 +void LegoCarBuildAnimPresenter::PutFrame() +{ + // TODO +} + +// STUB: LEGO1 0x100788c0 +void LegoCarBuildAnimPresenter::ReadyTickle() +{ + // TODO +} + +// STUB: LEGO1 0x100789e0 +void LegoCarBuildAnimPresenter::StreamingTickle() +{ + // TODO +} + +// STUB: LEGO1 0x10078db0 +void LegoCarBuildAnimPresenter::EndAction() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/video/legoflctexturepresenter.cpp b/LEGO1/lego/legoomni/src/video/legoflctexturepresenter.cpp new file mode 100644 index 00000000..8d77a1eb --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legoflctexturepresenter.cpp @@ -0,0 +1,34 @@ +#include "legoflctexturepresenter.h" + +DECOMP_SIZE_ASSERT(LegoFlcTexturePresenter, 0x70) + +// FUNCTION: LEGO1 0x1005de80 +LegoFlcTexturePresenter::LegoFlcTexturePresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x1005df70 +void LegoFlcTexturePresenter::Init() +{ + this->m_unk0x68 = 0; + this->m_unk0x6c = 0; +} + +// STUB: LEGO1 0x1005df80 +void LegoFlcTexturePresenter::StartingTickle() +{ + // TODO +} + +// STUB: LEGO1 0x1005e0c0 +void LegoFlcTexturePresenter::LoadFrame(MxStreamChunk* p_chunk) +{ + // TODO +} + +// STUB: LEGO1 0x1005e100 +void LegoFlcTexturePresenter::PutFrame() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp new file mode 100644 index 00000000..51e62448 --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legohideanimpresenter.cpp @@ -0,0 +1,227 @@ +#include "legohideanimpresenter.h" + +#include "anim/legoanim.h" +#include "legomain.h" +#include "legoworld.h" +#include "misc.h" + +DECOMP_SIZE_ASSERT(LegoHideAnimPresenter, 0xc4) +DECOMP_SIZE_ASSERT(LegoHideAnimStruct, 0x08) + +// FUNCTION: LEGO1 0x1006d7e0 +LegoHideAnimPresenter::LegoHideAnimPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x1006d860 +void LegoHideAnimPresenter::VTable0x8c() +{ +} + +// FUNCTION: LEGO1 0x1006d870 +void LegoHideAnimPresenter::VTable0x90() +{ +} + +// FUNCTION: LEGO1 0x1006d9f0 +LegoHideAnimPresenter::~LegoHideAnimPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x1006da50 +void LegoHideAnimPresenter::Init() +{ + m_boundaryMap = NULL; +} + +// FUNCTION: LEGO1 0x1006da60 +void LegoHideAnimPresenter::Destroy(MxBool p_fromDestructor) +{ + m_criticalSection.Enter(); + + if (m_boundaryMap) { + delete[] m_boundaryMap; + } + Init(); + + m_criticalSection.Leave(); + + // This appears to be a bug, since it results in an endless loop + if (!p_fromDestructor) { + LegoHideAnimPresenter::Destroy(); + } +} + +// FUNCTION: LEGO1 0x1006dab0 +MxResult LegoHideAnimPresenter::AddToManager() +{ + return LegoAnimPresenter::AddToManager(); +} + +// FUNCTION: LEGO1 0x1006dac0 +void LegoHideAnimPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x1006dad0 +void LegoHideAnimPresenter::PutFrame() +{ +} + +// FUNCTION: LEGO1 0x1006dae0 +// FUNCTION: BETA10 0x100530f4 +void LegoHideAnimPresenter::ReadyTickle() +{ + LegoLoopingAnimPresenter::ReadyTickle(); + + if (m_currentWorld) { + if (m_currentTickleState == e_starting && m_compositePresenter != NULL) { + SendToCompositePresenter(Lego()); + } + + m_currentWorld->Add(this); + } +} + +// FUNCTION: LEGO1 0x1006db20 +// FUNCTION: BETA10 0x1005316b +void LegoHideAnimPresenter::StartingTickle() +{ + LegoLoopingAnimPresenter::StartingTickle(); + + if (m_currentTickleState == e_streaming) { + FUN_1006dc10(); + FUN_1006db40(0); + } +} + +// FUNCTION: LEGO1 0x1006db40 +// FUNCTION: BETA10 0x100531ab +void LegoHideAnimPresenter::FUN_1006db40(LegoTime p_time) +{ + FUN_1006db60(m_anim->GetRoot(), p_time); +} + +// FUNCTION: LEGO1 0x1006db60 +// FUNCTION: BETA10 0x100531de +void LegoHideAnimPresenter::FUN_1006db60(LegoTreeNode* p_node, LegoTime p_time) +{ + LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); + MxBool newB = FALSE; + MxBool previousB = FALSE; + + if (m_roiMap != NULL) { + LegoROI* roi = m_roiMap[data->GetUnknown0x20()]; + + if (roi != NULL) { + newB = data->FUN_100a0990(p_time); + previousB = roi->GetVisibility(); + roi->SetVisibility(newB); + } + } + + if (m_boundaryMap != NULL) { + LegoPathBoundary* boundary = m_boundaryMap[data->GetUnknown0x22()]; + + if (boundary != NULL) { + newB = data->FUN_100a0990(p_time); + boundary->GetFlag0x10(); + // TODO: Match + boundary->SetFlag0x10(newB); + } + } + + for (MxS32 i = 0; i < p_node->GetNumChildren(); i++) { + FUN_1006db60(p_node->GetChild(i), p_time); + } +} + +// FUNCTION: LEGO1 0x1006dc10 +// FUNCTION: BETA10 0x100532fd +void LegoHideAnimPresenter::FUN_1006dc10() +{ + LegoHideAnimStructMap map; + + FUN_1006e3f0(map, m_anim->GetRoot()); + + if (m_boundaryMap != NULL) { + delete[] m_boundaryMap; + } + + m_boundaryMap = new LegoPathBoundary*[map.size() + 1]; + m_boundaryMap[0] = NULL; + + for (LegoHideAnimStructMap::iterator it = map.begin(); !(it == map.end()); it++) { + m_boundaryMap[(*it).second.m_index] = (*it).second.m_boundary; + delete[] const_cast((*it).first); + } +} + +// FUNCTION: LEGO1 0x1006e3f0 +// FUNCTION: BETA10 0x1005345e +void LegoHideAnimPresenter::FUN_1006e3f0(LegoHideAnimStructMap& p_map, LegoTreeNode* p_node) +{ + LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); + const char* name = data->GetName(); + + if (name != NULL) { + LegoPathBoundary* boundary = m_currentWorld->FindPathBoundary(name); + + if (boundary != NULL) { + FUN_1006e470(p_map, data, name, boundary); + } + else { + data->SetUnknown0x22(0); + } + } + + MxS32 count = p_node->GetNumChildren(); + for (MxS32 i = 0; i < count; i++) { + FUN_1006e3f0(p_map, p_node->GetChild(i)); + } +} + +// FUNCTION: LEGO1 0x1006e470 +// FUNCTION: BETA10 0x10053520 +void LegoHideAnimPresenter::FUN_1006e470( + LegoHideAnimStructMap& p_map, + LegoAnimNodeData* p_data, + const char* p_name, + LegoPathBoundary* p_boundary +) +{ + LegoHideAnimStructMap::iterator it; + + it = p_map.find(p_name); + if (it == p_map.end()) { + LegoHideAnimStruct animStruct; + animStruct.m_index = p_map.size() + 1; + animStruct.m_boundary = p_boundary; + + p_data->SetUnknown0x22(animStruct.m_index); + + char* name = new char[strlen(p_name) + 1]; + strcpy(name, p_name); + + p_map[name] = animStruct; + } + else { + p_data->SetUnknown0x22((*it).second.m_index); + } +} + +// FUNCTION: LEGO1 0x1006e9e0 +// FUNCTION: BETA10 0x100535ef +void LegoHideAnimPresenter::EndAction() +{ + if (m_action) { + MxVideoPresenter::EndAction(); + + if (m_currentWorld) { + m_currentWorld->Remove(this); + } + } +} diff --git a/LEGO1/lego/legoomni/src/video/legolocomotionanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legolocomotionanimpresenter.cpp new file mode 100644 index 00000000..90b6533e --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legolocomotionanimpresenter.cpp @@ -0,0 +1,164 @@ +#include "legolocomotionanimpresenter.h" + +#include "anim/legoanim.h" +#include "legoanimactor.h" +#include "legomain.h" +#include "legoworld.h" +#include "misc.h" +#include "mxautolock.h" +#include "mxdssubscriber.h" +#include "mxmisc.h" +#include "mxvariabletable.h" + +DECOMP_SIZE_ASSERT(LegoLocomotionAnimPresenter, 0xd8) + +// FUNCTION: LEGO1 0x1006cdd0 +LegoLocomotionAnimPresenter::LegoLocomotionAnimPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x1006d050 +LegoLocomotionAnimPresenter::~LegoLocomotionAnimPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x1006d0b0 +void LegoLocomotionAnimPresenter::Init() +{ + m_unk0xc0 = 0; + m_unk0xc4 = NULL; + m_unk0xcc = -1; + m_unk0xd0 = -1; + m_roiMapList = NULL; + m_unk0xd4 = 0; +} + +// FUNCTION: LEGO1 0x1006d0e0 +void LegoLocomotionAnimPresenter::Destroy(MxBool p_fromDestructor) +{ + m_criticalSection.Enter(); + + if (m_unk0xc4) { + delete[] m_unk0xc4; + } + + if (m_roiMapList) { + delete m_roiMapList; + } + + m_roiMap = NULL; + Init(); + + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + LegoLoopingAnimPresenter::Destroy(); + } +} + +// FUNCTION: LEGO1 0x1006d140 +MxResult LegoLocomotionAnimPresenter::CreateAnim(MxStreamChunk* p_chunk) +{ + MxResult result = LegoAnimPresenter::CreateAnim(p_chunk); + return result == SUCCESS ? SUCCESS : result; +} + +// FUNCTION: LEGO1 0x1006d160 +// FUNCTION: BETA10 0x100528c7 +MxResult LegoLocomotionAnimPresenter::AddToManager() +{ + m_roiMapList = new LegoROIMapList(); + + if (m_roiMapList == NULL) { + return FAILURE; + } + + return LegoAnimPresenter::AddToManager(); +} + +// FUNCTION: LEGO1 0x1006d5b0 +void LegoLocomotionAnimPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x1006d5c0 +void LegoLocomotionAnimPresenter::PutFrame() +{ + // Empty +} + +// FUNCTION: LEGO1 0x1006d5d0 +void LegoLocomotionAnimPresenter::ReadyTickle() +{ + LegoLoopingAnimPresenter::ReadyTickle(); + + if (m_currentWorld != NULL && m_currentTickleState == e_starting) { + m_currentWorld->Add(this); + if (m_compositePresenter != NULL) { + SendToCompositePresenter(Lego()); + } + + m_unk0xd4++; + } +} + +// FUNCTION: LEGO1 0x1006d610 +// FUNCTION: BETA10 0x10052a34 +void LegoLocomotionAnimPresenter::StartingTickle() +{ + if (m_subscriber->PeekData()) { + MxStreamChunk* chunk = m_subscriber->PopData(); + m_subscriber->FreeDataChunk(chunk); + } + + if (m_roiMapList->GetCount() != 0) { + ProgressTickleState(e_streaming); + } +} + +// FUNCTION: LEGO1 0x1006d660 +void LegoLocomotionAnimPresenter::StreamingTickle() +{ + if (m_unk0xd4 == 0) { + EndAction(); + } +} + +// FUNCTION: LEGO1 0x1006d670 +void LegoLocomotionAnimPresenter::EndAction() +{ + if (m_action) { + MxVideoPresenter::EndAction(); + } +} + +// FUNCTION: LEGO1 0x1006d680 +// FUNCTION: BETA10 0x10052b3d +void LegoLocomotionAnimPresenter::FUN_1006d680(LegoAnimActor* p_actor, MxFloat p_value) +{ + AUTOLOCK(m_criticalSection); + + MxVariableTable* variableTable = VariableTable(); + + const char* key = ((LegoAnimNodeData*) m_anim->GetRoot()->GetData())->GetName(); + variableTable->SetVariable(key, p_actor->GetROI()->GetName()); + + FUN_100695c0(); + FUN_10069b10(); + + if (m_roiMap != NULL) { + m_roiMapList->Append(m_roiMap); + p_actor->FUN_1001c450(m_anim, p_value, m_roiMap, m_roiMapSize); + m_roiMap = NULL; + } + + variableTable->SetVariable(key, ""); + + if (m_unk0x70 != NULL) { + delete m_unk0x70; + m_unk0x70 = NULL; + } +} diff --git a/LEGO1/lego/legoomni/src/video/legoloopinganimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoloopinganimpresenter.cpp new file mode 100644 index 00000000..eaba5d98 --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legoloopinganimpresenter.cpp @@ -0,0 +1,88 @@ +#include "legoloopinganimpresenter.h" + +#include "anim/legoanim.h" +#include "legocameracontroller.h" +#include "legoworld.h" +#include "mxcompositepresenter.h" +#include "mxdsaction.h" +#include "mxdssubscriber.h" + +DECOMP_SIZE_ASSERT(LegoLoopingAnimPresenter, 0xc0) + +// FUNCTION: LEGO1 0x1006caa0 +// FUNCTION: BETA10 0x1005223d +void LegoLoopingAnimPresenter::StreamingTickle() +{ + if (m_subscriber->PeekData()) { + MxStreamChunk* chunk = m_subscriber->PopData(); + m_subscriber->FreeDataChunk(chunk); + } + + if (m_unk0x95) { + ProgressTickleState(e_done); + if (m_compositePresenter) { + if (m_compositePresenter->IsA("LegoAnimMMPresenter")) { + m_compositePresenter->VTable0x60(this); + } + } + } + else { + if (m_action->GetDuration() != -1) { + if (m_action->GetElapsedTime() > m_action->GetDuration() + m_action->GetStartTime()) { + m_unk0x95 = TRUE; + } + } + } +} + +// FUNCTION: LEGO1 0x1006cb40 +// FUNCTION: BETA10 0x1005239a +void LegoLoopingAnimPresenter::PutFrame() +{ + MxLong time; + + if (m_action->GetStartTime() <= m_action->GetElapsedTime()) { + time = (m_action->GetElapsedTime() - m_action->GetStartTime()) % m_anim->GetDuration(); + } + else { + time = 0; + } + + FUN_1006b9a0(m_anim, time, m_unk0x78); + + if (m_unk0x8c != NULL && m_currentWorld != NULL && m_currentWorld->GetCamera() != NULL) { + for (MxS32 i = 0; i < m_unk0x94; i++) { + if (m_unk0x8c[i] != NULL) { + MxMatrix mat(m_unk0x8c[i]->GetLocal2World()); + + Vector3 pos(mat[0]); + Vector3 dir(mat[1]); + Vector3 up(mat[2]); + Vector3 und(mat[3]); + + float possqr = sqrt(pos.LenSquared()); + float dirsqr = sqrt(dir.LenSquared()); + float upsqr = sqrt(up.LenSquared()); + + up = und; + +#ifdef COMPAT_MODE + Mx3DPointFloat location = m_currentWorld->GetCamera()->GetWorldLocation(); + ((Vector3&) up).Sub(&location); +#else + ((Vector3&) up).Sub(&m_currentWorld->GetCamera()->GetWorldLocation()); +#endif + ((Vector3&) dir).Div(dirsqr); + pos.EqualsCross(&dir, &up); + pos.Unitize(); + up.EqualsCross(&pos, &dir); + ((Vector3&) pos).Mul(possqr); + ((Vector3&) dir).Mul(dirsqr); + ((Vector3&) up).Mul(upsqr); + + m_unk0x8c[i]->FUN_100a58f0(mat); + m_unk0x8c[i]->VTable0x14(); + } + } + } +} diff --git a/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp b/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp new file mode 100644 index 00000000..79c481c4 --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legomodelpresenter.cpp @@ -0,0 +1,330 @@ +#include "legomodelpresenter.h" + +#include "3dmanager/lego3dmanager.h" +#include "anim/legoanim.h" +#include "define.h" +#include "legocharactermanager.h" +#include "legoentity.h" +#include "legoentitypresenter.h" +#include "legovideomanager.h" +#include "legoworld.h" +#include "misc.h" +#include "misc/legocontainer.h" +#include "misc/legotexture.h" +#include "misc/version.h" +#include "mxcompositepresenter.h" +#include "mxdirectx/mxdirect3d.h" +#include "mxdssubscriber.h" +#include "mxutilities.h" +#include "realtime/realtime.h" +#include "roi/legoroi.h" + +DECOMP_SIZE_ASSERT(LegoModelPresenter, 0x6c) + +// GLOBAL: LEGO1 0x100f7ae0 +MxS32 g_modelPresenterConfig = 1; + +// FUNCTION: LEGO1 0x1000cca0 +void LegoModelPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x1007f660 +void LegoModelPresenter::configureLegoModelPresenter(MxS32 p_modelPresenterConfig) +{ + g_modelPresenterConfig = p_modelPresenterConfig; +} + +// FUNCTION: LEGO1 0x1007f670 +void LegoModelPresenter::Destroy(MxBool p_fromDestructor) +{ + m_criticalSection.Enter(); + m_roi = NULL; + m_addedToView = FALSE; + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxVideoPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x1007f6b0 +MxResult LegoModelPresenter::CreateROI(MxDSChunk* p_chunk) +{ + MxResult result = FAILURE; + LegoU32 numROIs; + Mx3DPointFloat vect; + LegoMemory storage(p_chunk->GetData()); + LegoAnim anim; + LegoU32 version, textureInfoOffset, i, numTextures, skipTextures; + MxMatrix mat; + LegoChar* textureName = NULL; + LegoTexture* texture = NULL; + LegoTextureInfo* textureInfo = NULL; + LegoS32 hardwareMode = VideoManager()->GetDirect3D()->AssignedDevice()->GetHardwareMode(); + + if (m_roi) { + delete m_roi; + } + if (!(m_roi = new LegoROI(VideoManager()->GetRenderer()))) { + goto done; + } + if (storage.Read(&version, sizeof(version)) != SUCCESS) { + goto done; + } + if (version != MODEL_VERSION) { + goto done; + } + if (storage.Read(&textureInfoOffset, sizeof(textureInfoOffset)) != SUCCESS) { + goto done; + } + + storage.SetPosition(textureInfoOffset); + + if (storage.Read(&numTextures, sizeof(numTextures)) != SUCCESS) { + goto done; + } + if (storage.Read(&skipTextures, sizeof(skipTextures)) != SUCCESS) { + goto done; + } + + for (i = 0; i < numTextures; i++) { + LegoU32 textureNameLength; + + storage.Read(&textureNameLength, sizeof(textureNameLength)); + textureName = new LegoChar[textureNameLength + 1]; + storage.Read(textureName, textureNameLength); + textureName[textureNameLength] = '\0'; + + strlwr(textureName); + + if (textureName[0] == '^') { + strcpy(textureName, textureName + 1); + + if (g_modelPresenterConfig) { + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + + LegoTexture* discardTexture = new LegoTexture(); + if (discardTexture->Read(&storage, FALSE) != SUCCESS) { + goto done; + } + delete discardTexture; + } + else { + LegoTexture* discardTexture = new LegoTexture(); + if (discardTexture->Read(&storage, FALSE) != SUCCESS) { + goto done; + } + delete discardTexture; + + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + } + } + else { + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + } + + if (!skipTextures) { + if (TextureContainer()->Get(textureName) == NULL) { + textureInfo = LegoTextureInfo::Create(textureName, texture); + + if (textureInfo == NULL) { + goto done; + } + + TextureContainer()->Add(textureName, textureInfo); + } + + delete[] textureName; + textureName = NULL; + delete texture; + texture = NULL; + } + } + + storage.SetPosition(8); + + if (storage.Read(&numROIs, sizeof(numROIs)) != SUCCESS) { + goto done; + } + if (anim.Read(&storage, FALSE) != SUCCESS) { + goto done; + } + if (m_roi->Read(NULL, VideoManager()->GetRenderer(), GetViewLODListManager(), TextureContainer(), &storage) != + SUCCESS) { + goto done; + } + if (m_roi->SetFrame(&anim, 0) != SUCCESS) { + goto done; + } + + // Get scripted location, direction and up vectors + + CalcLocalTransform( + Mx3DPointFloat(m_action->GetLocation().GetX(), m_action->GetLocation().GetY(), m_action->GetLocation().GetZ()), + Mx3DPointFloat( + m_action->GetDirection().GetX(), + m_action->GetDirection().GetY(), + m_action->GetDirection().GetZ() + ), + Mx3DPointFloat(m_action->GetUp().GetX(), m_action->GetUp().GetY(), m_action->GetUp().GetZ()), + mat + ); + m_roi->FUN_100a46b0(mat); + + result = SUCCESS; + +done: + if (textureName != NULL) { + delete[] textureName; + } + if (texture != NULL) { + delete texture; + } + if (result != SUCCESS) { + if (m_roi) { + delete m_roi; + m_roi = NULL; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1007ff70 +MxResult LegoModelPresenter::FUN_1007ff70( + MxDSChunk& p_chunk, + LegoEntity* p_entity, + MxBool p_roiVisible, + LegoWorld* p_world +) +{ + MxResult result = SUCCESS; + + ParseExtra(); + + if (m_roi == NULL && (result = CreateROI(&p_chunk)) == SUCCESS && p_entity != NULL) { + VideoManager()->Get3DManager()->GetLego3DView()->Add(*m_roi); + VideoManager()->Get3DManager()->GetLego3DView()->Moved(*m_roi); + } + + if (m_roi != NULL) { + m_roi->SetVisibility(p_roiVisible); + } + + if (p_entity != NULL) { + p_entity->SetROI(m_roi, TRUE, TRUE); + p_entity->ClearFlag(LegoEntity::c_bit2); + } + else { + p_world->GetROIList().push_back(m_roi); + } + + return result; +} + +// FUNCTION: LEGO1 0x10080050 +void LegoModelPresenter::ReadyTickle() +{ + if (m_compositePresenter != NULL && m_compositePresenter->IsA("LegoEntityPresenter") && + m_compositePresenter->GetCurrentTickleState() <= e_ready) { + return; + } + + ParseExtra(); + + if (m_roi != NULL) { + if (m_compositePresenter && m_compositePresenter->IsA("LegoEntityPresenter")) { + ((LegoEntityPresenter*) m_compositePresenter)->GetInternalEntity()->SetROI(m_roi, m_addedToView, TRUE); + ((LegoEntityPresenter*) m_compositePresenter) + ->GetInternalEntity() + ->SetFlags( + ((LegoEntityPresenter*) m_compositePresenter)->GetInternalEntity()->GetFlags() & ~LegoEntity::c_bit2 + ); + ((LegoEntityPresenter*) m_compositePresenter)->GetInternalEntity()->SetType(LegoEntity::e_character); + } + + ParseExtra(); + ProgressTickleState(e_starting); + EndAction(); + } + else { + MxStreamChunk* chunk = m_subscriber->PeekData(); + + if (chunk != NULL && chunk->GetTime() <= m_action->GetElapsedTime()) { + chunk = m_subscriber->PopData(); + MxResult result = CreateROI(chunk); + m_subscriber->FreeDataChunk(chunk); + + if (result == SUCCESS) { + VideoManager()->Get3DManager()->GetLego3DView()->Add(*m_roi); + VideoManager()->Get3DManager()->GetLego3DView()->Moved(*m_roi); + + if (m_compositePresenter != NULL && m_compositePresenter->IsA("LegoEntityPresenter")) { + ((LegoEntityPresenter*) m_compositePresenter)->GetInternalEntity()->SetROI(m_roi, TRUE, TRUE); + ((LegoEntityPresenter*) m_compositePresenter) + ->GetInternalEntity() + ->SetFlags( + ((LegoEntityPresenter*) m_compositePresenter)->GetInternalEntity()->GetFlags() & + ~LegoEntity::c_bit2 + ); + } + + ParseExtra(); + ProgressTickleState(e_starting); + } + + EndAction(); + } + } +} + +// FUNCTION: LEGO1 0x100801b0 +void LegoModelPresenter::ParseExtra() +{ + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[1024], output[1024]; + output[0] = '\0'; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + if (KeyValueStringParse(output, g_strAUTO_CREATE, extraCopy) != 0) { + char* token = strtok(output, g_parseExtraTokens); + + if (m_roi == NULL) { + m_roi = CharacterManager()->GetROI(token, FALSE); + m_addedToView = FALSE; + } + } + else if (KeyValueStringParse(output, g_strDB_CREATE, extraCopy) != 0 && m_roi == NULL) { + LegoWorld* currentWorld = CurrentWorld(); + list& roiList = currentWorld->GetROIList(); + + for (list::iterator it = roiList.begin(); it != roiList.end(); it++) { + if (!strcmpi((*it)->GetName(), output)) { + m_roi = *it; + roiList.erase(it); + + m_addedToView = TRUE; + VideoManager()->Get3DManager()->GetLego3DView()->Add(*m_roi); + VideoManager()->Get3DManager()->GetLego3DView()->Moved(*m_roi); + break; + } + } + } + } +} diff --git a/LEGO1/lego/legoomni/src/video/legopalettepresenter.cpp b/LEGO1/lego/legoomni/src/video/legopalettepresenter.cpp new file mode 100644 index 00000000..880f1b9f --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legopalettepresenter.cpp @@ -0,0 +1,95 @@ +#include "legopalettepresenter.h" + +#include "legovideomanager.h" +#include "misc.h" +#include "misc/legostorage.h" +#include "mxdsaction.h" +#include "mxdssubscriber.h" +#include "mxpalette.h" +#include "mxstreamchunk.h" + +DECOMP_SIZE_ASSERT(LegoPalettePresenter, 0x68) + +// FUNCTION: LEGO1 0x10079e50 +LegoPalettePresenter::LegoPalettePresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x1007a070 +LegoPalettePresenter::~LegoPalettePresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x1007a0d0 +void LegoPalettePresenter::Init() +{ + m_palette = NULL; +} + +// FUNCTION: LEGO1 0x1007a0e0 +void LegoPalettePresenter::Destroy(MxBool p_fromDestructor) +{ + m_criticalSection.Enter(); + if (m_palette) { + delete m_palette; + } + Init(); + m_criticalSection.Leave(); + if (!p_fromDestructor) { + MxVideoPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x1007a120 +void LegoPalettePresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x1007a130 +MxResult LegoPalettePresenter::ParsePalette(MxStreamChunk* p_chunk) +{ + MxU8 buffer[40]; + RGBQUAD palette[256]; + MxResult result = FAILURE; + + LegoMemory stream((char*) p_chunk->GetData()); + if (stream.Read(buffer, sizeof(buffer)) == SUCCESS) { + if (stream.Read(palette, sizeof(palette)) == SUCCESS) { + m_palette = new MxPalette(palette); + if (m_palette) { + result = SUCCESS; + } + } + } + + if (result != SUCCESS && m_palette) { + delete m_palette; + m_palette = NULL; + } + + return result; +} + +// FUNCTION: LEGO1 0x1007a230 +void LegoPalettePresenter::ReadyTickle() +{ + MxStreamChunk* chunk = m_subscriber->PeekData(); + if (chunk) { + if (chunk->GetTime() <= m_action->GetElapsedTime()) { + ParseExtra(); + ProgressTickleState(e_starting); + + chunk = m_subscriber->PopData(); + MxResult result = ParsePalette(chunk); + m_subscriber->FreeDataChunk(chunk); + + if (result == SUCCESS) { + VideoManager()->RealizePalette(m_palette); + } + EndAction(); + } + } +} diff --git a/LEGO1/lego/legoomni/src/video/legopartpresenter.cpp b/LEGO1/lego/legoomni/src/video/legopartpresenter.cpp new file mode 100644 index 00000000..87e15745 --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legopartpresenter.cpp @@ -0,0 +1,279 @@ +#include "legopartpresenter.h" + +#include "legovideomanager.h" +#include "misc.h" +#include "misc/legocontainer.h" +#include "misc/legostorage.h" +#include "misc/legotexture.h" +#include "mxdirectx/mxdirect3d.h" +#include "mxdsaction.h" +#include "mxdssubscriber.h" +#include "viewmanager/viewlodlist.h" + +DECOMP_SIZE_ASSERT(LegoLODList, 0x18) +DECOMP_SIZE_ASSERT(LegoNamedPart, 0x14) +DECOMP_SIZE_ASSERT(LegoNamedPartList, 0x18) + +// GLOBAL: LEGO1 0x100f7aa0 +MxS32 g_partPresenterConfig1 = 1; + +// GLOBAL: LEGO1 0x100f7aa4 +MxS32 g_partPresenterConfig2 = 100; + +// FUNCTION: LEGO1 0x1000cf60 +void LegoPartPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x1007c990 +void LegoPartPresenter::configureLegoPartPresenter(MxS32 p_partPresenterConfig1, MxS32 p_partPresenterConfig2) +{ + g_partPresenterConfig1 = p_partPresenterConfig1; + g_partPresenterConfig2 = p_partPresenterConfig2; +} + +// FUNCTION: LEGO1 0x1007c9b0 +MxResult LegoPartPresenter::AddToManager() +{ + VideoManager()->RegisterPresenter(*this); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1007c9d0 +void LegoPartPresenter::Destroy(MxBool p_fromDestructor) +{ + m_criticalSection.Enter(); + VideoManager()->UnregisterPresenter(*this); + + if (m_parts) { + delete m_parts; + m_parts = NULL; + } + m_parts = NULL; + + m_criticalSection.Leave(); + if (!p_fromDestructor) { + MxMediaPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x1007ca30 +MxResult LegoPartPresenter::Read(MxDSChunk& p_chunk) +{ + MxResult result = FAILURE; + LegoU32 numROIs, numLODs; + LegoMemory storage(p_chunk.GetData()); + LegoU32 textureInfoOffset, i, j, numTextures; + LegoU32 roiNameLength, roiInfoOffset, surplusLODs; + LegoLODList* lods; + LegoNamedPart* namedPart; + LegoChar* roiName = NULL; + LegoChar* textureName = NULL; + LegoTexture* texture = NULL; + LegoTextureInfo* textureInfo = NULL; + LegoS32 hardwareMode = VideoManager()->GetDirect3D()->AssignedDevice()->GetHardwareMode(); + + if (storage.Read(&textureInfoOffset, sizeof(textureInfoOffset)) != SUCCESS) { + goto done; + } + if (storage.SetPosition(textureInfoOffset) != SUCCESS) { + goto done; + } + if (storage.Read(&numTextures, sizeof(numTextures)) != SUCCESS) { + goto done; + } + + for (i = 0; i < numTextures; i++) { + LegoU32 textureNameLength; + + storage.Read(&textureNameLength, sizeof(textureNameLength)); + textureName = new LegoChar[textureNameLength + 1]; + storage.Read(textureName, textureNameLength); + textureName[textureNameLength] = '\0'; + + strlwr(textureName); + + if (textureName[0] == '^') { + strcpy(textureName, textureName + 1); + + if (g_partPresenterConfig1) { + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + + LegoTexture* discardTexture = new LegoTexture(); + if (discardTexture->Read(&storage, FALSE) != SUCCESS) { + goto done; + } + delete discardTexture; + } + else { + LegoTexture* discardTexture = new LegoTexture(); + if (discardTexture->Read(&storage, FALSE) != SUCCESS) { + goto done; + } + delete discardTexture; + + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + } + } + else { + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + } + + if (TextureContainer()->Get(textureName) == NULL) { + textureInfo = LegoTextureInfo::Create(textureName, texture); + + if (textureInfo == NULL) { + goto done; + } + + TextureContainer()->Add(textureName, textureInfo); + } + + delete[] textureName; + textureName = NULL; + delete texture; + texture = NULL; + } + + if (storage.SetPosition(4) != SUCCESS) { + goto done; + } + + m_parts = new LegoNamedPartList(); + + if (storage.Read(&numROIs, sizeof(numROIs)) != SUCCESS) { + goto done; + } + + for (i = 0; i < numROIs; i++) { + if (storage.Read(&roiNameLength, sizeof(roiNameLength)) != SUCCESS) { + goto done; + } + + roiName = new LegoChar[roiNameLength + 1]; + if (storage.Read(roiName, roiNameLength) != SUCCESS) { + goto done; + } + + roiName[roiNameLength] = '\0'; + strlwr(roiName); + + if (storage.Read(&numLODs, sizeof(numLODs)) != SUCCESS) { + goto done; + } + if (storage.Read(&roiInfoOffset, sizeof(roiInfoOffset)) != SUCCESS) { + goto done; + } + + if (numLODs > g_partPresenterConfig2) { + surplusLODs = numLODs - g_partPresenterConfig2; + numLODs = g_partPresenterConfig2; + } + else { + surplusLODs = 0; + } + + lods = new LegoLODList(); + + for (j = 0; j < numLODs; j++) { + LegoLOD* lod = new LegoLOD(VideoManager()->GetRenderer()); + + if (lod->Read(VideoManager()->GetRenderer(), TextureContainer(), &storage) != SUCCESS) { + goto done; + } + + if (j == 0) { + if (surplusLODs != 0 && lod->GetUnknown0x08Test8()) { + numLODs++; + surplusLODs--; + } + } + + lods->Append(lod); + } + + storage.SetPosition(roiInfoOffset); + + namedPart = new LegoNamedPart(roiName, lods); + m_parts->Append(namedPart); + + delete[] roiName; + roiName = NULL; + } + + result = SUCCESS; + +done: + if (roiName != NULL) { + delete[] roiName; + } + if (result != SUCCESS && m_parts != NULL) { + delete m_parts; + m_parts = NULL; + } + + return result; +} + +// FUNCTION: LEGO1 0x1007deb0 +void LegoPartPresenter::ReadyTickle() +{ + MxStreamChunk* chunk = m_subscriber->PeekData(); + + if (chunk != NULL && chunk->GetTime() <= m_action->GetElapsedTime()) { + ParseExtra(); + ProgressTickleState(e_starting); + + chunk = m_subscriber->PopData(); + MxResult result = Read(*chunk); + m_subscriber->FreeDataChunk(chunk); + + if (result == SUCCESS) { + Store(); + } + + EndAction(); + } +} + +// FUNCTION: LEGO1 0x1007df20 +void LegoPartPresenter::Store() +{ + LegoNamedPartListCursor partCursor(m_parts); + LegoNamedPart* part; + + while (partCursor.Next(part)) { + ViewLODList* lodList = GetViewLODListManager()->Lookup(part->GetName()->GetData()); + + if (lodList == NULL) { + lodList = GetViewLODListManager()->Create(part->GetName()->GetData(), part->GetList()->GetCount()); + + LegoLODListCursor lodCursor(part->GetList()); + LegoLOD* lod; + + while (lodCursor.First(lod)) { + lodCursor.Detach(); + lodList->PushBack(lod); + } + } + else { + lodList->Release(); + } + } + + if (m_parts != NULL) { + delete m_parts; + } + + m_parts = NULL; +} diff --git a/LEGO1/lego/legoomni/src/video/legophonemepresenter.cpp b/LEGO1/lego/legoomni/src/video/legophonemepresenter.cpp new file mode 100644 index 00000000..5fbbba21 --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legophonemepresenter.cpp @@ -0,0 +1,171 @@ +#include "legophonemepresenter.h" + +#include "legocharactermanager.h" +#include "legovideomanager.h" +#include "misc.h" +#include "misc/legocontainer.h" +#include "mxcompositepresenter.h" +#include "mxdsaction.h" + +DECOMP_SIZE_ASSERT(LegoPhonemePresenter, 0x88) + +// FUNCTION: LEGO1 0x1004e180 +LegoPhonemePresenter::LegoPhonemePresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x1004e340 +LegoPhonemePresenter::~LegoPhonemePresenter() +{ +} + +// FUNCTION: LEGO1 0x1004e3b0 +void LegoPhonemePresenter::Init() +{ + m_rectCount = 0; + m_textureInfo = NULL; + m_unk0x70 = FALSE; + m_unk0x84 = FALSE; +} + +// FUNCTION: LEGO1 0x1004e3d0 +// FUNCTION: BETA10 0x100c3646 +void LegoPhonemePresenter::StartingTickle() +{ + MxFlcPresenter::StartingTickle(); + + if (m_textureInfo == NULL) { + MxU16 extraLength; + char* extraData; + + m_action->GetExtra(extraLength, extraData); + + if (extraData != NULL) { + m_roiName = extraData; + m_roiName.ToUpperCase(); + + LegoROI *entityROI, *head; + + if (m_compositePresenter != NULL && m_compositePresenter->IsA("LegoAnimMMPresenter")) { + entityROI = FindROI(m_roiName.GetData()); + m_unk0x84 = TRUE; + } + else { + entityROI = CharacterManager()->GetROI(m_roiName.GetData(), TRUE); + } + + head = entityROI->FindChildROI("head", entityROI); + head->GetTexture(m_textureInfo); + + LegoPhonemeList* phonemeList = VideoManager()->GetPhonemeList(); + LegoPhoneme* phoneme = new LegoPhoneme(m_roiName.GetData(), 1); + + LegoPhonemeListCursor cursor(phonemeList); + + if (!cursor.Find(phoneme)) { + LegoTextureInfo* textureInfo = TextureContainer()->GetCached(m_textureInfo); + + CharacterManager()->FUN_100849a0(entityROI, textureInfo); + + phoneme->VTable0x0c(m_textureInfo); + phoneme->VTable0x14(textureInfo); + phonemeList->Append(phoneme); + m_textureInfo = textureInfo; + } + else { + LegoPhoneme* newPhoneme = phoneme; + cursor.Current(phoneme); + delete newPhoneme; + + phoneme->VTable0x04(phoneme->VTable0x00() + 1); + cursor.SetValue(phoneme); + + m_unk0x70 = TRUE; + } + } + } +} + +// FUNCTION: LEGO1 0x1004e800 +// FUNCTION: BETA10 0x100c3ac9 +void LegoPhonemePresenter::LoadFrame(MxStreamChunk* p_chunk) +{ + MxU8* data = p_chunk->GetData(); + + m_rectCount = *(MxS32*) data; + data += sizeof(MxS32); + + MxRect32* rects = (MxRect32*) data; + data += m_rectCount * sizeof(MxRect32); + + MxBool decodedColorMap; + DecodeFLCFrame( + &m_frameBitmap->GetBitmapInfo()->m_bmiHeader, + m_frameBitmap->GetImage(), + m_flcHeader, + (FLIC_FRAME*) data, + &decodedColorMap + ); +} + +// FUNCTION: LEGO1 0x1004e840 +// FUNCTION: BETA10 0x100c3b5d +void LegoPhonemePresenter::PutFrame() +{ + if (m_textureInfo != NULL && m_rectCount != 0) { + m_textureInfo->FUN_10066010(m_frameBitmap->GetImage()); + m_rectCount = 0; + } +} + +// FUNCTION: LEGO1 0x1004e870 +// FUNCTION: BETA10 0x100c3c24 +void LegoPhonemePresenter::EndAction() +{ + if (m_action != NULL) { + MxFlcPresenter::EndAction(); + + LegoPhonemeList* phonemeList = VideoManager()->GetPhonemeList(); + LegoPhoneme* phoneme = new LegoPhoneme(m_roiName.GetData(), 1); + + LegoPhonemeListCursor cursor(phonemeList); + + if (cursor.Find(phoneme)) { + LegoPhoneme* newPhoneme = phoneme; + cursor.Current(phoneme); + delete newPhoneme; + + if (phoneme->VTable0x00() == 1) { + LegoROI* roi; + + if (m_unk0x84) { + roi = FindROI(m_roiName.GetData()); + } + else { + roi = CharacterManager()->GetROI(m_roiName.GetData(), TRUE); + } + + if (roi != NULL) { + CharacterManager()->FUN_100849a0(roi, NULL); + } + + if (!m_unk0x84) { + CharacterManager()->FUN_10083c30(m_roiName.GetData()); + } + + TextureContainer()->EraseCached(phoneme->VTable0x10()); + TextureContainer()->EraseCached(phoneme->VTable0x08()); + cursor.Destroy(); + } + else { + phoneme->VTable0x04(phoneme->VTable0x00() - 1); + cursor.SetValue(phoneme); + } + + if (!m_unk0x84) { + CharacterManager()->FUN_10083c30(m_roiName.GetData()); + } + } + } +} diff --git a/LEGO1/lego/legoomni/src/video/legotexturepresenter.cpp b/LEGO1/lego/legoomni/src/video/legotexturepresenter.cpp new file mode 100644 index 00000000..0c76b447 --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legotexturepresenter.cpp @@ -0,0 +1,148 @@ +#include "legotexturepresenter.h" + +#include "legovideomanager.h" +#include "misc.h" +#include "misc/legocontainer.h" +#include "misc/legoimage.h" +#include "misc/legostorage.h" +#include "mxcompositepresenter.h" +#include "mxdirectx/mxdirect3d.h" +#include "mxdssubscriber.h" + +DECOMP_SIZE_ASSERT(LegoTexturePresenter, 0x54) +DECOMP_SIZE_ASSERT(LegoNamedTexture, 0x14) +DECOMP_SIZE_ASSERT(LegoNamedTextureList, 0x18) +DECOMP_SIZE_ASSERT(LegoNamedTextureListCursor, 0x10) + +// FUNCTION: LEGO1 0x1004eb40 +LegoTexturePresenter::~LegoTexturePresenter() +{ + VideoManager()->UnregisterPresenter(*this); +} + +// FUNCTION: LEGO1 0x1004ebb0 +MxResult LegoTexturePresenter::AddToManager() +{ + VideoManager()->RegisterPresenter(*this); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1004ebd0 +MxResult LegoTexturePresenter::Read(MxDSChunk& p_chunk) +{ + MxResult result = FAILURE; + LegoMemory storage(p_chunk.GetData()); + LegoChar* textureName = NULL; + LegoS32 hardwareMode = VideoManager()->GetDirect3D()->AssignedDevice()->GetHardwareMode(); + + m_textures = new LegoNamedTextureList(); + + LegoU32 numTextures, i; + if (storage.Read(&numTextures, sizeof(numTextures)) != SUCCESS) { + goto done; + } + + for (i = 0; i < numTextures; i++) { + LegoU32 textureNameLength; + LegoTexture* texture; + LegoNamedTexture* namedTexture; + + if (storage.Read(&textureNameLength, sizeof(textureNameLength)) != SUCCESS) { + goto done; + } + + textureName = new LegoChar[textureNameLength + 1]; + if (storage.Read(textureName, textureNameLength) != SUCCESS) { + goto done; + } + + textureName[textureNameLength] = '\0'; + strlwr(textureName); + + texture = new LegoTexture(); + if (texture->Read(&storage, hardwareMode) != SUCCESS) { + goto done; + } + + namedTexture = new LegoNamedTexture(textureName, texture); + m_textures->Append(namedTexture); + + delete[] textureName; + textureName = NULL; + } + + result = SUCCESS; + +done: + if (textureName != NULL) { + delete[] textureName; + } + if (result != SUCCESS && m_textures != NULL) { + delete m_textures; + m_textures = NULL; + } + + return result; +} + +// FUNCTION: LEGO1 0x1004f290 +MxResult LegoTexturePresenter::Store() +{ + LegoNamedTextureListCursor cursor(m_textures); + LegoNamedTexture* namedTexture; + VideoManager(); + + while (cursor.Next(namedTexture)) { + LegoTexture* texture = namedTexture->GetTexture(); + LegoTextureInfo* textureInfo = TextureContainer()->Get(namedTexture->GetName()->GetData()); + + if (textureInfo == NULL) { + textureInfo = LegoTextureInfo::Create(namedTexture->GetName()->GetData(), texture); + + if (textureInfo != NULL) { + TextureContainer()->Add(namedTexture->GetName()->GetData(), textureInfo); + } + } + else { + textureInfo->FUN_10066010(texture->GetImage()->GetBits()); + } + } + + if (m_textures != NULL) { + delete m_textures; + } + + m_textures = NULL; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1004fc60 +MxResult LegoTexturePresenter::PutData() +{ + MxResult result = SUCCESS; + + if (MxPresenter::IsEnabled() && m_currentChunk != NULL) { + result = Read(*m_currentChunk); + if (result == SUCCESS) { + Store(); + } + + if (m_currentTickleState == e_streaming) { + m_subscriber->FreeDataChunk(m_currentChunk); + } + m_currentChunk = NULL; + } + + return result; +} + +// FUNCTION: LEGO1 0x1004fcb0 +void LegoTexturePresenter::DoneTickle() +{ + if (this->m_compositePresenter && !this->m_compositePresenter->VTable0x64(2)) { + SetTickleState(e_idle); + return; + } + + MxMediaPresenter::DoneTickle(); +} diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp new file mode 100644 index 00000000..d1767f16 --- /dev/null +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -0,0 +1,578 @@ +#include "legovideomanager.h" + +#include "3dmanager/lego3dmanager.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "misc.h" +#include "mxdirectx/mxdirect3d.h" +#include "mxdirectx/mxstopwatch.h" +#include "mxdisplaysurface.h" +#include "mxmisc.h" +#include "mxpalette.h" +#include "mxregion.h" +#include "mxtimer.h" +#include "mxtransitionmanager.h" +#include "realtime/matrix.h" +#include "realtime/realtime.h" +#include "roi/legoroi.h" +#include "tgl/d3drm/impl.h" +#include "viewmanager/viewroi.h" + +DECOMP_SIZE_ASSERT(LegoVideoManager, 0x590) +DECOMP_SIZE_ASSERT(MxStopWatch, 0x18) +DECOMP_SIZE_ASSERT(MxFrequencyMeter, 0x20) + +// FUNCTION: LEGO1 0x1007aa20 +LegoVideoManager::LegoVideoManager() +{ + m_renderer = NULL; + m_3dManager = NULL; + m_viewROI = NULL; + m_direct3d = NULL; + m_unk0xe6 = FALSE; + memset(m_unk0x78, 0, sizeof(m_unk0x78)); + m_unk0x78[0] = 0x6c; + m_phonemeRefList = NULL; + m_isFullscreenMovie = FALSE; + m_palette = NULL; + m_stopWatch = NULL; + m_drawCursor = FALSE; + m_cursorX = m_cursorY; + m_cursorYCopy = m_cursorY; + m_cursorXCopy = m_cursorY; + m_cursorSurface = NULL; + m_fullScreenMovie = FALSE; + m_drawFPS = FALSE; + m_unk0x528 = NULL; + m_arialFont = NULL; + m_unk0xe5 = FALSE; + m_unk0x554 = FALSE; + m_paused = FALSE; +} + +// FUNCTION: LEGO1 0x1007ab40 +LegoVideoManager::~LegoVideoManager() +{ + Destroy(); + delete m_palette; +} + +// FUNCTION: LEGO1 0x1007abb0 +MxResult LegoVideoManager::CreateDirect3D() +{ + if (!m_direct3d) { + m_direct3d = new MxDirect3D; + } + + return m_direct3d ? SUCCESS : FAILURE; +} + +// FUNCTION: LEGO1 0x1007ac40 +MxResult LegoVideoManager::Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, MxBool p_createThread) +{ + MxResult result = FAILURE; + MxBool paletteCreated = FALSE; + MxS32 deviceNum = -1; + Direct3DDeviceInfo* device = NULL; + MxDriver* driver = NULL; + MxDeviceEnumerate100d9cc8 deviceEnumerate; + Mx3DPointFloat posVec(0.0, 1.25, -50.0); + Mx3DPointFloat dirVec(0.0, 0.0, 1.0); + Mx3DPointFloat upVec(0.0, 1.0, 0.0); + MxMatrix outMatrix; + HWND hwnd = MxOmni::GetInstance()->GetWindowHandle(); + MxS32 bits = p_videoParam.Flags().Get16Bit() ? 16 : 8; + + if (!p_videoParam.GetPalette()) { + MxPalette* palette = new MxPalette; + p_videoParam.SetPalette(palette); + + if (!p_videoParam.GetPalette()) { + goto done; + } + paletteCreated = TRUE; + } + + PALETTEENTRY paletteEntries[256]; + p_videoParam.GetPalette()->GetEntries(paletteEntries); + + if (CreateDirect3D() != SUCCESS) { + goto done; + } + + if (deviceEnumerate.DoEnumerate() != SUCCESS) { + goto done; + } + + if (p_videoParam.GetDeviceName()) { + deviceNum = deviceEnumerate.ParseDeviceName(p_videoParam.GetDeviceName()); + if (deviceNum >= 0) { + if ((deviceNum = deviceEnumerate.GetDevice(deviceNum, driver, device)) != SUCCESS) { + deviceNum = -1; + } + } + } + + if (deviceNum < 0) { + deviceEnumerate.FUN_1009d210(); + deviceNum = deviceEnumerate.FUN_1009d0d0(); + deviceNum = deviceEnumerate.GetDevice(deviceNum, driver, device); + } + + m_direct3d->SetDevice(deviceEnumerate, driver, device); + + if (!driver->m_ddCaps.dwCaps2 && driver->m_ddCaps.dwSVBRops[7] != 2) { + p_videoParam.Flags().SetF2bit0(TRUE); + } + else { + p_videoParam.Flags().SetF2bit0(FALSE); + } + + ViewROI::SetUnk101013d8(p_videoParam.Flags().GetF2bit0() == FALSE); + + if (!m_direct3d->Create( + hwnd, + p_videoParam.Flags().GetFullScreen(), + p_videoParam.Flags().GetFlipSurfaces(), + p_videoParam.Flags().GetBackBuffers() == FALSE, + p_videoParam.GetRect().GetWidth(), + p_videoParam.GetRect().GetHeight(), + bits, + paletteEntries, + sizeof(paletteEntries) / sizeof(paletteEntries[0]) + )) { + goto done; + } + + if (MxVideoManager::VTable0x28( + p_videoParam, + m_direct3d->DirectDraw(), + m_direct3d->Direct3D(), + m_direct3d->FrontBuffer(), + m_direct3d->BackBuffer(), + m_direct3d->Clipper(), + p_frequencyMS, + p_createThread + ) != SUCCESS) { + goto done; + } + + m_renderer = Tgl::CreateRenderer(); + + if (!m_renderer) { + goto done; + } + + m_3dManager = new Lego3DManager; + + if (!m_3dManager) { + goto done; + } + + Lego3DManager::CreateStruct createStruct; + memset(&createStruct, 0, sizeof(createStruct)); + createStruct.m_hWnd = LegoOmni::GetInstance()->GetWindowHandle(); + createStruct.m_pDirectDraw = m_pDirectDraw; + createStruct.m_pFrontBuffer = m_displaySurface->GetDirectDrawSurface1(); + createStruct.m_pBackBuffer = m_displaySurface->GetDirectDrawSurface2(); + createStruct.m_pPalette = m_videoParam.GetPalette()->CreateNativePalette(); + createStruct.m_isFullScreen = FALSE; + createStruct.m_isWideViewAngle = m_videoParam.Flags().GetWideViewAngle(); + createStruct.m_direct3d = m_direct3d->Direct3D(); + createStruct.m_d3dDevice = m_direct3d->Direct3DDevice(); + + if (!m_3dManager->Create(createStruct)) { + goto done; + } + + ViewLODList* pLODList; + + if (ConfigureD3DRM() != SUCCESS) { + goto done; + } + + pLODList = m_3dManager->GetViewLODListManager()->Create("CameraROI", 1); + m_viewROI = new TimeROI(m_renderer, pLODList, Timer()->GetTime()); + pLODList->Release(); + + CalcLocalTransform(posVec, dirVec, upVec, outMatrix); + m_viewROI->WrappedSetLocalTransform(outMatrix); + + m_3dManager->Add(*m_viewROI); + m_3dManager->SetPointOfView(*m_viewROI); + + m_phonemeRefList = new LegoPhonemeList; + SetRender3D(FALSE); + m_stopWatch = new MxStopWatch; + m_stopWatch->Start(); + + result = SUCCESS; + +done: + if (paletteCreated) { + delete p_videoParam.GetPalette(); + p_videoParam.SetPalette(NULL); + } + + return result; +} + +// FUNCTION: LEGO1 0x1007b5e0 +void LegoVideoManager::Destroy() +{ + if (m_cursorSurface != NULL) { + m_cursorSurface->Release(); + m_cursorSurface = NULL; + } + + if (m_unk0x528 != NULL) { + m_unk0x528->Release(); + m_unk0x528 = NULL; + } + + if (m_arialFont != NULL) { + DeleteObject(m_arialFont); + m_arialFont = NULL; + } + + delete m_renderer; + + if (m_viewROI != NULL) { + if (m_3dManager != NULL) { + m_3dManager->Remove(*m_viewROI); + } + + delete m_viewROI; + } + + delete m_3dManager; + MxVideoManager::Destroy(); + delete m_phonemeRefList; + delete m_stopWatch; +} + +// FUNCTION: LEGO1 0x1007b6a0 +void LegoVideoManager::MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY) +{ + m_cursorX = p_cursorX; + m_cursorY = p_cursorY; + m_drawCursor = TRUE; + + if (623 < p_cursorX) { + m_cursorX = 623; + } + + if (463 < p_cursorY) { + m_cursorY = 463; + } +} + +// FUNCTION: LEGO1 0x1007b6f0 +void LegoVideoManager::ToggleFPS(MxBool p_visible) +{ + if (p_visible && !m_drawFPS) { + m_drawFPS = TRUE; + m_unk0x550 = 1.0; + m_unk0x54c = Timer()->GetTime(); + } + else { + m_drawFPS = p_visible; + } +} + +// FUNCTION: LEGO1 0x1007b770 +MxResult LegoVideoManager::Tickle() +{ + if (m_unk0x554 && !m_videoParam.Flags().GetFlipSurfaces() && + TransitionManager()->GetTransitionType() == MxTransitionManager::e_notTransitioning) { + Sleep(30); + } + + m_stopWatch->Stop(); + m_elapsedSeconds = m_stopWatch->ElapsedSeconds(); + m_stopWatch->Reset(); + m_stopWatch->Start(); + + m_direct3d->RestoreSurfaces(); + + SortPresenterList(); + + MxPresenter* presenter; + MxPresenterListCursor cursor(m_presenters); + + while (cursor.Next(presenter)) { + presenter->Tickle(); + } + + if (m_render3d && !m_paused) { + m_3dManager->GetLego3DView()->GetView()->Clear(); + } + + MxRect32 rect(0, 0, m_videoParam.GetRect().GetWidth() - 1, m_videoParam.GetRect().GetHeight() - 1); + InvalidateRect(rect); + + if (!m_paused && (m_render3d || m_unk0xe5)) { + cursor.Reset(); + + while (cursor.Next(presenter) && presenter->GetDisplayZ() >= 0) { + presenter->PutData(); + } + + if (!m_unk0xe5) { + m_3dManager->Render(0.0); + m_3dManager->GetLego3DView()->GetDevice()->Update(); + } + + cursor.Prev(); + + while (cursor.Next(presenter)) { + presenter->PutData(); + } + + if (m_drawCursor) { + DrawCursor(); + } + + if (m_drawFPS) { + DrawFPS(); + } + } + else if (m_fullScreenMovie) { + MxPresenter* presenter; + MxPresenterListCursor cursor(m_presenters); + + if (cursor.Last(presenter)) { + presenter->PutData(); + } + } + + if (!m_paused) { + if (m_render3d && m_videoParam.Flags().GetFlipSurfaces()) { + m_3dManager->GetLego3DView() + ->GetView() + ->ForceUpdate(0, 0, m_videoParam.GetRect().GetWidth(), m_videoParam.GetRect().GetHeight()); + } + + UpdateRegion(); + } + + m_region->Reset(); + return SUCCESS; +} + +inline void LegoVideoManager::DrawCursor() +{ + if (m_cursorX != m_cursorXCopy || m_cursorY != m_cursorYCopy) { + if (m_cursorX >= 0 && m_cursorY >= 0) { + m_cursorXCopy = m_cursorX; + m_cursorYCopy = m_cursorY; + } + } + + LPDIRECTDRAWSURFACE ddSurface2 = m_displaySurface->GetDirectDrawSurface2(); + + if (!m_cursorSurface) { + m_cursorRect.top = 0; + m_cursorRect.left = 0; + m_cursorRect.bottom = 16; + m_cursorRect.right = 16; + m_cursorSurface = MxDisplaySurface::CreateCursorSurface(); + + if (!m_cursorSurface) { + m_drawCursor = FALSE; + } + } + + ddSurface2 + ->BltFast(m_cursorXCopy, m_cursorYCopy, m_cursorSurface, &m_cursorRect, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); +} + +// STUB: LEGO1 0x1007bbc0 +void LegoVideoManager::DrawFPS() +{ + // TODO +} + +// FUNCTION: LEGO1 0x1007c080 +MxPresenter* LegoVideoManager::GetPresenterAt(MxS32 p_x, MxS32 p_y) +{ + MxPresenterListCursor cursor(m_presenters); + MxPresenter* presenter; + + while (cursor.Prev(presenter)) { + if (presenter->IsHit(p_x, p_y)) { + return presenter; + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x1007c290 +MxResult LegoVideoManager::RealizePalette(MxPalette* p_pallete) +{ + if (p_pallete && m_videoParam.GetPalette()) { + p_pallete->GetEntries(m_paletteEntries); + m_videoParam.GetPalette()->SetEntries(m_paletteEntries); + m_displaySurface->SetPalette(m_videoParam.GetPalette()); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1007c2d0 +MxResult LegoVideoManager::ResetPalette(MxBool p_ignoreSkyColor) +{ + MxResult result = FAILURE; + + if (m_videoParam.GetPalette() != NULL) { + m_videoParam.GetPalette()->Reset(p_ignoreSkyColor); + m_displaySurface->SetPalette(m_videoParam.GetPalette()); + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x1007c300 +void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable) +{ + EnableFullScreenMovie(p_enable, TRUE); +} + +// FUNCTION: LEGO1 0x1007c310 +void LegoVideoManager::EnableFullScreenMovie(MxBool p_enable, MxBool p_scale) +{ + if (m_isFullscreenMovie != p_enable) { + m_isFullscreenMovie = p_enable; + + if (p_enable) { + m_palette = m_videoParam.GetPalette()->Clone(); + OverrideSkyColor(FALSE); + + m_displaySurface->GetVideoParam().Flags().SetF1bit3(p_scale); + + m_render3d = FALSE; + m_fullScreenMovie = TRUE; + } + else { + m_displaySurface->ClearScreen(); + m_displaySurface->GetVideoParam().Flags().SetF1bit3(FALSE); + + // restore previous pallete + RealizePalette(m_palette); + delete m_palette; + m_palette = NULL; + + // update region where video used to be + MxRect32 rect( + 0, + 0, + m_videoParam.GetRect().GetRight() - m_videoParam.GetRect().GetLeft(), + m_videoParam.GetRect().GetBottom() - m_videoParam.GetRect().GetTop() + ); + + InvalidateRect(rect); + UpdateRegion(); + OverrideSkyColor(TRUE); + + m_render3d = TRUE; + m_fullScreenMovie = FALSE; + } + } + + if (p_enable) { + m_displaySurface->GetVideoParam().Flags().SetF1bit3(p_scale); + } + else { + m_displaySurface->GetVideoParam().Flags().SetF1bit3(FALSE); + } +} + +// FUNCTION: LEGO1 0x1007c440 +void LegoVideoManager::SetSkyColor(float p_red, float p_green, float p_blue) +{ + PALETTEENTRY colorStrucure; + + colorStrucure.peRed = (p_red * 255.0f); + colorStrucure.peGreen = (p_green * 255.0f); + colorStrucure.peBlue = (p_blue * 255.0f); + colorStrucure.peFlags = -124; + m_videoParam.GetPalette()->SetSkyColor(&colorStrucure); + m_videoParam.GetPalette()->SetOverrideSkyColor(TRUE); + m_3dManager->GetLego3DView()->GetView()->SetBackgroundColor(p_red, p_green, p_blue); +} + +// FUNCTION: LEGO1 0x1007c4c0 +void LegoVideoManager::OverrideSkyColor(MxBool p_shouldOverride) +{ + this->m_videoParam.GetPalette()->SetOverrideSkyColor(p_shouldOverride); +} + +// FUNCTION: LEGO1 0x1007c4d0 +void LegoVideoManager::UpdateView(MxU32 p_x, MxU32 p_y, MxU32 p_width, MxU32 p_height) +{ + if (p_width == 0) { + p_width = m_videoParam.GetRect().GetWidth(); + } + if (p_height == 0) { + p_height = m_videoParam.GetRect().GetHeight(); + } + + if (!m_paused) { + m_3dManager->GetLego3DView()->GetView()->ForceUpdate(p_x, p_y, p_width, p_height); + } +} + +// FUNCTION: LEGO1 0x1007c520 +void LegoVideoManager::FUN_1007c520() +{ + m_unk0xe5 = TRUE; + m_render3d = FALSE; + m_videoParam.GetPalette()->SetOverrideSkyColor(FALSE); + + m_displaySurface->ClearScreen(); + InputManager()->EnableInputProcessing(); + InputManager()->SetUnknown335(TRUE); +} + +// STUB: LEGO1 0x1007c560 +int LegoVideoManager::EnableRMDevice() +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x1007c740 +int LegoVideoManager::DisableRMDevice() +{ + // TODO + return 0; +} + +// FUNCTION: LEGO1 0x1007c930 +MxResult LegoVideoManager::ConfigureD3DRM() +{ + IDirect3DRMDevice2* d3drm = + ((TglImpl::DeviceImpl*) m_3dManager->GetLego3DView()->GetDevice())->ImplementationData(); + + if (!d3drm) { + return FAILURE; + } + + MxAssignedDevice* assignedDevice = m_direct3d->AssignedDevice(); + + if (assignedDevice && assignedDevice->GetFlags() & MxAssignedDevice::c_hardwareMode) { + if (assignedDevice->GetDesc().dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_LINEAR) { + d3drm->SetTextureQuality(D3DRMTEXTURE_LINEAR); + } + + d3drm->SetDither(TRUE); + + if (assignedDevice->GetDesc().dpcTriCaps.dwShadeCaps & D3DPSHADECAPS_ALPHAFLATBLEND) { + d3drm->SetRenderMode(D3DRMRENDERMODE_BLENDEDTRANSPARENCY); + } + } + + return SUCCESS; +} diff --git a/LEGO1/lego/legoomni/src/worlds/act3.cpp b/LEGO1/lego/legoomni/src/worlds/act3.cpp new file mode 100644 index 00000000..8195e6c7 --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/act3.cpp @@ -0,0 +1,95 @@ +#include "act3.h" + +DECOMP_SIZE_ASSERT(Act3, 0x4274) + +// STUB: LEGO1 0x10072270 +Act3::Act3() +{ + // TODO +} + +// FUNCTION: LEGO1 0x10072500 +MxBool Act3::VTable0x5c() +{ + return TRUE; +} + +// STUB: LEGO1 0x100726a0 +Act3::~Act3() +{ + // TODO +} + +// STUB: LEGO1 0x100727e0 +MxBool Act3::FUN_100727e0(LegoPathController*, Mx3DPointFloat& p_loc, Mx3DPointFloat& p_dir, Mx3DPointFloat& p_up) +{ + return FALSE; +} + +// STUB: LEGO1 0x10072980 +MxBool Act3::FUN_10072980(LegoPathController*, Mx3DPointFloat& p_loc, Mx3DPointFloat& p_dir, Mx3DPointFloat& p_up) +{ + return FALSE; +} + +// STUB: LEGO1 0x10072c30 +MxResult Act3::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10072d50 +void Act3::Destroy(MxBool p_fromDestructor) +{ + // TODO +} + +// STUB: LEGO1 0x10072de0 +MxLong Act3::Notify(MxParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10073270 +void Act3::ReadyWorld() +{ + // TODO +} + +// STUB: LEGO1 0x10073300 +MxResult Act3::Tickle() +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10073400 +void Act3::FUN_10073400() +{ +} + +// STUB: LEGO1 0x10073430 +void Act3::FUN_10073430() +{ +} + +// STUB: LEGO1 0x10073a90 +void Act3::Enable(MxBool p_enable) +{ + // TODO +} + +// STUB: LEGO1 0x10073e40 +void Act3::VTable0x60() +{ + // TODO +} + +// STUB: LEGO1 0x10073e50 +MxBool Act3::VTable0x64() +{ + // TODO + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp b/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp new file mode 100644 index 00000000..b3184aff --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/elevatorbottom.cpp @@ -0,0 +1,141 @@ +#include "elevatorbottom.h" + +#include "act1state.h" +#include "elevbott_actions.h" +#include "jukebox.h" +#include "jukebox_actions.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "legovariables.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxtransitionmanager.h" +#include "mxvariabletable.h" + +DECOMP_SIZE_ASSERT(ElevatorBottom, 0xfc) + +// FUNCTION: LEGO1 0x10017e90 +ElevatorBottom::ElevatorBottom() +{ + NotificationManager()->Register(this); + m_destLocation = LegoGameState::e_undefined; +} + +// FUNCTION: LEGO1 0x10018060 +ElevatorBottom::~ElevatorBottom() +{ + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + ControlManager()->Unregister(this); + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x100180f0 +MxResult ElevatorBottom::Create(MxDSAction& p_dsAction) +{ + MxResult result = LegoWorld::Create(p_dsAction); + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + } + + SetIsWorldActive(FALSE); + + GameState()->SetCurrentArea(LegoGameState::e_elevbott); + GameState()->StopArea(LegoGameState::e_previousArea); + + return result; +} + +// FUNCTION: LEGO1 0x10018150 +MxLong ElevatorBottom::Notify(MxParam& p_param) +{ + MxLong ret = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetType()) { + case c_notificationClick: + ret = HandleClick((LegoControlManagerEvent&) p_param); + break; + case c_notificationTransitioned: + GameState()->SwitchArea(m_destLocation); + break; + } + } + + return ret; +} + +// FUNCTION: LEGO1 0x100181b0 +void ElevatorBottom::ReadyWorld() +{ + LegoWorld::ReadyWorld(); + PlayMusic(JukeboxScript::c_InformationCenter_Music); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); +} + +// FUNCTION: LEGO1 0x100181d0 +MxLong ElevatorBottom::HandleClick(LegoControlManagerEvent& p_param) +{ + MxLong result = 0; + + if (p_param.GetUnknown0x28() == 1) { + switch (p_param.GetClickedObjectId()) { + case ElevbottScript::c_LeftArrow_Ctl: + m_destLocation = LegoGameState::e_infodoor; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + result = 1; + break; + case ElevbottScript::c_RightArrow_Ctl: + m_destLocation = LegoGameState::e_infomain; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + result = 1; + break; + case ElevbottScript::c_ElevBott_Elevator_Ctl: + LegoGameState* gs = GameState(); + Act1State* state = (Act1State*) gs->GetState("Act1State"); + + if (state == NULL) { + state = (Act1State*) gs->CreateState("Act1State"); + } + + state->SetElevatorFloor(Act1State::c_floor1); + m_destLocation = LegoGameState::e_elevride; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + VariableTable()->SetVariable(g_varCAMERALOCATION, "LCAMZI1,90"); + result = 1; + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100182c0 +void ElevatorBottom::Enable(MxBool p_enable) +{ + LegoWorld::Enable(p_enable); + + if (p_enable) { + InputManager()->SetWorld(this); + SetIsWorldActive(FALSE); + } + else { + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + } +} + +// FUNCTION: LEGO1 0x10018310 +MxBool ElevatorBottom::VTable0x64() +{ + DeleteObjects(&m_atom, 500, 999); + m_destLocation = LegoGameState::e_infomain; + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/gasstation.cpp b/LEGO1/lego/legoomni/src/worlds/gasstation.cpp new file mode 100644 index 00000000..d32b32ab --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/gasstation.cpp @@ -0,0 +1,421 @@ +#include "gasstation.h" + +#include "garage_actions.h" +#include "gasstationstate.h" +#include "islepathactor.h" +#include "jukebox.h" +#include "jukebox_actions.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "misc.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstillpresenter.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "mxtransitionmanager.h" +#include "radio.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(GasStation, 0x128) + +// GLOBAL: LEGO1 0x100f0160 +undefined4 g_unk0x100f0160 = 3; + +// GLOBAL: LEGO1 0x100f0164 +MxBool g_trackLedEnabled = FALSE; + +// FUNCTION: LEGO1 0x100046a0 +GasStation::GasStation() +{ + m_currentActorId = 0; + m_state = NULL; + m_destLocation = LegoGameState::e_undefined; + m_trackLedBitmap = NULL; + m_unk0x104 = 0; + m_unk0x114 = FALSE; + m_unk0x106 = 0; + m_unk0x10c = 0; + m_unk0x115 = FALSE; + m_trackLedTimer = 0; + + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x10004770 +MxBool GasStation::VTable0x5c() +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x100048c0 +GasStation::~GasStation() +{ + InputManager()->UnRegister(this); + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + ControlManager()->Unregister(this); + TickleManager()->UnregisterClient(this); + NotificationManager()->Unregister(this); + g_unk0x100f0160 = 3; +} + +// FUNCTION: LEGO1 0x10004990 +MxResult GasStation::Create(MxDSAction& p_dsAction) +{ + MxResult result = LegoWorld::Create(p_dsAction); + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + } + + InputManager()->SetCamera(NULL); + + m_state = (GasStationState*) GameState()->GetState("GasStationState"); + if (!m_state) { + m_state = (GasStationState*) GameState()->CreateState("GasStationState"); + m_state->m_unk0x14.m_unk0x00 = 1; + } + else if (m_state->m_unk0x14.m_unk0x00 == 4) { + m_state->m_unk0x14.m_unk0x00 = 4; + } + else { + m_state->m_unk0x14.m_unk0x00 = 3; + } + + GameState()->SetCurrentArea(LegoGameState::e_garage); + GameState()->StopArea(LegoGameState::e_previousArea); + + InputManager()->Register(this); + SetIsWorldActive(FALSE); + return result; +} + +// FUNCTION: LEGO1 0x10004a60 +MxLong GasStation::Notify(MxParam& p_param) +{ + MxResult result = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationEndAction: + result = HandleEndAction((MxEndActionNotificationParam&) p_param); + break; + case c_notificationKeyPress: + result = HandleKeyPress((((LegoEventNotificationParam&) p_param)).GetKey()); + break; + case c_notificationButtonDown: + result = HandleButtonDown(((LegoControlManagerEvent&) p_param)); + break; + case c_notificationClick: + result = HandleClick((LegoControlManagerEvent&) p_param); + break; + case c_notificationTransitioned: + GameState()->SwitchArea(m_destLocation); + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x10004b30 +void GasStation::ReadyWorld() +{ + PlayMusic(JukeboxScript::c_JBMusic2); + + m_trackLedBitmap = (MxStillPresenter*) Find("MxStillPresenter", "TrackLed_Bitmap"); + m_currentActorId = CurrentActor()->GetActorId(); + + switch (m_currentActorId) { + case 1: + switch (m_state->m_unk0x18) { + case 0: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs002nu_RunAnim); + m_unk0x106 = 1; + break; + case 1: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs003nu_RunAnim); + m_unk0x106 = 1; + break; + case 2: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs004nu_RunAnim); + m_unk0x106 = 1; + break; + default: + m_state->m_unk0x14.m_unk0x00 = 6; + PlayAction(GarageScript::c_wgs008nu_RunAnim); + m_unk0x106 = 1; + m_unk0x104 = 1; + break; + } + + if (m_state->m_unk0x18 < 5) { + m_state->m_unk0x18++; + } + + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + case 2: + switch (m_state->m_unk0x1a) { + case 0: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs006nu_RunAnim); + m_unk0x106 = 1; + break; + case 1: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs007nu_RunAnim); + m_unk0x106 = 1; + break; + default: + m_state->m_unk0x14.m_unk0x00 = 6; + PlayAction(GarageScript::c_wgs008nu_RunAnim); + m_unk0x106 = 1; + m_unk0x104 = 1; + break; + } + + if (m_state->m_unk0x1a < 5) { + m_state->m_unk0x1a++; + } + + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + case 3: + switch (m_state->m_unk0x1c) { + case 0: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs012nu_RunAnim); + m_unk0x106 = 1; + break; + case 1: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs014nu_RunAnim); + m_unk0x106 = 1; + break; + default: + m_state->m_unk0x14.m_unk0x00 = 6; + PlayAction(GarageScript::c_wgs017nu_RunAnim); + m_unk0x106 = 1; + m_unk0x104 = 1; + break; + } + + if (m_state->m_unk0x1c < 5) { + m_state->m_unk0x1c++; + } + + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + case 4: + switch (m_state->m_unk0x1e) { + case 0: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs009nu_RunAnim); + m_unk0x106 = 1; + break; + case 1: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs010nu_RunAnim); + m_unk0x106 = 1; + break; + default: + m_state->m_unk0x14.m_unk0x00 = 6; + PlayAction(GarageScript::c_wgs008nu_RunAnim); + m_unk0x106 = 1; + m_unk0x104 = 1; + break; + } + + if (m_state->m_unk0x1e < 5) { + m_state->m_unk0x1e++; + } + + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + case 5: + switch (m_state->m_unk0x20) { + case 0: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs020nu_RunAnim); + m_unk0x106 = 1; + break; + case 1: + m_state->m_unk0x14.m_unk0x00 = 5; + PlayAction(GarageScript::c_wgs021nu_RunAnim); + m_unk0x106 = 1; + break; + default: + m_state->m_unk0x14.m_unk0x00 = 6; + PlayAction(GarageScript::c_wgs022nu_RunAnim); + m_unk0x106 = 1; + m_unk0x104 = 1; + break; + } + + if (m_state->m_unk0x20 < 5) { + m_state->m_unk0x20++; + } + + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + default: + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + } +} + +// FUNCTION: LEGO1 0x10005590 +inline void GasStation::PlayAction(MxU32 p_objectId) +{ + MxDSAction action; + action.SetAtomId(*g_garageScript); + action.SetObjectId(p_objectId); + + BackgroundAudioManager()->LowerVolume(); + Start(&action); + m_state->FUN_10006430(p_objectId); +} + +// STUB: LEGO1 0x10005660 +MxLong GasStation::HandleEndAction(MxEndActionNotificationParam& p_param) +{ + // TODO + return 0; +} + +// FUNCTION: LEGO1 0x10005920 +MxLong GasStation::HandleKeyPress(MxS8 p_key) +{ + if (p_key == ' ' && g_unk0x100f0160 == 0 && this->m_unk0x106 != 0) { + m_state->FUN_10006490(); + return 1; + } + + return 0; +} + +// STUB: LEGO1 0x10005960 +MxLong GasStation::HandleButtonDown(LegoControlManagerEvent& p_param) +{ + // TODO + return 0; +} + +// FUNCTION: LEGO1 0x10005b20 +MxLong GasStation::HandleClick(LegoControlManagerEvent& p_param) +{ + if (p_param.GetUnknown0x28() == 1) { + MxDSAction action; + + switch (p_param.GetClickedObjectId()) { + case GarageScript::c_LeftArrow_Ctl: + case GarageScript::c_RightArrow_Ctl: + m_state->m_unk0x14.m_unk0x00 = 0; + m_destLocation = LegoGameState::Area::e_garadoor; + + m_state->FUN_10006490(); + m_radio.Stop(); + BackgroundAudioManager()->Stop(); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case GarageScript::c_Info_Ctl: + m_state->m_unk0x14.m_unk0x00 = 0; + m_destLocation = LegoGameState::Area::e_infomain; + + m_state->FUN_10006490(); + m_radio.Stop(); + BackgroundAudioManager()->Stop(); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case GarageScript::c_Buggy_Ctl: + m_state->m_unk0x14.m_unk0x00 = 0; + m_destLocation = LegoGameState::Area::e_dunecarbuild; + + m_state->FUN_10006490(); + m_radio.Stop(); + BackgroundAudioManager()->Stop(); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + } + } + + return 1; +} + +// FUNCTION: LEGO1 0x10005c40 +void GasStation::Enable(MxBool p_enable) +{ + LegoWorld::Enable(p_enable); + + if (p_enable) { + InputManager()->SetWorld(this); + InputManager()->SetCamera(NULL); + } + else { + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + } +} + +// FUNCTION: LEGO1 0x10005c90 +MxResult GasStation::Tickle() +{ + if (!m_worldStarted) { + LegoWorld::Tickle(); + return SUCCESS; + } + + if (g_unk0x100f0160 != 0) { + g_unk0x100f0160--; + } + + MxLong time = Timer()->GetTime(); + + if (m_unk0x114) { + if (time - m_unk0x10c > 15000) { + m_unk0x10c = time; + if (m_unk0x104 == 1) { + m_unk0x104 = 2; + } + else if (m_unk0x104 != 0) { + m_unk0x104 = 0; + MxDSAction action; + m_state->m_unk0x14.m_unk0x00 = 9; + PlayAction(GarageScript::c_wgs031nu_RunAnim); + m_unk0x106 = 1; + } + } + } + + if (m_unk0x115) { + if (time - m_trackLedTimer > 300) { + m_trackLedTimer = time; + g_trackLedEnabled = !g_trackLedEnabled; + m_trackLedBitmap->Enable(g_trackLedEnabled); + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10005e70 +MxBool GasStation::VTable0x64() +{ + m_radio.Stop(); + m_state->FUN_10006490(); + m_state->m_unk0x14.m_unk0x00 = 0; + m_destLocation = LegoGameState::Area::e_infomain; + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/historybook.cpp b/LEGO1/lego/legoomni/src/worlds/historybook.cpp new file mode 100644 index 00000000..56e09bed --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/historybook.cpp @@ -0,0 +1,156 @@ +#include "historybook.h" + +#include "jukebox.h" +#include "jukebox_actions.h" +#include "legocontrolmanager.h" +#include "legoinputmanager.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstillpresenter.h" +#include "mxtransitionmanager.h" + +DECOMP_SIZE_ASSERT(HistoryBook, 0x3e4) + +// FUNCTION: LEGO1 0x100822f0 +HistoryBook::HistoryBook() +{ + memset(m_alphabet, NULL, sizeof(m_alphabet)); + memset(m_names, NULL, sizeof(m_names)); + memset(m_scores, NULL, sizeof(m_scores)); + NotificationManager()->Register(this); +} + +// STUB: LEGO1 0x100824d0 +HistoryBook::~HistoryBook() +{ + // TODO +} + +// FUNCTION: LEGO1 0x10082610 +MxResult HistoryBook::Create(MxDSAction& p_dsAction) +{ + MxResult result = LegoWorld::Create(p_dsAction); + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + } + + InputManager()->SetCamera(NULL); + InputManager()->Register(this); + + GameState()->SetCurrentArea(LegoGameState::Area::e_histbook); + GameState()->StopArea(LegoGameState::Area::e_previousArea); + return result; +} + +// FUNCTION: LEGO1 0x10082680 +MxLong HistoryBook::Notify(MxParam& p_param) +{ + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationButtonUp: + m_destLocation = LegoGameState::Area::e_infoscor; + TransitionManager()->StartTransition(MxTransitionManager::TransitionType::e_mosaic, 50, FALSE, FALSE); + break; + case c_notificationTransitioned: + GameState()->SwitchArea(m_destLocation); + break; + } + } + + return 0; +} + +inline void SetColor(MxStillPresenter* p_presenter, MxU8 p_color, MxU8* p_colors, MxS32 p_x, MxS32 p_y) +{ + if (p_color) { + for (MxS32 lax = 0; lax < 4; lax++) { + if (p_presenter->GetAlphaMask() != NULL) { + memset(NULL, p_colors[p_color - 1], 4); + } + else { + memset(p_presenter->GetBitmap()->GetStart(p_x, p_y + lax), p_colors[p_color - 1], 4); + } + } + } +} + +// FUNCTION: LEGO1 0x100826f0 +void HistoryBook::ReadyWorld() +{ + LegoWorld::ReadyWorld(); + GameState()->GetHistory()->WriteScoreHistory(); + + char bitmap[] = "A_Bitmap"; + for (MxS16 i = 0; i < 26; i++) { + m_alphabet[i] = (MxStillPresenter*) Find("MxStillPresenter", bitmap); + bitmap[0]++; + } + + MxStillPresenter* scoreboxMaster = (MxStillPresenter*) Find("MxStillPresenter", "ScoreBox"); + MxU8 scoreColors[3] = + {0x76, 0x4c, 0x38}; // yellow - #FFB900, blue - #00548C, red - #CB1220, background - #CECECE, border - #74818B + MxS32 scoreY = 0x79; + + for (MxS16 scoreIndex = 0; scoreIndex < GameState()->GetHistory()->m_count; scoreIndex++) { + LegoGameState::ScoreItem* score = GameState()->GetHistory()->GetScore(scoreIndex); + + MxStillPresenter** scorebox = &m_scores[scoreIndex]; + *scorebox = scoreboxMaster->Clone(); + + MxS32 scoreX = 0x90; + if (scoreIndex >= 10) { + if (scoreIndex == 10) { + scoreY = 0x79; + } + + scoreX = 0x158; + } + + MxS32 scoreboxX = 1; + MxS32 scoreboxRow = 5; + MxS32 scoreState = 0; + + for (; scoreboxRow > 0; scoreboxRow--) { + for (MxS32 scoreBoxColumn = 0, scoreboxY = 1; scoreBoxColumn < 5; scoreBoxColumn++, scoreboxY += 5) { + SetColor(*scorebox, score->m_state[scoreState][scoreBoxColumn], scoreColors, scoreboxX, scoreboxY); + } + + scoreState++; + scoreboxX += 5; + } + + (*scorebox)->Enable(TRUE); + (*scorebox)->SetTickleState(MxPresenter::e_repeating); + (*scorebox)->SetPosition(scoreX + 0xa1, scoreY); + + for (MxS16 letterIndex = 0; letterIndex < (MxS16) sizeOfArray(m_names[0]);) { + MxS16 letter = score->m_name.m_letters[letterIndex]; + + if (letter == -1) { + break; + } + + MxS16 nameIndex = letterIndex++; + m_names[scoreIndex][nameIndex] = m_alphabet[letter]->Clone(); + m_names[scoreIndex][nameIndex]->Enable(TRUE); + m_names[scoreIndex][nameIndex]->SetTickleState(MxPresenter::e_repeating); + m_names[scoreIndex][nameIndex]->SetPosition(scoreX, scoreY); + scoreX += 0x17; + } + + scoreY += 0x1b; + } + + PlayMusic(JukeboxScript::c_InformationCenter_Music); +} + +// FUNCTION: LEGO1 0x10082a10 +MxBool HistoryBook::VTable0x64() +{ + m_destLocation = LegoGameState::Area::e_infomain; + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/hospital.cpp b/LEGO1/lego/legoomni/src/worlds/hospital.cpp new file mode 100644 index 00000000..cbc86643 --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/hospital.cpp @@ -0,0 +1,673 @@ +#include "hospital.h" + +#include "act1state.h" +#include "hospital_actions.h" +#include "hospitalstate.h" +#include "islepathactor.h" +#include "jukebox.h" +#include "jukebox_actions.h" +#include "legocontrolmanager.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "legoutils.h" +#include "misc.h" +#include "mxactionnotificationparam.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstillpresenter.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(Hospital, 0x12c) + +// GLOBAL: LEGO1 0x100f7918 +undefined4 g_unk0x100f7918 = 3; + +// GLOBAL: LEGO1 0x100f791c +MxBool g_copLedEnabled = FALSE; + +// GLOBAL: LEGO1 0x100f7920 +MxBool g_pizzaLedEnabled = FALSE; + +// FUNCTION: LEGO1 0x100745e0 +Hospital::Hospital() +{ + m_currentActorId = 0; + m_unk0x100 = 0; + m_hospitalState = NULL; + m_unk0x108 = 0; + m_destLocation = LegoGameState::e_undefined; + m_currentAction = HospitalScript::c__StartUp; + m_copLedBitmap = NULL; + m_pizzaLedBitmap = NULL; + m_unk0x118 = 0; + m_copLedAnimTimer = 0; + m_pizzaLedAnimTimer = 0; + m_unk0x128 = 0; + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x100746a0 +MxBool Hospital::VTable0x5c() +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x100747f0 +Hospital::~Hospital() +{ + InputManager()->UnRegister(this); + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + ControlManager()->Unregister(this); + TickleManager()->UnregisterClient(this); + + m_hospitalState->m_unk0x08.m_unk0x00 = 3; + + NotificationManager()->Unregister(this); + g_unk0x100f7918 = 3; +} + +// FUNCTION: LEGO1 0x100748c0 +MxResult Hospital::Create(MxDSAction& p_dsAction) +{ + MxResult result = LegoWorld::Create(p_dsAction); + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + } + + SetIsWorldActive(FALSE); + + m_hospitalState = (HospitalState*) GameState()->GetState("HospitalState"); + if (!m_hospitalState) { + m_hospitalState = (HospitalState*) GameState()->CreateState("HospitalState"); + m_hospitalState->m_unk0x08.m_unk0x00 = 1; + } + else if (m_hospitalState->m_unk0x08.m_unk0x00 == 4) { + m_hospitalState->m_unk0x08.m_unk0x00 = 4; + } + else { + m_hospitalState->m_unk0x08.m_unk0x00 = 3; + } + + GameState()->SetCurrentArea(LegoGameState::e_hospital); + GameState()->StopArea(LegoGameState::e_previousArea); + + InputManager()->Register(this); + FUN_1003ef00(FALSE); + + return result; +} + +// FUNCTION: LEGO1 0x10074990 +MxLong Hospital::Notify(MxParam& p_param) +{ + MxLong result = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationEndAction: + result = HandleEndAction((MxEndActionNotificationParam&) p_param); + break; + case c_notificationKeyPress: + result = HandleKeyPress((((LegoEventNotificationParam&) p_param)).GetKey()); + break; + case c_notificationButtonDown: + result = HandleButtonDown(((LegoControlManagerEvent&) p_param)); + break; + case c_notificationClick: + result = HandleClick((LegoControlManagerEvent&) p_param); + break; + case c_notificationTransitioned: + if (m_destLocation != LegoGameState::e_undefined) { + GameState()->SwitchArea(m_destLocation); + } + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x10074a60 +void Hospital::ReadyWorld() +{ + PlayMusic(JukeboxScript::c_Hospital_Music); + + m_copLedBitmap = (MxStillPresenter*) Find("MxStillPresenter", "CopLed_Bitmap"); + m_pizzaLedBitmap = (MxStillPresenter*) Find("MxStillPresenter", "PizzaLed_Bitmap"); + + if (CurrentActor() == NULL) { + m_currentActorId = 5; + } + else { + m_currentActorId = CurrentActor()->GetActorId(); + } + + switch (m_currentActorId) { + case 1: + m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x0e; + + if (m_hospitalState->m_unk0x0e < 5) { + m_hospitalState->m_unk0x0e += 1; + } + + break; + case 2: + m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x10; + + if (m_hospitalState->m_unk0x10 < 5) { + m_hospitalState->m_unk0x10 += 1; + } + + break; + case 3: + m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x12; + + if (m_hospitalState->m_unk0x12 < 5) { + m_hospitalState->m_unk0x12 += 1; + } + + break; + case 4: + m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x14; + + if (m_hospitalState->m_unk0x14 < 5) { + m_hospitalState->m_unk0x14 += 1; + } + + break; + case 5: + m_hospitalState->m_unk0x0c = m_hospitalState->m_unk0x16; + + if (m_hospitalState->m_unk0x16 < 5) { + m_hospitalState->m_unk0x16 += 1; + } + + break; + } + + if (m_hospitalState->m_unk0x0c < 3) { + HospitalScript::Script hospitalScript[] = { + HospitalScript::c_hho002cl_RunAnim, + HospitalScript::c_hho004jk_RunAnim, + HospitalScript::c_hho007p1_RunAnim + }; + + m_hospitalState->m_unk0x08.m_unk0x00 = 5; + + PlayAction(hospitalScript[m_hospitalState->m_unk0x0c]); + m_currentAction = hospitalScript[m_hospitalState->m_unk0x0c]; + } + else { + m_unk0x100 = 1; + m_time = Timer()->GetTime(); + + m_hospitalState->m_unk0x08.m_unk0x00 = 6; + + PlayAction(HospitalScript::c_hho003cl_RunAnim); + m_currentAction = HospitalScript::c_hho003cl_RunAnim; + } + + m_unk0x108 = 1; + + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); +} + +// FUNCTION: LEGO1 0x10074dd0 +MxLong Hospital::HandleKeyPress(MxS8 p_key) +{ + MxLong result = 0; + + if (p_key == ' ' && g_unk0x100f7918 == 0) { + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); + result = 1; + } + + return result; +} + +// FUNCTION: LEGO1 0x10074e00 +MxLong Hospital::HandleEndAction(MxEndActionNotificationParam& p_param) +{ + MxLong result = 0; + MxDSAction* action = p_param.GetAction(); + Act1State* act1State; + + if (action->GetAtomId() != m_atom) { + return result; + } + + m_unk0x108 = 0; + + switch (m_hospitalState->m_unk0x08.m_unk0x00) { + case 5: + m_hospitalState->m_unk0x08.m_unk0x00 = 7; + PlayAction(HospitalScript::c_hho006cl_RunAnim); + + m_currentAction = HospitalScript::c_hho006cl_RunAnim; + m_unk0x108 = 1; + m_unk0x118 = 1; + g_unk0x100f7918 = 0; + break; + case 6: + m_time = Timer()->GetTime(); + m_unk0x100 = 1; + break; + case 7: + case 10: + m_hospitalState->m_unk0x08.m_unk0x00 = 8; + m_unk0x100 = 1; + m_time = Timer()->GetTime(); + break; + case 11: + switch (m_currentActorId) { + case 1: + switch (m_hospitalState->m_unk0x0e) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho017cl_RunAnim); + + m_currentAction = HospitalScript::c_hho017cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho018cl_RunAnim); + + m_currentAction = HospitalScript::c_hho018cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + case 2: + switch (m_hospitalState->m_unk0x10) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho019cl_RunAnim); + + m_currentAction = HospitalScript::c_hho019cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho020cl_RunAnim); + + m_currentAction = HospitalScript::c_hho020cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + case 3: + switch (m_hospitalState->m_unk0x12) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho023cl_RunAnim); + + m_currentAction = HospitalScript::c_hho023cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho024cl_RunAnim); + + m_currentAction = HospitalScript::c_hho024cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + case 4: + switch (m_hospitalState->m_unk0x14) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho021cl_RunAnim); + + m_currentAction = HospitalScript::c_hho021cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hhoa22cl_RunAnim); + + m_currentAction = HospitalScript::c_hhoa22cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + case 5: + switch (m_hospitalState->m_unk0x16) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho025cl_RunAnim); + + m_currentAction = HospitalScript::c_hho025cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho026cl_RunAnim); + + m_currentAction = HospitalScript::c_hho026cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + } + break; + case 12: + m_hospitalState->m_unk0x08.m_unk0x00 = 9; + act1State = (Act1State*) GameState()->GetState("Act1State"); + act1State->SetUnknown18(9); + case 14: + if (m_unk0x128 == 0) { + m_unk0x128 = 1; + m_destLocation = LegoGameState::e_unk31; + + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + break; + case 15: + if (m_unk0x128 == 0) { + m_unk0x128 = 1; + m_destLocation = LegoGameState::e_infomain; + + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + break; + } + + result = 1; + + return result; +} + +// FUNCTION: LEGO1 0x10075710 +MxLong Hospital::HandleButtonDown(LegoControlManagerEvent& p_param) +{ + if (m_unk0x100 == 1) { + LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY()); + if (roi != NULL) { + LegoChar* roiName = (LegoChar*) roi->GetName(); + + if (roiName[0] == '*') { + roiName += 1; + } + + if (!strcmpi("actor_ha", roiName)) { + LegoInputManager* inputManager = InputManager(); + inputManager->SetUnknown88(TRUE); + inputManager->SetUnknown336(FALSE); + + m_unk0x100 = 3; + + if (m_hospitalState->m_unk0x08.m_unk0x00 == 6) { + if (m_unk0x128 == 0) { + m_unk0x128 = 1; + + TickleManager()->UnregisterClient(this); + + m_hospitalState->m_unk0x08.m_unk0x00 = 9; + Act1State* act1State = (Act1State*) GameState()->GetState("Act1State"); + act1State->SetUnknown18(9); + + m_destLocation = LegoGameState::e_unk31; + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + } + else if (m_hospitalState->m_unk0x08.m_unk0x00 == 10 || m_hospitalState->m_unk0x08.m_unk0x00 == 8) { + if (m_hospitalState->m_unk0x08.m_unk0x00 == 10) { + m_hospitalState->m_unk0x08.m_unk0x00 = 11; + + BackgroundAudioManager()->RaiseVolume(); + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); + } + else { + switch (m_currentActorId) { + case 1: + switch (m_hospitalState->m_unk0x0e) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho017cl_RunAnim); + + m_currentAction = HospitalScript::c_hho017cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho018cl_RunAnim); + + m_currentAction = HospitalScript::c_hho018cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + case 2: + switch (m_hospitalState->m_unk0x10) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho019cl_RunAnim); + + m_currentAction = HospitalScript::c_hho019cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho020cl_RunAnim); + + m_currentAction = HospitalScript::c_hho020cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + case 3: + switch (m_hospitalState->m_unk0x12) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho023cl_RunAnim); + + m_currentAction = HospitalScript::c_hho023cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho024cl_RunAnim); + + m_currentAction = HospitalScript::c_hho024cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + case 4: + switch (m_hospitalState->m_unk0x14) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho021cl_RunAnim); + + m_currentAction = HospitalScript::c_hho021cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hhoa22cl_RunAnim); + + m_currentAction = HospitalScript::c_hhoa22cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + case 5: + switch (m_hospitalState->m_unk0x16) { + case 0: + case 1: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho025cl_RunAnim); + + m_currentAction = HospitalScript::c_hho025cl_RunAnim; + m_unk0x108 = 1; + break; + default: + m_hospitalState->m_unk0x08.m_unk0x00 = 12; + PlayAction(HospitalScript::c_hho026cl_RunAnim); + + m_currentAction = HospitalScript::c_hho026cl_RunAnim; + m_unk0x108 = 1; + break; + } + break; + } + } + } + + return 1; + } + else { + return 0; + } + } + } + else { + return 0; + } + + return 0; +} + +// FUNCTION: LEGO1 0x10075f90 +MxBool Hospital::HandleClick(LegoControlManagerEvent& p_param) +{ + if (p_param.GetUnknown0x28() == 1) { + switch (p_param.GetClickedObjectId()) { + case HospitalScript::c_Info_Ctl: + BackgroundAudioManager()->RaiseVolume(); + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); + + if (m_unk0x100 == 1) { + m_hospitalState->m_unk0x08.m_unk0x00 = 14; + + PlayAction(HospitalScript::c_hho016cl_RunAnim); + m_currentAction = HospitalScript::c_hho016cl_RunAnim; + m_unk0x108 = 1; + } + else if (m_unk0x128 == 0) { + m_unk0x128 = 1; + m_hospitalState->m_unk0x08.m_unk0x00 = 13; + m_destLocation = LegoGameState::e_infomain; + + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + + break; + + case HospitalScript::c_Door_Ctl: + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); + + if (m_unk0x100 == 1) { + m_hospitalState->m_unk0x08.m_unk0x00 = 15; + + PlayAction(HospitalScript::c_hho016cl_RunAnim); + m_currentAction = HospitalScript::c_hho016cl_RunAnim; + m_unk0x108 = 1; + } + else if (m_unk0x128 == 0) { + m_unk0x128 = 1; + m_hospitalState->m_unk0x08.m_unk0x00 = 13; + m_destLocation = LegoGameState::e_unk31; + + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + + break; + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x10076220 +void Hospital::Enable(MxBool p_enable) +{ + LegoWorld::Enable(p_enable); + + if (p_enable) { + InputManager()->SetWorld(this); + SetIsWorldActive(FALSE); + } + else { + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + } +} + +inline void Hospital::PlayAction(MxU32 p_objectId) +{ + MxDSAction action; + action.SetAtomId(*g_hospitalScript); + action.SetObjectId(p_objectId); + + BackgroundAudioManager()->LowerVolume(); + Start(&action); +} + +// FUNCTION: LEGO1 0x10076270 +MxResult Hospital::Tickle() +{ + if (!m_worldStarted) { + LegoWorld::Tickle(); + return SUCCESS; + } + + if (g_unk0x100f7918 != 0) { + g_unk0x100f7918 -= 1; + } + + MxLong time = Timer()->GetTime(); + + if (m_unk0x118 != 0) { + if (time - m_copLedAnimTimer > 300) { + m_copLedAnimTimer = time; + g_copLedEnabled = !g_copLedEnabled; + m_copLedBitmap->Enable(g_copLedEnabled); + } + + if (time - m_pizzaLedAnimTimer > 200) { + m_pizzaLedAnimTimer = time; + g_pizzaLedEnabled = !g_pizzaLedEnabled; + m_pizzaLedBitmap->Enable(g_pizzaLedEnabled); + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10076330 +MxBool Hospital::VTable0x64() +{ + DeleteObjects(&m_atom, HospitalScript::c_hho002cl_RunAnim, 999); + m_hospitalState->m_unk0x08.m_unk0x00 = 0; + + m_destLocation = LegoGameState::e_infomain; + + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp new file mode 100644 index 00000000..d5d68518 --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp @@ -0,0 +1,1465 @@ +#include "infocenter.h" + +#include "act3state.h" +#include "credits_actions.h" +#include "helicopterstate.h" +#include "infocenterstate.h" +#include "infomain_actions.h" +#include "jukebox.h" +#include "jukebox_actions.h" +#include "legoact2state.h" +#include "legoanimationmanager.h" +#include "legobuildingmanager.h" +#include "legocharactermanager.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "legoplantmanager.h" +#include "legoutils.h" +#include "legovideomanager.h" +#include "misc.h" +#include "mxactionnotificationparam.h" +#include "mxbackgroundaudiomanager.h" +#include "mxcontrolpresenter.h" +#include "mxdisplaysurface.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstillpresenter.h" +#include "mxticklemanager.h" +#include "mxtransitionmanager.h" +#include "mxutilities.h" +#include "radiostate.h" +#include "scripts.h" +#include "sndanim_actions.h" +#include "viewmanager/viewmanager.h" + +DECOMP_SIZE_ASSERT(Infocenter, 0x1d8) +DECOMP_SIZE_ASSERT(InfocenterMapEntry, 0x18) + +// GLOBAL: LEGO1 0x100f76a0 +const char* g_object2x4red = "2x4red"; + +// GLOBAL: LEGO1 0x100f76a4 +const char* g_object2x4grn = "2x4grn"; + +// FUNCTION: LEGO1 0x1006ea20 +Infocenter::Infocenter() +{ + m_selectedCharacter = e_noCharacter; + m_unk0x11c = NULL; + m_infocenterState = NULL; + m_frameHotBitmap = NULL; + m_destLocation = LegoGameState::e_undefined; + m_currentInfomainScript = InfomainScript::c_noneInfomain; + m_currentCutscene = e_noIntro; + + memset(&m_mapAreas, 0, sizeof(m_mapAreas)); + + m_unk0x1c8 = -1; + SetAppCursor(1); + NotificationManager()->Register(this); + + m_infoManDialogueTimer = 0; + m_bookAnimationTimer = 0; + m_unk0x1d4 = 0; + m_unk0x1d6 = 0; +} + +// FUNCTION: LEGO1 0x1006ec90 +Infocenter::~Infocenter() +{ + BackgroundAudioManager()->Stop(); + + MxS16 i = 0; + do { + if (m_infocenterState->GetNameLetter(i) != NULL) { + m_infocenterState->GetNameLetter(i)->Enable(FALSE); + } + i++; + } while (i < m_infocenterState->GetMaxNameLength()); + + ControlManager()->Unregister(this); + + InputManager()->UnRegister(this); + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + NotificationManager()->Unregister(this); + + TickleManager()->UnregisterClient(this); +} + +// FUNCTION: LEGO1 0x1006ed90 +MxResult Infocenter::Create(MxDSAction& p_dsAction) +{ + MxResult result = LegoWorld::Create(p_dsAction); + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + } + + m_infocenterState = (InfocenterState*) GameState()->GetState("InfocenterState"); + if (!m_infocenterState) { + m_infocenterState = (InfocenterState*) GameState()->CreateState("InfocenterState"); + m_infocenterState->SetUnknown0x74(3); + } + else { + if (m_infocenterState->GetUnknown0x74() != 8 && m_infocenterState->GetUnknown0x74() != 4 && + m_infocenterState->GetUnknown0x74() != 15) { + m_infocenterState->SetUnknown0x74(2); + } + + MxS16 count, i; + for (count = 0; count < m_infocenterState->GetMaxNameLength(); count++) { + if (m_infocenterState->GetNameLetter(count) == NULL) { + break; + } + } + + for (i = 0; i < count; i++) { + if (m_infocenterState->GetNameLetter(i)) { + m_infocenterState->GetNameLetter(i)->Enable(TRUE); + m_infocenterState->GetNameLetter(i)->SetTickleState(MxPresenter::e_repeating); + m_infocenterState->GetNameLetter(i)->SetPosition(((7 - count) / 2 + i) * 29 + 223, 45); + } + } + } + + GameState()->SetCurrentArea(LegoGameState::e_infomain); + GameState()->StopArea(LegoGameState::e_previousArea); + + if (m_infocenterState->GetUnknown0x74() == 4) { + LegoGameState* state = GameState(); + state->SetPreviousArea(GameState()->GetUnknown0x42c()); + } + + InputManager()->Register(this); + SetIsWorldActive(FALSE); + + return result; +} + +// FUNCTION: LEGO1 0x1006ef10 +MxLong Infocenter::Notify(MxParam& p_param) +{ + MxLong result = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationType0: + result = HandleNotification0((MxNotificationParam&) p_param); + break; + case c_notificationEndAction: + result = HandleEndAction((MxEndActionNotificationParam&) p_param); + break; + case c_notificationKeyPress: + result = HandleKeyPress(((LegoEventNotificationParam&) p_param).GetKey()); + break; + case c_notificationButtonUp: + result = HandleButtonUp( + ((LegoEventNotificationParam&) p_param).GetX(), + ((LegoEventNotificationParam&) p_param).GetY() + ); + break; + case c_notificationMouseMove: + result = HandleMouseMove( + ((LegoEventNotificationParam&) p_param).GetX(), + ((LegoEventNotificationParam&) p_param).GetY() + ); + break; + case c_notificationClick: + result = HandleClick((LegoControlManagerEvent&) p_param); + break; + case c_notificationTransitioned: + StopBookAnimation(); + m_bookAnimationTimer = 0; + + if (m_infocenterState->GetUnknown0x74() == 0x0c) { + StartCredits(); + m_infocenterState->SetUnknown0x74(0xd); + } + else if (m_destLocation != 0) { + BackgroundAudioManager()->RaiseVolume(); + GameState()->SwitchArea(m_destLocation); + m_destLocation = LegoGameState::e_undefined; + } + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1006f080 +MxLong Infocenter::HandleEndAction(MxEndActionNotificationParam& p_param) +{ + MxDSAction* action = p_param.GetAction(); + if (action->GetAtomId() == *g_creditsScript && action->GetObjectId() == CreditsScript::c_LegoCredits) { + Lego()->CloseMainWindow(); + return 1; + } + + if (action->GetAtomId() == m_atom && (action->GetObjectId() == InfomainScript::c_Mama_All_Movie || + action->GetObjectId() == InfomainScript::c_Papa_All_Movie || + action->GetObjectId() == InfomainScript::c_Pepper_All_Movie || + action->GetObjectId() == InfomainScript::c_Nick_All_Movie || + action->GetObjectId() == InfomainScript::c_Laura_All_Movie)) { + if (m_unk0x1d4) { + m_unk0x1d4--; + } + + if (!m_unk0x1d4) { + PlayMusic(JukeboxScript::c_InformationCenter_Music); + GameState()->SetActor(m_selectedCharacter); + + switch (m_selectedCharacter) { + case e_pepper: + PlayAction(InfomainScript::c_avo901in_RunAnim); + break; + case e_mama: + PlayAction(InfomainScript::c_avo902in_RunAnim); + break; + case e_papa: + PlayAction(InfomainScript::c_avo903in_RunAnim); + break; + case e_nick: + PlayAction(InfomainScript::c_avo904in_RunAnim); + break; + case e_laura: + PlayAction(InfomainScript::c_avo905in_RunAnim); + break; + default: + break; + } + + UpdateFrameHot(TRUE); + } + } + + MxLong result = m_radio.Notify(p_param); + + if (result || (action->GetAtomId() != m_atom && action->GetAtomId() != *g_introScript)) { + return result; + } + + if (action->GetObjectId() == InfomainScript::c_iicx26in_RunAnim) { + ControlManager()->FUN_100293c0(0x10, action->GetAtomId().GetInternal(), 0); + m_unk0x1d6 = 0; + } + + switch (m_infocenterState->GetUnknown0x74()) { + case 0: + switch (m_currentCutscene) { + case e_legoMovie: + PlayCutscene(e_mindscapeMovie, FALSE); + return 1; + case e_mindscapeMovie: + PlayCutscene(e_introMovie, TRUE); + return 1; + case e_badEndMovie: + StopCutscene(); + m_infocenterState->SetUnknown0x74(11); + PlayAction(InfomainScript::c_tic092in_RunAnim); + m_currentCutscene = e_noIntro; + return 1; + case e_goodEndMovie: + StopCutscene(); + m_infocenterState->SetUnknown0x74(11); + PlayAction(InfomainScript::c_tic089in_RunAnim); + m_currentCutscene = e_noIntro; + return 1; + } + + // default / 2nd case probably? + StopCutscene(); + m_infocenterState->SetUnknown0x74(11); + PlayAction(InfomainScript::c_iic001in_RunAnim); + m_currentCutscene = e_noIntro; + + if (!m_infocenterState->HasRegistered()) { + m_bookAnimationTimer = 1; + return 1; + } + break; + case 1: + m_infocenterState->SetUnknown0x74(11); + + switch (m_currentCutscene) { + case e_badEndMovie: + PlayAction(InfomainScript::c_tic092in_RunAnim); + break; + case e_goodEndMovie: + PlayAction(InfomainScript::c_tic089in_RunAnim); + break; + default: + PlayAction(InfomainScript::c_iic001in_RunAnim); + } + + m_currentCutscene = e_noIntro; + return 1; + case 2: + SetROIVisible(g_object2x4red, FALSE); + SetROIVisible(g_object2x4grn, FALSE); + BackgroundAudioManager()->RaiseVolume(); + return 1; + case 4: + if (action->GetObjectId() == InfomainScript::c_GoTo_RegBook || + action->GetObjectId() == InfomainScript::c_GoTo_RegBook_Red) { + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + m_infocenterState->SetUnknown0x74(14); + return 1; + } + break; + case 5: + if (action->GetObjectId() == m_currentInfomainScript) { + if (GameState()->GetCurrentAct() != LegoGameState::e_act3 && m_selectedCharacter != e_noCharacter) { + GameState()->SetActor(m_selectedCharacter); + } + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + m_infocenterState->SetUnknown0x74(14); + return 1; + } + break; + case 11: + if (!m_infocenterState->HasRegistered() && m_currentInfomainScript != InfomainScript::c_Mama_All_Movie && + m_currentInfomainScript != InfomainScript::c_Papa_All_Movie && + m_currentInfomainScript != InfomainScript::c_Pepper_All_Movie && + m_currentInfomainScript != InfomainScript::c_Nick_All_Movie && + m_currentInfomainScript != InfomainScript::c_Laura_All_Movie) { + m_infoManDialogueTimer = 1; + PlayMusic(JukeboxScript::c_InformationCenter_Music); + } + + m_infocenterState->SetUnknown0x74(2); + SetROIVisible("infoman", TRUE); + return 1; + case 12: + if (action->GetObjectId() == m_currentInfomainScript) { + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + } + + result = 1; + + return result; +} + +// FUNCTION: LEGO1 0x1006f4e0 +void Infocenter::ReadyWorld() +{ + m_infoManDialogueTimer = 0; + m_bookAnimationTimer = 0; + m_unk0x1d4 = 0; + m_unk0x1d6 = 0; + + MxStillPresenter* bg = (MxStillPresenter*) Find("MxStillPresenter", "Background_Bitmap"); + MxStillPresenter* bgRed = (MxStillPresenter*) Find("MxStillPresenter", "BackgroundRed_Bitmap"); + + switch (GameState()->GetCurrentAct()) { + case LegoGameState::e_act1: + bg->Enable(TRUE); + InitializeBitmaps(); + + switch (m_infocenterState->GetUnknown0x74()) { + case 3: + PlayCutscene(e_legoMovie, TRUE); + m_infocenterState->SetUnknown0x74(0); + break; + case 4: + m_infocenterState->SetUnknown0x74(2); + if (!m_infocenterState->HasRegistered()) { + m_bookAnimationTimer = 1; + } + + PlayAction(InfomainScript::c_iicx18in_RunAnim); + PlayMusic(JukeboxScript::c_InformationCenter_Music); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + case 5: + default: { + PlayMusic(JukeboxScript::c_InformationCenter_Music); + + InfomainScript::Script script = + (InfomainScript::Script) m_infocenterState->GetReturnDialogue(GameState()->GetCurrentAct()).Next(); + PlayAction(script); + + if (script == InfomainScript::c_iicx26in_RunAnim) { + m_unk0x1d6 = 1; + } + + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + + if (!m_infocenterState->HasRegistered()) { + m_bookAnimationTimer = 1; + } + + m_infocenterState->SetUnknown0x74(11); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + } + case 8: + PlayMusic(JukeboxScript::c_InformationCenter_Music); + PlayAction(InfomainScript::c_iic043in_RunAnim); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + case 0xf: + m_infocenterState->SetUnknown0x74(2); + if (!m_infocenterState->HasRegistered()) { + m_bookAnimationTimer = 1; + } + + PlayAction(InfomainScript::c_iicx17in_RunAnim); + PlayMusic(JukeboxScript::c_InformationCenter_Music); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + break; + } + return; + case LegoGameState::e_act2: { + if (m_infocenterState->GetUnknown0x74() == 8) { + PlayMusic(JukeboxScript::c_InformationCenter_Music); + bgRed->Enable(TRUE); + PlayAction(InfomainScript::c_iic043in_RunAnim); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + return; + } + + LegoAct2State* state = (LegoAct2State*) GameState()->GetState("LegoAct2State"); + GameState()->FindLoadedAct(); + + if (state && state->GetUnknown0x08() == 0x68) { + bg->Enable(TRUE); + PlayCutscene(e_badEndMovie, TRUE); + m_infocenterState->SetUnknown0x74(0); + return; + } + + if (m_infocenterState->GetUnknown0x74() == 4) { + bgRed->Enable(TRUE); + + if (GameState()->GetCurrentAct() == GameState()->GetLoadedAct()) { + GameState()->SetCurrentArea(LegoGameState::e_act2main); + GameState()->StopArea(LegoGameState::e_act2main); + GameState()->SetCurrentArea(LegoGameState::e_infomain); + } + + m_infocenterState->SetUnknown0x74(5); + m_destLocation = LegoGameState::e_act2main; + + InfomainScript::Script script = + (InfomainScript::Script) m_infocenterState->GetReturnDialogue(GameState()->GetCurrentAct()).Next(); + PlayAction(script); + + InputManager()->DisableInputProcessing(); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + return; + } + + PlayMusic(JukeboxScript::c_InformationCenter_Music); + InfomainScript::Script script = + (InfomainScript::Script) m_infocenterState->GetReturnDialogue(GameState()->GetCurrentAct()).Next(); + PlayAction(script); + bgRed->Enable(TRUE); + break; + } + case LegoGameState::e_act3: { + if (m_infocenterState->GetUnknown0x74() == 8) { + PlayMusic(JukeboxScript::c_InformationCenter_Music); + bgRed->Enable(TRUE); + PlayAction(InfomainScript::c_iic043in_RunAnim); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + return; + } + + Act3State* state = (Act3State*) GameState()->GetState("Act3State"); + GameState()->FindLoadedAct(); + + if (state) { + if (state->GetUnknown0x08() == 3) { + bg->Enable(TRUE); + PlayCutscene(e_badEndMovie, TRUE); + m_infocenterState->SetUnknown0x74(0); + return; + } + + if (state && state->GetUnknown0x08() == 2) { + bg->Enable(TRUE); + PlayCutscene(e_goodEndMovie, TRUE); + m_infocenterState->SetUnknown0x74(0); + return; + } + } + + if (m_infocenterState->GetUnknown0x74() == 4) { + bgRed->Enable(TRUE); + + if (GameState()->GetCurrentAct() == GameState()->GetLoadedAct()) { + GameState()->SetCurrentArea(LegoGameState::e_act3script); + GameState()->StopArea(LegoGameState::e_act3script); + GameState()->SetCurrentArea(LegoGameState::e_infomain); + } + + m_infocenterState->SetUnknown0x74(5); + m_destLocation = LegoGameState::e_act3script; + + InfomainScript::Script script = + (InfomainScript::Script) m_infocenterState->GetReturnDialogue(GameState()->GetCurrentAct()).Next(); + PlayAction(script); + + InputManager()->DisableInputProcessing(); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + return; + } + + PlayMusic(JukeboxScript::c_InformationCenter_Music); + InfomainScript::Script script = + (InfomainScript::Script) m_infocenterState->GetReturnDialogue(GameState()->GetCurrentAct()).Next(); + PlayAction(script); + bgRed->Enable(TRUE); + break; + } + } + + m_infocenterState->SetUnknown0x74(11); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); +} + +// FUNCTION: LEGO1 0x1006f9a0 +void Infocenter::InitializeBitmaps() +{ + m_radio.Initialize(TRUE); + + ((MxPresenter*) Find(m_atom, InfomainScript::c_LeftArrow_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_RightArrow_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Info_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Boat_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Race_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Pizza_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Gas_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Med_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Cop_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Mama_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Papa_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Pepper_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Nick_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Laura_Ctl))->Enable(TRUE); + ((MxPresenter*) Find(m_atom, InfomainScript::c_Radio_Ctl))->Enable(TRUE); + + m_mapAreas[0].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Info_A_Bitmap"); + m_mapAreas[0].m_area.SetLeft(391); + m_mapAreas[0].m_area.SetTop(182); + m_mapAreas[0].m_area.SetRight(427); + m_mapAreas[0].m_area.SetBottom(230); + m_mapAreas[0].m_unk0x04 = 3; + + m_mapAreas[1].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Boat_A_Bitmap"); + m_mapAreas[1].m_area.SetLeft(304); + m_mapAreas[1].m_area.SetTop(225); + m_mapAreas[1].m_area.SetRight(350); + m_mapAreas[1].m_area.SetBottom(268); + m_mapAreas[1].m_unk0x04 = 10; + + m_mapAreas[2].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Race_A_Bitmap"); + m_mapAreas[2].m_area.SetLeft(301); + m_mapAreas[2].m_area.SetTop(133); + m_mapAreas[2].m_area.SetRight(347); + m_mapAreas[2].m_area.SetBottom(181); + m_mapAreas[2].m_unk0x04 = 11; + + m_mapAreas[3].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Pizza_A_Bitmap"); + m_mapAreas[3].m_area.SetLeft(289); + m_mapAreas[3].m_area.SetTop(182); + m_mapAreas[3].m_area.SetRight(335); + m_mapAreas[3].m_area.SetBottom(225); + m_mapAreas[3].m_unk0x04 = 12; + + m_mapAreas[4].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Gas_A_Bitmap"); + m_mapAreas[4].m_area.SetLeft(350); + m_mapAreas[4].m_area.SetTop(161); + m_mapAreas[4].m_area.SetRight(391); + m_mapAreas[4].m_area.SetBottom(209); + m_mapAreas[4].m_unk0x04 = 13; + + m_mapAreas[5].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Med_A_Bitmap"); + m_mapAreas[5].m_area.SetLeft(392); + m_mapAreas[5].m_area.SetTop(130); + m_mapAreas[5].m_area.SetRight(438); + m_mapAreas[5].m_area.SetBottom(176); + m_mapAreas[5].m_unk0x04 = 14; + + m_mapAreas[6].m_presenter = (MxStillPresenter*) Find("MxStillPresenter", "Cop_A_Bitmap"); + m_mapAreas[6].m_area.SetLeft(396); + m_mapAreas[6].m_area.SetTop(229); + m_mapAreas[6].m_area.SetRight(442); + m_mapAreas[6].m_area.SetBottom(272); + m_mapAreas[6].m_unk0x04 = 15; + + m_frameHotBitmap = (MxStillPresenter*) Find("MxStillPresenter", "FrameHot_Bitmap"); + + UpdateFrameHot(TRUE); +} + +// FUNCTION: LEGO1 0x1006fd00 +MxU8 Infocenter::HandleMouseMove(MxS32 p_x, MxS32 p_y) +{ + if (m_unk0x11c) { + if (!m_unk0x11c->IsEnabled()) { + MxS32 oldDisplayZ = m_unk0x11c->GetDisplayZ(); + + m_unk0x11c->SetDisplayZ(1000); + VideoManager()->SortPresenterList(); + m_unk0x11c->Enable(TRUE); + m_unk0x11c->SetPosition(p_x, p_y); + + m_unk0x11c->SetDisplayZ(oldDisplayZ); + } + else { + m_unk0x11c->SetPosition(p_x, p_y); + } + + FUN_10070d10(p_x, p_y); + return 1; + } + + return 0; +} + +// FUNCTION: LEGO1 0x1006fda0 +MxLong Infocenter::HandleKeyPress(MxS8 p_key) +{ + MxLong result = 0; + + if (p_key == ' ' && m_worldStarted) { + switch (m_infocenterState->GetUnknown0x74()) { + case 0: + StopCutscene(); + m_infocenterState->SetUnknown0x74(1); + + if (!m_infocenterState->HasRegistered()) { + m_bookAnimationTimer = 1; + return 1; + } + break; + case 1: + case 4: + break; + default: { + InfomainScript::Script script = m_currentInfomainScript; + StopCurrentAction(); + + switch (m_infocenterState->GetUnknown0x74()) { + case 5: + case 12: + m_currentInfomainScript = script; + return 1; + default: + m_infocenterState->SetUnknown0x74(2); + return 1; + case 8: + case 11: + break; + } + } + case 13: + StopCredits(); + break; + } + + result = 1; + } + + return result; +} + +// FUNCTION: LEGO1 0x1006feb0 +MxU8 Infocenter::HandleButtonUp(MxS32 p_x, MxS32 p_y) +{ + if (m_unk0x11c) { + MxControlPresenter* control = InputManager()->GetControlManager()->FUN_100294e0(p_x - 1, p_y - 1); + + switch (m_unk0x11c->GetAction()->GetObjectId()) { + case InfomainScript::c_PepperHot_Bitmap: + m_selectedCharacter = e_pepper; + break; + case InfomainScript::c_MamaHot_Bitmap: + m_selectedCharacter = e_mama; + break; + case InfomainScript::c_PapaHot_Bitmap: + m_selectedCharacter = e_papa; + break; + case InfomainScript::c_NickHot_Bitmap: + m_selectedCharacter = e_nick; + break; + case InfomainScript::c_LauraHot_Bitmap: + m_selectedCharacter = e_laura; + break; + } + + if (control != NULL) { + m_infoManDialogueTimer = 0; + + switch (control->GetAction()->GetObjectId()) { + case InfomainScript::c_Pepper_Ctl: + if (m_selectedCharacter == e_pepper) { + m_radio.Stop(); + BackgroundAudioManager()->Stop(); + PlayAction(InfomainScript::c_Pepper_All_Movie); + m_unk0x1d4++; + } + break; + case InfomainScript::c_Mama_Ctl: + if (m_selectedCharacter == e_mama) { + m_radio.Stop(); + BackgroundAudioManager()->Stop(); + PlayAction(InfomainScript::c_Mama_All_Movie); + m_unk0x1d4++; + } + break; + case InfomainScript::c_Papa_Ctl: + if (m_selectedCharacter == e_papa) { + m_radio.Stop(); + BackgroundAudioManager()->Stop(); + PlayAction(InfomainScript::c_Papa_All_Movie); + m_unk0x1d4++; + } + break; + case InfomainScript::c_Nick_Ctl: + if (m_selectedCharacter == e_nick) { + m_radio.Stop(); + BackgroundAudioManager()->Stop(); + PlayAction(InfomainScript::c_Nick_All_Movie); + m_unk0x1d4++; + } + break; + case InfomainScript::c_Laura_Ctl: + if (m_selectedCharacter == e_laura) { + m_radio.Stop(); + BackgroundAudioManager()->Stop(); + PlayAction(InfomainScript::c_Laura_All_Movie); + m_unk0x1d4++; + } + break; + } + } + else { + if (m_unk0x1c8 != -1) { + m_infoManDialogueTimer = 0; + + switch (m_mapAreas[m_unk0x1c8].m_unk0x04) { + case 3: + GameState()->SetActor(m_selectedCharacter); + + switch (m_selectedCharacter) { + case e_pepper: + PlayAction(InfomainScript::c_avo901in_RunAnim); + break; + case e_mama: + PlayAction(InfomainScript::c_avo902in_RunAnim); + break; + case e_papa: + PlayAction(InfomainScript::c_avo903in_RunAnim); + break; + case e_nick: + PlayAction(InfomainScript::c_avo904in_RunAnim); + break; + case e_laura: + PlayAction(InfomainScript::c_avo905in_RunAnim); + break; + } + break; + case 10: + if (m_selectedCharacter) { + m_destLocation = LegoGameState::e_jetraceExterior; + m_infocenterState->SetUnknown0x74(5); + } + break; + case 11: + if (m_selectedCharacter) { + m_destLocation = LegoGameState::e_carraceExterior; + m_infocenterState->SetUnknown0x74(5); + } + break; + case 12: + if (m_selectedCharacter) { + m_destLocation = LegoGameState::e_pizzeriaExterior; + m_infocenterState->SetUnknown0x74(5); + } + break; + case 13: + if (m_selectedCharacter) { + m_destLocation = LegoGameState::e_garageExterior; + m_infocenterState->SetUnknown0x74(5); + } + break; + case 14: + if (m_selectedCharacter) { + m_destLocation = LegoGameState::e_hospitalExterior; + m_infocenterState->SetUnknown0x74(5); + } + break; + case 15: + if (m_selectedCharacter) { + m_destLocation = LegoGameState::e_policeExterior; + m_infocenterState->SetUnknown0x74(5); + } + break; + } + } + } + + m_unk0x11c->Enable(FALSE); + m_unk0x11c = NULL; + + if (m_infocenterState->GetUnknown0x74() == 5) { + InfomainScript::Script dialogueToPlay; + + if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { + if (!m_infocenterState->HasRegistered()) { + m_infocenterState->SetUnknown0x74(2); + m_destLocation = LegoGameState::e_undefined; + dialogueToPlay = InfomainScript::c_iic007in_PlayWav; + } + else { + switch (m_selectedCharacter) { + case e_pepper: + dialogueToPlay = InfomainScript::c_avo901in_RunAnim; + GameState()->SetActorId(m_selectedCharacter); + break; + case e_mama: + dialogueToPlay = InfomainScript::c_avo902in_RunAnim; + GameState()->SetActorId(m_selectedCharacter); + break; + case e_papa: + dialogueToPlay = InfomainScript::c_avo903in_RunAnim; + GameState()->SetActorId(m_selectedCharacter); + break; + case e_nick: + dialogueToPlay = InfomainScript::c_avo904in_RunAnim; + GameState()->SetActorId(m_selectedCharacter); + break; + case e_laura: + dialogueToPlay = InfomainScript::c_avo905in_RunAnim; + GameState()->SetActorId(m_selectedCharacter); + break; + default: + dialogueToPlay = + (InfomainScript::Script) m_infocenterState->GetLeaveDialogue(GameState()->GetCurrentAct()) + .Next(); + break; + } + + InputManager()->DisableInputProcessing(); + InputManager()->SetUnknown336(TRUE); + } + } + else { + dialogueToPlay = + (InfomainScript::Script) m_infocenterState->GetLeaveDialogue(GameState()->GetCurrentAct()).Next(); + } + + PlayAction(dialogueToPlay); + } + + UpdateFrameHot(TRUE); + FUN_10070d10(0, 0); + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10070370 +MxU8 Infocenter::HandleClick(LegoControlManagerEvent& p_param) +{ + if (p_param.GetUnknown0x28() == 1) { + m_infoManDialogueTimer = 0; + + InfomainScript::Script actionToPlay = InfomainScript::c_noneInfomain; + StopCurrentAction(); + InfomainScript::Script characterBitmap = InfomainScript::c_noneInfomain; + + LegoGameState* state = GameState(); + + switch (p_param.GetClickedObjectId()) { + case InfomainScript::c_LeftArrow_Ctl: + m_infocenterState->SetUnknown0x74(14); + StopCurrentAction(); + + if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { + m_radio.Stop(); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + m_destLocation = LegoGameState::e_elevbott; + } + else { + MxU32 objectId = m_infocenterState->GetBricksterDialogue().Next(); + PlayAction((InfomainScript::Script) objectId); + } + + break; + case InfomainScript::c_RightArrow_Ctl: + m_infocenterState->SetUnknown0x74(14); + StopCurrentAction(); + + if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { + m_radio.Stop(); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + m_destLocation = LegoGameState::e_infoscor; + } + else { + MxU32 objectId = m_infocenterState->GetBricksterDialogue().Next(); + PlayAction((InfomainScript::Script) objectId); + } + + break; + case InfomainScript::c_Info_Ctl: + actionToPlay = InfomainScript::c_iic007ra_PlayWav; + m_radio.Stop(); + break; + case InfomainScript::c_Door_Ctl: + if (m_infocenterState->GetUnknown0x74() != 8) { + actionToPlay = InfomainScript::c_iic043in_RunAnim; + m_radio.Stop(); + m_infocenterState->SetUnknown0x74(8); + } + + break; + case InfomainScript::c_Boat_Ctl: + actionToPlay = InfomainScript::c_ijs002ra_PlayWav; + m_radio.Stop(); + break; + case InfomainScript::c_Race_Ctl: + actionToPlay = InfomainScript::c_irt001ra_PlayWav; + m_radio.Stop(); + break; + case InfomainScript::c_Pizza_Ctl: + actionToPlay = InfomainScript::c_ipz006ra_PlayWav; + m_radio.Stop(); + break; + case InfomainScript::c_Gas_Ctl: + actionToPlay = InfomainScript::c_igs004ra_PlayWav; + m_radio.Stop(); + break; + case InfomainScript::c_Med_Ctl: + actionToPlay = InfomainScript::c_iho003ra_PlayWav; + m_radio.Stop(); + break; + case InfomainScript::c_Cop_Ctl: + actionToPlay = InfomainScript::c_ips005ra_PlayWav; + m_radio.Stop(); + break; + case InfomainScript::c_BigInfo_Ctl: + switch (state->GetCurrentAct()) { + case LegoGameState::e_act1: + switch (state->GetPreviousArea()) { + case LegoGameState::e_infodoor: + case LegoGameState::e_regbook: + case LegoGameState::e_infoscor: + m_infocenterState->SetUnknown0x74(5); + m_destLocation = state->GetPreviousArea(); + actionToPlay = + (InfomainScript::Script) m_infocenterState->GetLeaveDialogue(GameState()->GetCurrentAct()) + .Next(); + m_radio.Stop(); + InputManager()->DisableInputProcessing(); + InputManager()->SetUnknown336(TRUE); + break; + case LegoGameState::e_unk4: + if (state->GetActorId()) { + if (m_infocenterState->HasRegistered()) { + m_infocenterState->SetUnknown0x74(5); + m_destLocation = state->GetPreviousArea(); + actionToPlay = (InfomainScript::Script) m_infocenterState + ->GetLeaveDialogue(GameState()->GetCurrentAct()) + .Next(); + m_radio.Stop(); + InputManager()->DisableInputProcessing(); + InputManager()->SetUnknown336(TRUE); + } + else { + PlayAction(InfomainScript::c_iic007in_PlayWav); + m_infocenterState->SetUnknown0x74(2); + } + } + break; + } + break; + case LegoGameState::e_act2: + m_infocenterState->SetUnknown0x74(5); + m_destLocation = LegoGameState::e_act2main; + actionToPlay = + (InfomainScript::Script) m_infocenterState->GetLeaveDialogue(GameState()->GetCurrentAct()).Next(); + InputManager()->DisableInputProcessing(); + InputManager()->SetUnknown336(TRUE); + break; + case LegoGameState::e_act3: + m_infocenterState->SetUnknown0x74(5); + m_destLocation = LegoGameState::e_act3script; + actionToPlay = + (InfomainScript::Script) m_infocenterState->GetLeaveDialogue(GameState()->GetCurrentAct()).Next(); + InputManager()->DisableInputProcessing(); + InputManager()->SetUnknown336(TRUE); + break; + } + break; + case InfomainScript::c_Book_Ctl: + m_destLocation = LegoGameState::e_regbook; + m_infocenterState->SetUnknown0x74(4); + actionToPlay = GameState()->GetCurrentAct() != LegoGameState::e_act1 ? InfomainScript::c_GoTo_RegBook_Red + : InfomainScript::c_GoTo_RegBook; + m_radio.Stop(); + GameState()->SetUnknown0x42c(GameState()->GetPreviousArea()); + InputManager()->DisableInputProcessing(); + break; + case InfomainScript::c_Mama_Ctl: + characterBitmap = InfomainScript::c_MamaHot_Bitmap; + UpdateFrameHot(FALSE); + break; + case InfomainScript::c_Papa_Ctl: + characterBitmap = InfomainScript::c_PapaHot_Bitmap; + UpdateFrameHot(FALSE); + break; + case InfomainScript::c_Pepper_Ctl: + characterBitmap = InfomainScript::c_PepperHot_Bitmap; + UpdateFrameHot(FALSE); + break; + case InfomainScript::c_Nick_Ctl: + characterBitmap = InfomainScript::c_NickHot_Bitmap; + UpdateFrameHot(FALSE); + break; + case InfomainScript::c_Laura_Ctl: + characterBitmap = InfomainScript::c_LauraHot_Bitmap; + UpdateFrameHot(FALSE); + break; + } + + if (actionToPlay != InfomainScript::c_noneInfomain) { + PlayAction(actionToPlay); + } + + if (characterBitmap != InfomainScript::c_noneInfomain) { + m_unk0x11c = (MxStillPresenter*) Find(m_atom, characterBitmap); + } + } + + return 1; +} + +// FUNCTION: LEGO1 0x10070870 +MxLong Infocenter::HandleNotification0(MxNotificationParam& p_param) +{ + // MxLong result + MxCore* sender = p_param.GetSender(); + + if (sender == NULL) { + if (m_infocenterState->GetUnknown0x74() == 8) { + m_infoManDialogueTimer = 0; + StopCutscene(); + PlayAction(InfomainScript::c_iic043in_RunAnim); + } + } + else if (sender->IsA("MxEntity") && m_infocenterState->GetUnknown0x74() != 5 && m_infocenterState->GetUnknown0x74() != 12) { + switch (((MxEntity*) sender)->GetEntityId()) { + case 5: { + m_infoManDialogueTimer = 0; + + InfomainScript::Script objectId; + if (GameState()->GetCurrentAct() != LegoGameState::e_act1) { + objectId = (InfomainScript::Script) m_infocenterState->GetExitDialogueAct23().Next(); + } + else { + objectId = (InfomainScript::Script) m_infocenterState->GetExitDialogueAct1().Next(); + } + + PlayAction(objectId); + SetROIVisible(g_object2x4red, FALSE); + SetROIVisible(g_object2x4grn, FALSE); + return 1; + } + case 6: + if (m_infocenterState->GetUnknown0x74() == 8) { + StopCurrentAction(); + SetROIVisible(g_object2x4red, FALSE); + SetROIVisible(g_object2x4grn, FALSE); + m_infocenterState->SetUnknown0x74(2); + PlayAction(InfomainScript::c_iicb28in_RunAnim); + return 1; + } + case 7: + if (m_infocenterState->GetUnknown0x74() == 8) { + if (m_infocenterState->HasRegistered()) { + GameState()->Save(0); + } + + m_infocenterState->SetUnknown0x74(12); + PlayAction(InfomainScript::c_iic046in_RunAnim); + InputManager()->DisableInputProcessing(); + InputManager()->SetUnknown336(TRUE); + return 1; + } + } + } + else { + if (sender->IsA("Radio") && m_radio.GetState()->IsActive()) { + if (m_currentInfomainScript == InfomainScript::c_Mama_All_Movie || + m_currentInfomainScript == InfomainScript::c_Papa_All_Movie || + m_currentInfomainScript == InfomainScript::c_Pepper_All_Movie || + m_currentInfomainScript == InfomainScript::c_Nick_All_Movie || + m_currentInfomainScript == InfomainScript::c_Laura_All_Movie || + m_currentInfomainScript == InfomainScript::c_iic007ra_PlayWav || + m_currentInfomainScript == InfomainScript::c_ijs002ra_PlayWav || + m_currentInfomainScript == InfomainScript::c_irt001ra_PlayWav || + m_currentInfomainScript == InfomainScript::c_ipz006ra_PlayWav || + m_currentInfomainScript == InfomainScript::c_igs004ra_PlayWav || + m_currentInfomainScript == InfomainScript::c_iho003ra_PlayWav || + m_currentInfomainScript == InfomainScript::c_ips005ra_PlayWav) { + StopCurrentAction(); + } + } + } + + return 1; +} + +// FUNCTION: LEGO1 0x10070aa0 +void Infocenter::Enable(MxBool p_enable) +{ + LegoWorld::Enable(p_enable); + + if (p_enable) { + InputManager()->SetWorld(this); + SetIsWorldActive(FALSE); + } + else { + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + } +} + +// FUNCTION: LEGO1 0x10070af0 +MxResult Infocenter::Tickle() +{ + if (m_worldStarted == FALSE) { + LegoWorld::Tickle(); + return SUCCESS; + } + + if (m_infoManDialogueTimer != 0 && (m_infoManDialogueTimer += 100) > 25000) { + PlayAction(InfomainScript::c_iicx17in_RunAnim); + m_infoManDialogueTimer = 0; + } + + if (m_bookAnimationTimer != 0 && (m_bookAnimationTimer += 100) > 3000) { + PlayBookAnimation(); + m_bookAnimationTimer = 1; + } + + if (m_unk0x1d6 != 0) { + m_unk0x1d6 += 100; + + if (m_unk0x1d6 > 3400 && m_unk0x1d6 < 3650) { + ControlManager()->FUN_100293c0(0x10, m_atom.GetInternal(), 1); + } + else if (m_unk0x1d6 > 3650 && m_unk0x1d6 < 3900) { + ControlManager()->FUN_100293c0(0x10, m_atom.GetInternal(), 0); + } + else if (m_unk0x1d6 > 3900 && m_unk0x1d6 < 4150) { + ControlManager()->FUN_100293c0(0x10, m_atom.GetInternal(), 1); + } + else if (m_unk0x1d6 > 4400) { + ControlManager()->FUN_100293c0(0x10, m_atom.GetInternal(), 0); + m_unk0x1d6 = 0; + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10070c20 +void Infocenter::PlayCutscene(Cutscene p_entityId, MxBool p_scale) +{ + m_currentCutscene = p_entityId; + + VideoManager()->EnableFullScreenMovie(TRUE, p_scale); + InputManager()->SetUnknown336(TRUE); + InputManager()->SetUnknown335(TRUE); + SetAppCursor(0xb); // Hide cursor + VideoManager()->GetDisplaySurface()->ClearScreen(); + + if (m_currentCutscene != e_noIntro) { + // check if the cutscene is an ending + if (m_currentCutscene >= e_badEndMovie && m_currentCutscene <= e_goodEndMovie) { + Reset(); + } + + InvokeAction(Extra::ActionType::e_opendisk, *g_introScript, m_currentCutscene, NULL); + } +} + +// FUNCTION: LEGO1 0x10070cb0 +void Infocenter::StopCutscene() +{ + if (m_currentCutscene != e_noIntro) { + InvokeAction(Extra::ActionType::e_close, *g_introScript, m_currentCutscene, NULL); + } + + VideoManager()->EnableFullScreenMovie(FALSE); + InputManager()->SetUnknown335(FALSE); + SetAppCursor(0); // Restore cursor to arrow + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); +} + +// FUNCTION: LEGO1 0x10070d00 +MxBool Infocenter::VTable0x5c() +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x10070d10 +void Infocenter::FUN_10070d10(MxS32 p_x, MxS32 p_y) +{ + MxS16 i; + for (i = 0; i < (MxS32) (sizeof(m_mapAreas) / sizeof(m_mapAreas[0])); i++) { + MxS32 right = m_mapAreas[i].m_area.GetRight(); + MxS32 bottom = m_mapAreas[i].m_area.GetBottom(); + MxS32 left = m_mapAreas[i].m_area.GetLeft(); + MxS32 top = m_mapAreas[i].m_area.GetTop(); + + if (left <= p_x && p_x <= right && top <= p_y && p_y <= bottom) { + break; + } + } + + if (i == 7) { + i = -1; + } + + if (i != m_unk0x1c8) { + if (m_unk0x1c8 != -1) { + m_mapAreas[m_unk0x1c8].m_presenter->Enable(FALSE); + } + + m_unk0x1c8 = i; + if (i != -1) { + m_mapAreas[i].m_presenter->Enable(TRUE); + } + } +} + +// FUNCTION: LEGO1 0x10070dc0 +void Infocenter::UpdateFrameHot(MxBool p_display) +{ + if (p_display) { + MxS32 x, y; + + switch (GameState()->GetActorId()) { + case 1: + x = 302; + y = 81; + break; + case 2: + x = 204; + y = 81; + break; + case 3: + x = 253; + y = 81; + break; + case 4: + x = 353; + y = 81; + break; + case 5: + x = 399; + y = 81; + break; + default: + return; + } + + MxS32 originalDisplayZ = m_frameHotBitmap->GetDisplayZ(); + + m_frameHotBitmap->SetDisplayZ(1000); + VideoManager()->SortPresenterList(); + + m_frameHotBitmap->Enable(TRUE); + m_frameHotBitmap->SetPosition(x, y); + m_frameHotBitmap->SetDisplayZ(originalDisplayZ); + } + else { + if (m_frameHotBitmap) { + m_frameHotBitmap->Enable(FALSE); + } + } +} + +// FUNCTION: LEGO1 0x10070e90 +void Infocenter::Reset() +{ + switch (GameState()->GetCurrentAct()) { + case LegoGameState::e_act2: + Lego()->RemoveWorld(*g_act2mainScript, 0); + break; + case LegoGameState::e_act3: + Lego()->RemoveWorld(*g_act3Script, 0); + break; + } + + PlantManager()->FUN_10027120(); + BuildingManager()->FUN_10030590(); + AnimationManager()->Reset(FALSE); + CharacterManager()->FUN_100832a0(); + GameState()->SetCurrentAct(LegoGameState::e_act1); + GameState()->SetPreviousArea(LegoGameState::e_undefined); + GameState()->SetUnknown0x42c(LegoGameState::e_undefined); + + InitializeBitmaps(); + m_selectedCharacter = e_pepper; + + GameState()->SetActor(e_pepper); + + HelicopterState* state = (HelicopterState*) GameState()->GetState("HelicopterState"); + + if (state) { + state->SetFlag(); + } +} + +// FUNCTION: LEGO1 0x10070f60 +MxBool Infocenter::VTable0x64() +{ + if (m_infocenterState != NULL) { + MxU32 val = m_infocenterState->GetUnknown0x74(); + + if (val == 0) { + StopCutscene(); + m_infocenterState->SetUnknown0x74(1); + } + else if (val == 13) { + StopCredits(); + } + else if (val != 8) { + m_infocenterState->SetUnknown0x74(8); + +#ifdef COMPAT_MODE + { + MxNotificationParam param(c_notificationType0, NULL); + Notify(param); + } +#else + Notify(MxNotificationParam(c_notificationType0, NULL)); +#endif + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x10071030 +void Infocenter::StartCredits() +{ + MxPresenter* presenter; + + while (!m_set0xa8.empty()) { + MxCoreSet::iterator it = m_set0xa8.begin(); + MxCore* object = *it; + m_set0xa8.erase(it); + + if (object->IsA("MxPresenter")) { + presenter = (MxPresenter*) object; + MxDSAction* action = presenter->GetAction(); + + if (action) { + FUN_100b7220(action, MxDSAction::c_world, FALSE); + presenter->EndAction(); + } + } + else { + delete object; + } + } + + MxPresenterListCursor cursor(&m_controlPresenters); + + while (cursor.First(presenter)) { + cursor.Detach(); + + MxDSAction* action = presenter->GetAction(); + if (action) { + FUN_100b7220(action, MxDSAction::c_world, FALSE); + presenter->EndAction(); + } + } + + BackgroundAudioManager()->Stop(); + + MxS16 i = 0; + do { + if (m_infocenterState->GetNameLetter(i) != NULL) { + m_infocenterState->GetNameLetter(i)->Enable(FALSE); + } + i++; + } while (i < m_infocenterState->GetMaxNameLength()); + + VideoManager()->FUN_1007c520(); + GetViewManager()->RemoveAll(NULL); + + InvokeAction(Extra::e_opendisk, *g_creditsScript, CreditsScript::c_LegoCredits, NULL); + SetAppCursor(0); +} + +// FUNCTION: LEGO1 0x10071250 +void Infocenter::StopCredits() +{ + MxDSAction action; + action.SetObjectId(CreditsScript::c_LegoCredits); + action.SetAtomId(*g_creditsScript); + action.SetUnknown24(-2); + DeleteObject(action); +} + +// FUNCTION: LEGO1 0x10071300 +void Infocenter::PlayAction(InfomainScript::Script p_script) +{ + MxDSAction action; + action.SetObjectId(p_script); + action.SetAtomId(*g_infomainScript); + StopCurrentAction(); + + m_currentInfomainScript = p_script; + BackgroundAudioManager()->LowerVolume(); + Start(&action); +} + +// FUNCTION: LEGO1 0x100713d0 +void Infocenter::StopCurrentAction() +{ + if (m_currentInfomainScript != InfomainScript::c_noneInfomain) { + MxDSAction action; + action.SetObjectId(m_currentInfomainScript); + action.SetAtomId(*g_infomainScript); + action.SetUnknown24(-2); + DeleteObject(action); + m_currentInfomainScript = InfomainScript::c_noneInfomain; + } +} + +// FUNCTION: LEGO1 0x100714a0 +void Infocenter::PlayBookAnimation() +{ + MxDSAction action; + action.SetObjectId(SndanimScript::c_BookWig_Flic); + action.SetAtomId(*g_sndAnimScript); + Start(&action); +} + +// FUNCTION: LEGO1 0x10071550 +void Infocenter::StopBookAnimation() +{ + MxDSAction action; + action.SetObjectId(SndanimScript::c_BookWig_Flic); + action.SetAtomId(*g_sndAnimScript); + action.SetUnknown24(-2); + DeleteObject(action); +} diff --git a/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp b/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp new file mode 100644 index 00000000..bc961368 --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/infocenterdoor.cpp @@ -0,0 +1,173 @@ +#include "infocenterdoor.h" + +#include "infocenterstate.h" +#include "infodoor_actions.h" +#include "jukebox.h" +#include "jukebox_actions.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "misc.h" +#include "mxactionnotificationparam.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxtransitionmanager.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(InfocenterDoor, 0xfc) + +// FUNCTION: LEGO1 0x10037730 +InfocenterDoor::InfocenterDoor() +{ + m_destLocation = LegoGameState::e_undefined; + + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x100378f0 +InfocenterDoor::~InfocenterDoor() +{ + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + ControlManager()->Unregister(this); + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x10037980 +MxResult InfocenterDoor::Create(MxDSAction& p_dsAction) +{ + MxResult result = LegoWorld::Create(p_dsAction); + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + } + + SetIsWorldActive(FALSE); + + GameState()->SetCurrentArea(LegoGameState::e_infodoor); + GameState()->StopArea(LegoGameState::e_previousArea); + + return result; +} + +// FUNCTION: LEGO1 0x100379e0 +MxLong InfocenterDoor::Notify(MxParam& p_param) +{ + MxLong result = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetType()) { + case c_notificationEndAction: + if (((MxEndActionNotificationParam&) p_param).GetAction()->GetAtomId() == m_atom) { + BackgroundAudioManager()->RaiseVolume(); + result = 1; + } + break; + case c_notificationClick: + result = HandleClick((LegoControlManagerEvent&) p_param); + break; + case c_notificationTransitioned: + GameState()->SwitchArea(m_destLocation); + result = 1; + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x10037a70 +void InfocenterDoor::ReadyWorld() +{ + LegoWorld::ReadyWorld(); + PlayMusic(JukeboxScript::c_InformationCenter_Music); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); +} + +// FUNCTION: LEGO1 0x10037a90 +MxLong InfocenterDoor::HandleClick(LegoControlManagerEvent& p_param) +{ + MxLong result = 0; + + if (p_param.GetUnknown0x28() == 1) { + DeleteObjects(&m_atom, 500, 510); + + switch (p_param.GetClickedObjectId()) { + case InfodoorScript::c_LeftArrow_Ctl: + m_destLocation = LegoGameState::e_infoscor; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + result = 1; + break; + case InfodoorScript::c_RightArrow_Ctl: + m_destLocation = LegoGameState::e_elevbott; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + result = 1; + break; + case InfodoorScript::c_Info_Ctl: + m_destLocation = LegoGameState::e_infomain; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + result = 1; + break; + case InfodoorScript::c_Door_Ctl: + if (GameState()->GetActorId()) { + InfocenterState* state = (InfocenterState*) GameState()->GetState("InfocenterState"); + if (state->HasRegistered()) { + m_destLocation = LegoGameState::e_unk4; + } + else { + MxDSAction action; + action.SetObjectId(503); + action.SetAtomId(*g_infodoorScript); + BackgroundAudioManager()->LowerVolume(); + Start(&action); + goto done; + } + } + else { + MxDSAction action; + action.SetObjectId(500); + action.SetAtomId(*g_infodoorScript); + BackgroundAudioManager()->LowerVolume(); + Start(&action); + goto done; + } + + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + + done: + result = 1; + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x10037c80 +void InfocenterDoor::Enable(MxBool p_enable) +{ + LegoWorld::Enable(p_enable); + + if (p_enable) { + InputManager()->SetWorld(this); + SetIsWorldActive(FALSE); + } + else { + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + } +} + +// FUNCTION: LEGO1 0x10037cd0 +MxBool InfocenterDoor::VTable0x64() +{ + DeleteObjects(&m_atom, 500, 510); + m_destLocation = LegoGameState::e_infomain; + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp new file mode 100644 index 00000000..21d95cac --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -0,0 +1,1103 @@ +#include "isle.h" + +#include "3dmanager/lego3dmanager.h" +#include "act1state.h" +#include "ambulance.h" +#include "bike.h" +#include "carracestate.h" +#include "dunebuggy.h" +#include "helicopter.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "jetski.h" +#include "jetskiracestate.h" +#include "jukebox_actions.h" +#include "jukeboxentity.h" +#include "legoanimationmanager.h" +#include "legobackgroundcolor.h" +#include "legocontrolmanager.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "legoutils.h" +#include "legovariables.h" +#include "legovideomanager.h" +#include "misc.h" +#include "motocycle.h" +#include "mxactionnotificationparam.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstillpresenter.h" +#include "mxtransitionmanager.h" +#include "mxvariabletable.h" +#include "pizza.h" +#include "scripts.h" +#include "skateboard.h" +#include "towtrack.h" + +DECOMP_SIZE_ASSERT(Isle, 0x140) + +// GLOBAL: LEGO1 0x100f1198 +undefined4 g_unk0x100f1198 = 0x7f; + +// FUNCTION: LEGO1 0x10030820 +Isle::Isle() +{ + m_pizza = NULL; + m_pizzeria = NULL; + m_towtrack = NULL; + m_ambulance = NULL; + m_jukebox = NULL; + m_helicopter = NULL; + m_bike = NULL; + m_dunebuggy = NULL; + m_motocycle = NULL; + m_skateboard = NULL; + m_racecar = NULL; + m_jetski = NULL; + m_act1state = NULL; + m_destLocation = LegoGameState::e_undefined; + + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x10030a50 +Isle::~Isle() +{ + TransitionManager()->SetWaitIndicator(NULL); + ControlManager()->Unregister(this); + + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + if (CurrentActor() != NULL) { + VTable0x6c(CurrentActor()); + } + + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x10030b20 +MxResult Isle::Create(MxDSAction& p_dsAction) +{ + GameState()->FindLoadedAct(); + MxResult result = LegoWorld::Create(p_dsAction); + + if (result == SUCCESS) { + ControlManager()->Register(this); + InputManager()->SetWorld(this); + GameState()->StopArea(LegoGameState::e_previousArea); + + switch (GameState()->GetLoadedAct()) { + case LegoGameState::e_act2: + GameState()->StopArea(LegoGameState::e_act2main); + break; + case LegoGameState::e_act3: + GameState()->StopArea(LegoGameState::e_act2main); // Looks like a bug + break; + case LegoGameState::e_actNotFound: + m_destLocation = LegoGameState::e_infomain; + } + + if (GameState()->GetCurrentArea() == LegoGameState::e_isle) { + GameState()->SetCurrentArea(LegoGameState::e_undefined); + } + + LegoGameState* gameState = GameState(); + Act1State* act1state = (Act1State*) gameState->GetState("Act1State"); + if (act1state == NULL) { + act1state = (Act1State*) gameState->CreateState("Act1State"); + } + m_act1state = act1state; + + FUN_1003ef00(TRUE); + GameState()->SetDirty(TRUE); + } + + return result; +} + +// FUNCTION: LEGO1 0x10030c10 +MxLong Isle::Notify(MxParam& p_param) +{ + MxLong result = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationEndAction: + result = HandleEndAction((MxEndActionNotificationParam&) p_param); + break; + case c_notificationButtonUp: + case c_notificationButtonDown: + switch (m_act1state->m_unk0x018) { + case 3: + result = m_pizza->Notify(p_param); + break; + case 10: + result = m_ambulance->Notify(p_param); + break; + } + break; + case c_notificationClick: + result = HandleClick((LegoControlManagerEvent&) p_param); + break; + case c_notificationEndAnim: + switch (m_act1state->m_unk0x018) { + case 4: + result = CurrentActor()->Notify(p_param); + break; + case 8: + result = m_towtrack->Notify(p_param); + break; + case 10: + result = m_ambulance->Notify(p_param); + break; + } + break; + case c_notificationType19: + result = HandleType19Notification(p_param); + break; + case c_notificationType20: + Enable(TRUE); + break; + case c_notificationTransitioned: + result = HandleTransitionEnd(); + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x10030d90 +MxLong Isle::HandleEndAction(MxEndActionNotificationParam& p_param) +{ + MxLong result; + + switch (m_act1state->m_unk0x018) { + case 2: + HandleElevatorEndAction(); + result = 1; + break; + case 3: + result = m_pizza->Notify(p_param); + break; + case 8: + result = m_towtrack->Notify(p_param); + break; + case 10: + result = m_ambulance->Notify(p_param); + break; + default: + result = m_radio.Notify(p_param); + + if (result == 0) { + MxDSAction* action = p_param.GetAction(); + + // TODO: Should be signed, but worsens match + MxU32 script; + + if (action->GetAtomId() == *g_jukeboxScript) { + script = action->GetObjectId(); + + if (script >= JukeboxScript::c_JBMusic1 && script <= JukeboxScript::c_JBMusic6) { + m_jukebox->StopAction((JukeboxScript::Script) script); + result = 1; + } + } + else if (m_act1state->m_planeActive) { + script = action->GetObjectId(); + + if (script >= IsleScript::c_nic002pr_RunAnim && script <= IsleScript::c_nic004pr_RunAnim) { + m_act1state->m_planeActive = FALSE; + } + } + else { + script = action->GetObjectId(); + + if (script == IsleScript::c_Avo917In_PlayWav || + (script >= IsleScript::c_Avo900Ps_PlayWav && script <= IsleScript::c_Avo907Ps_PlayWav)) { + BackgroundAudioManager()->RaiseVolume(); + } + } + } + } + + return result; +} + +// FUNCTION: LEGO1 0x10030ef0 +void Isle::HandleElevatorEndAction() +{ + switch (m_act1state->m_elevFloor) { + case Act1State::c_floor1: + m_destLocation = LegoGameState::e_infomain; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + m_act1state->m_unk0x018 = 0; + break; + case Act1State::c_floor2: + if (m_act1state->m_unk0x01e) { + m_act1state->m_unk0x01e = FALSE; + m_act1state->m_unk0x018 = 0; + InputManager()->EnableInputProcessing(); + } + else { + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_Floor2, NULL); + InputManager()->EnableInputProcessing(); + m_act1state->m_unk0x01e = TRUE; + } + break; + case Act1State::c_floor3: + m_destLocation = LegoGameState::e_elevopen; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + m_act1state->m_unk0x018 = 0; + break; + } +} + +// FUNCTION: LEGO1 0x10030fc0 +void Isle::ReadyWorld() +{ + LegoWorld::ReadyWorld(); + + if (m_act1state->GetUnknown21()) { + GameState()->SwitchArea(LegoGameState::e_infomain); + m_act1state->SetUnknown18(0); + m_act1state->SetUnknown21(0); + } + else if (GameState()->GetLoadedAct() != LegoGameState::e_act1) { + FUN_1003ef00(TRUE); + FUN_10032620(); + m_act1state->FUN_10034d00(); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + } +} + +// FUNCTION: LEGO1 0x10031030 +MxLong Isle::HandleClick(LegoControlManagerEvent& p_param) +{ + if (p_param.GetUnknown0x28() == 1) { + MxDSAction action; + + switch (p_param.GetClickedObjectId()) { + case IsleScript::c_ElevRide_Info_Ctl: + m_act1state->m_unk0x018 = 2; + + switch (m_act1state->m_elevFloor) { + case Act1State::c_floor1: + m_destLocation = LegoGameState::e_infomain; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case Act1State::c_floor2: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_Elev2_1_Ride, NULL); + InputManager()->DisableInputProcessing(); + break; + case Act1State::c_floor3: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_Elev3_1_Ride, NULL); + InputManager()->DisableInputProcessing(); + break; + } + + m_act1state->m_elevFloor = Act1State::c_floor1; + break; + case IsleScript::c_ElevRide_Two_Ctl: + m_act1state->m_unk0x018 = 2; + + switch (m_act1state->m_elevFloor) { + case Act1State::c_floor1: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_Elev1_2_Ride, NULL); + InputManager()->DisableInputProcessing(); + break; + case Act1State::c_floor2: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_Floor2, NULL); + m_act1state->m_unk0x01e = TRUE; + break; + case Act1State::c_floor3: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_Elev3_2_Ride, NULL); + InputManager()->DisableInputProcessing(); + break; + } + + m_act1state->m_elevFloor = Act1State::c_floor2; + break; + case IsleScript::c_ElevRide_Three_Ctl: + m_act1state->m_unk0x018 = 2; + + switch (m_act1state->m_elevFloor) { + case Act1State::c_floor1: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_Elev1_3_Ride, NULL); + InputManager()->DisableInputProcessing(); + break; + case Act1State::c_floor2: + InputManager()->DisableInputProcessing(); + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_Elev2_3_Ride, NULL); + break; + case Act1State::c_floor3: + m_destLocation = LegoGameState::e_elevopen; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + } + + m_act1state->m_elevFloor = Act1State::c_floor3; + break; + case IsleScript::c_ElevOpen_LeftArrow_Ctl: + case IsleScript::c_ElevDown_RightArrow_Ctl: + m_destLocation = LegoGameState::e_seaview; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case IsleScript::c_ElevOpen_RightArrow_Ctl: + case IsleScript::c_ElevDown_LeftArrow_Ctl: + m_destLocation = LegoGameState::e_observe; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case IsleScript::c_Observe_LeftArrow_Ctl: + m_act1state->FUN_100346a0(); + m_radio.Stop(); + case IsleScript::c_SeaView_RightArrow_Ctl: + m_destLocation = LegoGameState::e_elevopen; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case IsleScript::c_Observe_RightArrow_Ctl: + m_act1state->FUN_100346a0(); + m_radio.Stop(); + case IsleScript::c_SeaView_LeftArrow_Ctl: + m_destLocation = LegoGameState::e_elevdown; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case IsleScript::c_Observe_Plane_Ctl: + if (!m_act1state->m_planeActive) { + switch (rand() % 3) { + case 0: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_nic002pr_RunAnim, NULL); + break; + case 1: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_nic003pr_RunAnim, NULL); + break; + case 2: + InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_nic004pr_RunAnim, NULL); + break; + } + + m_act1state->m_planeActive = TRUE; + } + break; + case IsleScript::c_Observe_Sun_Ctl: + GameState()->GetBackgroundColor()->ToggleDayNight(TRUE); + break; + case IsleScript::c_Observe_Moon_Ctl: + GameState()->GetBackgroundColor()->ToggleDayNight(FALSE); + break; + case IsleScript::c_Observe_SkyColor_Ctl: + GameState()->GetBackgroundColor()->ToggleSkyColor(); + break; + case IsleScript::c_Observe_LCab_Ctl: + action.SetAtomId(*g_isleScript); + action.SetObjectId(IsleScript::c_Observe_Monkey_Flc); + action.SetUnknown24(0); + Start(&action); + break; + case IsleScript::c_Observe_RCab_Ctl: + FUN_10031590(); + break; + case IsleScript::c_Observe_GlobeLArrow_Ctl: + UpdateLightPosition(-1); + FUN_10031590(); + break; + case IsleScript::c_Observe_GlobeRArrow_Ctl: + UpdateLightPosition(1); + FUN_10031590(); + break; + case IsleScript::c_Observe_Draw1_Ctl: + case IsleScript::c_Observe_Draw2_Ctl: + m_act1state->FUN_10034660(); + break; + case IsleScript::c_ElevDown_Elevator_Ctl: + m_destLocation = LegoGameState::e_elevride2; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case IsleScript::c_PoliDoor_LeftArrow_Ctl: + case IsleScript::c_PoliDoor_RightArrow_Ctl: + m_destLocation = LegoGameState::e_police; + VariableTable()->SetVariable("VISIBILITY", "Show Policsta"); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case IsleScript::c_PoliDoor_Door_Ctl: + m_destLocation = LegoGameState::e_unk33; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case IsleScript::c_GaraDoor_LeftArrow_Ctl: + case IsleScript::c_GaraDoor_RightArrow_Ctl: + m_destLocation = LegoGameState::e_garage; + VariableTable()->SetVariable("VISIBILITY", "Show Gas"); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case IsleScript::c_GaraDoor_Door_Ctl: + m_destLocation = LegoGameState::e_unk28; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + } + } + + return 0; +} + +// STUB: LEGO1 0x10031590 +void Isle::FUN_10031590() +{ + // TODO +} + +// STUB: LEGO1 0x100315f0 +MxLong Isle::HandleType19Notification(MxParam& p_param) +{ + return 0; +} + +// FUNCTION: LEGO1 0x10031820 +void Isle::Enable(MxBool p_enable) +{ + if (m_set0xd0.empty() == p_enable) { + return; + } + + LegoWorld::Enable(p_enable); + m_radio.Initialize(p_enable); + + if (p_enable) { + FUN_100330e0(); + + VideoManager()->ResetPalette(FALSE); + m_act1state->FUN_10034d00(); + + if (CurrentActor() != NULL && CurrentActor()->GetActorId() != 0) { + // TODO: Match, most likely an inline function + MxS32 targetEntityId = (CurrentActor()->GetActorId() == 1) + 250; + + if (targetEntityId != -1) { + InvokeAction(Extra::e_start, *g_isleScript, targetEntityId, NULL); + } + } + + InputManager()->SetWorld(this); + GameState()->StopArea(LegoGameState::e_previousArea); + GameState()->m_previousArea = GameState()->m_currentArea; + + FUN_1003ef00(TRUE); + + if (m_act1state->m_unk0x018 == 0) { + MxS32 locations[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + for (MxU32 i = 0; i < 5; i++) { + MxS32 r = rand() % 5; + + for (MxU32 j = 0; j < sizeOfArray(locations); j++) { + if (locations[j] != 0 && r-- == 0) { + AnimationManager()->AddExtra(locations[j], TRUE); + locations[j] = 0; + break; + } + } + } + } + + if (CurrentActor() != NULL && CurrentActor()->IsA("Jetski")) { + IslePathActor* actor = CurrentActor(); + actor->SpawnPlayer( + LegoGameState::e_unk45, + FALSE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + actor->SetState(0); + } + else { + FUN_10032620(); + } + + switch (GameState()->m_currentArea) { + case LegoGameState::e_elevride: + m_destLocation = LegoGameState::e_elevride; + NotificationManager()->Send(this, MxNotificationParam(c_notificationTransitioned, NULL)); + SetIsWorldActive(FALSE); + break; + case LegoGameState::e_jetrace2: + if (((JetskiRaceState*) GameState()->GetState("JetskiRaceState"))->GetUnknown0x28() == 2) { + m_act1state->m_unk0x018 = 5; + } + + AddPathActor(CurrentActor()); + SetIsWorldActive(TRUE); + +#ifdef COMPAT_MODE + { + LegoEventNotificationParam param(c_notificationType11, NULL, 0, 0, 0, 0); + m_jetski->Notify(param); + } +#else + m_jetski->Notify(LegoEventNotificationParam(c_notificationType11, NULL, 0, 0, 0, 0)); +#endif + break; + case LegoGameState::e_garadoor: + m_destLocation = LegoGameState::e_garadoor; + NotificationManager()->Send(this, MxNotificationParam(c_notificationTransitioned, NULL)); + SetIsWorldActive(FALSE); + break; + case LegoGameState::e_polidoor: + m_destLocation = LegoGameState::e_polidoor; + NotificationManager()->Send(this, MxNotificationParam(c_notificationTransitioned, NULL)); + SetIsWorldActive(FALSE); + break; + case LegoGameState::e_bike: + AddPathActor(CurrentActor()); + SetIsWorldActive(TRUE); + +#ifdef COMPAT_MODE + { + LegoEventNotificationParam param(c_notificationType11, NULL, 0, 0, 0, 0); + m_bike->Notify(param); + } +#else + m_bike->Notify(LegoEventNotificationParam(c_notificationType11, NULL, 0, 0, 0, 0)); +#endif + break; + case LegoGameState::e_dunecar: + AddPathActor(CurrentActor()); + SetIsWorldActive(TRUE); + +#ifdef COMPAT_MODE + { + LegoEventNotificationParam param(c_notificationType11, NULL, 0, 0, 0, 0); + m_dunebuggy->Notify(param); + } +#else + m_dunebuggy->Notify(LegoEventNotificationParam(c_notificationType11, NULL, 0, 0, 0, 0)); +#endif + break; + case LegoGameState::e_motocycle: + AddPathActor(CurrentActor()); + SetIsWorldActive(TRUE); + +#ifdef COMPAT_MODE + { + LegoEventNotificationParam param(c_notificationType11, NULL, 0, 0, 0, 0); + m_motocycle->Notify(param); + } +#else + m_motocycle->Notify(LegoEventNotificationParam(c_notificationType11, NULL, 0, 0, 0, 0)); +#endif + break; + case LegoGameState::e_copter: + AddPathActor(CurrentActor()); + SetIsWorldActive(TRUE); + +#ifdef COMPAT_MODE + { + LegoEventNotificationParam param(c_notificationType11, NULL, 0, 0, 0, 0); + m_helicopter->Notify(param); + } +#else + m_helicopter->Notify(LegoEventNotificationParam(c_notificationType11, NULL, 0, 0, 0, 0)); +#endif + break; + case LegoGameState::e_skateboard: + AddPathActor(CurrentActor()); + SetIsWorldActive(TRUE); + +#ifdef COMPAT_MODE + { + LegoEventNotificationParam param(c_notificationType11, NULL, 0, 0, 0, 0); + m_skateboard->Notify(param); + } +#else + m_skateboard->Notify(LegoEventNotificationParam(c_notificationType11, NULL, 0, 0, 0, 0)); +#endif + break; + case LegoGameState::e_jetski: + AddPathActor(CurrentActor()); + SetIsWorldActive(TRUE); + +#ifdef COMPAT_MODE + { + LegoEventNotificationParam param(c_notificationType11, NULL, 0, 0, 0, 0); + m_jetski->Notify(param); + } +#else + m_jetski->Notify(LegoEventNotificationParam(c_notificationType11, NULL, 0, 0, 0, 0)); +#endif + break; + default: + InputManager()->SetCamera(m_cameraController); + SetIsWorldActive(TRUE); + break; + } + + switch (m_act1state->m_unk0x018) { + case 0: + case 1: + m_act1state->m_unk0x018 = 0; + + if (GameState()->m_currentArea == LegoGameState::e_pizzeriaExterior) { + AnimationManager()->FUN_10064740(NULL); + } + else if (GameState()->m_currentArea == LegoGameState::e_unk66) { + Mx3DPointFloat position(CurrentActor()->GetROI()->GetWorldPosition()); + + Mx3DPointFloat sub(-21.375f, 0.0f, -41.75f); + ((Vector3&) sub).Sub(&position); + if (sub.LenSquared() < 1024.0f) { + AnimationManager()->FUN_10064740(NULL); + } + + Mx3DPointFloat sub2(98.874992f, 0.0f, -46.156292f); + ((Vector3&) sub2).Sub(&position); + if (sub2.LenSquared() < 1024.0f) { + AnimationManager()->FUN_10064670(NULL); + } + } + break; + case 5: { + CurrentActor()->SpawnPlayer( + LegoGameState::e_jetrace2, + FALSE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + JetskiRaceState* raceState = (JetskiRaceState*) GameState()->GetState("JetskiRaceState"); + + if (raceState->GetUnknown0x28() == 2) { + IsleScript::Script script = IsleScript::c_noneIsle; + + switch (raceState->GetState(GameState()->GetActorId())->GetUnknown0x02()) { + case 1: + script = IsleScript::c_sjs014in_RunAnim; + break; + case 2: + script = IsleScript::c_sjs013in_RunAnim; + break; + case 3: + script = IsleScript::c_sjs012in_RunAnim; + break; + } + + AnimationManager()->FUN_10060dc0(script, NULL, TRUE, TRUE, NULL, FALSE, FALSE, TRUE, FALSE); + } + + m_act1state->m_unk0x018 = 0; + FUN_1003ef00(FALSE); + AnimationManager()->FUN_10064670(NULL); + break; + } + case 6: { + GameState()->m_currentArea = LegoGameState::e_carraceExterior; + CurrentActor()->SpawnPlayer( + LegoGameState::e_unk21, + FALSE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + CarRaceState* raceState = (CarRaceState*) GameState()->GetState("CarRaceState"); + + if (raceState->GetUnknown0x28() == 2) { + IsleScript::Script script = IsleScript::c_noneIsle; + + switch (raceState->GetState(GameState()->GetActorId())->GetUnknown0x02()) { + case 1: + script = IsleScript::c_srt003in_RunAnim; + break; + case 2: + script = IsleScript::c_srt002in_RunAnim; + break; + case 3: + script = IsleScript::c_srt001in_RunAnim; + break; + } + + AnimationManager()->FUN_10060dc0(script, NULL, TRUE, TRUE, NULL, FALSE, FALSE, TRUE, FALSE); + } + + m_act1state->m_unk0x018 = 0; + FUN_1003ef00(TRUE); + break; + } + case 7: + m_act1state->m_unk0x018 = 8; + + AnimationManager()->FUN_1005f6d0(FALSE); + AnimationManager()->FUN_1005f700(FALSE); + + g_unk0x100f1198 &= ~c_bit7; + m_towtrack->FUN_1004dab0(); + break; + case 9: + m_act1state->m_unk0x018 = 10; + + AnimationManager()->FUN_1005f6d0(FALSE); + AnimationManager()->FUN_1005f700(FALSE); + + g_unk0x100f1198 &= ~c_bit7; + m_ambulance->FUN_10036e60(); + break; + case 11: + m_act1state->m_unk0x018 = 0; + CurrentActor()->SpawnPlayer( + LegoGameState::e_unk54, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + GameState()->m_currentArea = LegoGameState::e_unk66; + FUN_1003ef00(TRUE); + m_jukebox->StartAction(); + break; + } + + SetAppCursor(0); + + if (m_act1state->m_unk0x018 != 8 && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_elevride) && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_polidoor) && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_garadoor) && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_bike) && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_dunecar) && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_motocycle) && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_copter) && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_jetski) && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_skateboard) && + (m_act1state->m_unk0x018 != 0 || GameState()->m_currentArea != LegoGameState::e_jetrace2)) { + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + } + + SetROIVisible("stretch", FALSE); + SetROIVisible("bird", FALSE); + SetROIVisible("rcred", FALSE); + SetROIVisible("towtk", FALSE); + SetROIVisible("pizpie", FALSE); + } + else { + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + m_act1state->FUN_10034b60(); + } +} + +// FUNCTION: LEGO1 0x10032620 +void Isle::FUN_10032620() +{ + VideoManager()->Get3DManager()->SetFrustrum(90.0, 0.1, 250.0); + + switch (GameState()->m_currentArea) { + case LegoGameState::e_unk66: { + MxMatrix mat(CurrentActor()->GetROI()->GetLocal2World()); + LegoPathBoundary* boundary = CurrentActor()->GetBoundary(); + CurrentActor()->VTable0xec(mat, boundary, TRUE); + break; + } + case LegoGameState::e_unk4: + case LegoGameState::e_jetraceExterior: + case LegoGameState::e_unk17: + case LegoGameState::e_carraceExterior: + case LegoGameState::e_unk20: + case LegoGameState::e_pizzeriaExterior: + case LegoGameState::e_garageExterior: + case LegoGameState::e_hospitalExterior: + case LegoGameState::e_unk31: + case LegoGameState::e_policeExterior: + CurrentActor()->SpawnPlayer( + GameState()->m_currentArea, + TRUE, + IslePathActor::c_spawnBit1 | IslePathActor::c_playMusic | IslePathActor::c_spawnBit3 + ); + GameState()->m_currentArea = LegoGameState::e_unk66; + break; + } +} + +// FUNCTION: LEGO1 0x100327a0 +MxLong Isle::HandleTransitionEnd() +{ + InvokeAction(Extra::e_stop, *g_isleScript, IsleScript::c_Avo917In_PlayWav, NULL); + DeleteObjects(&m_atom, IsleScript::c_Avo900Ps_PlayWav, IsleScript::c_Avo907Ps_PlayWav); + + if (m_destLocation != LegoGameState::e_skateboard) { + m_act1state->m_unk0x018 = 0; + } + + switch (m_destLocation) { + case LegoGameState::e_infomain: + ((LegoEntity*) Find(*g_isleScript, IsleScript::c_InfoCenter_Entity))->GetROI()->SetVisibility(TRUE); + GameState()->SwitchArea(m_destLocation); + m_destLocation = LegoGameState::e_undefined; + break; + case LegoGameState::e_elevride: + m_act1state->m_unk0x01f = TRUE; + VariableTable()->SetVariable("VISIBILITY", "Hide infocen"); + FUN_10032d30(IsleScript::c_ElevRide_Background_Bitmap, JukeboxScript::c_Elevator_Music, "LCAMZI1,90", FALSE); + break; + case LegoGameState::e_elevride2: + FUN_10032d30(IsleScript::c_ElevRide_Background_Bitmap, JukeboxScript::c_Elevator_Music, "LCAMZI2,90", FALSE); + + if (m_destLocation == LegoGameState::e_undefined) { + ((MxStillPresenter*) Find(m_atom, IsleScript::c_Meter3_Bitmap))->Enable(TRUE); + } + break; + case LegoGameState::e_elevopen: + FUN_10032d30( + IsleScript::c_ElevOpen_Background_Bitmap, + JukeboxScript::c_InfoCenter_3rd_Floor_Music, + "LCAMZIS,90", + FALSE + ); + break; + case LegoGameState::e_seaview: + FUN_10032d30( + IsleScript::c_SeaView_Background_Bitmap, + JukeboxScript::c_InfoCenter_3rd_Floor_Music, + "LCAMZIE,90", + FALSE + ); + break; + case LegoGameState::e_observe: + FUN_10032d30( + IsleScript::c_Observe_Background_Bitmap, + JukeboxScript::c_InfoCenter_3rd_Floor_Music, + "LCAMZIW,90", + FALSE + ); + break; + case LegoGameState::e_elevdown: + FUN_10032d30( + IsleScript::c_ElevDown_Background_Bitmap, + JukeboxScript::c_InfoCenter_3rd_Floor_Music, + "LCAMZIN,90", + FALSE + ); + break; + case LegoGameState::e_garadoor: + m_act1state->m_unk0x01f = TRUE; + VariableTable()->SetVariable("VISIBILITY", "Hide Gas"); + FUN_10032d30(IsleScript::c_GaraDoor_Background_Bitmap, JukeboxScript::c_JBMusic2, "LCAMZG1,90", FALSE); + break; + case LegoGameState::e_unk28: + GameState()->SwitchArea(m_destLocation); + GameState()->StopArea(LegoGameState::e_previousArea); + m_destLocation = LegoGameState::e_undefined; + VariableTable()->SetVariable("VISIBILITY", "Show Gas"); + AnimationManager()->Resume(); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + SetAppCursor(0); + SetIsWorldActive(TRUE); + break; + case LegoGameState::e_unk33: + GameState()->SwitchArea(m_destLocation); + GameState()->StopArea(LegoGameState::e_previousArea); + m_destLocation = LegoGameState::e_undefined; + VariableTable()->SetVariable("VISIBILITY", "Show Policsta"); + AnimationManager()->Resume(); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + SetAppCursor(0); + SetIsWorldActive(TRUE); + break; + case LegoGameState::e_polidoor: + m_act1state->m_unk0x01f = TRUE; + VariableTable()->SetVariable("VISIBILITY", "Hide Policsta"); + FUN_10032d30( + IsleScript::c_PoliDoor_Background_Bitmap, + JukeboxScript::c_PoliceStation_Music, + "LCAMZP1,90", + FALSE + ); + break; + case LegoGameState::e_bike: + m_act1state->m_unk0x01f = TRUE; + FUN_10032d30(IsleScript::c_BikeDashboard_Bitmap, JukeboxScript::c_MusicTheme1, NULL, TRUE); + + if (!m_act1state->m_unk0x01f) { + m_bike->FUN_10076b60(); + } + break; + case LegoGameState::e_dunecar: + m_act1state->m_unk0x01f = TRUE; + FUN_10032d30(IsleScript::c_DuneCarFuelMeter, JukeboxScript::c_MusicTheme1, NULL, TRUE); + + if (!m_act1state->m_unk0x01f) { + m_dunebuggy->FUN_10068350(); + } + break; + case LegoGameState::e_motocycle: + m_act1state->m_unk0x01f = TRUE; + FUN_10032d30(IsleScript::c_MotoBikeDashboard_Bitmap, JukeboxScript::c_MusicTheme1, NULL, TRUE); + + if (!m_act1state->m_unk0x01f) { + m_motocycle->FUN_10035e10(); + } + break; + case LegoGameState::e_copter: + m_act1state->m_unk0x01f = TRUE; + FUN_10032d30(IsleScript::c_HelicopterDashboard_Bitmap, JukeboxScript::c_MusicTheme1, NULL, TRUE); + break; + case LegoGameState::e_skateboard: + m_act1state->m_unk0x01f = TRUE; + FUN_10032d30(IsleScript::c_SkatePizza_Bitmap, JukeboxScript::c_MusicTheme1, NULL, TRUE); + + if (!m_act1state->m_unk0x01f) { + m_skateboard->FUN_10010510(); + } + break; + case LegoGameState::e_ambulance: + m_act1state->m_unk0x01f = TRUE; + m_act1state->m_unk0x018 = 10; + FUN_10032d30(IsleScript::c_AmbulanceFuelMeter, JukeboxScript::c_MusicTheme1, NULL, TRUE); + + if (!m_act1state->m_unk0x01f) { + m_ambulance->FUN_10037060(); + } + break; + case LegoGameState::e_towtrack: + m_act1state->m_unk0x01f = TRUE; + m_act1state->m_unk0x018 = 8; + FUN_10032d30(IsleScript::c_TowFuelMeter, JukeboxScript::c_MusicTheme1, NULL, TRUE); + + if (!m_act1state->m_unk0x01f) { + m_towtrack->FUN_1004dad0(); + } + break; + case LegoGameState::e_jetski: + m_act1state->m_unk0x01f = TRUE; + FUN_10032d30((IsleScript::Script) m_jetski->GetUnknown0x160(), JukeboxScript::c_MusicTheme1, NULL, TRUE); + + if (!m_act1state->m_unk0x01f) { + m_jetski->FUN_1007e990(); + } + break; + default: + GameState()->SwitchArea(m_destLocation); + m_destLocation = LegoGameState::e_undefined; + } + + return 1; +} + +// FUNCTION: LEGO1 0x10032d30 +void Isle::FUN_10032d30( + IsleScript::Script p_script, + JukeboxScript::Script p_music, + const char* p_cameraLocation, + MxBool p_und +) +{ + if (m_act1state->m_unk0x01f) { + MxPresenter* presenter = (MxPresenter*) Find(m_atom, p_script); + + if (presenter != NULL && presenter->GetCurrentTickleState() == MxPresenter::e_repeating) { + if (p_music != JukeboxScript::c_MusicTheme1) { + PlayMusic(p_music); + } + + if (p_und) { + InputManager()->SetCamera(m_cameraController); + } + else { + InputManager()->SetCamera(NULL); + } + + if (p_cameraLocation != NULL) { + VariableTable()->SetVariable(g_varCAMERALOCATION, p_cameraLocation); + } + + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + SetAppCursor(0); + m_destLocation = LegoGameState::e_undefined; + m_act1state->m_unk0x01f = FALSE; + } + else { + NotificationManager()->Send(this, MxNotificationParam(c_notificationTransitioned, NULL)); + } + } + else { + GameState()->SwitchArea(m_destLocation); + GameState()->StopArea(LegoGameState::e_previousArea); + NotificationManager()->Send(this, MxNotificationParam(c_notificationTransitioned, NULL)); + m_act1state->m_unk0x01f = TRUE; + } +} + +// FUNCTION: LEGO1 0x10032f10 +void Isle::Add(MxCore* p_object) +{ + LegoWorld::Add(p_object); + + if (p_object->IsA("Pizza")) { + m_pizza = (Pizza*) p_object; + } + else if (p_object->IsA("Pizzeria")) { + m_pizzeria = (Pizzeria*) p_object; + } + else if (p_object->IsA("TowTrack")) { + m_towtrack = (TowTrack*) p_object; + } + else if (p_object->IsA("Ambulance")) { + m_ambulance = (Ambulance*) p_object; + } + else if (p_object->IsA("JukeBoxEntity")) { + m_jukebox = (JukeBoxEntity*) p_object; + } + else if (p_object->IsA("Helicopter")) { + m_helicopter = (Helicopter*) p_object; + } + else if (p_object->IsA("Bike")) { + m_bike = (Bike*) p_object; + } + else if (p_object->IsA("DuneBuggy")) { + m_dunebuggy = (DuneBuggy*) p_object; + } + else if (p_object->IsA("Motorcycle")) { + m_motocycle = (Motocycle*) p_object; + } + else if (p_object->IsA("SkateBoard")) { + m_skateboard = (SkateBoard*) p_object; + } + else if (p_object->IsA("Jetski")) { + m_jetski = (Jetski*) p_object; + } + else if (p_object->IsA("RaceCar")) { + m_racecar = (RaceCar*) p_object; + } +} + +// FUNCTION: LEGO1 0x10033050 +void Isle::VTable0x6c(IslePathActor* p_actor) +{ + LegoWorld::Remove(p_actor); + + if (p_actor->IsA("Helicopter")) { + m_helicopter = NULL; + } + else if (p_actor->IsA("DuneBuggy")) { + m_dunebuggy = NULL; + } + else if (p_actor->IsA("Jetski")) { + m_jetski = NULL; + } + else if (p_actor->IsA("RaceCar")) { + m_racecar = NULL; + } +} + +// STUB: LEGO1 0x100330e0 +void Isle::FUN_100330e0() +{ + // TODO +} + +// STUB: LEGO1 0x10033180 +MxBool Isle::VTable0x64() +{ + // TODO + return FALSE; +} + +// STUB: LEGO1 0x10033350 +void Isle::FUN_10033350() +{ + // TODO +} diff --git a/LEGO1/lego/legoomni/src/worlds/jukebox.cpp b/LEGO1/lego/legoomni/src/worlds/jukebox.cpp new file mode 100644 index 00000000..257db67b --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/jukebox.cpp @@ -0,0 +1,262 @@ +#include "jukebox.h" + +#include "act1state.h" +#include "jukebox_actions.h" +#include "jukeboxstate.h" +#include "jukeboxw_actions.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "misc.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstillpresenter.h" +#include "mxticklemanager.h" +#include "mxtransitionmanager.h" +#include "mxvideopresenter.h" + +DECOMP_SIZE_ASSERT(JukeBox, 0x104) + +// FUNCTION: LEGO1 0x1005d660 +JukeBox::JukeBox() +{ + m_unk0x100 = 0; + m_state = NULL; + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x1005d6e0 +MxBool JukeBox::VTable0x5c() +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x1005d830 +JukeBox::~JukeBox() +{ + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + ControlManager()->Unregister(this); + TickleManager()->UnregisterClient(this); + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x1005d8d0 +MxResult JukeBox::Create(MxDSAction& p_dsAction) +{ + MxResult ret = LegoWorld::Create(p_dsAction); + if (ret == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + } + + InputManager()->SetCamera(NULL); + + m_state = (JukeBoxState*) GameState()->GetState("JukeBoxState"); + if (!m_state) { + m_state = (JukeBoxState*) GameState()->CreateState("JukeBoxState"); + m_state->SetState(0); + } + + GameState()->SetCurrentArea(LegoGameState::e_jukeboxw); + GameState()->StopArea(LegoGameState::e_previousArea); + TickleManager()->RegisterClient(this, 2000); + return ret; +} + +// FUNCTION: LEGO1 0x1005d980 +MxLong JukeBox::Notify(MxParam& p_param) +{ + MxLong result = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationClick: + result = HandleClick((LegoControlManagerEvent&) p_param); + break; + case c_notificationTransitioned: + GameState()->SwitchArea(m_destLocation); + result = 1; + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1005d9f0 +void JukeBox::ReadyWorld() +{ + MxStillPresenter* presenter = NULL; + + switch (m_state->GetState()) { + case 1: + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Right_Bitmap"); + break; + case 2: + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Decal_Bitmap"); + break; + case 3: + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Wallis_Bitmap"); + break; + case 4: + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Nelson_Bitmap"); + break; + case 5: + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Torpedos_Bitmap"); + break; + } + + if (presenter) { + presenter->Enable(TRUE); + } + + m_unk0x100 = 1; +} + +// FUNCTION: LEGO1 0x1005da70 +MxBool JukeBox::HandleClick(LegoControlManagerEvent& p_param) +{ + MxStillPresenter* presenter; + + if (p_param.GetUnknown0x28() == 1) { + switch (p_param.GetClickedObjectId()) { + case JukeboxwScript::c_Dback_Ctl: + switch (m_state->GetState()) { + case JukeboxScript::c_MusicTheme1: + m_state->SetState(JukeboxScript::c_ResidentalArea_Music); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Torpedos_Bitmap"); + presenter->Enable(TRUE); + break; + case JukeboxScript::c_MusicTheme3: + m_state->SetState(JukeboxScript::c_MusicTheme1); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Right_Bitmap"); + presenter->Enable(FALSE); + break; + case JukeboxScript::c_Act2Cave: + m_state->SetState(JukeboxScript::c_MusicTheme3); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Decal_Bitmap"); + presenter->Enable(FALSE); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Right_Bitmap"); + presenter->Enable(TRUE); + break; + case JukeboxScript::c_BrickstrChase: + m_state->SetState(JukeboxScript::c_Act2Cave); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Wallis_Bitmap"); + presenter->Enable(FALSE); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Decal_Bitmap"); + presenter->Enable(TRUE); + break; + case JukeboxScript::c_BrickHunt: + m_state->SetState(JukeboxScript::c_BrickstrChase); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Nelson_Bitmap"); + presenter->Enable(FALSE); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Wallis_Bitmap"); + presenter->Enable(TRUE); + break; + case JukeboxScript::c_ResidentalArea_Music: + m_state->SetState(JukeboxScript::c_BrickHunt); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Torpedos_Bitmap"); + presenter->Enable(FALSE); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Nelson_Bitmap"); + presenter->Enable(TRUE); + break; + } + break; + case JukeboxwScript::c_Dfwd_Ctl: + switch (m_state->GetState()) { + case JukeboxScript::c_MusicTheme1: + m_state->SetState(JukeboxScript::c_MusicTheme3); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Right_Bitmap"); + presenter->Enable(TRUE); + break; + case JukeboxScript::c_MusicTheme3: + m_state->SetState(JukeboxScript::c_Act2Cave); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Right_Bitmap"); + presenter->Enable(FALSE); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Decal_Bitmap"); + presenter->Enable(TRUE); + break; + case JukeboxScript::c_Act2Cave: + m_state->SetState(JukeboxScript::c_BrickstrChase); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Decal_Bitmap"); + presenter->Enable(FALSE); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Wallis_Bitmap"); + presenter->Enable(TRUE); + break; + case JukeboxScript::c_BrickstrChase: + m_state->SetState(JukeboxScript::c_BrickHunt); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Wallis_Bitmap"); + presenter->Enable(FALSE); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Nelson_Bitmap"); + presenter->Enable(TRUE); + break; + case JukeboxScript::c_BrickHunt: + m_state->SetState(JukeboxScript::c_ResidentalArea_Music); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Nelson_Bitmap"); + presenter->Enable(FALSE); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Torpedos_Bitmap"); + presenter->Enable(TRUE); + break; + case JukeboxScript::c_ResidentalArea_Music: + m_state->SetState(JukeboxScript::c_MusicTheme1); + presenter = (MxStillPresenter*) Find("MxStillPresenter", "Torpedos_Bitmap"); + presenter->Enable(FALSE); + break; + } + break; + case JukeboxwScript::c_Note_Ctl: + LegoGameState* gameState = GameState(); + Act1State* act1State = (Act1State*) gameState->GetState("Act1State"); + act1State->SetUnknown18(11); + m_destLocation = LegoGameState::Area::e_unk54; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, 0, FALSE); + break; + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1005dde0 +void JukeBox::Enable(MxBool p_enable) +{ + LegoWorld::Enable(p_enable); + + if (p_enable) { + InputManager()->SetWorld(this); + InputManager()->SetCamera(NULL); + } + else { + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + } +} + +// FUNCTION: LEGO1 0x1005de30 +MxResult JukeBox::Tickle() +{ + if (m_worldStarted == FALSE) { + LegoWorld::Tickle(); + return SUCCESS; + } + + if (m_unk0x100 == 1) { + m_unk0x100 = 0; + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1005de70 +MxBool JukeBox::VTable0x64() +{ + m_destLocation = LegoGameState::e_infomain; + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/legoact2.cpp b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp new file mode 100644 index 00000000..43c05750 --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/legoact2.cpp @@ -0,0 +1,55 @@ +#include "legoact2.h" + +DECOMP_SIZE_ASSERT(LegoAct2, 0x1154) + +// FUNCTION: LEGO1 0x1004fe10 +MxBool LegoAct2::VTable0x5c() +{ + return TRUE; +} + +// STUB: LEGO1 0x1004ff20 +MxResult LegoAct2::Create(MxDSAction& p_dsAction) +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10050040 +MxResult LegoAct2::Tickle() +{ + // TODO + return SUCCESS; +} + +// STUB: LEGO1 0x10050380 +MxLong LegoAct2::Notify(MxParam& p_param) +{ + // TODO + return 0; +} + +// STUB: LEGO1 0x10050a80 +void LegoAct2::ReadyWorld() +{ + // TODO +} + +// STUB: LEGO1 0x10050cf0 +void LegoAct2::Enable(MxBool p_enable) +{ + // TODO +} + +// STUB: LEGO1 0x100519c0 +void LegoAct2::VTable0x60() +{ + // TODO +} + +// STUB: LEGO1 0x100519d0 +MxBool LegoAct2::VTable0x64() +{ + // TODO + return FALSE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/police.cpp b/LEGO1/lego/legoomni/src/worlds/police.cpp new file mode 100644 index 00000000..1cf8f879 --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/police.cpp @@ -0,0 +1,198 @@ +#include "police.h" + +#include "jukebox.h" +#include "jukebox_actions.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "misc.h" +#include "mxactionnotificationparam.h" +#include "mxbackgroundaudiomanager.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxtransitionmanager.h" +#include "police_actions.h" +#include "policestate.h" + +DECOMP_SIZE_ASSERT(Police, 0x110) + +// FUNCTION: LEGO1 0x1005e130 +Police::Police() +{ + m_policeState = NULL; + m_destLocation = LegoGameState::e_undefined; + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x1005e1d0 +MxBool Police::VTable0x5c() +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x1005e320 +Police::~Police() +{ + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + ControlManager()->Unregister(this); + InputManager()->UnRegister(this); + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x1005e3e0 +MxResult Police::Create(MxDSAction& p_dsAction) +{ + MxResult ret = LegoWorld::Create(p_dsAction); + if (ret == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + } + + SetIsWorldActive(FALSE); + InputManager()->Register(this); + + LegoGameState* gameState = GameState(); + PoliceState* policeState = (PoliceState*) gameState->GetState("PoliceState"); + if (!policeState) { + policeState = (PoliceState*) gameState->CreateState("PoliceState"); + } + + m_policeState = policeState; + GameState()->SetCurrentArea(LegoGameState::e_police); + GameState()->StopArea(LegoGameState::e_previousArea); + return ret; +} + +// FUNCTION: LEGO1 0x1005e480 +MxLong Police::Notify(MxParam& p_param) +{ + MxLong result = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationEndAction: + result = HandleEndAction((MxEndActionNotificationParam&) p_param); + break; + case c_notificationKeyPress: + result = HandleKeyPress(((LegoEventNotificationParam&) p_param)); + break; + case c_notificationClick: + result = HandleClick((LegoControlManagerEvent&) p_param); + break; + case c_notificationTransitioned: + GameState()->SwitchArea(m_destLocation); + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x1005e530 +void Police::ReadyWorld() +{ + LegoWorld::ReadyWorld(); + PlayMusic(JukeboxScript::c_PoliceStation_Music); + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); +} + +// FUNCTION: LEGO1 0x1005e550 +MxLong Police::HandleClick(LegoControlManagerEvent& p_param) +{ + if (p_param.GetUnknown0x28() == 1) { + switch (p_param.GetClickedObjectId()) { + case PoliceScript::c_LeftArrow_Ctl: + case PoliceScript::c_RightArrow_Ctl: + if (m_policeState->GetUnknown0x0c() == 1) { + DeleteObjects(&m_atom, PoliceScript::c_nps001ni_RunAnim, PoliceScript::c_nps002la_RunAnim); + } + + BackgroundAudioManager()->Stop(); + m_destLocation = LegoGameState::Area::e_polidoor; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case PoliceScript::c_Info_Ctl: + if (m_policeState->GetUnknown0x0c() == 1) { + DeleteObjects(&m_atom, PoliceScript::c_nps001ni_RunAnim, PoliceScript::c_nps002la_RunAnim); + } + + BackgroundAudioManager()->Stop(); + m_destLocation = LegoGameState::Area::e_infomain; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case PoliceScript::c_Door_Ctl: + if (m_policeState->GetUnknown0x0c() == 1) { + DeleteObjects(&m_atom, PoliceScript::c_nps001ni_RunAnim, PoliceScript::c_nps002la_RunAnim); + } + + BackgroundAudioManager()->Stop(); + m_destLocation = LegoGameState::Area::e_copterbuild; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case PoliceScript::c_Donut_Ctl: + m_policeState->FUN_1005ea40(); + } + } + + return 1; +} + +// FUNCTION: LEGO1 0x1005e6a0 +MxLong Police::HandleEndAction(MxEndActionNotificationParam& p_param) +{ + MxDSAction* action = p_param.GetAction(); + + if (m_radio.Notify(p_param) == 0 && m_atom == action->GetAtomId()) { + if (m_policeState->GetUnknown0x0c() == 1) { + m_policeState->SetUnknown0x0c(0); + return 1; + } + + return 0; + } + + return 0; +} + +// FUNCTION: LEGO1 0x1005e6f0 +MxLong Police::HandleKeyPress(LegoEventNotificationParam& p_param) +{ + MxLong result = 0; + + if (p_param.GetKey() == ' ' && m_policeState->GetUnknown0x0c() == 1) { + DeleteObjects(&m_atom, PoliceScript::c_nps001ni_RunAnim, PoliceScript::c_nps002la_RunAnim); + m_policeState->SetUnknown0x0c(0); + return 1; + } + + return 0; +} + +// FUNCTION: LEGO1 0x1005e740 +void Police::Enable(MxBool p_enable) +{ + LegoWorld::Enable(p_enable); + + if (p_enable) { + InputManager()->SetWorld(this); + SetIsWorldActive(FALSE); + } + else { + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + } +} + +// FUNCTION: LEGO1 0x1005e790 +MxBool Police::VTable0x64() +{ + DeleteObjects(&m_atom, PoliceScript::c_nps001ni_RunAnim, 510); + m_destLocation = LegoGameState::e_infomain; + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp b/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp new file mode 100644 index 00000000..29802f23 --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/registrationbook.cpp @@ -0,0 +1,500 @@ +#include "registrationbook.h" + +#include "infocenterstate.h" +#include "jukebox_actions.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "misc.h" +#include "mxactionnotificationparam.h" +#include "mxbackgroundaudiomanager.h" +#include "mxcontrolpresenter.h" +#include "mxdisplaysurface.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstillpresenter.h" +#include "mxtimer.h" +#include "mxtransitionmanager.h" +#include "regbook_actions.h" +#include "scripts.h" + +DECOMP_SIZE_ASSERT(RegistrationBook, 0x2d0) + +// GLOBAL: LEGO1 0x100d9924 +const char* g_infoman = "infoman"; + +// GLOBAL: LEGO1 0x100f7964 +MxLong g_checkboxBlinkTimer = 0; + +// GLOBAL: LEGO1 0x100f7968 +MxBool g_nextCheckbox = FALSE; + +// FUNCTION: LEGO1 0x10076d20 +RegistrationBook::RegistrationBook() : m_registerDialogueTimer(0x80000000), m_unk0xfc(1) +{ + memset(m_alphabet, 0, sizeof(m_alphabet)); + memset(m_name, 0, sizeof(m_name)); + m_unk0x280.m_cursorPos = 0; + + memset(m_checkmark, 0, sizeof(m_checkmark)); + memset(&m_unk0x280, -1, sizeof(m_unk0x280) - 2); + + m_unk0x2b8 = 0; + m_infocenterState = NULL; + + NotificationManager()->Register(this); + + m_unk0x2c1 = 0; + m_checkboxHilite = NULL; + m_checkboxSurface = NULL; + m_checkboxNormal = NULL; +} + +// FUNCTION: LEGO1 0x10076f50 +RegistrationBook::~RegistrationBook() +{ + for (MxS16 i = 0; i < 10; i++) { + for (MxS16 j = 0; j < 7; j++) { + if (m_name[i][j] != NULL) { + delete m_name[i][j]->GetAction(); + delete m_name[i][j]; + m_name[i][j] = NULL; + } + } + } + + InputManager()->UnRegister(this); + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + ControlManager()->Unregister(this); + NotificationManager()->Unregister(this); + + if (m_checkboxNormal) { + m_checkboxNormal->Release(); + } +} + +// FUNCTION: LEGO1 0x10077060 +MxResult RegistrationBook::Create(MxDSAction& p_dsAction) +{ + MxResult result = LegoWorld::Create(p_dsAction); + + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + SetIsWorldActive(FALSE); + InputManager()->Register(this); + + GameState()->SetCurrentArea(LegoGameState::e_regbook); + GameState()->StopArea(LegoGameState::e_previousArea); + + m_infocenterState = (InfocenterState*) GameState()->GetState("InfocenterState"); + } + + return result; +} + +// FUNCTION: LEGO1 0x100770e0 +MxLong RegistrationBook::Notify(MxParam& p_param) +{ + MxLong result = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetType()) { + case c_notificationEndAction: + result = HandleEndAction((MxEndActionNotificationParam&) p_param); + break; + case c_notificationKeyPress: + m_registerDialogueTimer = Timer()->GetTime(); + result = HandleKeyPress(((LegoEventNotificationParam&) p_param).GetKey()); + break; + case c_notificationButtonDown: + m_registerDialogueTimer = Timer()->GetTime(); + break; + case c_notificationClick: + result = HandleClick((LegoControlManagerEvent&) p_param); + break; + case c_notificationType19: + result = HandleNotification19(p_param); + break; + case c_notificationTransitioned: + GameState()->SwitchArea(LegoGameState::e_infomain); + break; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x10077210 +MxLong RegistrationBook::HandleEndAction(MxEndActionNotificationParam& p_param) +{ + if (p_param.GetAction()->GetAtomId() != m_atom) { + return 0; + } + + switch ((MxS32) p_param.GetAction()->GetObjectId()) { + case RegbookScript::c_Textures: + m_unk0x2c1 = 0; + + if (m_unk0x2b8 == 0) { + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + break; + case RegbookScript::c_iic006in_RunAnim: + case RegbookScript::c_iic007in_PlayWav: + case RegbookScript::c_iic008in_PlayWav: + BackgroundAudioManager()->RaiseVolume(); + m_registerDialogueTimer = Timer()->GetTime(); + break; + } + + return 1; +} + +// FUNCTION: LEGO1 0x100772d0 +MxLong RegistrationBook::HandleKeyPress(MxU8 p_key) +{ + MxS16 key; + if (p_key >= 'a' && p_key <= 'z') { + key = p_key - ' '; + } + else { + key = p_key; + } + + if ((key < 'A' || key > 'Z') && key != '\b') { + if (key == ' ') { + DeleteObjects(&m_atom, RegbookScript::c_iic006in_RunAnim, RegbookScript::c_iic008in_PlayWav); + BackgroundAudioManager()->RaiseVolume(); + } + } + else if (key != '\b' && m_unk0x280.m_cursorPos < 7) { + m_name[0][m_unk0x280.m_cursorPos] = m_alphabet[key - 'A']->Clone(); + + if (m_name[0][m_unk0x280.m_cursorPos] != NULL) { + m_alphabet[key - 'A']->GetAction()->SetUnknown24(m_alphabet[key - 'A']->GetAction()->GetUnknown24() + 1); + m_name[0][m_unk0x280.m_cursorPos]->Enable(TRUE); + m_name[0][m_unk0x280.m_cursorPos]->SetTickleState(MxPresenter::e_repeating); + m_name[0][m_unk0x280.m_cursorPos]->SetPosition(m_unk0x280.m_cursorPos * 23 + 343, 121); + + if (m_unk0x280.m_cursorPos == 0) { + m_checkmark[0]->Enable(TRUE); + } + + m_unk0x280.m_letters[m_unk0x280.m_cursorPos] = key - 'A'; + m_unk0x280.m_cursorPos++; + } + } + else { + if (key == '\b' && m_unk0x280.m_cursorPos > 0) { + m_unk0x280.m_cursorPos--; + + m_name[0][m_unk0x280.m_cursorPos]->Enable(FALSE); + + delete m_name[0][m_unk0x280.m_cursorPos]; + m_name[0][m_unk0x280.m_cursorPos] = NULL; + + if (m_unk0x280.m_cursorPos == 0) { + m_checkmark[0]->Enable(FALSE); + } + + m_unk0x280.m_letters[m_unk0x280.m_cursorPos] = -1; + } + } + + return 1; +} + +// FUNCTION: LEGO1 0x100774a0 +MxLong RegistrationBook::HandleClick(LegoControlManagerEvent& p_param) +{ + MxS16 unk0x28 = p_param.GetUnknown0x28(); + + if (unk0x28 >= 1 && unk0x28 <= 28) { + if (p_param.GetClickedObjectId() == RegbookScript::c_Alphabet_Ctl) { + if (unk0x28 == 28) { + DeleteObjects(&m_atom, RegbookScript::c_iic006in_RunAnim, RegbookScript::c_iic008in_PlayWav); + + if (GameState()->GetCurrentAct() == LegoGameState::e_act1) { + m_infocenterState->SetUnknown0x74(15); + } + else { + m_infocenterState->SetUnknown0x74(2); + } + + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + else { + if (unk0x28 > 28) { + return 1; + } + + HandleKeyPress(unk0x28 < 27 ? unk0x28 + 64 : 8); + } + } + else { + InputManager()->DisableInputProcessing(); + DeleteObjects(&m_atom, RegbookScript::c_iic006in_RunAnim, RegbookScript::c_iic008in_PlayWav); + + MxS16 i; + for (i = 0; i < 10; i++) { + if (m_checkmark[i]->GetAction()->GetObjectId() == p_param.GetClickedObjectId()) { + break; + } + } + + FUN_100775c0(i); + } + } + + return 1; +} + +// FUNCTION: LEGO1 0x100775c0 +void RegistrationBook::FUN_100775c0(MxS16 p_playerIndex) +{ + if (m_infocenterState->HasRegistered()) { + GameState()->Save(0); + } + + // TODO: structure incorrect + MxS16 player = p_playerIndex == 0 ? GameState()->FindPlayer(*(LegoGameState::Username*) &m_unk0x280.m_letters) + : p_playerIndex - 1; + + switch (player) { + case 0: + if (!m_infocenterState->HasRegistered()) { + GameState()->SwitchPlayer(0); + WriteInfocenterLetters(1); + FUN_100778c0(); + } + break; + case -1: + GameState()->Init(); + + PlayAction(RegbookScript::c_Textures); + + m_unk0x2c1 = 1; + + // TOOD: structure incorrect + GameState()->AddPlayer(*(LegoGameState::Username*) &m_unk0x280.m_letters); + GameState()->Save(0); + + WriteInfocenterLetters(0); + GameState()->SerializePlayersInfo(2); + FUN_100778c0(); + break; + default: + GameState()->Init(); + + PlayAction(RegbookScript::c_Textures); + + m_unk0x2c1 = 1; + + GameState()->SwitchPlayer(player); + + WriteInfocenterLetters(player + 1); + GameState()->SerializePlayersInfo(2); + FUN_100778c0(); + break; + } + + m_infocenterState->SetUnknown0x74(4); + if (m_unk0x2b8 == 0 && m_unk0x2c1 == 0) { + DeleteObjects(&m_atom, RegbookScript::c_iic006in_RunAnim, RegbookScript::c_iic008in_PlayWav); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } +} + +// FUNCTION: LEGO1 0x10077860 +void RegistrationBook::WriteInfocenterLetters(MxS16 p_user) +{ + for (MxS16 i = 0; i < 7; i++) { + delete m_infocenterState->GetNameLetter(i); + m_infocenterState->SetNameLetter(i, m_name[p_user][i]); + m_name[p_user][i] = NULL; + } +} + +// STUB: LEGO1 0x100778c0 +void RegistrationBook::FUN_100778c0() +{ + // TODO +} + +// FUNCTION: LEGO1 0x10077cc0 +void RegistrationBook::ReadyWorld() +{ + LegoGameState* gameState = GameState(); + gameState->GetHistory()->WriteScoreHistory(); + MxS16 i; + + PlayMusic(JukeboxScript::c_InformationCenter_Music); + + char letterBuffer[] = "A_Bitmap"; + for (i = 0; i < 26; i++) { + m_alphabet[i] = (MxStillPresenter*) Find("MxStillPresenter", letterBuffer); + + // We need to loop through the entire alphabet, + // so increment the first char of the bitmap name + letterBuffer[0]++; + } + + // Now we have to do the checkmarks + char checkmarkBuffer[] = "Check0_Ctl"; + for (i = 0; i < 10; i++) { + m_checkmark[i] = (MxControlPresenter*) Find("MxControlPresenter", checkmarkBuffer); + + // Just like in the prior letter loop, + // we need to increment the fifth char + // to get the next checkmark bitmap + checkmarkBuffer[5]++; + } + + LegoGameState::Username* players = GameState()->m_players; + + for (i = 1; i <= GameState()->m_playerCount; i++) { + for (MxS16 j = 0; j < 7; j++) { + if (players[i - 1].m_letters[j] != -1) { + if (j == 0) { + m_checkmark[i]->Enable(TRUE); + } + + // Start building the player names using a two-dimensional array + m_name[i][j] = m_alphabet[players[i - 1].m_letters[j]]->Clone(); + + // Enable the presenter to actually show the letter in the grid + m_name[i][j]->Enable(TRUE); + + m_name[i][j]->SetTickleState(MxPresenter::e_repeating); + m_name[i][j]->SetPosition(23 * j + 343, 27 * i + 121); + } + } + } + + if (m_infocenterState->HasRegistered()) { + PlayAction(RegbookScript::c_iic008in_PlayWav); + + LegoROI* infoman = FindROI(g_infoman); + if (infoman != NULL) { + infoman->SetVisibility(FALSE); + } + } + else { + PlayAction(RegbookScript::c_iic006in_RunAnim); + } +} + +inline void RegistrationBook::PlayAction(MxU32 p_objectId) +{ + MxDSAction action; + action.SetAtomId(*g_regbookScript); + action.SetObjectId(p_objectId); + + BackgroundAudioManager()->LowerVolume(); + Start(&action); +} + +// FUNCTION: LEGO1 0x10077fd0 +MxResult RegistrationBook::Tickle() +{ + if (!m_worldStarted) { + LegoWorld::Tickle(); + } + else { + MxLong time = Timer()->GetTime(); + if (m_registerDialogueTimer != 0x80000000 && m_registerDialogueTimer + 30000 <= time) { + m_registerDialogueTimer = 0x80000000; + PlayAction(RegbookScript::c_iic007in_PlayWav); + } + + if (g_checkboxBlinkTimer + 500 <= time) { + g_checkboxBlinkTimer = time; + + if (m_checkboxHilite) { + DDBLTFX op; + op.dwSize = sizeof(op); + op.dwROP = SRCCOPY; + + if (g_nextCheckbox) { + m_checkboxSurface->Blt(NULL, m_checkboxHilite, NULL, DDBLT_ROP, &op); + } + else { + m_checkboxSurface->Blt(NULL, m_checkboxNormal, NULL, DDBLT_ROP, &op); + } + } + else { + CreateSurface(); + } + + g_nextCheckbox = !g_nextCheckbox; + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10078180 +void RegistrationBook::Enable(MxBool p_enable) +{ + LegoWorld::Enable(p_enable); + + if (p_enable) { + InputManager()->SetWorld(this); + SetIsWorldActive(FALSE); + } + else { + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + } +} + +// STUB: LEGO1 0x100781d0 +MxLong RegistrationBook::HandleNotification19(MxParam& p_param) +{ + return 0; +} + +// FUNCTION: LEGO1 0x10078350 +MxBool RegistrationBook::CreateSurface() +{ + MxCompositePresenterList* list = m_checkmark[0]->GetList(); + MxStillPresenter *presenter, *uninitialized; + + if (list) { + if (list->begin() != list->end()) { + presenter = (MxStillPresenter*) list->front(); + } + else { + presenter = uninitialized; // intentionally uninitialized variable + } + + if (presenter) { + m_checkboxSurface = presenter->VTable0x78(); + } + + presenter = (MxStillPresenter*) Find("MxStillPresenter", "CheckHiLite_Bitmap"); + if (presenter) { + m_checkboxHilite = presenter->VTable0x78(); + } + + if (m_checkboxSurface && m_checkboxHilite) { + m_checkboxNormal = MxDisplaySurface::CopySurface(m_checkboxSurface); + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x100783e0 +MxBool RegistrationBook::VTable0x64() +{ + DeleteObjects(&m_atom, RegbookScript::c_iic006in_RunAnim, RegbookScript::c_iic008in_PlayWav); + return TRUE; +} diff --git a/LEGO1/lego/legoomni/src/worlds/score.cpp b/LEGO1/lego/legoomni/src/worlds/score.cpp new file mode 100644 index 00000000..0bb40ea7 --- /dev/null +++ b/LEGO1/lego/legoomni/src/worlds/score.cpp @@ -0,0 +1,320 @@ +#include "score.h" + +#include "ambulancemissionstate.h" +#include "carracestate.h" +#include "infoscor_actions.h" +#include "jetskiracestate.h" +#include "jukebox.h" +#include "jukebox_actions.h" +#include "legocontrolmanager.h" +#include "legogamestate.h" +#include "legoinputmanager.h" +#include "legomain.h" +#include "misc.h" +#include "misc/legocontainer.h" +#include "mxactionnotificationparam.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxnotificationparam.h" +#include "mxtransitionmanager.h" +#include "pizzamissionstate.h" +#include "racestate.h" +#include "scorestate.h" +#include "scripts.h" +#include "towtrackmissionstate.h" + +DECOMP_SIZE_ASSERT(Score, 0x104) + +// FUNCTION: LEGO1 0x10001000 +Score::Score() +{ + m_destLocation = LegoGameState::e_undefined; + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x100010b0 +MxBool Score::VTable0x5c() +{ + return TRUE; +} + +// FUNCTION: LEGO1 0x10001200 +Score::~Score() +{ + if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } + + InputManager()->UnRegister(this); + ControlManager()->Unregister(this); + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x100012a0 +MxResult Score::Create(MxDSAction& p_dsAction) +{ + MxResult result = LegoWorld::Create(p_dsAction); + + if (result == SUCCESS) { + InputManager()->SetWorld(this); + ControlManager()->Register(this); + InputManager()->Register(this); + SetIsWorldActive(FALSE); + LegoGameState* gameState = GameState(); + ScoreState* state = (ScoreState*) gameState->GetState("ScoreState"); + m_state = state ? state : (ScoreState*) gameState->CreateState("ScoreState"); + GameState()->SetCurrentArea(LegoGameState::e_infoscor); + GameState()->StopArea(LegoGameState::e_previousArea); + } + + return result; +} + +// FUNCTION: LEGO1 0x10001340 +void Score::DeleteScript() +{ + if (m_state->GetTutorialFlag()) { + MxDSAction action; + action.SetObjectId(InfoscorScript::c_iicc31in_PlayWav); + action.SetAtomId(*g_infoscorScript); + action.SetUnknown24(-2); + DeleteObject(action); + m_state->SetTutorialFlag(FALSE); + } +} + +// FUNCTION: LEGO1 0x10001410 +MxLong Score::Notify(MxParam& p_param) +{ + MxLong ret = 0; + LegoWorld::Notify(p_param); + + if (m_worldStarted) { + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationStartAction: + Paint(); + ret = 1; + break; + case c_notificationEndAction: + ret = FUN_10001510((MxEndActionNotificationParam&) p_param); + break; + case c_notificationKeyPress: + if (((LegoEventNotificationParam&) p_param).GetKey() == VK_SPACE) { + DeleteScript(); + } + ret = 1; + break; + case c_notificationClick: + ret = FUN_100016d0((LegoControlManagerEvent&) p_param); + break; + case c_notificationTransitioned: + DeleteObjects(g_infoscorScript, InfoscorScript::c_LegoBox1_Flc, InfoscorScript::c_LegoBox3_Flc); + if (m_destLocation) { + GameState()->SwitchArea(m_destLocation); + } + ret = 1; + break; + } + } + + return ret; +} + +// FUNCTION: LEGO1 0x10001510 +MxLong Score::FUN_10001510(MxEndActionNotificationParam& p_param) +{ + MxDSAction* action = p_param.GetAction(); + + if (m_atom == action->GetAtomId()) { + switch (action->GetObjectId()) { + case InfoscorScript::c_GoTo_HistBook: + m_destLocation = LegoGameState::e_histbook; + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case InfoscorScript::c_iicc31in_PlayWav: + PlayMusic(JukeboxScript::c_InformationCenter_Music); + m_state->SetTutorialFlag(FALSE); + break; + } + } + + return 1; +} + +// FUNCTION: LEGO1 0x10001580 +void Score::ReadyWorld() +{ + LegoWorld::ReadyWorld(); + + MxDSAction action; + action.SetObjectId(InfoscorScript::c_nin001pr_RunAnim); + action.SetAtomId(m_atom); + action.SetUnknown84(this); + Start(&action); + + if (m_state->GetTutorialFlag()) { + MxDSAction action; + action.SetObjectId(InfoscorScript::c_iicc31in_PlayWav); + action.SetAtomId(*g_infoscorScript); + Start(&action); + } + else { + PlayMusic(JukeboxScript::c_InformationCenter_Music); + } + + FUN_10015820(FALSE, LegoOmni::c_disableInput | LegoOmni::c_disable3d | LegoOmni::c_clearScreen); +} + +// FUNCTION: LEGO1 0x100016d0 +MxLong Score::FUN_100016d0(LegoControlManagerEvent& p_param) +{ + MxS16 unk0x28 = p_param.GetUnknown0x28(); + + if (unk0x28 == 1 || p_param.GetClickedObjectId() == InfoscorScript::c_LegoBox_Ctl) { + switch (p_param.GetClickedObjectId()) { + case InfoscorScript::c_LeftArrow_Ctl: + m_destLocation = LegoGameState::e_infomain; + DeleteScript(); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case InfoscorScript::c_RightArrow_Ctl: + m_destLocation = LegoGameState::e_infodoor; + DeleteScript(); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + break; + case InfoscorScript::c_Book_Ctl: { + InputManager()->DisableInputProcessing(); + DeleteScript(); + + MxDSAction action; + action.SetObjectId(InfoscorScript::c_GoTo_HistBook); + action.SetAtomId(*g_infoscorScript); + Start(&action); + break; + } + case InfoscorScript::c_LegoBox_Ctl: { + switch (unk0x28) { + case 1: { + MxDSAction action; + action.SetObjectId(InfoscorScript::c_LegoBox1_Flc); + action.SetAtomId(*g_infoscorScript); + Start(&action); + break; + } + case 2: { + MxDSAction action; + action.SetObjectId(InfoscorScript::c_LegoBox2_Flc); + action.SetAtomId(*g_infoscorScript); + Start(&action); + break; + } + case 3: { + MxDSAction action; + action.SetObjectId(InfoscorScript::c_LegoBox3_Flc); + action.SetAtomId(*g_infoscorScript); + Start(&action); + break; + } + } + break; + } + } + } + + return 1; +} + +// FUNCTION: LEGO1 0x10001980 +void Score::Enable(MxBool p_enable) +{ + LegoWorld::Enable(p_enable); + + if (p_enable) { + InputManager()->SetWorld(this); + SetIsWorldActive(FALSE); + } + else if (InputManager()->GetWorld() == this) { + InputManager()->ClearWorld(); + } +} + +// FUNCTION: LEGO1 0x100019d0 +// FUNCTION: BETA10 0x100f47d8 +void Score::Paint() +{ + LegoTextureInfo* cube = TextureContainer()->Get("bigcube.gif"); + + if (cube != NULL) { + JetskiRaceState* jetskiRaceState = (JetskiRaceState*) GameState()->GetState("JetskiRaceState"); + CarRaceState* carRaceState = (CarRaceState*) GameState()->GetState("CarRaceState"); + TowTrackMissionState* towTrackMissionState = + (TowTrackMissionState*) GameState()->GetState("TowTrackMissionState"); + PizzaMissionState* pizzaMissionState = (PizzaMissionState*) GameState()->GetState("PizzaMissionState"); + AmbulanceMissionState* ambulanceMissionState = + (AmbulanceMissionState*) GameState()->GetState("AmbulanceMissionState"); + + DDSURFACEDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (cube->m_surface->Lock(NULL, &desc, 0, NULL) == DD_OK) { + if (desc.lPitch != desc.dwWidth) { + cube->m_surface->Unlock(desc.lpSurface); + return; + } + + m_surface = (MxU8*) desc.lpSurface; + + for (MxU8 actor = 1; actor <= 5; actor++) { + MxU16 score; + + score = carRaceState ? carRaceState->GetState(actor)->GetScore() : 0; + FillArea(0, actor - 1, score); + + score = jetskiRaceState ? jetskiRaceState->GetState(actor)->GetScore() : 0; + FillArea(1, actor - 1, score); + + score = pizzaMissionState ? pizzaMissionState->GetScore(actor) : 0; + FillArea(2, actor - 1, score); + + score = towTrackMissionState ? towTrackMissionState->GetScore(actor) : 0; + FillArea(3, actor - 1, score); + + score = ambulanceMissionState ? ambulanceMissionState->GetScore(actor) : 0; + FillArea(4, actor - 1, score); + } + + cube->m_surface->Unlock(desc.lpSurface); + cube->m_texture->Changed(TRUE, FALSE); + m_surface = NULL; + } + } +} + +// FUNCTION: LEGO1 0x10001d20 +// FUNCTION: BETA10 0x100f4a52 +void Score::FillArea(MxU32 i_activity, MxU32 i_actor, MxS16 score) +{ + MxS32 local3c[] = {0x2b00, 0x5700, 0x8000, 0xab00, 0xd600}; + MxS32 local14[] = {0x2a, 0x27, 0x29, 0x29, 0x2a}; + MxS32 local50[] = {0x2f, 0x56, 0x81, 0xaa, 0xd4}; + MxS32 local28[] = {0x25, 0x29, 0x27, 0x28, 0x28}; + MxS32 local60[] = {0x11, 0x0f, 0x08, 0x05}; + + MxU8* ptr = m_surface + local3c[i_actor] + local50[i_activity]; + MxS32 val = local60[score]; + MxS32 size = local28[i_activity]; + + for (MxS32 i = 0; i < local14[i_actor]; i++) { + memset(ptr, val, size); + ptr += 0x100; + } +} + +// FUNCTION: LEGO1 0x10001e40 +MxBool Score::VTable0x64() +{ + DeleteScript(); + m_destLocation = LegoGameState::e_infomain; + return TRUE; +} diff --git a/LEGO1/lego/sources/3dmanager/lego3dmanager.cpp b/LEGO1/lego/sources/3dmanager/lego3dmanager.cpp new file mode 100644 index 00000000..1781870a --- /dev/null +++ b/LEGO1/lego/sources/3dmanager/lego3dmanager.cpp @@ -0,0 +1,105 @@ +// Lego3DManager.cpp : implementation file +// +#include "lego3dmanager.h" + +#include "decomp.h" +#include "viewmanager/viewlodlist.h" +#include "viewmanager/viewmanager.h" + +DECOMP_SIZE_ASSERT(Lego3DManager, 0x10); + +////////////////////////////////////////////////////////////////////////////// + +// FUNCTION: LEGO1 0x100ab2d0 +BOOL InitializeCreateStruct( + TglSurface::CreateStruct& rTglSurfaceCreateStruct, + const Lego3DManager::CreateStruct& rCreateStruct +) +{ + // initializes a TglSurface::CreateStruct from a Lego3DManager::CreateStruct + rTglSurfaceCreateStruct.m_pDriverGUID = rCreateStruct.m_pDriverGUID; + rTglSurfaceCreateStruct.m_hWnd = rCreateStruct.m_hWnd; + rTglSurfaceCreateStruct.m_pDirectDraw = rCreateStruct.m_pDirectDraw; + rTglSurfaceCreateStruct.m_pFrontBuffer = rCreateStruct.m_pFrontBuffer; + rTglSurfaceCreateStruct.m_pBackBuffer = rCreateStruct.m_pBackBuffer; + rTglSurfaceCreateStruct.m_pPalette = rCreateStruct.m_pPalette; + rTglSurfaceCreateStruct.m_isFullScreen = rCreateStruct.m_isFullScreen; + rTglSurfaceCreateStruct.m_isWideViewAngle = rCreateStruct.m_isWideViewAngle; + rTglSurfaceCreateStruct.m_direct3d = rCreateStruct.m_direct3d; + rTglSurfaceCreateStruct.m_d3dDevice = rCreateStruct.m_d3dDevice; + return TRUE; +} + +////////////////////////////////////////////////////////////////////////////// + +// FUNCTION: LEGO1 0x100ab320 +Lego3DManager::Lego3DManager() +{ + // Tgl things + m_pRenderer = 0; + + m_pLego3DView = 0; + m_pViewLODListManager = 0; +} + +// FUNCTION: LEGO1 0x100ab360 +Lego3DManager::~Lego3DManager() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100ab370 +BOOL Lego3DManager::Create(CreateStruct& rCreateStruct) +{ + TglSurface::CreateStruct tglSurfaceCreateStruct; + BOOL result; + + assert(!m_pViewLODListManager); + assert(!m_pRenderer); + assert(!m_pLego3DView); + + m_pViewLODListManager = new ViewLODListManager; + assert(m_pViewLODListManager); + + m_pRenderer = Tgl::CreateRenderer(); + assert(m_pRenderer); + + m_pLego3DView = new Lego3DView; + + result = InitializeCreateStruct(tglSurfaceCreateStruct, rCreateStruct); + assert(result); + + result = m_pLego3DView->Create(tglSurfaceCreateStruct, m_pRenderer); + assert(result); + + return result; +} + +// FUNCTION: LEGO1 0x100ab460 +void Lego3DManager::Destroy() +{ + delete m_pLego3DView; + m_pLego3DView = 0; + + delete m_pRenderer; + m_pRenderer = 0; + + delete m_pViewLODListManager; + m_pViewLODListManager = 0; +} + +// FUNCTION: LEGO1 0x100ab4b0 +double Lego3DManager::Render(double p_und) +{ + assert(m_pLego3DView); + + return m_pLego3DView->Render(p_und); +} + +// FUNCTION: LEGO1 0x100ab4d0 +int Lego3DManager::SetFrustrum(float p_fov, float p_front, float p_back) +{ + m_pLego3DView->GetView()->SetFrustrum(p_front, p_back, p_fov); + m_pLego3DView->GetViewManager()->SetFrustrum(p_fov, p_front, p_back); + return 0; +} diff --git a/LEGO1/lego/sources/3dmanager/lego3dmanager.h b/LEGO1/lego/sources/3dmanager/lego3dmanager.h new file mode 100644 index 00000000..82f4e4a3 --- /dev/null +++ b/LEGO1/lego/sources/3dmanager/lego3dmanager.h @@ -0,0 +1,126 @@ +#ifndef _Lego3DManager_h +#define _Lego3DManager_h + +#include "assert.h" +#include "lego3dview.h" + +namespace Tgl +{ +class Renderer; +class Group; +} // namespace Tgl + +class ViewROI; + +// ??? for now +class ViewLODListManager; + +///////////////////////////////////////////////////////////////////////////// +// +// Lego3DManager + +// VTABLE: LEGO1 0x100dbfa4 +// SIZE 0x10 +class Lego3DManager { +public: + // SIZE 0x28 + struct CreateStruct { + const GUID* m_pDriverGUID; // 0x00 + HWND m_hWnd; // 0x04 + IDirectDraw* m_pDirectDraw; // 0x08 + IDirectDrawSurface* m_pFrontBuffer; // 0x0c + IDirectDrawSurface* m_pBackBuffer; // 0x10 + IDirectDrawPalette* m_pPalette; // 0x14 + BOOL m_isFullScreen; // 0x18 + BOOL m_isWideViewAngle; // 0x1c + IDirect3D2* m_direct3d; // 0x20 + IDirect3DDevice2* m_d3dDevice; // 0x24 + }; + +public: + Lego3DManager(); + virtual ~Lego3DManager(); + + BOOL Create(CreateStruct&); + void Destroy(); + + BOOL Add(ViewROI&); + BOOL Remove(ViewROI&); + BOOL Moved(ViewROI&); + BOOL SetPointOfView(ViewROI&); + + double Render(double p_und); + + int SetFrustrum(float p_fov, float p_front, float p_back); + + Tgl::Renderer* GetRenderer(); + Tgl::Group* GetScene(); + Lego3DView* GetLego3DView(); + // ??? for now + ViewLODListManager* GetViewLODListManager(); + + // SYNTHETIC: LEGO1 0x100ab340 + // Lego3DManager::`scalar deleting destructor' + +private: + Tgl::Renderer* m_pRenderer; // 0x04 + + Lego3DView* m_pLego3DView; // 0x08 + ViewLODListManager* m_pViewLODListManager; // 0x0c +}; + +///////////////////////////////////////////////////////////////////////////// +// +// Lego3DManager implementaion + +inline BOOL Lego3DManager::Add(ViewROI& rROI) +{ + assert(m_pLego3DView); + + return m_pLego3DView->Add(rROI); +} + +inline BOOL Lego3DManager::Remove(ViewROI& rROI) +{ + assert(m_pLego3DView); + + return m_pLego3DView->Remove(rROI); +} + +inline BOOL Lego3DManager::SetPointOfView(ViewROI& rROI) +{ + assert(m_pLego3DView); + + return m_pLego3DView->SetPointOfView(rROI); +} + +inline BOOL Lego3DManager::Moved(ViewROI& rROI) +{ + assert(m_pLego3DView); + + return m_pLego3DView->Moved(rROI); +} + +inline Tgl::Renderer* Lego3DManager::GetRenderer() +{ + return m_pRenderer; +} + +inline Tgl::Group* Lego3DManager::GetScene() +{ + assert(m_pLego3DView); + + return m_pLego3DView->GetScene(); +} + +inline Lego3DView* Lego3DManager::GetLego3DView() +{ + return m_pLego3DView; +} + +inline ViewLODListManager* Lego3DManager::GetViewLODListManager() +{ + return m_pViewLODListManager; +} + +#endif /* _Lego3DManager_h */ diff --git a/LEGO1/lego/sources/3dmanager/lego3dview.cpp b/LEGO1/lego/sources/3dmanager/lego3dview.cpp new file mode 100644 index 00000000..e895e378 --- /dev/null +++ b/LEGO1/lego/sources/3dmanager/lego3dview.cpp @@ -0,0 +1,156 @@ +// Lego3DView.cpp : implementation file +// + +#include "lego3dview.h" + +#include "viewmanager/viewmanager.h" + +DECOMP_SIZE_ASSERT(Lego3DView, 0xa8) + +///////////////////////////////////////////////////////////////////////////// +// Lego3DView + +// FUNCTION: LEGO1 0x100aae90 +Lego3DView::Lego3DView() +{ + m_pViewManager = 0; + m_previousRenderTime = 0; + m_unk0x98 = 0; + m_pPointOfView = 0; +} + +// FUNCTION: LEGO1 0x100aaf30 +Lego3DView::~Lego3DView() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100aaf90 +BOOL Lego3DView::Create(const TglSurface::CreateStruct& rCreateStruct, Tgl::Renderer* pRenderer) +{ + double viewAngle = 45; + if (rCreateStruct.m_isWideViewAngle) { + viewAngle = 90; + } + + float frontClippingDistance = 0.1; + float backClippingDistance = 500; + + if (!LegoView1::Create(rCreateStruct, pRenderer)) { + return FALSE; + } + + assert(GetView()); + GetView()->SetFrustrum(frontClippingDistance, backClippingDistance, viewAngle); + + assert(GetScene()); + assert(!m_pViewManager); + + m_pViewManager = new ViewManager(pRenderer, GetScene(), 0); + m_pViewManager->SetResolution(GetWidth(), GetHeight()); + m_pViewManager->SetFrustrum(viewAngle, frontClippingDistance, backClippingDistance); + m_previousRenderTime = 0; + m_unk0x98 = 0; + + // // NOTE: a derived class must inform view manager when it configures + // // its (Tgl) view: calling Tgl::View::SetFrustrum() should be + // // accompanied by calling ViewManager::SetFrustrum() + + return TRUE; +} + +// FUNCTION: LEGO1 0x100ab0b0 +void Lego3DView::Destroy() +{ + if (m_pPointOfView) { + m_pPointOfView = 0; + m_pViewManager->SetPOVSource(0); + } + + delete m_pViewManager; + m_pViewManager = 0; + + LegoView1::Destroy(); +} + +// FUNCTION: LEGO1 0x100ab100 +BOOL Lego3DView::Add(ViewROI& rROI) +{ + assert(m_pViewManager); + + m_pViewManager->Add(&rROI); + + return TRUE; +} + +// FUNCTION: LEGO1 0x100ab170 +BOOL Lego3DView::Remove(ViewROI& rROI) +{ + assert(m_pViewManager); + + m_pViewManager->Remove(&rROI); + + if (m_pPointOfView == &rROI) { + m_pPointOfView = 0; + m_pViewManager->SetPOVSource(0); + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x100ab1b0 +BOOL Lego3DView::SetPointOfView(ViewROI& rROI) +{ + Tgl::FloatMatrix4 transformation; + Matrix4 mat(transformation); + Tgl::Result result; + + m_pPointOfView = &rROI; + + assert(m_pViewManager); + m_pViewManager->SetPOVSource(m_pPointOfView); + + assert(GetCamera()); + rROI.GetLocalTransform(mat); + result = GetCamera()->SetTransformation(transformation); + assert(Tgl::Succeeded(result)); + + return TRUE; +} + +// FUNCTION: LEGO1 0x100ab210 +BOOL Lego3DView::Moved(ViewROI& rROI) +{ + assert(m_pViewManager); + + if (m_pPointOfView == &rROI) { + // move the camera + Tgl::FloatMatrix4 transformation; + Matrix4 mat(transformation); + Tgl::Result result; + + assert(GetCamera()); + + rROI.GetLocalTransform(mat); + result = GetCamera()->SetTransformation(transformation); + assert(Tgl::Succeeded(result)); + m_pViewManager->SetPOVSource(&rROI); + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x100ab270 +double Lego3DView::Render(double p_und) +{ + assert(m_pViewManager); + m_pViewManager->Update(m_previousRenderTime, p_und); + m_previousRenderTime = TglSurface::Render(); + return m_previousRenderTime; +} + +// FUNCTION: LEGO1 0x100ab2b0 +ViewROI* Lego3DView::Pick(unsigned long x, unsigned long y) +{ + return m_pViewManager->Pick(GetView(), x, y); +} diff --git a/LEGO1/lego/sources/3dmanager/lego3dview.h b/LEGO1/lego/sources/3dmanager/lego3dview.h new file mode 100644 index 00000000..6c8930e9 --- /dev/null +++ b/LEGO1/lego/sources/3dmanager/lego3dview.h @@ -0,0 +1,59 @@ +#ifndef _Lego3DView_h +#define _Lego3DView_h + +#include "decomp.h" +#include "legoview1.h" + +class ViewManager; +class ViewROI; + +///////////////////////////////////////////////////////////////////////////// +// Lego3DView + +// VTABLE: LEGO1 0x100dbf78 +// SIZE 0xa8 +class Lego3DView : public LegoView1 { +public: + Lego3DView(); + ~Lego3DView() override; + + BOOL Create(const CreateStruct&, Tgl::Renderer*); + void Destroy() override; // vtable+0x08 + + BOOL Add(ViewROI&); + BOOL Remove(ViewROI&); + BOOL Moved(ViewROI&); + BOOL SetPointOfView(ViewROI&); + + double Render(double p_und); + + ViewROI* Pick(unsigned long x, unsigned long y); + + ViewROI* GetPointOfView(); + ViewManager* GetViewManager(); + +private: + ViewManager* m_pViewManager; // 0x88 + double m_previousRenderTime; // 0x90 + double m_unk0x98; // 0x98 + ViewROI* m_pPointOfView; // 0xa0 +}; + +// SYNTHETIC: LEGO1 0x100aaf10 +// Lego3DView::`scalar deleting destructor' + +///////////////////////////////////////////////////////////////////////////// +// +// Lego3DView implementation + +inline ViewManager* Lego3DView::GetViewManager() +{ + return m_pViewManager; +} + +inline ViewROI* Lego3DView::GetPointOfView() +{ + return m_pPointOfView; +} + +#endif /* _Lego3DView_h */ diff --git a/LEGO1/lego/sources/3dmanager/legoview1.cpp b/LEGO1/lego/sources/3dmanager/legoview1.cpp new file mode 100644 index 00000000..cfc70a3b --- /dev/null +++ b/LEGO1/lego/sources/3dmanager/legoview1.cpp @@ -0,0 +1,242 @@ +// LegoView1.cpp : implementation file +// + +#include "legoview1.h" + +#include "decomp.h" +#include "mxgeometry/mxgeometry3d.h" +#include "mxgeometry/mxmatrix.h" +#include "realtime/realtime.h" + +#include + +DECOMP_SIZE_ASSERT(LegoView, 0x78); +DECOMP_SIZE_ASSERT(LegoView1, 0x88); + +// GLOBAL: LEGO1 0x101013e4 +float g_sunLightRGB = 1.0; + +// GLOBAL: LEGO1 0x101013e8 +float g_directionalLightRGB = 1.0; + +// GLOBAL: LEGO1 0x101013ec +float g_ambientLightRGB = 0.3; + +///////////////////////////////////////////////////////////////////////////// +// LegoView + +// FUNCTION: LEGO1 0x100ab510 +// FUNCTION: BETA10 0x1017bb90 +LegoView::LegoView() +{ + m_pScene = 0; + m_pCamera = 0; +} + +// FUNCTION: LEGO1 0x100ab5a0 +// FUNCTION: BETA10 0x1017bc19 +LegoView::~LegoView() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100ab600 +// FUNCTION: BETA10 0x1017bc89 +BOOL LegoView::Create(const TglSurface::CreateStruct& rCreateStruct, Tgl::Renderer* pRenderer) +{ + float viewAngle = 45; + + float frontClippingDistance = 0.1; + float backClippingDistance = 500; + + assert(!m_pScene); + assert(!m_pCamera); + assert(pRenderer); + + if (rCreateStruct.m_isWideViewAngle) { + viewAngle = 90; + } + + m_pScene = pRenderer->CreateGroup(); + assert(m_pScene); + // TglSurface::Create() calls CreateView(), and we need the camera in + // CreateView(), so create camera before calling TglSurface::Create() + m_pCamera = pRenderer->CreateCamera(); + assert(m_pCamera); + + if (!TglSurface::Create(rCreateStruct, pRenderer, m_pScene)) { + delete m_pScene; + m_pScene = 0; + + delete m_pCamera; + m_pCamera = 0; + + return FALSE; + } + + assert(GetView()); + GetView()->SetFrustrum(frontClippingDistance, backClippingDistance, viewAngle); + GetView()->SetBackgroundColor(.223, .639, .851); + + return TRUE; +} + +// FUNCTION: LEGO1 0x100ab6c0 +// FUNCTION: BETA10 0x1017befd +Tgl::View* LegoView::CreateView(Tgl::Renderer* pRenderer, Tgl::Device* pDevice) +{ + assert(pRenderer); + assert(pDevice); + + return pRenderer->CreateView(pDevice, m_pCamera, 0, 0, GetWidth(), GetHeight()); +} + +// FUNCTION: LEGO1 0x100ab6f0 +// FUNCTION: BETA10 0x1017bf96 +void LegoView::Destroy() +{ + delete m_pScene; + m_pScene = 0; + + delete m_pCamera; + m_pCamera = 0; + + TglSurface::Destroy(); +} + +///////////////////////////////////////////////////////////////////////////// +// LegoView1 + +// FUNCTION: LEGO1 0x100ab730 +// FUNCTION: BETA10 0x1017c028 +LegoView1::LegoView1() +{ + m_pSunLight = 0; + m_pDirectionalLight = 0; + m_pAmbientLight = 0; +} + +// FUNCTION: LEGO1 0x100ab7c0 +// FUNCTION: BETA10 0x1017c0be +LegoView1::~LegoView1() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100ab820 +// FUNCTION: BETA10 0x1017c12e +BOOL LegoView1::AddLightsToViewport() +{ + assert(GetView()); + GetView()->Add(m_pSunLight); + GetView()->Add(m_pDirectionalLight); + GetView()->Add(m_pAmbientLight); + return TRUE; +} + +// FUNCTION: LEGO1 0x100ab860 +// FUNCTION: BETA10 0x1017c1ea +BOOL LegoView1::Create(const TglSurface::CreateStruct& rCreateStruct, Tgl::Renderer* pRenderer) +{ + if (!LegoView::Create(rCreateStruct, pRenderer)) { + return FALSE; + } + + // lights + m_pSunLight = pRenderer->CreateLight(Tgl::Point, g_sunLightRGB, g_sunLightRGB, g_sunLightRGB); + m_pDirectionalLight = + pRenderer->CreateLight(Tgl::Directional, g_directionalLightRGB, g_directionalLightRGB, g_directionalLightRGB); + m_pAmbientLight = pRenderer->CreateLight(Tgl::Ambient, g_ambientLightRGB, g_ambientLightRGB, g_ambientLightRGB); + + Mx3DPointFloat position(0.0, 0.0, 0.0); + Mx3DPointFloat direction(0.0, -1.0, 0.0); + Mx3DPointFloat up(1.0, 0.0, 0.0); + + Tgl::FloatMatrix4 matrix; + Matrix4 in(matrix); + MxMatrix transform; + + CalcLocalTransform(position, direction, up, transform); + SETMAT4(in, transform); + m_pDirectionalLight->SetTransformation(matrix); + + position[0] = 0, position[1] = 150, position[2] = -150; + CalcLocalTransform(position, direction, up, transform); + SETMAT4(in, transform); + m_pSunLight->SetTransformation(matrix); + + // assert(GetView()); + + return AddLightsToViewport(); +} + +// FUNCTION: LEGO1 0x100abad0 +// FUNCTION: BETA10 0x1017c912 +void LegoView1::Destroy() +{ + if (m_pSunLight) { + GetView()->Remove(m_pSunLight); + delete m_pSunLight; + m_pSunLight = 0; + } + + if (m_pDirectionalLight) { + GetView()->Remove(m_pDirectionalLight); + delete m_pDirectionalLight; + m_pDirectionalLight = 0; + } + + if (m_pAmbientLight) { + GetView()->Remove(m_pAmbientLight); + delete m_pAmbientLight; + m_pAmbientLight = 0; + } + + LegoView::Destroy(); +} + +// FUNCTION: LEGO1 0x100abb60 +// FUNCTION: BETA10 0x1017ca80 +void LegoView1::SetLightTransform(BOOL bDirectionalLight, Tgl::FloatMatrix4& rMatrix) +{ + Tgl::Light* pLight; + + if (bDirectionalLight == FALSE) { + pLight = m_pSunLight; + } + else { + pLight = m_pDirectionalLight; + } + + SetLightTransform(pLight, rMatrix); +} + +// FUNCTION: LEGO1 0x100abb80 +// FUNCTION: BETA10 0x1017cacf +void LegoView1::SetLightTransform(Tgl::Light* pLight, Tgl::FloatMatrix4& rMatrix) +{ + pLight->SetTransformation(rMatrix); +} + +// FUNCTION: LEGO1 0x100abba0 +// FUNCTION: BETA10 0x1017caf6 +void LegoView1::SetLightColor(BOOL bDirectionalLight, float red, float green, float blue) +{ + Tgl::Light* pLight; + + if (bDirectionalLight == FALSE) { + pLight = m_pSunLight; + } + else { + pLight = m_pDirectionalLight; + } + + SetLightColor(pLight, red, green, blue); +} + +// FUNCTION: LEGO1 0x100abbd0 +// FUNCTION: BETA10 0x1017cb4d +void LegoView1::SetLightColor(Tgl::Light* pLight, float red, float green, float blue) +{ + pLight->SetColor(red, green, blue); +} diff --git a/LEGO1/lego/sources/3dmanager/legoview1.h b/LEGO1/lego/sources/3dmanager/legoview1.h new file mode 100644 index 00000000..0c90263b --- /dev/null +++ b/LEGO1/lego/sources/3dmanager/legoview1.h @@ -0,0 +1,87 @@ +#ifndef _LegoView1_h +#define _LegoView1_h + +#include "compat.h" +#include "decomp.h" +#include "tglsurface.h" + +namespace Tgl +{ +class Camera; +class Light; +} // namespace Tgl + +///////////////////////////////////////////////////////////////////////////// +// LegoView + +// VTABLE: LEGO1 0x100dc000 +// VTABLE: BETA10 0x101c3578 +// SIZE 0x78 +class LegoView : public TglSurface { +public: + LegoView(); + ~LegoView() override; + + BOOL Create(const CreateStruct&, Tgl::Renderer*); + void Destroy() override; // vtable+0x08 + + Tgl::Group* GetScene() const; + Tgl::Camera* GetCamera() const; + +protected: + Tgl::View* CreateView(Tgl::Renderer*, Tgl::Device*) override; // vtable+0x10 + +private: + Tgl::Group* m_pScene; // 0x70 + Tgl::Camera* m_pCamera; // 0x74 +}; + +///////////////////////////////////////////////////////////////////////////// +// LegoView implementation + +inline Tgl::Group* LegoView::GetScene() const +{ + return m_pScene; +} + +inline Tgl::Camera* LegoView::GetCamera() const +{ + return m_pCamera; +} + +// SYNTHETIC: LEGO1 0x100ab580 +// SYNTHETIC: BETA10 0x1017cb80 +// LegoView::`scalar deleting destructor' + +///////////////////////////////////////////////////////////////////////////// +// LegoView1 + +// VTABLE: LEGO1 0x100dc018 +// VTABLE: BETA10 0x101c3590 +// SIZE 0x88 +class LegoView1 : public LegoView { +public: + LegoView1(); + ~LegoView1() override; + + BOOL AddLightsToViewport(); + BOOL Create(const TglSurface::CreateStruct&, Tgl::Renderer*); + void Destroy() override; // vtable+0x08 + + void SetLightTransform(BOOL bDirectionalLight, Tgl::FloatMatrix4& rMatrix); + void SetLightColor(BOOL bDirectionalLight, float red, float green, float blue); + +private: + void SetLightTransform(Tgl::Light* pLight, Tgl::FloatMatrix4& rMatrix); + void SetLightColor(Tgl::Light* pLight, float red, float green, float blue); + + Tgl::Light* m_pSunLight; // 0x78 + Tgl::Light* m_pDirectionalLight; // 0x7c + Tgl::Light* m_pAmbientLight; // 0x80 +}; + +// SYNTHETIC: LEGO1 0x100ab7a0 +// SYNTHETIC: BETA10 0x1017cc00 +// LegoView1::`scalar deleting destructor' + +#endif /* _LegoView1_h */ diff --git a/LEGO1/lego/sources/3dmanager/tglsurface.cpp b/LEGO1/lego/sources/3dmanager/tglsurface.cpp new file mode 100644 index 00000000..f03206d9 --- /dev/null +++ b/LEGO1/lego/sources/3dmanager/tglsurface.cpp @@ -0,0 +1,236 @@ +// TglSurface.cpp : implementation file + +#include "tglsurface.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(TglSurface, 0x70); + +using namespace Tgl; + +///////////////////////////////////////////////////////////////////////////// +// TglSurface + +// FUNCTION: LEGO1 0x100abbf0 +// FUNCTION: BETA10 0x1017d490 +TglSurface::TglSurface() +{ + m_pRenderer = 0; + m_pDevice = 0; + m_pView = 0; + m_pScene = 0; + + m_width = 0; + m_height = 0; + + m_stopRendering = FALSE; + m_isInitialized = FALSE; + + // statistics + m_frameCount = 0; +#ifdef _DEBUG + m_triangleCount = 0; +#endif +} + +// FUNCTION: LEGO1 0x100abd60 +// FUNCTION: BETA10 0x1017d5a2 +TglSurface::~TglSurface() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100abde0 +// FUNCTION: BETA10 0x1017d647 +void TglSurface::Destroy() +{ + DestroyView(); + + delete m_pDevice; + m_pDevice = 0; + + m_pRenderer = 0; + m_pScene = 0; +} + +// ??? +// FUNCTION: LEGO1 0x100abe10 +// FUNCTION: BETA10 0x1017d6b0 +int GetBitsPerPixel(IDirectDrawSurface* pSurface) +{ + DDPIXELFORMAT pixelFormat; + HRESULT result; + + memset(&pixelFormat, 0, sizeof(pixelFormat)); + pixelFormat.dwSize = sizeof(pixelFormat); + + result = pSurface->GetPixelFormat(&pixelFormat); + assert(result == DD_OK); + assert(pixelFormat.dwFlags & DDPF_RGB); + + return pixelFormat.dwRGBBitCount; +} + +// FUNCTION: LEGO1 0x100abe50 +// FUNCTION: BETA10 0x1017d742 +BOOL TglSurface::Create(const CreateStruct& rCreateStruct, Renderer* pRenderer, Group* pScene) +{ + DeviceDirect3DCreateData createData = {rCreateStruct.m_direct3d, rCreateStruct.m_d3dDevice}; + int bitsPerPixel = GetBitsPerPixel(rCreateStruct.m_pFrontBuffer); + + ColorModel colorModel = Ramp; + ShadingModel shadingModel = Gouraud; + int shadeCount = 32; + BOOL dither = TRUE; + int textureShadeCount = -1; + int textureColorCount = -1; + Result result; + + m_pRenderer = pRenderer; + m_pScene = pScene; + m_pDevice = m_pRenderer->CreateDevice(createData); + + if (!m_pDevice) { + assert(0); + m_pRenderer = 0; + m_pScene = 0; + return FALSE; + } + + if (bitsPerPixel == 1) { + shadeCount = 4; + textureShadeCount = 4; + } + else if (bitsPerPixel == 8) { + shadeCount = 32; + shadeCount = 16; + dither = FALSE; + textureShadeCount = shadeCount; + textureColorCount = 256; + } + else if (bitsPerPixel == 16) { + shadeCount = 32; + dither = FALSE; + textureShadeCount = shadeCount; + textureColorCount = 256; + } + else if (bitsPerPixel >= 24) { + shadeCount = 256; + dither = FALSE; + textureShadeCount = 256; + textureColorCount = 64; + } + else { + dither = FALSE; + } + + if (textureShadeCount != -1) { + result = pRenderer->SetTextureDefaultShadeCount(textureShadeCount); + assert(Succeeded(result)); + } + if (textureColorCount != -1) { + result = pRenderer->SetTextureDefaultColorCount(textureColorCount); + assert(Succeeded(result)); + } + + result = m_pDevice->SetColorModel(colorModel); + assert(Succeeded(result)); + result = m_pDevice->SetShadingModel(shadingModel); + assert(Succeeded(result)); + result = m_pDevice->SetShadeCount(shadeCount); + assert(Succeeded(result)); + result = m_pDevice->SetDither(dither); + assert(Succeeded(result)); + + m_width = m_pDevice->GetWidth(); + m_height = m_pDevice->GetHeight(); + + m_pView = CreateView(m_pRenderer, m_pDevice); + if (!m_pView) { + delete m_pDevice; + m_pDevice = 0; + m_pRenderer = 0; + m_pScene = 0; + return FALSE; + } + + m_frameRateMeter.Reset(); + m_renderingRateMeter.Reset(); +#ifdef _DEBUG + m_triangleRateMeter.Reset(); +#endif + m_frameRateMeter.StartOperation(); + + m_isInitialized = TRUE; + + return TRUE; +} + +// FUNCTION: LEGO1 0x100ac030 +// FUNCTION: BETA10 0x1017db86 +void TglSurface::DestroyView() +{ + delete m_pView; + m_pView = 0; +} + +// FUNCTION: LEGO1 0x100ac050 +// FUNCTION: BETA10 0x1017dbd0 +double TglSurface::Render() +{ + MxStopWatch renderTimer; + + if (m_isInitialized && !m_stopRendering) { + Result result; + +#ifdef _DEBUG + m_triangleRateMeter.StartOperation(); +#endif + m_renderingRateMeter.StartOperation(); + renderTimer.Start(); + + result = m_pView->Render(m_pScene); + + renderTimer.Stop(); + assert(Succeeded(result)); + m_renderingRateMeter.EndOperation(); +#ifdef _DEBUG + m_triangleRateMeter.EndOperation(); +#endif + m_frameRateMeter.EndOperation(); + m_frameCount++; + +#ifdef _DEBUG + { +#if 0 + // FIXME: Tgl::Device::GetDrawnTriangleCount does not exist + unsigned long triangleCount = m_pDevice->GetDrawnTriangleCount(); +#else + unsigned long triangleCount = 0; +#endif + + m_triangleRateMeter.IncreaseOperationCount(triangleCount - m_triangleCount - 1); + m_triangleCount = triangleCount; + } +#endif + +#if 0 + // reset rate meters every 20 frames + if ((++m_frameCount % 20) == 0) +#else + // reset rate meters every 4 seconds + if (m_frameRateMeter.ElapsedSeconds() > 4.0) +#endif + { + m_frameRateMeter.Reset(); + m_renderingRateMeter.Reset(); +#ifdef _DEBUG + m_triangleRateMeter.Reset(); +#endif + } + + m_frameRateMeter.StartOperation(); + } + + return renderTimer.ElapsedSeconds(); +} diff --git a/LEGO1/lego/sources/3dmanager/tglsurface.h b/LEGO1/lego/sources/3dmanager/tglsurface.h new file mode 100644 index 00000000..0ee9a61c --- /dev/null +++ b/LEGO1/lego/sources/3dmanager/tglsurface.h @@ -0,0 +1,97 @@ +#ifndef _TglSurface_h +#define _TglSurface_h + +#include "mxdirectx/mxstopwatch.h" +#include "tgl/tgl.h" + +namespace Tgl +{ +class Renderer; +class Device; +class View; +class Group; +} // namespace Tgl + +///////////////////////////////////////////////////////////////////////////// +// TglSurface + +// VTABLE: LEGO1 0x100dc060 +// VTABLE: BETA10 0x101c3648 +// SIZE 0x70 +class TglSurface { +public: + // SIZE 0x28 + struct CreateStruct { + const GUID* m_pDriverGUID; // 0x00 + HWND m_hWnd; // 0x04 + IDirectDraw* m_pDirectDraw; // 0x08 + IDirectDrawSurface* m_pFrontBuffer; // 0x0c + IDirectDrawSurface* m_pBackBuffer; // 0x10 + IDirectDrawPalette* m_pPalette; // 0x14 + BOOL m_isFullScreen; // 0x18 + BOOL m_isWideViewAngle; // 0x1c + IDirect3D2* m_direct3d; // 0x20 + IDirect3DDevice2* m_d3dDevice; // 0x24 + }; + +public: + TglSurface(); + virtual ~TglSurface(); + + virtual BOOL Create(const CreateStruct&, Tgl::Renderer*, Tgl::Group* pScene); // vtable+0x04 + virtual void Destroy(); // vtable+0x08 + virtual double Render(); // render time in seconds // vtable+0x0c + + Tgl::Renderer* GetRenderer() const { return m_pRenderer; } + Tgl::Device* GetDevice() const { return m_pDevice; } + + // FUNCTION: BETA10 0x100d5570 + Tgl::View* GetView() const { return m_pView; } + Tgl::Group* GetScene() const { return m_pScene; } + + // FUNCTION: BETA10 0x1017cbc0 + unsigned long GetWidth() const { return m_width; } + + // FUNCTION: BETA10 0x1017cbe0 + unsigned long GetHeight() const { return m_height; } + + double GetRenderingRate() const { return m_renderingRateMeter.Frequency(); } + double GetFrameRate() const { return m_frameRateMeter.Frequency(); } + unsigned long GetFrameCount() const { return m_frameCount; } +#ifdef _DEBUG + double GetTriangleRate() const { return m_triangleRateMeter.Frequency(); } +#endif + +protected: + virtual Tgl::View* CreateView(Tgl::Renderer*, Tgl::Device*) = 0; // vtable+0x10 + virtual void DestroyView(); // vtable+0x14 + +private: + Tgl::Renderer* m_pRenderer; // 0x08 + Tgl::Device* m_pDevice; // 0x0c + Tgl::View* m_pView; // 0x10 + Tgl::Group* m_pScene; // 0x14 + + unsigned long m_width; // 0x18 + unsigned long m_height; // 0x1c + + BOOL m_isInitialized; // 0x20 + BOOL m_stopRendering; // 0x24 + + // statistics + MxFrequencyMeter m_renderingRateMeter; // 0x28 + MxFrequencyMeter m_frameRateMeter; // 0x48 + unsigned long m_frameCount; // 0x68 +#ifdef _DEBUG + MxFrequencyMeter m_triangleRateMeter; + unsigned long m_triangleCount; +#endif +}; + +///////////////////////////////////////////////////////////////////////////// + +// SYNTHETIC: LEGO1 0x100abcf0 +// SYNTHETIC: BETA10 0x1017de00 +// TglSurface::`scalar deleting destructor' + +#endif /* _TglSurface_h */ diff --git a/LEGO1/lego/sources/anim/legoanim.cpp b/LEGO1/lego/sources/anim/legoanim.cpp new file mode 100644 index 00000000..92de53ae --- /dev/null +++ b/LEGO1/lego/sources/anim/legoanim.cpp @@ -0,0 +1,840 @@ +#include "legoanim.h" + +#include "mxgeometry/mxmatrix.h" + +#include + +DECOMP_SIZE_ASSERT(LegoAnimKey, 0x08) +DECOMP_SIZE_ASSERT(LegoTranslationKey, 0x14) +DECOMP_SIZE_ASSERT(LegoRotationKey, 0x18) +DECOMP_SIZE_ASSERT(LegoScaleKey, 0x14) +DECOMP_SIZE_ASSERT(LegoMorphKey, 0x0c) +DECOMP_SIZE_ASSERT(LegoUnknownKey, 0x0c) +DECOMP_SIZE_ASSERT(LegoAnimNodeData, 0x34) +DECOMP_SIZE_ASSERT(LegoAnimActorEntry, 0x08) +DECOMP_SIZE_ASSERT(LegoAnimScene, 0x24) +DECOMP_SIZE_ASSERT(LegoAnim, 0x18) + +// FUNCTION: LEGO1 0x1009f000 +LegoUnknownKey::LegoUnknownKey() +{ + m_unk0x08 = 0; +} + +// FUNCTION: LEGO1 0x1009f020 +LegoResult LegoUnknownKey::Read(LegoStorage* p_storage) +{ + LegoResult result; + + if ((result = LegoAnimKey::Read(p_storage)) != SUCCESS) { + return result; + } + + result = p_storage->Read(&m_unk0x08, sizeof(m_unk0x08)); + return result == SUCCESS ? SUCCESS : result; +} + +// FUNCTION: LEGO1 0x1009f0a0 +LegoAnimScene::LegoAnimScene() +{ + m_unk0x00 = 0; + m_unk0x04 = NULL; + m_unk0x08 = 0; + m_unk0x0c = NULL; + m_unk0x10 = 0; + m_unk0x14 = NULL; + m_unk0x18 = 0; + m_unk0x1c = 0; + m_unk0x20 = 0; +} + +// FUNCTION: LEGO1 0x1009f0d0 +LegoAnimScene::~LegoAnimScene() +{ + if (m_unk0x04 != NULL) { + delete[] m_unk0x04; + m_unk0x04 = NULL; + } + + if (m_unk0x0c != NULL) { + delete[] m_unk0x0c; + m_unk0x0c = NULL; + } + + if (m_unk0x14 != NULL) { + delete[] m_unk0x14; + m_unk0x14 = NULL; + } +} + +// FUNCTION: LEGO1 0x1009f200 +LegoResult LegoAnimScene::Read(LegoStorage* p_storage) +{ + LegoResult result; + LegoS32 i; + + if ((result = p_storage->Read(&m_unk0x00, sizeof(m_unk0x00))) != SUCCESS) { + return result; + } + + if (m_unk0x00) { + m_unk0x04 = new LegoTranslationKey[m_unk0x00]; + for (i = 0; i < m_unk0x00; i++) { + if ((result = m_unk0x04[i].Read(p_storage)) != SUCCESS) { + goto done; + } + } + } + + if ((result = p_storage->Read(&m_unk0x08, sizeof(m_unk0x08))) != SUCCESS) { + return result; + } + + if (m_unk0x08) { + m_unk0x0c = new LegoTranslationKey[m_unk0x08]; + for (i = 0; i < m_unk0x08; i++) { + if ((result = m_unk0x0c[i].Read(p_storage)) != SUCCESS) { + goto done; + } + } + } + + if ((result = p_storage->Read(&m_unk0x10, sizeof(m_unk0x10))) != SUCCESS) { + return result; + } + + if (m_unk0x10) { + m_unk0x14 = new LegoUnknownKey[m_unk0x10]; + for (i = 0; i < m_unk0x10; i++) { + if ((result = m_unk0x14[i].Read(p_storage)) != SUCCESS) { + goto done; + } + } + } + + return SUCCESS; + +done: + if (m_unk0x04 != NULL) { + delete[] m_unk0x04; + m_unk0x00 = 0; + m_unk0x04 = NULL; + } + + if (m_unk0x0c != NULL) { + delete[] m_unk0x0c; + m_unk0x08 = 0; + m_unk0x0c = NULL; + } + + if (m_unk0x14 != NULL) { + delete[] m_unk0x14; + m_unk0x10 = 0; + m_unk0x14 = NULL; + } + + return result; +} + +// STUB: LEGO1 0x1009f490 +undefined4 LegoAnimScene::FUN_1009f490(LegoFloat p_time, Matrix4& p_matrix) +{ + // TODO + return 0; +} + +// FUNCTION: LEGO1 0x1009f900 +LegoAnimKey::LegoAnimKey() +{ + m_flags = 0; + m_time = 0; +} + +// FUNCTION: LEGO1 0x1009f910 +LegoResult LegoAnimKey::Read(LegoStorage* p_storage) +{ + LegoResult result; + LegoS32 und; + + if ((result = p_storage->Read(&und, sizeof(und))) != SUCCESS) { + return result; + } + + m_flags = (LegoU32) und >> 24; + m_time = und & 0xffffff; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1009f990 +LegoTranslationKey::LegoTranslationKey() +{ + m_x = 0.0F; + m_y = 0.0F; + m_z = 0.0F; +} + +// FUNCTION: LEGO1 0x1009f9b0 +LegoResult LegoTranslationKey::Read(LegoStorage* p_storage) +{ + LegoResult result; + + if ((result = LegoAnimKey::Read(p_storage)) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_x, sizeof(m_x))) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_y, sizeof(m_y))) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_z, sizeof(m_z))) != SUCCESS) { + return result; + } + + if (m_x > 1e-05F || m_x < -1e-05F || m_y > 1e-05F || m_y < -1e-05F || m_z > 1e-05F || m_z < -1e-05F) { + m_flags |= c_bit1; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1009faa0 +LegoRotationKey::LegoRotationKey() +{ + m_angle = 1.0F; + m_x = 0.0F; + m_y = 0.0F; + m_z = 0.0F; +} + +// FUNCTION: LEGO1 0x1009fac0 +LegoResult LegoRotationKey::Read(LegoStorage* p_storage) +{ + LegoResult result; + + if ((result = LegoAnimKey::Read(p_storage)) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_angle, sizeof(m_angle))) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_x, sizeof(m_x))) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_y, sizeof(m_y))) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_z, sizeof(m_z))) != SUCCESS) { + return result; + } + + if (m_angle != 1.0F) { + m_flags |= c_bit1; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1009fba0 +LegoScaleKey::LegoScaleKey() +{ + m_x = 1.0F; + m_y = 1.0F; + m_z = 1.0F; +} + +// FUNCTION: LEGO1 0x1009fbc0 +LegoResult LegoScaleKey::Read(LegoStorage* p_storage) +{ + LegoResult result; + + if ((result = LegoAnimKey::Read(p_storage)) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_x, sizeof(m_x))) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_y, sizeof(m_y))) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&m_z, sizeof(m_z))) != SUCCESS) { + return result; + } + + if (m_x > 1.00001 || m_x < 0.99999 || m_y > 1.00001 || m_y < 0.99999 || m_z > 1.00001 || m_z < 0.99999) { + m_flags |= c_bit1; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1009fcf0 +LegoAnimNodeData::LegoAnimNodeData() +{ + m_numTranslationKeys = 0; + m_numRotationKeys = 0; + m_numScaleKeys = 0; + m_numMorphKeys = 0; + + m_name = NULL; + m_translationKeys = NULL; + m_unk0x20 = 0; + m_rotationKeys = NULL; + m_unk0x22 = 0; + m_scaleKeys = NULL; + m_morphKeys = NULL; + m_translationIndex = 0; + m_rotationIndex = 0; + m_scaleIndex = 0; + m_morphIndex = 0; +} + +// FUNCTION: LEGO1 0x1009fda0 +LegoAnimNodeData::~LegoAnimNodeData() +{ + if (m_name) { + delete[] m_name; + } + if (m_translationKeys) { + delete[] m_translationKeys; + } + if (m_rotationKeys) { + delete[] m_rotationKeys; + } + if (m_scaleKeys) { + delete[] m_scaleKeys; + } + if (m_morphKeys) { + delete[] m_morphKeys; + } +} + +// FUNCTION: LEGO1 0x1009fe60 +LegoResult LegoAnimNodeData::Read(LegoStorage* p_storage) +{ + LegoResult result; + + LegoU32 length; + if ((result = p_storage->Read(&length, sizeof(length))) != SUCCESS) { + return result; + } + + if (m_name) { + delete[] m_name; + m_name = NULL; + } + if (length) { + m_name = new LegoChar[length + 1]; + if ((result = p_storage->Read(m_name, length)) != SUCCESS) { + return result; + } + m_name[length] = '\0'; + } + + LegoU32 i; + + if ((result = p_storage->Read(&m_numTranslationKeys, sizeof(m_numTranslationKeys))) != SUCCESS) { + return result; + } + if (m_translationKeys) { + delete[] m_translationKeys; + m_translationKeys = NULL; + } + if (m_numTranslationKeys) { + m_translationKeys = new LegoTranslationKey[m_numTranslationKeys]; + for (i = 0; i < m_numTranslationKeys; i++) { + if ((result = m_translationKeys[i].Read(p_storage)) != SUCCESS) { + return result; + } + } + } + + if ((result = p_storage->Read(&m_numRotationKeys, sizeof(m_numRotationKeys))) != SUCCESS) { + return result; + } + if (m_rotationKeys) { + delete[] m_rotationKeys; + m_rotationKeys = NULL; + } + if (m_numRotationKeys) { + m_rotationKeys = new LegoRotationKey[m_numRotationKeys]; + for (i = 0; i < m_numRotationKeys; i++) { + if ((result = m_rotationKeys[i].Read(p_storage)) != SUCCESS) { + return result; + } + } + } + + if ((result = p_storage->Read(&m_numScaleKeys, sizeof(m_numScaleKeys))) != SUCCESS) { + return result; + } + if (m_scaleKeys) { + delete[] m_scaleKeys; + m_scaleKeys = NULL; + } + if (m_numScaleKeys) { + m_scaleKeys = new LegoScaleKey[m_numScaleKeys]; + for (i = 0; i < m_numScaleKeys; i++) { + if ((result = m_scaleKeys[i].Read(p_storage)) != SUCCESS) { + return result; + } + } + } + + if ((result = p_storage->Read(&m_numMorphKeys, sizeof(m_numMorphKeys))) != SUCCESS) { + return result; + } + if (m_morphKeys) { + delete[] m_morphKeys; + m_morphKeys = NULL; + } + if (m_numMorphKeys) { + m_morphKeys = new LegoMorphKey[m_numMorphKeys]; + for (i = 0; i < m_numMorphKeys; i++) { + if ((result = m_morphKeys[i].Read(p_storage)) != SUCCESS) { + return result; + } + } + } + + return SUCCESS; +} + +// STUB: LEGO1 0x100a01e0 +LegoResult LegoAnimNodeData::Write(LegoStorage* p_storage) +{ + // TODO + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100a03c0 +LegoResult LegoAnimNodeData::CreateLocalTransform(LegoFloat p_time, Matrix4& p_matrix) +{ + LegoU32 index; + + if (m_scaleKeys != NULL) { + index = GetScaleIndex(); + GetScale(m_numScaleKeys, m_scaleKeys, p_time, p_matrix, index); + SetScaleIndex(index); + + if (m_rotationKeys != NULL) { + MxMatrix a, b; + a.SetIdentity(); + + index = GetRotationIndex(); + GetRotation(m_numRotationKeys, m_rotationKeys, p_time, a, index); + SetRotationIndex(index); + + b = p_matrix; + p_matrix.Product(b, a); + } + } + else if (m_rotationKeys != NULL) { + index = GetRotationIndex(); + GetRotation(m_numRotationKeys, m_rotationKeys, p_time, p_matrix, index); + SetRotationIndex(index); + } + + if (m_translationKeys != NULL) { + index = GetTranslationIndex(); + GetTranslation(m_numTranslationKeys, m_translationKeys, p_time, p_matrix, index); + SetTranslationIndex(index); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100a0600 +inline void LegoAnimNodeData::GetTranslation( + LegoU16 p_numTranslationKeys, + LegoTranslationKey* p_translationKeys, + LegoFloat p_time, + Matrix4& p_matrix, + LegoU32& p_old_index +) +{ + LegoU32 i, n; + LegoFloat x, y, z; + n = FindKeys( + p_time, + p_numTranslationKeys & USHRT_MAX, + p_translationKeys, + sizeof(*p_translationKeys), + i, + p_old_index + ); + + switch (n) { + case 0: + return; + case 1: + if (!p_translationKeys[i].TestBit1()) { + return; + } + + x = p_translationKeys[i].GetX(); + y = p_translationKeys[i].GetY(); + z = p_translationKeys[i].GetZ(); + break; + case 2: + if (!p_translationKeys[i].TestBit1() && !p_translationKeys[i + 1].TestBit1()) { + return; + } + + x = Interpolate( + p_time, + p_translationKeys[i], + p_translationKeys[i].GetX(), + p_translationKeys[i + 1], + p_translationKeys[i + 1].GetX() + ); + y = Interpolate( + p_time, + p_translationKeys[i], + p_translationKeys[i].GetY(), + p_translationKeys[i + 1], + p_translationKeys[i + 1].GetY() + ); + z = Interpolate( + p_time, + p_translationKeys[i], + p_translationKeys[i].GetZ(), + p_translationKeys[i + 1], + p_translationKeys[i + 1].GetZ() + ); + break; + } + + p_matrix.TranslateBy(x, y, z); +} + +// FUNCTION: LEGO1 0x100a06f0 +/*inline*/ void LegoAnimNodeData::GetRotation( + LegoU16 p_numRotationKeys, + LegoRotationKey* p_rotationKeys, + LegoFloat p_time, + Matrix4& p_matrix, + LegoU32& p_old_index +) +{ + LegoU32 i, n; + n = FindKeys(p_time, p_numRotationKeys & USHRT_MAX, p_rotationKeys, sizeof(*p_rotationKeys), i, p_old_index); + + switch (n) { + case 0: + return; + case 1: + if (p_rotationKeys[i].TestBit1()) { + p_matrix.FromQuaternion(Mx4DPointFloat( + p_rotationKeys[i].GetX(), + p_rotationKeys[i].GetY(), + p_rotationKeys[i].GetZ(), + p_rotationKeys[i].GetAngle() + )); + } + break; + case 2: + Mx4DPointFloat a; + UnknownMx4DPointFloat b; + + if (p_rotationKeys[i].TestBit1() || p_rotationKeys[i + 1].TestBit1()) { + a[0] = p_rotationKeys[i].GetX(); + a[1] = p_rotationKeys[i].GetY(); + a[2] = p_rotationKeys[i].GetZ(); + a[3] = p_rotationKeys[i].GetAngle(); + + if (p_rotationKeys[i + 1].TestBit3()) { + p_matrix.FromQuaternion(a); + return; + } + + Mx4DPointFloat c; + if (p_rotationKeys[i + 1].TestBit2()) { + c[0] = -p_rotationKeys[i + 1].GetX(); + c[1] = -p_rotationKeys[i + 1].GetY(); + c[2] = -p_rotationKeys[i + 1].GetZ(); + c[3] = -p_rotationKeys[i + 1].GetAngle(); + } + else { + c[0] = p_rotationKeys[i + 1].GetX(); + c[1] = p_rotationKeys[i + 1].GetY(); + c[2] = p_rotationKeys[i + 1].GetZ(); + c[3] = p_rotationKeys[i + 1].GetAngle(); + } + + b.Unknown1(a); + b.Unknown2(c); + b.Unknown_100040a0( + p_matrix, + (p_time - p_rotationKeys[i].GetTime()) / (p_rotationKeys[i + 1].GetTime() - p_rotationKeys[i].GetTime()) + ); + } + } +} + +inline void LegoAnimNodeData::GetScale( + LegoU16 p_numScaleKeys, + LegoScaleKey* p_scaleKeys, + LegoFloat p_time, + Matrix4& p_matrix, + LegoU32& p_old_index +) +{ + LegoU32 i, n; + LegoFloat x, y, z; + n = FindKeys(p_time, p_numScaleKeys & USHRT_MAX, p_scaleKeys, sizeof(*p_scaleKeys), i, p_old_index); + + switch (n) { + case 0: + return; + case 1: + x = p_scaleKeys[i].GetX(); + y = p_scaleKeys[i].GetY(); + z = p_scaleKeys[i].GetZ(); + break; + case 2: + x = Interpolate(p_time, p_scaleKeys[i], p_scaleKeys[i].GetX(), p_scaleKeys[i + 1], p_scaleKeys[i + 1].GetX()); + y = Interpolate(p_time, p_scaleKeys[i], p_scaleKeys[i].GetY(), p_scaleKeys[i + 1], p_scaleKeys[i + 1].GetY()); + z = Interpolate(p_time, p_scaleKeys[i], p_scaleKeys[i].GetZ(), p_scaleKeys[i + 1], p_scaleKeys[i + 1].GetZ()); + break; + } + + p_matrix.Scale(x, y, z); +} + +// FUNCTION: LEGO1 0x100a0990 +LegoBool LegoAnimNodeData::FUN_100a0990(LegoFloat p_time) +{ + LegoU32 i, n; + LegoU32 index = GetMorphIndex(); + LegoBool result; + + n = FindKeys(p_time, m_numMorphKeys, m_morphKeys, sizeof(*m_morphKeys), i, index); + SetMorphIndex(index); + + switch (n) { + case 0: + result = TRUE; + break; + case 1: + case 2: + result = m_morphKeys[i].GetUnknown0x08(); + break; + } + + return result; +} + +// FUNCTION: LEGO1 0x100a0a00 +LegoU32 LegoAnimNodeData::FindKeys( + LegoFloat p_time, + LegoU32 p_numKeys, + LegoAnimKey* p_keys, + LegoU32 p_size, + LegoU32& p_new_index, + LegoU32& p_old_index +) +{ + LegoU32 numKeys; + if (p_numKeys == 0) { + numKeys = 0; + } + else if (p_time < GetKey(0, p_keys, p_size).GetTime()) { + numKeys = 0; + } + else if (p_time > GetKey(p_numKeys - 1, p_keys, p_size).GetTime()) { + p_new_index = p_numKeys - 1; + numKeys = 1; + } + else { + if (GetKey(p_old_index, p_keys, p_size).GetTime() <= p_time) { + for (p_new_index = p_old_index; + p_new_index < p_numKeys - 1 && p_time >= GetKey(p_new_index + 1, p_keys, p_size).GetTime(); + p_new_index++) { + } + } + else { + for (p_new_index = 0; + p_new_index < p_numKeys - 1 && p_time >= GetKey(p_new_index + 1, p_keys, p_size).GetTime(); + p_new_index++) { + } + } + + p_old_index = p_new_index; + if (p_time == GetKey(p_new_index, p_keys, p_size).GetTime()) { + numKeys = 1; + } + else if (p_new_index < p_numKeys - 1) { + numKeys = 2; + } + else { + numKeys = 0; + } + } + + return numKeys; +} + +// FUNCTION: LEGO1 0x100a0b00 +inline LegoFloat LegoAnimNodeData::Interpolate( + LegoFloat p_time, + LegoAnimKey& p_key1, + LegoFloat p_value1, + LegoAnimKey& p_key2, + LegoFloat p_value2 +) +{ + return p_value1 + (p_value2 - p_value1) * (p_time - p_key1.GetTime()) / (p_key2.GetTime() - p_key1.GetTime()); +} + +inline LegoAnimKey& LegoAnimNodeData::GetKey(LegoU32 p_i, LegoAnimKey* p_keys, LegoU32 p_size) +{ + return *((LegoAnimKey*) (((LegoU8*) p_keys) + (p_i * p_size))); +} + +// FUNCTION: LEGO1 0x100a0b30 +LegoAnim::LegoAnim() +{ + m_duration = 0; + m_actors = NULL; + m_numActors = 0; + m_scene = NULL; +} + +// FUNCTION: LEGO1 0x100a0bc0 +LegoAnim::~LegoAnim() +{ + if (m_actors != NULL) { + for (LegoU32 i = 0; i < m_numActors; i++) { + delete[] m_actors[i].m_name; + } + + delete[] m_actors; + } + + if (m_scene != NULL) { + delete m_scene; + } +} + +// FUNCTION: LEGO1 0x100a0c70 +LegoResult LegoAnim::Read(LegoStorage* p_storage, LegoS32 p_parseScene) +{ + LegoResult result = FAILURE; + LegoU32 length, i; + + if (p_storage->Read(&length, sizeof(length)) != SUCCESS) { + goto done; + } + + m_actors = new LegoAnimActorEntry[length]; + m_numActors = 0; + + for (i = 0; i < length; i++) { + LegoU32 length; + if (p_storage->Read(&length, sizeof(length)) != SUCCESS) { + goto done; + } + + if (length) { + m_actors[i].m_name = new LegoChar[length + 1]; + + if (p_storage->Read(m_actors[i].m_name, length) != SUCCESS) { + goto done; + } + + m_actors[i].m_name[length] = '\0'; + + if (p_storage->Read(&m_actors[i].m_unk0x04, sizeof(m_actors[i].m_unk0x04)) != SUCCESS) { + goto done; + } + } + + m_numActors++; + } + + if ((result = p_storage->Read(&m_duration, sizeof(m_duration))) != SUCCESS) { + goto done; + } + + if (p_parseScene) { + m_scene = new LegoAnimScene(); + + result = m_scene->Read(p_storage); + + if (result != SUCCESS) { + goto done; + } + } + + result = LegoTree::Read(p_storage); + +done: + if (result != SUCCESS && m_actors != NULL) { + for (i = 0; i < m_numActors; i++) { + delete[] m_actors[i].m_name; + } + + m_numActors = 0; + delete[] m_actors; + m_actors = NULL; + } + + return result; +} + +// STUB: LEGO1 0x100a0e30 +LegoResult LegoAnim::Write(LegoStorage* p_storage) +{ + // TODO + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100a0f20 +const LegoChar* LegoAnim::GetActorName(LegoU32 p_index) +{ + if (p_index < m_numActors) { + return m_actors[p_index].m_name; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x100a0f40 +undefined4 LegoAnim::GetActorUnknown0x04(LegoU32 p_index) +{ + if (p_index < m_numActors) { + return m_actors[p_index].m_unk0x04; + } + + return NULL; +} + +// FUNCTION: LEGO1 0x100a0f60 +LegoMorphKey::LegoMorphKey() +{ + m_unk0x08 = 0; +} + +// FUNCTION: LEGO1 0x100a0f70 +LegoResult LegoMorphKey::Read(LegoStorage* p_storage) +{ + LegoResult result; + + if ((result = LegoAnimKey::Read(p_storage)) != SUCCESS) { + return result; + } + + result = p_storage->Read(&m_unk0x08, sizeof(m_unk0x08)); + return result == SUCCESS ? SUCCESS : result; +} diff --git a/LEGO1/lego/sources/anim/legoanim.h b/LEGO1/lego/sources/anim/legoanim.h new file mode 100644 index 00000000..ae6f3bb6 --- /dev/null +++ b/LEGO1/lego/sources/anim/legoanim.h @@ -0,0 +1,258 @@ +#ifndef __LEGOANIM_H +#define __LEGOANIM_H + +#include "decomp.h" +#include "misc/legostorage.h" +#include "misc/legotree.h" + +class Matrix4; + +// SIZE 0x08 +class LegoAnimKey { +public: + enum Flags { + c_bit1 = 0x01, + c_bit2 = 0x02, + c_bit3 = 0x04 + }; + + LegoAnimKey(); + LegoResult Read(LegoStorage* p_storage); + LegoFloat GetTime() { return m_time; } + void SetTime(LegoFloat p_time) { m_time = p_time; } + LegoU32 TestBit1() { return m_flags & c_bit1; } + LegoU32 TestBit2() { return m_flags & c_bit2; } + LegoU32 TestBit3() { return m_flags & c_bit3; } + +protected: + LegoU8 m_flags; // 0x00 + LegoFloat m_time; // 0x04 +}; + +// SIZE 0x14 +class LegoTranslationKey : public LegoAnimKey { +public: + LegoTranslationKey(); + LegoResult Read(LegoStorage* p_storage); + LegoFloat GetX() { return m_x; } + void SetX(LegoFloat p_x) { m_x = p_x; } + LegoFloat GetY() { return m_y; } + void SetY(LegoFloat p_y) { m_y = p_y; } + LegoFloat GetZ() { return m_z; } + void SetZ(LegoFloat p_z) { m_z = p_z; } + +protected: + LegoFloat m_x; // 0x08 + LegoFloat m_y; // 0x0c + LegoFloat m_z; // 0x10 +}; + +// SIZE 0x18 +class LegoRotationKey : public LegoAnimKey { +public: + LegoRotationKey(); + LegoResult Read(LegoStorage* p_storage); + LegoFloat GetAngle() { return m_angle; } + void SetAngle(LegoFloat p_angle) { m_angle = p_angle; } + LegoFloat GetX() { return m_x; } + void SetX(LegoFloat p_x) { m_x = p_x; } + LegoFloat GetY() { return m_y; } + void SetY(LegoFloat p_y) { m_y = p_y; } + LegoFloat GetZ() { return m_z; } + void SetZ(LegoFloat p_z) { m_z = p_z; } + +protected: + LegoFloat m_angle; // 0x08 + LegoFloat m_x; // 0x0c + LegoFloat m_y; // 0x10 + LegoFloat m_z; // 0x14 +}; + +// SIZE 0x14 +class LegoScaleKey : public LegoAnimKey { +public: + LegoScaleKey(); + LegoResult Read(LegoStorage* p_storage); + LegoFloat GetX() { return m_x; } + void SetX(LegoFloat p_x) { m_x = p_x; } + LegoFloat GetY() { return m_y; } + void SetY(LegoFloat p_y) { m_y = p_y; } + LegoFloat GetZ() { return m_z; } + void SetZ(LegoFloat p_z) { m_z = p_z; } + +protected: + LegoFloat m_x; // 0x08 + LegoFloat m_y; // 0x0c + LegoFloat m_z; // 0x10 +}; + +// SIZE 0x0c +class LegoMorphKey : public LegoAnimKey { +public: + LegoMorphKey(); + LegoResult Read(LegoStorage* p_storage); + LegoBool GetUnknown0x08() { return m_unk0x08; } + +protected: + LegoBool m_unk0x08; // 0x08 +}; + +// SIZE 0x0c +class LegoUnknownKey : public LegoAnimKey { +public: + LegoUnknownKey(); + LegoResult Read(LegoStorage* p_storage); + +protected: + undefined4 m_unk0x08; // 0x08 +}; + +// VTABLE: LEGO1 0x100db8c8 +// SIZE 0x34 +class LegoAnimNodeData : public LegoTreeNodeData { +public: + LegoAnimNodeData(); + ~LegoAnimNodeData() override; + LegoResult Read(LegoStorage* p_storage) override; // vtable+0x04 + LegoResult Write(LegoStorage* p_storage) override; // vtable+0x08 + + LegoResult CreateLocalTransform(LegoFloat p_time, Matrix4& p_matrix); + LegoBool FUN_100a0990(LegoFloat p_time); + + const LegoChar* GetName() { return m_name; } + LegoU32 GetTranslationIndex() { return m_translationIndex; } + LegoU32 GetRotationIndex() { return m_rotationIndex; } + LegoU32 GetScaleIndex() { return m_scaleIndex; } + LegoU32 GetMorphIndex() { return m_morphIndex; } + LegoU16 GetUnknown0x20() { return m_unk0x20; } + LegoU16 GetUnknown0x22() { return m_unk0x22; } + + void SetTranslationIndex(LegoU32 p_translationIndex) { m_translationIndex = p_translationIndex; } + void SetRotationIndex(LegoU32 p_rotationIndex) { m_rotationIndex = p_rotationIndex; } + void SetScaleIndex(LegoU32 p_scaleIndex) { m_scaleIndex = p_scaleIndex; } + void SetMorphIndex(LegoU32 p_morphIndex) { m_morphIndex = p_morphIndex; } + void SetUnknown0x20(LegoU16 p_unk0x20) { m_unk0x20 = p_unk0x20; } + void SetUnknown0x22(LegoU16 p_unk0x22) { m_unk0x22 = p_unk0x22; } + + LegoResult CreateLocalTransform(LegoTime p_time, Matrix4& p_matrix) + { + return CreateLocalTransform((LegoFloat) p_time, p_matrix); + } + LegoBool FUN_100a0990(LegoTime p_time) { return FUN_100a0990((LegoFloat) p_time); } + + inline static void GetTranslation( + LegoU16 p_numTranslationKeys, + LegoTranslationKey* p_translationKeys, + LegoFloat p_time, + Matrix4& p_matrix, + LegoU32& p_old_index + ); + /*inline*/ static void GetRotation( + LegoU16 p_numRotationKeys, + LegoRotationKey* p_rotationKeys, + LegoFloat p_time, + Matrix4& p_matrix, + LegoU32& p_old_index + ); + inline static void GetScale( + LegoU16 p_numScaleKeys, + LegoScaleKey* p_scaleKeys, + LegoFloat p_time, + Matrix4& p_matrix, + LegoU32& p_old_index + ); + inline static LegoFloat Interpolate( + LegoFloat p_time, + LegoAnimKey& p_key1, + LegoFloat p_value1, + LegoAnimKey& p_key2, + LegoFloat p_value2 + ); + inline static LegoAnimKey& GetKey(LegoU32 p_i, LegoAnimKey* p_keys, LegoU32 p_size); + + static LegoU32 FindKeys( + LegoFloat p_time, + LegoU32 p_numKeys, + LegoAnimKey* p_keys, + LegoU32 p_size, + LegoU32& p_new_index, + LegoU32& p_old_index + ); + + // SYNTHETIC: LEGO1 0x1009fd80 + // LegoAnimNodeData::`scalar deleting destructor' + +protected: + LegoChar* m_name; // 0x04 + LegoU16 m_numTranslationKeys; // 0x08 + LegoU16 m_numRotationKeys; // 0x0a + LegoU16 m_numScaleKeys; // 0x0c + LegoU16 m_numMorphKeys; // 0x0e + LegoTranslationKey* m_translationKeys; // 0x10 + LegoRotationKey* m_rotationKeys; // 0x14 + LegoScaleKey* m_scaleKeys; // 0x18 + LegoMorphKey* m_morphKeys; // 0x1c + LegoU16 m_unk0x20; // 0x20 + LegoU16 m_unk0x22; // 0x22 + LegoU32 m_translationIndex; // 0x24 + LegoU32 m_rotationIndex; // 0x28 + LegoU32 m_scaleIndex; // 0x2c + LegoU32 m_morphIndex; // 0x30 +}; + +// SIZE 0x08 +struct LegoAnimActorEntry { + LegoChar* m_name; // 0x00 + undefined4 m_unk0x04; // 0x04 +}; + +// SIZE 0x24 +class LegoAnimScene { +public: + LegoAnimScene(); + ~LegoAnimScene(); + LegoResult Read(LegoStorage* p_storage); + undefined4 FUN_1009f490(LegoFloat p_time, Matrix4& p_matrix); + +private: + LegoU16 m_unk0x00; // 0x00 + LegoTranslationKey* m_unk0x04; // 0x04 + LegoU16 m_unk0x08; // 0x08 + LegoTranslationKey* m_unk0x0c; // 0x0c + LegoU16 m_unk0x10; // 0x10 + LegoUnknownKey* m_unk0x14; // 0x14 + undefined4 m_unk0x18; // 0x18 + undefined4 m_unk0x1c; // 0x1c + undefined4 m_unk0x20; // 0x20 +}; + +// VTABLE: LEGO1 0x100db8d8 +// SIZE 0x18 +class LegoAnim : public LegoTree { +public: + LegoAnim(); + ~LegoAnim() override; + LegoTime GetDuration() { return m_duration; } + LegoU32 GetNumActors() { return m_numActors; } + LegoResult Write(LegoStorage* p_storage) override; // vtable+0x08 + virtual LegoResult Read(LegoStorage* p_storage, LegoS32 p_parseScene); // vtable+0x10 + + const LegoChar* GetActorName(LegoU32 p_index); + undefined4 GetActorUnknown0x04(LegoU32 p_index); + + inline LegoAnimScene* GetScene() { return m_scene; } + + // SYNTHETIC: LEGO1 0x100a0ba0 + // LegoAnim::`scalar deleting destructor' + +protected: + LegoTime m_duration; // 0x08 + LegoAnimActorEntry* m_actors; // 0x0c + LegoU32 m_numActors; // 0x10 + LegoAnimScene* m_scene; // 0x14 + + // FUNCTION: LEGO1 0x100a1040 + LegoTreeNodeData* CreateData() override { return new LegoAnimNodeData(); } // vtable+0x0c +}; + +#endif // __LEGOANIM_H diff --git a/LEGO1/lego/sources/geom/legobox.cpp b/LEGO1/lego/sources/geom/legobox.cpp new file mode 100644 index 00000000..0a5f2bdb --- /dev/null +++ b/LEGO1/lego/sources/geom/legobox.cpp @@ -0,0 +1,19 @@ +#include "legobox.h" + +#include "decomp.h" +#include "misc/legoutil.h" + +DECOMP_SIZE_ASSERT(LegoBox, 0x18) + +// FUNCTION: LEGO1 0x100d3740 +LegoResult LegoBox::Read(LegoStorage* p_storage) +{ + LegoResult result; + if ((result = m_min.Read(p_storage)) != SUCCESS) { + return result; + } + if ((result = m_max.Read(p_storage)) != SUCCESS) { + return result; + } + return SUCCESS; +} diff --git a/LEGO1/lego/sources/geom/legobox.h b/LEGO1/lego/sources/geom/legobox.h new file mode 100644 index 00000000..f0816c98 --- /dev/null +++ b/LEGO1/lego/sources/geom/legobox.h @@ -0,0 +1,32 @@ +#ifndef __LEGOBOX_H +#define __LEGOBOX_H + +#include "legovertex.h" + +// SIZE 0x18 +class LegoBox { +public: + LegoVertex& GetMin() { return m_min; } + void SetMin(LegoVertex& p_min) { m_min = p_min; } + LegoVertex& GetMax() { return m_max; } + void SetMax(LegoVertex& p_max) { m_max = p_max; } + // LegoVertex GetCenter() + // { + // return LegoVertex( + // (m_min.GetX() + m_max.GetX()) / 2, + // (m_min.GetY() + m_max.GetY()) / 2, + // (m_min.GetZ() + m_max.GetZ()) / 2 + // ); + // } + LegoFloat GetDX() { return m_max.GetX() - m_min.GetX(); } + LegoFloat GetDY() { return m_max.GetY() - m_min.GetY(); } + LegoFloat GetDZ() { return m_max.GetZ() - m_min.GetZ(); } + LegoBool IsEmpty() { return m_min.IsOrigin() && m_max.IsOrigin(); } + LegoResult Read(LegoStorage* p_storage); + +protected: + LegoVertex m_min; // 0x00 + LegoVertex m_max; // 0x0c +}; + +#endif // __LEGOBOX_H diff --git a/LEGO1/lego/sources/geom/legoedge.cpp b/LEGO1/lego/sources/geom/legoedge.cpp new file mode 100644 index 00000000..63e988c0 --- /dev/null +++ b/LEGO1/lego/sources/geom/legoedge.cpp @@ -0,0 +1,63 @@ +#include "legoedge.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(LegoEdge, 0x24) + +// FUNCTION: LEGO1 0x1009a470 +LegoEdge::LegoEdge() +{ + m_faceA = NULL; + m_faceB = NULL; + m_ccwA = NULL; + m_cwA = NULL; + m_ccwB = NULL; + m_cwB = NULL; + m_pointA = NULL; + m_pointB = NULL; +} + +// FUNCTION: LEGO1 0x1009a4c0 +LegoEdge::~LegoEdge() +{ +} + +// FUNCTION: LEGO1 0x1009a4d0 +LegoEdge* LegoEdge::GetClockwiseEdge(LegoWEEdge* p_face) +{ + if (p_face == m_faceA) { + return m_cwA; + } + else if (p_face == m_faceB) { + return m_cwB; + } + else { + return NULL; + } +} + +// FUNCTION: LEGO1 0x1009a4f0 +LegoEdge* LegoEdge::GetCounterclockwiseEdge(LegoWEEdge* p_face) +{ + if (p_face == m_faceA) { + return m_ccwA; + } + else if (p_face == m_faceB) { + return m_ccwB; + } + else { + return NULL; + } +} + +// FUNCTION: LEGO1 0x1009a510 +Vector3* LegoEdge::GetOpposingPoint(LegoWEEdge* p_face) +{ + return p_face == m_faceA ? m_pointB : m_pointA; +} + +// FUNCTION: LEGO1 0x1009a530 +Vector3* LegoEdge::GetPoint(LegoWEEdge* p_face) +{ + return p_face == m_faceB ? m_pointB : m_pointA; +} diff --git a/LEGO1/lego/sources/geom/legoedge.h b/LEGO1/lego/sources/geom/legoedge.h new file mode 100644 index 00000000..da440e71 --- /dev/null +++ b/LEGO1/lego/sources/geom/legoedge.h @@ -0,0 +1,35 @@ +#ifndef __LEGOEDGE_H +#define __LEGOEDGE_H + +#include "misc/legotypes.h" + +class LegoWEEdge; +class Vector3; + +// VTABLE: LEGO1 0x100db7b8 +// SIZE 0x24 +struct LegoEdge { + LegoEdge(); + virtual ~LegoEdge(); // vtable+0x00 + + LegoEdge* GetClockwiseEdge(LegoWEEdge* face); + LegoEdge* GetCounterclockwiseEdge(LegoWEEdge* face); + Vector3* GetOpposingPoint(LegoWEEdge* face); + Vector3* GetPoint(LegoWEEdge* face); + + LegoResult FUN_1002ddc0(LegoWEEdge* p_face, Vector3& p_point); + + // SYNTHETIC: LEGO1 0x1009a4a0 + // LegoEdge::`scalar deleting destructor' + + LegoWEEdge* m_faceA; // 0x04 + LegoWEEdge* m_faceB; // 0x08 + LegoEdge* m_ccwA; // 0x0c + LegoEdge* m_cwA; // 0x10 + LegoEdge* m_ccwB; // 0x14 + LegoEdge* m_cwB; // 0x18 + Vector3* m_pointA; // 0x1c + Vector3* m_pointB; // 0x20 +}; + +#endif // __LEGOEDGE_H diff --git a/LEGO1/lego/sources/geom/legomesh.cpp b/LEGO1/lego/sources/geom/legomesh.cpp new file mode 100644 index 00000000..51b61fb0 --- /dev/null +++ b/LEGO1/lego/sources/geom/legomesh.cpp @@ -0,0 +1,91 @@ +#include "legomesh.h" + +#include "misc/legostorage.h" + +DECOMP_SIZE_ASSERT(LegoMeshUnkComponent, 0x1c) +DECOMP_SIZE_ASSERT(LegoMesh, 0x24) + +// FUNCTION: LEGO1 0x100d3810 +LegoMesh::LegoMesh() +{ + m_alpha = 0.0F; + m_shading = e_flat; + m_unk0x14 = 0; + m_textureName = NULL; + m_unk0x0d = 0; + m_unk0x10 = NULL; + m_unk0x20 = 0; + m_unk0x21 = FALSE; + m_materialName = NULL; +} + +// FUNCTION: LEGO1 0x100d3860 +LegoMesh::~LegoMesh() +{ + if (m_textureName != NULL) { + delete[] m_textureName; + } + + if (m_materialName != NULL) { + delete[] m_materialName; + } + + if (m_unk0x10 != NULL) { + delete m_unk0x10; + } +} + +// FUNCTION: LEGO1 0x100d38f0 +LegoResult LegoMesh::Read(LegoStorage* p_storage) +{ + LegoResult result; + LegoU32 textureLength, materialLength; + if ((result = m_color.Read(p_storage)) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_alpha, sizeof(m_alpha))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_shading, sizeof(m_shading))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_unk0x0d, sizeof(m_unk0x0d))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_unk0x20, sizeof(m_unk0x20))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_unk0x21, sizeof(m_unk0x21))) != SUCCESS) { + return result; + } + + if ((result = p_storage->Read(&textureLength, sizeof(textureLength))) != SUCCESS) { + return result; + } + if (textureLength) { + m_textureName = new LegoChar[textureLength + 1]; + + if ((result = p_storage->Read(m_textureName, textureLength)) != SUCCESS) { + return result; + } + + m_textureName[textureLength] = '\0'; + strlwr(m_textureName); + } + + if ((result = p_storage->Read(&materialLength, sizeof(materialLength))) != SUCCESS) { + return result; + } + if (materialLength) { + m_materialName = new LegoChar[materialLength + 1]; + + if ((result = p_storage->Read(m_materialName, materialLength)) != SUCCESS) { + return result; + } + + m_materialName[materialLength] = '\0'; + strlwr(m_materialName); + } + + return SUCCESS; +} diff --git a/LEGO1/lego/sources/geom/legomesh.h b/LEGO1/lego/sources/geom/legomesh.h new file mode 100644 index 00000000..1832ae7b --- /dev/null +++ b/LEGO1/lego/sources/geom/legomesh.h @@ -0,0 +1,78 @@ +#ifndef __LEGOMESH_H +#define __LEGOMESH_H + +#include "decomp.h" +#include "misc/legocolor.h" +#include "misc/legotypes.h" + +class LegoStorage; + +// SIZE 0x1c +struct LegoMeshUnkComponent { + ~LegoMeshUnkComponent() + { + if (m_unk0x08) { + delete m_unk0x08; + } + if (m_unk0x0c) { + delete m_unk0x0c; + } + if (m_unk0x10) { + delete m_unk0x10; + } + if (m_unk0x14) { + delete m_unk0x14; + } + if (m_unk0x18) { + delete m_unk0x18; + } + } + + undefined m_unk0x00[8]; // 0x00 + undefined* m_unk0x08; // 0x08 + undefined* m_unk0x0c; // 0x0c + undefined* m_unk0x10; // 0x10 + undefined* m_unk0x14; // 0x14 + undefined* m_unk0x18; // 0x18 +}; + +// VTABLE: LEGO1 0x100dd228 +// SIZE 0x24 +class LegoMesh { +public: + enum { + e_flat, + e_gouraud, + e_wireframe + }; + + LegoMesh(); + virtual ~LegoMesh(); + LegoColor GetColor() { return m_color; } + void SetColor(LegoColor p_color) { m_color = p_color; } + LegoFloat GetAlpha() { return m_alpha; } + LegoU8 GetShading() { return m_shading; } + void SetShading(LegoU8 p_shading) { m_shading = p_shading; } + LegoU8 GetUnknown0x0d() { return m_unk0x0d; } + const LegoChar* GetTextureName() { return m_textureName; } + const LegoChar* GetMaterialName() { return m_materialName; } + LegoBool GetUnknown0x21() { return m_unk0x21; } + LegoResult Read(LegoStorage* p_storage); + + // SYNTHETIC: LEGO1 0x100d3840 + // LegoMesh::`scalar deleting destructor' + +protected: + LegoColor m_color; // 0x04 + LegoFloat m_alpha; // 0x08 + LegoU8 m_shading; // 0x0c + LegoU8 m_unk0x0d; // 0x0d + LegoMeshUnkComponent* m_unk0x10; // 0x10 - unused, except in destructor + undefined4 m_unk0x14; // 0x14 - unused + LegoChar* m_textureName; // 0x18 + LegoChar* m_materialName; // 0x1c + undefined m_unk0x20; // 0x20 - unused + LegoBool m_unk0x21; // 0x21 +}; + +#endif // __LEGOMESH_H diff --git a/LEGO1/lego/sources/geom/legosphere.cpp b/LEGO1/lego/sources/geom/legosphere.cpp new file mode 100644 index 00000000..7b916326 --- /dev/null +++ b/LEGO1/lego/sources/geom/legosphere.cpp @@ -0,0 +1,19 @@ +#include "legosphere.h" + +#include "decomp.h" +#include "misc/legostorage.h" + +DECOMP_SIZE_ASSERT(LegoSphere, 0x10) + +// FUNCTION: LEGO1 0x100d3770 +LegoResult LegoSphere::Read(LegoStorage* p_storage) +{ + LegoResult result; + if ((result = m_center.Read(p_storage)) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_radius, sizeof(m_radius))) != SUCCESS) { + return result; + } + return SUCCESS; +} diff --git a/LEGO1/lego/sources/geom/legosphere.h b/LEGO1/lego/sources/geom/legosphere.h new file mode 100644 index 00000000..566713a2 --- /dev/null +++ b/LEGO1/lego/sources/geom/legosphere.h @@ -0,0 +1,21 @@ +#ifndef __LEGOSPHERE_H +#define __LEGOSPHERE_H + +#include "legovertex.h" + +// SIZE 0x10 +class LegoSphere { +public: + LegoSphere() { m_radius = 0.0F; } + LegoVertex& GetCenter() { return m_center; } + void SetCenter(LegoVertex& p_center) { m_center = p_center; } + LegoFloat GetRadius() { return m_radius; } + void SetRadius(LegoFloat p_radius) { m_radius = p_radius; } + LegoResult Read(LegoStorage* p_storage); + +protected: + LegoVertex m_center; // 0x00 + LegoFloat m_radius; // 0x0c +}; + +#endif // __LEGOSPHERE_H diff --git a/LEGO1/lego/sources/geom/legounkown100db7f4.cpp b/LEGO1/lego/sources/geom/legounkown100db7f4.cpp new file mode 100644 index 00000000..eab51447 --- /dev/null +++ b/LEGO1/lego/sources/geom/legounkown100db7f4.cpp @@ -0,0 +1,12 @@ +#include "legounkown100db7f4.h" + +DECOMP_SIZE_ASSERT(LegoUnknown100db7f4, 0x40) + +// FUNCTION: LEGO1 0x1009a630 +// FUNCTION: BETA10 0x10183050 +LegoUnknown100db7f4::LegoUnknown100db7f4() +{ + m_flags = 0; + m_unk0x28.Clear(); + m_unk0x3c = 0; +} diff --git a/LEGO1/lego/sources/geom/legounkown100db7f4.h b/LEGO1/lego/sources/geom/legounkown100db7f4.h new file mode 100644 index 00000000..0a609d51 --- /dev/null +++ b/LEGO1/lego/sources/geom/legounkown100db7f4.h @@ -0,0 +1,47 @@ +#ifndef __LEGOUNKNOWN100DB7F4_H +#define __LEGOUNKNOWN100DB7F4_H + +#include "legoedge.h" +#include "legoweedge.h" +#include "mxgeometry/mxgeometry3d.h" + +// VTABLE: LEGO1 0x100db7f4 +// SIZE 0x40 +struct LegoUnknown100db7f4 : public LegoEdge { +public: + enum { + c_bit1 = 0x01, + c_bit2 = 0x02, + c_bit3 = 0x04, + c_bit4 = 0x08 + }; + + LegoUnknown100db7f4(); + + // FUNCTION: LEGO1 0x1002ddc0 + // FUNCTION: BETA10 0x100372a0 + LegoResult FUN_1002ddc0(LegoWEEdge& p_f, Vector3& p_point) + { + if (p_f.IsEqual(*m_faceA)) { + p_point[0] = -m_unk0x28[0]; + p_point[1] = -m_unk0x28[1]; + p_point[2] = -m_unk0x28[2]; + } + else { + p_point = m_unk0x28; + } + + return SUCCESS; + } + + LegoU32 GetMask0x03() { return m_flags & (c_bit1 | c_bit2); } + + // SYNTHETIC: LEGO1 0x1009a6c0 + // LegoUnknown100db7f4::`scalar deleting destructor' + + LegoU16 m_flags; // 0x24 + Mx3DPointFloat m_unk0x28; // 0x28 + LegoU32 m_unk0x3c; // 0x3c +}; + +#endif // __LEGOUNKNOWN100DB7F4_H diff --git a/LEGO1/lego/sources/geom/legovertex.cpp b/LEGO1/lego/sources/geom/legovertex.cpp new file mode 100644 index 00000000..2977d60a --- /dev/null +++ b/LEGO1/lego/sources/geom/legovertex.cpp @@ -0,0 +1,30 @@ +#include "legovertex.h" + +#include "decomp.h" +#include "misc/legostorage.h" + +DECOMP_SIZE_ASSERT(LegoVertex, 0x0c) + +// FUNCTION: LEGO1 0x100d37b0 +LegoVertex::LegoVertex() +{ + m_coordinates[0] = 0.0F; + m_coordinates[1] = 0.0F; + m_coordinates[2] = 0.0F; +} + +// FUNCTION: LEGO1 0x100d37c0 +LegoResult LegoVertex::Read(LegoStorage* p_storage) +{ + LegoResult result; + if ((result = p_storage->Read(&m_coordinates[0], sizeof(m_coordinates[0]))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_coordinates[1], sizeof(m_coordinates[1]))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_coordinates[2], sizeof(m_coordinates[2]))) != SUCCESS) { + return result; + } + return SUCCESS; +} diff --git a/LEGO1/lego/sources/geom/legovertex.h b/LEGO1/lego/sources/geom/legovertex.h new file mode 100644 index 00000000..91aca80a --- /dev/null +++ b/LEGO1/lego/sources/geom/legovertex.h @@ -0,0 +1,30 @@ +#ifndef __LEGOVERTEX_H +#define __LEGOVERTEX_H + +#include "misc/legotypes.h" + +class LegoStorage; + +// SIZE 0x0c +class LegoVertex { +public: + LegoVertex(); + LegoFloat GetCoordinate(LegoU32 p_i) { return m_coordinates[p_i]; } + void SetCoordinate(LegoU32 p_i, LegoFloat p_coordinate) { m_coordinates[p_i] = p_coordinate; } + LegoFloat GetX() { return m_coordinates[0]; } + void SetX(LegoFloat p_x) { m_coordinates[0] = p_x; } + LegoFloat GetY() { return m_coordinates[1]; } + void SetY(LegoFloat p_y) { m_coordinates[1] = p_y; } + LegoFloat GetZ() { return m_coordinates[2]; } + void SetZ(LegoFloat p_z) { m_coordinates[2] = p_z; } + LegoBool IsOrigin() { return m_coordinates[0] == 0.0 && m_coordinates[1] == 0.0 && m_coordinates[2] == 0.0; } + LegoResult Read(LegoStorage* p_storage); + + LegoFloat& operator[](int i) { return m_coordinates[i]; } + LegoFloat operator[](int i) const { return m_coordinates[i]; } + +protected: + LegoFloat m_coordinates[3]; // 0x00 +}; + +#endif // __LEGOVERTEX_H diff --git a/LEGO1/lego/sources/geom/legoweedge.cpp b/LEGO1/lego/sources/geom/legoweedge.cpp new file mode 100644 index 00000000..c03a5e3f --- /dev/null +++ b/LEGO1/lego/sources/geom/legoweedge.cpp @@ -0,0 +1,54 @@ +#include "legoweedge.h" + +DECOMP_SIZE_ASSERT(LegoWEEdge, 0x0c) + +// FUNCTION: LEGO1 0x1009a550 +LegoWEEdge::LegoWEEdge() +{ + m_edges = NULL; + m_numEdges = 0; +} + +// FUNCTION: LEGO1 0x1009a590 +LegoWEEdge::~LegoWEEdge() +{ + if (m_edges) { + delete m_edges; + } +} + +// FUNCTION: LEGO1 0x1009a5b0 +LegoResult LegoWEEdge::VTable0x04() +{ + for (LegoS32 i = 0; i < m_numEdges; i++) { + LegoEdge* e1 = m_edges[i]; + LegoEdge* e2 = (m_numEdges - i) == 1 ? m_edges[0] : m_edges[i + 1]; + + if (e2->m_pointA == e1->m_pointA) { + e1->m_faceA = this; + e2->m_faceB = this; + e1->m_ccwA = e2; + e2->m_cwB = e1; + } + else if (e2->m_pointB == e1->m_pointA) { + e1->m_faceA = this; + e2->m_faceA = this; + e1->m_ccwA = e2; + e2->m_cwA = e1; + } + else if (e1->m_pointB == e2->m_pointA) { + e1->m_faceB = this; + e2->m_faceB = this; + e1->m_ccwB = e2; + e2->m_cwB = e1; + } + else { + e1->m_faceB = this; + e2->m_faceA = this; + e1->m_ccwB = e2; + e2->m_cwA = e1; + } + } + + return SUCCESS; +} diff --git a/LEGO1/lego/sources/geom/legoweedge.h b/LEGO1/lego/sources/geom/legoweedge.h new file mode 100644 index 00000000..f433aa63 --- /dev/null +++ b/LEGO1/lego/sources/geom/legoweedge.h @@ -0,0 +1,36 @@ +#ifndef __LEGOWEEDGE_H +#define __LEGOWEEDGE_H + +#include "decomp.h" +#include "legoedge.h" +#include "misc/legotypes.h" + +// might be a struct with public members +// VTABLE: LEGO1 0x100db7c0 +// SIZE 0x0c +class LegoWEEdge { +public: + LegoWEEdge(); + virtual ~LegoWEEdge(); // vtable+0x00 + + virtual LegoResult VTable0x04(); // vtable+0x04 + + inline LegoU8 GetNumEdges() { return m_numEdges; } + inline LegoEdge** GetEdges() { return m_edges; } + inline LegoU32 IsEqual(LegoWEEdge& p_other) { return this == &p_other; } + + inline void SetEdges(LegoEdge** p_edges, LegoU8 p_numEdges) + { + m_edges = p_edges; + m_numEdges = p_numEdges; + } + + // SYNTHETIC: LEGO1 0x1009a570 + // LegoWEEdge::`scalar deleting destructor' + +protected: + LegoU8 m_numEdges; // 0x04 + LegoEdge** m_edges; // 0x08 +}; + +#endif // __LEGOWEEDGE_H diff --git a/LEGO1/lego/sources/geom/legowegedge.cpp b/LEGO1/lego/sources/geom/legowegedge.cpp new file mode 100644 index 00000000..1eb88448 --- /dev/null +++ b/LEGO1/lego/sources/geom/legowegedge.cpp @@ -0,0 +1,45 @@ +#include "legowegedge.h" + +DECOMP_SIZE_ASSERT(LegoWEGEdge, 0x54) +DECOMP_SIZE_ASSERT(LegoWEGEdge::Path, 0x0c) + +// FUNCTION: LEGO1 0x1009a730 +LegoWEGEdge::LegoWEGEdge() +{ + m_unk0x0d = 0; + m_name = NULL; + m_unk0x14.Clear(); + m_edgeNormals = NULL; + m_flags = 0; + m_unk0x48 = 0; + m_unk0x4c = NULL; + m_unk0x50 = NULL; +} + +// FUNCTION: LEGO1 0x1009a800 +LegoWEGEdge::~LegoWEGEdge() +{ + if (m_edges) { + delete[] m_edges; + m_edges = NULL; + } + if (m_name) { + delete[] m_name; + } + if (m_edgeNormals) { + delete[] m_edgeNormals; + } + if (m_unk0x4c) { + delete m_unk0x4c; + } + if (m_unk0x50) { + delete m_unk0x50; + } +} + +// STUB: LEGO1 0x1009a8c0 +LegoResult LegoWEGEdge::VTable0x04() +{ + // TODO + return SUCCESS; +} diff --git a/LEGO1/lego/sources/geom/legowegedge.h b/LEGO1/lego/sources/geom/legowegedge.h new file mode 100644 index 00000000..e8a0c396 --- /dev/null +++ b/LEGO1/lego/sources/geom/legowegedge.h @@ -0,0 +1,74 @@ +#ifndef __LEGOWEGEDGE_H +#define __LEGOWEGEDGE_H + +#include "decomp.h" +#include "legoweedge.h" +#include "mxgeometry/mxgeometry3d.h" + +struct LegoPathStruct; + +// might be a struct with public members +// VTABLE: LEGO1 0x100db7f8 +// SIZE 0x54 +class LegoWEGEdge : public LegoWEEdge { +public: + enum { + c_bit3 = 0x04, + c_bit5 = 0x10 + }; + + // SIZE 0x0c + struct Path { + // FUNCTION: LEGO1 0x10048280 + // FUNCTION: BETA10 0x100bd450 + Path() + { + m_unk0x00 = NULL; + m_unk0x04 = 0; + m_unk0x08 = 0; + } + + LegoPathStruct* m_unk0x00; // 0x00 + undefined4 m_unk0x04; // 0x04 + undefined4 m_unk0x08; // 0x08 + }; + + LegoWEGEdge(); + ~LegoWEGEdge() override; + + LegoResult VTable0x04() override; // vtable+0x04 + + inline LegoU32 GetFlag0x10() { return m_flags & c_bit5 ? FALSE : TRUE; } + inline Mx4DPointFloat* GetUnknown0x14() { return &m_unk0x14; } + inline Mx4DPointFloat* GetEdgeNormal(int index) { return &m_edgeNormals[index]; } + inline LegoChar* GetName() { return m_name; } + + inline void SetFlag0x10(LegoU32 p_disable) + { + if (p_disable) { + m_flags &= ~c_bit5; + } + else { + m_flags |= c_bit5; + } + } + + // SYNTHETIC: LEGO1 0x1009a7e0 + // LegoWEGEdge::`scalar deleting destructor' + + friend class LegoPathController; + +private: + LegoU8 m_flags; // 0x0c + LegoU8 m_unk0x0d; // 0x0d + LegoChar* m_name; // 0x10 + Mx4DPointFloat m_unk0x14; // 0x14 + Mx4DPointFloat* m_edgeNormals; // 0x2c + Mx3DPointFloat m_unk0x30; // 0x30 + LegoU32 m_unk0x44; // 0x44 + LegoU8 m_unk0x48; // 0x48 + Path* m_unk0x4c; // 0x4c + Mx3DPointFloat* m_unk0x50; // 0x50 +}; + +#endif // __LEGOWEGEDGE_H diff --git a/LEGO1/lego/sources/misc/legocolor.cpp b/LEGO1/lego/sources/misc/legocolor.cpp new file mode 100644 index 00000000..1dc1dce4 --- /dev/null +++ b/LEGO1/lego/sources/misc/legocolor.cpp @@ -0,0 +1,22 @@ +#include "legocolor.h" + +#include "decomp.h" +#include "legostorage.h" + +DECOMP_SIZE_ASSERT(LegoColor, 0x03) + +// FUNCTION: LEGO1 0x100d3a20 +LegoResult LegoColor::Read(LegoStorage* p_storage) +{ + LegoResult result; + if ((result = p_storage->Read(&m_red, sizeof(m_red))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_green, sizeof(m_green))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_blue, sizeof(m_blue))) != SUCCESS) { + return result; + } + return SUCCESS; +} diff --git a/LEGO1/lego/sources/misc/legocolor.h b/LEGO1/lego/sources/misc/legocolor.h new file mode 100644 index 00000000..027362ce --- /dev/null +++ b/LEGO1/lego/sources/misc/legocolor.h @@ -0,0 +1,26 @@ +#ifndef __LEGOCOLOR_H +#define __LEGOCOLOR_H + +#include "legotypes.h" + +class LegoStorage; + +// SIZE 0x03 +class LegoColor { +public: + LegoColor() { m_red = m_green = m_blue = 0; } + LegoU8 GetRed() { return m_red; } + void SetRed(LegoU8 p_red) { m_red = p_red; } + LegoU8 GetGreen() { return m_green; } + void SetGreen(LegoU8 p_green) { m_green = p_green; } + LegoU8 GetBlue() { return m_blue; } + void SetBlue(LegoU8 p_blue) { m_blue = p_blue; } + LegoResult Read(LegoStorage* p_storage); + +protected: + LegoU8 m_red; // 0x00 + LegoU8 m_green; // 0x01 + LegoU8 m_blue; // 0x02 +}; + +#endif // __LEGOCOLOR_H diff --git a/LEGO1/lego/sources/misc/legocontainer.cpp b/LEGO1/lego/sources/misc/legocontainer.cpp new file mode 100644 index 00000000..d9bdc0eb --- /dev/null +++ b/LEGO1/lego/sources/misc/legocontainer.cpp @@ -0,0 +1,138 @@ +#include "legocontainer.h" + +#include "lego/legoomni/include/legovideomanager.h" +#include "lego/legoomni/include/misc.h" +#include "mxdirectx/mxdirect3d.h" +#include "tgl/d3drm/impl.h" + +DECOMP_SIZE_ASSERT(LegoContainerInfo, 0x10); +// DECOMP_SIZE_ASSERT(LegoContainer, 0x18); +DECOMP_SIZE_ASSERT(LegoTextureContainer, 0x24); + +// FUNCTION: LEGO1 0x10099870 +LegoTextureContainer::~LegoTextureContainer() +{ +} + +// FUNCTION: LEGO1 0x100998e0 +LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo) +{ + DDSURFACEDESC desc, newDesc; + DWORD width, height; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (p_textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + width = desc.dwWidth; + height = desc.dwHeight; + p_textureInfo->m_surface->Unlock(desc.lpSurface); + } + + for (LegoCachedTextureList::iterator it = m_cached.begin(); it != m_cached.end(); it++) { + if ((*it).second == FALSE && (*it).first->m_texture->AddRef() != 0 && (*it).first->m_texture->Release() == 1) { + if (!strcmp((*it).first->m_name, p_textureInfo->m_name)) { + LPDIRECTDRAWSURFACE surface = (*it).first->m_surface; + memset(&newDesc, 0, sizeof(newDesc)); + newDesc.dwSize = sizeof(newDesc); + + if (surface->Lock(NULL, &newDesc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + BOOL und = FALSE; + if (newDesc.dwWidth == width && newDesc.dwHeight == height) { + und = TRUE; + } + + surface->Unlock(newDesc.lpSurface); + + if (und) { + (*it).second = TRUE; + (*it).first->m_texture->AddRef(); + return (*it).first; + } + } + } + } + } + + LegoTextureInfo* textureInfo = new LegoTextureInfo(); + + textureInfo->m_palette = p_textureInfo->m_palette; + textureInfo->m_palette->AddRef(); + + memset(&newDesc, 0, sizeof(newDesc)); + newDesc.dwWidth = desc.dwWidth; + newDesc.dwHeight = desc.dwHeight; + newDesc.dwSize = sizeof(newDesc); + newDesc.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + newDesc.ddsCaps.dwCaps = DDCAPS_OVERLAYCANTCLIP | DDCAPS_OVERLAY; + newDesc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat); + newDesc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_PALETTEINDEXED8; + newDesc.ddpfPixelFormat.dwRGBBitCount = 8; + + if (VideoManager()->GetDirect3D()->DirectDraw()->CreateSurface(&newDesc, &textureInfo->m_surface, NULL) == DD_OK) { + RECT rect; + rect.left = 0; + rect.right = newDesc.dwWidth - 1; + rect.top = 0; + rect.bottom = newDesc.dwHeight - 1; + + textureInfo->m_surface->SetPalette(textureInfo->m_palette); + + if (textureInfo->m_surface->BltFast(0, 0, p_textureInfo->m_surface, &rect, DDBLTFAST_WAIT) != DD_OK) { + textureInfo->m_surface->Release(); + textureInfo->m_palette->Release(); + delete textureInfo; + return NULL; + } + else { + if (((TglImpl::RendererImpl*) VideoManager()->GetRenderer()) + ->CreateTextureFromSurface(textureInfo->m_surface, &textureInfo->m_texture) != D3DRM_OK) { + textureInfo->m_surface->Release(); + textureInfo->m_palette->Release(); + delete textureInfo; + return NULL; + } + else { + textureInfo->m_texture->SetAppData((DWORD) textureInfo); + m_cached.push_back(LegoCachedTexture(textureInfo, TRUE)); + + textureInfo->m_texture->AddRef(); + + if (textureInfo->m_name != NULL) { + delete[] textureInfo->m_name; + } + + textureInfo->m_name = new char[strlen(p_textureInfo->m_name) + 1]; + strcpy(textureInfo->m_name, p_textureInfo->m_name); + return textureInfo; + } + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x10099cc0 +void LegoTextureContainer::EraseCached(LegoTextureInfo* p_textureInfo) +{ + if (p_textureInfo == NULL) { + return; + } + +#ifdef COMPAT_MODE + LegoCachedTextureList::iterator it; + for (it = m_cached.begin(); it != m_cached.end(); it++) { +#else + for (LegoCachedTextureList::iterator it = m_cached.begin(); it != m_cached.end(); it++) { +#endif + if ((*it).first == p_textureInfo) { + (*it).second = FALSE; + + if (p_textureInfo->m_texture->Release() == TRUE) { + delete p_textureInfo; + m_cached.erase(it); + } + + return; + } + } +} diff --git a/LEGO1/lego/sources/misc/legocontainer.h b/LEGO1/lego/sources/misc/legocontainer.h new file mode 100644 index 00000000..7ddad1de --- /dev/null +++ b/LEGO1/lego/sources/misc/legocontainer.h @@ -0,0 +1,200 @@ +#ifndef LEGOCONTAINER_H +#define LEGOCONTAINER_H + +#include "compat.h" +#include "decomp.h" +#include "legotexture.h" +#include "legotypes.h" +#include "mxstl/stlcompat.h" + +// Note: dependency on LegoOmni +#include "lego/legoomni/include/legotextureinfo.h" + +#pragma warning(disable : 4237) + +struct LegoContainerInfoComparator { + LegoBool operator()(const char* const& p_key0, const char* const& p_key1) const + { + return strcmp(p_key0, p_key1) > 0; + } +}; + +// SIZE 0x10 +template +class LegoContainerInfo : public map {}; + +// SIZE 0x18 +template +class LegoContainer { +public: + virtual ~LegoContainer() + { +#ifdef COMPAT_MODE + typename LegoContainerInfo::iterator it; +#else + LegoContainerInfo::iterator it; +#endif + for (it = m_map.begin(); it != m_map.end(); it++) { + // DECOMP: Use of const_cast here matches ~ViewLODListManager from 96 source. + const char* const& key = (*it).first; + delete[] const_cast(key); + + if (m_ownership) { + delete (*it).second; + } + } + } + + void Clear() + { +#ifdef COMPAT_MODE + for (typename LegoContainerInfo::iterator it = m_map.begin(); it != m_map.end(); it++) +#else + for (LegoContainerInfo::iterator it = m_map.begin(); it != m_map.end(); it++) +#endif + { + delete (*it).second; + } + } + + // FUNCTION: BETA10 0x1007bc00 + inline T* Get(const char* p_name) + { + T* value = NULL; + +#ifdef COMPAT_MODE + typename LegoContainerInfo::iterator it = m_map.find(p_name); +#else + LegoContainerInfo::iterator it = m_map.find(p_name); +#endif + + if (it != m_map.end()) { + value = (*it).second; + } + + return value; + } + + inline void Add(const char* p_name, T* p_value) + { +#ifdef COMPAT_MODE + typename LegoContainerInfo::iterator it = m_map.find(p_name); +#else + LegoContainerInfo::iterator it = m_map.find(p_name); +#endif + + char* name; + if (it != m_map.end()) { + name = const_cast((*it).first); + + if (m_ownership) { + delete (*it).second; + } + } + else { + name = new char[strlen(p_name) + 1]; + strcpy(name, p_name); + } + + m_map[name] = p_value; + } + + inline void SetOwnership(LegoBool p_ownership) { m_ownership = p_ownership; } + +protected: + LegoBool m_ownership; // 0x04 + LegoContainerInfo m_map; // 0x08 +}; + +// VTABLE: LEGO1 0x100d86d4 +// class LegoContainer + +typedef pair LegoCachedTexture; +typedef list LegoCachedTextureList; + +// VTABLE: LEGO1 0x100d86fc +// SIZE 0x24 +class LegoTextureContainer : public LegoContainer { +public: + LegoTextureContainer() { m_ownership = TRUE; } + ~LegoTextureContainer() override; + + LegoTextureInfo* GetCached(LegoTextureInfo* p_textureInfo); + void EraseCached(LegoTextureInfo* p_textureInfo); + +protected: + LegoCachedTextureList m_cached; // 0x18 +}; + +// TEMPLATE: LEGO1 0x10059c50 +// allocator::_Charalloc + +// clang-format off +// TEMPLATE: LEGO1 0x10001cc0 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Lbound + +// TEMPLATE: LEGO1 0x1004f740 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::find + +// TEMPLATE: LEGO1 0x1004f800 +// map >::insert + +// TEMPLATE: LEGO1 0x1004f960 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x1004f9b0 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Insert + +// TEMPLATE: LEGO1 0x10059c70 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Color + +// TEMPLATE: LEGO1 0x10059c80 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Left + +// TEMPLATE: LEGO1 0x10059c90 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Parent + +// TEMPLATE: LEGO1 0x10059ca0 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Right + +// TEMPLATE: LEGO1 0x10059cb0 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::~_Tree,map >::_Kfn,LegoContainerInfoComparator,allocator > + +// TEMPLATE: LEGO1 0x10059d80 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x10059dc0 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x1005a210 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Erase + +// TEMPLATE: LEGO1 0x1005a250 +// list,allocator > >::~list,allocator > > + +// TEMPLATE: LEGO1 0x1005a2c0 +// map >::~map > + +// TEMPLATE: LEGO1 0x1005a310 +// LegoContainer::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1005a400 +// LegoContainerInfo::~LegoContainerInfo + +// TEMPLATE: LEGO1 0x1005a450 +// Map::~Map + +// SYNTHETIC: LEGO1 0x1005a580 +// LegoTextureContainer::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1005a5a0 +// List >::~List > + +// TEMPLATE: LEGO1 0x1005b660 +// LegoContainer::~LegoContainer + +// GLOBAL: LEGO1 0x100f0100 +// _Tree,map >::_Kfn,LegoContainerInfoComparator,allocator >::_Nil +// clang-format on + +#endif // LEGOCONTAINER_H diff --git a/LEGO1/lego/sources/misc/legoimage.cpp b/LEGO1/lego/sources/misc/legoimage.cpp new file mode 100644 index 00000000..da3f04a0 --- /dev/null +++ b/LEGO1/lego/sources/misc/legoimage.cpp @@ -0,0 +1,176 @@ +#include "legoimage.h" + +#include "decomp.h" +#include "legostorage.h" +#include "memory.h" + +DECOMP_SIZE_ASSERT(LegoPaletteEntry, 0x03); +DECOMP_SIZE_ASSERT(LegoImage, 0x310); + +// FUNCTION: LEGO1 0x100994c0 +LegoPaletteEntry::LegoPaletteEntry() +{ + m_red = 0; + m_green = 0; + m_blue = 0; +} + +// FUNCTION: LEGO1 0x100994d0 +LegoResult LegoPaletteEntry::Read(LegoStorage* p_storage) +{ + LegoResult result; + if ((result = p_storage->Read(&m_red, sizeof(m_red))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_green, sizeof(m_green))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_blue, sizeof(m_blue))) != SUCCESS) { + return result; + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10099520 +LegoResult LegoPaletteEntry::Write(LegoStorage* p_storage) +{ + LegoResult result; + if ((result = p_storage->Write(&m_red, sizeof(m_red))) != SUCCESS) { + return result; + } + if ((result = p_storage->Write(&m_green, sizeof(m_green))) != SUCCESS) { + return result; + } + if ((result = p_storage->Write(&m_blue, sizeof(m_blue))) != SUCCESS) { + return result; + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10099570 +LegoImage::LegoImage() +{ + m_width = 0; + m_height = 0; + m_count = 0; + m_bits = NULL; +} + +// FUNCTION: LEGO1 0x100995a0 +LegoImage::LegoImage(LegoU32 p_width, LegoU32 p_height) +{ + m_width = p_width; + m_height = p_height; + m_count = 0; + m_bits = new LegoU8[m_width * m_height]; +} + +// FUNCTION: LEGO1 0x100995f0 +LegoImage::~LegoImage() +{ + if (m_bits) { + delete[] m_bits; + } +} + +// FUNCTION: LEGO1 0x10099610 +LegoResult LegoImage::Read(LegoStorage* p_storage, LegoU32 p_square) +{ + LegoResult result; + if ((result = p_storage->Read(&m_width, sizeof(m_width))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_height, sizeof(m_height))) != SUCCESS) { + return result; + } + if ((result = p_storage->Read(&m_count, sizeof(m_height))) != SUCCESS) { + return result; + } + for (LegoU32 i = 0; i < m_count; i++) { + if ((result = m_palette[i].Read(p_storage)) != SUCCESS) { + return result; + } + } + if (m_bits) { + delete[] m_bits; + } + m_bits = new LegoU8[m_width * m_height]; + if ((result = p_storage->Read(m_bits, m_width * m_height)) != SUCCESS) { + return result; + } + + if (p_square && m_width != m_height) { + LegoU8* newBits; + + if (m_height < m_width) { + LegoU32 aspect = m_width / m_height; + newBits = new LegoU8[m_width * m_width]; + LegoU8* src = m_bits; + LegoU8* dst = newBits; + + for (LegoU32 row = 0; row < m_height; row++) { + if (aspect) { + for (LegoU32 dup = aspect; dup; dup--) { + memcpy(dst, src, m_width); + dst += m_width; + } + } + src += m_width; + } + + m_height = m_width; + } + else { + LegoU32 aspect = m_height / m_width; + newBits = new LegoU8[m_height * m_height]; + LegoU8* src = m_bits; + LegoU8* dst = newBits; + + for (LegoU32 row = 0; row < m_height; row++) { + for (LegoU32 col = 0; col < m_width; col++) { + if (aspect) { + for (LegoU32 dup = aspect; dup; dup--) { + *dst = *src; + dst++; + } + } + + src++; + } + } + + m_width = m_height; + } + + delete[] m_bits; + m_bits = newBits; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100997e0 +LegoResult LegoImage::Write(LegoStorage* p_storage) +{ + LegoResult result; + if ((result = p_storage->Write(&m_width, sizeof(m_width))) != SUCCESS) { + return result; + } + if ((result = p_storage->Write(&m_height, sizeof(m_height))) != SUCCESS) { + return result; + } + if ((result = p_storage->Write(&m_count, sizeof(m_height))) != SUCCESS) { + return result; + } + for (LegoU32 i = 0; i < m_count; i++) { + if ((result = m_palette[i].Write(p_storage)) != SUCCESS) { + return result; + } + } + if (m_bits) { + if ((result = p_storage->Write(m_bits, m_width * m_height)) != SUCCESS) { + return result; + } + } + return SUCCESS; +} diff --git a/LEGO1/lego/sources/misc/legoimage.h b/LEGO1/lego/sources/misc/legoimage.h new file mode 100644 index 00000000..7e0fbb17 --- /dev/null +++ b/LEGO1/lego/sources/misc/legoimage.h @@ -0,0 +1,55 @@ +#ifndef __LEGOIMAGE_H +#define __LEGOIMAGE_H + +#include "legotypes.h" + +class LegoStorage; + +// SIZE 0x03 +class LegoPaletteEntry { +public: + LegoPaletteEntry(); + // LegoPaletteEntry(LegoU8 p_red, LegoU8 p_green, LegoU8 p_blue); + LegoU8 GetRed() { return m_red; } + void SetRed(LegoU8 p_red) { m_red = p_red; } + LegoU8 GetGreen() { return m_green; } + void SetGreen(LegoU8 p_green) { m_green = p_green; } + LegoU8 GetBlue() { return m_blue; } + void SetBlue(LegoU8 p_blue) { m_blue = p_blue; } + LegoResult Read(LegoStorage* p_storage); + LegoResult Write(LegoStorage* p_storage); + +protected: + LegoU8 m_red; // 0x00 + LegoU8 m_green; // 0x01 + LegoU8 m_blue; // 0x02 +}; + +// 0x310 +class LegoImage { +public: + LegoImage(); + LegoImage(LegoU32 p_width, LegoU32 p_height); + ~LegoImage(); + LegoU32 GetWidth() { return m_width; } + void SetWidth(LegoU32 p_width) { m_width = p_width; } + LegoU32 GetHeight() { return m_height; } + void SetHeight(LegoU32 p_height) { m_height = p_height; } + LegoU32 GetCount() { return m_count; } + LegoPaletteEntry* GetPalette() { return m_palette; } + LegoPaletteEntry& GetPaletteEntry(LegoU32 p_i) { return m_palette[p_i]; } + void SetPaletteEntry(LegoU32 p_i, LegoPaletteEntry& p_paletteEntry) { m_palette[p_i] = p_paletteEntry; } + LegoU8* GetBits() { return m_bits; } + void SetBits(LegoU8* p_bits) { m_bits = p_bits; } + LegoResult Read(LegoStorage* p_storage, LegoU32 p_square); + LegoResult Write(LegoStorage* p_storage); + +protected: + LegoU32 m_width; // 0x00 + LegoU32 m_height; // 0x04 + LegoU32 m_count; // 0x08 + LegoPaletteEntry m_palette[256]; // 0x0c + LegoU8* m_bits; // 0x30c +}; + +#endif // __LEGOIMAGE_H diff --git a/LEGO1/lego/sources/misc/legostorage.cpp b/LEGO1/lego/sources/misc/legostorage.cpp new file mode 100644 index 00000000..7da93569 --- /dev/null +++ b/LEGO1/lego/sources/misc/legostorage.cpp @@ -0,0 +1,128 @@ +#include "legostorage.h" + +#include "decomp.h" + +#include +#include + +DECOMP_SIZE_ASSERT(LegoStorage, 0x08); +DECOMP_SIZE_ASSERT(LegoMemory, 0x10); +DECOMP_SIZE_ASSERT(LegoFile, 0x0c); + +// FUNCTION: LEGO1 0x10099080 +LegoMemory::LegoMemory(void* p_buffer) : LegoStorage() +{ + m_buffer = (LegoU8*) p_buffer; + m_position = 0; +} + +// FUNCTION: LEGO1 0x10099160 +LegoResult LegoMemory::Read(void* p_buffer, LegoU32 p_size) +{ + memcpy(p_buffer, m_buffer + m_position, p_size); + m_position += p_size; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10099190 +LegoResult LegoMemory::Write(const void* p_buffer, LegoU32 p_size) +{ + memcpy(m_buffer + m_position, p_buffer, p_size); + m_position += p_size; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100991c0 +LegoFile::LegoFile() +{ + m_file = NULL; +} + +// FUNCTION: LEGO1 0x10099250 +LegoFile::~LegoFile() +{ + if (m_file) { + fclose(m_file); + } +} + +// FUNCTION: LEGO1 0x100992c0 +LegoResult LegoFile::Read(void* p_buffer, LegoU32 p_size) +{ + if (!m_file) { + return FAILURE; + } + if (fread(p_buffer, 1, p_size, m_file) != p_size) { + return FAILURE; + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10099300 +LegoResult LegoFile::Write(const void* p_buffer, LegoU32 p_size) +{ + if (!m_file) { + return FAILURE; + } + if (fwrite(p_buffer, 1, p_size, m_file) != p_size) { + return FAILURE; + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10099340 +LegoResult LegoFile::GetPosition(LegoU32& p_position) +{ + if (!m_file) { + return FAILURE; + } + LegoU32 position = ftell(m_file); + if (position == -1) { + return FAILURE; + } + p_position = position; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x10099370 +LegoResult LegoFile::SetPosition(LegoU32 p_position) +{ + if (!m_file) { + return FAILURE; + } + if (fseek(m_file, p_position, SEEK_SET) != 0) { + return FAILURE; + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100993a0 +LegoResult LegoFile::Open(const char* p_name, LegoU32 p_mode) +{ + if (m_file) { + fclose(m_file); + } + char mode[4]; + mode[0] = '\0'; + if (p_mode & c_read) { + m_mode = c_read; + strcat(mode, "r"); + } + if (p_mode & c_write) { + if (m_mode != c_read) { + m_mode = c_write; + } + strcat(mode, "w"); + } + if ((p_mode & c_text) != 0) { + strcat(mode, "t"); + } + else { + strcat(mode, "b"); + } + + if (!(m_file = fopen(p_name, mode))) { + return FAILURE; + } + return SUCCESS; +} diff --git a/LEGO1/lego/sources/misc/legostorage.h b/LEGO1/lego/sources/misc/legostorage.h new file mode 100644 index 00000000..5934617b --- /dev/null +++ b/LEGO1/lego/sources/misc/legostorage.h @@ -0,0 +1,159 @@ +#ifndef __LEGOSTORAGE_H +#define __LEGOSTORAGE_H + +#include "legotypes.h" +#include "mxgeometry/mxgeometry3d.h" +#include "mxstring.h" + +#include + +// VTABLE: LEGO1 0x100d7d80 +// SIZE 0x08 +class LegoStorage { +public: + enum OpenFlags { + c_read = 1, + c_write = 2, + c_text = 4 + }; + + LegoStorage() : m_mode(0) {} + + // FUNCTION: LEGO1 0x10045ad0 + virtual ~LegoStorage() {} + + virtual LegoResult Read(void* p_buffer, LegoU32 p_size) = 0; // vtable+0x04 + virtual LegoResult Write(const void* p_buffer, LegoU32 p_size) = 0; // vtable+0x08 + virtual LegoResult GetPosition(LegoU32& p_position) = 0; // vtable+0x0c + virtual LegoResult SetPosition(LegoU32 p_position) = 0; // vtable+0x10 + + // FUNCTION: LEGO1 0x10045ae0 + virtual LegoBool IsWriteMode() { return m_mode == c_write; } // vtable+0x14 + + // FUNCTION: LEGO1 0x10045af0 + virtual LegoBool IsReadMode() { return m_mode == c_read; } // vtable+0x18 + + // SYNTHETIC: LEGO1 0x10045b00 + // LegoStorage::`scalar deleting destructor' + +protected: + LegoU8 m_mode; // 0x04 +}; + +template +inline void Read(LegoStorage* p_storage, T* p_variable, LegoU32 p_size = sizeof(T)) +{ + p_storage->Read(p_variable, p_size); +} + +template +inline void Write(LegoStorage* p_storage, T p_variable) +{ + p_storage->Write(&p_variable, sizeof(p_variable)); +} + +// VTABLE: LEGO1 0x100db710 +// SIZE 0x10 +class LegoMemory : public LegoStorage { +public: + LegoMemory(void* p_buffer); + LegoResult Read(void* p_buffer, LegoU32 p_size) override; // vtable+0x04 + LegoResult Write(const void* p_buffer, LegoU32 p_size) override; // vtable+0x08 + + // FUNCTION: LEGO1 0x100994a0 + LegoResult GetPosition(LegoU32& p_position) override // vtable+0x0c + { + p_position = m_position; + return SUCCESS; + } + + // FUNCTION: LEGO1 0x100994b0 + LegoResult SetPosition(LegoU32 p_position) override // vtable+0x10 + { + m_position = p_position; + return SUCCESS; + } + + // SYNTHETIC: LEGO1 0x10045a80 + // LegoMemory::~LegoMemory + + // SYNTHETIC: LEGO1 0x100990f0 + // LegoMemory::`scalar deleting destructor' + +protected: + LegoU8* m_buffer; // 0x04 + LegoU32 m_position; // 0x08 +}; + +// VTABLE: LEGO1 0x100db730 +// SIZE 0x0c +class LegoFile : public LegoStorage { +public: + LegoFile(); + ~LegoFile() override; + LegoResult Read(void* p_buffer, LegoU32 p_size) override; // vtable+0x04 + LegoResult Write(const void* p_buffer, LegoU32 p_size) override; // vtable+0x08 + LegoResult GetPosition(LegoU32& p_position) override; // vtable+0x0c + LegoResult SetPosition(LegoU32 p_position) override; // vtable+0x10 + LegoResult Open(const char* p_name, LegoU32 p_mode); + + // FUNCTION: LEGO1 0x100343d0 + LegoStorage* WriteVector3(Mx3DPointFloat p_vec3) + { + float data = p_vec3[0]; + Write(&data, sizeof(float)); + + data = p_vec3[1]; + Write(&data, sizeof(float)); + + data = p_vec3[2]; + Write(&data, sizeof(float)); + return this; + } + + // FUNCTION: LEGO1 0x10034430 + LegoStorage* ReadVector3(Mx3DPointFloat& p_vec3) + { + Read(&p_vec3[0], sizeof(float)); + Read(&p_vec3[1], sizeof(float)); + Read(&p_vec3[2], sizeof(float)); + return this; + } + + // FUNCTION: LEGO1 0x10034470 + LegoStorage* ReadString(MxString& p_str) + { + MxS16 len; + Read(&len, sizeof(MxS16)); + + char* text = new char[len + 1]; + Read(text, len); + + text[len] = '\0'; + p_str = text; + delete[] text; + + return this; + } + + // FUNCTION: LEGO1 0x10006030 + LegoStorage* WriteString(MxString p_str) + { + const char* data = p_str.GetData(); + LegoU32 fullLength = strlen(data); + + LegoU16 limitedLength = fullLength; + Write(&limitedLength, sizeof(limitedLength)); + Write((char*) data, (LegoS16) fullLength); + + return this; + } + + // SYNTHETIC: LEGO1 0x10099230 + // LegoFile::`scalar deleting destructor' + +protected: + FILE* m_file; // 0x08 +}; + +#endif // __LEGOSTORAGE_H diff --git a/LEGO1/lego/sources/misc/legotexture.cpp b/LEGO1/lego/sources/misc/legotexture.cpp new file mode 100644 index 00000000..1f8844ff --- /dev/null +++ b/LEGO1/lego/sources/misc/legotexture.cpp @@ -0,0 +1,31 @@ +#include "legotexture.h" + +#include "decomp.h" +#include "legoimage.h" +#include "legostorage.h" + +DECOMP_SIZE_ASSERT(LegoTexture, 0x04); + +// FUNCTION: LEGO1 0x10098fb0 +LegoTexture::LegoTexture() +{ + m_image = new LegoImage(); +} + +// FUNCTION: LEGO1 0x10099030 +LegoTexture::~LegoTexture() +{ + delete m_image; +} + +// FUNCTION: LEGO1 0x10099050 +LegoResult LegoTexture::Read(LegoStorage* p_storage, LegoU32 p_square) +{ + return m_image->Read(p_storage, p_square); +} + +// FUNCTION: LEGO1 0x10099070 +LegoResult LegoTexture::Write(LegoStorage* p_storage) +{ + return m_image->Write(p_storage); +} diff --git a/LEGO1/lego/sources/misc/legotexture.h b/LEGO1/lego/sources/misc/legotexture.h new file mode 100644 index 00000000..1e279660 --- /dev/null +++ b/LEGO1/lego/sources/misc/legotexture.h @@ -0,0 +1,23 @@ +#ifndef __LEGOTEXTURE_H +#define __LEGOTEXTURE_H + +#include "legotypes.h" + +class LegoImage; +class LegoStorage; + +// SIZE 0x04 +class LegoTexture { +public: + LegoTexture(); + ~LegoTexture(); + LegoImage* GetImage() { return m_image; } + void SetImage(LegoImage* p_image) { m_image = p_image; } + LegoResult Read(LegoStorage* p_storage, LegoU32 p_square); + LegoResult Write(LegoStorage* p_storage); + +protected: + LegoImage* m_image; // 0x00 +}; + +#endif // __LEGOTEXTURE_H diff --git a/LEGO1/lego/sources/misc/legotree.cpp b/LEGO1/lego/sources/misc/legotree.cpp new file mode 100644 index 00000000..e7f24513 --- /dev/null +++ b/LEGO1/lego/sources/misc/legotree.cpp @@ -0,0 +1,110 @@ +#include "legotree.h" + +#include "decomp.h" +#include "legostorage.h" + +DECOMP_SIZE_ASSERT(LegoTreeNodeData, 0x04) +DECOMP_SIZE_ASSERT(LegoTreeNode, 0x010) +DECOMP_SIZE_ASSERT(LegoTree, 0x08) + +// FUNCTION: LEGO1 0x10099d60 +LegoTreeNode::LegoTreeNode() +{ + m_data = NULL; + m_numChildren = 0; + m_children = NULL; +} + +// FUNCTION: LEGO1 0x10099da0 +LegoTreeNode::~LegoTreeNode() +{ + if (m_data) { + delete m_data; + } + if (m_children) { + delete[] m_children; + } +} + +// FUNCTION: LEGO1 0x10099dd0 +LegoTree::LegoTree() +{ + m_root = NULL; +} + +// FUNCTION: LEGO1 0x10099e00 +LegoTree::~LegoTree() +{ + if (m_root) { + Delete(m_root); + } +} + +// FUNCTION: LEGO1 0x10099e20 +LegoResult LegoTree::Read(LegoStorage* p_storage) +{ + return Read(p_storage, m_root); +} + +// FUNCTION: LEGO1 0x10099e40 +LegoResult LegoTree::Write(LegoStorage* p_storage) +{ + return Write(p_storage, m_root); +} + +// FUNCTION: LEGO1 0x10099e60 +LegoResult LegoTree::Read(LegoStorage* p_storage, LegoTreeNode*& p_node) +{ + LegoResult result; + p_node = new LegoTreeNode(); + p_node->SetData(CreateData()); + if ((result = p_node->GetData()->Read(p_storage)) != SUCCESS) { + return result; + } + LegoU32 numChildren; + if ((result = p_storage->Read(&numChildren, sizeof(numChildren))) != SUCCESS) { + return result; + } + if (numChildren) { + p_node->SetChildren(new LegoTreeNode*[numChildren]); + for (LegoU32 i = 0; i < numChildren; i++) { + LegoTreeNode* node; + if ((result = Read(p_storage, node)) != SUCCESS) { + return result; + } + p_node->SetNumChildren(p_node->GetNumChildren() + 1); + p_node->SetChild(i, node); + } + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1009a020 +LegoResult LegoTree::Write(LegoStorage* p_storage, LegoTreeNode* p_node) +{ + LegoResult result; + if (p_node->GetData()) { + if ((result = p_node->GetData()->Write(p_storage)) != SUCCESS) { + return result; + } + } + LegoU32 numChildren = p_node->GetNumChildren(); + if ((result = p_storage->Write(&numChildren, sizeof(numChildren))) != SUCCESS) { + return result; + } + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + if ((result = Write(p_storage, p_node->GetChild(i))) != SUCCESS) { + return result; + } + } + return SUCCESS; +} + +// FUNCTION: LEGO1 0x1009a0a0 +void LegoTree::Delete(LegoTreeNode* p_node) +{ + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + Delete(p_node->GetChild(i)); + } + delete p_node; +} diff --git a/LEGO1/lego/sources/misc/legotree.h b/LEGO1/lego/sources/misc/legotree.h new file mode 100644 index 00000000..9d4aec69 --- /dev/null +++ b/LEGO1/lego/sources/misc/legotree.h @@ -0,0 +1,78 @@ +#ifndef __LEGOTREE_H +#define __LEGOTREE_H + +#ifdef _DEBUG +#include +#endif +#include "legotypes.h" + +class LegoStorage; + +// VTABLE: LEGO1 0x100db778 +// SIZE 0x04 +class LegoTreeNodeData { +public: + LegoTreeNodeData() {} + // FUNCTION: LEGO1 0x1009a0e0 + virtual ~LegoTreeNodeData() {} + + // FUNCTION: LEGO1 0x10099fe0 + virtual LegoResult Read(LegoStorage* p_storage) { return SUCCESS; } // vtable+0x04 + + // FUNCTION: LEGO1 0x10099ff0 + virtual LegoResult Write(LegoStorage* p_storage) { return SUCCESS; } // vtable+0x08 + + // SYNTHETIC: LEGO1 0x1009a000 + // LegoTreeNodeData::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100db764 +// SIZE 0x10 +class LegoTreeNode { +public: + LegoTreeNode(); + virtual ~LegoTreeNode(); + LegoTreeNodeData* GetData() { return m_data; } + void SetData(LegoTreeNodeData* p_data) { m_data = p_data; } + LegoU32 GetNumChildren() { return m_numChildren; } + void SetNumChildren(LegoU32 p_numChildren) { m_numChildren = p_numChildren; } + LegoTreeNode* GetChild(LegoU32 p_i) { return m_children[p_i]; } + void SetChild(LegoU32 p_i, LegoTreeNode* p_child) { m_children[p_i] = p_child; } + LegoTreeNode** GetChildren() { return m_children; } + void SetChildren(LegoTreeNode** p_children) { m_children = p_children; } + + // SYNTHETIC: LEGO1 0x10099d80 + // LegoTreeNode::`scalar deleting destructor' + +protected: + LegoTreeNodeData* m_data; // 0x04 + LegoU32 m_numChildren; // 0x08 + LegoTreeNode** m_children; // 0x0c +}; + +// VTABLE: LEGO1 0x100db768 +// SIZE 0x08 +class LegoTree { +public: + LegoTree(); + virtual ~LegoTree(); + LegoTreeNode* GetRoot() { return m_root; } + void SetRoot(LegoTreeNode* p_root) { m_root = p_root; } + virtual LegoResult Read(LegoStorage* p_storage); // vtable+0x04 + virtual LegoResult Write(LegoStorage* p_storage); // vtable+0x08 + + // SYNTHETIC: LEGO1 0x10099de0 + // LegoTree::`scalar deleting destructor' + +protected: + LegoResult Read(LegoStorage* p_storage, LegoTreeNode*& p_node); + LegoResult Write(LegoStorage* p_storage, LegoTreeNode* p_node); + void Delete(LegoTreeNode* p_node); + + // FUNCTION: LEGO1 0x10099f70 + virtual LegoTreeNodeData* CreateData() { return new LegoTreeNodeData(); } // vtable+0x0c + + LegoTreeNode* m_root; // 0x04 +}; + +#endif // __LEGOTREE_H diff --git a/LEGO1/lego/sources/misc/legotypes.h b/LEGO1/lego/sources/misc/legotypes.h new file mode 100644 index 00000000..7ba6ada1 --- /dev/null +++ b/LEGO1/lego/sources/misc/legotypes.h @@ -0,0 +1,44 @@ +/* + This unpublished source code contains trade secrets and + copyrighted materials which are the property of Mindscape, Inc. + Unauthorized use, copying or distribution is a violation of U.S. + and international laws and is strictly prohibited. +*/ + +#ifndef __LEGOTYPES_H +#define __LEGOTYPES_H + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#ifndef SUCCESS +#define SUCCESS 0 +#endif + +#ifndef FAILURE +#define FAILURE -1 +#endif + +typedef char LegoS8; +typedef unsigned char LegoU8; +typedef short LegoS16; +typedef unsigned short LegoU16; +typedef long LegoS32; +typedef unsigned long LegoU32; +typedef float LegoFloat; +typedef char LegoChar; + +typedef LegoU8 LegoBool; +typedef LegoS32 LegoTime; +typedef LegoS32 LegoResult; + +#endif // __LEGOTYPES_H diff --git a/LEGO1/lego/sources/misc/legounknown.cpp b/LEGO1/lego/sources/misc/legounknown.cpp new file mode 100644 index 00000000..14178e44 --- /dev/null +++ b/LEGO1/lego/sources/misc/legounknown.cpp @@ -0,0 +1,34 @@ +#include "legounknown.h" + +DECOMP_SIZE_ASSERT(LegoUnknown, 0x50) + +// FUNCTION: LEGO1 0x1009a0f0 +LegoUnknown::LegoUnknown() +{ + for (LegoS32 i = 0; i < sizeOfArray(m_unk0x00); i++) { + m_unk0x00[i].Clear(); + } +} + +// FUNCTION: LEGO1 0x1009a130 +LegoUnknown::~LegoUnknown() +{ +} + +// FUNCTION: LEGO1 0x1009a140 +void LegoUnknown::FUN_1009a140(Vector3& p_point1, Vector3& p_point2, Vector3& p_point3, Vector3& p_point4) +{ + m_unk0x00[0] = p_point1; + m_unk0x00[1] = p_point2; + + for (LegoS32 i = 0; i < 3; i++) { + m_unk0x00[2][i] = (p_point3[i] - p_point1[i]) * 3.0f - p_point2[i] * 2.0f - p_point4[i]; + m_unk0x00[3][i] = (p_point1[i] - p_point3[i]) * 2.0f + p_point4[i] + p_point2[i]; + } +} + +// STUB: LEGO1 0x1009a1e0 +LegoResult LegoUnknown::FUN_1009a1e0(float, Matrix4&, Vector3&, LegoU32) +{ + return FAILURE; +} diff --git a/LEGO1/lego/sources/misc/legounknown.h b/LEGO1/lego/sources/misc/legounknown.h new file mode 100644 index 00000000..03eafcee --- /dev/null +++ b/LEGO1/lego/sources/misc/legounknown.h @@ -0,0 +1,22 @@ +#ifndef __LEGOUNKNOWN_H +#define __LEGOUNKNOWN_H + +#include "legotypes.h" +#include "mxgeometry/mxgeometry3d.h" + +class Matrix4; + +// SIZE 0x50 +class LegoUnknown { +public: + LegoUnknown(); + ~LegoUnknown(); + + void FUN_1009a140(Vector3& p_point1, Vector3& p_point2, Vector3& p_point3, Vector3& p_point4); + LegoResult FUN_1009a1e0(float, Matrix4&, Vector3&, LegoU32); + +private: + Mx3DPointFloat m_unk0x00[4]; // 0x00 +}; + +#endif // __LEGOUNKNOWN_H diff --git a/LEGO1/lego/sources/misc/legoutil.h b/LEGO1/lego/sources/misc/legoutil.h new file mode 100644 index 00000000..92bb84c2 --- /dev/null +++ b/LEGO1/lego/sources/misc/legoutil.h @@ -0,0 +1,54 @@ +#ifndef __LEGOUTIL_H +#define __LEGOUTIL_H + +template +inline T Min(T p_t1, T p_t2) +{ + return p_t1 < p_t2 ? p_t1 : p_t2; +} + +template +inline T Min(T p_t1, T p_t2, T p_t3) +{ + return Min(p_t1, Min(p_t2, p_t3)); +} + +template +inline T Max(T p_t1, T p_t2) +{ + return p_t1 > p_t2 ? p_t1 : p_t2; +} + +template +inline T Max(T p_t1, T p_t2, T p_t3) +{ + return Max(p_t1, Max(p_t2, p_t3)); +} + +template +inline T Abs(T p_t) +{ + return p_t < 0 ? -p_t : p_t; +} + +template +inline void Swap(T& p_t1, T& p_t2) +{ + T t = p_t1; + p_t1 = p_t2; + p_t2 = t; +} + +template +inline T DToR(T p_d) +{ + return p_d * 3.1416F / 180.0F; +} + +template +inline T RToD(T p_r) +{ + return p_r * 180.0F / 3.1416F; +} + +#endif // __LEGOUTIL_H diff --git a/LEGO1/lego/sources/misc/version.h b/LEGO1/lego/sources/misc/version.h new file mode 100644 index 00000000..7f88091c --- /dev/null +++ b/LEGO1/lego/sources/misc/version.h @@ -0,0 +1,6 @@ +#ifndef __VERSION_H +#define __VERSION_H + +#define MODEL_VERSION 19 + +#endif // __VERSION_H diff --git a/LEGO1/lego/sources/roi/legolod.cpp b/LEGO1/lego/sources/roi/legolod.cpp new file mode 100644 index 00000000..2170c101 --- /dev/null +++ b/LEGO1/lego/sources/roi/legolod.cpp @@ -0,0 +1,401 @@ + +#include "legolod.h" + +#include "geom/legomesh.h" +#include "legoroi.h" +#include "misc/legocontainer.h" +#include "misc/legostorage.h" +#include "tgl/d3drm/impl.h" + +DECOMP_SIZE_ASSERT(LODObject, 0x04) +DECOMP_SIZE_ASSERT(ViewLOD, 0x0c) +DECOMP_SIZE_ASSERT(LegoLOD, 0x20) +DECOMP_SIZE_ASSERT(LegoLOD::Mesh, 0x08) + +// GLOBAL: LEGO1 0x101013d4 +LPDIRECT3DRMMATERIAL g_unk0x101013d4 = NULL; + +// GLOBAL: LEGO1 0x101013dc +const char* g_unk0x101013dc = "inh"; + +inline IDirect3DRM2* GetD3DRM(Tgl::Renderer* pRenderer); +inline BOOL GetMeshData(IDirect3DRMMesh*& mesh, D3DRMGROUPINDEX& index, Tgl::Mesh* pMesh); + +// FUNCTION: LEGO1 0x100aa380 +LegoLOD::LegoLOD(Tgl::Renderer* p_renderer) : ViewLOD(p_renderer) +{ + if (g_unk0x101013d4 == NULL) { + GetD3DRM(p_renderer)->CreateMaterial(10.0, &g_unk0x101013d4); + } + + m_melems = NULL; + m_numMeshes = 0; + m_numVertices = 0; + m_numPolys = 0; + m_unk0x1c = 0; +} + +// FUNCTION: LEGO1 0x100aa450 +LegoLOD::~LegoLOD() +{ + if (m_numMeshes && m_melems != NULL) { + for (LegoU32 i = 0; i < m_numMeshes; i++) { + if (m_melems[i].m_tglMesh != NULL) { + delete m_melems[i].m_tglMesh; + m_melems[i].m_tglMesh = NULL; + } + } + } + + if (m_melems) { + delete[] m_melems; + } +} + +// FUNCTION: LEGO1 0x100aa510 +LegoResult LegoLOD::Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_textureContainer, LegoStorage* p_storage) +{ + float(*normals)[3] = NULL; + float(*vertices)[3] = NULL; + float(*textureVertices)[2] = NULL; + LegoS32 numVerts = 0; + LegoS32 numNormals = 0; + LegoS32 numTextureVertices = 0; + LegoMesh* mesh = NULL; + LegoU32(*polyIndices)[3] = NULL; + LegoU32(*textureIndices)[3] = NULL; + LegoTextureInfo* textureInfo = NULL; + + LegoU32 i, meshUnd1, meshUnd2, tempNumVertsAndNormals; + unsigned char paletteEntries[256]; + + if (p_storage->Read(&m_unk0x08, sizeof(m_unk0x08)) != SUCCESS) { + goto done; + } + + if (GetUnknown0x08Test4()) { + return SUCCESS; + } + + m_meshBuilder = p_renderer->CreateMeshBuilder(); + + if (p_storage->Read(&m_numMeshes, sizeof(m_numMeshes)) != SUCCESS) { + goto done; + } + + if (m_numMeshes == 0) { + ClearFlag(c_bit4); + return SUCCESS; + } + + SetFlag(c_bit4); + + m_melems = new Mesh[m_numMeshes]; + memset(m_melems, 0, sizeof(*m_melems) * m_numMeshes); + + meshUnd1 = m_numMeshes - 1; + meshUnd2 = 0; + + if (p_storage->Read(&tempNumVertsAndNormals, sizeof(tempNumVertsAndNormals)) != SUCCESS) { + goto done; + } + + numVerts = *((LegoU16*) &tempNumVertsAndNormals) & MAXSHORT; + numNormals = (*((LegoU16*) &tempNumVertsAndNormals + 1) >> 1) & MAXSHORT; + + if (p_storage->Read(&numTextureVertices, sizeof(numTextureVertices)) != SUCCESS) { + goto done; + } + + if (numVerts > 0) { + vertices = new float[numVerts][sizeOfArray(*vertices)]; + if (p_storage->Read(vertices, numVerts * sizeof(*vertices)) != SUCCESS) { + goto done; + } + } + + if (numNormals > 0) { + normals = new float[numNormals][sizeOfArray(*normals)]; + if (p_storage->Read(normals, numNormals * sizeof(*normals)) != SUCCESS) { + goto done; + } + } + + if (numTextureVertices > 0) { + textureVertices = new float[numTextureVertices][sizeOfArray(*textureVertices)]; + if (p_storage->Read(textureVertices, numTextureVertices * sizeof(*textureVertices)) != SUCCESS) { + goto done; + } + } + + for (i = 0; i < m_numMeshes; i++) { + LegoU32 numPolys, numVertices, numTextureIndices, meshIndex; + const LegoChar *textureName, *materialName; + Tgl::ShadingModel shadingModel; + + if (p_storage->Read(&numPolys, 2) != SUCCESS) { + goto done; + } + + m_numPolys += numPolys & MAXWORD; + + if (p_storage->Read(&numVertices, 2) != SUCCESS) { + goto done; + } + + polyIndices = new LegoU32[numPolys & MAXWORD][sizeOfArray(*polyIndices)]; + if (p_storage->Read(polyIndices, (numPolys & MAXWORD) * sizeof(*polyIndices)) != SUCCESS) { + goto done; + } + + if (p_storage->Read(&numTextureIndices, sizeof(numTextureIndices)) != SUCCESS) { + goto done; + } + + if (numTextureIndices > 0) { + textureIndices = new LegoU32[numPolys & MAXWORD][sizeOfArray(*textureIndices)]; + if (p_storage->Read(textureIndices, (numPolys & MAXWORD) * sizeof(*textureIndices)) != SUCCESS) { + goto done; + } + } + else { + textureIndices = NULL; + } + + mesh = new LegoMesh(); + + if (mesh->Read(p_storage) != SUCCESS) { + goto done; + } + + switch (mesh->GetShading()) { + case LegoMesh::e_flat: + shadingModel = Tgl::Flat; + break; + case LegoMesh::e_wireframe: + shadingModel = Tgl::Wireframe; + break; + default: + shadingModel = Tgl::Gouraud; + } + + m_numVertices += numVertices & MAXWORD; + + textureName = mesh->GetTextureName(); + materialName = mesh->GetMaterialName(); + + if (FUN_100aae20(textureName) || FUN_100aae20(materialName)) { + meshIndex = meshUnd1; + meshUnd1--; + } + else { + meshIndex = meshUnd2; + meshUnd2++; + } + + m_melems[meshIndex].m_tglMesh = m_meshBuilder->CreateMesh( + numPolys & MAXWORD, + numVertices & MAXWORD, + vertices, + normals, + textureVertices, + polyIndices, + textureIndices, + shadingModel + ); + + if (m_melems[meshIndex].m_tglMesh == NULL) { + goto done; + } + + m_melems[meshIndex].m_tglMesh->SetShadingModel(shadingModel); + + if (textureName != NULL) { + if (mesh->GetUnknown0x21()) { + LegoROI::FUN_100a9cf0(textureName, paletteEntries, sizeOfArray(paletteEntries)); + } + + textureInfo = p_textureContainer->Get(mesh->GetTextureName()); + + if (textureInfo == NULL) { + goto done; + } + + m_melems[meshIndex].m_tglMesh->SetColor(1.0F, 1.0F, 1.0F, 0.0F); + LegoTextureInfo::SetGroupTexture(m_melems[meshIndex].m_tglMesh, textureInfo); + m_melems[meshIndex].m_unk0x04 = TRUE; + } + else { + LegoFloat red = 1.0F; + LegoFloat green = 0.0F; + LegoFloat blue = 1.0F; + LegoFloat alpha = 0.0F; + + if (mesh->GetUnknown0x21()) { + LegoROI::FUN_100a9bf0(materialName, red, green, blue, alpha); + } + else { + red = mesh->GetColor().GetRed() / 255.0; + green = mesh->GetColor().GetGreen() / 255.0; + blue = mesh->GetColor().GetBlue() / 255.0; + alpha = mesh->GetAlpha(); + } + + m_melems[meshIndex].m_tglMesh->SetColor(red, green, blue, alpha); + } + + if (mesh->GetUnknown0x0d() > 0) { + IDirect3DRMMesh* mesh; + D3DRMGROUPINDEX index; + GetMeshData(mesh, index, m_melems[meshIndex].m_tglMesh); + mesh->SetGroupMaterial(index, g_unk0x101013d4); + } + + if (mesh != NULL) { + delete mesh; + mesh = NULL; + } + if (polyIndices != NULL) { + delete[] polyIndices; + polyIndices = NULL; + } + if (textureIndices != NULL) { + delete[] textureIndices; + textureIndices = NULL; + } + } + + m_unk0x1c = meshUnd2; + + if (textureVertices != NULL) { + delete[] textureVertices; + } + if (normals != NULL) { + delete[] normals; + } + if (vertices != NULL) { + delete[] vertices; + } + + return SUCCESS; + +done: + if (normals != NULL) { + delete[] normals; + } + if (vertices != NULL) { + delete[] vertices; + } + if (textureVertices != NULL) { + delete[] textureVertices; + } + if (mesh != NULL) { + delete mesh; + } + if (polyIndices != NULL) { + delete[] polyIndices; + } + if (textureIndices != NULL) { + delete[] textureIndices; + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x100aabb0 +LegoLOD* LegoLOD::Clone(Tgl::Renderer* p_renderer) +{ + LegoLOD* dupLod = new LegoLOD(p_renderer); + + dupLod->m_meshBuilder = m_meshBuilder->Clone(); + dupLod->m_melems = new Mesh[m_numMeshes]; + + for (LegoU32 i = 0; i < m_numMeshes; i++) { + dupLod->m_melems[i].m_tglMesh = m_melems[i].m_tglMesh->ShallowClone(dupLod->m_meshBuilder); + dupLod->m_melems[i].m_unk0x04 = m_melems[i].m_unk0x04; + } + + dupLod->m_unk0x08 = m_unk0x08; + dupLod->m_numMeshes = m_numMeshes; + dupLod->m_numVertices = m_numVertices; + dupLod->m_numPolys = m_numPolys; + dupLod->m_unk0x1c = m_unk0x1c; + + return dupLod; +} + +// FUNCTION: LEGO1 0x100aacb0 +LegoResult LegoLOD::FUN_100aacb0(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha) +{ + for (LegoU32 i = m_unk0x1c; i < m_numMeshes; i++) { + if (!m_melems[i].m_unk0x04) { + m_melems[i].m_tglMesh->SetColor(p_red, p_green, p_blue, p_alpha); + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100aad00 +LegoResult LegoLOD::FUN_100aad00(LegoTextureInfo* p_textureInfo) +{ + for (LegoU32 i = m_unk0x1c; i < m_numMeshes; i++) { + if (m_melems[i].m_unk0x04) { + LegoTextureInfo::SetGroupTexture(m_melems[i].m_tglMesh, p_textureInfo); + m_melems[i].m_tglMesh->SetColor(1.0F, 1.0F, 1.0F, 0.0F); + m_melems[i].m_unk0x04 = TRUE; + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100aad70 +LegoResult LegoLOD::FUN_100aad70(LegoTextureInfo* p_textureInfo) +{ + for (LegoU32 i = m_unk0x1c; i < m_numMeshes; i++) { + if (m_melems[i].m_unk0x04) { + LegoTextureInfo::SetGroupTexture(m_melems[i].m_tglMesh, p_textureInfo); + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100aadc0 +LegoResult LegoLOD::GetTexture(LegoTextureInfo*& p_textureInfo) +{ + for (LegoU32 i = m_unk0x1c; i < m_numMeshes; i++) { + if (m_melems[i].m_unk0x04) { + if (LegoTextureInfo::GetGroupTexture(m_melems[i].m_tglMesh, p_textureInfo) == TRUE) { + return SUCCESS; + } + } + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x100aae20 +LegoBool LegoLOD::FUN_100aae20(const LegoChar* p_name) +{ + if (p_name != NULL) { + if (!strnicmp(p_name, g_unk0x101013dc, strlen(g_unk0x101013dc))) { + return TRUE; + } + } + + return FALSE; +} + +inline BOOL GetMeshData(IDirect3DRMMesh*& mesh, D3DRMGROUPINDEX& index, Tgl::Mesh* pMesh) +{ + mesh = ((TglImpl::MeshImpl*) pMesh)->ImplementationData()->groupMesh; + index = ((TglImpl::MeshImpl*) pMesh)->ImplementationData()->groupIndex; + return FALSE; +} + +inline IDirect3DRM2* GetD3DRM(Tgl::Renderer* pRenderer) +{ + return ((TglImpl::RendererImpl*) pRenderer)->ImplementationData(); +} diff --git a/LEGO1/lego/sources/roi/legolod.h b/LEGO1/lego/sources/roi/legolod.h new file mode 100644 index 00000000..a47a3d24 --- /dev/null +++ b/LEGO1/lego/sources/roi/legolod.h @@ -0,0 +1,50 @@ +#ifndef LEGOLOD_H +#define LEGOLOD_H + +#include "misc/legotypes.h" +#include "viewmanager/viewlod.h" + +class LegoTextureContainer; +class LegoTextureInfo; +class LegoStorage; + +// VTABLE: LEGO1 0x100dbf10 +// SIZE 0x20 +class LegoLOD : public ViewLOD { +public: + // SIZE 0x08 + struct Mesh { + Tgl::Mesh* m_tglMesh; // 0x00 + BOOL m_unk0x04; // 0x04 + }; + + LegoLOD(Tgl::Renderer*); + ~LegoLOD() override; + + // FUNCTION: LEGO1 0x100aae70 + int NumPolys() const override { return m_numPolys; } // vtable+0x0c + + // FUNCTION: LEGO1 0x100aae80 + float VTable0x10() override { return 0.0; } // vtable+0x10 + + LegoResult Read(Tgl::Renderer* p_renderer, LegoTextureContainer* p_textureContainer, LegoStorage* p_storage); + LegoLOD* Clone(Tgl::Renderer* p_renderer); + LegoResult FUN_100aacb0(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha); + LegoResult FUN_100aad00(LegoTextureInfo* p_textureInfo); + LegoResult FUN_100aad70(LegoTextureInfo* p_textureInfo); + LegoResult GetTexture(LegoTextureInfo*& p_textureInfo); + + static LegoBool FUN_100aae20(const LegoChar* p_name); + + // SYNTHETIC: LEGO1 0x100aa430 + // LegoLOD::`scalar deleting destructor' + +protected: + Mesh* m_melems; // 0x0c + LegoU32 m_numMeshes; // 0x10 + LegoU32 m_numVertices; // 0x14 + LegoU32 m_numPolys; // 0x18 + undefined4 m_unk0x1c; // 0x1c +}; + +#endif // LEGOLOD_H diff --git a/LEGO1/lego/sources/roi/legoroi.cpp b/LEGO1/lego/sources/roi/legoroi.cpp new file mode 100644 index 00000000..33fbbb8e --- /dev/null +++ b/LEGO1/lego/sources/roi/legoroi.cpp @@ -0,0 +1,671 @@ +#include "legoroi.h" + +#include "anim/legoanim.h" +#include "geom/legobox.h" +#include "geom/legosphere.h" +#include "legolod.h" +#include "misc/legocontainer.h" +#include "misc/legostorage.h" +#include "realtime/realtime.h" + +#include +#include + +DECOMP_SIZE_ASSERT(LegoROI, 0x108) +DECOMP_SIZE_ASSERT(TimeROI, 0x10c) + +// SIZE 0x14 +typedef struct { + const char* m_name; + int m_red; + int m_green; + int m_blue; + int m_alpha; +} ROIColorAlias; + +// GLOBAL: LEGO1 0x101011b0 +ROIColorAlias g_roiColorAliases[22] = { + {"lego black", 0x21, 0x21, 0x21, 0}, {"lego black f", 0x21, 0x21, 0x21, 0}, + {"lego black flat", 0x21, 0x21, 0x21, 0}, {"lego blue", 0x00, 0x54, 0x8c, 0}, + {"lego blue flat", 0x00, 0x54, 0x8c, 0}, {"lego brown", 0x4a, 0x23, 0x1a, 0}, + {"lego brown flt", 0x4a, 0x23, 0x1a, 0}, {"lego brown flat", 0x4a, 0x23, 0x1a, 0}, + {"lego drk grey", 0x40, 0x40, 0x40, 0}, {"lego drk grey flt", 0x40, 0x40, 0x40, 0}, + {"lego dk grey flt", 0x40, 0x40, 0x40, 0}, {"lego green", 0x00, 0x78, 0x2d, 0}, + {"lego green flat", 0x00, 0x78, 0x2d, 0}, {"lego lt grey", 0x82, 0x82, 0x82, 0}, + {"lego lt grey flt", 0x82, 0x82, 0x82, 0}, {"lego lt grey fla", 0x82, 0x82, 0x82, 0}, + {"lego red", 0xcb, 0x12, 0x20, 0}, {"lego red flat", 0xcb, 0x12, 0x20, 0}, + {"lego white", 0xfa, 0xfa, 0xfa, 0}, {"lego white flat", 0xfa, 0xfa, 0xfa, 0}, + {"lego yellow", 0xff, 0xb9, 0x00, 0}, {"lego yellow flat", 0xff, 0xb9, 0x00, 0}, +}; + +// GLOBAL: LEGO1 0x10101368 +int g_roiConfig = 100; + +// GLOBAL: LEGO1 0x10101370 +const char* g_unk0x10101370[] = {"bike", "moto", NULL}; + +// GLOBAL: LEGO1 0x10101380 +const char* g_unk0x10101380[] = {"bike", "moto", "haus", NULL}; + +// GLOBAL: LEGO1 0x10101390 +const char* g_unk0x10101390[] = {"rcuser", "jsuser", "dunebugy", "chtrblad", "chtrbody", "chtrshld", NULL}; + +// GLOBAL: LEGO1 0x101013ac +ROIHandler g_unk0x101013ac = NULL; + +// FUNCTION: LEGO1 0x100a81b0 +void LegoROI::FUN_100a81b0(const LegoChar* p_error, const LegoChar* p_name) +{ +} + +// FUNCTION: LEGO1 0x100a81c0 +void LegoROI::configureLegoROI(int p_roiConfig) +{ + g_roiConfig = p_roiConfig; +} + +// FUNCTION: LEGO1 0x100a81d0 +LegoROI::LegoROI(Tgl::Renderer* p_renderer) : ViewROI(p_renderer, NULL) +{ + m_parentROI = NULL; + m_name = NULL; + m_entity = NULL; +} + +// FUNCTION: LEGO1 0x100a82d0 +LegoROI::LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList) : ViewROI(p_renderer, p_lodList) +{ + m_parentROI = NULL; + m_name = NULL; + m_entity = NULL; +} + +// FUNCTION: LEGO1 0x100a83c0 +LegoROI::~LegoROI() +{ + if (comp) { + CompoundObject::iterator iterator; + + for (iterator = comp->begin(); !(iterator == comp->end()); ++iterator) { + ROI* child = *iterator; + + delete child; + } + + delete comp; + comp = 0; + } + if (m_name) { + delete[] m_name; + } +} + +// FUNCTION: LEGO1 0x100a84a0 +LegoResult LegoROI::Read( + OrientableROI* p_unk0xd4, + Tgl::Renderer* p_renderer, + ViewLODListManager* p_viewLODListManager, + LegoTextureContainer* p_textureContainer, + LegoStorage* p_storage +) +{ + LegoResult result = FAILURE; + LegoU32 i, j; + LegoU32 numLODs, surplusLODs; + LegoROI* roi; + LegoLOD* lod; + LegoU32 length, roiLength; + LegoChar *roiName, *textureName; + LegoTextureInfo* textureInfo; + ViewLODList* lodList; + LegoU32 numROIs; + LegoSphere sphere; + LegoBox box; + + m_parentROI = p_unk0xd4; + + if (p_storage->Read(&length, sizeof(length)) != SUCCESS) { + goto done; + } + m_name = new LegoChar[length + 1]; + if (p_storage->Read(m_name, length) != SUCCESS) { + goto done; + } + m_name[length] = '\0'; + strlwr(m_name); + + if (sphere.Read(p_storage) != SUCCESS) { + goto done; + } + + SET3(m_sphere.Center(), sphere.GetCenter()); + m_sphere.Radius() = sphere.GetRadius(); + m_world_bounding_sphere.Radius() = m_sphere.Radius(); + + if (box.Read(p_storage) != SUCCESS) { + goto done; + } + + SET3(m_unk0x80.Min(), box.GetMin()); + SET3(m_unk0x80.Max(), box.GetMax()); + + if (p_storage->Read(&length, sizeof(length)) != SUCCESS) { + goto done; + } + + if (length != 0) { + textureName = new LegoChar[length + 1]; + if (p_storage->Read(textureName, length) != SUCCESS) { + goto done; + } + textureName[length] = '\0'; + strlwr(textureName); + } + else { + textureName = NULL; + } + + if (p_storage->Read(&m_unk0x100, sizeof(m_unk0x100)) != SUCCESS) { + goto done; + } + + if (m_unk0x100) { + for (roiLength = strlen(m_name); roiLength; roiLength--) { + if (m_name[roiLength - 1] < '0' || m_name[roiLength - 1] > '9') { + break; + } + } + + roiName = new LegoChar[roiLength + 1]; + memcpy(roiName, m_name, roiLength); + roiName[roiLength] = '\0'; + + lodList = p_viewLODListManager->Lookup(roiName); + delete[] roiName; + + if (lodList == NULL) { + goto done; + } + } + else { + if (p_storage->Read(&numLODs, sizeof(numLODs)) != SUCCESS) { + goto done; + } + + if (!numLODs) { + lodList = NULL; + } + else { + const LegoChar* roiName = m_name; + LegoU32 offset; + + if (p_storage->Read(&offset, sizeof(offset)) != SUCCESS) { + goto done; + } + + if (numLODs > g_roiConfig) { + surplusLODs = numLODs - g_roiConfig; + numLODs = g_roiConfig; + } + else { + surplusLODs = 0; + } + + if (g_roiConfig <= 2) { + for (i = 0; g_unk0x10101380[i] != NULL; i++) { + if (!strnicmp(m_name, g_unk0x10101380[i], 4)) { + roiName = g_unk0x10101380[i]; + break; + } + } + } + else { + for (i = 0; g_unk0x10101370[i] != NULL; i++) { + if (!strnicmp(m_name, g_unk0x10101370[i], 4)) { + roiName = g_unk0x10101370[i]; + break; + } + } + } + + if ((lodList = p_viewLODListManager->Lookup(roiName))) { + for (j = 0; g_unk0x10101390[j] != NULL; j++) { + if (!strcmpi(g_unk0x10101390[j], roiName)) { + break; + } + } + + if (g_unk0x10101390[j] != NULL) { + while (lodList->Size()) { + delete const_cast(lodList->PopBack()); + } + + for (j = 0; j < numLODs; j++) { + lod = new LegoLOD(p_renderer); + if (lod->Read(p_renderer, p_textureContainer, p_storage) != SUCCESS) { + goto done; + } + + if (j == 0) { + if (surplusLODs != 0 && lod->GetUnknown0x08Test8()) { + numLODs++; + } + } + + lodList->PushBack(lod); + } + } + } + else { + for (i = 0; i < numLODs; i++) { + lod = new LegoLOD(p_renderer); + if (lod->Read(p_renderer, p_textureContainer, p_storage) != SUCCESS) { + goto done; + } + + if (i == 0) { + if (surplusLODs != 0 && lod->GetUnknown0x08Test8()) { + numLODs++; + } + } + + if (i == 0 && (lodList = p_viewLODListManager->Create(roiName, numLODs)) == NULL) { + goto done; + } + + lodList->PushBack(lod); + } + } + + p_storage->SetPosition(offset); + } + } + + SetLODList(lodList); + + if (lodList != NULL) { + lodList->Release(); + } + + if (textureName != NULL) { + if (!strnicmp(textureName, "t_", 2)) { + textureInfo = p_textureContainer->Get(textureName + 2); + + if (textureInfo == NULL) { + goto done; + } + + FUN_100a9210(textureInfo); + FUN_100a9170(1.0F, 1.0F, 1.0F, 0.0F); + } + else { + LegoFloat red = 1.0F; + LegoFloat green = 0.0F; + LegoFloat blue = 1.0F; + LegoFloat alpha = 0.0F; + FUN_100a9bf0(textureName, red, green, blue, alpha); + FUN_100a9170(red, green, blue, alpha); + } + } + + if (p_storage->Read(&numROIs, sizeof(numROIs)) != SUCCESS) { + goto done; + } + + if (numROIs > 0) { + comp = new CompoundObject; + } + + for (i = 0; i < numROIs; i++) { + // Create and initialize a sub-component + roi = new LegoROI(p_renderer); + if (roi->Read(this, p_renderer, p_viewLODListManager, p_textureContainer, p_storage) != SUCCESS) { + goto done; + } + // Add the new sub-component to this ROI's protected list + comp->push_back(roi); + } + + result = SUCCESS; + +done: + return result; +} + +// FUNCTION: LEGO1 0x100a8cb0 +LegoResult LegoROI::FUN_100a8cb0(LegoAnimNodeData* p_data, LegoTime p_time, Matrix4& p_matrix) +{ + p_matrix.SetIdentity(); + p_data->CreateLocalTransform(p_time, p_matrix); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100a8ce0 +LegoROI* LegoROI::FindChildROI(const LegoChar* p_name, LegoROI* p_roi) +{ + CompoundObject::iterator it; + const LegoChar* name = p_roi->GetName(); + + if (name != NULL && *name != '\0' && !strcmpi(name, p_name)) { + return p_roi; + } + + CompoundObject* comp = p_roi->comp; + if (comp != NULL) { + for (it = comp->begin(); it != comp->end(); it++) { + LegoROI* roi = (LegoROI*) *it; + name = roi->GetName(); + + if (name != NULL && *name != '\0' && !strcmpi(name, p_name)) { + return roi; + } + } + + for (it = comp->begin(); it != comp->end(); it++) { + LegoROI* roi = FindChildROI(p_name, (LegoROI*) *it); + + if (roi != NULL) { + return roi; + } + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x100a8da0 +LegoResult LegoROI::FUN_100a8da0(LegoTreeNode* p_node, const Matrix4& p_matrix, LegoTime p_time, LegoROI* p_roi) +{ + MxMatrix mat; + LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); + const LegoChar* name = data->GetName(); + LegoROI* roi = FindChildROI(name, p_roi); + + if (roi == NULL) { + roi = FindChildROI(name, this); + } + + if (roi != NULL) { + FUN_100a8cb0(data, p_time, mat); + roi->m_local2world.Product(mat, p_matrix); + roi->VTable0x1c(); + + LegoBool und = data->FUN_100a0990(p_time); + roi->SetVisibility(und); + + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + FUN_100a8da0(p_node->GetChild(i), roi->m_local2world, p_time, roi); + } + } + else { + FUN_100a81b0("%s ROI Not found\n", name); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100a8e80 +void LegoROI::FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap) +{ + MxMatrix mat; + + LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); + FUN_100a8cb0(data, p_time, mat); + + LegoROI* roi = p_roiMap[data->GetUnknown0x20()]; + if (roi != NULL) { + roi->m_local2world.Product(mat, p_matrix); + roi->VTable0x1c(); + + LegoBool und = data->FUN_100a0990(p_time); + roi->SetVisibility(und); + + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + FUN_100a8e80(p_node->GetChild(i), roi->m_local2world, p_time, p_roiMap); + } + } + else { + MxMatrix local2world; + local2world.Product(mat, p_matrix); + + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + FUN_100a8e80(p_node->GetChild(i), local2world, p_time, p_roiMap); + } + } +} + +// FUNCTION: LEGO1 0x100a8fd0 +// FUNCTION: BETA10 0x1018ac81 +void LegoROI::FUN_100a8fd0(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap) +{ + MxMatrix mat; + + LegoAnimNodeData* data = (LegoAnimNodeData*) p_node->GetData(); + FUN_100a8cb0(data, p_time, mat); + + LegoROI* roi = p_roiMap[data->GetUnknown0x20()]; + if (roi != NULL) { + roi->m_local2world.Product(mat, p_matrix); + + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + FUN_100a8fd0(p_node->GetChild(i), roi->m_local2world, p_time, p_roiMap); + } + } + else { + MxMatrix local2world; + local2world.Product(mat, p_matrix); + + for (LegoU32 i = 0; i < p_node->GetNumChildren(); i++) { + FUN_100a8fd0(p_node->GetChild(i), local2world, p_time, p_roiMap); + } + } +} + +// FUNCTION: LEGO1 0x100a90f0 +LegoResult LegoROI::SetFrame(LegoAnim* p_anim, LegoTime p_time) +{ + LegoTreeNode* root = p_anim->GetRoot(); + MxMatrix mat; + + mat = m_local2world; + mat.SetIdentity(); + + return FUN_100a8da0(root, mat, p_time, this); +} + +// FUNCTION: LEGO1 0x100a9170 +LegoResult LegoROI::FUN_100a9170(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha) +{ + LegoResult result = SUCCESS; + CompoundObject::iterator it; + + int lodCount = GetLODCount(); + for (LegoU32 i = 0; i < lodCount; i++) { + LegoLOD* lod = (LegoLOD*) GetLOD(i); + + if (lod->FUN_100aacb0(p_red, p_green, p_blue, p_alpha) != SUCCESS) { + result = FAILURE; + } + } + + if (comp != NULL) { + for (it = comp->begin(); it != comp->end(); it++) { + if (((LegoROI*) *it)->FUN_100a9170(p_red, p_green, p_blue, p_alpha) != SUCCESS) { + result = FAILURE; + } + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100a9210 +LegoResult LegoROI::FUN_100a9210(LegoTextureInfo* p_textureInfo) +{ + LegoResult result = SUCCESS; + CompoundObject::iterator it; + + int lodCount = GetLODCount(); + for (LegoU32 i = 0; i < lodCount; i++) { + LegoLOD* lod = (LegoLOD*) GetLOD(i); + + if (lod->FUN_100aad00(p_textureInfo) != SUCCESS) { + result = FAILURE; + } + } + + if (comp != NULL) { + for (it = comp->begin(); it != comp->end(); it++) { + if (((LegoROI*) *it)->FUN_100a9210(p_textureInfo) != SUCCESS) { + result = FAILURE; + } + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100a92a0 +// FUNCTION: BETA10 0x1018b12d +LegoResult LegoROI::GetTexture(LegoTextureInfo*& p_textureInfo) +{ + CompoundObject::iterator it; + + int lodCount = GetLODCount(); + for (LegoU32 i = 0; i < lodCount; i++) { + LegoLOD* lod = (LegoLOD*) GetLOD(i); + + if (lod->GetTexture(p_textureInfo) == SUCCESS) { + return SUCCESS; + } + } + + if (comp != NULL) { + for (it = comp->begin(); it != comp->end(); it++) { + if (((LegoROI*) *it)->GetTexture(p_textureInfo) == SUCCESS) { + return SUCCESS; + } + } + } + + return FAILURE; +} + +// STUB: LEGO1 0x100a9410 +LegoU32 LegoROI::FUN_100a9410(Vector3&, Vector3&, float, float, Vector3&, LegoBool) +{ + return 0; +} + +// FUNCTION: LEGO1 0x100a9a50 +TimeROI::TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_time) : LegoROI(p_renderer, p_lodList) +{ + m_time = p_time; +} + +// FUNCTION: LEGO1 0x100a9b40 +void TimeROI::FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time) +{ + LegoTime time = p_time - m_time; + + if (time) { + m_time = p_time; + + Mx3DPointFloat targetPosition(p_matrix[3]); + + // TODO: Figure out how to get type right for the call + // TODO: Fix constness of vector/matrix functions +#ifdef COMPAT_MODE + Vector3 worldPosition(m_local2world[3]); + ((Vector3&) targetPosition).Sub(&worldPosition); +#else + ((Vector3&) targetPosition).Sub(&Vector3(m_local2world[3])); +#endif + + float division = time * 0.001; + ((Vector3&) targetPosition).Div(division); + + FUN_100a5a30(targetPosition); + } +} + +// FUNCTION: LEGO1 0x100a9bf0 +LegoBool LegoROI::FUN_100a9bf0(const LegoChar* p_param, float& p_red, float& p_green, float& p_blue, float& p_alpha) +{ + if (p_param == NULL) { + return FALSE; + } + + if (g_unk0x101013ac) { + char buf[32]; + if (g_unk0x101013ac(p_param, buf, 32)) { + p_param = buf; + } + } + + return ColorAliasLookup(p_param, p_red, p_green, p_blue, p_alpha); +} + +// FUNCTION: LEGO1 0x100a9c50 +LegoBool LegoROI::ColorAliasLookup(const LegoChar* p_param, float& p_red, float& p_green, float& p_blue, float& p_alpha) +{ + for (MxU32 i = 0; i < sizeOfArray(g_roiColorAliases); i++) { + if (strcmpi(g_roiColorAliases[i].m_name, p_param) == 0) { + p_red = g_roiColorAliases[i].m_red / 255.0; + p_green = g_roiColorAliases[i].m_green / 255.0; + p_blue = g_roiColorAliases[i].m_blue / 255.0; + p_alpha = g_roiColorAliases[i].m_alpha / 255.0; + return TRUE; + } + } + + return FALSE; +} + +// STUB: LEGO1 0x100a9cf0 +LegoBool LegoROI::FUN_100a9cf0(const LegoChar* p_param, unsigned char* paletteEntries, LegoU32 p_numEntries) +{ + // TODO + return FALSE; +} + +// FUNCTION: LEGO1 0x100a9d30 +void LegoROI::FUN_100a9d30(ROIHandler p_func) +{ + g_unk0x101013ac = p_func; +} + +// FUNCTION: LEGO1 0x100a9d40 +void LegoROI::SetName(const LegoChar* p_name) +{ + if (m_name != NULL) { + delete[] m_name; + } + + if (p_name != NULL) { + m_name = new LegoChar[strlen(p_name) + 1]; + strcpy(m_name, p_name); + strlwr(m_name); + } + else { + m_name = NULL; + } +} + +// FUNCTION: LEGO1 0x100a9e10 +void LegoROI::SetDisplayBB(int p_displayBB) +{ + // Intentionally empty function +} + +// FUNCTION: LEGO1 0x100aa340 +float LegoROI::IntrinsicImportance() const +{ + return .5; +} + +// FUNCTION: LEGO1 0x100aa350 +void LegoROI::UpdateWorldBoundingVolumes() +{ + CalcWorldBoundingVolumes(m_sphere, m_local2world, m_world_bounding_box, m_world_bounding_sphere); +} diff --git a/LEGO1/lego/sources/roi/legoroi.h b/LEGO1/lego/sources/roi/legoroi.h new file mode 100644 index 00000000..64002d30 --- /dev/null +++ b/LEGO1/lego/sources/roi/legoroi.h @@ -0,0 +1,96 @@ +#ifndef LEGOROI_H +#define LEGOROI_H + +#include "misc/legotypes.h" +#include "viewmanager/viewroi.h" + +typedef unsigned char (*ROIHandler)(const char*, char*, unsigned int); + +class LegoEntity; +class LegoTextureContainer; +class LegoTextureInfo; +class LegoStorage; +class LegoAnim; +class LegoAnimNodeData; +class LegoTreeNode; +struct LegoAnimActorEntry; + +// VTABLE: LEGO1 0x100dbe38 +// SIZE 0x108 +class LegoROI : public ViewROI { +public: + LegoROI(Tgl::Renderer* p_renderer); + LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList); + ~LegoROI() override; + + LegoResult Read( + OrientableROI* p_unk0xd4, + Tgl::Renderer* p_renderer, + ViewLODListManager* p_viewLODListManager, + LegoTextureContainer* p_textureContainer, + LegoStorage* p_storage + ); + LegoROI* FindChildROI(const LegoChar* p_name, LegoROI* p_roi); + LegoResult FUN_100a8da0(LegoTreeNode* p_node, const Matrix4& p_matrix, LegoTime p_time, LegoROI* p_roi); + static void FUN_100a8e80(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap); + static void FUN_100a8fd0(LegoTreeNode* p_node, Matrix4& p_matrix, LegoTime p_time, LegoROI** p_roiMap); + LegoResult SetFrame(LegoAnim* p_anim, LegoTime p_time); + LegoResult FUN_100a9170(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha); + LegoResult FUN_100a9210(LegoTextureInfo* p_textureInfo); + LegoResult GetTexture(LegoTextureInfo*& p_textureInfo); + LegoU32 FUN_100a9410(Vector3&, Vector3&, float, float, Vector3&, LegoBool); + void SetName(const LegoChar* p_name); + + float IntrinsicImportance() const override; // vtable+0x04 + void UpdateWorldBoundingVolumes() override; // vtable+0x18 + + void SetDisplayBB(int p_displayBB); + + static LegoResult FUN_100a8cb0(LegoAnimNodeData* p_data, LegoTime p_time, Matrix4& p_matrix); + static void FUN_100a81b0(const LegoChar* p_error, const LegoChar* p_name); + static void configureLegoROI(int p_roi); + static void FUN_100a9d30(ROIHandler p_func); + static LegoBool FUN_100a9bf0(const LegoChar* p_param, float& p_red, float& p_green, float& p_blue, float& p_alpha); + static LegoBool ColorAliasLookup( + const LegoChar* p_param, + float& p_red, + float& p_green, + float& p_blue, + float& p_alpha + ); + static LegoBool FUN_100a9cf0(const LegoChar* p_param, unsigned char* paletteEntries, LegoU32 p_numEntries); + + inline const LegoChar* GetName() const { return m_name; } + inline LegoEntity* GetEntity() { return m_entity; } + + inline void SetEntity(LegoEntity* p_entity) { m_entity = p_entity; } + inline void SetComp(CompoundObject* p_comp) { comp = p_comp; } + inline void SetBoundingSphere(const BoundingSphere& p_sphere) { m_sphere = m_world_bounding_sphere = p_sphere; } + inline void SetUnknown0x80(const BoundingBox& p_unk0x80) { m_unk0x80 = p_unk0x80; } + + // SYNTHETIC: LEGO1 0x100a82b0 + // LegoROI::`scalar deleting destructor' + +private: + LegoChar* m_name; // 0xe4 + BoundingSphere m_sphere; // 0xe8 + undefined m_unk0x100; // 0x100 + LegoEntity* m_entity; // 0x104 +}; + +// VTABLE: LEGO1 0x100dbea8 +// SIZE 0x10c +class TimeROI : public LegoROI { +public: + TimeROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList, LegoTime p_time); + + // SYNTHETIC: LEGO1 0x100a9ad0 + // TimeROI::`scalar deleting destructor' + + void FUN_100a9b40(Matrix4& p_matrix, LegoTime p_time); + +private: + LegoTime m_time; // 0x108 +}; + +#endif // LEGOROI_H diff --git a/LEGO1/library_msvc.h b/LEGO1/library_msvc.h new file mode 100644 index 00000000..7a4153b6 --- /dev/null +++ b/LEGO1/library_msvc.h @@ -0,0 +1,147 @@ +#ifdef 0 +// For LEGO1 symbols only + +// aka `operator new` +// LIBRARY: LEGO1 0x10086240 +// ??2@YAPAXI@Z + +// aka `operator delete` +// LIBRARY: LEGO1 0x10086260 +// ??3@YAXPAX@Z + +// LIBRARY: LEGO1 0x1008a090 +// _malloc + +// LIBRARY: LEGO1 0x1008a1c0 +// _free + +// LIBRARY: LEGO1 0x1008b020 +// ___CxxFrameHandler + +// LIBRARY: LEGO1 0x1008b24c +// __global_unwind2 + +// LIBRARY: LEGO1 0x1008b28e +// __local_unwind2 + +// LIBRARY: LEGO1 0x1008b322 +// __NLG_Notify + +// LIBRARY: LEGO1 0x1008b3dc +// __CIacos + +// LIBRARY: LEGO1 0x1008b400 +// _atol + +// LIBRARY: LEGO1 0x1008b4b0 +// _atoi + +// LIBRARY: LEGO1 0x1008b4c0 +// _strtok + +// LIBRARY: LEGO1 0x1008b5a0 +// _sprintf + +// LIBRARY: LEGO1 0x1008b608 +// __ftol + +// LIBRARY: LEGO1 0x1008b630 +// _srand + +// LIBRARY: LEGO1 0x1008b640 +// _rand + +// LIBRARY: LEGO1 0x1008b680 +// _strncmp + +// LIBRARY: LEGO1 0x1008b6c0 +// _atof + +// LIBRARY: LEGO1 0x1008b730 +// _fprintf + +// LIBRARY: LEGO1 0x1008b670 +// __purecall + +// LIBRARY: LEGO1 0x1008b780 +// _fwrite + +// LIBRARY: LEGO1 0x1008b950 +// _fread + +// LIBRARY: LEGO1 0x1008bbd0 +// _fclose + +// LIBRARY: LEGO1 0x1008bdd0 +// _ftell + +// LIBRARY: LEGO1 0x1008bff0 +// _fopen + +// LIBRARY: LEGO1 0x1008c010 +// _strncpy + +// LIBRARY: LEGO1 0x1008c110 +// __strcmpi + +// LIBRARY: LEGO1 0x1008c1e0 +// __spawnl + +// LIBRARY: LEGO1 0x1008c200 +// _sscanf + +// LIBRARY: LEGO1 0x1008c250 +// ??_L@YGXPAXIHP6EX0@Z1@Z + +// LIBRARY: LEGO1 0x1008c2e0 +// ??_M@YGXPAXIHP6EX0@Z@Z + +// LIBRARY: LEGO1 0x1008c370 +// ?__ArrayUnwind@@YGXPAXIHP6EX0@Z@Z + +// LIBRARY: LEGO1 0x1008c410 +// _strlwr + +// LIBRARY: LEGO1 0x1008c570 +// _access + +// LIBRARY: LEGO1 0x1008c5c0 +// _fseek + +// LIBRARY: LEGO1 0x1008c6a0 +// _isdigit + +// LIBRARY: LEGO1 0x1008c980 +// __except_handler3 + +// LIBRARY: LEGO1 0x1008ca60 +// _abort + +// LIBRARY: LEGO1 0x100977c0 +// _itoa + +// LIBRARY: LEGO1 0x10097b10 +// _strchr + +// LIBRARY: LEGO1 0x100d1ed0 +// _strnicmp + +// LIBRARY: LEGO1 0x100d1fd0 +// _strupr + +// LIBRARY: LEGO1 0x100d2130 +// _vsprintf + +// LIBRARY: LEGO1 0x100d21c2 +// __CIpow + +// LIBRARY: LEGO1 0x100d21f0 +// _strstr + +// LIBRARY: LEGO1 0x100d2270 +// __beginthreadex + +// LIBRARY: LEGO1 0x100fc8bc +// __NLG_Destination + +#endif diff --git a/LEGO1/library_smack.h b/LEGO1/library_smack.h new file mode 100644 index 00000000..2909ebd3 --- /dev/null +++ b/LEGO1/library_smack.h @@ -0,0 +1,18 @@ +#ifdef 0 + +// LIBRARY: LEGO1 0x100cd782 +// _SmackGetSizeTables + +// LIBRARY: LEGO1 0x100cd7e8 +// _SmackDoTables + +// LIBRARY: LEGO1 0x100cda83 +// _SmackDoFrameToBuffer + +// LIBRARY: LEGO1 0x100d052c +// _SmackGetSizeDeltas + +// LIBRARY: LEGO1 0x100d0543 +// _SmackGetRect + +#endif diff --git a/LEGO1/main.cpp b/LEGO1/main.cpp new file mode 100644 index 00000000..260afb24 --- /dev/null +++ b/LEGO1/main.cpp @@ -0,0 +1,7 @@ +#include + +// FUNCTION: LEGO1 0x10091ee0 +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + return TRUE; +} diff --git a/LEGO1/modeldb/modeldb.cpp b/LEGO1/modeldb/modeldb.cpp new file mode 100644 index 00000000..b0489b8c --- /dev/null +++ b/LEGO1/modeldb/modeldb.cpp @@ -0,0 +1,137 @@ +#include "modeldb.h" + +DECOMP_SIZE_ASSERT(ModelDbWorld, 0x18) +DECOMP_SIZE_ASSERT(ModelDbPart, 0x18) +DECOMP_SIZE_ASSERT(ModelDbModel, 0x38) +DECOMP_SIZE_ASSERT(ModelDbPartList, 0x1c) +DECOMP_SIZE_ASSERT(ModelDbPartListCursor, 0x10) + +// FUNCTION: LEGO1 0x100276b0 +MxResult ModelDbModel::Read(FILE* p_file) +{ + MxU32 len; + + if (fread(&len, sizeof(len), 1, p_file) != 1) { + return FAILURE; + } + + m_modelName = new char[len]; + if (fread(m_modelName, len, 1, p_file) != 1) { + return FAILURE; + } + + if (fread(&m_unk0x04, sizeof(m_unk0x04), 1, p_file) != 1) { + return FAILURE; + } + if (fread(&m_unk0x08, sizeof(m_unk0x08), 1, p_file) != 1) { + return FAILURE; + } + if (fread(&len, sizeof(len), 1, p_file) != 1) { + return FAILURE; + } + + m_presenterName = new char[len]; + if (fread(m_presenterName, len, 1, p_file) != 1) { + return FAILURE; + } + + if (fread(&m_location, sizeof(*m_location), 3, p_file) != 3) { + return FAILURE; + } + if (fread(&m_direction, sizeof(*m_direction), 3, p_file) != 3) { + return FAILURE; + } + if (fread(&m_up, sizeof(*m_up), 3, p_file) != 3) { + return FAILURE; + } + + return fread(&m_unk0x34, sizeof(m_unk0x34), 1, p_file) == 1 ? SUCCESS : FAILURE; +} + +// FUNCTION: LEGO1 0x10027850 +MxResult ModelDbPart::Read(FILE* p_file) +{ + MxU32 len; + char buff[128]; + + if (fread(&len, sizeof(len), 1, p_file) != 1) { + return FAILURE; + } + + // (modernization) critical bug: buffer overrun + if (fread(buff, len, 1, p_file) != 1) { + return FAILURE; + } + + m_roiName = buff; + + if (fread(&m_partDataLength, sizeof(m_partDataLength), 1, p_file) != 1) { + return FAILURE; + } + + return fread(&m_partDataOffset, sizeof(m_partDataOffset), 1, p_file) == 1 ? SUCCESS : FAILURE; +} + +// FUNCTION: LEGO1 0x10027910 +MxResult ReadModelDbWorlds(FILE* p_file, ModelDbWorld*& p_worlds, MxS32& p_numWorlds) +{ + p_worlds = NULL; + p_numWorlds = 0; + + MxS32 numWorlds; + if (fread(&numWorlds, sizeof(numWorlds), 1, p_file) != 1) { + return FAILURE; + } + + ModelDbWorld* worlds = new ModelDbWorld[numWorlds]; + MxS32 worldNameLen, numParts, i, j; + + for (i = 0; i < numWorlds; i++) { + if (fread(&worldNameLen, sizeof(worldNameLen), 1, p_file) != 1) { + return FAILURE; + } + + worlds[i].m_worldName = new char[worldNameLen]; + if (fread(worlds[i].m_worldName, worldNameLen, 1, p_file) != 1) { + return FAILURE; + } + + if (fread(&numParts, sizeof(numParts), 1, p_file) != 1) { + return FAILURE; + } + + worlds[i].m_partList = new ModelDbPartList(); + + for (j = 0; j < numParts; j++) { + ModelDbPart* part = new ModelDbPart(); + + if (part->Read(p_file) != SUCCESS) { + return FAILURE; + } + + worlds[i].m_partList->Append(part); + } + + if (fread(&worlds[i].m_numModels, sizeof(worlds[i].m_numModels), 1, p_file) != 1) { + return FAILURE; + } + + worlds[i].m_models = new ModelDbModel[worlds[i].m_numModels]; + + for (j = 0; j < worlds[i].m_numModels; j++) { + if (worlds[i].m_models[j].Read(p_file) != SUCCESS) { + return FAILURE; + } + } + } + + p_worlds = worlds; + p_numWorlds = numWorlds; + return SUCCESS; +} + +// STUB: LEGO1 0x10028080 +void FreeModelDbWorlds(ModelDbWorld*& p_worlds, MxS32 p_numWorlds) +{ + // TODO +} diff --git a/LEGO1/modeldb/modeldb.h b/LEGO1/modeldb/modeldb.h new file mode 100644 index 00000000..943927ef --- /dev/null +++ b/LEGO1/modeldb/modeldb.h @@ -0,0 +1,118 @@ +#ifndef MODELDB_H +#define MODELDB_H + +#include "decomp.h" +#include "mxlist.h" +#include "mxstring.h" +#include "mxtypes.h" + +#include + +// SIZE 0x18 +struct ModelDbPart { + MxResult Read(FILE* p_file); + + MxString m_roiName; // 0x00 + undefined4 m_partDataLength; // 0x10 + undefined4 m_partDataOffset; // 0x14 +}; + +// VTABLE: LEGO1 0x100d6888 +// class MxCollection + +// VTABLE: LEGO1 0x100d68a0 +// class MxList + +// VTABLE: LEGO1 0x100d68b8 +// SIZE 0x1c +class ModelDbPartList : public MxList { +public: + ModelDbPartList() { m_unk0x18 = 1; } + + // FUNCTION: LEGO1 0x10027c40 + MxS8 Compare(ModelDbPart* p_a, ModelDbPart* p_b) override + { + MxS32 compare = strcmpi(p_a->m_roiName.GetData(), p_b->m_roiName.GetData()); + + if (compare == 0) { + p_b->m_partDataLength = p_a->m_partDataLength; + p_b->m_partDataOffset = p_a->m_partDataOffset; + } + + return compare; + } // vtable+0x14 + + // SYNTHETIC: LEGO1 0x10027d70 + // ModelDbPartList::`scalar deleting destructor' + +private: + undefined m_unk0x18; +}; + +// VTABLE: LEGO1 0x100d68d0 +// class MxListCursor + +// VTABLE: LEGO1 0x100d68e8 +// SIZE 0x10 +class ModelDbPartListCursor : public MxListCursor { +public: + ModelDbPartListCursor(ModelDbPartList* p_list) : MxListCursor(p_list) {} +}; + +// TEMPLATE: LEGO1 0x10027c70 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x10027c80 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x10027cd0 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x10027ce0 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x10027de0 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10027e50 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10027f00 +// ModelDbPartListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x10027f70 +// MxListCursor::~MxListCursor + +// SYNTHETIC: LEGO1 0x10027fc0 +// MxListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x10028030 +// ModelDbPartListCursor::~ModelDbPartListCursor + +// SIZE 0x38 +struct ModelDbModel { + MxResult Read(FILE* p_file); + + char* m_modelName; // 0x00 + undefined4 m_unk0x04; // 0x04 + undefined4 m_unk0x08; // 0x08 + char* m_presenterName; // 0x0c + float m_location[3]; // 0x10 + float m_direction[3]; // 0x1c + float m_up[3]; // 0x28 + undefined m_unk0x34; // 0x34 +}; + +// SIZE 0x18 +struct ModelDbWorld { + char* m_worldName; // 0x00 + ModelDbPartList* m_partList; // 0x04 + ModelDbModel* m_models; // 0x08 + MxS32 m_numModels; // 0x0c + undefined m_unk0x10[0x08]; // 0x10 +}; + +MxResult ReadModelDbWorlds(FILE* p_file, ModelDbWorld*& p_worlds, MxS32& p_numWorlds); +void FreeModelDbWorlds(ModelDbWorld*& p_worlds, MxS32 p_numWorlds); + +#endif // MODELDB_H diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp new file mode 100644 index 00000000..ccfd6405 --- /dev/null +++ b/LEGO1/mxdirectx/mxdirect3d.cpp @@ -0,0 +1,1158 @@ +#include "mxdirect3d.h" + +#include // for vsprintf + +#if !defined(MXDIRECTX_FOR_CONFIG) +DECOMP_SIZE_ASSERT(MxAssignedDevice, 0xe4); +DECOMP_SIZE_ASSERT(MxDirect3D, 0x894); +#endif +DECOMP_SIZE_ASSERT(Direct3DDeviceInfo, 0x1a4); +DECOMP_SIZE_ASSERT(MxDisplayMode, 0x0c); +DECOMP_SIZE_ASSERT(MxDriver, 0x190); +DECOMP_SIZE_ASSERT(MxDeviceEnumerate, 0x14); + +#if !defined(MXDIRECTX_FOR_CONFIG) +#define RELEASE(x) \ + if (x != NULL) { \ + x->Release(); \ + x = NULL; \ + } + +// FUNCTION: LEGO1 0x1009b0a0 +MxDirect3D::MxDirect3D() +{ + this->m_pDirect3d = NULL; + this->m_pDirect3dDevice = NULL; + this->m_bTexturesDisabled = FALSE; + this->m_assignedDevice = NULL; +} + +// FUNCTION: LEGO1 0x1009b140 +MxDirect3D::~MxDirect3D() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x1009b1a0 +BOOL MxDirect3D::Create( + HWND hWnd, + BOOL fullscreen_1, + BOOL surface_fullscreen, + BOOL onlySystemMemory, + int width, + int height, + int bpp, + const PALETTEENTRY* pPaletteEntries, + int paletteEntryCount +) +{ + BOOL success = FALSE; + BOOL ret = MxDirectDraw::Create( + hWnd, + fullscreen_1, + surface_fullscreen, + onlySystemMemory, + width, + height, + bpp, + pPaletteEntries, + paletteEntryCount + ); + + if (ret && D3DCreate() && D3DSetMode()) { + success = TRUE; + } + + if (!success) { + FUN_1009d920(); + } + + return success; +} + +// FUNCTION: LEGO1 0x1009b210 +void MxDirect3D::Destroy() +{ + RELEASE(m_pDirect3dDevice); + RELEASE(m_pDirect3d); + + if (this->m_assignedDevice) { + delete m_assignedDevice; + this->m_assignedDevice = NULL; + } + + if (m_pCurrentDeviceModesList) { + m_pCurrentDeviceModesList = NULL; + } + + MxDirectDraw::Destroy(); +} + +// FUNCTION: LEGO1 0x1009b290 +void MxDirect3D::DestroyButNotDirectDraw() +{ + RELEASE(m_pDirect3dDevice); + RELEASE(m_pDirect3d); + MxDirectDraw::DestroyButNotDirectDraw(); +} + +// FUNCTION: LEGO1 0x1009b2d0 +BOOL MxDirect3D::D3DCreate() +{ + HRESULT result; + + result = DirectDraw()->QueryInterface(IID_IDirect3D2, (LPVOID*) &m_pDirect3d); + if (result != DD_OK) { + Error("Creation of IDirect3D failed", result); + return FALSE; + } + return TRUE; +} + +// FUNCTION: LEGO1 0x1009b310 +BOOL MxDirect3D::D3DSetMode() +{ + if (m_assignedDevice->m_flags & MxAssignedDevice::c_hardwareMode) { + if (m_bOnlySoftRender) { + Error("Failed to place vital surfaces in video memory for hardware driver", DDERR_GENERIC); + return FALSE; + } + + if (m_assignedDevice->m_desc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) { + m_bTexturesDisabled = FALSE; + } + else { + m_bTexturesDisabled = TRUE; + } + + if (!CreateZBuffer(DDSCAPS_VIDEOMEMORY, ZBufferDepth(m_assignedDevice))) { + return FALSE; + } + } + else { + if (m_assignedDevice->m_desc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE) { + m_bTexturesDisabled = FALSE; + } + else { + m_bTexturesDisabled = TRUE; + } + + if (!CreateZBuffer(DDSCAPS_SYSTEMMEMORY, ZBufferDepth(m_assignedDevice))) { + return FALSE; + } + } + + HRESULT result = m_pDirect3d->CreateDevice(m_assignedDevice->m_guid, m_pBackBuffer, &m_pDirect3dDevice); + + if (result != DD_OK) { + Error("Create D3D device failed", result); + return FALSE; + } + + MxDirectDraw::Mode mode = m_currentMode; + + if (IsFullScreen()) { + if (!IsSupportedMode(mode.width, mode.height, mode.bitsPerPixel)) { + Error("This device cannot support the current display mode", DDERR_GENERIC); + return FALSE; + } + } + + LPDIRECTDRAWSURFACE frontBuffer = m_pFrontBuffer; + LPDIRECTDRAWSURFACE backBuffer = m_pBackBuffer; + + DDSURFACEDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (backBuffer->Lock(NULL, &desc, DDLOCK_WAIT, NULL) == DD_OK) { + unsigned char* surface = (unsigned char*) desc.lpSurface; + + for (int i = mode.height; i > 0; i--) { + memset(surface, 0, mode.width * desc.ddpfPixelFormat.dwRGBBitCount / 8); + surface += desc.lPitch; + } + + backBuffer->Unlock(desc.lpSurface); + } + else { + OutputDebugString("MxDirect3D::D3DSetMode() back lock failed\n"); + } + + if (m_bFullScreen) { + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (frontBuffer->Lock(NULL, &desc, DDLOCK_WAIT, NULL) == DD_OK) { + unsigned char* surface = (unsigned char*) desc.lpSurface; + + for (int i = mode.height; i > 0; i--) { + memset(surface, 0, mode.width * desc.ddpfPixelFormat.dwRGBBitCount / 8); + surface += desc.lPitch; + } + + frontBuffer->Unlock(desc.lpSurface); + } + else { + OutputDebugString("MxDirect3D::D3DSetMode() front lock failed\n"); + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009b5a0 +int MxDirect3D::ZBufferDepth(MxAssignedDevice* p_assignedDevice) +{ + int depth; + DWORD deviceDepth; + + if (p_assignedDevice->m_desc.dwFlags & D3DDD_DEVICEZBUFFERBITDEPTH) { + deviceDepth = p_assignedDevice->m_desc.dwDeviceZBufferBitDepth; + } + else { + deviceDepth = 0; + } + + if (deviceDepth & DDBD_32) { + depth = 32; + } + else if (deviceDepth & DDBD_24) { + depth = 24; + } + else if (deviceDepth & DDBD_16) { + depth = 16; + } + else if (deviceDepth & DDBD_8) { + depth = 8; + } + else { + depth = -1; + } + + return depth; +} + +// FUNCTION: LEGO1 0x1009b5f0 +BOOL MxDirect3D::SetDevice(MxDeviceEnumerate& p_deviceEnumerate, MxDriver* p_driver, Direct3DDeviceInfo* p_device) +{ + if (m_assignedDevice) { + delete m_assignedDevice; + m_assignedDevice = NULL; + m_pCurrentDeviceModesList = NULL; + } + + MxAssignedDevice* assignedDevice = new MxAssignedDevice; + int i = 0; + + for (list::iterator it = p_deviceEnumerate.m_list.begin(); it != p_deviceEnumerate.m_list.end(); it++) { + MxDriver& driver = *it; + + if (&driver == p_driver) { + assignedDevice->m_deviceInfo = new MxDirectDraw::DeviceModesInfo; + + if (driver.m_guid) { + assignedDevice->m_deviceInfo->m_guid = new GUID; + memcpy(assignedDevice->m_deviceInfo->m_guid, driver.m_guid, sizeof(GUID)); + } + + assignedDevice->m_deviceInfo->m_count = driver.m_displayModes.size(); + + if (assignedDevice->m_deviceInfo->m_count > 0) { + assignedDevice->m_deviceInfo->m_modeArray = + new MxDirectDraw::Mode[assignedDevice->m_deviceInfo->m_count]; + + int j = 0; + for (list::iterator it2 = driver.m_displayModes.begin(); + it2 != driver.m_displayModes.end(); + it2++) { + assignedDevice->m_deviceInfo->m_modeArray[j].width = (*it2).m_width; + assignedDevice->m_deviceInfo->m_modeArray[j].height = (*it2).m_height; + assignedDevice->m_deviceInfo->m_modeArray[j].bitsPerPixel = (*it2).m_bitsPerPixel; + j++; + } + } + + memcpy( + &assignedDevice->m_deviceInfo->m_ddcaps, + &driver.m_ddCaps, + sizeof(assignedDevice->m_deviceInfo->m_ddcaps) + ); + + if (i == 0) { + assignedDevice->m_flags |= MxAssignedDevice::c_primaryDevice; + } + + for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); + it2++) { + Direct3DDeviceInfo& device = *it2; + if (&device != p_device) { + continue; + } + + memcpy(&assignedDevice->m_guid, device.m_guid, sizeof(assignedDevice->m_guid)); + + D3DDEVICEDESC* desc; + if (device.m_HWDesc.dcmColorModel) { + assignedDevice->m_flags |= MxAssignedDevice::c_hardwareMode; + desc = &device.m_HWDesc; + } + else { + desc = &device.m_HELDesc; + } + + memcpy(&assignedDevice->m_desc, desc, sizeof(assignedDevice->m_desc)); + m_assignedDevice = assignedDevice; + m_pCurrentDeviceModesList = assignedDevice->m_deviceInfo; + break; + } + } + + i++; + } + + if (!m_assignedDevice) { + delete assignedDevice; + return FALSE; + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009b8b0 +MxAssignedDevice::MxAssignedDevice() +{ + memset(this, 0, sizeof(*this)); +} + +// FUNCTION: LEGO1 0x1009b8d0 +MxAssignedDevice::~MxAssignedDevice() +{ + if (m_deviceInfo) { + delete m_deviceInfo; + m_deviceInfo = NULL; + } +} +#endif + +// FUNCTION: CONFIG 0x00401180 +// FUNCTION: LEGO1 0x1009ba80 +MxDriver::MxDriver(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName) +{ + m_guid = NULL; + m_driverDesc = NULL; + m_driverName = NULL; + memset(&m_ddCaps, 0, sizeof(m_ddCaps)); + + Init(p_guid, p_driverDesc, p_driverName); +} + +// FUNCTION: CONFIG 0x401280 +// FUNCTION: LEGO1 0x1009bb80 +MxDriver::~MxDriver() +{ + if (m_guid) { + delete m_guid; + } + if (m_driverDesc) { + delete[] m_driverDesc; + } + if (m_driverName) { + delete[] m_driverName; + } +} + +// FUNCTION: CONFIG 0x00401330 +// FUNCTION: LEGO1 0x1009bc30 +void MxDriver::Init(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName) +{ + if (m_driverDesc) { + delete[] m_driverDesc; + m_driverDesc = NULL; + } + + if (m_driverName) { + delete[] m_driverName; + m_driverName = NULL; + } + + if (p_guid) { + m_guid = new GUID; + memcpy(m_guid, p_guid, sizeof(*m_guid)); + } + + if (p_driverDesc) { + m_driverDesc = new char[strlen(p_driverDesc) + 1]; + strcpy(m_driverDesc, p_driverDesc); + } + + if (p_driverName) { + m_driverName = new char[strlen(p_driverName) + 1]; + strcpy(m_driverName, p_driverName); + } +} + +// FUNCTION: LEGO1 0x1009bd20 +Direct3DDeviceInfo::Direct3DDeviceInfo( + LPGUID p_guid, + LPSTR p_deviceDesc, + LPSTR p_deviceName, + LPD3DDEVICEDESC p_HWDesc, + LPD3DDEVICEDESC p_HELDesc +) +{ + memset(this, 0, sizeof(*this)); + + Initialize(p_guid, p_deviceDesc, p_deviceName, p_HWDesc, p_HELDesc); +} + +// FUNCTION: CONFIG 0x401460 +// FUNCTION: LEGO1 0x1009bd60 +Direct3DDeviceInfo::~Direct3DDeviceInfo() +{ + if (m_guid) { + delete m_guid; + } + if (m_deviceDesc) { + delete[] m_deviceDesc; + } + if (m_deviceName) { + delete[] m_deviceName; + } +} + +// FUNCTION: LEGO1 0x1009bda0 +void Direct3DDeviceInfo::Initialize( + LPGUID p_guid, + LPSTR p_deviceDesc, + LPSTR p_deviceName, + LPD3DDEVICEDESC p_HWDesc, + LPD3DDEVICEDESC p_HELDesc +) +{ + if (m_deviceDesc) { + delete[] m_deviceDesc; + m_deviceDesc = NULL; + } + + if (m_deviceName) { + delete[] m_deviceName; + m_deviceName = NULL; + } + + if (p_guid) { + m_guid = new GUID; + memcpy(m_guid, p_guid, sizeof(*m_guid)); + } + + if (p_deviceDesc) { + m_deviceDesc = new char[strlen(p_deviceDesc) + 1]; + strcpy(m_deviceDesc, p_deviceDesc); + } + + if (p_deviceName) { + m_deviceName = new char[strlen(p_deviceName) + 1]; + strcpy(m_deviceName, p_deviceName); + } + + if (p_HWDesc) { + memcpy(&m_HWDesc, p_HWDesc, sizeof(m_HWDesc)); + } + + if (p_HELDesc) { + memcpy(&m_HELDesc, p_HELDesc, sizeof(m_HELDesc)); + } +} + +// FUNCTION: CONFIG 0x004015c0 +// FUNCTION: LEGO1 0x1009bec0 +MxDeviceEnumerate::MxDeviceEnumerate() +{ + m_initialized = FALSE; +} + +// FUNCTION: CONFIG 0x401710 +// FUNCTION: LEGO1 0x1009c010 +MxDeviceEnumerate::~MxDeviceEnumerate() +{ +} + +// FUNCTION: CONFIG 0x00401770 +// FUNCTION: LEGO1 0x1009c070 +BOOL MxDeviceEnumerate::EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName) +{ + MxDriver driver(p_guid, p_driverDesc, p_driverName); + m_list.push_back(driver); + + // Must be zeroed because held resources are copied by pointer only + // and should not be freed at the end of this function + driver.m_guid = NULL; + driver.m_driverDesc = NULL; + driver.m_driverName = NULL; + memset(&driver.m_ddCaps, 0, sizeof(driver.m_ddCaps)); + + LPDIRECT3D2 lpDirect3d2 = NULL; + LPDIRECTDRAW lpDD = NULL; + MxDriver& newDevice = m_list.back(); + HRESULT result = DirectDrawCreate(newDevice.m_guid, &lpDD, NULL); + + if (result != DD_OK) { + BuildErrorString("DirectDraw Create failed: %s\n", EnumerateErrorToString(result)); + } + else { + lpDD->EnumDisplayModes(0, NULL, this, DisplayModesEnumerateCallback); + newDevice.m_ddCaps.dwSize = sizeof(newDevice.m_ddCaps); + result = lpDD->GetCaps(&newDevice.m_ddCaps, NULL); + + if (result != DD_OK) { + BuildErrorString("GetCaps failed: %s\n", EnumerateErrorToString(result)); + } + else { + result = lpDD->QueryInterface(IID_IDirect3D2, (LPVOID*) &lpDirect3d2); + + if (result != DD_OK) { + BuildErrorString("D3D creation failed: %s\n", EnumerateErrorToString(result)); + } + else { + result = lpDirect3d2->EnumDevices(DevicesEnumerateCallback, this); + + if (result != DD_OK) { + BuildErrorString("D3D enum devices failed: %s\n", EnumerateErrorToString(result)); + } + else { + if (newDevice.m_devices.empty()) { + m_list.pop_back(); + } + } + } + } + } + + if (lpDirect3d2) { + lpDirect3d2->Release(); + } + + if (lpDD) { + lpDD->Release(); + } + + return DDENUMRET_OK; +} + +// FUNCTION: CONFIG 0x00401bc0 +// FUNCTION: LEGO1 0x1009c4c0 +void MxDeviceEnumerate::BuildErrorString(const char* p_format, ...) +{ + va_list args; + char buf[512]; + + va_start(args, p_format); + vsprintf(buf, p_format, args); + va_end(args); + + OutputDebugString(buf); +} + +// FUNCTION: CONFIG 0x00401bf0 +// FUNCTION: LEGO1 0x1009c4f0 +HRESULT CALLBACK MxDeviceEnumerate::DisplayModesEnumerateCallback(LPDDSURFACEDESC p_ddsd, LPVOID p_context) +{ + MxDeviceEnumerate* deviceEnumerate = (MxDeviceEnumerate*) p_context; + return deviceEnumerate->EnumDisplayModesCallback(p_ddsd); +} + +// FUNCTION: CONFIG 0x00401c10 +// FUNCTION: LEGO1 0x1009c510 +HRESULT CALLBACK MxDeviceEnumerate::DevicesEnumerateCallback( + LPGUID p_guid, + LPSTR p_deviceDesc, + LPSTR p_deviceName, + LPD3DDEVICEDESC p_HWDesc, + LPD3DDEVICEDESC p_HELDesc, + LPVOID p_context +) +{ + MxDeviceEnumerate* deviceEnumerate = (MxDeviceEnumerate*) p_context; + return deviceEnumerate->EnumDevicesCallback(p_guid, p_deviceDesc, p_deviceName, p_HWDesc, p_HELDesc); +} + +// FUNCTION: CONFIG 0x00401c40 +// FUNCTION: LEGO1 0x1009c540 +HRESULT MxDeviceEnumerate::EnumDisplayModesCallback(LPDDSURFACEDESC p_ddsd) +{ + MxDisplayMode displayMode; + displayMode.m_width = p_ddsd->dwWidth; + displayMode.m_height = p_ddsd->dwHeight; + displayMode.m_bitsPerPixel = p_ddsd->ddpfPixelFormat.dwRGBBitCount; + + m_list.back().m_displayModes.push_back(displayMode); + return DDENUMRET_OK; +} + +// FUNCTION: CONFIG 0x00401cd0 +// FUNCTION: LEGO1 0x1009c5d0 +HRESULT MxDeviceEnumerate::EnumDevicesCallback( + LPGUID p_guid, + LPSTR p_deviceDesc, + LPSTR p_deviceName, + LPD3DDEVICEDESC p_HWDesc, + LPD3DDEVICEDESC p_HELDesc +) +{ + Direct3DDeviceInfo device(p_guid, p_deviceDesc, p_deviceName, p_HWDesc, p_HELDesc); + m_list.back().m_devices.push_back(device); + memset(&device, 0, sizeof(device)); + return DDENUMRET_OK; +} + +// FUNCTION: CONFIG 0x00401dc0 +// FUNCTION: LEGO1 0x1009c6c0 +int MxDeviceEnumerate::DoEnumerate() +{ + if (m_initialized) { + return -1; + } + + HRESULT ret = DirectDrawEnumerate(DirectDrawEnumerateCallback, this); + if (ret != DD_OK) { + BuildErrorString("DirectDrawEnumerate returned error %s\n", EnumerateErrorToString(ret)); + return -1; + } + + m_initialized = TRUE; + return 0; +} + +// FUNCTION: CONFIG 0x00401e10 +// FUNCTION: LEGO1 0x1009c710 +BOOL CALLBACK +MxDeviceEnumerate::DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_context) +{ + MxDeviceEnumerate* deviceEnumerate = (MxDeviceEnumerate*) p_context; + return deviceEnumerate->EnumDirectDrawCallback(p_guid, p_driverDesc, p_driverName); +} + +// FUNCTION: CONFIG 0x00401e30 +// FUNCTION: LEGO1 0x1009c730 +const char* MxDeviceEnumerate::EnumerateErrorToString(HRESULT p_error) +{ + switch (p_error) { + case DD_OK: + return "No error."; + case DDERR_GENERIC: + return "Generic failure."; + case DDERR_UNSUPPORTED: + return "Action not supported."; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect."; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation."; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface."; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized."; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available."; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface."; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment."; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation."; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect."; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface."; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode."; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist."; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified."; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object."; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked."; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid."; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or " + "available."; + case DDERR_NO3D: + return "There is no 3D present."; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or available."; + case DDERR_NOCLIPLIST: + return "No cliplist available."; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key"; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called."; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive " + "mode."; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color key."; + case DDERR_NOGDI: + return "There is no GDI present."; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported."; + case DDERR_NOTFOUND: + return "Requested item was not found."; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available."; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or " + "available."; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available."; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching."; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available."; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or available."; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color " + "palette."; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color " + "index palette."; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color."; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting."; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank " + "synchronized operations."; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated."; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support " + "z layering of overlays."; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation."; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough memory to perform the operation."; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays."; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays."; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread."; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of."; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to."; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured."; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread."; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached."; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface " + "object representing this surface should have Restore called on it."; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK."; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large."; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw."; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large."; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress."; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw."; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary."; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is " + "incomplete."; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier."; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process."; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any hardware."; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface."; + case DDERR_NOEMULATION: + return "Software emulation not available."; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small."; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd."; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object."; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel HWND."; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring " + "state."; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or " + "palettes created."; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface."; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes."; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call."; + case DDERR_NOBLTHW: + return "No blitter hardware present."; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware."; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay."; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on " + "to establish a destination."; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that destination."; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface."; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive."; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable."; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created."; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this " + "process, has been attempted."; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs."; + case DDERR_NODC: + return "No DC was ever created for this surface."; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode."; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface."; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface."; + default: + return "Unrecognized error value."; + } +} + +// FUNCTION: CONFIG 0x00402560 +// FUNCTION: LEGO1 0x1009ce60 +int MxDeviceEnumerate::ParseDeviceName(const char* p_deviceId) +{ + if (!m_initialized) { + return -1; + } + + int num = -1; + int hex[4]; + + if (sscanf(p_deviceId, "%d 0x%x 0x%x 0x%x 0x%x", &num, &hex[0], &hex[1], &hex[2], &hex[3]) != 5) { + return -1; + } + + if (num < 0) { + return -1; + } + + GUID guid; + memcpy(&guid, hex, sizeof(guid)); + + int result = ProcessDeviceBytes(num, guid); + + if (result < 0) { + return ProcessDeviceBytes(-1, guid); + } + return result; +} + +// FUNCTION: CONFIG 0x00402620 +// FUNCTION: LEGO1 0x1009cf20 +int MxDeviceEnumerate::ProcessDeviceBytes(int p_deviceNum, GUID& p_guid) +{ + if (!m_initialized) { + return -1; + } + + int i = 0; + int j = 0; + + struct GUID4 { + int m_data1; + int m_data2; + int m_data3; + int m_data4; + }; + + static_assert(sizeof(GUID4) == sizeof(GUID), "Equal size"); + + GUID4 deviceGuid; + memcpy(&deviceGuid, &p_guid, sizeof(GUID4)); + + for (list::iterator it = m_list.begin(); it != m_list.end(); it++) { + if (p_deviceNum >= 0 && p_deviceNum < i) { + return -1; + } + + GUID4 compareGuid; + MxDriver& driver = *it; + for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end(); it2++) { + memcpy(&compareGuid, (*it2).m_guid, sizeof(GUID4)); + + if (compareGuid.m_data1 == deviceGuid.m_data1 && compareGuid.m_data2 == deviceGuid.m_data2 && + compareGuid.m_data3 == deviceGuid.m_data3 && compareGuid.m_data4 == deviceGuid.m_data4 && + i == p_deviceNum) { + return j; + } + + j++; + } + + i++; + } + + return -1; +} + +// FUNCTION: CONFIG 0x00402730 +// FUNCTION: LEGO1 0x1009d030 +int MxDeviceEnumerate::GetDevice(int p_deviceNum, MxDriver*& p_driver, Direct3DDeviceInfo*& p_device) +{ + if (p_deviceNum >= 0 && m_initialized) { + int i = 0; + + for (list::iterator it = m_list.begin(); it != m_list.end(); it++) { + p_driver = &*it; + + for (list::iterator it2 = p_driver->m_devices.begin(); it2 != p_driver->m_devices.end(); + it2++) { + if (i == p_deviceNum) { + p_device = &*it2; + return 0; + } + i++; + } + } + + return -1; + } + + return -1; +} + +#if defined(MXDIRECTX_FOR_CONFIG) +// FUNCTION: CONFIG 0x004027d0 +int MxDeviceEnumerate::FormatDeviceName(char* p_buffer, const MxDriver* p_driver, const Direct3DDeviceInfo* p_device) + const +{ + int number = 0; + for (list::const_iterator it = m_list.begin(); it != m_list.end(); it++) { + if (&(*it) == p_driver) { + sprintf( + p_buffer, + "%d 0x%x 0x%x 0x%x 0x%x", + number, + ((DWORD*) (p_device->m_guid))[0], + ((DWORD*) (p_device->m_guid))[1], + ((DWORD*) (p_device->m_guid))[2], + ((DWORD*) (p_device->m_guid))[3] + ); + return 0; + } + number++; + } + return -1; +} +#endif + +// FUNCTION: CONFIG 0x00402860 +// FUNCTION: LEGO1 0x1009d0d0 +int MxDeviceEnumerate::FUN_1009d0d0() +{ + if (!m_initialized) { + return -1; + } + + if (m_list.empty()) { + return -1; + } + + int i = 0; + int j = 0; + int k = -1; + int cpu_mmx = SupportsMMX(); + + for (list::iterator it = m_list.begin();; it++) { + if (it == m_list.end()) { + return k; + } + + for (list::iterator it2 = (*it).m_devices.begin(); it2 != (*it).m_devices.end(); it2++) { + if ((*it2).m_HWDesc.dcmColorModel) { + return j; + } + + if ((cpu_mmx && (*it2).m_HELDesc.dcmColorModel == D3DCOLOR_RGB && i == 0) || + ((*it2).m_HELDesc.dcmColorModel == D3DCOLOR_MONO && i == 0 && k < 0)) { + k = j; + } + + j++; + } + + i++; + } +} + +// FUNCTION: CONFIG 0x00402930 +// FUNCTION: LEGO1 0x1009d1a0 +int MxDeviceEnumerate::SupportsMMX() +{ + if (!SupportsCPUID()) { + return 0; + } + int supports_mmx; +#ifdef _MSC_VER + __asm { + mov eax, 0x0 ; EAX=0: Highest Function Parameter and Manufacturer ID +#if _MSC_VER > 1100 + cpuid ; Run CPUID +#else + __emit 0x0f + __emit 0xa2 +#endif + mov eax, 0x1 ; EAX=1: Processor Info and Feature Bits (unused) +#if _MSC_VER > 1100 + cpuid ; Run CPUID +#else + __emit 0x0f + __emit 0xa2 +#endif + xor eax, eax ; Zero EAX register + bt edx, 0x17 ; Test bit 0x17 (23): MMX instructions (64-bit SIMD) (Store in CF) + adc eax, eax ; Add with carry: EAX = EAX + EAX + CF = CF + mov supports_mmx, eax ; Save eax into C variable + } +#else + __asm__("movl $0x0, %%eax\n\t" // EAX=0: Highest Function Parameter and Manufacturer ID + "cpuid\n\t" // Run CPUID\n" + "mov $0x1, %%eax\n\t" // EAX=1: Processor Info and Feature Bits (unused) + "cpuid\n\t" // Run CPUID + "xorl %%eax, %%eax\n\t" // Zero EAX register + "btl $0x15, %%edx\n\t" // Test bit 0x17 (23): MMX instructions (64-bit SIMD) (Store in CF) + "adc %%eax, %%eax" // Add with carry: EAX = EAX + EAX + CF = CF + : "=a"(supports_mmx) // supports_mmx == EAX + ); +#endif + return supports_mmx; +} + +// FUNCTION: CONFIG 0x00402970 +// FUNCTION: LEGO1 0x1009d1e0 +int MxDeviceEnumerate::SupportsCPUID() +{ + int has_cpuid; +#ifdef _MSC_VER + __asm { + xor eax, eax ; Zero EAX register + pushfd ; Push EFLAGS register value on the stack + or dword ptr[esp], 0x200000 ; Set bit 0x200000: Able to use CPUID instruction (Pentium+) + popfd ; Write the updated value into the EFLAGS register + pushfd ; Push EFLAGS register value on the stack (again) + btr dword ptr[esp], 0x15 ; Test bit 0x15 (21) and reset (set CF) + adc eax, eax ; Add with carry: EAX = EAX + EAX + CF = CF + popfd ; Push EFLAGS register value on the stack (again, and makes sure the stack remains the same) + mov has_cpuid, eax ; Save eax into C variable + } +#else + __asm__("xorl %%eax, %%eax\n\t" // Zero EAX register + "pushfl\n\t" // Push EFLAGS register value on the stack + "orl $0x200000, (%%esp)\n\t" // Set bit 0x200000: Able to use CPUID instruction (Pentium+) + "popfl\n\t" // Write the updated value into the EFLAGS register + "pushfl\n\t" // Push EFLAGS register value on the stack (again) + "btrl $0x15, (%%esp)\n\t" // Test bit 0x15 (21) and reset (set CF) + "adc %%eax, %%eax\n\t" // Add with carry: EAX = EAX + EAX + CF = CF + "popfl" // Push EFLAGS register value on the stack (again, and makes sure the stack remains the same) + : "=a"(has_cpuid) // has_cpuid == EAX + ); +#endif + return has_cpuid; +} + +// FUNCTION: CONFIG 0x004029a0 +// FUNCTION: LEGO1 0x1009d210 +int MxDeviceEnumerate::FUN_1009d210() +{ + if (!m_initialized) { + return -1; + } + + for (list::iterator it = m_list.begin(); it != m_list.end();) { + MxDriver& driver = *it; + + if (!DriverSupportsRequiredDisplayMode(driver)) { + m_list.erase(it++); + } + else { + for (list::iterator it2 = driver.m_devices.begin(); it2 != driver.m_devices.end();) { + Direct3DDeviceInfo& device = *it2; + + if (!FUN_1009d3d0(device)) { + driver.m_devices.erase(it2++); + } + else { + it2++; + } + } + + if (driver.m_devices.empty()) { + m_list.erase(it++); + } + else { + it++; + } + } + } + + return m_list.empty() ? -1 : 0; +} + +// FUNCTION: CONFIG 0x00402b00 +// FUNCTION: LEGO1 0x1009d370 +unsigned char MxDeviceEnumerate::DriverSupportsRequiredDisplayMode(MxDriver& p_driver) +{ + for (list::iterator it = p_driver.m_displayModes.begin(); it != p_driver.m_displayModes.end(); + it++) { + if ((*it).m_width == 640 && (*it).m_height == 480) { + if ((*it).m_bitsPerPixel == 8 || (*it).m_bitsPerPixel == 16) { + return TRUE; + } + } + } + + return FALSE; +} + +// FUNCTION: CONFIG 0x00402b60 +// FUNCTION: LEGO1 0x1009d3d0 +unsigned char MxDeviceEnumerate::FUN_1009d3d0(Direct3DDeviceInfo& p_device) +{ + if (m_list.size() <= 0) { + return FALSE; + } + + if (p_device.m_HWDesc.dcmColorModel) { + return p_device.m_HWDesc.dwDeviceZBufferBitDepth & DDBD_16 && + p_device.m_HWDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_PERSPECTIVE; + } + + for (list::iterator it = m_list.front().m_devices.begin(); it != m_list.front().m_devices.end(); + it++) { + if ((&*it) == &p_device) { + return TRUE; + } + } + + return FALSE; +} diff --git a/LEGO1/mxdirectx/mxdirect3d.h b/LEGO1/mxdirectx/mxdirect3d.h new file mode 100644 index 00000000..bbfe7e3b --- /dev/null +++ b/LEGO1/mxdirectx/mxdirect3d.h @@ -0,0 +1,258 @@ +#ifndef MXDIRECT3D_H +#define MXDIRECT3D_H + +#include "decomp.h" +#include "mxdirectdraw.h" +#include "mxstl/stlcompat.h" + +#include + +#if !defined(MXDIRECTX_FOR_CONFIG) +class MxDirect3D; + +// SIZE 0xe4 +class MxAssignedDevice { +public: + enum { + c_hardwareMode = 0x01, + c_primaryDevice = 0x02 + }; + + MxAssignedDevice(); + ~MxAssignedDevice(); + + inline unsigned int GetFlags() { return m_flags; } + inline BOOL GetHardwareMode() { return ((int) m_flags << 31) >> 31; } + inline D3DDEVICEDESC& GetDesc() { return m_desc; } + + friend class MxDirect3D; + +private: + GUID m_guid; // 0x00 + unsigned int m_flags; // 0x10 + D3DDEVICEDESC m_desc; // 0x14 + MxDirectDraw::DeviceModesInfo* m_deviceInfo; // 0xe0 +}; + +class MxDeviceEnumerate; +struct MxDriver; +struct Direct3DDeviceInfo; + +// VTABLE: LEGO1 0x100db800 +// SIZE 0x894 +class MxDirect3D : public MxDirectDraw { +public: + MxDirect3D(); + ~MxDirect3D() override; + + BOOL Create( + HWND hWnd, + BOOL fullscreen_1, + BOOL surface_fullscreen, + BOOL onlySystemMemory, + int width, + int height, + int bpp, + const PALETTEENTRY* pPaletteEntries, + int paletteEntryCount + ) override; // vtable+0x04 + void Destroy() override; // vtable+0x08 + void DestroyButNotDirectDraw() override; // vtable+0x0c + + inline MxAssignedDevice* AssignedDevice() { return this->m_assignedDevice; } + inline IDirect3D2* Direct3D() { return this->m_pDirect3d; } + inline IDirect3DDevice2* Direct3DDevice() { return this->m_pDirect3dDevice; } + + BOOL SetDevice(MxDeviceEnumerate& p_deviceEnumerate, MxDriver* p_driver, Direct3DDeviceInfo* p_device); + +protected: + BOOL D3DCreate(); + BOOL D3DSetMode(); + + int ZBufferDepth(MxAssignedDevice* p_assignedDevice); + + // SYNTHETIC: LEGO1 0x1009b120 + // MxDirect3D::`scalar deleting destructor' + +private: + MxAssignedDevice* m_assignedDevice; // 0x880 + IDirect3D2* m_pDirect3d; // 0x884 + IDirect3DDevice2* m_pDirect3dDevice; // 0x888 + BOOL m_bTexturesDisabled; // 0x88c + undefined4 m_unk0x890; // 0x890 +}; +#endif + +// SIZE 0x1a4 +struct Direct3DDeviceInfo { + Direct3DDeviceInfo() {} + ~Direct3DDeviceInfo(); + Direct3DDeviceInfo( + LPGUID p_guid, + LPSTR p_deviceDesc, + LPSTR p_deviceName, + LPD3DDEVICEDESC p_HWDesc, + LPD3DDEVICEDESC p_HELDesc + ); + + void Initialize( + LPGUID p_guid, + LPSTR p_deviceDesc, + LPSTR p_deviceName, + LPD3DDEVICEDESC p_HWDesc, + LPD3DDEVICEDESC p_HELDesc + ); + + LPGUID m_guid; // 0x00 + char* m_deviceDesc; // 0x04 + char* m_deviceName; // 0x08 + D3DDEVICEDESC m_HWDesc; // 0x0c + D3DDEVICEDESC m_HELDesc; // 0xd8 + + int operator==(Direct3DDeviceInfo) const { return 0; } + int operator<(Direct3DDeviceInfo) const { return 0; } +}; + +// SIZE 0x0c +struct MxDisplayMode { + DWORD m_width; // 0x00 + DWORD m_height; // 0x04 + DWORD m_bitsPerPixel; // 0x08 + + int operator==(MxDisplayMode) const { return 0; } + int operator<(MxDisplayMode) const { return 0; } +}; + +// SIZE 0x190 +struct MxDriver { + MxDriver() {} + ~MxDriver(); + MxDriver(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName); + + void Init(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName); + + LPGUID m_guid; // 0x00 + char* m_driverDesc; // 0x04 + char* m_driverName; // 0x08 + DDCAPS m_ddCaps; // 0x0c + list m_devices; // 0x178 + list m_displayModes; // 0x184 + + int operator==(MxDriver) const { return 0; } + int operator<(MxDriver) const { return 0; } +}; + +// clang-format off +// TEMPLATE: CONFIG 0x401000 +// TEMPLATE: LEGO1 0x1009b900 +// list >::~list > +// clang-format on + +// clang-format off +// TEMPLATE: CONFIG 0x401070 +// TEMPLATE: LEGO1 0x1009b970 +// list >::~list > +// clang-format on + +// TEMPLATE: CONFIG 0x4010e0 +// TEMPLATE: LEGO1 0x1009b9e0 +// List::~List + +// TEMPLATE: CONFIG 0x401130 +// TEMPLATE: LEGO1 0x1009ba30 +// List::~List + +// clang-format off +// TEMPLATE: CONFIG 0x401650 +// TEMPLATE: LEGO1 0x1009bf50 +// list >::~list > +// clang-format on + +// TEMPLATE: CONFIG 0x4016c0 +// TEMPLATE: LEGO1 0x1009bfc0 +// List::~List + +// Compiler-generated copy ctor +// SYNTHETIC: CONFIG 0x401990 +// SYNTHETIC: LEGO1 0x1009c290 +// MxDriver::MxDriver + +// SYNTHETIC: CONFIG 0x401b00 +// SYNTHETIC: LEGO1 0x1009c400 +// list >::insert + +// SYNTHETIC: CONFIG 0x401b60 +// SYNTHETIC: LEGO1 0x1009c460 +// list >::insert + +// SYNTHETIC: LEGO1 0x1009d450 +// MxDriver::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1009d470 +// Direct3DDeviceInfo::`scalar deleting destructor' + +// VTABLE: CONFIG 0x00406000 +// VTABLE: LEGO1 0x100db814 +// SIZE 0x14 +class MxDeviceEnumerate { +public: + MxDeviceEnumerate(); + ~MxDeviceEnumerate(); + + virtual int DoEnumerate(); // vtable+0x00 + + BOOL EnumDirectDrawCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName); + HRESULT EnumDisplayModesCallback(LPDDSURFACEDESC p_ddsd); + HRESULT EnumDevicesCallback( + LPGUID p_guid, + LPSTR p_deviceDesc, + LPSTR p_deviceName, + LPD3DDEVICEDESC p_HWDesc, + LPD3DDEVICEDESC p_HELDesc + ); + const char* EnumerateErrorToString(HRESULT p_error); + int ParseDeviceName(const char* p_deviceId); + int ProcessDeviceBytes(int p_deviceNum, GUID& p_guid); + int GetDevice(int p_deviceNum, MxDriver*& p_driver, Direct3DDeviceInfo*& p_device); + +#if defined(MXDIRECTX_FOR_CONFIG) + int FormatDeviceName(char* p_buffer, const MxDriver* p_driver, const Direct3DDeviceInfo* p_device) const; +#endif + + int FUN_1009d0d0(); + int FUN_1009d210(); + unsigned char DriverSupportsRequiredDisplayMode(MxDriver& p_driver); + unsigned char FUN_1009d3d0(Direct3DDeviceInfo& p_device); + + static void BuildErrorString(const char*, ...); + static BOOL CALLBACK + DirectDrawEnumerateCallback(LPGUID p_guid, LPSTR p_driverDesc, LPSTR p_driverName, LPVOID p_context); + static HRESULT CALLBACK DisplayModesEnumerateCallback(LPDDSURFACEDESC p_ddsd, LPVOID p_context); + static HRESULT CALLBACK DevicesEnumerateCallback( + LPGUID p_guid, + LPSTR p_deviceDesc, + LPSTR p_deviceName, + LPD3DDEVICEDESC p_HWDesc, + LPD3DDEVICEDESC p_HELDesc, + LPVOID p_context + ); + static int SupportsMMX(); + static int SupportsCPUID(); + + friend class MxDirect3D; + + const list& GetDriverList() const { return m_list; } + +private: + list m_list; // 0x04 + unsigned char m_initialized; // 0x10 +}; + +// VTABLE: LEGO1 0x100d9cc8 +// SIZE 0x14 +class MxDeviceEnumerate100d9cc8 : public MxDeviceEnumerate {}; + +// SYNTHETIC: LEGO1 0x1007b590 +// MxDeviceEnumerate100d9cc8::~MxDeviceEnumerate100d9cc8 + +#endif // MXDIRECT3D_H diff --git a/LEGO1/mxdirectx/mxdirectdraw.cpp b/LEGO1/mxdirectx/mxdirectdraw.cpp new file mode 100644 index 00000000..cdd5f3b7 --- /dev/null +++ b/LEGO1/mxdirectx/mxdirectdraw.cpp @@ -0,0 +1,1115 @@ +#include "mxdirectdraw.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxDirectDraw, 0x880); +DECOMP_SIZE_ASSERT(MxDirectDraw::DeviceModesInfo, 0x17c); + +#define RELEASE(x) \ + if (x != NULL) { \ + x->Release(); \ + x = NULL; \ + } + +#ifndef DDSCAPS_3DDEVICE +#define DDSCAPS_3DDEVICE 0x00002000l +#endif + +// GLOBAL: LEGO1 0x10100c68 +BOOL g_isPaletteIndexed8 = 0; + +// FUNCTION: LEGO1 0x1009d490 +MxDirectDraw::MxDirectDraw() +{ + m_pFrontBuffer = NULL; + m_pBackBuffer = NULL; + m_pZBuffer = NULL; + m_pClipper = NULL; + m_pPalette = NULL; + m_pDirectDraw = NULL; + m_pText1Surface = NULL; + m_pText2Surface = NULL; + m_hWndMain = NULL; + m_bIgnoreWMSIZE = FALSE; + m_bPrimaryPalettized = FALSE; + m_bOnlySystemMemory = FALSE; + m_bFullScreen = FALSE; + m_bOnlySoftRender = FALSE; + m_pauseCount = 0; + m_pErrorHandler = NULL; + m_pFatalErrorHandler = NULL; + m_pErrorHandlerArg = NULL; + m_pFatalErrorHandlerArg = NULL; + m_pCurrentDeviceModesList = NULL; + m_bIsOnPrimaryDevice = TRUE; + m_hFont = NULL; +} + +// FUNCTION: LEGO1 0x1009d530 +MxDirectDraw::~MxDirectDraw() +{ + Destroy(); + + if (m_pCurrentDeviceModesList != NULL) { + delete m_pCurrentDeviceModesList; + m_pCurrentDeviceModesList = NULL; + } +} + +// FUNCTION: LEGO1 0x1009d570 +int MxDirectDraw::GetPrimaryBitDepth() +{ + DWORD dwRGBBitCount; + LPDIRECTDRAW pDDraw; + DDSURFACEDESC ddsd; + + HRESULT result = DirectDrawCreate(NULL, &pDDraw, NULL); + dwRGBBitCount = 8; + if (!result) { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + pDDraw->GetDisplayMode(&ddsd); + dwRGBBitCount = ddsd.ddpfPixelFormat.dwRGBBitCount; + g_isPaletteIndexed8 = (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) != 0; + pDDraw->Release(); + } + + return dwRGBBitCount; +} + +// FUNCTION: LEGO1 0x1009d5e0 +BOOL MxDirectDraw::Create( + HWND hWnd, + BOOL fullscreen, + BOOL surface_fullscreen, + BOOL onlySystemMemory, + int width, + int height, + int bpp, + const PALETTEENTRY* pPaletteEntries, + int paletteEntryCount +) +{ + m_hWndMain = hWnd; + + CacheOriginalPaletteEntries(); + + if (!RecreateDirectDraw(&m_pCurrentDeviceModesList->m_guid)) { + return FALSE; + } + + m_bFlipSurfaces = surface_fullscreen; + m_bOnlySystemMemory = onlySystemMemory; + m_bIsOnPrimaryDevice = !m_pCurrentDeviceModesList->m_guid; + + if (!m_bIsOnPrimaryDevice) { + fullscreen = TRUE; + } + + if (!SetPaletteEntries(pPaletteEntries, paletteEntryCount, fullscreen)) { + return FALSE; + } + + if (!DDInit(fullscreen)) { + return FALSE; + } + + if (!DDSetMode(width, height, bpp)) { + return FALSE; + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009d690 +BOOL MxDirectDraw::RecreateDirectDraw(GUID** ppGUID) +{ + RELEASE(m_pDirectDraw); + return (DirectDrawCreate(*ppGUID, &m_pDirectDraw, 0) == DD_OK); +} + +// FUNCTION: LEGO1 0x1009d6c0 +BOOL MxDirectDraw::CacheOriginalPaletteEntries() +{ + HDC hdc; + + if (g_isPaletteIndexed8) { + hdc = GetDC(NULL); + GetSystemPaletteEntries(hdc, 0, (1 << 8), &m_originalPaletteEntries[0]); + ReleaseDC(NULL, hdc); + } + return TRUE; +} + +// FUNCTION: LEGO1 0x1009d700 +BOOL MxDirectDraw::SetPaletteEntries(const PALETTEENTRY* pPaletteEntries, int paletteEntryCount, BOOL fullscreen) +{ + int reservedLowEntryCount = 10; + int reservedHighEntryCount = 10; + int arraySize = sizeOfArray(m_paletteEntries); + HDC hdc; + int i; + + if (g_isPaletteIndexed8) { + hdc = GetDC(NULL); + GetSystemPaletteEntries(hdc, 0, (1 << 8), m_paletteEntries); + ReleaseDC(NULL, hdc); + } + + for (i = 0; i < reservedLowEntryCount; i++) { + m_paletteEntries[i].peFlags = 0x80; + } + + for (i = reservedLowEntryCount; i < 142; i++) { + m_paletteEntries[i].peFlags = 0x44; + } + + for (i = 142; i < arraySize - reservedHighEntryCount; i++) { + m_paletteEntries[i].peFlags = 0x84; + } + + for (i = 256 - reservedHighEntryCount; i < 256; i++) { + m_paletteEntries[i].peFlags = 0x80; + } + + if (paletteEntryCount != 0) { + for (i = reservedLowEntryCount; (i < paletteEntryCount) && (i < 256 - reservedHighEntryCount); i++) { + m_paletteEntries[i].peRed = pPaletteEntries[i].peRed; + m_paletteEntries[i].peGreen = pPaletteEntries[i].peGreen; + m_paletteEntries[i].peBlue = pPaletteEntries[i].peBlue; + } + } + + if (m_pPalette) { + HRESULT result; + + result = m_pPalette->SetEntries(0, 0, sizeOfArray(m_paletteEntries), m_paletteEntries); + if (result != DD_OK) { + Error("SetEntries failed", result); + return FALSE; + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009d800 +void MxDirectDraw::Destroy() +{ + DestroyButNotDirectDraw(); + + FUN_1009d920(); + + RELEASE(m_pDirectDraw); + + m_bIsOnPrimaryDevice = TRUE; + + if (m_pCurrentDeviceModesList != NULL) { + delete m_pCurrentDeviceModesList; + m_pCurrentDeviceModesList = NULL; + } +} + +// FUNCTION: LEGO1 0x1009d860 +void MxDirectDraw::DestroyButNotDirectDraw() +{ + RestoreOriginalPaletteEntries(); + if (m_bFullScreen) { + if (m_pDirectDraw) { + m_bIgnoreWMSIZE = TRUE; + m_pDirectDraw->RestoreDisplayMode(); + m_bIgnoreWMSIZE = FALSE; + } + } + + RELEASE(m_pPalette); + RELEASE(m_pClipper); + RELEASE(m_pText1Surface); + RELEASE(m_pText2Surface); + RELEASE(m_pZBuffer); + RELEASE(m_pBackBuffer); + RELEASE(m_pFrontBuffer); +} + +// FUNCTION: LEGO1 0x1009d920 +void MxDirectDraw::FUN_1009d920() +{ + RestoreOriginalPaletteEntries(); + if (m_pDirectDraw != NULL) { + m_bIgnoreWMSIZE = TRUE; + m_pDirectDraw->RestoreDisplayMode(); + m_pDirectDraw->SetCooperativeLevel(NULL, DDSCL_NORMAL); + m_bIgnoreWMSIZE = FALSE; + } +} + +// FUNCTION: LEGO1 0x1009d960 +BOOL MxDirectDraw::DDInit(BOOL fullscreen) +{ + HRESULT result; + + if (fullscreen) { + m_bIgnoreWMSIZE = TRUE; + result = m_pDirectDraw->SetCooperativeLevel(m_hWndMain, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + m_bIgnoreWMSIZE = FALSE; + } + else { + result = m_pDirectDraw->SetCooperativeLevel(m_hWndMain, DDSCL_NORMAL); + } + + if (result != DD_OK) { + Error("SetCooperativeLevel failed", result); + return FALSE; + } + + m_bFullScreen = fullscreen; + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009d9d0 +BOOL MxDirectDraw::IsSupportedMode(int width, int height, int bpp) +{ + Mode mode = {width, height, bpp}; + + for (int i = 0; i < m_pCurrentDeviceModesList->m_count; i++) { + if (m_pCurrentDeviceModesList->m_modeArray[i] == mode) { + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x1009da20 +void EnableResizing(HWND p_hwnd, BOOL p_flag) +{ + static DWORD g_dwStyle; + + if (!p_flag) { + g_dwStyle = GetWindowLong(p_hwnd, GWL_STYLE); + if (g_dwStyle & WS_THICKFRAME) { + SetWindowLong(p_hwnd, GWL_STYLE, GetWindowLong(p_hwnd, GWL_STYLE) ^ WS_THICKFRAME); + } + } + else { + SetWindowLong(p_hwnd, GWL_STYLE, g_dwStyle); + } +} + +// FUNCTION: LEGO1 0x1009da80 +BOOL MxDirectDraw::DDSetMode(int width, int height, int bpp) +{ + HRESULT result; + + if (m_bFullScreen) { + LPDIRECTDRAW lpDD; + + EnableResizing(m_hWndMain, FALSE); + + if (!m_bIsOnPrimaryDevice) { + lpDD = NULL; + result = DirectDrawCreate(0, &lpDD, 0); + if (result == DD_OK) { + result = lpDD->SetCooperativeLevel(m_hWndMain, DDSCL_FULLSCREEN | DDSCL_EXCLUSIVE | DDSCL_ALLOWREBOOT); + if (result == DD_OK) { + lpDD->SetDisplayMode(width, height, 8); + } + } + } + + if (!IsSupportedMode(width, height, bpp)) { + width = m_pCurrentDeviceModesList->m_modeArray[0].width; + height = m_pCurrentDeviceModesList->m_modeArray[0].height; + bpp = m_pCurrentDeviceModesList->m_modeArray[0].bitsPerPixel; + } + + m_bIgnoreWMSIZE = TRUE; + result = m_pDirectDraw->SetDisplayMode(width, height, bpp); + m_bIgnoreWMSIZE = FALSE; + if (result != DD_OK) { + Error("SetDisplayMode failed", result); + return FALSE; + } + } + else { + RECT rc; + DWORD dwStyle; + + if (!m_bIsOnPrimaryDevice) { + Error( + "Attempt made enter a windowed mode on a DirectDraw device that is not the primary display", + DDERR_GENERIC + ); + return FALSE; + } + + m_bIgnoreWMSIZE = TRUE; + dwStyle = GetWindowLong(m_hWndMain, GWL_STYLE); + dwStyle &= ~WS_POPUP; + dwStyle |= WS_OVERLAPPED | WS_CAPTION | WS_THICKFRAME; + SetWindowLong(m_hWndMain, GWL_STYLE, dwStyle); + SetRect(&rc, 0, 0, width - 1, height - 1); + AdjustWindowRectEx( + &rc, + GetWindowLong(m_hWndMain, GWL_STYLE), + GetMenu(m_hWndMain) != NULL, + GetWindowLong(m_hWndMain, GWL_EXSTYLE) + ); + SetWindowPos( + m_hWndMain, + NULL, + 0, + 0, + rc.right - rc.left + 1, + rc.bottom - rc.top + 1, + SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE + ); + SetWindowPos(m_hWndMain, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + m_bIgnoreWMSIZE = FALSE; + } + + m_currentMode.width = width; + m_currentMode.height = height; + m_currentMode.bitsPerPixel = bpp; + + if (!DDCreateSurfaces()) { + return FALSE; + } + + DDSURFACEDESC ddsd; + + FUN_1009e020(); + + if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) { + return FALSE; + } + + if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) { + m_bPrimaryPalettized = TRUE; + } + else { + m_bPrimaryPalettized = FALSE; + } + + if (m_bPrimaryPalettized) { + result = m_pDirectDraw->CreatePalette( + DDPCAPS_8BIT | DDPCAPS_ALLOW256 | DDPCAPS_INITIALIZE, // 0x4c + m_paletteEntries, + &m_pPalette, + NULL + ); + if (result != DD_OK) { + Error("CreatePalette failed", result); + return 0; + } + result = m_pBackBuffer->SetPalette(m_pPalette); // TODO: add FIX_BUGS define and fix this + result = m_pFrontBuffer->SetPalette(m_pPalette); + if (result != DD_OK) { + Error("SetPalette failed", result); + return FALSE; + } + } + + // create debug text only in windowed mode? + return m_bFullScreen || CreateTextSurfaces(); +} + +// FUNCTION: LEGO1 0x1009dd80 +HRESULT MxDirectDraw::CreateDDSurface( + LPDDSURFACEDESC p_lpDDSurfDesc, + LPDIRECTDRAWSURFACE FAR* p_lpDDSurface, + IUnknown FAR* p_pUnkOuter +) +{ + return m_pDirectDraw->CreateSurface(p_lpDDSurfDesc, p_lpDDSurface, p_pUnkOuter); +} + +// FUNCTION: LEGO1 0x1009dda0 +BOOL MxDirectDraw::GetDDSurfaceDesc(LPDDSURFACEDESC lpDDSurfDesc, LPDIRECTDRAWSURFACE lpDDSurf) +{ + HRESULT result; + + memset(lpDDSurfDesc, 0, sizeof(DDSURFACEDESC)); + lpDDSurfDesc->dwSize = sizeof(DDSURFACEDESC); + result = lpDDSurf->GetSurfaceDesc(lpDDSurfDesc); + if (result != DD_OK) { + Error("Error getting a surface description", result); + } + + return (result == DD_OK); +} + +// FUNCTION: LEGO1 0x1009ddf0 +BOOL MxDirectDraw::DDCreateSurfaces() +{ + HRESULT result; + DDSURFACEDESC ddsd; + DDSCAPS ddscaps; + + if (m_bFlipSurfaces) { + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_3DDEVICE | DDSCAPS_COMPLEX; + if (m_bOnlySystemMemory) { + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + } + ddsd.dwBackBufferCount = 1; + result = CreateDDSurface(&ddsd, &m_pFrontBuffer, NULL); + if (result != DD_OK) { + Error("CreateSurface for front/back fullScreen buffer failed", result); + return FALSE; + } + ddscaps.dwCaps = DDSCAPS_BACKBUFFER; + result = m_pFrontBuffer->GetAttachedSurface(&ddscaps, &m_pBackBuffer); + if (result != DD_OK) { + Error("GetAttachedSurface failed to get back buffer", result); + return FALSE; + } + if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) { + return FALSE; + } + } + else { + memset(&ddsd, 0, sizeof(DDSURFACEDESC)); + ddsd.dwSize = sizeof(DDSURFACEDESC); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + result = CreateDDSurface(&ddsd, &m_pFrontBuffer, NULL); + if (result != DD_OK) { + Error("CreateSurface for window front buffer failed", result); + return FALSE; + } + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.dwHeight = m_currentMode.height; + ddsd.dwWidth = m_currentMode.width; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE; + if (m_bOnlySystemMemory) { + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + } + result = CreateDDSurface(&ddsd, &m_pBackBuffer, NULL); + if (result != DD_OK) { + Error("CreateSurface for window back buffer failed", result); + return FALSE; + } + if (!GetDDSurfaceDesc(&ddsd, m_pBackBuffer)) { + return FALSE; + } + + result = m_pDirectDraw->CreateClipper(0, &m_pClipper, NULL); + if (result != DD_OK) { + Error("CreateClipper failed", result); + return FALSE; + } + result = m_pClipper->SetHWnd(0, m_hWndMain); + if (result != DD_OK) { + Error("Clipper SetHWnd failed", result); + return FALSE; + } + result = m_pFrontBuffer->SetClipper(m_pClipper); + if (result != DD_OK) { + Error("SetClipper failed", result); + return FALSE; + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009e020 +void MxDirectDraw::FUN_1009e020() +{ + HRESULT result; + byte* line; + DDSURFACEDESC ddsd; + int j; + int count = m_bFlipSurfaces ? 2 : 1; + + for (int i = 0; i < count; i++) { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + result = m_pBackBuffer->Lock(NULL, &ddsd, 1, NULL); + if (result == DDERR_SURFACELOST) { + m_pBackBuffer->Restore(); + result = m_pBackBuffer->Lock(NULL, &ddsd, 1, NULL); + } + + if (result != DD_OK) { + // lock failed + return; + } + + // clear backBuffer + line = (byte*) ddsd.lpSurface; + for (j = ddsd.dwHeight; j--;) { + memset(line, 0, ddsd.dwWidth); + line += ddsd.lPitch; + } + + m_pBackBuffer->Unlock(ddsd.lpSurface); + + if (m_bFlipSurfaces) { + m_pFrontBuffer->Flip(NULL, DDFLIP_WAIT); + } + } +} + +// FUNCTION: LEGO1 0x1009e110 +BOOL MxDirectDraw::TextToTextSurface(const char* text, IDirectDrawSurface* pSurface, SIZE& textSizeOnSurface) +{ + HRESULT result; + HDC hdc; + RECT rc; + size_t textLength; + + if (!pSurface) { + return FALSE; + } + + result = pSurface->GetDC(&hdc); + if (result != DD_OK) { + Error("GetDC for text surface failed", result); + return FALSE; + } + + textLength = strlen(text); + + SelectObject(hdc, m_hFont); + SetTextColor(hdc, RGB(255, 255, 0)); + SetBkColor(hdc, RGB(0, 0, 0)); + SetBkMode(hdc, OPAQUE); + GetTextExtentPoint32(hdc, text, textLength, &textSizeOnSurface); + SetRect(&rc, 0, 0, textSizeOnSurface.cx, textSizeOnSurface.cy); + ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, text, textLength, NULL); + pSurface->ReleaseDC(hdc); + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009e210 +BOOL MxDirectDraw::TextToTextSurface1(const char* text) +{ + return TextToTextSurface(text, m_pText1Surface, m_text1SizeOnSurface); +} + +// FUNCTION: LEGO1 0x1009e230 +BOOL MxDirectDraw::TextToTextSurface2(const char* text) +{ + return TextToTextSurface(text, m_pText2Surface, m_text2SizeOnSurface); +} + +// FUNCTION: LEGO1 0x1009e250 +BOOL MxDirectDraw::CreateTextSurfaces() +{ + HRESULT result; + DDCOLORKEY ddck; + DDSURFACEDESC ddsd; + HDC hdc; + char dummyinfo[] = "000x000x00 (RAMP) 0000"; + char dummyfps[] = "000.00 fps (000.00 fps (000.00 fps) 00000 tps)"; + + if (m_hFont != NULL) { + DeleteObject(m_hFont); + } + m_hFont = CreateFont( + m_currentMode.width <= 600 ? 12 : 24, + 0, + 0, + 0, + FW_NORMAL, + FALSE, + FALSE, + FALSE, + ANSI_CHARSET, + OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + VARIABLE_PITCH, + "Arial" + ); + + hdc = GetDC(NULL); + SelectObject(hdc, m_hFont); + GetTextExtentPoint(hdc, dummyfps, strlen(dummyfps), &m_text1SizeOnSurface); + GetTextExtentPoint(hdc, dummyinfo, strlen(dummyinfo), &m_text2SizeOnSurface); + ReleaseDC(NULL, hdc); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + if (m_bOnlySystemMemory) { + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + } + ddsd.dwHeight = m_text1SizeOnSurface.cy; + ddsd.dwWidth = m_text1SizeOnSurface.cx; + result = CreateDDSurface(&ddsd, &m_pText1Surface, NULL); + if (result != DD_OK) { + Error("CreateSurface for text surface 1 failed", result); + return FALSE; + } + memset(&ddck, 0, sizeof(ddck)); + m_pText1Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); + if (!TextToTextSurface1(dummyfps)) { + return FALSE; + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; + if (m_bOnlySystemMemory) { + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + } + ddsd.dwHeight = m_text2SizeOnSurface.cy; + ddsd.dwWidth = m_text2SizeOnSurface.cx; + result = CreateDDSurface(&ddsd, &m_pText2Surface, NULL); + if (result != DD_OK) { + Error("CreateSurface for text surface 2 failed", result); + return FALSE; + } + memset(&ddck, 0, sizeof(ddck)); + m_pText2Surface->SetColorKey(DDCKEY_SRCBLT, &ddck); + if (!TextToTextSurface2(dummyinfo)) { + return FALSE; + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009e4d0 +BOOL MxDirectDraw::RestoreSurfaces() +{ + HRESULT result; + + if (m_pFrontBuffer != NULL) { + if (m_pFrontBuffer->IsLost() == DDERR_SURFACELOST) { + result = m_pFrontBuffer->Restore(); + if (result != DD_OK) { + Error("Restore of front buffer failed", result); + return FALSE; + } + } + } + + if (m_pBackBuffer != NULL) { + if (m_pBackBuffer->IsLost() == DDERR_SURFACELOST) { + result = m_pBackBuffer->Restore(); + if (result != DD_OK) { + Error("Restore of back buffer failed", result); + return FALSE; + } + } + } + + if (m_pZBuffer != NULL) { + if (m_pZBuffer->IsLost() == DDERR_SURFACELOST) { + result = m_pZBuffer->Restore(); + if (result != DD_OK) { + Error("Restore of Z-buffer failed", result); + return FALSE; + } + } + } + + if (m_pText1Surface != NULL) { + if (m_pText1Surface->IsLost() == DDERR_SURFACELOST) { + result = m_pText1Surface->Restore(); + if (result != DD_OK) { + Error("Restore of text surface 1 failed", result); + return FALSE; + } + } + } + + if (m_pText2Surface != NULL) { + if (m_pText2Surface->IsLost() == DDERR_SURFACELOST) { + result = m_pText2Surface->Restore(); + if (result != DD_OK) { + Error("Restore of text surface 2 failed", result); + return FALSE; + } + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009e5e0 +BOOL MxDirectDraw::CreateZBuffer(DWORD memorytype, DWORD depth) +{ + HRESULT result; // eax + LPDIRECTDRAWSURFACE lpZBuffer; // [esp+8h] [ebp-70h] BYREF + DDSURFACEDESC ddsd; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_ZBUFFERBITDEPTH; + ddsd.dwHeight = m_currentMode.height; + ddsd.dwWidth = m_currentMode.width; + ddsd.dwZBufferBitDepth = depth; + ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER | memorytype; + result = CreateDDSurface(&ddsd, &lpZBuffer, 0); + + if (result != DD_OK) { + Error("CreateSurface for fullScreen Z-buffer failed", result); + return FALSE; + } + + result = m_pBackBuffer->AddAttachedSurface(lpZBuffer); + if (result != DD_OK) { + Error("AddAttachedBuffer failed for Z-Buffer", result); + return FALSE; + } + + m_pZBuffer = lpZBuffer; + return TRUE; +} + +// FUNCTION: LEGO1 0x1009e6a0 +int MxDirectDraw::Pause(BOOL p_pause) +{ + if (p_pause) { + ++m_pauseCount; + + if (m_pauseCount > 1) { + return TRUE; + } + + if (!RestoreOriginalPaletteEntries()) { + return FALSE; + } + + if (m_bFullScreen) { + if (!FlipToGDISurface()) { + return FALSE; + } + + DrawMenuBar(m_hWndMain); + RedrawWindow(m_hWndMain, NULL, NULL, RDW_FRAME); + } + } + else { + --m_pauseCount; + + if (m_pauseCount > 0) { + return TRUE; + } + + if (m_pauseCount < 0) { + m_pauseCount = 0; + } + + if (!RestorePaletteEntries()) { + return FALSE; + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009e750 +BOOL MxDirectDraw::RestorePaletteEntries() +{ + + if (m_bFullScreen && m_bPrimaryPalettized) { + if (m_pPalette) { + HRESULT result; + + result = + m_pPalette->SetEntries(0, 0, sizeof(m_paletteEntries) / sizeof(m_paletteEntries[0]), m_paletteEntries); + if (result != DD_OK) { + Error("SetEntries failed", result); + return FALSE; + } + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009e7a0 +BOOL MxDirectDraw::RestoreOriginalPaletteEntries() +{ + if (m_bPrimaryPalettized) { + if (m_pPalette) { + HRESULT result; + + result = m_pPalette->SetEntries( + 0, + 0, + sizeof(m_originalPaletteEntries) / sizeof(m_originalPaletteEntries[0]), + m_originalPaletteEntries + ); + if (result != DD_OK) { + Error("SetEntries failed", result); + return FALSE; + } + } + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009e7f0 +int MxDirectDraw::FlipToGDISurface() +{ + + if (m_pDirectDraw) { + HRESULT result; + + result = m_pDirectDraw->FlipToGDISurface(); + if (result != DD_OK) { + Error("FlipToGDISurface failed", result); + } + return (result == DD_OK); + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x1009e830 +void MxDirectDraw::Error(const char* p_message, int p_error) +{ + // GLOBAL: LEGO1 0x10100c70 + static BOOL g_isInsideError = FALSE; + if (!g_isInsideError) { + g_isInsideError = TRUE; + Destroy(); + if (m_pErrorHandler) { + m_pErrorHandler(p_message, p_error, m_pErrorHandlerArg); + } + g_isInsideError = FALSE; + } +} + +// FUNCTION: LEGO1 0x1009e880 +const char* MxDirectDraw::ErrorToString(HRESULT p_error) +{ + switch (p_error) { + case DD_OK: + return "No error."; + case DDERR_ALREADYINITIALIZED: + return "This object is already initialized."; + case DDERR_BLTFASTCANTCLIP: + return "Return if a clipper object is attached to the source surface passed into a BltFast call."; + case DDERR_CANNOTATTACHSURFACE: + return "This surface can not be attached to the requested surface."; + case DDERR_CANNOTDETACHSURFACE: + return "This surface can not be detached from the requested surface."; + case DDERR_CANTCREATEDC: + return "Windows can not create any more DCs."; + case DDERR_CANTDUPLICATE: + return "Can't duplicate primary & 3D surfaces, or surfaces that are implicitly created."; + case DDERR_CLIPPERISUSINGHWND: + return "An attempt was made to set a cliplist for a clipper object that is already monitoring an hwnd."; + case DDERR_COLORKEYNOTSET: + return "No src color key specified for this operation."; + case DDERR_CURRENTLYNOTAVAIL: + return "Support is currently not available."; + case DDERR_DIRECTDRAWALREADYCREATED: + return "A DirectDraw object representing this driver has already been created for this process."; + case DDERR_EXCEPTION: + return "An exception was encountered while performing the requested operation."; + case DDERR_EXCLUSIVEMODEALREADYSET: + return "An attempt was made to set the cooperative level when it was already set to exclusive."; + case DDERR_GENERIC: + return "Generic failure."; + case DDERR_HEIGHTALIGN: + return "Height of rectangle provided is not a multiple of reqd alignment."; + case DDERR_HWNDALREADYSET: + return "The CooperativeLevel HWND has already been set. It can not be reset while the process has surfaces or " + "palettes created."; + case DDERR_HWNDSUBCLASSED: + return "HWND used by DirectDraw CooperativeLevel has been subclassed, this prevents DirectDraw from restoring " + "state."; + case DDERR_IMPLICITLYCREATED: + return "This surface can not be restored because it is an implicitly created surface."; + case DDERR_INCOMPATIBLEPRIMARY: + return "Unable to match primary surface creation request with existing primary surface."; + case DDERR_INVALIDCAPS: + return "One or more of the caps bits passed to the callback are incorrect."; + case DDERR_INVALIDCLIPLIST: + return "DirectDraw does not support the provided cliplist."; + case DDERR_INVALIDDIRECTDRAWGUID: + return "The GUID passed to DirectDrawCreate is not a valid DirectDraw driver identifier."; + case DDERR_INVALIDMODE: + return "DirectDraw does not support the requested mode."; + case DDERR_INVALIDOBJECT: + return "DirectDraw received a pointer that was an invalid DIRECTDRAW object."; + case DDERR_INVALIDPARAMS: + return "One or more of the parameters passed to the function are incorrect."; + case DDERR_INVALIDPIXELFORMAT: + return "The pixel format was invalid as specified."; + case DDERR_INVALIDPOSITION: + return "Returned when the position of the overlay on the destination is no longer legal for that " + "destination."; + case DDERR_INVALIDRECT: + return "Rectangle provided was invalid."; + case DDERR_LOCKEDSURFACES: + return "Operation could not be carried out because one or more surfaces are locked."; + case DDERR_NO3D: + return "There is no 3D present."; + case DDERR_NOALPHAHW: + return "Operation could not be carried out because there is no alpha accleration hardware present or " + "available."; + case DDERR_NOBLTHW: + return "No blitter hardware present."; + case DDERR_NOCLIPLIST: + return "No cliplist available."; + case DDERR_NOCLIPPERATTACHED: + return "No clipper object attached to surface object."; + case DDERR_NOCOLORCONVHW: + return "Operation could not be carried out because there is no color conversion hardware present or " + "available."; + case DDERR_NOCOLORKEY: + return "Surface doesn't currently have a color key"; + case DDERR_NOCOLORKEYHW: + return "Operation could not be carried out because there is no hardware support of the destination color " + "key."; + case DDERR_NOCOOPERATIVELEVELSET: + return "Create function called without DirectDraw object method SetCooperativeLevel being called."; + case DDERR_NODC: + return "No DC was ever created for this surface."; + case DDERR_NODDROPSHW: + return "No DirectDraw ROP hardware."; + case DDERR_NODIRECTDRAWHW: + return "A hardware-only DirectDraw object creation was attempted but the driver did not support any " + "hardware."; + case DDERR_NOEMULATION: + return "Software emulation not available."; + case DDERR_NOEXCLUSIVEMODE: + return "Operation requires the application to have exclusive mode but the application does not have exclusive " + "mode."; + case DDERR_NOFLIPHW: + return "Flipping visible surfaces is not supported."; + case DDERR_NOGDI: + return "There is no GDI present."; + case DDERR_NOHWND: + return "Clipper notification requires an HWND or no HWND has previously been set as the CooperativeLevel " + "HWND."; + case DDERR_NOMIRRORHW: + return "Operation could not be carried out because there is no hardware present or available."; + case DDERR_NOOVERLAYDEST: + return "Returned when GetOverlayPosition is called on an overlay that UpdateOverlay has never been called on " + "to establish a destination."; + case DDERR_NOOVERLAYHW: + return "Operation could not be carried out because there is no overlay hardware present or available."; + case DDERR_NOPALETTEATTACHED: + return "No palette object attached to this surface."; + case DDERR_NOPALETTEHW: + return "No hardware support for 16 or 256 color palettes."; + case DDERR_NORASTEROPHW: + return "Operation could not be carried out because there is no appropriate raster op hardware present or " + "available."; + case DDERR_NOROTATIONHW: + return "Operation could not be carried out because there is no rotation hardware present or available."; + case DDERR_NOSTRETCHHW: + return "Operation could not be carried out because there is no hardware support for stretching."; + case DDERR_NOT4BITCOLOR: + return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color " + "palette."; + case DDERR_NOT4BITCOLORINDEX: + return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color " + "index palette."; + case DDERR_NOT8BITCOLOR: + return "DirectDrawSurface is not in 8 bit color mode and the requested operation requires 8 bit color."; + case DDERR_NOTAOVERLAYSURFACE: + return "Returned when an overlay member is called for a non-overlay surface."; + case DDERR_NOTEXTUREHW: + return "Operation could not be carried out because there is no texture mapping hardware present or " + "available."; + case DDERR_NOTFLIPPABLE: + return "An attempt has been made to flip a surface that is not flippable."; + case DDERR_NOTFOUND: + return "Requested item was not found."; + case DDERR_NOTLOCKED: + return "Surface was not locked. An attempt to unlock a surface that was not locked at all, or by this " + "process, has been attempted."; + case DDERR_NOTPALETTIZED: + return "The surface being used is not a palette-based surface."; + case DDERR_NOVSYNCHW: + return "Operation could not be carried out because there is no hardware support for vertical blank " + "synchronized operations."; + case DDERR_NOZBUFFERHW: + return "Operation could not be carried out because there is no hardware support for zbuffer blitting."; + case DDERR_NOZOVERLAYHW: + return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support " + "z layering of overlays."; + case DDERR_OUTOFCAPS: + return "The hardware needed for the requested operation has already been allocated."; + case DDERR_OUTOFMEMORY: + return "DirectDraw does not have enough memory to perform the operation."; + case DDERR_OUTOFVIDEOMEMORY: + return "DirectDraw does not have enough memory to perform the operation."; + case DDERR_OVERLAYCANTCLIP: + return "The hardware does not support clipped overlays."; + case DDERR_OVERLAYCOLORKEYONLYONEACTIVE: + return "Can only have ony color key active at one time for overlays."; + case DDERR_OVERLAYNOTVISIBLE: + return "Returned when GetOverlayPosition is called on a hidden overlay."; + case DDERR_PALETTEBUSY: + return "Access to this palette is being refused because the palette is already locked by another thread."; + case DDERR_PRIMARYSURFACEALREADYEXISTS: + return "This process already has created a primary surface."; + case DDERR_REGIONTOOSMALL: + return "Region passed to Clipper::GetClipList is too small."; + case DDERR_SURFACEALREADYATTACHED: + return "This surface is already attached to the surface it is being attached to."; + case DDERR_SURFACEALREADYDEPENDENT: + return "This surface is already a dependency of the surface it is being made a dependency of."; + case DDERR_SURFACEBUSY: + return "Access to this surface is being refused because the surface is already locked by another thread."; + case DDERR_SURFACEISOBSCURED: + return "Access to surface refused because the surface is obscured."; + case DDERR_SURFACELOST: + return "Access to this surface is being refused because the surface memory is gone. The DirectDrawSurface " + "object representing this surface should have Restore called on it."; + case DDERR_SURFACENOTATTACHED: + return "The requested surface is not attached."; + case DDERR_TOOBIGHEIGHT: + return "Height requested by DirectDraw is too large."; + case DDERR_TOOBIGSIZE: + return "Size requested by DirectDraw is too large, but the individual height and width are OK."; + case DDERR_TOOBIGWIDTH: + return "Width requested by DirectDraw is too large."; + case DDERR_UNSUPPORTED: + return "Action not supported."; + case DDERR_UNSUPPORTEDFORMAT: + return "FOURCC format requested is unsupported by DirectDraw."; + case DDERR_UNSUPPORTEDMASK: + return "Bitmask in the pixel format requested is unsupported by DirectDraw."; + case DDERR_VERTICALBLANKINPROGRESS: + return "Vertical blank is in progress."; + case DDERR_WASSTILLDRAWING: + return "Informs DirectDraw that the previous Blt which is transfering information to or from this Surface is " + "incomplete."; + case DDERR_WRONGMODE: + return "This surface can not be restored because it was created in a different mode."; + case DDERR_XALIGN: + return "Rectangle provided was not horizontally aligned on required boundary."; + default: + return "Unrecognized error value."; + } +} + +// FUNCTION: LEGO1 0x1009efb0 +MxDirectDraw::DeviceModesInfo::DeviceModesInfo() +{ + memset(this, 0, sizeof(*this)); +} + +// FUNCTION: LEGO1 0x1009efd0 +MxDirectDraw::DeviceModesInfo::~DeviceModesInfo() +{ + if (m_guid != NULL) { + delete m_guid; + } + + if (m_modeArray != NULL) { + delete[] m_modeArray; + } +} diff --git a/LEGO1/mxdirectx/mxdirectdraw.h b/LEGO1/mxdirectx/mxdirectdraw.h new file mode 100644 index 00000000..61c92ae0 --- /dev/null +++ b/LEGO1/mxdirectx/mxdirectdraw.h @@ -0,0 +1,131 @@ +#ifndef MXDIRECTDRAW_H +#define MXDIRECTDRAW_H + +#include +#include + +// VTABLE: LEGO1 0x100db818 +// SIZE 0x880 +class MxDirectDraw { +public: + typedef void (*ErrorHandler)(const char*, HRESULT, void*); + + // SIZE 0x0c + struct Mode { + int operator==(const Mode& p_mode) const + { + return ((width == p_mode.width) && (height == p_mode.height) && (bitsPerPixel == p_mode.bitsPerPixel)); + } + + int width; // 0x00 + int height; // 0x04 + int bitsPerPixel; // 0x08 + }; + + // SIZE 0x17c + struct DeviceModesInfo { + DeviceModesInfo(); + ~DeviceModesInfo(); + + GUID* m_guid; // 0x00 + Mode* m_modeArray; // 0x04 + int m_count; // 0x08 + DDCAPS m_ddcaps; // 0x0c + void* m_unk0x178; // 0x178 + }; + + static int GetPrimaryBitDepth(); + + MxDirectDraw(); + virtual ~MxDirectDraw(); + + virtual BOOL Create( + HWND hWnd, + BOOL fullscreen_1, + BOOL surface_fullscreen, + BOOL onlySystemMemory, + int width, + int height, + int bpp, + const PALETTEENTRY* pPaletteEntries, + int paletteEntryCount + ); // vtable+0x04 + virtual void Destroy(); // vtable+0x08 + virtual void DestroyButNotDirectDraw(); // vtable+0x0c + + inline IDirectDraw* DirectDraw() { return m_pDirectDraw; } + inline IDirectDrawSurface* FrontBuffer() { return m_pFrontBuffer; } + inline IDirectDrawSurface* BackBuffer() { return m_pBackBuffer; } + inline IDirectDrawClipper* Clipper() { return m_pClipper; } + + BOOL IsFullScreen() { return m_bFullScreen; } + + BOOL IsSupportedMode(int width, int height, int bpp); + + int Pause(BOOL); + BOOL RestoreSurfaces(); + + BOOL TextToTextSurface1(const char* text); + BOOL TextToTextSurface2(const char* lpString); + + virtual const char* ErrorToString(HRESULT p_error); // vtable+0x10 + int FlipToGDISurface(); + +protected: + BOOL SetPaletteEntries(const PALETTEENTRY* pPaletteEntries, int paletteEntryCount, BOOL fullscreen); + BOOL CacheOriginalPaletteEntries(); + BOOL RestoreOriginalPaletteEntries(); + BOOL RestorePaletteEntries(); + + BOOL DDInit(BOOL fullscreen); + BOOL DDSetMode(int width, int height, int bpp); + BOOL DDCreateSurfaces(); + HRESULT CreateDDSurface(LPDDSURFACEDESC a2, LPDIRECTDRAWSURFACE* a3, IUnknown* a4); + BOOL GetDDSurfaceDesc(LPDDSURFACEDESC lpDDSurfDesc, LPDIRECTDRAWSURFACE lpDDSurf); + BOOL CreateZBuffer(DWORD memorytype, DWORD depth); + + BOOL CreateTextSurfaces(); + BOOL TextToTextSurface(const char* text, IDirectDrawSurface* pSurface, SIZE& textSizeOnSurface); + + void Error(const char* p_message, int p_error); + + BOOL RecreateDirectDraw(GUID** a2); + void FUN_1009e020(); + void FUN_1009d920(); + + // SYNTHETIC: LEGO1 0x1009d510 + // MxDirectDraw::`scalar deleting destructor' + +protected: + BOOL m_bOnlySoftRender; // 0x04 + BOOL m_bFlipSurfaces; // 0x08 + IDirectDraw* m_pDirectDraw; // 0x0c + IDirectDrawSurface* m_pFrontBuffer; // 0x10 + IDirectDrawSurface* m_pBackBuffer; // 0x14 + IDirectDrawSurface* m_pZBuffer; // 0x18 + IDirectDrawSurface* m_pText1Surface; // 0x1c + IDirectDrawSurface* m_pText2Surface; // 0x20 + IDirectDrawClipper* m_pClipper; // 0x24 + IDirectDrawPalette* m_pPalette; // 0x28 + PALETTEENTRY m_paletteEntries[256]; // 0x2c + PALETTEENTRY m_originalPaletteEntries[256]; // 0x42c + SIZE m_text1SizeOnSurface; // 0x82c + SIZE m_text2SizeOnSurface; // 0x834 + HWND m_hWndMain; // 0x83c + HFONT m_hFont; // 0x840 + BOOL m_bIgnoreWMSIZE; // 0x844 + BOOL m_bPrimaryPalettized; // 0x848 + BOOL m_bFullScreen; // 0x84c + void* m_unk0x850; // 0x850 + BOOL m_bOnlySystemMemory; // 0x854 + BOOL m_bIsOnPrimaryDevice; // 0x858 + ErrorHandler m_pErrorHandler; // 0x85c + ErrorHandler m_pFatalErrorHandler; // 0x860 + void* m_pErrorHandlerArg; // 0x864 + void* m_pFatalErrorHandlerArg; // 0x868 + int m_pauseCount; // 0x86c + DeviceModesInfo* m_pCurrentDeviceModesList; // 0x870 + Mode m_currentMode; // 0x874 +}; + +#endif // MXDIRECTDRAW_H diff --git a/LEGO1/mxdirectx/mxstopwatch.h b/LEGO1/mxdirectx/mxstopwatch.h new file mode 100644 index 00000000..fcd761a6 --- /dev/null +++ b/LEGO1/mxdirectx/mxstopwatch.h @@ -0,0 +1,206 @@ +#ifndef _MxStopWatch_h +#define _MxStopWatch_h + +#include "assert.h" + +#include // ULONG_MAX +#include +#include + +////////////////////////////////////////////////////////////////////////////// +// +// MxStopWatch +// +// NOTE: MxStopWatch measures elapsed (wall clock) time. +// + +#define HUGE_VAL_IMMEDIATE 1.7976931348623157e+308 + +// SIZE 0x18 +class MxStopWatch { +public: + MxStopWatch(); + ~MxStopWatch() {} + + void Start(); + void Stop(); + void Reset(); + + double ElapsedSeconds() const; + +protected: + unsigned long TicksPerSeconds() const; + +private: + LARGE_INTEGER m_startTick; // 0x00 + // ??? when we provide LARGE_INTEGER arithmetic, use a + // LARGE_INTEGER m_elapsedTicks rather than m_elapsedSeconds + double m_elapsedSeconds; // 0x0c + unsigned long m_ticksPerSeconds; // 0x14 +}; + +// FUNCTION: BETA10 0x100d8ba0 +inline MxStopWatch::MxStopWatch() +{ + Reset(); + m_ticksPerSeconds = TicksPerSeconds(); +} + +// FUNCTION: BETA10 0x100d8be0 +inline void MxStopWatch::Start() +{ + QueryPerformanceCounter(&m_startTick); +} + +// FUNCTION: BETA10 0x100d8f50 +inline void MxStopWatch::Stop() +{ + LARGE_INTEGER endTick; + BOOL result; + + result = QueryPerformanceCounter(&endTick); + assert(result); + + if (endTick.HighPart != m_startTick.HighPart) { + // LARGE_INTEGER arithmetic not yet provided + m_elapsedSeconds = HUGE_VAL_IMMEDIATE; + } + else { + m_elapsedSeconds += ((endTick.LowPart - m_startTick.LowPart) / (double) m_ticksPerSeconds); + } +} + +// FUNCTION: BETA10 0x100d8c10 +inline void MxStopWatch::Reset() +{ + m_startTick.LowPart = 0; + m_startTick.HighPart = 0; + m_elapsedSeconds = 0; +} + +// FUNCTION: BETA10 0x100d8c60 +inline unsigned long MxStopWatch::TicksPerSeconds() const +{ + LARGE_INTEGER ticksPerSeconds; + BOOL result; + + result = QueryPerformanceFrequency(&ticksPerSeconds); + assert(result); + + if (ticksPerSeconds.HighPart) { + // LARGE_INTEGER arithmetic not yet provided + + // timer is too fast (faster than 32bits/s, i.e. faster than 4GHz) + return ULONG_MAX; + } + else { + return ticksPerSeconds.LowPart; + } +} + +// FUNCTION: BETA10 0x100d9020 +inline double MxStopWatch::ElapsedSeconds() const +{ + return m_elapsedSeconds; +} + +// SYNTHETIC: LEGO1 0x100a6fc0 +// SYNTHETIC: BETA10 0x100d8e70 +// MxStopWatch::~MxStopWatch + +////////////////////////////////////////////////////////////////////////////// +// +// MxFrequencyMeter +// + +// SIZE 0x20 +class MxFrequencyMeter { +public: + MxFrequencyMeter(); + + void StartOperation(); + void EndOperation(); + double Frequency() const; + void Reset(); + + unsigned long OperationCount() const; + double ElapsedSeconds() const; + + void IncreaseOperationCount(unsigned long); + +private: + unsigned long m_operationCount; // 0x00 + MxStopWatch m_stopWatch; // 0x08 +}; + +////////////////////////////////////////////////////////////////////////////// +// +// MxFrequencyMeter implementation +// + +// FUNCTION: BETA10 0x1017dd80 +inline MxFrequencyMeter::MxFrequencyMeter() : m_operationCount(0) +{ +} + +// FUNCTION: BETA10 0x1017deb0 +inline void MxFrequencyMeter::StartOperation() +{ + m_stopWatch.Start(); +} + +// FUNCTION: BETA10 0x1017df10 +inline void MxFrequencyMeter::EndOperation() +{ + m_stopWatch.Stop(); + m_operationCount++; +} + +inline double MxFrequencyMeter::Frequency() const +{ + double elapsedSeconds = m_stopWatch.ElapsedSeconds(); + + if (elapsedSeconds > 0) { + return m_operationCount / elapsedSeconds; + } + else { + if (m_operationCount) { + // operations performed - no time elapsed + return HUGE_VAL; + } + else { + // no operations performed - no time elapsed + return 0; + } + } +} + +// FUNCTION: BETA10 0x1017dee0 +inline void MxFrequencyMeter::Reset() +{ + m_stopWatch.Reset(); + m_operationCount = 0; +} + +inline unsigned long MxFrequencyMeter::OperationCount() const +{ + return m_operationCount; +} + +// FUNCTION: BETA10 0x1017df40 +inline void MxFrequencyMeter::IncreaseOperationCount(unsigned long delta) +{ + m_operationCount += delta; +} + +// FUNCTION: BETA10 0x1017df60 +inline double MxFrequencyMeter::ElapsedSeconds() const +{ + return m_stopWatch.ElapsedSeconds(); +} + +// SYNTHETIC: LEGO1 0x100abd10 +// SYNTHETIC: BETA10 0x1017de40 +// MxFrequencyMeter::~MxFrequencyMeter + +#endif /* _MxStopWatch_h */ diff --git a/LEGO1/mxgeometry/mxgeometry3d.h b/LEGO1/mxgeometry/mxgeometry3d.h new file mode 100644 index 00000000..a214e25a --- /dev/null +++ b/LEGO1/mxgeometry/mxgeometry3d.h @@ -0,0 +1,171 @@ +#ifndef MXGEOMETRY3D_H +#define MXGEOMETRY3D_H + +#include "decomp.h" +#include "realtime/matrix.h" +#include "realtime/vector.h" + +// VTABLE: LEGO1 0x100d4488 +// SIZE 0x14 +class Mx3DPointFloat : public Vector3 { +public: + inline Mx3DPointFloat() : Vector3(m_elements) {} + inline Mx3DPointFloat(float p_x, float p_y, float p_z) : Vector3(m_elements) + { + m_elements[0] = p_x; + m_elements[1] = p_y; + m_elements[2] = p_z; + } + + // FUNCTION: LEGO1 0x100343a0 + inline Mx3DPointFloat(const Mx3DPointFloat& p_other) : Vector3(m_elements) { EqualsImpl(p_other.m_data); } + + inline Mx3DPointFloat(const Vector3& p_other) : Vector3(m_elements) { EqualsImpl(p_other.m_data); } + + // SYNTHETIC: LEGO1 0x1001d170 + // Mx3DPointFloat::Mx3DPointFloat + + // FUNCTION: LEGO1 0x10003c10 + virtual void operator=(const Vector3& p_impl) { EqualsImpl(p_impl.m_data); } // vtable+0x88 + + inline float GetX() { return m_data[0]; } + inline float GetY() { return m_data[1]; } + inline float GetZ() { return m_data[2]; } + + inline float& operator[](int idx) { return m_data[idx]; } + inline const float& operator[](int idx) const { return m_data[idx]; } + + // SYNTHETIC: LEGO1 0x10010c00 + // Mx3DPointFloat::operator= + +private: + float m_elements[3]; // 0x08 +}; + +// VTABLE: LEGO1 0x100d41e8 +// SIZE 0x18 +class Mx4DPointFloat : public Vector4 { +public: + // FUNCTION: LEGO1 0x10048290 + inline Mx4DPointFloat() : Vector4(m_elements) {} + + inline Mx4DPointFloat(float p_x, float p_y, float p_z, float p_a) : Vector4(m_elements) + { + m_elements[0] = p_x; + m_elements[1] = p_y; + m_elements[2] = p_z; + m_elements[3] = p_a; + } + + inline Mx4DPointFloat(const Mx4DPointFloat& p_other) : Vector4(m_elements) { EqualsImpl(p_other.m_data); } + + // FUNCTION: LEGO1 0x10003200 + virtual void operator=(const Vector4& p_impl) { EqualsImpl(p_impl.m_data); } // vtable+0x98 + + inline float& operator[](int idx) { return m_data[idx]; } + inline const float& operator[](int idx) const { return m_data[idx]; } + +private: + float m_elements[4]; // 0x08 +}; + +// SIZE 0x34 +class UnknownMx4DPointFloat { +public: + enum { + c_bit1 = 0x01, + c_bit2 = 0x02 + }; + + UnknownMx4DPointFloat() : m_unk0x30(0) {} + + inline void Unknown1(Vector4& p_v) + { + m_unk0x00 = p_v; + m_unk0x30 |= c_bit1; + } + + inline void Unknown2(Vector4& p_v) + { + m_unk0x18 = p_v; + m_unk0x30 |= c_bit2; + } + + inline int Unknown_100040a0(Matrix4& p_matrix, float p_f); + inline int FUN_100040a0(Vector4& p_v, float p_f); + +private: + Mx4DPointFloat m_unk0x00; // 0x00 + Mx4DPointFloat m_unk0x18; // 0x18 + undefined4 m_unk0x30; // 0x30 +}; + +int UnknownMx4DPointFloat::Unknown_100040a0(Matrix4& p_matrix, float p_f) +{ + float data[4]; + Vector4 v(data); + + if (FUN_100040a0(v, p_f) == 0) { + return p_matrix.FromQuaternion(v); + } + else { + return -1; + } +} + +// FUNCTION: LEGO1 0x100040a0 +inline int UnknownMx4DPointFloat::FUN_100040a0(Vector4& p_v, float p_f) +{ + undefined4 state = m_unk0x30; + + if (state == 1) { + p_v = m_unk0x00; + p_v[3] = (1.0 - p_f) * acos(p_v[3]) * 2.0; + return p_v.NormalizeQuaternion(); + } + else if (state == 2) { + p_v = m_unk0x18; + p_v[3] = p_f * acos(p_v[3]) * 2.0; + return p_v.NormalizeQuaternion(); + } + else if (state == 3) { + double d1 = p_v.Dot(&m_unk0x00, &m_unk0x18); + double d2; + + if (d1 + 1.0 > 0.00001) { + if (1.0 - d1 > 0.00001) { + double d = acos(d1); + sin(d); + d1 = sin((1 - p_f) * d) / sin(d); + d2 = sin(p_f * d) / sin(d); + } + else { + d1 = 1.0 - p_f; + d2 = p_f; + } + + for (int i = 0; i < 4; i++) { + p_v[i] = m_unk0x18[i] * d2 + m_unk0x00[i] * d1; + } + } + else { + p_v[0] = -m_unk0x00[1]; + p_v[1] = m_unk0x00[1]; + p_v[2] = -m_unk0x00[3]; + p_v[3] = m_unk0x00[2]; + d1 = sin((1.0 - p_f) * 1.570796326794895); + d2 = sin(p_f * 1.570796326794895); + + for (int i = 0; i < 3; i++) { + p_v[i] = m_unk0x00[i] * d1 + p_v[i] * d2; + } + } + + return 0; + } + else { + return -1; + } +} + +#endif // MXGEOMETRY3D_H diff --git a/LEGO1/mxgeometry/mxmatrix.h b/LEGO1/mxgeometry/mxmatrix.h new file mode 100644 index 00000000..f6d0cece --- /dev/null +++ b/LEGO1/mxgeometry/mxmatrix.h @@ -0,0 +1,33 @@ +#ifndef MXMATRIX_H +#define MXMATRIX_H + +#include "realtime/matrix.h" + +// VTABLE: LEGO1 0x100d4300 +// SIZE 0x48 +class MxMatrix : public Matrix4 { +public: + // FUNCTION: LEGO1 0x1006b120 + inline MxMatrix() : Matrix4(m_elements) {} + + // FUNCTION: LEGO1 0x10032770 + inline MxMatrix(const MxMatrix& p_matrix) : Matrix4(m_elements) { Equals(p_matrix); } + + inline MxMatrix(const Matrix4& p_matrix) : Matrix4(m_elements) { Equals(p_matrix); } + + float* operator[](int idx) { return m_data[idx]; } + const float* operator[](int idx) const { return m_data[idx]; } + + // FUNCTION: LEGO1 0x10002850 + void operator=(const Matrix4& p_matrix) override { Equals(p_matrix); } // vtable+0x28 + + // No idea why there's another equals. Maybe to some other type like the + // DirectX Retained Mode Matrix type which is also a float* alias? + // FUNCTION: LEGO1 0x10002860 + virtual void operator=(const MxMatrix& p_matrix) { Equals(p_matrix); } // vtable+0x48 + +private: + float m_elements[4][4]; // 0x08 +}; + +#endif // MXMATRIX_H diff --git a/LEGO1/mxstl/mxstl.h b/LEGO1/mxstl/mxstl.h new file mode 100644 index 00000000..f96dd005 --- /dev/null +++ b/LEGO1/mxstl/mxstl.h @@ -0,0 +1,222 @@ +// clang-format off + +#ifndef MXSTL_H +#define MXSTL_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef _MSC_VER +/* + * Currently, all MS C compilers for Win32 platforms default to 8 byte + * alignment. + */ +#pragma pack(push,8) +#endif // _MSC_VER + +template +class Deque : public deque<_TYPE, allocator<_TYPE> > +{ +public: + typedef Deque<_TYPE> _Myt; + typedef allocator<_TYPE> _A; + + explicit Deque(const _A& _Al = _A()) : deque<_TYPE, _A>(_Al) + {} + + explicit Deque(size_type _N, const _TYPE& _V = _TYPE()) : deque<_TYPE, _A>(_N, _V) + {} + + void swap(_Myt& _X) + { + deque<_TYPE, _A>::swap((deque<_TYPE, _A>&)_X); + } + + friend void swap(_Myt& _X, _Myt& _Y) + { + _X.swap(_Y); + } +}; + +template +class List : public list<_TYPE, allocator<_TYPE> > +{ +public: + typedef List<_TYPE> _Myt; + typedef allocator<_TYPE> _A; + + explicit List() : list<_TYPE, _A>() + {} + + explicit List(size_type _N, const _TYPE& _V = _TYPE()) : list<_TYPE, _A>(_N, _V) + {} + + void swap(_Myt& _X) + { + list<_TYPE, _A>::swap((list<_TYPE, _A>&)_X); + } + + friend void swap(_Myt& _X, _Myt& _Y) + { + _X.swap(_Y); + } +}; + +template +class Map : public map<_K, _TYPE, _Pr, allocator<_TYPE> > +{ +public: + typedef Map<_K, _TYPE, _Pr> _Myt; + typedef allocator<_TYPE> _A; + + explicit Map(const _Pr& _Pred = _Pr()) + : map<_K, _TYPE, _Pr, _A>(_Pred) + {} + + void swap(_Myt& _X) + { + map<_K, _TYPE, _Pr, _A>::swap((map<_K, _TYPE, _Pr, _A>&)_X); + } + + friend void swap(_Myt& _X, _Myt& _Y) + { + _X.swap(_Y); + } +}; + +template +class Multimap : public multimap<_K, _TYPE, _Pr, allocator<_TYPE> > +{ +public: + typedef Multimap<_K, _TYPE, _Pr> _Myt; + typedef allocator<_TYPE> _A; + + explicit Multimap(const _Pr& _Pred = _Pr()) : multimap<_K, _TYPE, _Pr, _A>(_Pred) + {} + + void swap(_Myt& _X) + { + multimap<_K, _TYPE, _Pr, _A>::swap((multimap<_K, _TYPE, _Pr, _A>&)_X); + } + + friend void swap(_Myt& _X, _Myt& _Y) + { + _X.swap(_Y); + } +}; + +template +class Set : public set<_K, _Pr, allocator<_K> > +{ +public: + typedef Set<_K, _Pr> _Myt; + typedef allocator<_K> _A; + + explicit Set(const _Pr& _Pred = _Pr()) : set<_K, _Pr, _A>(_Pred) + {} + + void swap(_Myt& _X) + { + set<_K, _Pr, _A>::swap((set<_K, _Pr, _A>&)_X); + } + + friend void swap(_Myt& _X, _Myt& _Y) + { + _X.swap(_Y); + } +}; + +template +class Multiset : public multiset<_K, _Pr, allocator<_K> > +{ +public: + typedef Multiset<_K, _Pr> _Myt; + typedef allocator<_K> _A; + + explicit Multiset(const _Pr& _Pred = _Pr()) + : multiset<_K, _Pr, _A>(_Pred) + {} + + void swap(_Myt& _X) + { + multiset<_K, _Pr, _A>::swap((multiset<_K, _Pr, _A>&)_X); + } + + friend void swap(_Myt& _X, _Myt& _Y) + { + _X.swap(_Y); + } +}; + +template +class Vector : public vector<_TYPE, allocator<_TYPE> > +{ +public: + typedef Vector<_TYPE> _Myt; + typedef allocator<_TYPE> _A; + + explicit Vector(const _A& _Al = _A()) : vector<_TYPE, _A>(_Al) + {} + + void swap(_Myt& _X) + { + vector<_TYPE, _A>::swap((vector<_TYPE, _A>&)_X); + } + + friend void swap(_Myt& _X, _Myt& _Y) + { + _X.swap(_Y); + } +}; + +template +class Priority_queue : public priority_queue<_C::value_type, _C, _Pr, _C::allocator_type> +{ +public: + typedef _C::value_type _TYPE; + typedef _C::allocator_type _A; + typedef _C::allocator_type allocator_type; + + explicit Priority_queue(const _Pr& _X = _Pr(), const _C::allocator_type& _Al = _C::allocator_type()) : priority_queue<_C::value_type, _C, _Pr, _C::allocator_type>(_X, _Al) + {} +}; + +template +class Queue : public queue<_C::value_type, _C, _C::allocator_type> +{}; + +template +class Stack : public stack<_C::value_type, _C, _C::allocator_type> +{}; + +#define deque Deque +#define list List +#define map Map +#define multimap Multimap +#define set Set +#define multiset Multiset +#define vector Vector +#define priority_queue Priority_queue +#define queue Queue +#define stack Stack + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +#endif // MXSTL_H + +// clang-format on diff --git a/LEGO1/mxstl/stlcompat.h b/LEGO1/mxstl/stlcompat.h new file mode 100644 index 00000000..c6f525bd --- /dev/null +++ b/LEGO1/mxstl/stlcompat.h @@ -0,0 +1,24 @@ +#ifndef STLCOMPAT_H +#define STLCOMPAT_H + +#include "compat.h" + +#if defined(_MSC_VER) && _MSC_VER <= MSVC420_VERSION +// Disable "nonstandard extension used : 'bool'" warning spam +#pragma warning(disable : 4237) +#include "mxstl.h" +#else +#include +#include +#include +#include +#include +#include +using std::list; +using std::map; +using std::pair; +using std::set; +using std::vector; +#endif + +#endif // STLCOMPAT_H diff --git a/LEGO1/omni/include/flic.h b/LEGO1/omni/include/flic.h new file mode 100644 index 00000000..21d114df --- /dev/null +++ b/LEGO1/omni/include/flic.h @@ -0,0 +1,54 @@ +#ifndef FLIC_H +#define FLIC_H + +#include "decomp.h" + +#include + +enum FLI_CHUNK_TYPE { + FLI_CHUNK_COLOR256 = 4, // 256-level color palette info + FLI_CHUNK_SS2 = 7, // Word-oriented delta compression + FLI_CHUNK_COLOR64 = 11, // 64-level color palette info + FLI_CHUNK_LC = 12, // Byte-oriented delta compression + FLI_CHUNK_BLACK = 13, // Entire frame is color index 0 + FLI_CHUNK_BRUN = 15, // Byte run length compression + FLI_CHUNK_COPY = 16, // No compression + FLI_CHUNK_PSTAMP = 18, // Postage stamp sized image + FLI_CHUNK_FRAME = 0xf1fa // Frame +}; + +#pragma pack(push, 1) +// A basic FLIC header structure from the "EGI" documentation. Source: https://www.compuphase.com/flic.htm#FLICHEADER +// This also goes over the FLIC structures: https://github.com/thinkbeforecoding/nomemalloc.handson/blob/master/flic.txt +typedef struct { + DWORD size; /* Size of the chunk, including subchunks */ // 0x00 + WORD type; // 0x04 +} FLIC_CHUNK; + +typedef struct : FLIC_CHUNK { + WORD frames; /* Number of frames in first segment */ // 0x06 + WORD width; /* FLIC width in pixels */ // 0x08 + WORD height; /* FLIC height in pixels */ // 0x0a + WORD depth; /* Bits per pixel (usually 8) */ // 0x0c + WORD flags; /* Set to zero or to three */ // 0x0e + DWORD speed; /* Delay between frames */ // 0x10 +} FLIC_HEADER; +#pragma pack(pop) + +typedef struct : FLIC_CHUNK { + WORD chunks; /* Number of subchunks */ // 0x06 + WORD delay; /* Delay in milliseconds */ // 0x08 + WORD reserved; /* Always zero */ // 0x0a + WORD width; /* Frame width override (if non-zero) */ // 0x0c + WORD height; /* Frame height override (if non-zero) */ // 0x0e +} FLIC_FRAME; + +void DecodeFLCFrame( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + FLIC_HEADER* p_flcHeader, + FLIC_FRAME* p_flcFrame, + BYTE* p_decodedColorMap +); + +#endif // FLIC_H diff --git a/LEGO1/omni/include/mxactionnotificationparam.h b/LEGO1/omni/include/mxactionnotificationparam.h new file mode 100644 index 00000000..3b4d83c2 --- /dev/null +++ b/LEGO1/omni/include/mxactionnotificationparam.h @@ -0,0 +1,142 @@ +#ifndef MXACTIONNOTIFICATIONPARAM_H +#define MXACTIONNOTIFICATIONPARAM_H + +#include "mxdsaction.h" +#include "mxnotificationparam.h" + +class MxPresenter; + +// VTABLE: LEGO1 0x100d8350 +// SIZE 0x14 +class MxActionNotificationParam : public MxNotificationParam { +public: + inline MxActionNotificationParam( + NotificationId p_type, + MxCore* p_sender, + MxDSAction* p_action, + MxBool p_reallocAction + ) + : MxNotificationParam(p_type, p_sender) + { + MxDSAction* oldAction = p_action; + this->m_realloc = p_reallocAction; + + if (p_reallocAction) { + this->m_action = new MxDSAction(); + } + else { + this->m_action = oldAction; + return; + } + + this->m_action->SetAtomId(oldAction->GetAtomId()); + this->m_action->SetObjectId(oldAction->GetObjectId()); + this->m_action->SetUnknown24(oldAction->GetUnknown24()); + } + + // FUNCTION: LEGO1 0x10051050 + inline ~MxActionNotificationParam() override + { + if (!this->m_realloc) { + return; + } + + if (this->m_action) { + delete this->m_action; + } + } + + // FUNCTION: LEGO1 0x100510c0 + MxNotificationParam* Clone() const override + { + return new MxActionNotificationParam(this->m_type, this->m_sender, this->m_action, this->m_realloc); + } // vtable+0x04 + + inline MxDSAction* GetAction() { return m_action; } + +protected: + MxDSAction* m_action; // 0x0c + MxBool m_realloc; // 0x10 +}; + +// VTABLE: LEGO1 0x100dc210 +// SIZE 0x14 +class MxStartActionNotificationParam : public MxActionNotificationParam { +public: + inline MxStartActionNotificationParam( + NotificationId p_type, + MxCore* p_sender, + MxDSAction* p_action, + MxBool p_reallocAction + ) + : MxActionNotificationParam(p_type, p_sender, p_action, p_reallocAction) + { + } + + MxNotificationParam* Clone() const override; // vtable+0x04 +}; + +// VTABLE: LEGO1 0x100d8358 +// SIZE 0x14 +class MxEndActionNotificationParam : public MxActionNotificationParam { +public: + inline MxEndActionNotificationParam( + NotificationId p_type, + MxCore* p_sender, + MxDSAction* p_action, + MxBool p_reallocAction + ) + : MxActionNotificationParam(p_type, p_sender, p_action, p_reallocAction) + { + } + + // FUNCTION: LEGO1 0x10051270 + MxNotificationParam* Clone() const override + { + return new MxEndActionNotificationParam( + c_notificationEndAction, + this->m_sender, + this->m_action, + this->m_realloc + ); + } // vtable+0x04 +}; + +// VTABLE: LEGO1 0x100dc208 +// SIZE 0x18 +class MxType4NotificationParam : public MxActionNotificationParam { +public: + inline MxType4NotificationParam(MxCore* p_sender, MxDSAction* p_action, MxPresenter* p_unk0x14) + : MxActionNotificationParam(c_notificationType4, p_sender, p_action, FALSE) + { + m_unk0x14 = p_unk0x14; + } + + MxNotificationParam* Clone() const override; // vtable+0x04 + +private: + MxPresenter* m_unk0x14; // 0x14 +}; + +// SYNTHETIC: LEGO1 0x100511e0 +// MxActionNotificationParam::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100513a0 +// MxEndActionNotificationParam::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x10051410 +// MxEndActionNotificationParam::~MxEndActionNotificationParam + +// SYNTHETIC: LEGO1 0x100b0430 +// MxStartActionNotificationParam::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100b04a0 +// MxStartActionNotificationParam::~MxStartActionNotificationParam + +// SYNTHETIC: LEGO1 0x100b05c0 +// MxType4NotificationParam::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100b0630 +// MxType4NotificationParam::~MxType4NotificationParam + +#endif diff --git a/LEGO1/omni/include/mxatom.h b/LEGO1/omni/include/mxatom.h new file mode 100644 index 00000000..bae01cb3 --- /dev/null +++ b/LEGO1/omni/include/mxatom.h @@ -0,0 +1,221 @@ +#ifndef MXATOM_H +#define MXATOM_H + +#include "mxstl/stlcompat.h" +#include "mxstring.h" +#include "mxtypes.h" + +// Counts the number of existing MxAtomId objects based +// on the matching char* string. A seems fit for purpose here: +// We have an MxString as a key and MxU16 as the value. +// And yet a is the best match. The malloc in MxOmni::Create +// for the _Nil node asks for more bytes than a regular node if a +// is used, but all nodes are 20 bytes wide with a . +// Also: the increment/decrement methods suggest a custom type was used +// for the combined key_value_pair, which doesn't seem possible with . + +// SIZE 0x14 +class MxAtom { +public: + // always inlined + // FUNCTION: BETA10 0x10123720 + MxAtom(const char* p_str) + { + m_key = p_str; + m_value = 0; + } + + void Inc(); + void Dec(); + + // FUNCTION: BETA10 0x101236d0 + inline MxString& GetKey() { return m_key; } + + // SYNTHETIC: BETA10 0x10124a50 + // MxAtom::`scalar deleting destructor' + +private: + MxString m_key; // 0x00 + MxU16 m_value; // 0x10 +}; + +struct MxAtomCompare { + // FUNCTION: LEGO1 0x100ad120 + // FUNCTION: BETA10 0x10123980 + int operator()(MxAtom* const& p_val0, MxAtom* const& p_val1) const + { + return strcmp(p_val0->GetKey().GetData(), p_val1->GetKey().GetData()) > 0; + } +}; + +class MxAtomSet : public set {}; + +enum LookupMode { + e_exact = 0, + e_lowerCase, + e_upperCase, + e_lowerCase2, +}; + +// SIZE 0x04 +class MxAtomId { +public: + MxAtomId(const char*, LookupMode); + ~MxAtomId(); + + MxAtomId& operator=(const MxAtomId& p_atomId); + + // FUNCTION: BETA10 0x100178d0 + inline MxBool operator==(const MxAtomId& p_atomId) const { return this->m_internal == p_atomId.m_internal; } + +#ifdef COMPAT_MODE + // Required for modern compilers. + // MSVC 4.20 uses a synthetic function from INCLUDE/UTILITY that inverts operator== + inline MxBool operator!=(const MxAtomId& p_atomId) const { return this->m_internal != p_atomId.m_internal; } +#endif + + // FUNCTION: BETA10 0x10025d40 + MxAtomId() { this->m_internal = 0; } + + void Clear(); + + // FUNCTION: BETA10 0x100735e0 + const char* GetInternal() const { return m_internal; } + +private: + // FUNCTION: BETA10 0x101236f0 + MxAtomId& operator=(const MxString& p_key) + { + m_internal = p_key.GetData(); + return *this; + } + + MxAtom* GetAtom(const char*, LookupMode); + void Destroy(); + + const char* m_internal; // 0x00 +}; + +// SYNTHETIC: BETA10 0x1002b520 +// ??9@YAHABVMxAtomId@@0@Z +// aka MxAtomId::operator!= + +// SYNTHETIC: LEGO1 0x100ad170 +// MxAtom::~MxAtom + +// clang-format off +// TEMPLATE: LEGO1 0x100ad480 +// _Tree >::_Kfn,MxAtomCompare,allocator >::iterator::_Dec +// clang-format on + +// clang-format off +// TEMPLATE: LEGO1 0x100ad780 +// _Tree >::_Kfn,MxAtomCompare,allocator >::_Lbound +// clang-format on + +// clang-format off +// TEMPLATE: LEGO1 0x100ad4d0 +// _Tree >::_Kfn,MxAtomCompare,allocator >::_Insert +// clang-format on + +// clang-format off +// TEMPLATE: BETA10 0x101237a0 +// _Tree >::_Kfn,MxAtomCompare,allocator >::const_iterator::operator* +// clang-format on + +// clang-format off +// TEMPLATE: LEGO1 0x100af6d0 +// TEMPLATE: BETA10 0x10131170 +// _Tree >::_Kfn,MxAtomCompare,allocator >::~_Tree >::_Kfn,MxAtomCompare,allocator > +// clang-format on + +// clang-format off +// TEMPLATE: LEGO1 0x100af7a0 +// _Tree >::_Kfn,MxAtomCompare,allocator >::iterator::_Inc +// clang-format on + +// clang-format off +// TEMPLATE: LEGO1 0x100af7e0 +// TEMPLATE: BETA10 0x10131210 +// _Tree >::_Kfn,MxAtomCompare,allocator >::erase +// clang-format on + +// TEMPLATE: BETA10 0x10131460 +// _Tree >::_Kfn,MxAtomCompare,allocator +// >::size + +// clang-format off +// TEMPLATE: LEGO1 0x100afc40 +// _Tree >::_Kfn,MxAtomCompare,allocator >::_Erase +// clang-format on + +// clang-format off +// TEMPLATE: LEGO1 0x100afc80 +// TEMPLATE: BETA10 0x10132080 +// set >::~set > +// clang-format on + +// TEMPLATE: LEGO1 0x100afe40 +// TEMPLATE: BETA10 0x101320e0 +// Set::~Set + +// TEMPLATE: BETA10 0x10132140 +// set >::begin + +// clang-format off +// GLOBAL: LEGO1 0x101013f0 +// GLOBAL: BETA10 0x10201264 +// _Tree >::_Kfn,MxAtomCompare,allocator >::_Nil +// clang-format on + +// TEMPLATE: BETA10 0x10132170 +// _Tree >::_Kfn,MxAtomCompare,allocator +// >::begin + +// TEMPLATE: BETA10 0x101321d0 +// set >::size + +// TEMPLATE: BETA10 0x101321f0 +// set >::erase + +// TEMPLATE: BETA10 0x101237f0 +// set >::end + +// TEMPLATE: BETA10 0x101238b0 +// set >::find + +// clang-format off +// TEMPLATE: BETA10 0x101238e0 +// _Tree >::_Kfn,MxAtomCompare,allocator >::find +// clang-format on + +// SYNTHETIC: BETA10 0x10123bf0 +// MxAtom::~MxAtom + +// TEMPLATE: BETA10 0x10123c50 +// set >::insert + +// SYNTHETIC: BETA10 0x10130fc0 +// MxAtomSet::MxAtomSet + +// TEMPLATE: BETA10 0x10131030 +// Set::Set + +// clang-format off +// TEMPLATE: BETA10 0x101310a0 +// set >::set > + +// TEMPLATE: BETA10 0x10131120 +// _Tree >::_Kfn,MxAtomCompare,allocator >::_Tree >::_Kfn,MxAtomCompare,allocator > + +// TEMPLATE: BETA10 0x10131f30 +// _Tree >::_Kfn,MxAtomCompare,allocator >::_Init +// clang-format on + +// SYNTHETIC: BETA10 0x101322a0 +// MxAtomSet::`scalar deleting destructor' + +// SYNTHETIC: BETA10 0x101322e0 +// MxAtomSet::~MxAtomSet + +#endif // MXATOM_H diff --git a/LEGO1/omni/include/mxaudiomanager.h b/LEGO1/omni/include/mxaudiomanager.h new file mode 100644 index 00000000..020bda54 --- /dev/null +++ b/LEGO1/omni/include/mxaudiomanager.h @@ -0,0 +1,36 @@ +#ifndef MXAUDIOMANAGER_H +#define MXAUDIOMANAGER_H + +#include "decomp.h" +#include "mxmediamanager.h" + +// VTABLE: LEGO1 0x100dc6e0 +// SIZE 0x30 +class MxAudioManager : public MxMediaManager { +public: + MxAudioManager(); + ~MxAudioManager() override; + + MxResult InitPresenters() override; // vtable+14 + void Destroy() override; // vtable+18 + + // FUNCTION: LEGO1 0x10029910 + virtual MxS32 GetVolume() { return this->m_volume; } // vtable+28 + + virtual void SetVolume(MxS32 p_volume); // vtable+2c + + // SYNTHETIC: LEGO1 0x100b8d70 + // MxAudioManager::`scalar deleting destructor' + +private: + void Destroy(MxBool p_fromDestructor); + + static MxS32 g_count; + +protected: + void Init(); + + MxS32 m_volume; // 0x2c +}; + +#endif // MXAUDIOMANAGER_H diff --git a/LEGO1/omni/include/mxaudiopresenter.h b/LEGO1/omni/include/mxaudiopresenter.h new file mode 100644 index 00000000..873871ec --- /dev/null +++ b/LEGO1/omni/include/mxaudiopresenter.h @@ -0,0 +1,42 @@ +#ifndef MXAUDIOPRESENTER_H +#define MXAUDIOPRESENTER_H + +#include "decomp.h" +#include "mxmediapresenter.h" + +// VTABLE: LEGO1 0x100d4c70 +// SIZE 0x54 +class MxAudioPresenter : public MxMediaPresenter { +public: + MxAudioPresenter() { m_volume = 100; } + + // FUNCTION: LEGO1 0x1000d280 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f078c + return "MxAudioPresenter"; + } + + // FUNCTION: LEGO1 0x1000d290 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxAudioPresenter::ClassName()) || MxMediaPresenter::IsA(p_name); + } + + // FUNCTION: LEGO1 0x1000d260 + virtual MxS32 GetVolume() { return m_volume; } // vtable+0x5c + + // FUNCTION: LEGO1 0x1000d270 + virtual void SetVolume(MxS32 p_volume) { m_volume = p_volume; } // vtable+0x60 + +protected: + MxS32 m_volume; +}; + +// SYNTHETIC: LEGO1 0x1000d370 +// MxAudioPresenter::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1000d3e0 +// MxAudioPresenter::~MxAudioPresenter + +#endif // MXAUDIOPRESENTER_H diff --git a/LEGO1/omni/include/mxautolock.h b/LEGO1/omni/include/mxautolock.h new file mode 100644 index 00000000..677804e7 --- /dev/null +++ b/LEGO1/omni/include/mxautolock.h @@ -0,0 +1,17 @@ +#ifndef MXAUTOLOCK_H +#define MXAUTOLOCK_H + +class MxCriticalSection; + +#define AUTOLOCK(CS) MxAutoLock lock(&CS) + +class MxAutoLock { +public: + MxAutoLock(MxCriticalSection* p_criticalSection); + ~MxAutoLock(); + +private: + MxCriticalSection* m_criticalSection; +}; + +#endif // MXAUTOLOCK_H diff --git a/LEGO1/omni/include/mxbitmap.h b/LEGO1/omni/include/mxbitmap.h new file mode 100644 index 00000000..a11853e4 --- /dev/null +++ b/LEGO1/omni/include/mxbitmap.h @@ -0,0 +1,154 @@ +#ifndef MXBITMAP_H +#define MXBITMAP_H + +#include "mxcore.h" +#include "mxtypes.h" + +#include +#include + +class MxPalette; + +// The stock BITMAPINFO struct from wingdi.h only makes room for one color +// in the palette. It seems like the expectation (if you use the struct) +// is to malloc as much as you actually need, and then index into the array +// anyway even though its stated size is [1]. +// https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-bitmapinfo +// In our case, the size 0x428 is used frequently, which matches +// a 40-byte header plus 256 colors, so just use that as our template. + +// SIZE 0x428 +struct MxBITMAPINFO { + BITMAPINFOHEADER m_bmiHeader; + RGBQUAD m_bmiColors[256]; + + static MxU32 Size() { return sizeof(MxBITMAPINFO); } +}; + +// Non-standard value for biCompression in the BITMAPINFOHEADER struct. +// By default, uncompressed bitmaps (BI_RGB) are stored in bottom-up order. +// You can specify that the bitmap has top-down order instead by providing +// a negative number for biHeight. It could be that Mindscape decided on a +// belt & suspenders approach here. +#define BI_RGB_TOPDOWN 0x10 + +// SIZE 0x20 +// VTABLE: LEGO1 0x100dc7b0 +class MxBitmap : public MxCore { +public: + MxBitmap(); + ~MxBitmap() override; // vtable+00 + + virtual MxResult ImportBitmap(MxBitmap* p_bitmap); // vtable+14 + virtual MxResult ImportBitmapInfo(MxBITMAPINFO* p_info); // vtable+18 + virtual MxResult SetSize(MxS32 p_width, MxS32 p_height, MxPalette* p_palette, MxBool); // vtable+1c + virtual MxResult LoadFile(HANDLE p_handle); // vtable+20 + virtual MxLong Read(const char* p_filename); // vtable+24 + + // FUNCTION: LEGO1 0x1004e0d0 + virtual int VTable0x28(int) { return -1; } // vtable+28 + + virtual void BitBlt( + MxBitmap* p_src, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height + ); // vtable+2c + virtual void BitBltTransparent( + MxBitmap* p_src, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height + ); // vtable+30 + virtual MxPalette* CreatePalette(); // vtable+34 + virtual void ImportPalette(MxPalette* p_palette); // vtable+38 + virtual MxResult SetBitDepth(MxBool); // vtable+3c + virtual MxResult StretchBits( + HDC p_hdc, + MxS32 p_xSrc, + MxS32 p_ySrc, + MxS32 p_xDest, + MxS32 p_yDest, + MxS32 p_destWidth, + MxS32 p_destHeight + ); // vtable+40 + + // Bit mask trick to round up to the nearest multiple of four. + // Pixel data may be stored with padding. + // https://learn.microsoft.com/en-us/windows/win32/medfound/image-stride + inline MxLong AlignToFourByte(MxLong p_value) const { return (p_value + 3) & -4; } + + // Same as the one from legoutils.h, but flipped the other way + // TODO: While it's not outside the realm of possibility that they + // reimplemented Abs for only this file, that seems odd, right? + inline MxLong AbsFlipped(MxLong p_value) const { return p_value > 0 ? p_value : -p_value; } + + inline BITMAPINFOHEADER* GetBmiHeader() const { return m_bmiHeader; } + inline MxLong GetBmiWidth() const { return m_bmiHeader->biWidth; } + inline MxLong GetBmiStride() const { return ((m_bmiHeader->biWidth + 3) & -4); } + inline MxLong GetBmiHeight() const { return m_bmiHeader->biHeight; } + inline MxLong GetBmiHeightAbs() const { return AbsFlipped(m_bmiHeader->biHeight); } + inline MxU8* GetImage() const { return m_data; } + inline MxBITMAPINFO* GetBitmapInfo() const { return m_info; } + inline MxLong GetDataSize() const + { + MxLong absHeight = GetBmiHeightAbs(); + MxLong alignedWidth = AlignToFourByte(m_bmiHeader->biWidth); + return alignedWidth * absHeight; + } + inline MxLong GetAdjustedStride() + { + if (m_bmiHeader->biCompression == BI_RGB_TOPDOWN || m_bmiHeader->biHeight < 0) { + return GetBmiStride(); + } + else { + return -GetBmiStride(); + } + } + + inline MxLong GetLine(MxS32 p_top) + { + MxS32 height; + if (m_bmiHeader->biCompression == BI_RGB_TOPDOWN || m_bmiHeader->biHeight < 0) { + height = p_top; + } + else { + height = GetBmiHeightAbs() - p_top - 1; + } + return GetBmiStride() * height; + } + + inline MxU8* GetStart(MxS32 p_left, MxS32 p_top) + { + if (m_bmiHeader->biCompression == BI_RGB) { + return GetLine(p_top) + m_data + p_left; + } + else if (m_bmiHeader->biCompression == BI_RGB_TOPDOWN) { + return m_data; + } + else { + return GetLine(0) + m_data; + } + } + + // SYNTHETIC: LEGO1 0x100bc9f0 + // MxBitmap::`scalar deleting destructor' + +private: + MxResult ImportColorsToPalette(RGBQUAD*, MxPalette*); + + MxBITMAPINFO* m_info; // 0x08 + BITMAPINFOHEADER* m_bmiHeader; // 0x0c + RGBQUAD* m_paletteData; // 0x10 + MxU8* m_data; // 0x14 + MxBool m_isHighColor; // 0x18 + MxPalette* m_palette; // 0x1c +}; + +#endif // MXBITMAP_H diff --git a/LEGO1/omni/include/mxbitset.h b/LEGO1/omni/include/mxbitset.h new file mode 100644 index 00000000..415470d8 --- /dev/null +++ b/LEGO1/omni/include/mxbitset.h @@ -0,0 +1,95 @@ +#ifndef MXBITSET_H +#define MXBITSET_H + +#pragma warning(disable : 4237) + +#include "mxtypes.h" + +#include +#include // CHAR_BIT + +template +class MxBitset { +public: + MxBitset() { Tidy(); } + + // SIZE 0x08 + class Reference { + friend class MxBitset; + + public: + Reference& Flip() + { + m_bitset->Flip(m_offset); + return (*this); + } + bool operator~() const { return (!m_bitset->Test(m_offset)); } + operator bool() const { return (m_bitset->Test(m_offset)); } + + private: + Reference(MxBitset& p_bitset, size_t p_offset) : m_bitset(&p_bitset), m_offset(p_offset) {} + MxBitset* m_bitset; // 0x00 + size_t m_offset; // 0x04 + }; + + Reference operator[](size_t p_bit) { return (Reference(*this, p_bit)); } + + MxBitset& Flip(size_t p_bit) + { + if (N <= p_bit) { + Xran(); + } + m_blocks[p_bit / e_bitsPerBlock] ^= 1 << p_bit % e_bitsPerBlock; + return (*this); + } + + size_t Count() + { + // debug only, intentionally unimplemented + return 0; + } + + bool Test(MxU32 p_bit) + { + if (p_bit >= N) { + Xran(); + } + + return (m_blocks[p_bit / e_bitsPerBlock] & (1 << p_bit % e_bitsPerBlock)) != 0; + } + + MxU32 Size() const { return N; } + +private: + void Tidy(MxU32 p_value = 0) + { + for (MxS32 i = e_blocksRequired; i >= 0; --i) { + m_blocks[i] = p_value; + } + + // No need to trim if all bits were zeroed out + if (p_value != 0) { + Trim(); + } + } + + // Apply bit mask to most significant block + void Trim() + { + if (N % e_bitsPerBlock != 0) { + m_blocks[e_blocksRequired] &= ((1 << (N % e_bitsPerBlock)) - 1); + } + } + + void Xran() { assert("invalid MxBitset position" == NULL); } + + // Not a real enum. This is how STL BITSET defines these constants. + enum { + e_bitsPerBlock = CHAR_BIT * sizeof(MxU32), + e_blocksRequired = N == 0 ? 0 : (N - 1) / e_bitsPerBlock + }; + + MxU32 m_blocks[e_blocksRequired + 1]; // 0x00 +}; + +#endif // MXBITSET_H diff --git a/LEGO1/omni/include/mxcollection.h b/LEGO1/omni/include/mxcollection.h new file mode 100644 index 00000000..0c21438c --- /dev/null +++ b/LEGO1/omni/include/mxcollection.h @@ -0,0 +1,27 @@ +#ifndef MXCOLLECTION_H +#define MXCOLLECTION_H + +#include "mxcore.h" + +template +class MxCollection : public MxCore { +public: + MxCollection() + { + m_count = 0; + SetDestroy(Destroy); + } + + static void Destroy(T) {} + + void SetDestroy(void (*p_customDestructor)(T)) { this->m_customDestructor = p_customDestructor; } + + ~MxCollection() override {} + virtual MxS8 Compare(T, T) { return 0; } + +protected: + MxU32 m_count; // 0x08 + void (*m_customDestructor)(T); // 0x0c +}; + +#endif // MXCOLLECTION_H diff --git a/LEGO1/omni/include/mxcompositepresenter.h b/LEGO1/omni/include/mxcompositepresenter.h new file mode 100644 index 00000000..977c1325 --- /dev/null +++ b/LEGO1/omni/include/mxcompositepresenter.h @@ -0,0 +1,76 @@ +#ifndef MXCOMPOSITEPRESENTER_H +#define MXCOMPOSITEPRESENTER_H + +#include "mxpresenter.h" +#include "mxstl/stlcompat.h" + +class MxEndActionNotificationParam; +class MxNotificationParam; + +class MxCompositePresenterList : public list {}; + +// VTABLE: LEGO1 0x100dc618 +// SIZE 0x4c +class MxCompositePresenter : public MxPresenter { +public: + MxCompositePresenter(); + ~MxCompositePresenter() override; // vtable+0x00 + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x100b6210 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0774 + return "MxCompositePresenter"; + } + + // FUNCTION: LEGO1 0x100b6220 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxCompositePresenter::ClassName()) || MxPresenter::IsA(p_name); + } + + MxResult StartAction(MxStreamController* p_controller, MxDSAction* p_action) override; // vtable+0x3c + void EndAction() override; // vtable+0x40 + void SetTickleState(TickleState p_tickleState) override; // vtable+0x44 + MxBool HasTickleStatePassed(TickleState p_tickleState) override; // vtable+0x48 + void Enable(MxBool p_enable) override; // vtable+0x54 + virtual void VTable0x58(MxEndActionNotificationParam& p_param); // vtable+0x58 + virtual void VTable0x5c(MxNotificationParam& p_param); // vtable+0x5c + virtual void VTable0x60(MxPresenter* p_presenter); // vtable+0x60 + + // FUNCTION: LEGO1 0x1000caf0 + virtual MxBool VTable0x64(undefined4 p_undefined) + { + if (m_compositePresenter) { + return m_compositePresenter->VTable0x64(p_undefined); + } + return TRUE; + } // vtable+0x64 + + inline MxCompositePresenterList* GetList() { return &m_list; } + +protected: + MxCompositePresenterList m_list; // 0x40 +}; + +// TEMPLATE: LEGO1 0x1004ae90 +// list >::_Buynode + +// TEMPLATE: LEGO1 0x100b61a0 +// list >::~list > + +// SYNTHETIC: LEGO1 0x100b62d0 +// MxCompositePresenter::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x100b62f0 +// MxCompositePresenterList::~MxCompositePresenterList + +// TEMPLATE: LEGO1 0x100b6340 +// List::~List + +// TEMPLATE: LEGO1 0x100b6cd0 +// MxList::DeleteEntry + +#endif // MXCOMPOSITEPRESENTER_H diff --git a/LEGO1/omni/include/mxcore.h b/LEGO1/omni/include/mxcore.h new file mode 100644 index 00000000..badecfa7 --- /dev/null +++ b/LEGO1/omni/include/mxcore.h @@ -0,0 +1,51 @@ +#ifndef MXCORE_H +#define MXCORE_H + +#include "compat.h" +#include "mxtypes.h" + +#include + +class MxParam; + +// VTABLE: LEGO1 0x100dc0f8 +// VTABLE: BETA10 0x101c1bc8 +// SIZE 0x08 +class MxCore { +public: + MxCore(); + virtual ~MxCore(); // vtable+00 + virtual MxLong Notify(MxParam& p_param); // vtable+04 + + // FUNCTION: LEGO1 0x10001f70 + // FUNCTION: BETA10 0x1000f380 + virtual MxResult Tickle() { return SUCCESS; } // vtable+08 + + // FUNCTION: LEGO1 0x100144c0 + // FUNCTION: BETA10 0x100126d0 + inline virtual const char* ClassName() const // vtable+0c + { + // STRING: LEGO1 0x100f007c + return "MxCore"; + } + + // FUNCTION: LEGO1 0x100140d0 + // FUNCTION: BETA10 0x10012680 + inline virtual MxBool IsA(const char* p_name) const // vtable+10 + { + return !strcmp(p_name, MxCore::ClassName()); + } + + inline MxU32 GetId() { return m_id; } + + // SYNTHETIC: LEGO1 0x100ae1c0 + // SYNTHETIC: BETA10 0x1012c0d0 + // MxCore::`scalar deleting destructor' + +private: + static MxU32 g_nextCoreId; + + MxU32 m_id; // 0x04 +}; + +#endif // MXCORE_H diff --git a/LEGO1/omni/include/mxcriticalsection.h b/LEGO1/omni/include/mxcriticalsection.h new file mode 100644 index 00000000..011ac680 --- /dev/null +++ b/LEGO1/omni/include/mxcriticalsection.h @@ -0,0 +1,20 @@ +#ifndef MXCRITICALSECTION_H +#define MXCRITICALSECTION_H + +#include + +// SIZE 0x1c +class MxCriticalSection { +public: + MxCriticalSection(); + ~MxCriticalSection(); + static void SetDoMutex(); + void Enter(); + void Leave(); + +private: + CRITICAL_SECTION m_criticalSection; // 0x00 + HANDLE m_mutex; // 0x18 +}; + +#endif // MXCRITICALSECTION_H diff --git a/LEGO1/omni/include/mxdiskstreamcontroller.h b/LEGO1/omni/include/mxdiskstreamcontroller.h new file mode 100644 index 00000000..b7312833 --- /dev/null +++ b/LEGO1/omni/include/mxdiskstreamcontroller.h @@ -0,0 +1,95 @@ +#ifndef MXDISKSTREAMCONTROLLER_H +#define MXDISKSTREAMCONTROLLER_H + +#include "decomp.h" +#include "mxdsbuffer.h" +#include "mxstl/stlcompat.h" +#include "mxstreamcontroller.h" +#include "mxtypes.h" + +#include + +class MxDSStreamingAction; + +// VTABLE: LEGO1 0x100dccb8 +// SIZE 0xc8 +class MxDiskStreamController : public MxStreamController { +public: + MxDiskStreamController(); + ~MxDiskStreamController() override; + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x100c7360 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10102144 + return "MxDiskStreamController"; + } + + // FUNCTION: LEGO1 0x100c7370 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDiskStreamController::ClassName()) || MxStreamController::IsA(p_name); + } + + MxResult Open(const char* p_filename) override; // vtable+0x14 + MxResult VTable0x18(undefined4, undefined4) override; // vtable+0x18 + MxResult VTable0x20(MxDSAction* p_action) override; // vtable+0x20 + MxResult VTable0x24(MxDSAction* p_action) override; // vtable+0x24 + MxDSStreamingAction* VTable0x28() override; // vtable+0x28 + MxResult VTable0x30(MxDSAction* p_action) override; // vtable+0x30 + virtual MxResult VTable0x34(undefined4); // vtable+0x34 + + inline MxBool GetUnk0xc4() const { return m_unk0xc4; } + + MxResult FUN_100c7890(MxDSStreamingAction* p_action); + void FUN_100c7cb0(MxDSStreamingAction* p_action); + void FUN_100c7f40(MxDSStreamingAction* p_streamingaction); + void FUN_100c8120(MxDSAction* p_action); + void InsertToList74(MxDSBuffer* p_buffer); + void FUN_100c8670(MxDSStreamingAction* p_streamingAction); + +private: + MxStreamListMxDSAction m_list0x64; // 0x64 + MxBool m_unk0x70; // 0x70 + list m_list0x74; // 0x74 + MxStreamListMxDSAction m_list0x80; // 0x80 + undefined2 m_unk0x8c; // 0x8c + MxStreamListMxDSAction m_list0x90; // 0x90 + MxCriticalSection m_critical9c; // 0x9c + MxStreamListMxDSAction m_list0xb8; // 0xb8 + MxBool m_unk0xc4; // 0xc4 + + void FUN_100c7970(); + void FUN_100c7ce0(MxDSBuffer* p_buffer); + MxResult FUN_100c7d10(); + void FUN_100c7980(); + MxDSStreamingAction* FUN_100c7db0(); + MxResult FUN_100c8360(MxDSStreamingAction* p_action); + void FUN_100c8540(); + void FUN_100c8720(); +}; + +// TEMPLATE: LEGO1 0x100c14d0 +// list >::erase + +// TEMPLATE: LEGO1 0x100c7330 +// list >::_Buynode + +// TEMPLATE: LEGO1 0x100c7420 +// list >::~list > + +// TEMPLATE: LEGO1 0x100c7490 +// list >::_Buynode + +// SYNTHETIC: LEGO1 0x100c74c0 +// MxDiskStreamController::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c74e0 +// List::~List + +// TEMPLATE: LEGO1 0x100c7ef0 +// list::insert + +#endif // MXDISKSTREAMCONTROLLER_H diff --git a/LEGO1/omni/include/mxdiskstreamprovider.h b/LEGO1/omni/include/mxdiskstreamprovider.h new file mode 100644 index 00000000..7bac3a0b --- /dev/null +++ b/LEGO1/omni/include/mxdiskstreamprovider.h @@ -0,0 +1,76 @@ +#ifndef MXDISKSTREAMPROVIDER_H +#define MXDISKSTREAMPROVIDER_H + +#include "compat.h" +#include "decomp.h" +#include "mxcriticalsection.h" +#include "mxdsaction.h" +#include "mxstreamlist.h" +#include "mxstreamprovider.h" +#include "mxthread.h" + +class MxDiskStreamProvider; +class MxDSStreamingAction; + +// VTABLE: LEGO1 0x100dd130 +// SIZE 0x1c +class MxDiskStreamProviderThread : public MxThread { +public: + inline MxDiskStreamProviderThread() : MxThread() { m_target = NULL; } + + MxResult Run() override; + MxResult StartWithTarget(MxDiskStreamProvider* p_target); +}; + +// VTABLE: LEGO1 0x100dd138 +// SIZE 0x60 +class MxDiskStreamProvider : public MxStreamProvider { +public: + MxDiskStreamProvider(); + ~MxDiskStreamProvider() override; + + // FUNCTION: LEGO1 0x100d1160 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x1010287c + return "MxDiskStreamProvider"; + } + + // FUNCTION: LEGO1 0x100d1170 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDiskStreamProvider::ClassName()) || MxStreamProvider::IsA(p_name); + } + + MxResult WaitForWorkToComplete(); + MxResult FUN_100d1780(MxDSStreamingAction* p_action); + void PerformWork(); + static MxBool FUN_100d1af0(MxDSStreamingAction* p_action); + MxResult FUN_100d1b20(MxDSStreamingAction* p_action); + + MxResult SetResourceToGet(MxStreamController* p_resource) override; // vtable+0x14 + MxU32 GetFileSize() override; // vtable+0x18 + MxS32 GetStreamBuffersNum() override; // vtable+0x1c + void VTable0x20(MxDSAction* p_action) override; // vtable+0x20 + MxU32 GetLengthInDWords() override; // vtable+0x24 + MxU32* GetBufferForDWords() override; // vtable+0x28 + +private: + MxDiskStreamProviderThread m_thread; // 0x10 + MxSemaphore m_busySemaphore; // 0x2c + MxBool m_remainingWork; // 0x34 + MxBool m_unk0x35; // 0x35 + MxCriticalSection m_criticalSection; // 0x38 + MxStreamListMxDSAction m_list; // 0x54 +}; + +// SYNTHETIC: LEGO1 0x100d10a0 +// MxDiskStreamProviderThread::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100d1110 +// MxDiskStreamProviderThread::~MxDiskStreamProviderThread + +// SYNTHETIC: LEGO1 0x100d1220 +// MxDiskStreamProvider::`scalar deleting destructor' + +#endif // MXDISKSTREAMPROVIDER_H diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h new file mode 100644 index 00000000..2ec14784 --- /dev/null +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -0,0 +1,130 @@ +#ifndef MXDISPLAYSURFACE_H +#define MXDISPLAYSURFACE_H + +#include "decomp.h" +#include "mxcore.h" +#include "mxvideoparam.h" + +#include + +class MxBitmap; +class MxPalette; + +// VTABLE: LEGO1 0x100dc768 +// SIZE 0xac +class MxDisplaySurface : public MxCore { +public: + MxDisplaySurface(); + ~MxDisplaySurface() override; + + virtual MxResult Init( + MxVideoParam& p_videoParam, + LPDIRECTDRAWSURFACE p_ddSurface1, + LPDIRECTDRAWSURFACE p_ddSurface2, + LPDIRECTDRAWCLIPPER p_ddClipper + ); // vtable+0x14 + virtual MxResult Create(MxVideoParam& p_videoParam); // vtable+0x18 + virtual void Destroy(); // vtable+0x1c + virtual void SetPalette(MxPalette* p_palette); // vtable+0x20 + virtual void VTable0x24( + LPDDSURFACEDESC, + MxBitmap*, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4 + ); // vtable+0x24 + virtual void VTable0x28( + MxBitmap* p_bitmap, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height + ); // vtable+0x28 + virtual MxBool VTable0x2c( + LPDDSURFACEDESC, + MxBitmap*, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4, + MxBool + ); // vtable+0x2c + virtual void VTable0x30( + MxBitmap* p_bitmap, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height, + MxBool p_und + ); // vtable+0x30 + virtual undefined4 VTable0x34( + undefined4, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4 + ); // vtable+0x34 + virtual void Display( + MxS32 p_left, + MxS32 p_top, + MxS32 p_left2, + MxS32 p_top2, + MxS32 p_width, + MxS32 p_height + ); // vtable+0x38 + virtual void GetDC(HDC* p_hdc); // vtable+0x3c + virtual void ReleaseDC(HDC p_hdc); // vtable+0x40 + virtual LPDIRECTDRAWSURFACE VTable0x44( + MxBitmap* p_bitmap, + undefined4* p_ret, + undefined4 p_doNotWriteToSurface, + undefined4 p_transparent + ); // vtable+0x44 + + void ClearScreen(); + static LPDIRECTDRAWSURFACE CreateCursorSurface(); + static LPDIRECTDRAWSURFACE CopySurface(LPDIRECTDRAWSURFACE p_src); + + inline LPDIRECTDRAWSURFACE GetDirectDrawSurface1() { return this->m_ddSurface1; } + inline LPDIRECTDRAWSURFACE GetDirectDrawSurface2() { return this->m_ddSurface2; } + inline MxVideoParam& GetVideoParam() { return this->m_videoParam; } + + static void FUN_100bb500( + MxU8** p_bitmapData, + MxU8** p_surfaceData, + MxU32 p_bitmapSize, + MxS32 p_width, + MxS32 p_height, + MxLong p_pitch, + MxU32 p_bpp + ); + +private: + MxU8 CountTotalBitsSetTo1(MxU32 p_param); + MxU8 CountContiguousBitsSetTo1(MxU32 p_param); + + void Init(); + + MxVideoParam m_videoParam; // 0x08 + LPDIRECTDRAWSURFACE m_ddSurface1; // 0x2c + LPDIRECTDRAWSURFACE m_ddSurface2; // 0x30 + LPDIRECTDRAWCLIPPER m_ddClipper; // 0x34 + MxBool m_initialized; // 0x38 + DDSURFACEDESC m_surfaceDesc; // 0x3c + MxU16* m_16bitPal; // 0xa8 +}; + +// SYNTHETIC: LEGO1 0x100ba580 +// MxDisplaySurface::`scalar deleting destructor' + +#endif // MXDISPLAYSURFACE_H diff --git a/LEGO1/omni/include/mxdsaction.h b/LEGO1/omni/include/mxdsaction.h new file mode 100644 index 00000000..532035b5 --- /dev/null +++ b/LEGO1/omni/include/mxdsaction.h @@ -0,0 +1,129 @@ +#ifndef MXDSACTION_H +#define MXDSACTION_H + +#include "mxdsobject.h" +#include "mxgeometry/mxgeometry3d.h" +#include "mxtypes.h" + +class MxOmni; + +// VTABLE: LEGO1 0x100dc098 +// VTABLE: BETA10 0x101c1b68 +// SIZE 0x94 +class MxDSAction : public MxDSObject { +public: + enum { + c_looping = 0x01, + c_bit3 = 0x04, + c_bit4 = 0x08, + c_bit5 = 0x10, + c_enabled = 0x20, + c_bit7 = 0x40, + c_world = 0x80, + c_bit9 = 0x100, + c_bit10 = 0x200, + c_bit11 = 0x400, + }; + + MxDSAction(); + ~MxDSAction() override; + + MxDSAction(MxDSAction& p_dsAction); + void CopyFrom(MxDSAction& p_dsAction); + MxDSAction& operator=(MxDSAction& p_dsAction); + + // FUNCTION: LEGO1 0x100ad980 + // FUNCTION: BETA10 0x1012bcf0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x101013f4 + return "MxDSAction"; + } + + // FUNCTION: LEGO1 0x100ad990 + // FUNCTION: BETA10 0x1012bd10 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSAction::ClassName()) || MxDSObject::IsA(p_name); + } + + undefined4 VTable0x14() override; // vtable+14; + MxU32 GetSizeOnDisk() override; // vtable+18; + void Deserialize(MxU8*& p_source, MxS16 p_unk0x24) override; // vtable+1c; + virtual MxLong GetDuration(); // vtable+24; + virtual void SetDuration(MxLong p_duration); // vtable+28; + virtual MxDSAction* Clone(); // vtable+2c; + virtual void MergeFrom(MxDSAction& p_dsAction); // vtable+30; + virtual MxBool HasId(MxU32 p_objectId); // vtable+34; + virtual void SetUnknown90(MxLong p_unk0x90); // vtable+38; + virtual MxLong GetUnknown90(); // vtable+3c; + virtual MxLong GetElapsedTime(); // vtable+40; + + void AppendExtra(MxU16 p_extraLength, const char* p_extraData); + + // FUNCTION: BETA10 0x1003a560 + inline void GetExtra(MxU16& p_extraLength, char*& p_extraData) + { + p_extraLength = m_extraLength; + p_extraData = m_extraData; + } + + // FUNCTION: BETA10 0x1003cf70 + inline MxU32 GetFlags() { return m_flags; } + + // FUNCTION: BETA10 0x1004daa0 + inline void SetFlags(MxU32 p_flags) { m_flags = p_flags; } + + inline char* GetExtraData() { return m_extraData; } + inline MxU16 GetExtraLength() const { return m_extraLength; } + + // FUNCTION: BETA10 0x1005a560 + inline MxLong GetStartTime() const { return m_startTime; } + + // FUNCTION: BETA10 0x1012be80 + inline MxS32 GetLoopCount() { return m_loopCount; } + + inline void SetLoopCount(MxS32 p_loopCount) { m_loopCount = p_loopCount; } + + // FUNCTION: BETA10 0x1003db50 + inline Mx3DPointFloat& GetLocation() { return m_location; } + + // FUNCTION: BETA10 0x1003db80 + inline Mx3DPointFloat& GetDirection() { return m_direction; } + + // FUNCTION: BETA10 0x1003dbb0 + inline Mx3DPointFloat& GetUp() { return m_up; } + + inline void SetLocation(const Vector3& p_location) { m_location = p_location; } + inline void SetDirection(const Vector3& p_direction) { m_direction = p_direction; } + inline void SetUp(const Vector3& p_up) { m_up = p_up; } + inline MxCore* GetUnknown84() { return m_unk0x84; } + inline void SetUnknown84(MxCore* p_unk0x84) { m_unk0x84 = p_unk0x84; } + inline MxCore* GetOrigin() { return m_origin; } + inline void SetOrigin(MxCore* p_origin) { m_origin = p_origin; } + + inline MxBool IsLooping() const { return m_flags & c_looping; } + inline MxBool IsBit3() const { return m_flags & c_bit3; } + + // SYNTHETIC: LEGO1 0x100ada60 + // SYNTHETIC: BETA10 0x1012be40 + // MxDSAction::`scalar deleting destructor' + +protected: + MxU32 m_sizeOnDisk; // 0x2c + MxU32 m_flags; // 0x30 + MxLong m_startTime; // 0x34 + MxLong m_duration; // 0x38 + MxS32 m_loopCount; // 0x3c + Mx3DPointFloat m_location; // 0x40 + Mx3DPointFloat m_direction; // 0x54 + Mx3DPointFloat m_up; // 0x68 + char* m_extraData; // 0x7c + MxU16 m_extraLength; // 0x80 + MxCore* m_unk0x84; // 0x84 + undefined4 m_unk0x88; // 0x88 + MxCore* m_origin; // 0x8c + MxLong m_unk0x90; // 0x90 +}; + +#endif // MXDSACTION_H diff --git a/LEGO1/omni/include/mxdsactionlist.h b/LEGO1/omni/include/mxdsactionlist.h new file mode 100644 index 00000000..989508e6 --- /dev/null +++ b/LEGO1/omni/include/mxdsactionlist.h @@ -0,0 +1,64 @@ +#ifndef MXDSACTIONLIST_H +#define MXDSACTIONLIST_H + +#include "decomp.h" +#include "mxdsaction.h" +#include "mxlist.h" + +// VTABLE: LEGO1 0x100dcea8 +// class MxCollection + +// VTABLE: LEGO1 0x100dcec0 +// class MxList + +// VTABLE: LEGO1 0x100dced8 +// SIZE 0x1c +class MxDSActionList : public MxList { +public: + MxDSActionList() { this->m_unk0x18 = 0; } + + // FUNCTION: LEGO1 0x100c9c90 + MxS8 Compare(MxDSAction* p_a, MxDSAction* p_b) override + { + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; + } // vtable+0x14 + + // FUNCTION: LEGO1 0x100c9cb0 + static void Destroy(MxDSAction* p_action) { delete p_action; } + + // SYNTHETIC: LEGO1 0x100c9dc0 + // MxDSActionList::`scalar deleting destructor' + +private: + undefined m_unk0x18; // 0x18 +}; + +// VTABLE: LEGO1 0x100d7e68 +// class MxListCursor + +// VTABLE: LEGO1 0x100d7e50 +// SIZE 0x10 +class MxDSActionListCursor : public MxListCursor { +public: + MxDSActionListCursor(MxDSActionList* p_list) : MxListCursor(p_list) {} +}; + +// TEMPLATE: LEGO1 0x100c9cc0 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x100c9cd0 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x100c9d20 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x100c9d30 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x100c9e30 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c9ea0 +// MxList::`scalar deleting destructor' + +#endif // MXDSACTIONLIST_H diff --git a/LEGO1/omni/include/mxdsanim.h b/LEGO1/omni/include/mxdsanim.h new file mode 100644 index 00000000..09f9c72c --- /dev/null +++ b/LEGO1/omni/include/mxdsanim.h @@ -0,0 +1,35 @@ +#ifndef MXDSANIM_H +#define MXDSANIM_H + +#include "mxdsmediaaction.h" + +// VTABLE: LEGO1 0x100dcd88 +// SIZE 0xb8 +class MxDSAnim : public MxDSMediaAction { +public: + MxDSAnim(); + ~MxDSAnim() override; + + void CopyFrom(MxDSAnim& p_dsAnim); + MxDSAnim& operator=(MxDSAnim& p_dsAnim); + + // FUNCTION: LEGO1 0x100c9060 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x101025d8 + return "MxDSAnim"; + } + + // FUNCTION: LEGO1 0x100c9070 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSAnim::ClassName()) || MxDSMediaAction::IsA(p_name); + } + + MxDSAction* Clone() override; // vtable+2c; + + // SYNTHETIC: LEGO1 0x100c9180 + // MxDSAnim::`scalar deleting destructor' +}; + +#endif // MXDSANIM_H diff --git a/LEGO1/omni/include/mxdsbuffer.h b/LEGO1/omni/include/mxdsbuffer.h new file mode 100644 index 00000000..47c7bb07 --- /dev/null +++ b/LEGO1/omni/include/mxdsbuffer.h @@ -0,0 +1,95 @@ +#ifndef MXDSBUFFER_H +#define MXDSBUFFER_H + +#include "decomp.h" +#include "mxcore.h" + +class MxStreamController; +class MxDSAction; +class MxDSStreamingAction; +class MxStreamChunk; +class MxDSChunk; + +// VTABLE: LEGO1 0x100dcca0 +// SIZE 0x34 +class MxDSBuffer : public MxCore { +public: + enum Type { + e_chunk = 0, + e_allocate = 1, + e_preallocated = 2, + e_unknown = 3, + }; + + MxDSBuffer(); + ~MxDSBuffer() override; + + // FUNCTION: LEGO1 0x100c6500 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x101025b8 + return "MxDSBuffer"; + } + + MxResult AllocateBuffer(MxU32 p_bufferSize, Type p_mode); + MxResult SetBufferPointer(MxU8* p_buffer, MxU32 p_size); + MxResult FUN_100c67b0( + MxStreamController* p_controller, + MxDSAction* p_action, + MxDSStreamingAction** p_streamingAction + ); + MxResult CreateObject( + MxStreamController* p_controller, + MxU32* p_data, + MxDSAction* p_action, + MxDSStreamingAction** p_streamingAction + ); + MxResult StartPresenterFromAction(MxStreamController* p_controller, MxDSAction* p_action1, MxDSAction* p_action2); + MxResult ParseChunk( + MxStreamController* p_controller, + MxU32* p_data, + MxDSAction* p_action, + MxDSStreamingAction** p_streamingAction, + MxStreamChunk* p_header + ); + MxU8* SkipToData(); + MxU8 ReleaseRef(MxDSChunk*); + void AddRef(MxDSChunk* p_chunk); + MxResult CalcBytesRemaining(MxU8* p_data); + void FUN_100c6f80(MxU32 p_writeOffset); + MxU8* FUN_100c6fa0(MxU8* p_data); + MxResult FUN_100c7090(MxDSBuffer* p_buf); + + static MxCore* ReadChunk(MxDSBuffer* p_buffer, MxU32* p_chunkData, MxU16 p_flags); + static MxResult Append(MxU8* p_buffer1, MxU8* p_buffer2); + + inline MxU8* GetBuffer() { return m_pBuffer; } + inline MxU8** GetBufferRef() { return &m_pBuffer; } + inline undefined4 GetUnknown14() { return m_unk0x14; } + inline MxU16 GetRefCount() { return m_referenceCount; } + inline Type GetMode() { return m_mode; } + inline MxU32 GetWriteOffset() { return m_writeOffset; } + inline MxU32 GetBytesRemaining() { return m_bytesRemaining; } + inline void SetUnknown14(undefined4 p_unk0x14) { m_unk0x14 = p_unk0x14; } + inline void SetUnknown1c(undefined4 p_unk0x1c) { m_unk0x1c = p_unk0x1c; } + inline void SetMode(Type p_mode) { m_mode = p_mode; } + inline void SetUnk30(MxDSStreamingAction* p_unk0x30) { m_unk0x30 = p_unk0x30; } + + // SYNTHETIC: LEGO1 0x100c6510 + // MxDSBuffer::`scalar deleting destructor' + +private: + MxU8* m_pBuffer; // 0x08 + MxU8* m_pIntoBuffer; // 0x0c + MxU8* m_pIntoBuffer2; // 0x10 + undefined4 m_unk0x14; // 0x14 + undefined4 m_unk0x18; // 0x18 + undefined4 m_unk0x1c; // 0x1c + MxU16 m_referenceCount; // 0x20 + Type m_mode; // 0x24 + MxU32 m_writeOffset; // 0x28 + MxU32 m_bytesRemaining; // 0x2c + MxDSStreamingAction* m_unk0x30; // 0x30 +}; + +#endif // MXDSBUFFER_H diff --git a/LEGO1/omni/include/mxdschunk.h b/LEGO1/omni/include/mxdschunk.h new file mode 100644 index 00000000..10ed9b8b --- /dev/null +++ b/LEGO1/omni/include/mxdschunk.h @@ -0,0 +1,70 @@ +#ifndef MXDSCHUNK_H +#define MXDSCHUNK_H + +#include "decomp.h" +#include "mxcore.h" +#include "mxtypes.h" + +#define DS_CHUNK_BIT1 0x01 +#define DS_CHUNK_END_OF_STREAM 0x02 +#define DS_CHUNK_BIT3 0x04 +#define DS_CHUNK_SPLIT 0x10 +#define DS_CHUNK_BIT16 0x8000 + +// VTABLE: LEGO1 0x100dc7f8 +// SIZE 0x1c +class MxDSChunk : public MxCore { +public: + MxDSChunk(); + ~MxDSChunk() override; + + // FUNCTION: LEGO1 0x100be0c0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101e6c + return "MxDSChunk"; + } + + // FUNCTION: LEGO1 0x100be0d0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSChunk::ClassName()) || MxCore::IsA(p_name); + } + + static MxU32 GetHeaderSize(); + inline static MxU32* IntoType(MxU8* p_buffer) { return (MxU32*) p_buffer; } + inline static MxU32* IntoLength(MxU8* p_buffer) { return (MxU32*) (p_buffer + 4); } + inline static MxU32 Size(MxU32 p_dataSize) { return (p_dataSize & 1) + p_dataSize + 8; } + inline static MxU8* End(MxU8* p_buffer) { return p_buffer + Size(*IntoLength(p_buffer)); } + + inline void SetChunkFlags(MxU16 p_flags) { m_flags = p_flags; } + inline void SetObjectId(undefined4 p_objectid) { m_objectId = p_objectid; } + inline void SetTime(MxLong p_time) { m_time = p_time; } + inline void SetLength(MxU32 p_length) { m_length = p_length; } + inline void SetData(MxU8* p_data) { m_data = p_data; } + + inline MxU16 GetChunkFlags() { return m_flags; } + inline undefined4 GetObjectId() { return m_objectId; } + inline MxLong GetTime() { return m_time; } + inline MxU32 GetLength() { return m_length; } + inline MxU8* GetData() { return m_data; } + + inline void Release() + { + if (m_data) { + delete[] m_data; + } + } + + // SYNTHETIC: LEGO1 0x100be150 + // MxDSChunk::`scalar deleting destructor' + +protected: + MxU16 m_flags; // 0x08 + MxU32 m_objectId; // 0x0c + MxLong m_time; // 0x10 + MxU32 m_length; // 0x14 + MxU8* m_data; // 0x18 +}; + +#endif // MXDSCHUNK_H diff --git a/LEGO1/omni/include/mxdsevent.h b/LEGO1/omni/include/mxdsevent.h new file mode 100644 index 00000000..492cfd10 --- /dev/null +++ b/LEGO1/omni/include/mxdsevent.h @@ -0,0 +1,34 @@ +#ifndef MXDSEVENT_H +#define MXDSEVENT_H + +#include "mxdsmediaaction.h" + +// VTABLE: LEGO1 0x100dce18 +class MxDSEvent : public MxDSMediaAction { +public: + MxDSEvent(); + ~MxDSEvent() override; + + void CopyFrom(MxDSEvent& p_dsEvent); + MxDSEvent& operator=(MxDSEvent& p_dsEvent); + + // FUNCTION: LEGO1 0x100c9660 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x101025f0 + return "MxDSEvent"; + } + + // FUNCTION: LEGO1 0x100c9670 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSEvent::ClassName()) || MxDSMediaAction::IsA(p_name); + } + + MxDSAction* Clone() override; // vtable+2c; + + // SYNTHETIC: LEGO1 0x100c9780 + // MxDSEvent::`scalar deleting destructor' +}; + +#endif // MXDSEVENT_H diff --git a/LEGO1/omni/include/mxdsfile.h b/LEGO1/omni/include/mxdsfile.h new file mode 100644 index 00000000..bd4c74a1 --- /dev/null +++ b/LEGO1/omni/include/mxdsfile.h @@ -0,0 +1,76 @@ +#ifndef MXDSFILE_H +#define MXDSFILE_H + +#include "mxdssource.h" +#include "mxio.h" +#include "mxstring.h" +#include "mxtypes.h" + +#include + +// VTABLE: LEGO1 0x100dc890 +// SIZE 0x7c +class MxDSFile : public MxDSSource { +public: + MxDSFile(const char* p_filename, MxULong p_skipReadingChunks); + +#ifdef ISLE_APP + ~MxDSFile() override { Close(); } +#else + // We have to explicitly use dllexport, otherwise this function cannot be exported, + // since it is inlined everywhere in LEGO1.DLL + // FUNCTION: LEGO1 0x100bfed0 + __declspec(dllexport) ~MxDSFile() override { Close(); } +#endif + + // FUNCTION: LEGO1 0x100c0120 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10102594 + return "MxDSFile"; + } + + // FUNCTION: LEGO1 0x100c0130 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSFile::ClassName()) || MxDSSource::IsA(p_name); + } + + MxLong Open(MxULong) override; // vtable+0x14 + MxLong Close() override; // vtable+0x18 + MxResult Read(unsigned char*, MxULong) override; // vtable+0x20 + MxLong Seek(MxLong, int) override; // vtable+0x24 + MxULong GetBufferSize() override; // vtable+0x28 + MxULong GetStreamBuffersNum() override; // vtable+0x2c + + inline void SetFileName(const char* p_filename) { m_filename = p_filename; } + + inline MxS32 CalcFileSize() { return GetFileSize(m_io.m_info.hmmio, NULL); } + + // SYNTHETIC: LEGO1 0x100c01e0 + // MxDSFile::`scalar deleting destructor' + + // SIZE 0x0c + struct ChunkHeader { + ChunkHeader() : m_majorVersion(0), m_minorVersion(0), m_bufferSize(0), m_streamBuffersNum(0) {} + + MxU16 m_majorVersion; // 0x00 + MxU16 m_minorVersion; // 0x02 + MxULong m_bufferSize; // 0x04 + MxS16 m_streamBuffersNum; // 0x08 + MxS16 m_reserved; // 0x0a + }; + +private: + MxLong ReadChunks(); + + MxString m_filename; // 0x14 + MXIOINFO m_io; // 0x24 + ChunkHeader m_header; // 0x6c + + // If false, read chunks immediately on open, otherwise + // skip reading chunks until ReadChunks is explicitly called. + MxULong m_skipReadingChunks; // 0x78 +}; + +#endif // MXDSFILE_H diff --git a/LEGO1/omni/include/mxdsmediaaction.h b/LEGO1/omni/include/mxdsmediaaction.h new file mode 100644 index 00000000..9b5f8604 --- /dev/null +++ b/LEGO1/omni/include/mxdsmediaaction.h @@ -0,0 +1,80 @@ +#ifndef MXDSMEDIAACTION_H +#define MXDSMEDIAACTION_H + +#include "decomp.h" +#include "mxdsaction.h" + +// VTABLE: LEGO1 0x100dcd40 +// VTABLE: BETA10 0x101c2ad8 +// SIZE 0xb8 +class MxDSMediaAction : public MxDSAction { +public: + MxDSMediaAction(); + ~MxDSMediaAction() override; + + void CopyFrom(MxDSMediaAction& p_dsMediaAction); + MxDSMediaAction(MxDSMediaAction& p_dsMediaAction); + MxDSMediaAction& operator=(MxDSMediaAction& p_dsMediaAction); + + // FUNCTION: LEGO1 0x100c8be0 + // FUNCTION: BETA10 0x1015c700 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f7624 + return "MxDSMediaAction"; + } + + // FUNCTION: LEGO1 0x100c8bf0 + // FUNCTION: BETA10 0x1015c6a0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSMediaAction::ClassName()) || MxDSAction::IsA(p_name); + } + + // SYNTHETIC: LEGO1 0x100c8cd0 + // SYNTHETIC: BETA10 0x1015d810 + // MxDSMediaAction::`scalar deleting destructor' + + undefined4 VTable0x14() override; // vtable+14; + MxU32 GetSizeOnDisk() override; // vtable+18; + void Deserialize(MxU8*& p_source, MxS16 p_unk0x24) override; // vtable+1c; + MxDSAction* Clone() override; // vtable+2c; + + void CopyMediaSrcPath(const char* p_mediaSrcPath); + + // FUNCTION: BETA10 0x1013c2e0 + inline MxS32 GetFramesPerSecond() const { return m_framesPerSecond; } + + // FUNCTION: BETA10 0x1012efd0 + inline MxS32 GetMediaFormat() const { return m_mediaFormat; } + + // FUNCTION: BETA10 0x1013b860 + inline MxS32 GetPaletteManagement() const { return m_paletteManagement; } + + // FUNCTION: BETA10 0x1005ab60 + inline MxLong GetSustainTime() const { return m_sustainTime; } + +private: + struct Unk0x9cStruct { + // FUNCTION: BETA10 0x1015d7c0 + void SetUnk0x00(undefined4 p_value) { m_unk0x00 = p_value; } + + // FUNCTION: BETA10 0x1015d7e0 + void SetUnk0x04(undefined4 p_value) { m_unk0x04 = p_value; } + + // intentionally public + undefined4 m_unk0x00; + undefined4 m_unk0x04; + }; + + MxU32 m_sizeOnDisk; // 0x94 + char* m_mediaSrcPath; // 0x98 + Unk0x9cStruct m_unk0x9c; // 0x9c + MxS32 m_framesPerSecond; // 0xa4 + MxS32 m_mediaFormat; // 0xa8 + MxS32 m_paletteManagement; // 0xac + MxLong m_sustainTime; // 0xb0 + undefined4 m_unk0xb4; // 0xb4 +}; + +#endif // MXDSMEDIAACTION_H diff --git a/LEGO1/omni/include/mxdsmultiaction.h b/LEGO1/omni/include/mxdsmultiaction.h new file mode 100644 index 00000000..c74d62f0 --- /dev/null +++ b/LEGO1/omni/include/mxdsmultiaction.h @@ -0,0 +1,61 @@ +#ifndef MXDSMULTIACTION_H +#define MXDSMULTIACTION_H + +#include "mxdsaction.h" +#include "mxdsactionlist.h" + +// VTABLE: LEGO1 0x100dcef0 +// SIZE 0x9c +class MxDSMultiAction : public MxDSAction { +public: + MxDSMultiAction(); + ~MxDSMultiAction() override; + + void CopyFrom(MxDSMultiAction& p_dsMultiAction); + MxDSMultiAction& operator=(MxDSMultiAction& p_dsMultiAction); + + // FUNCTION: LEGO1 0x100c9f50 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101dbc + return "MxDSMultiAction"; + } + + // FUNCTION: LEGO1 0x100c9f60 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSMultiAction::ClassName()) || MxDSAction::IsA(p_name); + } + + undefined4 VTable0x14() override; // vtable+14; + MxU32 GetSizeOnDisk() override; // vtable+18; + void Deserialize(MxU8*& p_source, MxS16 p_unk0x24) override; // vtable+1c; + void SetAtomId(MxAtomId p_atomId) override; // vtable+20; + MxDSAction* Clone() override; // vtable+2c; + void MergeFrom(MxDSAction& p_dsAction) override; // vtable+30; + MxBool HasId(MxU32 p_objectId) override; // vtable+34; + void SetUnknown90(MxLong p_unk0x90) override; // vtable+38; + + inline MxDSActionList* GetActionList() const { return m_actions; } + + // SYNTHETIC: LEGO1 0x100ca040 + // MxDSMultiAction::`scalar deleting destructor' + +protected: + MxU32 m_sizeOnDisk; // 0x94 + MxDSActionList* m_actions; // 0x98 +}; + +// SYNTHETIC: LEGO1 0x1004ad10 +// MxDSActionListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1004ad80 +// MxListCursor::~MxListCursor + +// SYNTHETIC: LEGO1 0x1004add0 +// MxListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x1004ae40 +// MxDSActionListCursor::~MxDSActionListCursor + +#endif // MXDSMULTIACTION_H diff --git a/LEGO1/omni/include/mxdsobject.h b/LEGO1/omni/include/mxdsobject.h new file mode 100644 index 00000000..8fe2426c --- /dev/null +++ b/LEGO1/omni/include/mxdsobject.h @@ -0,0 +1,101 @@ +#ifndef MXDSOBJECT_H +#define MXDSOBJECT_H + +#include "decomp.h" +#include "mxatom.h" +#include "mxcore.h" + +class MxPresenter; + +// VTABLE: LEGO1 0x100dc868 +// VTABLE: BETA10 0x101c23f0 +// SIZE 0x2c +class MxDSObject : public MxCore { +public: + enum Type { + e_object = 0, + e_action, + e_mediaAction, + e_anim, + e_sound, + e_multiAction, + e_serialAction, + e_parallelAction, + e_event, + e_selectAction, + e_still, + e_objectAction, + }; + + MxDSObject(); + ~MxDSObject() override; + + void CopyFrom(MxDSObject& p_dsObject); + MxDSObject(MxDSObject& p_dsObject); + MxDSObject& operator=(MxDSObject& p_dsObject); + + void SetObjectName(const char* p_objectName); + void SetSourceName(const char* p_sourceName); + + // FUNCTION: LEGO1 0x100bf730 + // FUNCTION: BETA10 0x1012bdd0 + inline const char* ClassName() const override { return "MxDSObject"; } // vtable+0c + + // FUNCTION: LEGO1 0x100bf740 + // FUNCTION: BETA10 0x1012bd70 + inline MxBool IsA(const char* p_name) const override + { + return !strcmp(p_name, MxDSObject::ClassName()) || MxCore::IsA(p_name); + } // vtable+10; + + virtual undefined4 VTable0x14(); // vtable+14; + virtual MxU32 GetSizeOnDisk(); // vtable+18; + virtual void Deserialize(MxU8*& p_source, MxS16 p_unk0x24); // vtable+1c; + + // FUNCTION: ISLE 0x401c40 + // FUNCTION: LEGO1 0x10005530 + // FUNCTION: BETA10 0x100152e0 + inline virtual void SetAtomId(MxAtomId p_atomId) { m_atomId = p_atomId; } // vtable+20; + + // FUNCTION: BETA10 0x1012ef90 + inline Type GetType() const { return (Type) m_type; } + + // FUNCTION: BETA10 0x1012efb0 + inline const char* GetSourceName() const { return m_sourceName; } + inline const char* GetObjectName() const { return m_objectName; } + inline MxU32 GetObjectId() { return m_objectId; } + inline const MxAtomId& GetAtomId() { return m_atomId; } + inline MxS16 GetUnknown24() { return m_unk0x24; } + inline MxPresenter* GetUnknown28() { return m_unk0x28; } + + inline void SetType(Type p_type) { m_type = p_type; } + + // FUNCTION: BETA10 0x100152b0 + inline void SetObjectId(MxU32 p_objectId) { m_objectId = p_objectId; } + + // FUNCTION: BETA10 0x10039570 + inline void SetUnknown24(MxS16 p_unk0x24) { m_unk0x24 = p_unk0x24; } + + inline void SetUnknown28(MxPresenter* p_unk0x28) { m_unk0x28 = p_unk0x28; } + + inline void ClearAtom() { m_atomId.Clear(); } + + // SYNTHETIC: LEGO1 0x100bf7c0 + // SYNTHETIC: BETA10 0x10148770 + // MxDSObject::`scalar deleting destructor' + +protected: + MxU32 m_sizeOnDisk; // 0x08 + MxU16 m_type; // 0x0c + char* m_sourceName; // 0x10 + undefined4 m_unk0x14; // 0x14 + char* m_objectName; // 0x18 + MxU32 m_objectId; // 0x1c + MxAtomId m_atomId; // 0x20 + MxS16 m_unk0x24; // 0x24 + MxPresenter* m_unk0x28; // 0x28 +}; + +MxDSObject* DeserializeDSObjectDispatch(MxU8*&, MxS16); + +#endif // MXDSOBJECT_H diff --git a/LEGO1/omni/include/mxdsobjectaction.h b/LEGO1/omni/include/mxdsobjectaction.h new file mode 100644 index 00000000..205c6d81 --- /dev/null +++ b/LEGO1/omni/include/mxdsobjectaction.h @@ -0,0 +1,35 @@ +#ifndef MXDSOBJECTACTION_H +#define MXDSOBJECTACTION_H + +#include "mxdsmediaaction.h" + +// VTABLE: LEGO1 0x100dccf8 +// SIZE 0xb8 +class MxDSObjectAction : public MxDSMediaAction { +public: + MxDSObjectAction(); + ~MxDSObjectAction() override; + + MxDSObjectAction& operator=(MxDSObjectAction& p_dsObjectAction); + + // FUNCTION: LEGO1 0x100c88e0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x101025c4 + return "MxDSObjectAction"; + } + + // FUNCTION: LEGO1 0x100c88f0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSObjectAction::ClassName()) || MxDSMediaAction::IsA(p_name); + } + + MxDSAction* Clone() override; // vtable+2c; + virtual void CopyFrom(MxDSObjectAction& p_dsObjectAction); // vtable+44; + + // SYNTHETIC: LEGO1 0x100c8a00 + // MxDSObjectAction::`scalar deleting destructor' +}; + +#endif // MXDSOBJECTACTION_H diff --git a/LEGO1/omni/include/mxdsparallelaction.h b/LEGO1/omni/include/mxdsparallelaction.h new file mode 100644 index 00000000..212fb8f0 --- /dev/null +++ b/LEGO1/omni/include/mxdsparallelaction.h @@ -0,0 +1,40 @@ +#ifndef MXDSPARALLELACTION_H +#define MXDSPARALLELACTION_H + +#include "mxdsmultiaction.h" + +// VTABLE: LEGO1 0x100dcf80 +// SIZE 0x9c +class MxDSParallelAction : public MxDSMultiAction { +public: + MxDSParallelAction(); + ~MxDSParallelAction() override; + + void CopyFrom(MxDSParallelAction& p_dsParallelAction); + MxDSParallelAction& operator=(MxDSParallelAction& p_dsParallelAction); + + // FUNCTION: LEGO1 0x100caf00 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10102608 + return "MxDSParallelAction"; + } + + // FUNCTION: LEGO1 0x100caf10 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSParallelAction::ClassName()) || MxDSMultiAction::IsA(p_name); + } + + // SYNTHETIC: LEGO1 0x100cb020 + // MxDSParallelAction::`scalar deleting destructor' + + MxLong GetDuration() override; // vtable+24; + + // FUNCTION: LEGO1 0x100caef0 + void SetDuration(MxLong p_duration) override { m_duration = p_duration; } // vtable+0x28 + + MxDSAction* Clone() override; // vtable+2c; +}; + +#endif // MXDSPARALLELACTION_H diff --git a/LEGO1/omni/include/mxdsselectaction.h b/LEGO1/omni/include/mxdsselectaction.h new file mode 100644 index 00000000..24c8a6d5 --- /dev/null +++ b/LEGO1/omni/include/mxdsselectaction.h @@ -0,0 +1,55 @@ +#ifndef MXDSSELECTACTION_H +#define MXDSSELECTACTION_H + +#include "decomp.h" +#include "mxdsparallelaction.h" +#include "mxstringlist.h" + +// VTABLE: LEGO1 0x100dcfc8 +// SIZE 0xb0 +class MxDSSelectAction : public MxDSParallelAction { +public: + MxDSSelectAction(); + ~MxDSSelectAction() override; + + void CopyFrom(MxDSSelectAction& p_dsSelectAction); + MxDSSelectAction& operator=(MxDSSelectAction& p_dsSelectAction); + + // FUNCTION: LEGO1 0x100cb6f0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x1010261c + return "MxDSSelectAction"; + } + + // FUNCTION: LEGO1 0x100cb700 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSSelectAction::ClassName()) || MxDSParallelAction::IsA(p_name); + } + + MxU32 GetSizeOnDisk() override; // vtable+18; + void Deserialize(MxU8*& p_source, MxS16 p_unk0x24) override; // vtable+1c; + MxDSAction* Clone() override; // vtable+2c; + + // SYNTHETIC: LEGO1 0x100cb840 + // MxDSSelectAction::`scalar deleting destructor' + +private: + MxString m_unk0x9c; + MxStringList* m_unk0xac; +}; + +// SYNTHETIC: LEGO1 0x100cbbd0 +// MxStringListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100cbc40 +// MxListCursor::~MxListCursor + +// SYNTHETIC: LEGO1 0x100cbc90 +// MxListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x100cbd00 +// MxStringListCursor::~MxStringListCursor + +#endif // MXDSSELECTACTION_H diff --git a/LEGO1/omni/include/mxdsserialaction.h b/LEGO1/omni/include/mxdsserialaction.h new file mode 100644 index 00000000..b1c2a695 --- /dev/null +++ b/LEGO1/omni/include/mxdsserialaction.h @@ -0,0 +1,43 @@ +#ifndef MXDSSERIALACTION_H +#define MXDSSERIALACTION_H + +#include "decomp.h" +#include "mxdsmultiaction.h" + +// VTABLE: LEGO1 0x100dcf38 +// SIZE 0xa8 +class MxDSSerialAction : public MxDSMultiAction { +public: + MxDSSerialAction(); + ~MxDSSerialAction() override; + + void CopyFrom(MxDSSerialAction& p_dsSerialAction); + MxDSSerialAction& operator=(MxDSSerialAction& p_dsSerialAction); + + // FUNCTION: LEGO1 0x100caad0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f75dc + return "MxDSSerialAction"; + } + + // FUNCTION: LEGO1 0x100caae0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSSerialAction::ClassName()) || MxDSMultiAction::IsA(p_name); + } + + MxLong GetDuration() override; // vtable+24; + void SetDuration(MxLong p_duration) override; // vtable+28; + MxDSAction* Clone() override; // vtable+2c; + + // SYNTHETIC: LEGO1 0x100cabf0 + // MxDSSerialAction::`scalar deleting destructor' + +private: + MxDSActionListCursor* m_cursor; + undefined4 m_unk0xa0; + undefined4 m_unk0xa4; +}; + +#endif // MXDSSERIALACTION_H diff --git a/LEGO1/omni/include/mxdssound.h b/LEGO1/omni/include/mxdssound.h new file mode 100644 index 00000000..c406ba92 --- /dev/null +++ b/LEGO1/omni/include/mxdssound.h @@ -0,0 +1,43 @@ +#ifndef MXDSSOUND_H +#define MXDSSOUND_H + +#include "mxdsmediaaction.h" + +// VTABLE: LEGO1 0x100dcdd0 +// SIZE 0xc0 +class MxDSSound : public MxDSMediaAction { +public: + MxDSSound(); + ~MxDSSound() override; + + void CopyFrom(MxDSSound& p_dsSound); + MxDSSound& operator=(MxDSSound& p_dsSound); + + // FUNCTION: LEGO1 0x100c9330 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x101025e4 + return "MxDSSound"; + } + + // FUNCTION: LEGO1 0x100c9340 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSSound::ClassName()) || MxDSMediaAction::IsA(p_name); + } + + MxU32 GetSizeOnDisk() override; // vtable+18; + void Deserialize(MxU8*& p_source, MxS16 p_unk0x24) override; // vtable+1c; + MxDSAction* Clone() override; // vtable+2c; + + inline MxS32 GetVolume() const { return m_volume; } + + // SYNTHETIC: LEGO1 0x100c9450 + // MxDSSound::`scalar deleting destructor' + +private: + MxU32 m_sizeOnDisk; + MxS32 m_volume; // 0xbc +}; + +#endif // MXDSSOUND_H diff --git a/LEGO1/omni/include/mxdssource.h b/LEGO1/omni/include/mxdssource.h new file mode 100644 index 00000000..d3b9474b --- /dev/null +++ b/LEGO1/omni/include/mxdssource.h @@ -0,0 +1,50 @@ +#ifndef MXDSSOURCE_H +#define MXDSSOURCE_H + +#include "mxcore.h" + +class MxDSBuffer; + +// VTABLE: LEGO1 0x100dc8c8 +// SIZE 0x14 +class MxDSSource : public MxCore { +public: + MxDSSource() : m_lengthInDWords(0), m_pBuffer(NULL), m_position(-1) {} + + // FUNCTION: LEGO1 0x100bff60 + ~MxDSSource() override { delete[] m_pBuffer; } + + // FUNCTION: LEGO1 0x100c0010 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10102588 + return "MxDSSource"; + } + + // FUNCTION: LEGO1 0x100c0020 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSSource::ClassName()) || MxCore::IsA(p_name); + } + + virtual MxLong Open(MxULong) = 0; // vtable+0x14 + virtual MxLong Close() = 0; // vtable+0x18 + virtual MxResult ReadToBuffer(MxDSBuffer* p_buffer); // vtable+0x1c + virtual MxResult Read(unsigned char*, MxULong) = 0; // vtable+0x20 + virtual MxLong Seek(MxLong, int) = 0; // vtable+0x24 + virtual MxULong GetBufferSize() = 0; // vtable+0x28 + virtual MxULong GetStreamBuffersNum() = 0; // vtable+0x2c + virtual MxLong GetLengthInDWords(); // vtable+0x30 + virtual MxU32* GetBuffer(); // vtable+0x34 + inline MxLong GetPosition() const { return m_position; } + +protected: + MxULong m_lengthInDWords; // 0x08 + MxU32* m_pBuffer; // 0x0c + MxLong m_position; // 0x10 +}; + +// SYNTHETIC: LEGO1 0x100c00a0 +// MxDSSource::`scalar deleting destructor' + +#endif // MXDSSOURCE_H diff --git a/LEGO1/omni/include/mxdsstill.h b/LEGO1/omni/include/mxdsstill.h new file mode 100644 index 00000000..f46fff32 --- /dev/null +++ b/LEGO1/omni/include/mxdsstill.h @@ -0,0 +1,35 @@ +#ifndef MXDSSTILL_H +#define MXDSSTILL_H + +#include "mxdsmediaaction.h" + +// VTABLE: LEGO1 0x100dce60 +// SIZE 0xb8 +class MxDSStill : public MxDSMediaAction { +public: + MxDSStill(); + ~MxDSStill() override; + + void CopyFrom(MxDSStill& p_dsStill); + MxDSStill& operator=(MxDSStill& p_dsStill); + + // FUNCTION: LEGO1 0x100c9930 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x101025fc + return "MxDSStill"; + } + + // FUNCTION: LEGO1 0x100c9940 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSStill::ClassName()) || MxDSMediaAction::IsA(p_name); + } + + MxDSAction* Clone() override; // vtable+2c; + + // SYNTHETIC: LEGO1 0x100c9a50 + // MxDSStill::`scalar deleting destructor' +}; + +#endif // MXDSSTILL_H diff --git a/LEGO1/omni/include/mxdsstreamingaction.h b/LEGO1/omni/include/mxdsstreamingaction.h new file mode 100644 index 00000000..94e652ae --- /dev/null +++ b/LEGO1/omni/include/mxdsstreamingaction.h @@ -0,0 +1,61 @@ +#ifndef MXDSSTREAMINGACTION_H +#define MXDSSTREAMINGACTION_H + +#include "mxdsaction.h" + +class MxDSBuffer; + +// VTABLE: LEGO1 0x100dd088 +// SIZE 0xb4 +class MxDSStreamingAction : public MxDSAction { +public: + MxDSStreamingAction(MxDSAction& p_dsAction, MxU32 p_offset); + MxDSStreamingAction(MxDSStreamingAction& p_dsStreamingAction); + ~MxDSStreamingAction() override; + + MxDSStreamingAction* CopyFrom(MxDSStreamingAction& p_dsStreamingAction); + MxDSStreamingAction& operator=(MxDSAction& p_dsAction) + { + MxDSAction::operator=(p_dsAction); + return *this; + } + MxDSStreamingAction& operator=(MxDSStreamingAction& p_dsStreamingAction) + { + MxDSAction::operator=(p_dsStreamingAction); + return *this; + } + + MxBool HasId(MxU32 p_objectId) override; // vtable+34; + + MxResult Init(); + void SetInternalAction(MxDSAction* p_dsAction); + void FUN_100cd2d0(); + + inline MxU32 GetUnknown94() { return m_unk0x94; } + inline MxS32 GetUnknown9c() { return m_unk0x9c; } + inline MxDSBuffer* GetUnknowna0() { return m_unk0xa0; } + inline MxDSBuffer* GetUnknowna4() { return m_unk0xa4; } + inline MxLong GetUnknowna8() { return m_unk0xa8; } + inline MxDSAction* GetInternalAction() { return m_internalAction; } + inline MxU32 GetBufferOffset() { return m_bufferOffset; } + inline void SetUnknown94(MxU32 p_unk0x94) { m_unk0x94 = p_unk0x94; } + inline void SetUnknown9c(MxS32 p_unk0x9c) { m_unk0x9c = p_unk0x9c; } + inline void SetUnknowna0(MxDSBuffer* p_unk0xa0) { m_unk0xa0 = p_unk0xa0; } + inline void SetUnknowna4(MxDSBuffer* p_unk0xa4) { m_unk0xa4 = p_unk0xa4; } + inline void SetBufferOffset(MxU32 p_bufferOffset) { m_bufferOffset = p_bufferOffset; } + + // SYNTHETIC: LEGO1 0x100cd0b0 + // MxDSStreamingAction::`scalar deleting destructor' + +private: + MxU32 m_unk0x94; // 0x94 + MxU32 m_bufferOffset; // 0x98 + MxS32 m_unk0x9c; // 0x9c + MxDSBuffer* m_unk0xa0; // 0xa0 + MxDSBuffer* m_unk0xa4; // 0xa4 + MxLong m_unk0xa8; // 0xa8 + undefined2 m_unk0xac; // 0xac + MxDSAction* m_internalAction; // 0xb0 +}; + +#endif // MXDSSTREAMINGACTION_H diff --git a/LEGO1/omni/include/mxdssubscriber.h b/LEGO1/omni/include/mxdssubscriber.h new file mode 100644 index 00000000..6d420c35 --- /dev/null +++ b/LEGO1/omni/include/mxdssubscriber.h @@ -0,0 +1,56 @@ +#ifndef MXDSSUBSCRIBER_H +#define MXDSSUBSCRIBER_H + +#include "decomp.h" +#include "mxcore.h" +#include "mxstreamchunklist.h" + +class MxStreamController; + +// VTABLE: LEGO1 0x100dc698 +// SIZE 0x4c +class MxDSSubscriber : public MxCore { +public: + MxDSSubscriber(); + ~MxDSSubscriber() override; + + // FUNCTION: LEGO1 0x100b7d50 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x101020f8 + return "MxDSSubscriber"; + } + + // FUNCTION: LEGO1 0x100b7d60 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxDSSubscriber::ClassName()) || MxCore::IsA(p_name); + } + + MxResult Create(MxStreamController* p_controller, MxU32 p_objectId, MxS16 p_unk0x48); + void DestroyData(); + MxResult AddData(MxStreamChunk* p_chunk, MxBool p_append); + MxStreamChunk* PopData(); + MxStreamChunk* PeekData(); + void FreeDataChunk(MxStreamChunk* p_chunk); + + inline MxU32 GetObjectId() { return m_objectId; } + inline MxS16 GetUnknown48() { return m_unk0x48; } + +private: + MxStreamChunkList m_pendingChunks; // 0x08 + MxStreamChunkListCursor* m_pendingChunkCursor; // 0x20 + MxStreamChunkList m_consumedChunks; // 0x24 + MxStreamChunkListCursor* m_consumedChunkCursor; // 0x3c + MxStreamController* m_controller; // 0x40 + MxU32 m_objectId; // 0x44 + MxS16 m_unk0x48; // 0x48 +}; + +// SYNTHETIC: LEGO1 0x100b7de0 +// MxDSSubscriber::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b7d00 +// MxStreamChunkList::~MxStreamChunkList + +#endif // MXDSSUBSCRIBER_H diff --git a/LEGO1/omni/include/mxentity.h b/LEGO1/omni/include/mxentity.h new file mode 100644 index 00000000..715b8b10 --- /dev/null +++ b/LEGO1/omni/include/mxentity.h @@ -0,0 +1,59 @@ +#ifndef MXENTITY_H +#define MXENTITY_H + +#include "decomp.h" +#include "mxatom.h" +#include "mxcore.h" +#include "mxdsaction.h" +#include "mxtypes.h" + +// VTABLE: LEGO1 0x100d5390 +// SIZE 0x10 +class MxEntity : public MxCore { +public: + // FUNCTION: LEGO1 0x1001d190 + MxEntity() { this->m_mxEntityId = -1; } + + // FUNCTION: LEGO1 0x1000c110 + ~MxEntity() override {} + + // FUNCTION: LEGO1 0x1000c180 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0070 + return "MxEntity"; + } + + // FUNCTION: LEGO1 0x1000c190 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxEntity::ClassName()) || MxCore::IsA(p_name); + } + + // FUNCTION: LEGO1 0x10001070 + virtual MxResult Create(MxS32 p_id, const MxAtomId& p_atom) + { + this->m_mxEntityId = p_id; + this->m_atom = p_atom; + return SUCCESS; + } // vtable+0x14 + + inline MxResult Create(MxDSAction& p_dsAction) + { + m_mxEntityId = p_dsAction.GetObjectId(); + m_atom = p_dsAction.GetAtomId(); + return SUCCESS; + } + + inline MxS32 GetEntityId() { return m_mxEntityId; } + inline MxAtomId& GetAtom() { return m_atom; } + + // SYNTHETIC: LEGO1 0x1000c210 + // MxEntity::`scalar deleting destructor' + +protected: + MxS32 m_mxEntityId; // 0x08 + MxAtomId m_atom; // 0x0c +}; + +#endif // MXENTITY_H diff --git a/LEGO1/omni/include/mxeventmanager.h b/LEGO1/omni/include/mxeventmanager.h new file mode 100644 index 00000000..b23a2ad0 --- /dev/null +++ b/LEGO1/omni/include/mxeventmanager.h @@ -0,0 +1,25 @@ +#ifndef MXEVENTMANAGER_H +#define MXEVENTMANAGER_H + +#include "decomp.h" +#include "mxmediamanager.h" + +// VTABLE: LEGO1 0x100dc900 +// SIZE 0x2c +class MxEventManager : public MxMediaManager { +public: + MxEventManager(); + ~MxEventManager() override; + + void Destroy() override; // vtable+18 + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+28 + + // SYNTHETIC: LEGO1 0x100c03d0 + // MxEventManager::`scalar deleting destructor' + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); +}; + +#endif // MXEVENTMANAGER_H diff --git a/LEGO1/omni/include/mxeventpresenter.h b/LEGO1/omni/include/mxeventpresenter.h new file mode 100644 index 00000000..1812280f --- /dev/null +++ b/LEGO1/omni/include/mxeventpresenter.h @@ -0,0 +1,43 @@ +#ifndef MXEVENTPRESENTER_H +#define MXEVENTPRESENTER_H + +#include "decomp.h" +#include "mxmediapresenter.h" + +// VTABLE: LEGO1 0x100dca88 +// SIZE 0x54 +class MxEventPresenter : public MxMediaPresenter { +public: + MxEventPresenter(); + ~MxEventPresenter() override; + + // FUNCTION: LEGO1 0x100c2c30 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101dcc + return "MxEventPresenter"; + } + + // FUNCTION: LEGO1 0x100c2c40 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxEventPresenter::ClassName()) || MxMediaPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + MxResult PutData() override; // vtable+0x4c + virtual void CopyData(MxStreamChunk* p_chunk); // vtable+0x5c + + // SYNTHETIC: LEGO1 0x100c2d20 + // MxEventPresenter::`scalar deleting destructor' + +private: + void Init(); + + MxU8* m_data; // 0x50 +}; + +#endif // MXEVENTPRESENTER_H diff --git a/LEGO1/omni/include/mxflcpresenter.h b/LEGO1/omni/include/mxflcpresenter.h new file mode 100644 index 00000000..569fa06c --- /dev/null +++ b/LEGO1/omni/include/mxflcpresenter.h @@ -0,0 +1,41 @@ +#ifndef MXFLCPRESENTER_H +#define MXFLCPRESENTER_H + +#include "decomp.h" +#include "mxvideopresenter.h" + +#include + +// VTABLE: LEGO1 0x100dc2c0 +// SIZE 0x68 +class MxFlcPresenter : public MxVideoPresenter { +public: + MxFlcPresenter(); + ~MxFlcPresenter() override; + + // FUNCTION: LEGO1 0x1004e200 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxFlcPresenter::ClassName()) || MxVideoPresenter::IsA(p_name); + } + + // FUNCTION: LEGO1 0x100b33f0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f43c8 + return "MxFlcPresenter"; + } + + void LoadHeader(MxStreamChunk* p_chunk) override; // vtable+0x5c + void CreateBitmap() override; // vtable+0x60 + void LoadFrame(MxStreamChunk* p_chunk) override; // vtable+0x68 + void RealizePalette() override; // vtable+0x70 + + // SYNTHETIC: LEGO1 0x100b3400 + // MxFlcPresenter::`scalar deleting destructor' + +protected: + FLIC_HEADER* m_flcHeader; // 0x64 +}; + +#endif // MXFLCPRESENTER_H diff --git a/LEGO1/omni/include/mxhashtable.h b/LEGO1/omni/include/mxhashtable.h new file mode 100644 index 00000000..e15128e9 --- /dev/null +++ b/LEGO1/omni/include/mxhashtable.h @@ -0,0 +1,230 @@ +#ifndef MXHASHTABLE_H +#define MXHASHTABLE_H + +#include "mxcollection.h" +#include "mxcore.h" +#include "mxtypes.h" + +#define HASH_TABLE_INIT_SIZE 128 + +template +class MxHashTableCursor; + +template +class MxHashTableNode { +public: + MxHashTableNode(T p_obj, MxU32 p_hash, MxHashTableNode* p_prev, MxHashTableNode* p_next) + { + m_obj = p_obj; + m_hash = p_hash; + m_prev = p_prev; + m_next = p_next; + } + + // DECOMP: Should use getter and setter methods here per the style guide. + // However, LEGO1D (with no functions inlined) does not use them. + T m_obj; + MxU32 m_hash; + MxHashTableNode* m_prev; + MxHashTableNode* m_next; +}; + +template +class MxHashTable : protected MxCollection { +public: + enum Option { + e_noExpand = 0, + e_expandAll, + e_expandMultiply, + }; + + MxHashTable() + { + m_numSlots = HASH_TABLE_INIT_SIZE; + MxU32 unused = 0; + m_slots = new MxHashTableNode*[m_numSlots]; + memset(m_slots, 0, sizeof(MxHashTableNode*) * m_numSlots); + m_resizeOption = e_noExpand; + } + + ~MxHashTable() override; + + void Resize(); + void Add(T); + void DeleteAll(); + + virtual MxU32 Hash(T) { return 0; } + + friend class MxHashTableCursor; + +protected: + void NodeInsert(MxHashTableNode*); + + MxHashTableNode** m_slots; // 0x10 + MxU32 m_numSlots; // 0x14 + MxU32 m_autoResizeRatio; // 0x18 + Option m_resizeOption; // 0x1c + // FIXME: or FIXME? This qword is used as an integer or double depending + // on the value of m_resizeOption. Hard to say whether this is how the devs + // did it, but a simple cast in either direction doesn't match. + union { + MxU32 m_increaseAmount; // 0x20 + double m_increaseFactor; // 0x20 + }; +}; + +template +class MxHashTableCursor : public MxCore { +public: + MxHashTableCursor(MxHashTable* p_table) + { + m_table = p_table; + m_match = NULL; + } + + MxBool Find(T p_obj); + MxBool Current(T& p_obj); + void DeleteMatch(); + +private: + MxHashTable* m_table; + MxHashTableNode* m_match; +}; + +template +MxBool MxHashTableCursor::Find(T p_obj) +{ + MxU32 hash = m_table->Hash(p_obj); + + for (MxHashTableNode* t = m_table->m_slots[hash % m_table->m_numSlots]; t; t = t->m_next) { + if (t->m_hash == hash && !m_table->Compare(t->m_obj, p_obj)) { + m_match = t; + } + } + + return m_match != NULL; +} + +template +MxBool MxHashTableCursor::Current(T& p_obj) +{ + if (m_match) { + p_obj = m_match->m_obj; + } + + return m_match != NULL; +} + +template +void MxHashTableCursor::DeleteMatch() +{ + // Cut the matching node out of the linked list + // by updating pointer references. + if (m_match) { + if (m_match->m_prev) { + m_match->m_prev->m_next = m_match->m_next; + } + else { + // No "prev" node, so move "next" to the head of the list. + m_table->m_slots[m_match->m_hash % m_table->m_numSlots] = m_match->m_next; + } + + if (m_match->m_next) { + m_match->m_next->m_prev = m_match->m_prev; + } + + m_table->m_customDestructor(m_match->m_obj); + delete m_match; + m_table->m_count--; + } +} + +template +MxHashTable::~MxHashTable() +{ + DeleteAll(); + delete[] m_slots; +} + +template +void MxHashTable::DeleteAll() +{ + for (MxS32 i = 0; i < m_numSlots; i++) { + MxHashTableNode* next; + for (MxHashTableNode* t = m_slots[i]; t != NULL; t = next) { + next = t->m_next; + this->m_customDestructor(t->m_obj); + delete t; + } + } + + this->m_count = 0; + memset(m_slots, 0, sizeof(MxHashTableNode*) * m_numSlots); +} + +template +inline void MxHashTable::Resize() +{ + // Save a reference to the current table + // so we can walk nodes and re-insert + MxU32 oldSize = m_numSlots; + MxHashTableNode** oldTable = m_slots; + + switch (m_resizeOption) { + case e_expandAll: + m_numSlots += m_increaseAmount; + break; + case e_expandMultiply: + m_numSlots *= m_increaseFactor; + break; + } + + MxU32 unused = 0; + m_slots = new MxHashTableNode*[m_numSlots]; + memset(m_slots, 0, sizeof(MxHashTableNode*) * m_numSlots); + this->m_count = 0; + + for (MxS32 i = 0; i < oldSize; i++) { + MxHashTableNode* next; + for (MxHashTableNode* t = oldTable[i]; t != NULL; t = next) { + next = t->m_next; + NodeInsert(t); + } + } + + delete[] oldTable; +} + +template +inline void MxHashTable::NodeInsert(MxHashTableNode* p_node) +{ + MxS32 bucket = p_node->m_hash % m_numSlots; + + p_node->m_next = m_slots[bucket]; + + if (m_slots[bucket]) { + m_slots[bucket]->m_prev = p_node; + } + + m_slots[bucket] = p_node; + this->m_count++; +} + +template +inline void MxHashTable::Add(T p_newobj) +{ + if (m_resizeOption && ((this->m_count + 1) / m_numSlots) > m_autoResizeRatio) { + MxHashTable::Resize(); + } + + MxU32 hash = Hash(p_newobj); + MxU32 unused = 0; + + MxHashTableNode* node = new MxHashTableNode(p_newobj, hash, NULL, NULL); + + MxHashTable::NodeInsert(node); +} + +#undef HASH_TABLE_INIT_SIZE + +#endif // MXHASHTABLE_H diff --git a/LEGO1/omni/include/mxio.h b/LEGO1/omni/include/mxio.h new file mode 100644 index 00000000..86ef5581 --- /dev/null +++ b/LEGO1/omni/include/mxio.h @@ -0,0 +1,34 @@ +#ifndef MXIO_H +#define MXIO_H + +#include "mxtypes.h" + +// mmsystem.h requires inclusion of windows.h before +// clang-format off +#include +#include +// clang-format on + +// SIZE 0x48 +class MXIOINFO { +public: + MXIOINFO(); + ~MXIOINFO(); + + MxU16 Open(const char*, MxULong); + MxU16 Close(MxLong); + MxLong Read(void*, MxLong); + MxLong Write(void*, MxLong); + MxLong Seek(MxLong, MxLong); + MxU16 SetBuffer(char*, MxLong, MxLong); + MxU16 Flush(MxU16); + MxU16 Advance(MxU16); + MxU16 Descend(MMCKINFO*, const MMCKINFO*, MxU16); + MxU16 Ascend(MMCKINFO*, MxU16); + + // NOTE: In MXIOINFO, the `hmmio` member of MMIOINFO is used like + // an HFILE (int) instead of an HMMIO (WORD). + MMIOINFO m_info; +}; + +#endif // MXIO_H diff --git a/LEGO1/omni/include/mxlist.h b/LEGO1/omni/include/mxlist.h new file mode 100644 index 00000000..985c48d2 --- /dev/null +++ b/LEGO1/omni/include/mxlist.h @@ -0,0 +1,343 @@ +#ifndef MXLIST_H +#define MXLIST_H + +#include "mxcollection.h" +#include "mxcore.h" +#include "mxtypes.h" + +template +class MxList; +template +class MxListCursor; + +template +class MxListEntry { +public: + MxListEntry() {} + MxListEntry(T p_obj, MxListEntry* p_prev) + { + m_obj = p_obj; + m_prev = p_prev; + m_next = NULL; + } + MxListEntry(T p_obj, MxListEntry* p_prev, MxListEntry* p_next) + { + m_obj = p_obj; + m_prev = p_prev; + m_next = p_next; + } + + T GetValue() { return this->m_obj; } + MxListEntry* GetNext() { return m_next; } + MxListEntry* GetPrev() { return m_prev; } + + void SetValue(T p_obj) { m_obj = p_obj; } + void SetNext(MxListEntry* p_next) { m_next = p_next; } + void SetPrev(MxListEntry* p_prev) { m_prev = p_prev; } + +private: + T m_obj; + MxListEntry* m_prev; + MxListEntry* m_next; +}; + +// SIZE 0x18 +template +class MxList : protected MxCollection { +public: + MxList() + { + m_last = NULL; + m_first = NULL; + } + + ~MxList() override; + + void Append(T p_obj) { InsertEntry(p_obj, this->m_last, NULL); } + void Prepend(T p_obj) { InsertEntry(p_obj, NULL, this->m_first); } + void DeleteAll(MxBool p_destroy = TRUE); + MxU32 GetCount() { return this->m_count; } + + friend class MxListCursor; + using MxCollection::SetDestroy; + +protected: + MxListEntry* m_first; // 0x10 + MxListEntry* m_last; // 0x14 + + void DeleteEntry(MxListEntry*); + MxListEntry* InsertEntry(T, MxListEntry*, MxListEntry*); +}; + +// SIZE 0x18 +template +class MxPtrList : public MxList { +public: + MxPtrList(MxBool p_ownership) { SetOwnership(p_ownership); } + + static void Destroy(T* p_obj) { delete p_obj; } + + void SetOwnership(MxBool p_ownership) + { + MxCollection::SetDestroy(p_ownership ? MxPtrList::Destroy : MxCollection::Destroy); + } +}; + +// SIZE 0x10 +template +class MxListCursor : public MxCore { +public: + MxListCursor(MxList* p_list) + { + m_list = p_list; + m_match = NULL; + } + + MxBool Find(T p_obj); + void Detach(); + void Destroy(); + MxBool Next(); + MxBool Next(T& p_obj); + MxBool Prev(); + MxBool Prev(T& p_obj); + MxBool Current(T& p_obj); + MxBool First(T& p_obj); + MxBool Last(T& p_obj); + MxBool HasMatch() { return m_match != NULL; } + void SetValue(T p_obj); + MxBool Head() + { + m_match = m_list->m_first; + return m_match != NULL; + } + MxBool Tail() + { + m_match = m_list->m_last; + return m_match != NULL; + } + void Reset() { m_match = NULL; } + void Prepend(T p_newobj); + +private: + MxList* m_list; // 0x08 + MxListEntry* m_match; // 0x0c +}; + +// SIZE 0x10 +template +class MxPtrListCursor : public MxListCursor { +public: + MxPtrListCursor(MxPtrList* p_list) : MxListCursor(p_list) {} +}; + +template +MxList::~MxList() +{ + DeleteAll(); +} + +template +inline void MxList::DeleteAll(MxBool p_destroy) +{ + for (MxListEntry* t = m_first;;) { + if (!t) { + break; + } + + MxListEntry* next = t->GetNext(); + + if (p_destroy) { + this->m_customDestructor(t->GetValue()); + } + + delete t; + t = next; + } + + this->m_count = 0; + m_last = NULL; + m_first = NULL; +} + +template +inline MxListEntry* MxList::InsertEntry(T p_newobj, MxListEntry* p_prev, MxListEntry* p_next) +{ + MxListEntry* newEntry = new MxListEntry(p_newobj, p_prev, p_next); + + if (p_prev) { + p_prev->SetNext(newEntry); + } + else { + this->m_first = newEntry; + } + + if (p_next) { + p_next->SetPrev(newEntry); + } + else { + this->m_last = newEntry; + } + + this->m_count++; + return newEntry; +} + +template +inline void MxList::DeleteEntry(MxListEntry* p_match) +{ + if (p_match->GetPrev()) { + p_match->GetPrev()->SetNext(p_match->GetNext()); + } + else { + m_first = p_match->GetNext(); + } + + if (p_match->GetNext()) { + p_match->GetNext()->SetPrev(p_match->GetPrev()); + } + else { + m_last = p_match->GetPrev(); + } + + delete p_match; + this->m_count--; +} + +template +inline MxBool MxListCursor::Find(T p_obj) +{ + for (m_match = m_list->m_first; m_match && m_list->Compare(m_match->GetValue(), p_obj); + m_match = m_match->GetNext()) { + } + + return m_match != NULL; +} + +template +inline void MxListCursor::Detach() +{ + if (m_match) { + m_list->DeleteEntry(m_match); + m_match = NULL; + } +} + +template +inline void MxListCursor::Destroy() +{ + if (m_match) { + m_list->m_customDestructor(m_match->GetValue()); + m_list->DeleteEntry(m_match); + m_match = NULL; + } +} + +template +inline MxBool MxListCursor::Next() +{ + if (!m_match) { + m_match = m_list->m_first; + } + else { + m_match = m_match->GetNext(); + } + + return m_match != NULL; +} + +template +inline MxBool MxListCursor::Next(T& p_obj) +{ + if (!m_match) { + m_match = m_list->m_first; + } + else { + m_match = m_match->GetNext(); + } + + if (m_match) { + p_obj = m_match->GetValue(); + } + + return m_match != NULL; +} + +template +inline MxBool MxListCursor::Prev() +{ + if (!m_match) { + m_match = m_list->m_last; + } + else { + m_match = m_match->GetPrev(); + } + + return m_match != NULL; +} + +template +inline MxBool MxListCursor::Prev(T& p_obj) +{ + if (!m_match) { + m_match = m_list->m_last; + } + else { + m_match = m_match->GetPrev(); + } + + if (m_match) { + p_obj = m_match->GetValue(); + } + + return m_match != NULL; +} + +template +inline MxBool MxListCursor::Current(T& p_obj) +{ + if (m_match) { + p_obj = m_match->GetValue(); + } + + return m_match != NULL; +} + +template +inline MxBool MxListCursor::First(T& p_obj) +{ + m_match = m_list->m_first; + if (m_match) { + p_obj = m_match->GetValue(); + } + + return m_match != NULL; +} + +template +inline MxBool MxListCursor::Last(T& p_obj) +{ + m_match = m_list->m_last; + if (m_match) { + p_obj = m_match->GetValue(); + } + + return m_match != NULL; +} + +template +inline void MxListCursor::SetValue(T p_obj) +{ + if (m_match) { + m_match->SetValue(p_obj); + } +} + +template +inline void MxListCursor::Prepend(T p_newobj) +{ + if (m_match) { + m_list->InsertEntry(p_newobj, m_match->GetPrev(), m_match); + } +} + +#endif // MXLIST_H diff --git a/LEGO1/omni/include/mxloopingflcpresenter.h b/LEGO1/omni/include/mxloopingflcpresenter.h new file mode 100644 index 00000000..1bc76e18 --- /dev/null +++ b/LEGO1/omni/include/mxloopingflcpresenter.h @@ -0,0 +1,37 @@ +#ifndef MXLOOPINGFLCPRESENTER_H +#define MXLOOPINGFLCPRESENTER_H + +#include "decomp.h" +#include "mxflcpresenter.h" + +// VTABLE: LEGO1 0x100dc480 +// SIZE 0x6c +class MxLoopingFlcPresenter : public MxFlcPresenter { +public: + MxLoopingFlcPresenter(); + ~MxLoopingFlcPresenter() override; + + // FUNCTION: LEGO1 0x100b4380 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101e20 + return "MxLoopingFlcPresenter"; + } + + void RepeatingTickle() override; // vtable+0x24 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + void NextFrame() override; // vtable+0x64 + virtual void VTable0x88(); // vtable+0x88 + + // SYNTHETIC: LEGO1 0x100b4390 + // MxLoopingFlcPresenter::`scalar deleting destructor' + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + + MxLong m_elapsedDuration; // 0x68 +}; + +#endif // MXLOOPINGFLCPRESENTER_H diff --git a/LEGO1/omni/include/mxloopingmidipresenter.h b/LEGO1/omni/include/mxloopingmidipresenter.h new file mode 100644 index 00000000..1a9eff73 --- /dev/null +++ b/LEGO1/omni/include/mxloopingmidipresenter.h @@ -0,0 +1,31 @@ +#ifndef MXLOOPINGMIDIPRESENTER_H +#define MXLOOPINGMIDIPRESENTER_H + +#include "mxmidipresenter.h" + +// VTABLE: LEGO1 0x100dc240 +// SIZE 0x58 +class MxLoopingMIDIPresenter : public MxMIDIPresenter { +public: + // FUNCTION: LEGO1 0x100b1830 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101de0 + return "MxLoopingMIDIPresenter"; + } + + // FUNCTION: LEGO1 0x100b1840 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxLoopingMIDIPresenter::ClassName()) || MxMIDIPresenter::IsA(p_name); + } + + void StreamingTickle() override; // vtable+0x20 + void DoneTickle() override; // vtable+0x2c + MxResult PutData() override; // vtable+0x4c +}; + +// SYNTHETIC: LEGO1 0x100b19c0 +// MxLoopingMIDIPresenter::`scalar deleting destructor' + +#endif // MXLOOPINGMIDIPRESENTER_H diff --git a/LEGO1/omni/include/mxloopingsmkpresenter.h b/LEGO1/omni/include/mxloopingsmkpresenter.h new file mode 100644 index 00000000..de0f506f --- /dev/null +++ b/LEGO1/omni/include/mxloopingsmkpresenter.h @@ -0,0 +1,38 @@ +#ifndef MXLOOPINGSMKPRESENTER_H +#define MXLOOPINGSMKPRESENTER_H + +#include "decomp.h" +#include "mxsmkpresenter.h" + +// VTABLE: LEGO1 0x100dc540 +// SIZE 0x724 +class MxLoopingSmkPresenter : public MxSmkPresenter { +public: + MxLoopingSmkPresenter(); + ~MxLoopingSmkPresenter() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x100b4920 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101e08 + return "MxLoopingSmkPresenter"; + } + + void RepeatingTickle() override; // vtable+0x24 + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + void NextFrame() override; // vtable+0x64 + void VTable0x88() override; // vtable+0x88 + virtual void VTable0x8c(); // vtable+0x8c + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + + MxLong m_elapsedDuration; // 0x720 +}; + +// SYNTHETIC: LEGO1 0x100b4930 +// MxLoopingSmkPresenter::`scalar deleting destructor' + +#endif // MXLOOPINGSMKPRESENTER_H diff --git a/LEGO1/omni/include/mxmediamanager.h b/LEGO1/omni/include/mxmediamanager.h new file mode 100644 index 00000000..5fd2390c --- /dev/null +++ b/LEGO1/omni/include/mxmediamanager.h @@ -0,0 +1,36 @@ +#ifndef MXMEDIAMANGER_H +#define MXMEDIAMANGER_H + +#include "mxcore.h" +#include "mxcriticalsection.h" +#include "mxpresenterlist.h" +#include "mxtypes.h" + +class MxThread; + +// VTABLE: LEGO1 0x100dc6b0 +// SIZE 0x2c +class MxMediaManager : public MxCore { +public: + MxMediaManager(); + ~MxMediaManager() override; + + MxResult Tickle() override; // vtable+08 + virtual MxResult InitPresenters(); // vtable+14 + virtual void Destroy(); // vtable+18 + virtual void RegisterPresenter(MxPresenter& p_presenter); // vtable+1c + virtual void UnregisterPresenter(MxPresenter& p_presenter); // vtable+20 + virtual void StopPresenters(); // vtable+24 + + MxResult Init(); + + // SYNTHETIC: LEGO1 0x100b8540 + // MxMediaManager::`scalar deleting destructor' + +protected: + MxPresenterList* m_presenters; // 0x08 + MxThread* m_thread; // 0x0c + MxCriticalSection m_criticalSection; // 0x10 +}; + +#endif // MXMEDIAMANGER_H diff --git a/LEGO1/omni/include/mxmediapresenter.h b/LEGO1/omni/include/mxmediapresenter.h new file mode 100644 index 00000000..e78ac194 --- /dev/null +++ b/LEGO1/omni/include/mxmediapresenter.h @@ -0,0 +1,74 @@ +#ifndef MXMEDIAPRESENTER_H +#define MXMEDIAPRESENTER_H + +#include "decomp.h" +#include "mxpresenter.h" +#include "mxstreamchunklist.h" + +class MxDSSubscriber; + +// VTABLE: LEGO1 0x100d4cd8 +// SIZE 0x50 +class MxMediaPresenter : public MxPresenter { +public: + inline MxMediaPresenter() { Init(); } + + // FUNCTION: LEGO1 0x1000c550 + ~MxMediaPresenter() override { Destroy(TRUE); } + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1000c5c0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f074c + return "MxMediaPresenter"; + } + + // FUNCTION: LEGO1 0x1000c5d0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxMediaPresenter::ClassName()) || MxPresenter::IsA(p_name); + } + + void StreamingTickle() override; // vtable+0x20 + void RepeatingTickle() override; // vtable+0x24 + void DoneTickle() override; // vtable+0x2c + + // FUNCTION: LEGO1 0x1000c5b0 + void Destroy() override { Destroy(FALSE); } // vtable+0x38 + + MxResult StartAction(MxStreamController*, MxDSAction*) override; // vtable+0x3c + void EndAction() override; // vtable+0x40 + void Enable(MxBool p_enable) override; // vtable+0x54 + virtual void LoopChunk(MxStreamChunk* p_chunk); // vtable+0x58 + + MxStreamChunk* CurrentChunk(); + MxStreamChunk* NextChunk(); + + // SYNTHETIC: LEGO1 0x1000c680 + // MxMediaPresenter::`scalar deleting destructor' + +protected: + MxDSSubscriber* m_subscriber; // 0x40 + MxStreamChunkList* m_loopingChunks; // 0x44 + MxStreamChunkListCursor* m_loopingChunkCursor; // 0x48 + MxStreamChunk* m_currentChunk; // 0x4c + + void Init(); + void Destroy(MxBool p_fromDestructor); +}; + +// SYNTHETIC: LEGO1 0x100b46e0 +// MxStreamChunkListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b4750 +// MxListCursor::~MxListCursor + +// SYNTHETIC: LEGO1 0x100b47a0 +// MxListCursor::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x100b4810 +// MxStreamChunkListCursor::~MxStreamChunkListCursor + +#endif // MXMEDIAPRESENTER_H diff --git a/LEGO1/omni/include/mxmemorypool.h b/LEGO1/omni/include/mxmemorypool.h new file mode 100644 index 00000000..a5023457 --- /dev/null +++ b/LEGO1/omni/include/mxmemorypool.h @@ -0,0 +1,86 @@ +#ifndef MXMEMORYPOOL_H +#define MXMEMORYPOOL_H + +#include "decomp.h" +#include "mxbitset.h" +#include "mxtypes.h" + +#include + +template +class MxMemoryPool { +public: + MxMemoryPool() : m_pool(NULL), m_blockSize(BS) {} + ~MxMemoryPool() { delete[] m_pool; } + + MxResult Allocate(); + MxU8* Get(); + void Release(MxU8*); + + MxU32 GetPoolSize() const { return m_blockRef.Size(); } + +private: + MxU8* m_pool; // 0x00 + MxU32 m_blockSize; // 0x04 + MxBitset m_blockRef; // 0x08 +}; + +template +MxResult MxMemoryPool::Allocate() +{ + assert(m_pool == NULL); + assert(m_blockSize); + assert(m_blockRef.Size()); + + m_pool = new MxU8[GetPoolSize() * m_blockSize * 1024]; + assert(m_pool); + + return m_pool ? SUCCESS : FAILURE; +} + +template +MxU8* MxMemoryPool::Get() +{ + assert(m_pool != NULL); + assert(m_blockSize); + assert(m_blockRef.Size()); + + for (MxU32 i = 0; i < GetPoolSize(); i++) { + if (!m_blockRef[i]) { + m_blockRef[i].Flip(); + +#ifdef _DEBUG + // TODO: This is actually some debug print function, but + // we just need any func with variatic args to eliminate diff noise. + printf("Get> %d pool: busy %d blocks\n", m_blockSize, m_blockRef.Count()); +#endif + + return &m_pool[i * m_blockSize * 1024]; + } + } + + return NULL; +} + +template +void MxMemoryPool::Release(MxU8* p_buf) +{ + assert(m_pool != NULL); + assert(m_blockSize); + assert(m_blockRef.Size()); + + MxU32 i = (MxU32) (p_buf - m_pool) / (m_blockSize * 1024); + + assert(i >= 0 && i < GetPoolSize()); + assert(m_blockRef[i]); + + if (m_blockRef[i]) { + m_blockRef[i].Flip(); + } + +#ifdef _DEBUG + printf("Release> %d pool: busy %d blocks\n", m_blockSize, m_blockRef.Count()); +#endif +} + +#endif // MXMEMORYPOOL_H diff --git a/LEGO1/omni/include/mxmidipresenter.h b/LEGO1/omni/include/mxmidipresenter.h new file mode 100644 index 00000000..adab6fe2 --- /dev/null +++ b/LEGO1/omni/include/mxmidipresenter.h @@ -0,0 +1,48 @@ +#ifndef MXMIDIPRESENTER_H +#define MXMIDIPRESENTER_H + +#include "mxmusicpresenter.h" + +class MxStreamChunk; + +// VTABLE: LEGO1 0x100dca20 +// SIZE 0x58 +class MxMIDIPresenter : public MxMusicPresenter { +public: + MxMIDIPresenter(); + ~MxMIDIPresenter() override; + + // FUNCTION: LEGO1 0x100c2650 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101df8 + return "MxMIDIPresenter"; + } + + // FUNCTION: LEGO1 0x100c2660 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxMIDIPresenter::ClassName()) || MxMusicPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + void DoneTickle() override; // vtable+0x2c + void Destroy() override; // vtable+0x38 + void EndAction() override; // vtable+0x40 + MxResult PutData() override; // vtable+0x4c + void SetVolume(MxS32 p_volume) override; // vtable+0x60 + + // SYNTHETIC: LEGO1 0x100c27a0 + // MxMIDIPresenter::`scalar deleting destructor' + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + +protected: + MxStreamChunk* m_chunk; // 0x54 +}; + +#endif // MXMIDIPRESENTER_H diff --git a/LEGO1/omni/include/mxmisc.h b/LEGO1/omni/include/mxmisc.h new file mode 100644 index 00000000..0f149a02 --- /dev/null +++ b/LEGO1/omni/include/mxmisc.h @@ -0,0 +1,33 @@ +#ifndef MXMISC_H +#define MXMISC_H + +#include "mxtypes.h" + +class MxAtomSet; +class MxDSAction; +class MxEventManager; +class MxMusicManager; +class MxNotificationManager; +class MxObjectFactory; +class MxSoundManager; +class MxStreamer; +class MxTickleManager; +class MxTimer; +class MxVariableTable; +class MxVideoManager; + +MxTickleManager* TickleManager(); +MxTimer* Timer(); +MxStreamer* Streamer(); +MxSoundManager* MSoundManager(); +MxVariableTable* VariableTable(); +MxMusicManager* MusicManager(); +MxEventManager* EventManager(); +MxResult Start(MxDSAction*); +MxNotificationManager* NotificationManager(); +MxVideoManager* MVideoManager(); +MxAtomSet* AtomSet(); +MxObjectFactory* ObjectFactory(); +void DeleteObject(MxDSAction& p_dsAction); + +#endif // MXMISC_H diff --git a/LEGO1/omni/include/mxmusicmanager.h b/LEGO1/omni/include/mxmusicmanager.h new file mode 100644 index 00000000..1107e7e3 --- /dev/null +++ b/LEGO1/omni/include/mxmusicmanager.h @@ -0,0 +1,61 @@ +#ifndef MXMUSICMANAGER_H +#define MXMUSICMANAGER_H + +#include "decomp.h" +#include "mxaudiomanager.h" + +#include + +// VTABLE: LEGO1 0x100dc930 +// SIZE 0x58 +class MxMusicManager : public MxAudioManager { +public: + MxMusicManager(); + ~MxMusicManager() override; + + void Destroy() override; // vtable+18 + void SetVolume(MxS32 p_volume) override; // vtable+2c + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+30 + + inline MxBool GetMIDIInitialized() { return m_midiInitialized; } + inline void GetMIDIVolume(DWORD& p_volume) + { + if (midiOutGetVolume((HMIDIOUT) m_midiStreamH, &p_volume)) { + p_volume = CalculateVolume(100); + } + } + + MxResult ResetStream(); + void ResetBuffer(); + MxResult InitializeMIDI(MxU8* p_data, MxS32 p_loopCount); + void DeinitializeMIDI(); + void SetMultiplier(MxS32 p_multiplier); + +private: + void Destroy(MxBool p_fromDestructor); + + MxS32 CalculateVolume(MxS32 p_volume); + void SetMIDIVolume(); + + static void CALLBACK MidiCallbackProc(HDRVR p_hdrvr, UINT p_uMsg, DWORD p_dwUser, DWORD p_dw1, DWORD p_dw2); + + HMIDISTRM m_midiStreamH; // 0x30 + MxBool m_midiInitialized; // 0x34 + MxU32 m_bufferSize; // 0x38 + MxU32 m_bufferCurrentSize; // 0x3c + MxU8* m_bufferOffset; // 0x40 + MxU8* m_bufferCurrentOffset; // 0x44 + MxU32 m_loopCount; // 0x48 + MIDIHDR* m_midiHdrP; // 0x4c + MxS32 m_multiplier; // 0x50 + DWORD m_midiVolume; // 0x54 + + // SYNTHETIC: LEGO1 0x100c0610 + // MxMusicManager::`scalar deleting destructor' + +protected: + void Init(); + void InitData(); +}; + +#endif // MXMUSICMANAGER_H diff --git a/LEGO1/omni/include/mxmusicpresenter.h b/LEGO1/omni/include/mxmusicpresenter.h new file mode 100644 index 00000000..a66afa78 --- /dev/null +++ b/LEGO1/omni/include/mxmusicpresenter.h @@ -0,0 +1,37 @@ +#ifndef MXMUSICPRESENTER_H +#define MXMUSICPRESENTER_H + +#include "mxaudiopresenter.h" + +// VTABLE: LEGO1 0x100dc9b8 +// SIZE 0x54 +class MxMusicPresenter : public MxAudioPresenter { +public: + MxMusicPresenter(); + ~MxMusicPresenter() override; + + // FUNCTION: LEGO1 0x100c23a0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101e48 + return "MxMusicPresenter"; + } + + // FUNCTION: LEGO1 0x100c23b0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxMusicPresenter::ClassName()) || MxAudioPresenter::IsA(p_name); + } + + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + + // SYNTHETIC: LEGO1 0x100c24c0 + // MxMusicPresenter::`scalar deleting destructor' + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); +}; + +#endif // MXMUSICPRESENTER_H diff --git a/LEGO1/omni/include/mxnextactiondatastart.h b/LEGO1/omni/include/mxnextactiondatastart.h new file mode 100644 index 00000000..0f08ec75 --- /dev/null +++ b/LEGO1/omni/include/mxnextactiondatastart.h @@ -0,0 +1,45 @@ +#ifndef MXNEXTACTIONDATASTART_H +#define MXNEXTACTIONDATASTART_H + +#include "mxcore.h" + +// VTABLE: LEGO1 0x100dc9a0 +// SIZE 0x14 +class MxNextActionDataStart : public MxCore { +public: + // inlined constructor at 0x100c1847 + inline MxNextActionDataStart(MxU32 p_objectId, MxS16 p_unk0x24, MxU32 p_data) + { + m_objectId = p_objectId; + m_unk0x24 = p_unk0x24; + m_data = p_data; + } + + // FUNCTION: LEGO1 0x100c1900 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x101025a0 + return "MxNextActionDataStart"; + } + + // FUNCTION: LEGO1 0x100c1910 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxNextActionDataStart::ClassName()) || MxCore::IsA(p_name); + } + + inline MxU32 GetObjectId() const { return m_objectId; } + inline MxS16 GetUnknown24() const { return m_unk0x24; } + inline MxU32 GetData() const { return m_data; } + inline void SetData(MxU32 p_data) { m_data = p_data; } + + // SYNTHETIC: LEGO1 0x100c1990 + // MxNextActionDataStart::`scalar deleting destructor' + +private: + MxU32 m_objectId; // 0x08 + MxS16 m_unk0x24; // 0x0c + MxU32 m_data; // 0x10 +}; + +#endif // MXNEXTACTIONDATASTART_H diff --git a/LEGO1/omni/include/mxnotificationmanager.h b/LEGO1/omni/include/mxnotificationmanager.h new file mode 100644 index 00000000..5b1acd50 --- /dev/null +++ b/LEGO1/omni/include/mxnotificationmanager.h @@ -0,0 +1,97 @@ +#ifndef MXNOTIFICATIONMANAGER_H +#define MXNOTIFICATIONMANAGER_H + +#include "mxcore.h" +#include "mxcriticalsection.h" +#include "mxstl/stlcompat.h" +#include "mxtypes.h" + +class MxNotificationParam; + +class MxNotification { +public: + MxNotification(MxCore* p_target, const MxNotificationParam& p_param); + ~MxNotification(); + + inline MxCore* GetTarget() { return m_target; } + inline MxNotificationParam* GetParam() { return m_param; } + +private: + MxCore* m_target; // 0x00 + MxNotificationParam* m_param; // 0x04 +}; + +class MxIdList : public list {}; + +class MxNotificationPtrList : public list {}; + +// VTABLE: LEGO1 0x100dc078 +class MxNotificationManager : public MxCore { +private: + MxNotificationPtrList* m_queue; // 0x08 + MxNotificationPtrList* m_sendList; // 0x0c + MxCriticalSection m_lock; // 0x10 + MxS32 m_unk0x2c; // 0x2c + MxIdList m_listenerIds; // 0x30 + MxBool m_active; // 0x3c + +public: + MxNotificationManager(); + ~MxNotificationManager() override; // vtable+0x00 (scalar deleting destructor) + + MxResult Tickle() override; // vtable+0x08 + // TODO: Where does this method come from? + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x14 + void Register(MxCore* p_listener); + void Unregister(MxCore* p_listener); + MxResult Send(MxCore* p_listener, const MxNotificationParam& p_param); + + inline MxNotificationPtrList* GetQueue() { return m_queue; } + + // FUNCTION: BETA10 0x10132270 + inline void SetActive(MxBool p_active) { m_active = p_active; } + + // FUNCTION: BETA10 0x10132230 + inline MxBool IsEmpty() const { return m_queue ? m_queue->empty() : TRUE; } + + // SYNTHETIC: LEGO1 0x100ac390 + // MxNotificationManager::`scalar deleting destructor' + +private: + void FlushPending(MxCore* p_listener); +}; + +// TEMPLATE: LEGO1 0x100ac320 +// list >::~list > + +// FUNCTION: LEGO1 0x100ac3b0 +// MxIdList::~MxIdList + +// TEMPLATE: LEGO1 0x100ac400 +// List::~List + +// TEMPLATE: LEGO1 0x100ac540 +// List::~List + +// TEMPLATE: LEGO1 0x100ac590 +// list >::~list > + +// TEMPLATE: LEGO1 0x100acbf0 +// list >::begin + +// TEMPLATE: LEGO1 0x100acc00 +// list >::insert + +// TEMPLATE: LEGO1 0x100acc50 +// list >::erase + +// TEMPLATE: LEGO1 0x100acca0 +// list >::_Buynode + +// SYNTHETIC: LEGO1 0x100accd0 +// MxNotificationPtrList::~MxNotificationPtrList + +// TEMPLATE: BETA10 0x10129670 +// list >::empty + +#endif // MXNOTIFICATIONMANAGER_H diff --git a/LEGO1/omni/include/mxnotificationparam.h b/LEGO1/omni/include/mxnotificationparam.h new file mode 100644 index 00000000..afe2282b --- /dev/null +++ b/LEGO1/omni/include/mxnotificationparam.h @@ -0,0 +1,66 @@ +#ifndef MXNOTIFICATIONPARAM_H +#define MXNOTIFICATIONPARAM_H + +#include "compat.h" +#include "mxparam.h" +#include "mxtypes.h" + +class MxCore; + +// Several of those should be defined in LegoOmni +enum NotificationId { + c_notificationType0 = 0, + c_notificationStartAction = 1, // 100dc210:100d8350 + c_notificationEndAction = 2, // 100d8358:100d8350 + c_notificationType4 = 4, // 100dc208:100d8350 + c_notificationPresenter = 5, + c_notificationStreamer = 6, // 100dc760 + c_notificationKeyPress = 7, // 100d6aa0 + c_notificationButtonUp = 8, // 100d6aa0 + c_notificationButtonDown = 9, // 100d6aa0 + c_notificationMouseMove = 10, // 100d6aa0 + c_notificationType11 = 11, // 100d6aa0 + c_notificationDragEnd = 12, + c_notificationDragStart = 13, + c_notificationDrag = 14, + c_notificationTimer = 15, // 100d6aa0 + c_notificationClick = 17, + c_notificationEndAnim = 18, // 100d7e80 + c_notificationType19 = 19, // 100d6230 + c_notificationType20 = 20, + c_notificationNewPresenter = 21, + c_notificationType22 = 22, + c_notificationType23 = 23, + c_notificationTransitioned = 24 +}; + +// VTABLE: LEGO1 0x100d56e0 +// SIZE 0x0c +class MxNotificationParam : public MxParam { +public: + inline MxNotificationParam(NotificationId p_type, MxCore* p_sender) : MxParam(), m_type(p_type), m_sender(p_sender) + { + } + + // FUNCTION: LEGO1 0x10010390 + virtual MxNotificationParam* Clone() const { return new MxNotificationParam(m_type, m_sender); } // vtable+0x04 + + inline NotificationId GetNotification() const { return m_type; } + inline MxCore* GetSender() const { return m_sender; } + inline NotificationId GetType() const { return m_type; } + + inline void SetType(NotificationId p_type) { m_type = p_type; } + inline void SetSender(MxCore* p_sender) { m_sender = p_sender; } + +protected: + NotificationId m_type; // 0x04 + MxCore* m_sender; // 0x08 +}; + +// SYNTHETIC: LEGO1 0x10010430 +// MxNotificationParam::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100104a0 +// MxNotificationParam::~MxNotificationParam + +#endif // MXNOTIFICATIONPARAM_H diff --git a/LEGO1/omni/include/mxobjectfactory.h b/LEGO1/omni/include/mxobjectfactory.h new file mode 100644 index 00000000..882ddc55 --- /dev/null +++ b/LEGO1/omni/include/mxobjectfactory.h @@ -0,0 +1,51 @@ +#ifndef MXOBJECTFACTORY_H +#define MXOBJECTFACTORY_H + +#include "mxatom.h" +#include "mxcore.h" + +#define FOR_MXOBJECTFACTORY_OBJECTS(X) \ + X(MxPresenter) \ + X(MxCompositePresenter) \ + X(MxVideoPresenter) \ + X(MxFlcPresenter) \ + X(MxSmkPresenter) \ + X(MxStillPresenter) \ + X(MxWavePresenter) \ + X(MxMIDIPresenter) \ + X(MxEventPresenter) \ + X(MxLoopingFlcPresenter) \ + X(MxLoopingSmkPresenter) \ + X(MxLoopingMIDIPresenter) + +// VTABLE: LEGO1 0x100dc220 +class MxObjectFactory : public MxCore { +public: + MxObjectFactory(); + + // FUNCTION: LEGO1 0x10008f70 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0730 + return "MxObjectFactory"; + } + + // FUNCTION: LEGO1 0x10008f80 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxObjectFactory::ClassName()) || MxCore::IsA(p_name); + } + + virtual MxCore* Create(const char* p_name); // vtable+0x14 + virtual void Destroy(MxCore* p_object); // vtable+0x18 + + // SYNTHETIC: LEGO1 0x100b1160 + // MxObjectFactory::`scalar deleting destructor' + +private: +#define X(V) MxAtomId m_id##V; + FOR_MXOBJECTFACTORY_OBJECTS(X) +#undef X +}; + +#endif // MXOBJECTFACTORY_H diff --git a/LEGO1/omni/include/mxomni.h b/LEGO1/omni/include/mxomni.h new file mode 100644 index 00000000..cb32e8c6 --- /dev/null +++ b/LEGO1/omni/include/mxomni.h @@ -0,0 +1,121 @@ +#ifndef MXOMNI_H +#define MXOMNI_H + +#include "mxcore.h" +#include "mxcriticalsection.h" +#include "mxstring.h" + +class MxAtomSet; +class MxDSAction; +class MxEntity; +class MxEventManager; +class MxMusicManager; +class MxNotificationManager; +class MxNotificationParam; +class MxObjectFactory; +class MxOmniCreateParam; +class MxPresenter; +class MxSoundManager; +class MxStreamer; +class MxStreamController; +class MxTickleManager; +class MxTimer; +class MxVariableTable; +class MxVideoManager; + +// VTABLE: LEGO1 0x100dc168 +// SIZE 0x68 +class MxOmni : public MxCore { +public: + static void DestroyInstance(); + static const char* GetCD(); + static const char* GetHD(); + static MxOmni* GetInstance(); + static MxBool IsSound3D(); + static void SetCD(const char* p_cd); + static void SetHD(const char* p_hd); + static void SetSound3D(MxBool p_use3dSound); + + MxOmni(); + ~MxOmni() override; + + MxLong Notify(MxParam& p_param) override; // vtable+04 + virtual void Init(); // vtable+14 + virtual MxResult Create(MxOmniCreateParam& p_param); // vtable+18 + virtual void Destroy(); // vtable+1c + virtual MxResult Start(MxDSAction* p_dsAction); // vtable+20 + virtual void DeleteObject(MxDSAction& p_dsAction); // vtable+24 + virtual MxBool DoesEntityExist(MxDSAction& p_dsAction); // vtable+28 + virtual MxResult CreatePresenter(MxStreamController* p_controller, MxDSAction& p_action); // vtable+2c + virtual MxEntity* AddToWorld(const char*, MxS32, MxPresenter*); // vtable+30 + virtual void NotifyCurrentEntity(const MxNotificationParam& p_param); // vtable+34 + virtual void StartTimer(); // vtable+38 + virtual void StopTimer(); // vtable+3c + + // FUNCTION: LEGO1 0x10058a90 + virtual MxBool IsTimerRunning() { return m_timerRunning; } // vtable+40 + + static void SetInstance(MxOmni* p_instance); + static MxBool ActionSourceEquals(MxDSAction* p_action, const char* p_name); + + HWND GetWindowHandle() const { return this->m_windowHandle; } + + // FUNCTION: BETA10 0x10125100 + MxObjectFactory* GetObjectFactory() const { return this->m_objectFactory; } + + // FUNCTION: BETA10 0x10125120 + MxNotificationManager* GetNotificationManager() const { return this->m_notificationManager; } + + // FUNCTION: BETA10 0x10125140 + MxTickleManager* GetTickleManager() const { return this->m_tickleManager; } + + // FUNCTION: BETA10 0x10125160 + MxTimer* GetTimer() const { return this->m_timer; } + + // FUNCTION: BETA10 0x101251a0 + MxStreamer* GetStreamer() const { return this->m_streamer; } + + // FUNCTION: BETA10 0x100e5250 + MxSoundManager* GetSoundManager() const { return this->m_soundManager; } + + // FUNCTION: BETA10 0x1009e860 + MxVideoManager* GetVideoManager() const { return this->m_videoManager; } + + // FUNCTION: BETA10 0x101251c0 + MxVariableTable* GetVariableTable() const { return this->m_variableTable; } + + // FUNCTION: BETA10 0x101251e0 + MxMusicManager* GetMusicManager() const { return this->m_musicManager; } + + // FUNCTION: BETA10 0x10125200 + MxEventManager* GetEventManager() const { return this->m_eventManager; } + + // FUNCTION: BETA10 0x10125180 + MxAtomSet* GetAtomSet() const { return this->m_atomSet; } + + MxLong HandleEndAction(MxParam& p_param); + + // SYNTHETIC: LEGO1 0x100aefd0 + // MxOmni::`scalar deleting destructor' + +protected: + static MxOmni* g_instance; + + MxString m_mediaPath; // 0x08 + HWND m_windowHandle; // 0x18 + MxObjectFactory* m_objectFactory; // 0x1c + MxVariableTable* m_variableTable; // 0x20 + MxTickleManager* m_tickleManager; // 0x24 + MxNotificationManager* m_notificationManager; // 0x28 + MxVideoManager* m_videoManager; // 0x2c + MxSoundManager* m_soundManager; // 0x30 + MxMusicManager* m_musicManager; // 0x34 + MxEventManager* m_eventManager; // 0x38 + MxTimer* m_timer; // 0x3c + MxStreamer* m_streamer; // 0x40 + MxAtomSet* m_atomSet; // 0x44 + MxCriticalSection m_criticalSection; // 0x48 + MxBool m_timerRunning; // 0x64 +}; + +#endif // MXOMNI_H diff --git a/LEGO1/omni/include/mxomnicreateflags.h b/LEGO1/omni/include/mxomnicreateflags.h new file mode 100644 index 00000000..561af2a1 --- /dev/null +++ b/LEGO1/omni/include/mxomnicreateflags.h @@ -0,0 +1,58 @@ +#ifndef MXOMNICREATEFLAGS_H +#define MXOMNICREATEFLAGS_H + +#include "mxtypes.h" + +// SIZE 0x02 +class MxOmniCreateFlags { +public: + MxOmniCreateFlags(); + + // FUNCTION: BETA10 0x10092b50 + inline void CreateObjectFactory(MxBool p_enable) { this->m_flags1.m_bit0 = p_enable; } + + // FUNCTION: BETA10 0x10092b90 + inline void CreateTickleManager(MxBool p_enable) { this->m_flags1.m_bit2 = p_enable; } + + // FUNCTION: BETA10 0x10092bd0 + inline void CreateVideoManager(MxBool p_enable) { this->m_flags1.m_bit4 = p_enable; } + + // FUNCTION: BETA10 0x10092c10 + inline void CreateSoundManager(MxBool p_enable) { this->m_flags1.m_bit5 = p_enable; } + + // FUNCTION: BETA10 0x10130cd0 + inline const MxBool CreateObjectFactory() const { return this->m_flags1.m_bit0; } + + // FUNCTION: BETA10 0x10130cf0 + inline const MxBool CreateVariableTable() const { return this->m_flags1.m_bit1; } + + // FUNCTION: BETA10 0x10130d10 + inline const MxBool CreateTickleManager() const { return this->m_flags1.m_bit2; } + + // FUNCTION: BETA10 0x10130d30 + inline const MxBool CreateNotificationManager() const { return this->m_flags1.m_bit3; } + + // FUNCTION: BETA10 0x10130d50 + inline const MxBool CreateVideoManager() const { return this->m_flags1.m_bit4; } + + // FUNCTION: BETA10 0x10130d70 + inline const MxBool CreateSoundManager() const { return this->m_flags1.m_bit5; } + + // FUNCTION: BETA10 0x10130d90 + inline const MxBool CreateMusicManager() const { return this->m_flags1.m_bit6; } + + // FUNCTION: BETA10 0x10130db0 + inline const MxBool CreateEventManager() const { return this->m_flags1.m_bit7; } + + // FUNCTION: BETA10 0x10130dd0 + inline const MxBool CreateTimer() const { return this->m_flags2.m_bit1; } + + // FUNCTION: BETA10 0x10130e00 + inline const MxBool CreateStreamer() const { return this->m_flags2.m_bit2; } + +private: + FlagBitfield m_flags1; + FlagBitfield m_flags2; +}; + +#endif // MXOMNICREATEFLAGS_H diff --git a/LEGO1/omni/include/mxomnicreateparam.h b/LEGO1/omni/include/mxomnicreateparam.h new file mode 100644 index 00000000..338767bb --- /dev/null +++ b/LEGO1/omni/include/mxomnicreateparam.h @@ -0,0 +1,45 @@ +#ifndef MXOMNICREATEPARAM_H +#define MXOMNICREATEPARAM_H + +#include "mxomnicreateflags.h" +#include "mxparam.h" +#include "mxstring.h" +#include "mxvideoparam.h" + +#include + +// VTABLE: LEGO1 0x100dc218 +// VTABLE: BETA10 0x101c1ca8 +class MxOmniCreateParam : public MxParam { +public: + MxOmniCreateParam( + const char* p_mediaPath, + struct HWND__* p_windowHandle, + MxVideoParam& p_vparam, + MxOmniCreateFlags p_flags + ); + + // FUNCTION: BETA10 0x10092cb0 + MxOmniCreateFlags& CreateFlags() { return this->m_createFlags; } + + const MxString& GetMediaPath() const { return m_mediaPath; } + const HWND GetWindowHandle() const { return m_windowHandle; } + MxVideoParam& GetVideoParam() { return m_videoParam; } + const MxVideoParam& GetVideoParam() const { return m_videoParam; } + + // SYNTHETIC: LEGO1 0x100b0a70 + // SYNTHETIC: BETA10 0x10132740 + // MxOmniCreateParam::`scalar deleting destructor' + +private: + MxString m_mediaPath; // 0x04 + HWND m_windowHandle; // 0x14 + MxVideoParam m_videoParam; // 0x18 + MxOmniCreateFlags m_createFlags; // 0x3c +}; + +// SYNTHETIC: ISLE 0x4014b0 +// SYNTHETIC: BETA10 0x10132780 +// MxOmniCreateParam::~MxOmniCreateParam + +#endif // MXOMNICREATEPARAM_H diff --git a/LEGO1/omni/include/mxpalette.h b/LEGO1/omni/include/mxpalette.h new file mode 100644 index 00000000..4f38c91b --- /dev/null +++ b/LEGO1/omni/include/mxpalette.h @@ -0,0 +1,41 @@ +#ifndef MXPALETTE_H +#define MXPALETTE_H + +#include "mxcore.h" +#include "mxtypes.h" + +#include + +// VTABLE: LEGO1 0x100dc848 +// SIZE 0x414 +class MxPalette : public MxCore { +public: + MxBool operator==(MxPalette& p_other); + void Detach(); + + MxPalette(); + MxPalette(const RGBQUAD*); + ~MxPalette() override; + + void ApplySystemEntriesToPalette(LPPALETTEENTRY p_entries); + MxPalette* Clone(); + void GetDefaultPalette(LPPALETTEENTRY p_entries); + MxResult GetEntries(LPPALETTEENTRY p_entries); + MxResult SetEntries(LPPALETTEENTRY p_palette); + MxResult SetSkyColor(LPPALETTEENTRY p_skyColor); + void Reset(MxBool p_ignoreSkyColor); + LPDIRECTDRAWPALETTE CreateNativePalette(); + + inline void SetOverrideSkyColor(MxBool p_value) { this->m_overrideSkyColor = p_value; } + + // SYNTHETIC: LEGO1 0x100beeb0 + // MxPalette::`scalar deleting destructor' + +private: + LPDIRECTDRAWPALETTE m_palette; + PALETTEENTRY m_entries[256]; // 0x0c + MxBool m_overrideSkyColor; // 0x40c + PALETTEENTRY m_skyColor; // 0x40d +}; + +#endif // MXPALETTE_H diff --git a/LEGO1/omni/include/mxparam.h b/LEGO1/omni/include/mxparam.h new file mode 100644 index 00000000..a266b12b --- /dev/null +++ b/LEGO1/omni/include/mxparam.h @@ -0,0 +1,18 @@ +#ifndef MXPARAM_H +#define MXPARAM_H + +// VTABLE: ISLE 0x40f018 +// VTABLE: LEGO1 0x100d56e8 +// SIZE 0x04 +class MxParam { +public: + // FUNCTION: ISLE 0x401530 + // FUNCTION: LEGO1 0x10010360 + virtual ~MxParam() {} +}; + +// SYNTHETIC: ISLE 0x401540 +// SYNTHETIC: LEGO1 0x10010370 +// MxParam::`scalar deleting destructor' + +#endif // MXPARAM_H diff --git a/LEGO1/omni/include/mxpoint32.h b/LEGO1/omni/include/mxpoint32.h new file mode 100644 index 00000000..80aace10 --- /dev/null +++ b/LEGO1/omni/include/mxpoint32.h @@ -0,0 +1,36 @@ +#ifndef MXPOINT32_H +#define MXPOINT32_H + +#include "mxtypes.h" + +class MxPoint32 { +public: + MxPoint32() {} + + // FUNCTION: LEGO1 0x10012170 + MxPoint32(MxS32 p_x, MxS32 p_y) { CopyFrom(p_x, p_y); } + + MxPoint32(const MxPoint32& p_point) + { + this->m_x = p_point.m_x; + this->m_y = p_point.m_y; + } + + inline MxS32 GetX() const { return m_x; } + inline MxS32 GetY() const { return m_y; } + + inline void SetX(MxS32 p_x) { m_x = p_x; } + inline void SetY(MxS32 p_y) { m_y = p_y; } + +private: + inline void CopyFrom(MxS32 p_x, MxS32 p_y) + { + this->m_x = p_x; + this->m_y = p_y; + } + + MxS32 m_x; // 0x00 + MxS32 m_y; // 0x04 +}; + +#endif // MXPOINT32_H diff --git a/LEGO1/omni/include/mxpresenter.h b/LEGO1/omni/include/mxpresenter.h new file mode 100644 index 00000000..a652f40d --- /dev/null +++ b/LEGO1/omni/include/mxpresenter.h @@ -0,0 +1,146 @@ +#ifndef MXPRESENTER_H +#define MXPRESENTER_H + +#include "decomp.h" +#include "mxcore.h" +#include "mxcriticalsection.h" +#include "mxpoint32.h" + +class MxCompositePresenter; +class MxDSAction; +class MxOmni; +class MxStreamController; +class MxEntity; + +// VTABLE: LEGO1 0x100d4d38 +// SIZE 0x40 +class MxPresenter : public MxCore { +public: + enum TickleState { + e_idle = 0, + e_ready, + e_starting, + e_streaming, + e_repeating, + e_freezing, + e_done, + }; + + MxPresenter() { Init(); } + + // FUNCTION: LEGO1 0x1000bf00 + ~MxPresenter() override {} // vtable+0x00 + + MxResult Tickle() override; // vtable+0x08 + + // FUNCTION: LEGO1 0x1000bfe0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0740 + return "MxPresenter"; + } + + // FUNCTION: LEGO1 0x1000bff0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxPresenter::ClassName()) || MxCore::IsA(p_name); + } + + // FUNCTION: LEGO1 0x1000be30 + virtual void VTable0x14() {} // vtable+0x14 + + // FUNCTION: LEGO1 0x1000be40 + virtual void ReadyTickle() + { + ParseExtra(); + ProgressTickleState(e_starting); + } // vtable+0x18 + + // FUNCTION: LEGO1 0x1000be60 + virtual void StartingTickle() { ProgressTickleState(e_streaming); } // vtable+0x1c + + // FUNCTION: LEGO1 0x1000be80 + virtual void StreamingTickle() { ProgressTickleState(e_repeating); } // vtable+0x20 + + // FUNCTION: LEGO1 0x1000bea0 + virtual void RepeatingTickle() { ProgressTickleState(e_freezing); } // vtable+0x24 + + // FUNCTION: LEGO1 0x1000bec0 + virtual void FreezingTickle() { ProgressTickleState(e_done); } // vtable+0x28 + +protected: + // FUNCTION: LEGO1 0x1000bee0 + virtual void DoneTickle() { ProgressTickleState(e_idle); } // vtable+0x2c + + virtual void ParseExtra(); // vtable+0x30 + + inline void ProgressTickleState(TickleState p_tickleState) + { + m_previousTickleStates |= 1 << (MxU8) m_currentTickleState; + m_currentTickleState = p_tickleState; + } + +public: + // FUNCTION: LEGO1 0x1000bf70 + virtual MxResult AddToManager() { return SUCCESS; } // vtable+0x34 + + // FUNCTION: LEGO1 0x1000bf80 + virtual void Destroy() { Init(); } // vtable+0x38 + + virtual MxResult StartAction(MxStreamController*, MxDSAction*); // vtable+0x3c + virtual void EndAction(); // vtable+0x40 + + // FUNCTION: LEGO1 0x1000bf90 + virtual void SetTickleState(TickleState p_tickleState) { ProgressTickleState(p_tickleState); } // vtable+0x44 + + // FUNCTION: LEGO1 0x1000bfb0 + virtual MxBool HasTickleStatePassed(TickleState p_tickleState) + { + return m_previousTickleStates & (1 << (MxU8) p_tickleState); + } // vtable+0x48 + + // FUNCTION: LEGO1 0x1000bfc0 + virtual MxResult PutData() { return SUCCESS; } // vtable+0x4c + + // FUNCTION: LEGO1 0x1000bfd0 + virtual MxBool IsHit(MxS32 p_x, MxS32 p_y) { return FALSE; } // vtable+0x50 + + virtual void Enable(MxBool p_enable); // vtable+0x54 + + MxEntity* CreateEntity(const char* p_defaultName); + void SendToCompositePresenter(MxOmni* p_omni); + MxBool IsEnabled(); + + inline MxS32 GetCurrentTickleState() const { return this->m_currentTickleState; } + inline MxPoint32 GetLocation() const { return this->m_location; } + inline MxS32 GetX() const { return this->m_location.GetX(); } + inline MxS32 GetY() const { return this->m_location.GetY(); } + inline MxS32 GetDisplayZ() const { return this->m_displayZ; } + inline MxDSAction* GetAction() const { return this->m_action; } + inline void SetAction(MxDSAction* p_action) { m_action = p_action; } + + inline void SetCompositePresenter(MxCompositePresenter* p_compositePresenter) + { + m_compositePresenter = p_compositePresenter; + } + + inline void SetDisplayZ(MxS32 p_displayZ) { m_displayZ = p_displayZ; } + + // SYNTHETIC: LEGO1 0x1000c070 + // MxPresenter::`scalar deleting destructor' + +protected: + void Init(); + + TickleState m_currentTickleState; // 0x08 + MxU32 m_previousTickleStates; // 0x0c + MxPoint32 m_location; // 0x10 + MxS32 m_displayZ; // 0x18 + MxDSAction* m_action; // 0x1c + MxCriticalSection m_criticalSection; // 0x20 + MxCompositePresenter* m_compositePresenter; // 0x3c +}; + +const char* PresenterNameDispatch(const MxDSAction&); + +#endif // MXPRESENTER_H diff --git a/LEGO1/omni/include/mxpresenterlist.h b/LEGO1/omni/include/mxpresenterlist.h new file mode 100644 index 00000000..87430a53 --- /dev/null +++ b/LEGO1/omni/include/mxpresenterlist.h @@ -0,0 +1,101 @@ +#ifndef MXPRESENTERLIST_H +#define MXPRESENTERLIST_H + +#include "mxlist.h" +#include "mxpresenter.h" + +// VTABLE: LEGO1 0x100d62f0 +// class MxPtrList + +// VTABLE: LEGO1 0x100d6308 +// SIZE 0x18 +class MxPresenterList : public MxPtrList { +public: + MxPresenterList(MxBool p_ownership = FALSE) : MxPtrList(p_ownership) {} + + // FUNCTION: LEGO1 0x1001cd00 + MxS8 Compare(MxPresenter* p_a, MxPresenter* p_b) override + { + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; + } // vtable+0x14 + + // SYNTHETIC: LEGO1 0x1001ceb0 + // MxPresenterList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100d6488 +// class MxListCursor + +// VTABLE: LEGO1 0x100d6530 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100d6470 +class MxPresenterListCursor : public MxPtrListCursor { +public: + MxPresenterListCursor(MxPresenterList* p_list) : MxPtrListCursor(p_list) {} +}; + +// VTABLE: LEGO1 0x100d6350 +// class MxCollection + +// VTABLE: LEGO1 0x100d6368 +// class MxList + +// TEMPLATE: LEGO1 0x1001cd20 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x1001cd30 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x1001cd40 +// MxList::MxList + +// TEMPLATE: LEGO1 0x1001cdd0 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x1001ce20 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x1001cf20 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x1001cf70 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001cfe0 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001d090 +// MxPtrList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001d100 +// MxPresenterList::~MxPresenterList + +// SYNTHETIC: LEGO1 0x1001eed0 +// MxPresenterListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001ef40 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x1001ef90 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x1001f000 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x1001f070 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x1001f0c0 +// MxPresenterListCursor::~MxPresenterListCursor + +// TEMPLATE: LEGO1 0x10020760 +// MxListCursor::MxListCursor + +// TEMPLATE: LEGO1 0x10022380 +// MxList::InsertEntry + +// TEMPLATE: LEGO1 0x100225e0 +// MxList::DeleteEntry + +#endif // MXPRESENTERLIST_H diff --git a/LEGO1/omni/include/mxqueue.h b/LEGO1/omni/include/mxqueue.h new file mode 100644 index 00000000..4e45c035 --- /dev/null +++ b/LEGO1/omni/include/mxqueue.h @@ -0,0 +1,26 @@ +#ifndef MXQUEUE_H +#define MXQUEUE_H + +#include "mxlist.h" + +template +class MxQueue : public MxList { +public: + void Enqueue(T& p_obj) + { + // TODO + } + + MxBool Dequeue(T& p_obj) + { + MxBool hasNext = (this->m_first != NULL); + if (this->m_first) { + p_obj = this->m_first->GetValue(); + this->DeleteEntry(this->m_first); + } + + return hasNext; + } +}; + +#endif // MXQUEUE_H diff --git a/LEGO1/omni/include/mxramstreamcontroller.h b/LEGO1/omni/include/mxramstreamcontroller.h new file mode 100644 index 00000000..b445e8cd --- /dev/null +++ b/LEGO1/omni/include/mxramstreamcontroller.h @@ -0,0 +1,42 @@ +#ifndef MXRAMSTREAMCONTROLLER_H +#define MXRAMSTREAMCONTROLLER_H + +#include "mxdsbuffer.h" +#include "mxstreamcontroller.h" + +class MxDSStreamingAction; + +// VTABLE: LEGO1 0x100dc728 +// SIZE 0x98 +class MxRAMStreamController : public MxStreamController { +public: + inline MxRAMStreamController() {} + + // FUNCTION: LEGO1 0x100b9430 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10102118 + return "MxRAMStreamController"; + } + + // FUNCTION: LEGO1 0x100b9440 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxRAMStreamController::ClassName()) || + !strcmp(p_name, MxStreamController::ClassName()) || MxCore::IsA(p_name); + } + + MxResult Open(const char* p_filename) override; + MxResult VTable0x20(MxDSAction* p_action) override; + MxResult VTable0x24(MxDSAction* p_action) override; + +private: + MxDSBuffer m_buffer; // 0x64 + + MxResult DeserializeObject(MxDSStreamingAction& p_action); +}; + +// SYNTHETIC: LEGO1 0x100b94f0 +// MxRAMStreamController::`scalar deleting destructor' + +#endif // MXRAMSTREAMCONTROLLER_H diff --git a/LEGO1/omni/include/mxramstreamprovider.h b/LEGO1/omni/include/mxramstreamprovider.h new file mode 100644 index 00000000..08c1ea95 --- /dev/null +++ b/LEGO1/omni/include/mxramstreamprovider.h @@ -0,0 +1,47 @@ +#ifndef MXRAMSTREAMPROVIDER_H +#define MXRAMSTREAMPROVIDER_H + +#include "mxstreamprovider.h" + +// VTABLE: LEGO1 0x100dd0d0 +// SIZE 0x24 +class MxRAMStreamProvider : public MxStreamProvider { +public: + MxRAMStreamProvider(); + ~MxRAMStreamProvider() override; + + // FUNCTION: LEGO1 0x100d0970 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10102864 + return "MxRAMStreamProvider"; + } + + // FUNCTION: LEGO1 0x100d0980 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxRAMStreamProvider::ClassName()) || MxStreamProvider::IsA(p_name); + } + + MxResult SetResourceToGet(MxStreamController* p_resource) override; // vtable+0x14 + MxU32 GetFileSize() override; // vtable+0x18 + MxS32 GetStreamBuffersNum() override; // vtable+0x1c + MxU32 GetLengthInDWords() override; // vtable+0x24 + MxU32* GetBufferForDWords() override; // vtable+0x28 + + inline MxU8* GetBufferOfFileSize() { return m_pBufferOfFileSize; } + +protected: + MxU32 m_bufferSize; // 0x10 + MxU32 m_fileSize; // 0x14 + MxU8* m_pBufferOfFileSize; // 0x18 + MxU32 m_lengthInDWords; // 0x1c + MxU32* m_bufferForDWords; // 0x20 +}; + +// SYNTHETIC: LEGO1 0x100d0a30 +// MxRAMStreamProvider::`scalar deleting destructor' + +MxU32 ReadData(MxU8* p_fileSizeBuffer, MxU32 p_fileSize); + +#endif // MXRAMSTREAMPROVIDER_H diff --git a/LEGO1/omni/include/mxrect32.h b/LEGO1/omni/include/mxrect32.h new file mode 100644 index 00000000..207d93fa --- /dev/null +++ b/LEGO1/omni/include/mxrect32.h @@ -0,0 +1,127 @@ +#ifndef MXRECT32_H +#define MXRECT32_H + +#include "mxpoint32.h" +#include "mxsize32.h" + +// SIZE 0x10 +class MxRect32 { +public: + MxRect32() {} + MxRect32(MxS32 p_left, MxS32 p_top, MxS32 p_right, MxS32 p_bottom) { CopyFrom(p_left, p_top, p_right, p_bottom); } + MxRect32(const MxPoint32& p_point, const MxSize32& p_size) { CopyFrom(p_point, p_size); } + MxRect32(const MxRect32& p_a, const MxRect32& p_b) + { + m_left = Max(p_a.m_left, p_b.m_left); + m_top = Max(p_a.m_top, p_b.m_top); + m_right = Min(p_a.m_right, p_b.m_right); + m_bottom = Min(p_a.m_bottom, p_b.m_bottom); + } + + MxRect32(const MxRect32& p_rect) { CopyFrom(p_rect); } + + MxRect32& operator=(const MxRect32& p_rect) + { + CopyFrom(p_rect); + return *this; + } + + inline void Intersect(const MxRect32& p_rect) + { + m_left = Max(p_rect.m_left, m_left); + m_top = Max(p_rect.m_top, m_top); + m_right = Min(p_rect.m_right, m_right); + m_bottom = Min(p_rect.m_bottom, m_bottom); + } + + inline void SetPoint(const MxPoint32& p_point) + { + this->m_left = p_point.GetX(); + this->m_top = p_point.GetY(); + } + + inline void AddPoint(const MxPoint32& p_point) + { + this->m_left += p_point.GetX(); + this->m_top += p_point.GetY(); + this->m_right += p_point.GetX(); + this->m_bottom += p_point.GetY(); + } + + inline void SubtractPoint(const MxPoint32& p_point) + { + this->m_left -= p_point.GetX(); + this->m_top -= p_point.GetY(); + this->m_right -= p_point.GetX(); + this->m_bottom -= p_point.GetY(); + } + + inline void UpdateBounds(const MxRect32& p_rect) + { + m_left = Min(m_left, p_rect.m_left); + m_top = Min(m_top, p_rect.m_top); + m_right = Max(m_right, p_rect.m_right); + m_bottom = Max(m_bottom, p_rect.m_bottom); + } + + inline MxBool IsValid() const { return m_left < m_right && m_top < m_bottom; } + + inline MxBool IntersectsWith(const MxRect32& p_rect) const + { + return m_left < p_rect.m_right && p_rect.m_left < m_right && m_top < p_rect.m_bottom && p_rect.m_top < m_bottom; + } + + inline MxS32 GetWidth() const { return (m_right - m_left) + 1; } + inline MxS32 GetHeight() const { return (m_bottom - m_top) + 1; } + + inline MxPoint32 GetPoint() const { return MxPoint32(this->m_left, this->m_top); } + inline MxSize32 GetSize() const { return MxSize32(this->m_right, this->m_bottom); } + + inline MxS32 GetLeft() const { return m_left; } + inline MxS32 GetTop() const { return m_top; } + inline MxS32 GetRight() const { return m_right; } + inline MxS32 GetBottom() const { return m_bottom; } + + inline void SetLeft(MxS32 p_left) { m_left = p_left; } + inline void SetTop(MxS32 p_top) { m_top = p_top; } + inline void SetRight(MxS32 p_right) { m_right = p_right; } + inline void SetBottom(MxS32 p_bottom) { m_bottom = p_bottom; } + +private: + inline void CopyFrom(MxS32 p_left, MxS32 p_top, MxS32 p_right, MxS32 p_bottom) + { + this->m_left = p_left; + this->m_top = p_top; + this->m_right = p_right; + this->m_bottom = p_bottom; + } + + inline void CopyFrom(const MxRect32& p_rect) + { + this->m_left = p_rect.m_left; + this->m_top = p_rect.m_top; + this->m_right = p_rect.m_right; + this->m_bottom = p_rect.m_bottom; + } + + // The address might also be the constructor that calls CopyFrom + // FUNCTION: LEGO1 0x100b6fc0 + inline MxRect32* CopyFrom(const MxPoint32& p_point, const MxSize32& p_size) + { + this->m_left = p_point.GetX(); + this->m_top = p_point.GetY(); + this->m_right = p_size.GetWidth() + p_point.GetX() - 1; + this->m_bottom = p_size.GetHeight() + p_point.GetY() - 1; + return this; + } + + inline static MxS32 Min(MxS32 p_a, MxS32 p_b) { return p_a <= p_b ? p_a : p_b; } + inline static MxS32 Max(MxS32 p_a, MxS32 p_b) { return p_a <= p_b ? p_b : p_a; } + + MxS32 m_left; // 0x00 + MxS32 m_top; // 0x04 + MxS32 m_right; // 0x08 + MxS32 m_bottom; // 0x0c +}; + +#endif // MXRECT32_H diff --git a/LEGO1/omni/include/mxrectlist.h b/LEGO1/omni/include/mxrectlist.h new file mode 100644 index 00000000..88cffa9f --- /dev/null +++ b/LEGO1/omni/include/mxrectlist.h @@ -0,0 +1,89 @@ +#ifndef MXRECTLIST_H +#define MXRECTLIST_H + +#include "mxlist.h" +#include "mxrect32.h" + +// VTABLE: LEGO1 0x100dc3f0 +// SIZE 0x18 +class MxRectList : public MxPtrList { +public: + MxRectList(MxBool p_ownership = FALSE) : MxPtrList(p_ownership) {} +}; + +// VTABLE: LEGO1 0x100dc438 +// class MxListCursor + +// VTABLE: LEGO1 0x100dc408 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100dc420 +class MxRectListCursor : public MxPtrListCursor { +public: + MxRectListCursor(MxRectList* p_list) : MxPtrListCursor(p_list) {} +}; + +// VTABLE: LEGO1 0x100dc3d8 +// class MxPtrList + +// VTABLE: LEGO1 0x100dc450 +// class MxList + +// VTABLE: LEGO1 0x100dc468 +// class MxCollection + +// TEMPLATE: LEGO1 0x100b3c00 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x100b3c10 +// MxCollection::MxCollection + +// TEMPLATE: LEGO1 0x100b3c80 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x100b3cd0 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x100b3ce0 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x100b3d70 +// MxPtrList::Destroy + +// SYNTHETIC: LEGO1 0x100b3d80 +// MxRectList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b3df0 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x100b3e40 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100b3eb0 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100b3f60 +// MxPtrList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b3fd0 +// MxRectList::~MxRectList + +// SYNTHETIC: LEGO1 0x100b4020 +// MxRectListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b4090 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x100b40e0 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100b4150 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b41c0 +// MxListCursor::~MxListCursor + +// TEMPLATE: LEGO1 0x100b4210 +// MxRectListCursor::~MxRectListCursor + +#endif // MXRECTLIST_H diff --git a/LEGO1/omni/include/mxregion.h b/LEGO1/omni/include/mxregion.h new file mode 100644 index 00000000..3bf639e1 --- /dev/null +++ b/LEGO1/omni/include/mxregion.h @@ -0,0 +1,34 @@ +#ifndef MXREGION_H +#define MXREGION_H + +#include "decomp.h" +#include "mxcore.h" +#include "mxrect32.h" +#include "mxregionlist.h" + +// VTABLE: LEGO1 0x100dcae8 +// SIZE 0x1c +class MxRegion : public MxCore { +public: + MxRegion(); + ~MxRegion() override; + + virtual void Reset(); // vtable+0x14 + virtual void VTable0x18(MxRect32& p_rect); // vtable+0x18 + virtual MxBool VTable0x1c(MxRect32& p_rect); // vtable+0x1c + virtual MxBool VTable0x20(); // vtable+0x20 + + inline MxRegionTopBottomList* GetTopBottomList() const { return m_list; } + inline const MxRect32& GetRect() const { return m_rect; } + + friend class MxRegionCursor; + + // SYNTHETIC: LEGO1 0x100c3670 + // MxRegion::`scalar deleting destructor' + +private: + MxRegionTopBottomList* m_list; // 0x08 + MxRect32 m_rect; // 0x0c +}; + +#endif // MXREGION_H diff --git a/LEGO1/omni/include/mxregioncursor.h b/LEGO1/omni/include/mxregioncursor.h new file mode 100644 index 00000000..e114c7ed --- /dev/null +++ b/LEGO1/omni/include/mxregioncursor.h @@ -0,0 +1,45 @@ +#ifndef MXREGIONCURSOR_H +#define MXREGIONCURSOR_H + +#include "mxregion.h" + +// VTABLE: LEGO1 0x100dcbb8 +// SIZE 0x18 +class MxRegionCursor : public MxCore { +public: + MxRegionCursor(MxRegion* p_region); + ~MxRegionCursor() override; + + virtual MxRect32* VTable0x14(MxRect32& p_rect); // vtable+0x14 + virtual MxRect32* VTable0x18(); // vtable+0x18 + virtual MxRect32* VTable0x1c(MxRect32& p_rect); // vtable+0x1c + virtual MxRect32* VTable0x20(); // vtable+0x20 + virtual MxRect32* VTable0x24(MxRect32& p_rect); // vtable+0x24 + virtual MxRect32* VTable0x28(); // vtable+0x28 + virtual MxRect32* VTable0x2c(MxRect32& p_rect); // vtable+0x2c + virtual MxRect32* VTable0x30(); // vtable+0x30 + + // FUNCTION: LEGO1 0x100c4070 + virtual MxRect32* GetRect() { return m_rect; } // vtable+0x34 + + // FUNCTION: LEGO1 0x100c4080 + virtual MxBool HasRect() { return m_rect != NULL; } // vtable+0x38 + + virtual void Reset(); // vtable+0x3c + +private: + void FUN_100c46c0(MxRegionLeftRightList& p_leftRightList); + void UpdateRect(MxS32 p_left, MxS32 p_top, MxS32 p_right, MxS32 p_bottom); + void FUN_100c4a20(MxRect32& p_rect); + void FUN_100c4b50(MxRect32& p_rect); + + MxRegion* m_region; // 0x08 + MxRect32* m_rect; // 0x0c + MxRegionTopBottomListCursor* m_topBottomCursor; // 0x10 + MxRegionLeftRightListCursor* m_leftRightCursor; // 0x14 +}; + +// SYNTHETIC: LEGO1 0x100c4090 +// MxRegionCursor::`scalar deleting destructor' + +#endif // MXREGIONCURSOR_H diff --git a/LEGO1/omni/include/mxregionlist.h b/LEGO1/omni/include/mxregionlist.h new file mode 100644 index 00000000..b7eff3ae --- /dev/null +++ b/LEGO1/omni/include/mxregionlist.h @@ -0,0 +1,230 @@ +#ifndef MXREGIONLIST_H +#define MXREGIONLIST_H + +#include "mxlist.h" + +// SIZE 0x08 +struct MxRegionLeftRight { + MxRegionLeftRight(MxS32 p_left, MxS32 p_right) + { + m_left = p_left; + m_right = p_right; + } + + MxRegionLeftRight* Clone() { return new MxRegionLeftRight(m_left, m_right); } + + inline MxS32 GetLeft() { return m_left; } + inline MxS32 GetRight() { return m_right; } + + inline void SetLeft(MxS32 p_left) { m_left = p_left; } + inline void SetRight(MxS32 p_right) { m_right = p_right; } + + inline MxBool IntersectsWith(MxRect32& p_rect) { return m_left < p_rect.GetRight() && p_rect.GetTop() < m_right; } + +private: + MxS32 m_left; // 0x00 + MxS32 m_right; // 0x04 +}; + +// VTABLE: LEGO1 0x100dcc40 +// class MxCollection + +// VTABLE: LEGO1 0x100dcc58 +// class MxList + +// VTABLE: LEGO1 0x100dcc70 +// class MxPtrList + +// VTABLE: LEGO1 0x100dcc88 +// SIZE 0x18 +class MxRegionLeftRightList : public MxPtrList { +public: + MxRegionLeftRightList() : MxPtrList(TRUE) {} + + // SYNTHETIC: LEGO1 0x100c4e90 + // MxRegionLeftRightList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dcbf8 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100dcc28 +// class MxListCursor + +// VTABLE: LEGO1 0x100dcc10 +class MxRegionLeftRightListCursor : public MxPtrListCursor { +public: + MxRegionLeftRightListCursor(MxRegionLeftRightList* p_list) : MxPtrListCursor(p_list) {} +}; + +// SIZE 0x0c +struct MxRegionTopBottom { + MxRegionTopBottom(MxRect32& p_rect); + MxRegionTopBottom(MxS32 p_top, MxS32 p_bottom); + ~MxRegionTopBottom() { delete m_leftRightList; } + + MxRegionTopBottom* Clone(); + void FUN_100c5280(MxS32 p_left, MxS32 p_right); + MxBool FUN_100c57b0(MxRect32& p_rect); + + inline MxS32 GetTop() { return m_top; } + inline MxS32 GetBottom() { return m_bottom; } + + inline void SetTop(MxS32 p_top) { m_top = p_top; } + inline void SetBottom(MxS32 p_bottom) { m_bottom = p_bottom; } + + inline MxBool IntersectsWith(MxRect32& p_rect) { return m_top < p_rect.GetBottom() && p_rect.GetTop() < m_bottom; } + + friend class MxRegionTopBottomList; + friend class MxRegionCursor; + +private: + MxS32 m_top; // 0x00 + MxS32 m_bottom; // 0x04 + MxRegionLeftRightList* m_leftRightList; // 0x08 +}; + +// VTABLE: LEGO1 0x100dcb10 +// class MxCollection + +// VTABLE: LEGO1 0x100dcb28 +// class MxList + +// VTABLE: LEGO1 0x100dcb40 +// class MxPtrList + +// VTABLE: LEGO1 0x100dcb58 +// SIZE 0x18 +class MxRegionTopBottomList : public MxPtrList { +public: + MxRegionTopBottomList() : MxPtrList(TRUE) {} + + // SYNTHETIC: LEGO1 0x100c3410 + // MxRegionTopBottomList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dcb70 +// class MxPtrListCursor + +// VTABLE: LEGO1 0x100dcba0 +// class MxListCursor + +// TODO: The initialize list param type should be MxRegionTopBottomList, but doing that +// drastically reduced the match percentage for MxRegion::VTable0x18. +// It also works with MxPtrList, so we'll do that until we figure this out. + +// VTABLE: LEGO1 0x100dcb88 +class MxRegionTopBottomListCursor : public MxPtrListCursor { +public: + MxRegionTopBottomListCursor(MxPtrList* p_list) : MxPtrListCursor(p_list) {} +}; + +// TEMPLATE: LEGO1 0x100c32e0 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x100c32f0 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x100c3340 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x100c3350 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x100c33e0 +// MxPtrList::Destroy + +// TEMPLATE: LEGO1 0x100c3480 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x100c34d0 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c3540 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c35f0 +// MxPtrList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c3be0 +// MxRegionTopBottomListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c3c50 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x100c3ca0 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c3d10 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c3d80 +// MxListCursor::~MxListCursor + +// FUNCTION: LEGO1 0x100c3dd0 +// MxRegionTopBottomListCursor::~MxRegionTopBottomListCursor + +// SYNTHETIC: LEGO1 0x100c4790 +// MxRegionLeftRightListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c4800 +// MxPtrListCursor::~MxPtrListCursor + +// SYNTHETIC: LEGO1 0x100c4850 +// MxListCursor::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c48c0 +// MxPtrListCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c4930 +// MxListCursor::~MxListCursor + +// TEMPLATE: LEGO1 0x100c4d80 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x100c4d90 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x100c4de0 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x100c4df0 +// MxList::~MxList + +// TEMPLATE: LEGO1 0x100c4f00 +// MxPtrList::~MxPtrList + +// SYNTHETIC: LEGO1 0x100c4f50 +// MxCollection::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c4e80 +// MxPtrList::Destroy + +// SYNTHETIC: LEGO1 0x100c4fc0 +// MxList::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c5070 +// MxPtrList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100c54f0 +// MxListCursor::MxListCursor + +// FUNCTION: LEGO1 0x100c5560 +// MxRegionLeftRightListCursor::~MxRegionLeftRightListCursor + +// TEMPLATE: LEGO1 0x100c55b0 +// MxListCursor::operator= + +// TEMPLATE: LEGO1 0x100c58c0 +// MxList::InsertEntry + +// TEMPLATE: LEGO1 0x100c5970 +// MxList::InsertEntry + +// TEMPLATE: LEGO1 0x100c5a20 +// MxListEntry::MxListEntry + +// TEMPLATE: LEGO1 0x100c5a40 +// MxList::DeleteEntry + +#endif // MXREGIONLIST_H diff --git a/LEGO1/omni/include/mxscheduler.h b/LEGO1/omni/include/mxscheduler.h new file mode 100644 index 00000000..1f60029d --- /dev/null +++ b/LEGO1/omni/include/mxscheduler.h @@ -0,0 +1,12 @@ +#ifndef MXSCHEDULER_H +#define MXSCHEDULER_H + +#include "mxtypes.h" + +class MxScheduler { +public: + static MxScheduler* GetInstance(); + void StartMultiTasking(MxULong); +}; + +#endif // MXSCHEDULER_H diff --git a/LEGO1/omni/include/mxsemaphore.h b/LEGO1/omni/include/mxsemaphore.h new file mode 100644 index 00000000..4e692395 --- /dev/null +++ b/LEGO1/omni/include/mxsemaphore.h @@ -0,0 +1,26 @@ +#ifndef MX_SEMAPHORE_H +#define MX_SEMAPHORE_H + +#include "mxtypes.h" + +#include + +// VTABLE: LEGO1 0x100dccf0 +// SIZE 0x08 +class MxSemaphore { +public: + MxSemaphore(); + + // FUNCTION: LEGO1 0x100c87e0 + ~MxSemaphore() { CloseHandle(m_hSemaphore); } + + virtual MxResult Init(MxU32 p_initialCount, MxU32 p_maxCount); + + void Wait(MxU32 p_timeoutMS); + void Release(MxU32 p_releaseCount); + +private: + HANDLE m_hSemaphore; // 0x04 +}; + +#endif // MX_SEMAPHORE_H diff --git a/LEGO1/omni/include/mxsize32.h b/LEGO1/omni/include/mxsize32.h new file mode 100644 index 00000000..8fb90210 --- /dev/null +++ b/LEGO1/omni/include/mxsize32.h @@ -0,0 +1,25 @@ +#ifndef MXSIZE32_H +#define MXSIZE32_H + +#include "mxtypes.h" + +class MxSize32 { +public: + MxSize32() {} + MxSize32(MxS32 p_width, MxS32 p_height) { CopyFrom(p_width, p_height); } + + inline MxS32 GetWidth() const { return m_width; } + inline MxS32 GetHeight() const { return m_height; } + +private: + inline void CopyFrom(MxS32 p_width, MxS32 p_height) + { + this->m_width = p_width; + this->m_height = p_height; + } + + MxS32 m_width; + MxS32 m_height; +}; + +#endif // MXSIZE32_H diff --git a/LEGO1/omni/include/mxsmack.h b/LEGO1/omni/include/mxsmack.h new file mode 100644 index 00000000..e7fdf3ce --- /dev/null +++ b/LEGO1/omni/include/mxsmack.h @@ -0,0 +1,54 @@ +#ifndef MXSMACK_H +#define MXSMACK_H + +#include "decomp.h" +#include "mxrectlist.h" +#include "mxtypes.h" + +#include + +struct MxBITMAPINFO; + +// These functions are not part of the public interface, +// but present in SMACK.LIB and used directly by Mindscape. +extern "C" +{ + u32 SmackGetSizeTables(); + void SmackDoTables( + u8* p_huffmanTrees, + u8* p_huffmanTables, + u32 p_codeSize, + u32 p_abSize, + u32 p_detailSize, + u32 p_typeSize + ); + void SmackDoFrameToBuffer(u8* p_source, u8* p_huffmanTables, u8* p_unk0x6b4); + u32 SmackGetSizeDeltas(u32 p_width, u32 p_height); + u8 SmackGetRect(u8* p_unk0x6b4, u32* p_rect); +} + +// SIZE 0x6b8 +struct MxSmack { + SmackTag m_smackTag; // 0x00 + undefined m_unk0x390[784]; // 0x390 + MxU32* m_frameSizes; // 0x6a0 + MxU8* m_frameTypes; // 0x6a4 + MxU8* m_huffmanTrees; // 0x6a8 + MxU8* m_huffmanTables; // 0x6ac + MxU32 m_maxFrameSize; // 0x6b0 + MxU8* m_unk0x6b4; // 0x6b4 + + static MxResult LoadHeader(MxU8* p_data, MxSmack* p_mxSmack); + static void Destroy(MxSmack* p_mxSmack); + static MxResult LoadFrame( + MxBITMAPINFO* p_bitmapInfo, + MxU8* p_bitmapData, + MxSmack* p_mxSmack, + MxU8* p_chunkData, + MxBool p_paletteChanged, + MxRectList* p_list + ); + static MxBool GetRect(MxU8* p_unk0x6b4, MxU16* p_und, u32* p_smackRect, MxRect32* p_rect); +}; + +#endif // MXSMACK_H diff --git a/LEGO1/omni/include/mxsmkpresenter.h b/LEGO1/omni/include/mxsmkpresenter.h new file mode 100644 index 00000000..d17ce59d --- /dev/null +++ b/LEGO1/omni/include/mxsmkpresenter.h @@ -0,0 +1,48 @@ +#ifndef MXSMKPRESENTER_H +#define MXSMKPRESENTER_H + +#include "decomp.h" +#include "mxsmack.h" +#include "mxvideopresenter.h" + +// VTABLE: LEGO1 0x100dc348 +// SIZE 0x720 +class MxSmkPresenter : public MxVideoPresenter { +public: + MxSmkPresenter(); + ~MxSmkPresenter() override; + + // FUNCTION: LEGO1 0x100b3730 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101e38 + return "MxSmkPresenter"; + } + + // FUNCTION: LEGO1 0x100b3740 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxSmkPresenter::ClassName()) || MxVideoPresenter::IsA(p_name); + } + + MxResult AddToManager() override; // vtable+0x34 + void Destroy() override; // vtable+0x38 + void LoadHeader(MxStreamChunk* p_chunk) override; // vtable+0x5c + void CreateBitmap() override; // vtable+0x60 + void LoadFrame(MxStreamChunk* p_chunk) override; // vtable+0x68 + void RealizePalette() override; // vtable+0x70 + virtual void VTable0x88(); // vtable+0x88 + + // SYNTHETIC: LEGO1 0x100b3850 + // MxSmkPresenter::`scalar deleting destructor' + +private: + void Init(); + void Destroy(MxBool p_fromDestructor); + +protected: + MxSmack m_mxSmack; // 0x64 + MxU32 m_currentFrame; // 0x71c +}; + +#endif // MXSMKPRESENTER_H diff --git a/LEGO1/omni/include/mxsoundmanager.h b/LEGO1/omni/include/mxsoundmanager.h new file mode 100644 index 00000000..8d1d573d --- /dev/null +++ b/LEGO1/omni/include/mxsoundmanager.h @@ -0,0 +1,40 @@ +#ifndef MXSOUNDMANAGER_H +#define MXSOUNDMANAGER_H + +#include "decomp.h" +#include "mxatom.h" +#include "mxaudiomanager.h" + +#include + +// VTABLE: LEGO1 0x100dc128 +// SIZE 0x3c +class MxSoundManager : public MxAudioManager { +public: + MxSoundManager(); + ~MxSoundManager() override; // vtable+0x00 + + void Destroy() override; // vtable+0x18 + void SetVolume(MxS32 p_volume) override; // vtable+0x2c + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x30 + virtual void Pause(); // vtable+0x34 + virtual void Resume(); // vtable+0x38 + + inline LPDIRECTSOUND GetDirectSound() { return m_directSound; } + + MxS32 GetAttenuation(MxU32 p_volume); + +protected: + void Init(); + void Destroy(MxBool p_fromDestructor); + MxPresenter* FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_objectId); + + LPDIRECTSOUND m_directSound; // 0x30 + LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x34 + undefined m_unk0x38[4]; +}; + +// SYNTHETIC: LEGO1 0x100ae7b0 +// MxSoundManager::`scalar deleting destructor' + +#endif // MXSOUNDMANAGER_H diff --git a/LEGO1/omni/include/mxsoundpresenter.h b/LEGO1/omni/include/mxsoundpresenter.h new file mode 100644 index 00000000..3f578109 --- /dev/null +++ b/LEGO1/omni/include/mxsoundpresenter.h @@ -0,0 +1,38 @@ +#ifndef MXSOUNDPRESENTER_H +#define MXSOUNDPRESENTER_H + +#include "mxaudiopresenter.h" + +// VTABLE: LEGO1 0x100d4b08 +// SIZE 0x54 +class MxSoundPresenter : public MxAudioPresenter { +public: + // FUNCTION: LEGO1 0x1000d430 + ~MxSoundPresenter() override { Destroy(TRUE); } + + // FUNCTION: LEGO1 0x1000d4a0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f07a0 + return "MxSoundPresenter"; + } + + // FUNCTION: LEGO1 0x1000d4b0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxSoundPresenter::ClassName()) || MxAudioPresenter::IsA(p_name); + } + + MxResult AddToManager() override; // vtable+0x34 + + // FUNCTION: LEGO1 0x1000d490 + void Destroy() override { Destroy(FALSE); } // vtable+0x38 + + // SYNTHETIC: LEGO1 0x1000d5c0 + // MxSoundPresenter::`scalar deleting destructor' + +protected: + void Destroy(MxBool p_fromDestructor); +}; + +#endif // MXSOUNDPRESENTER_H diff --git a/LEGO1/omni/include/mxstillpresenter.h b/LEGO1/omni/include/mxstillpresenter.h new file mode 100644 index 00000000..0fb92862 --- /dev/null +++ b/LEGO1/omni/include/mxstillpresenter.h @@ -0,0 +1,56 @@ +#ifndef MXSTILLPRESENTER_H +#define MXSTILLPRESENTER_H + +#include "decomp.h" +#include "mxvideopresenter.h" + +// VTABLE: LEGO1 0x100d7a38 +// SIZE 0x6c +class MxStillPresenter : public MxVideoPresenter { +public: + MxStillPresenter() { m_bitmapInfo = NULL; } + + // FUNCTION: LEGO1 0x10043550 + ~MxStillPresenter() override { Destroy(TRUE); } // vtable+0x00 + + // FUNCTION: LEGO1 0x100435c0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0184 + return "MxStillPresenter"; + } + + // FUNCTION: LEGO1 0x100435d0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxStillPresenter::ClassName()) || MxVideoPresenter::IsA(p_name); + } + + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + void RepeatingTickle() override; // vtable+0x24 + void ParseExtra() override; // vtable+0x30 + + // FUNCTION: LEGO1 0x100435b0 + void Destroy() override { Destroy(FALSE); } // vtable+0x38 + + void Enable(MxBool p_enable) override; // vtable+0x54 + void LoadHeader(MxStreamChunk* p_chunk) override; // vtable+0x5c + void CreateBitmap() override; // vtable+0x60 + void NextFrame() override; // vtable+0x64 + void LoadFrame(MxStreamChunk* p_chunk) override; // vtable+0x68 + void RealizePalette() override; // vtable+0x70 + virtual void SetPosition(MxS32 p_x, MxS32 p_y); // vtable+0x88 + virtual MxStillPresenter* Clone(); // vtable+0x8c + +private: + void Destroy(MxBool p_fromDestructor); + + MxLong m_chunkTime; // 0x64 + MxBITMAPINFO* m_bitmapInfo; // 0x68 +}; + +// SYNTHETIC: LEGO1 0x100436e0 +// MxStillPresenter::`scalar deleting destructor' + +#endif // MXSTILLPRESENTER_H diff --git a/LEGO1/omni/include/mxstreamchunk.h b/LEGO1/omni/include/mxstreamchunk.h new file mode 100644 index 00000000..80c33c8a --- /dev/null +++ b/LEGO1/omni/include/mxstreamchunk.h @@ -0,0 +1,48 @@ +#ifndef MXSTREAMCHUNK_H +#define MXSTREAMCHUNK_H + +#include "mxdschunk.h" + +class MxDSBuffer; +class MxStreamListMxDSSubscriber; + +// VTABLE: LEGO1 0x100dc2a8 +// SIZE 0x20 +class MxStreamChunk : public MxDSChunk { +public: + inline MxStreamChunk() : m_buffer(NULL) {} + ~MxStreamChunk() override; + + // FUNCTION: LEGO1 0x100b1fe0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10101e5c + return "MxStreamChunk"; + } + + // FUNCTION: LEGO1 0x100b1ff0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxStreamChunk::ClassName()) || MxDSChunk::IsA(p_name); + } + + inline MxDSBuffer* GetBuffer() { return m_buffer; } + + MxResult ReadChunk(MxDSBuffer* p_buffer, MxU8* p_chunkData); + MxU32 ReadChunkHeader(MxU8* p_chunkData); + MxResult SendChunk(MxStreamListMxDSSubscriber& p_subscriberList, MxBool p_append, MxS16 p_obj24val); + void SetBuffer(MxDSBuffer* p_buffer); + + static MxU16* IntoFlags(MxU8* p_buffer); + static MxU32* IntoObjectId(MxU8* p_buffer); + static MxLong* IntoTime(MxU8* p_buffer); + static MxU32* IntoLength(MxU8* p_buffer); + +private: + MxDSBuffer* m_buffer; // 0x1c +}; + +// SYNTHETIC: LEGO1 0x100b20a0 +// MxStreamChunk::`scalar deleting destructor' + +#endif // MXSTREAMCHUNK_H diff --git a/LEGO1/omni/include/mxstreamchunklist.h b/LEGO1/omni/include/mxstreamchunklist.h new file mode 100644 index 00000000..105ff93b --- /dev/null +++ b/LEGO1/omni/include/mxstreamchunklist.h @@ -0,0 +1,61 @@ +#ifndef MXSTREAMCHUNKLIST_H +#define MXSTREAMCHUNKLIST_H + +#include "decomp.h" +#include "mxlist.h" +#include "mxstreamchunk.h" + +// VTABLE: LEGO1 0x100dc5d0 +// class MxCollection + +// VTABLE: LEGO1 0x100dc5e8 +// class MxList + +// VTABLE: LEGO1 0x100dc600 +// SIZE 0x18 +class MxStreamChunkList : public MxList { +public: + MxStreamChunkList() { m_customDestructor = Destroy; } + + // FUNCTION: LEGO1 0x100b5900 + MxS8 Compare(MxStreamChunk* p_a, MxStreamChunk* p_b) override + { + return p_a == p_b ? 0 : p_a < p_b ? -1 : 1; + } // vtable+0x14 + + // FUNCTION: LEGO1 0x100b5920 + static void Destroy(MxStreamChunk* p_chunk) { delete p_chunk; } + + // SYNTHETIC: LEGO1 0x100b5a30 + // MxStreamChunkList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dc510 +// SIZE 0x10 +class MxStreamChunkListCursor : public MxListCursor { +public: + MxStreamChunkListCursor(MxStreamChunkList* p_list) : MxListCursor(p_list) {} +}; + +// VTABLE: LEGO1 0x100dc528 +// class MxListCursor + +// TEMPLATE: LEGO1 0x100b5930 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x100b5940 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x100b5990 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x100b59a0 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x100b5aa0 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100b5b10 +// MxList::`scalar deleting destructor' + +#endif // MXSTREAMCHUNKLIST_H diff --git a/LEGO1/omni/include/mxstreamcontroller.h b/LEGO1/omni/include/mxstreamcontroller.h new file mode 100644 index 00000000..8948edf4 --- /dev/null +++ b/LEGO1/omni/include/mxstreamcontroller.h @@ -0,0 +1,122 @@ +#ifndef MXSTREAMCONTROLLER_H +#define MXSTREAMCONTROLLER_H + +#include "decomp.h" +#include "mxatom.h" +#include "mxcore.h" +#include "mxcriticalsection.h" +#include "mxdssubscriber.h" +#include "mxstl/stlcompat.h" +#include "mxstreamlist.h" + +class MxDSStreamingAction; +class MxStreamProvider; + +// VTABLE: LEGO1 0x100dc968 +// SIZE 0x64 +class MxStreamController : public MxCore { +public: + MxStreamController(); + ~MxStreamController() override; // vtable+0x00 + + // FUNCTION: LEGO1 0x100c0f10 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x10102130 + return "MxStreamController"; + } + + // FUNCTION: LEGO1 0x100c0f20 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxStreamController::ClassName()) || MxCore::IsA(p_name); + } + + virtual MxResult Open(const char* p_filename); // vtable+0x14 + virtual MxResult VTable0x18(undefined4, undefined4); // vtable+0x18 + virtual MxResult VTable0x1c(undefined4, undefined4); // vtable+0x1c + virtual MxResult VTable0x20(MxDSAction* p_action); // vtable+0x20 + virtual MxResult VTable0x24(MxDSAction* p_action); // vtable+0x24 + virtual MxDSStreamingAction* VTable0x28(); // vtable+0x28 + virtual MxResult VTable0x2c(MxDSAction* p_action, MxU32 p_bufferval); // vtable+0x2c + virtual MxResult VTable0x30(MxDSAction* p_action); // vtable+0x30 + + void AddSubscriber(MxDSSubscriber* p_subscriber); + void RemoveSubscriber(MxDSSubscriber* p_subscriber); + MxResult FUN_100c1800(MxDSAction* p_action, MxU32 p_val); + MxResult FUN_100c1a00(MxDSAction* p_action, MxU32 p_offset); + MxPresenter* FUN_100c1e70(MxDSAction& p_action); + MxResult FUN_100c1f00(MxDSAction* p_action); + MxBool FUN_100c20d0(MxDSObject& p_obj); + MxResult InsertActionToList54(MxDSAction* p_action); + MxNextActionDataStart* FindNextActionDataStartFromStreamingAction(MxDSStreamingAction* p_action); + + inline MxAtomId& GetAtom() { return m_atom; } + inline MxStreamProvider* GetProvider() { return m_provider; } + inline MxStreamListMxDSAction& GetUnk0x3c() { return m_unk0x3c; } + inline MxStreamListMxDSAction& GetUnk0x54() { return m_unk0x54; } + inline MxStreamListMxDSSubscriber& GetSubscriberList() { return m_subscriberList; } + +protected: + MxCriticalSection m_criticalSection; // 0x08 + MxAtomId m_atom; // 0x24 + MxStreamProvider* m_provider; // 0x28 + undefined4* m_unk0x2c; // 0x2c + MxStreamListMxDSSubscriber m_subscriberList; // 0x30 + MxStreamListMxDSAction m_unk0x3c; // 0x3c + MxStreamListMxNextActionDataStart m_nextActionList; // 0x48 + MxStreamListMxDSAction m_unk0x54; // 0x54 + MxDSAction* m_action0x60; // 0x60 +}; + +// TEMPLATE: LEGO1 0x100c0d60 +// list >::~list > + +// TEMPLATE: LEGO1 0x100c0dd0 +// list >::~list > + +// TEMPLATE: LEGO1 0x100c0e40 +// list >::_Buynode + +// clang-format off +// TEMPLATE: LEGO1 0x100c0e70 +// list >::~list > +// clang-format on + +// TEMPLATE: LEGO1 0x100c0ee0 +// list >::_Buynode + +// SYNTHETIC: LEGO1 0x100c0fa0 +// MxStreamController::`scalar deleting destructor' + +// FUNCTION: LEGO1 0x100c0fc0 +// MxStreamListMxDSSubscriber::~MxStreamListMxDSSubscriber + +// FUNCTION: LEGO1 0x100c1010 +// MxStreamListMxDSAction::~MxStreamListMxDSAction + +// FUNCTION: LEGO1 0x100c1060 +// MxStreamListMxNextActionDataStart::~MxStreamListMxNextActionDataStart + +// TEMPLATE: LEGO1 0x100c10b0 +// MxStreamList::~MxStreamList + +// TEMPLATE: LEGO1 0x100c1100 +// MxStreamList::~MxStreamList + +// TEMPLATE: LEGO1 0x100c1150 +// MxStreamList::~MxStreamList + +// TEMPLATE: LEGO1 0x100c11a0 +// List::~List + +// TEMPLATE: LEGO1 0x100c11f0 +// List::~List + +// TEMPLATE: LEGO1 0x100c1240 +// List::~List + +// TEMPLATE: LEGO1 0x100c1bc0 +// list >::insert + +#endif // MXSTREAMCONTROLLER_H diff --git a/LEGO1/omni/include/mxstreamer.h b/LEGO1/omni/include/mxstreamer.h new file mode 100644 index 00000000..95c53fee --- /dev/null +++ b/LEGO1/omni/include/mxstreamer.h @@ -0,0 +1,139 @@ +#ifndef MXSTREAMER_H +#define MXSTREAMER_H + +#include "decomp.h" +#include "mxcore.h" +#include "mxmemorypool.h" +#include "mxnotificationparam.h" +#include "mxstl/stlcompat.h" +#include "mxstreamcontroller.h" +#include "mxtypes.h" + +#include + +class MxDSObject; + +typedef MxMemoryPool<64, 22> MxMemoryPool64; +typedef MxMemoryPool<128, 2> MxMemoryPool128; + +// VTABLE: LEGO1 0x100dc760 +// SIZE 0x10 +class MxStreamerNotification : public MxNotificationParam { +public: + inline MxStreamerNotification(NotificationId p_type, MxCore* p_sender, MxStreamController* p_ctrlr) + : MxNotificationParam(p_type, p_sender) + { + m_controller = p_ctrlr; + } + + MxNotificationParam* Clone() const override; + + MxStreamController* GetController() { return m_controller; } + +private: + MxStreamController* m_controller; // 0x0c +}; + +// VTABLE: LEGO1 0x100dc710 +// SIZE 0x2c +class MxStreamer : public MxCore { +public: + enum OpenMode { + e_diskStream = 0, + e_RAMStream + }; + + MxStreamer(); + ~MxStreamer() override; // vtable+0x00 + + MxStreamController* Open(const char* p_name, MxU16 p_openMode); + MxLong Close(const char* p_name); + + MxLong Notify(MxParam& p_param) override; // vtable+0x04 + + // FUNCTION: LEGO1 0x100b9000 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x1010210c + return "MxStreamer"; + } + + // FUNCTION: LEGO1 0x100b9010 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxStreamer::ClassName()) || MxCore::IsA(p_name); + } + + virtual MxResult Create(); // vtable+0x14 + + MxBool FUN_100b9b30(MxDSObject& p_dsObject); + MxStreamController* GetOpenStream(const char* p_name); + void FUN_100b98f0(MxDSAction* p_action); + MxResult AddStreamControllerToOpenList(MxStreamController* p_stream); + MxResult FUN_100b99b0(MxDSAction* p_action); + MxResult DeleteObject(MxDSAction* p_dsAction); + + MxU8* GetMemoryBlock(MxU32 p_blockSize) + { + switch (p_blockSize) { + case 0x40: + return m_pool64.Get(); + + case 0x80: + return m_pool128.Get(); + + default: + assert("Invalid block size for memory pool" == NULL); + break; + } + + return NULL; + } + + void ReleaseMemoryBlock(MxU8* p_block, MxU32 p_blockSize) + { + switch (p_blockSize) { + case 0x40: + m_pool64.Release(p_block); + break; + + case 0x80: + m_pool128.Release(p_block); + break; + + default: + assert("Invalid block size for memory pool" == NULL); + break; + } + } + +private: + list m_openStreams; // 0x08 + MxMemoryPool64 m_pool64; // 0x14 + MxMemoryPool128 m_pool128; // 0x20 +}; + +// clang-format off +// TEMPLATE: LEGO1 0x100b9090 +// list >::~list > +// clang-format on + +// TEMPLATE: LEGO1 0x100b9100 +// MxMemoryPool<64,22>::~MxMemoryPool<64,22> + +// TEMPLATE: LEGO1 0x100b9110 +// MxMemoryPool<128,2>::~MxMemoryPool<128,2> + +// SYNTHETIC: LEGO1 0x100b9120 +// MxStreamer::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b9140 +// List::~List + +// SYNTHETIC: LEGO1 0x100b97b0 +// MxStreamerNotification::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100b9820 +// MxStreamerNotification::~MxStreamerNotification + +#endif // MXSTREAMER_H diff --git a/LEGO1/omni/include/mxstreamlist.h b/LEGO1/omni/include/mxstreamlist.h new file mode 100644 index 00000000..0e0f1e9f --- /dev/null +++ b/LEGO1/omni/include/mxstreamlist.h @@ -0,0 +1,56 @@ +#ifndef MXSTREAMLIST_H +#define MXSTREAMLIST_H + +#include "mxdsstreamingaction.h" +#include "mxdssubscriber.h" +#include "mxnextactiondatastart.h" +#include "mxstl/stlcompat.h" + +template +class MxStreamList : public list { +public: + MxBool PopFront(T& p_obj) + { + if (this->empty()) { + return FALSE; + } + + p_obj = this->front(); + this->pop_front(); + return TRUE; + } +}; + +// SIZE 0x0c +class MxStreamListMxDSAction : public MxStreamList { +public: + MxDSAction* Find(MxDSAction* p_action, MxBool p_delete); + + // There chance this list actually holds MxDSStreamingListAction + // instead of MxDSAction. Until then, we use this helper. + MxBool PopFrontStreamingAction(MxDSStreamingAction*& p_obj) + { + if (empty()) { + return FALSE; + } + + p_obj = (MxDSStreamingAction*) front(); + pop_front(); + return TRUE; + } +}; + +// SIZE 0x0c +class MxStreamListMxNextActionDataStart : public MxStreamList { +public: + MxNextActionDataStart* Find(MxU32 p_id, MxS16 p_value); + MxNextActionDataStart* FindAndErase(MxU32 p_id, MxS16 p_value); +}; + +// SIZE 0x0c +class MxStreamListMxDSSubscriber : public MxStreamList { +public: + MxDSSubscriber* Find(MxDSObject* p_object); +}; + +#endif // MXSTREAMLIST_H diff --git a/LEGO1/omni/include/mxstreamprovider.h b/LEGO1/omni/include/mxstreamprovider.h new file mode 100644 index 00000000..19f455e8 --- /dev/null +++ b/LEGO1/omni/include/mxstreamprovider.h @@ -0,0 +1,47 @@ +#ifndef MXSTREAMPROVIDER_H +#define MXSTREAMPROVIDER_H + +#include "decomp.h" +#include "mxcore.h" + +class MxStreamController; +class MxDSAction; +class MxDSFile; + +// VTABLE: LEGO1 0x100dd100 +// SIZE 0x10 +class MxStreamProvider : public MxCore { +public: + inline MxStreamProvider() : m_pLookup(NULL), m_pFile(NULL) {} + + // FUNCTION: LEGO1 0x100d07e0 + inline const char* ClassName() const override // vtable+0x0c + { + return "MxStreamProvider"; + } + + // FUNCTION: LEGO1 0x100d07f0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxStreamProvider::ClassName()) || MxCore::IsA(p_name); + } + + virtual MxResult SetResourceToGet(MxStreamController* p_resource); // vtable+0x14 + virtual MxU32 GetFileSize() = 0; // vtable+0x18 + virtual MxS32 GetStreamBuffersNum() = 0; // vtable+0x1c + virtual void VTable0x20(MxDSAction* p_action); // vtable+0x20 + virtual MxU32 GetLengthInDWords() = 0; // vtable+0x24 + virtual MxU32* GetBufferForDWords() = 0; // vtable+0x28 + +protected: + MxStreamController* m_pLookup; // 0x08 + MxDSFile* m_pFile; // 0x0c +}; + +// SYNTHETIC: LEGO1 0x100d0870 +// MxStreamProvider::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100d08e0 +// MxStreamProvider::~MxStreamProvider + +#endif // MXSTREAMPROVIDER_H diff --git a/LEGO1/omni/include/mxstring.h b/LEGO1/omni/include/mxstring.h new file mode 100644 index 00000000..5d973e69 --- /dev/null +++ b/LEGO1/omni/include/mxstring.h @@ -0,0 +1,50 @@ +#ifndef MXSTRING_H +#define MXSTRING_H + +#include "mxcore.h" + +// VTABLE: LEGO1 0x100dc110 +// VTABLE: BETA10 0x101c1be0 +// SIZE 0x10 +class MxString : public MxCore { +public: + MxString(); + MxString(const MxString& p_str); + MxString(const char* p_str); + MxString(const char* p_str, MxU16 p_maxlen); + ~MxString() override; + + void Reverse(); + void ToUpperCase(); + void ToLowerCase(); + + MxString& operator=(const MxString& p_str); + const MxString& operator=(const char* p_str); + MxString operator+(const MxString& p_str) const; + MxString operator+(const char* p_str) const; + MxString& operator+=(const char* p_str); + + static void CharSwap(char* p_a, char* p_b); + + // FUNCTION: BETA10 0x10017c50 + inline char* GetData() const { return m_data; } + + // FUNCTION: BETA10 0x10067630 + inline const MxU16 GetLength() const { return m_length; } + + // FUNCTION: BETA10 0x100d8a30 + inline MxBool Equal(const MxString& p_str) const { return strcmp(m_data, p_str.m_data) == 0; } + + // FUNCTION: BETA10 0x1012a810 + inline MxS8 Compare(const MxString& p_str) const { return strcmp(m_data, p_str.m_data); } + + // SYNTHETIC: LEGO1 0x100ae280 + // SYNTHETIC: BETA10 0x1012c9d0 + // MxString::`scalar deleting destructor' + +private: + char* m_data; // 0x08 + MxU16 m_length; // 0x0c +}; + +#endif // MXSTRING_H diff --git a/LEGO1/omni/include/mxstringlist.h b/LEGO1/omni/include/mxstringlist.h new file mode 100644 index 00000000..7894aabd --- /dev/null +++ b/LEGO1/omni/include/mxstringlist.h @@ -0,0 +1,60 @@ +#ifndef MXSTRINGLIST_H +#define MXSTRINGLIST_H + +#include "mxlist.h" +#include "mxstring.h" + +// VTABLE: LEGO1 0x100dd040 +// SIZE 0x18 +class MxStringList : public MxList {}; + +// VTABLE: LEGO1 0x100dd058 +// SIZE 0x10 +class MxStringListCursor : public MxListCursor { +public: + MxStringListCursor(MxStringList* p_list) : MxListCursor(p_list) {} + + // SYNTHETIC: LEGO1 0x100cb860 + // MxStringList::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dd010 +// class MxCollection + +// VTABLE: LEGO1 0x100dd028 +// class MxList + +// VTABLE: LEGO1 0x100dd070 +// class MxListCursor + +// TEMPLATE: LEGO1 0x100cb3c0 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x100cb420 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x100cb470 +// MxCollection::Destroy + +// TEMPLATE: LEGO1 0x100cb4c0 +// MxList::~MxList + +// SYNTHETIC: LEGO1 0x100cb590 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100cb600 +// MxList::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100cbb40 +// MxList::Append + +// TEMPLATE: LEGO1 0x100cc2d0 +// MxList::InsertEntry + +// TEMPLATE: LEGO1 0x100cc3c0 +// MxListEntry::MxListEntry + +// TEMPLATE: LEGO1 0x100cc450 +// MxListEntry::GetValue + +#endif // MXSTRINGLIST_H diff --git a/LEGO1/omni/include/mxthread.h b/LEGO1/omni/include/mxthread.h new file mode 100644 index 00000000..6016aa8f --- /dev/null +++ b/LEGO1/omni/include/mxthread.h @@ -0,0 +1,60 @@ +#ifndef MXTHREAD_H +#define MXTHREAD_H + +#include "compat.h" +#include "mxsemaphore.h" +#include "mxtypes.h" + +class MxCore; + +// VTABLE: LEGO1 0x100dc860 +// SIZE 0x1c +class MxThread { +public: + // Note: Comes before virtual destructor + virtual MxResult Run(); + + MxResult Start(MxS32 p_stack, MxS32 p_flag); + + void Terminate(); + void Sleep(MxS32 p_milliseconds); + + inline MxBool IsRunning() { return m_running; } + + // SYNTHETIC: LEGO1 0x100bf580 + // MxThread::`scalar deleting destructor' + +protected: + MxThread(); + +public: + virtual ~MxThread(); + +private: + static unsigned ThreadProc(void* p_thread); + + MxULong m_hThread; // 0x04 + MxU32 m_threadId; // 0x08 + MxBool m_running; // 0x0c + MxSemaphore m_semaphore; // 0x10 + +protected: + MxCore* m_target; // 0x18 +}; + +// VTABLE: LEGO1 0x100dc6d8 +// SIZE 0x20 +class MxTickleThread : public MxThread { +public: + MxTickleThread(MxCore* p_target, MxS32 p_frequencyMS); + + MxResult Run() override; + + // SYNTHETIC: LEGO1 0x100b8c20 + // MxTickleThread::`scalar deleting destructor' + +private: + MxS32 m_frequencyMS; // 0x1c +}; + +#endif // MXTHREAD_H diff --git a/LEGO1/omni/include/mxticklemanager.h b/LEGO1/omni/include/mxticklemanager.h new file mode 100644 index 00000000..8d1327a5 --- /dev/null +++ b/LEGO1/omni/include/mxticklemanager.h @@ -0,0 +1,64 @@ +#ifndef MXTICKLEMANAGER_H +#define MXTICKLEMANAGER_H + +#include "mxcore.h" +#include "mxstl/stlcompat.h" +#include "mxtypes.h" + +// SIZE 0x10 +class MxTickleClient { +public: + MxTickleClient(MxCore* p_client, MxTime p_interval); + + inline MxCore* GetClient() const { return m_client; } + + inline MxTime GetTickleInterval() const { return m_interval; } + + inline MxTime GetLastUpdateTime() const { return m_lastUpdateTime; } + + inline MxU16 GetFlags() const { return m_flags; } + + inline void SetTickleInterval(MxTime p_interval) { m_interval = p_interval; } + + inline void SetLastUpdateTime(MxTime p_lastUpdateTime) { m_lastUpdateTime = p_lastUpdateTime; } + + inline void SetFlags(MxU16 p_flags) { m_flags = p_flags; } + +private: + MxCore* m_client; // 0x00 + MxTime m_interval; // 0x04 + MxTime m_lastUpdateTime; // 0x08 + MxU16 m_flags; // 0x0c +}; + +typedef list MxTickleClientPtrList; + +// VTABLE: LEGO1 0x100d86d8 +// SIZE 0x14 +class MxTickleManager : public MxCore { +public: + inline MxTickleManager() {} + ~MxTickleManager() override; + + MxResult Tickle() override; // vtable+0x08 + virtual void RegisterClient(MxCore* p_client, MxTime p_interval); // vtable+0x14 + virtual void UnregisterClient(MxCore* p_client); // vtable+0x18 + virtual void SetClientTickleInterval(MxCore* p_client, MxTime p_interval); // vtable+0x1c + virtual MxTime GetClientTickleInterval(MxCore* p_client); // vtable+0x20 + + // SYNTHETIC: LEGO1 0x1005a510 + // MxTickleManager::`scalar deleting destructor' + +private: + MxTickleClientPtrList m_clients; // 0x08 +}; + +#define TICKLE_MANAGER_NOT_FOUND 0x80000000 + +// TEMPLATE: LEGO1 0x1005a4a0 +// list >::~list > + +// TEMPLATE: LEGO1 0x1005a530 +// List::~List + +#endif // MXTICKLEMANAGER_H diff --git a/LEGO1/omni/include/mxtimer.h b/LEGO1/omni/include/mxtimer.h new file mode 100644 index 00000000..980719de --- /dev/null +++ b/LEGO1/omni/include/mxtimer.h @@ -0,0 +1,38 @@ +#ifndef MXTIMER_H +#define MXTIMER_H + +#include "mxcore.h" + +// VTABLE: LEGO1 0x100dc0e0 +// SIZE 0x10 +class MxTimer : public MxCore { +public: + MxTimer(); + + void Start(); + void Stop(); + + MxLong GetRealTime(); + + inline MxLong GetTime() + { + if (this->m_isRunning) { + return g_lastTimeTimerStarted; + } + else { + return g_lastTimeCalculated - this->m_startTime; + } + } + + // SYNTHETIC: LEGO1 0x100ae0d0 + // MxTimer::`scalar deleting destructor' + +private: + MxLong m_startTime; // 0x08 + MxBool m_isRunning; // 0x0c + + static MxLong g_lastTimeCalculated; + static MxLong g_lastTimeTimerStarted; +}; + +#endif // MXTIMER_H diff --git a/LEGO1/omni/include/mxtype19notificationparam.h b/LEGO1/omni/include/mxtype19notificationparam.h new file mode 100644 index 00000000..51a6a713 --- /dev/null +++ b/LEGO1/omni/include/mxtype19notificationparam.h @@ -0,0 +1,15 @@ +#ifndef MXTYPE19NOTIFICATIONPARAM_H +#define MXTYPE19NOTIFICATIONPARAM_H + +#include "decomp.h" +#include "mxnotificationparam.h" + +// VTABLE: LEGO1 0x100d6230 +// SIZE 0x10 +class MxType19NotificationParam : public MxNotificationParam { +protected: + MxU16 m_unk0x0c; // 0x0c + MxU8 m_unk0x0e; // 0x0e +}; + +#endif // MXTYPE19NOTIFICATIONPARAM_H diff --git a/LEGO1/omni/include/mxtypes.h b/LEGO1/omni/include/mxtypes.h new file mode 100644 index 00000000..caecb68a --- /dev/null +++ b/LEGO1/omni/include/mxtypes.h @@ -0,0 +1,77 @@ +#ifndef MXTYPES_H +#define MXTYPES_H + +typedef unsigned char MxU8; +typedef signed char MxS8; +typedef unsigned short MxU16; +typedef signed short MxS16; +typedef unsigned int MxU32; +typedef signed int MxS32; +#ifdef _MSC_VER +typedef unsigned __int64 MxU64; +typedef signed __int64 MxS64; +#else +typedef unsigned long long int MxU64; +typedef signed long long int MxS64; +#endif +typedef float MxFloat; +typedef double MxDouble; + +// On MSVC, a long is 32-bit, but on GCC/Clang, it's 64-bit. LEGO Island obviously +// assumes the former in all cases, which could become an issue in the future. +// The "longs" can't all be changed to "ints" (which are 32-bit on both) because +// this will break DLL export compatibility. Therefore, we define MxLong/MxULong, +// which is guaranteed to be 32-bit, and guaranteed to be a "long" on MSVC. +#if defined(_MSC_VER) +typedef long MxLong; +typedef unsigned long MxULong; +#else +typedef int MxLong; +typedef unsigned int MxULong; +#endif + +typedef MxS32 MxTime; + +typedef MxLong MxResult; + +#ifndef SUCCESS +#define SUCCESS 0 +#endif + +#ifndef FAILURE +#define FAILURE -1 +#endif + +typedef MxU8 MxBool; + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define TWOCC(a, b) (((a) << 0) | ((b) << 8)) +#define FOURCC(a, b, c, d) (((a) << 0) | ((b) << 8) | ((c) << 16) | ((d) << 24)) + +// Must be union with struct for match. +typedef union { + struct { + MxU8 m_bit0 : 1; + MxU8 m_bit1 : 1; + MxU8 m_bit2 : 1; + MxU8 m_bit3 : 1; + MxU8 m_bit4 : 1; + MxU8 m_bit5 : 1; + MxU8 m_bit6 : 1; + MxU8 m_bit7 : 1; + }; + // BYTE all; // ? +} FlagBitfield; + +#endif // MXTYPES_H diff --git a/LEGO1/omni/include/mxutilities.h b/LEGO1/omni/include/mxutilities.h new file mode 100644 index 00000000..59ff7d89 --- /dev/null +++ b/LEGO1/omni/include/mxutilities.h @@ -0,0 +1,82 @@ +#ifndef MXUTILITIES_H +#define MXUTILITIES_H + +#include "mxtypes.h" + +#include + +class MxDSFile; +class MxDSObject; +class MxDSAction; +class MxCompositePresenterList; +class MxPresenter; + +template +inline T Abs(T p_t) +{ + return p_t < 0 ? -p_t : p_t; +} + +template +inline T Min(T p_t1, T p_t2) +{ + return p_t1 < p_t2 ? p_t1 : p_t2; +} + +template +inline T Max(T p_t1, T p_t2) +{ + return p_t1 > p_t2 ? p_t1 : p_t2; +} + +template +inline void GetScalar(MxU8*& p_source, T& p_dest) +{ + p_dest = *(T*) p_source; + p_source += sizeof(T); +} + +template +inline T GetScalar(T*& p_source) +{ + T val = *p_source; + p_source += 1; + return val; +} + +template +inline void GetDouble(MxU8*& p_source, T& p_dest) +{ + p_dest = *(double*) p_source; + p_source += sizeof(double); +} + +template +inline void GetString(MxU8*& p_source, char*& p_dest, T* p_obj, void (T::*p_setter)(const char*)) +{ + (p_obj->*p_setter)((char*) p_source); + p_source += strlen(p_dest) + 1; +} + +MxBool GetRectIntersection( + MxS32 p_rect1Width, + MxS32 p_rect1Height, + MxS32 p_rect2Width, + MxS32 p_rect2Height, + MxS32* p_rect1Left, + MxS32* p_rect1Top, + MxS32* p_rect2Left, + MxS32* p_rect2Top, + MxS32* p_width, + MxS32* p_height +); + +void MakeSourceName(char*, const char*); +void OmniError(const char* p_message, MxS32 p_status); +void SetOmniUserMessage(void (*p_omniUserMessage)(const char*, MxS32)); +MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter* p_presenter); +void FUN_100b7220(MxDSAction* p_action, MxU32 p_newFlags, MxBool p_setFlags); +MxDSObject* CreateStreamObject(MxDSFile*, MxS16); +MxBool KeyValueStringParse(char*, const char*, const char*); + +#endif // MXUTILITIES_H diff --git a/LEGO1/omni/include/mxvariable.h b/LEGO1/omni/include/mxvariable.h new file mode 100644 index 00000000..7f1e8c33 --- /dev/null +++ b/LEGO1/omni/include/mxvariable.h @@ -0,0 +1,52 @@ +#ifndef MXVARIABLE_H +#define MXVARIABLE_H + +#include "mxcore.h" +#include "mxstring.h" + +// VTABLE: LEGO1 0x100d7498 +// VTABLE: BETA10 0x101bc038 +// SIZE 0x24 +class MxVariable { +public: + MxVariable() {} + + // FUNCTION: BETA10 0x1012a840 + MxVariable(const char* p_key, const char* p_value) + { + m_key = p_key; + m_key.ToUpperCase(); + m_value = p_value; + } + + // FUNCTION: BETA10 0x1012aa30 + MxVariable(const char* p_key) + { + m_key = p_key; + m_key.ToUpperCase(); + } + + // FUNCTION: LEGO1 0x1003bea0 + // FUNCTION: BETA10 0x1007b810 + virtual MxString* GetValue() { return &m_value; } // vtable+0x00 + + // FUNCTION: LEGO1 0x1003beb0 + // FUNCTION: BETA10 0x1007b840 + virtual void SetValue(const char* p_value) { m_value = p_value; } // vtable+0x04 + + // FUNCTION: LEGO1 0x1003bec0 + // FUNCTION: BETA10 0x1007b870 + virtual void Destroy() { delete this; } // vtable+0x08 + + // FUNCTION: BETA10 0x1012a7f0 + inline const MxString* GetKey() const { return &m_key; } + +protected: + MxString m_key; // 0x04 + MxString m_value; // 0x14 +}; + +// SYNTHETIC: LEGO1 0x1003bf40 +// MxVariable::~MxVariable + +#endif // MXVARIABLE_H diff --git a/LEGO1/omni/include/mxvariabletable.h b/LEGO1/omni/include/mxvariabletable.h new file mode 100644 index 00000000..a9dab29e --- /dev/null +++ b/LEGO1/omni/include/mxvariabletable.h @@ -0,0 +1,120 @@ +#ifndef MXVARIABLETABLE_H +#define MXVARIABLETABLE_H + +#include "mxhashtable.h" +#include "mxtypes.h" +#include "mxvariable.h" + +// VTABLE: LEGO1 0x100dc1c8 +// VTABLE: BETA10 0x101c1c78 +// SIZE 0x28 +class MxVariableTable : public MxHashTable { +public: + // FUNCTION: BETA10 0x10130e50 + MxVariableTable() { SetDestroy(Destroy); } + void SetVariable(const char* p_key, const char* p_value); + void SetVariable(MxVariable* p_var); + const char* GetVariable(const char* p_key); + + // FUNCTION: LEGO1 0x100afdb0 + // FUNCTION: BETA10 0x10130f00 + static void Destroy(MxVariable* p_obj) { p_obj->Destroy(); } + + MxS8 Compare(MxVariable*, MxVariable*) override; // vtable+0x14 + MxU32 Hash(MxVariable*) override; // vtable+0x18 + + // SYNTHETIC: LEGO1 0x100afdd0 + // SYNTHETIC: BETA10 0x10130f20 + // MxVariableTable::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dc1b0 +// VTABLE: BETA10 0x101c1cd0 +// class MxCollection + +// VTABLE: LEGO1 0x100dc1e8 +// VTABLE: BETA10 0x101c1cb0 +// class MxHashTable + +// VTABLE: LEGO1 0x100dc680 +// VTABLE: BETA10 0x101c1b48 +// class MxHashTableCursor + +// TEMPLATE: LEGO1 0x100afcd0 +// TEMPLATE: BETA10 0x10132950 +// MxCollection::Compare + +// TEMPLATE: LEGO1 0x100afce0 +// TEMPLATE: BETA10 0x10132a00 +// MxCollection::~MxCollection + +// TEMPLATE: LEGO1 0x100afd30 +// TEMPLATE: BETA10 0x10132a70 +// MxCollection::Destroy + +// SYNTHETIC: LEGO1 0x100afd40 +// SYNTHETIC: BETA10 0x10132a80 +// MxCollection::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100afdc0 +// TEMPLATE: BETA10 0x10132ac0 +// MxHashTable::Hash + +// TEMPLATE: LEGO1 0x100b0bd0 +// TEMPLATE: BETA10 0x10132ae0 +// MxHashTable::~MxHashTable + +// SYNTHETIC: LEGO1 0x100b0ca0 +// SYNTHETIC: BETA10 0x10132b70 +// MxHashTable::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b7680 +// TEMPLATE: BETA10 0x1012a990 +// MxHashTableCursor::~MxHashTableCursor + +// SYNTHETIC: LEGO1 0x100b76d0 +// SYNTHETIC: BETA10 0x1012a9f0 +// MxHashTableCursor::`scalar deleting destructor' + +// TEMPLATE: LEGO1 0x100b7ab0 +// TEMPLATE: BETA10 0x1012adc0 +// MxHashTable::Resize + +// TEMPLATE: LEGO1 0x100b7b80 +// TEMPLATE: BETA10 0x1012af10 +// MxHashTable::NodeInsert + +// TEMPLATE: BETA10 0x1012a900 +// MxHashTableCursor::MxHashTableCursor + +// TEMPLATE: BETA10 0x1012aae0 +// MxHashTable::Add + +// TEMPLATE: BETA10 0x1012abd0 +// MxHashTableCursor::Current + +// TEMPLATE: BETA10 0x1012ac20 +// MxHashTableCursor::DeleteMatch + +// TEMPLATE: BETA10 0x1012ad00 +// MxHashTableCursor::Find + +// TEMPLATE: BETA10 0x1012af90 +// MxHashTableNode::MxHashTableNode + +// TEMPLATE: BETA10 0x10132890 +// MxHashTable::MxHashTable + +// TEMPLATE: BETA10 0x10130ed0 +// MxCollection::SetDestroy + +// SYNTHETIC: BETA10 0x10130f60 +// MxVariableTable::~MxVariableTable + +// SYNTHETIC: BETA10 0x10132970 +// MxCollection::MxCollection + +// TEMPLATE: BETA10 0x10132bb0 +// MxHashTable::DeleteAll + +#endif // MXVARIABLETABLE_H diff --git a/LEGO1/omni/include/mxvideomanager.h b/LEGO1/omni/include/mxvideomanager.h new file mode 100644 index 00000000..02c16b61 --- /dev/null +++ b/LEGO1/omni/include/mxvideomanager.h @@ -0,0 +1,60 @@ +#ifndef MXVIDEOMANAGER_H +#define MXVIDEOMANAGER_H + +#include "mxmediamanager.h" +#include "mxvideoparam.h" + +#include + +class MxDisplaySurface; +class MxRect32; +class MxRegion; + +// VTABLE: LEGO1 0x100dc810 +// SIZE 0x64 +class MxVideoManager : public MxMediaManager { +public: + MxVideoManager(); + ~MxVideoManager() override; + + MxResult Tickle() override; // vtable+0x08 + void Destroy() override; // vtable+0x18 + virtual MxResult VTable0x28( + MxVideoParam& p_videoParam, + LPDIRECTDRAW p_pDirectDraw, + LPDIRECT3D2 p_pDirect3D, + LPDIRECTDRAWSURFACE p_ddSurface1, + LPDIRECTDRAWSURFACE p_ddSurface2, + LPDIRECTDRAWCLIPPER p_ddClipper, + MxU32 p_frequencyMS, + MxBool p_createThread + ); // vtable+0x28 + virtual MxResult Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x2c + + void InvalidateRect(MxRect32&); + virtual MxResult RealizePalette(MxPalette*); // vtable+0x30 + virtual void UpdateView(MxU32 p_x, MxU32 p_y, MxU32 p_width, MxU32 p_height); // vtable+0x34 + + MxResult Init(); + void Destroy(MxBool p_fromDestructor); + void SortPresenterList(); + void UpdateRegion(); + + inline MxVideoParam& GetVideoParam() { return this->m_videoParam; } + inline LPDIRECTDRAW GetDirectDraw() { return this->m_pDirectDraw; } + inline MxDisplaySurface* GetDisplaySurface() { return this->m_displaySurface; } + inline MxRegion* GetRegion() { return this->m_region; } + + // SYNTHETIC: LEGO1 0x100be280 + // MxVideoManager::`scalar deleting destructor' + +protected: + MxVideoParam m_videoParam; // 0x2c + LPDIRECTDRAW m_pDirectDraw; // 0x50 + LPDIRECT3D2 m_pDirect3D; // 0x54 + MxDisplaySurface* m_displaySurface; // 0x58 + MxRegion* m_region; // 0x5c + MxBool m_unk0x60; // 0x60 +}; + +#endif // MXVIDEOMANAGER_H diff --git a/LEGO1/omni/include/mxvideoparam.h b/LEGO1/omni/include/mxvideoparam.h new file mode 100644 index 00000000..f9766b97 --- /dev/null +++ b/LEGO1/omni/include/mxvideoparam.h @@ -0,0 +1,43 @@ +#ifndef MXVIDEOPARAM_H +#define MXVIDEOPARAM_H + +#include "compat.h" +#include "mxrect32.h" +#include "mxtypes.h" +#include "mxvideoparamflags.h" + +#include + +class MxPalette; + +// SIZE 0x24 +class MxVideoParam { +public: + MxVideoParam(); + MxVideoParam(MxVideoParam& p_videoParam); + __declspec(dllexport) + MxVideoParam(MxRect32& p_rect, MxPalette* p_palette, MxULong p_backBuffers, MxVideoParamFlags& p_flags); + MxVideoParam& operator=(const MxVideoParam& p_videoParam); + ~MxVideoParam(); + void SetDeviceName(char* p_deviceId); + + inline MxVideoParamFlags& Flags() { return m_flags; } + + inline void SetPalette(MxPalette* p_palette) { this->m_palette = p_palette; } + inline void SetBackBuffers(MxU32 p_backBuffers) { this->m_backBuffers = p_backBuffers; } + + inline MxRect32& GetRect() { return this->m_rect; } + inline MxPalette* GetPalette() { return this->m_palette; } + inline MxU32 GetBackBuffers() { return this->m_backBuffers; } + inline char* GetDeviceName() { return this->m_deviceId; } + +private: + MxRect32 m_rect; // 0x00 + MxPalette* m_palette; // 0x10 + MxU32 m_backBuffers; // 0x14 + MxVideoParamFlags m_flags; // 0x18 + int m_unk0x1c; // 0x1c + char* m_deviceId; // 0x20 +}; + +#endif // MXVIDEOPARAM_H diff --git a/LEGO1/omni/include/mxvideoparamflags.h b/LEGO1/omni/include/mxvideoparamflags.h new file mode 100644 index 00000000..8b937d38 --- /dev/null +++ b/LEGO1/omni/include/mxvideoparamflags.h @@ -0,0 +1,51 @@ +#ifndef MXVIDEOPARAMFLAGS_H +#define MXVIDEOPARAMFLAGS_H + +#include "mxtypes.h" + +#include + +class MxVideoParamFlags { +public: + MxVideoParamFlags(); + + inline void SetFullScreen(BOOL p_e) { m_flags1.m_bit0 = p_e; } + inline void SetFlipSurfaces(BOOL p_e) { m_flags1.m_bit1 = p_e; } + inline void SetBackBuffers(BOOL p_e) { m_flags1.m_bit2 = p_e; } + inline void SetF1bit3(BOOL p_e) { m_flags1.m_bit3 = p_e; } + inline void SetF1bit4(BOOL p_e) { m_flags1.m_bit4 = p_e; } + inline void Set16Bit(BYTE p_e) { m_flags1.m_bit5 = p_e; } + inline void SetWideViewAngle(BOOL p_e) { m_flags1.m_bit6 = p_e; } + inline void SetF1bit7(BOOL p_e) { m_flags1.m_bit7 = p_e; } + inline void SetF2bit0(BOOL p_e) { m_flags2.m_bit0 = p_e; } + inline void SetF2bit1(BOOL p_e) { m_flags2.m_bit1 = p_e; } + inline void SetF2bit2(BOOL p_e) { m_flags2.m_bit2 = p_e; } + inline void SetF2bit3(BOOL p_e) { m_flags2.m_bit3 = p_e; } + inline void SetF2bit4(BOOL p_e) { m_flags2.m_bit4 = p_e; } + inline void SetF2bit5(BOOL p_e) { m_flags2.m_bit5 = p_e; } + inline void SetF2bit6(BOOL p_e) { m_flags2.m_bit6 = p_e; } + inline void SetF2bit7(BOOL p_e) { m_flags2.m_bit7 = p_e; } + + inline BYTE GetFullScreen() { return m_flags1.m_bit0; } + inline BYTE GetFlipSurfaces() { return m_flags1.m_bit1; } + inline BYTE GetBackBuffers() { return m_flags1.m_bit2; } + inline BYTE GetF1bit3() { return m_flags1.m_bit3; } + inline BYTE GetF1bit4() { return m_flags1.m_bit4; } + inline BYTE Get16Bit() { return m_flags1.m_bit5; } + inline BYTE GetWideViewAngle() { return m_flags1.m_bit6; } + inline BYTE GetF1bit7() { return m_flags1.m_bit7; } + inline BYTE GetF2bit0() { return m_flags2.m_bit0; } + inline BYTE GetF2bit1() { return m_flags2.m_bit1; } + inline BYTE GetF2bit2() { return m_flags2.m_bit2; } + inline BYTE GetF2bit3() { return m_flags2.m_bit3; } + inline BYTE GetF2bit4() { return m_flags2.m_bit4; } + inline BYTE GetF2bit5() { return m_flags2.m_bit5; } + inline BYTE GetF2bit6() { return m_flags2.m_bit6; } + inline BYTE GetF2bit7() { return m_flags2.m_bit7; } + +private: + FlagBitfield m_flags1; + FlagBitfield m_flags2; +}; + +#endif // MXVIDEOPARAMFLAGS_H diff --git a/LEGO1/omni/include/mxvideopresenter.h b/LEGO1/omni/include/mxvideopresenter.h new file mode 100644 index 00000000..19a40e39 --- /dev/null +++ b/LEGO1/omni/include/mxvideopresenter.h @@ -0,0 +1,127 @@ +#ifndef MXVIDEOPRESENTER_H +#define MXVIDEOPRESENTER_H + +#include "decomp.h" +#include "mxbitmap.h" +#include "mxmediapresenter.h" +#include "mxrect32.h" + +#include + +// VTABLE: LEGO1 0x100d4be8 +// SIZE 0x64 +class MxVideoPresenter : public MxMediaPresenter { +public: + MxVideoPresenter() { Init(); } + + // FUNCTION: LEGO1 0x1000c740 + ~MxVideoPresenter() override { Destroy(TRUE); } // vtable+0x00 + + // FUNCTION: LEGO1 0x1000c820 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f0760 + return "MxVideoPresenter"; + } + + // FUNCTION: LEGO1 0x1000c830 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxVideoPresenter::ClassName()) || MxMediaPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + void RepeatingTickle() override; // vtable+0x24 + void FreezingTickle() override; // vtable+0x28 + MxResult AddToManager() override; // vtable+0x34 + + // FUNCTION: LEGO1 0x1000c7a0 + void Destroy() override { Destroy(FALSE); } // vtable+0x38 + + void EndAction() override; // vtable+0x40 + MxResult PutData() override; // vtable+0x4c + MxBool IsHit(MxS32 p_x, MxS32 p_y) override; // vtable+0x50 + + // FUNCTION: LEGO1 0x1000c700 + virtual void LoadHeader(MxStreamChunk* p_chunk) {} // vtable+0x5c + + // FUNCTION: LEGO1 0x1000c710 + virtual void CreateBitmap() {} // vtable+0x60 + + virtual void NextFrame(); // vtable+0x64 + + // FUNCTION: LEGO1 0x1000c720 + virtual void LoadFrame(MxStreamChunk* p_chunk) {} // vtable+0x68 + + virtual void PutFrame(); // vtable+0x6c + + // FUNCTION: LEGO1 0x1000c730 + virtual void RealizePalette() {} // vtable+0x70 + + virtual undefined VTable0x74(); // vtable+0x74 + + // FUNCTION: LEGO1 0x1000c7b0 + virtual LPDIRECTDRAWSURFACE VTable0x78() { return m_unk0x58; } // vtable+0x78 + + // FUNCTION: LEGO1 0x1000c7c0 + virtual MxBool VTable0x7c() { return m_frameBitmap != NULL || m_alpha != NULL; } // vtable+0x7c + + // FUNCTION: LEGO1 0x1000c7e0 + virtual MxS32 GetWidth() { return m_alpha ? m_alpha->m_width : m_frameBitmap->GetBmiWidth(); } // vtable+0x80 + + // FUNCTION: LEGO1 0x1000c800 + virtual MxS32 GetHeight() { return m_alpha ? m_alpha->m_height : m_frameBitmap->GetBmiHeightAbs(); } // vtable+0x84 + + // VTABLE: LEGO1 0x100dc2bc + // SIZE 0x0c + struct AlphaMask { + MxU8* m_bitmask; + MxU16 m_width; + MxU16 m_height; + + AlphaMask(const MxBitmap&); + AlphaMask(const AlphaMask&); + virtual ~AlphaMask(); + + MxS32 IsHit(MxU32 p_x, MxU32 p_y); + + // SYNTHETIC: LEGO1 0x100b2650 + // MxVideoPresenter::AlphaMask::`scalar deleting destructor' + }; + + inline MxS32 PrepareRects(RECT& p_rectDest, RECT& p_rectSrc); + inline MxBitmap* GetBitmap() { return m_frameBitmap; } + inline AlphaMask* GetAlphaMask() { return m_alpha; } + + inline void SetBit0(BOOL p_e) { m_flags.m_bit0 = p_e; } + inline void SetBit1(BOOL p_e) { m_flags.m_bit1 = p_e; } + inline void SetBit2(BOOL p_e) { m_flags.m_bit2 = p_e; } + inline void SetBit3(BOOL p_e) { m_flags.m_bit3 = p_e; } + inline void SetBit4(BOOL p_e) { m_flags.m_bit4 = p_e; } + + inline BYTE GetBit0() { return m_flags.m_bit0; } + inline BYTE GetBit1() { return m_flags.m_bit1; } + inline BYTE GetBit2() { return m_flags.m_bit2; } + inline BYTE GetBit3() { return m_flags.m_bit3; } + inline BYTE GetBit4() { return m_flags.m_bit4; } + + // SYNTHETIC: LEGO1 0x1000c910 + // MxVideoPresenter::`scalar deleting destructor' + +private: + void Init(); + +protected: + void Destroy(MxBool p_fromDestructor); + + MxBitmap* m_frameBitmap; // 0x50 + AlphaMask* m_alpha; // 0x54 + LPDIRECTDRAWSURFACE m_unk0x58; // 0x58 + MxS16 m_unk0x5c; // 0x5c + FlagBitfield m_flags; // 0x5e + MxLong m_unk0x60; // 0x60 +}; + +#endif // MXVIDEOPRESENTER_H diff --git a/LEGO1/omni/include/mxwavepresenter.h b/LEGO1/omni/include/mxwavepresenter.h new file mode 100644 index 00000000..27bd1824 --- /dev/null +++ b/LEGO1/omni/include/mxwavepresenter.h @@ -0,0 +1,81 @@ +#ifndef MXWAVEPRESENTER_H +#define MXWAVEPRESENTER_H + +#include "decomp.h" +#include "mxsoundpresenter.h" + +#include + +// VTABLE: LEGO1 0x100d49a8 +// SIZE 0x6c +class MxWavePresenter : public MxSoundPresenter { +public: + MxWavePresenter() { Init(); } + + // FUNCTION: LEGO1 0x1000d640 + ~MxWavePresenter() override { Destroy(TRUE); } // vtable+0x00 + + // FUNCTION: LEGO1 0x1000d6c0 + inline const char* ClassName() const override // vtable+0x0c + { + // STRING: LEGO1 0x100f07b4 + return "MxWavePresenter"; + } + + // FUNCTION: LEGO1 0x1000d6d0 + inline MxBool IsA(const char* p_name) const override // vtable+0x10 + { + return !strcmp(p_name, MxWavePresenter::ClassName()) || MxSoundPresenter::IsA(p_name); + } + + void ReadyTickle() override; // vtable+0x18 + void StartingTickle() override; // vtable+0x1c + void StreamingTickle() override; // vtable+0x20 + void DoneTickle() override; // vtable+0x2c + void ParseExtra() override; // vtable+0x30 + MxResult AddToManager() override; // vtable+0x34 + + // FUNCTION: LEGO1 0x1000d6a0 + void Destroy() override { Destroy(FALSE); } // vtable+0x38 + + void EndAction() override; // vtable+0x40 + MxResult PutData() override; // vtable+0x4c + void Enable(MxBool p_enable) override; // vtable+0x54 + void LoopChunk(MxStreamChunk* p_chunk) override; // vtable+0x58 + void SetVolume(MxS32 p_volume) override; // vtable+0x60 + virtual void Pause(); // vtable+0x64 + virtual void Resume(); // vtable+0x68 + + // FUNCTION: LEGO1 0x1000d6b0 + virtual MxBool IsPaused() { return m_paused; } // vtable+0x6c + + // SIZE 0x18 + struct WaveFormat { + PCMWAVEFORMAT m_pcmWaveFormat; // 0x00 + MxU32 m_dataSize; // 0x10 + MxU32 m_flags; // 0x14 + }; + + // SYNTHETIC: LEGO1 0x1000d810 + // MxWavePresenter::`scalar deleting destructor' + +protected: + void Init(); + void Destroy(MxBool p_fromDestructor); + + MxS8 GetPlayedChunks(); + MxBool FUN_100b1ba0(); + void WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length); + + WaveFormat* m_waveFormat; // 0x54 + LPDIRECTSOUNDBUFFER m_dsBuffer; // 0x58 + MxU32 m_chunkLength; // 0x5c + MxU32 m_lockSize; // 0x60 + MxU8 m_writtenChunks; // 0x64 + MxBool m_started; // 0x65 + MxBool m_is3d; // 0x66 + MxS8 m_silenceData; // 0x67 + MxBool m_paused; // 0x68 +}; + +#endif // MXWAVEPRESENTER_H diff --git a/LEGO1/omni/src/action/mxdsaction.cpp b/LEGO1/omni/src/action/mxdsaction.cpp new file mode 100644 index 00000000..8dc22fcf --- /dev/null +++ b/LEGO1/omni/src/action/mxdsaction.cpp @@ -0,0 +1,285 @@ +#include "mxdsaction.h" + +#include "mxmisc.h" +#include "mxtimer.h" +#include "mxutilities.h" + +#include +#include +#include + +DECOMP_SIZE_ASSERT(MxDSAction, 0x94) + +// GLOBAL: LEGO1 0x10101410 +// GLOBAL: BETA10 0x10201f5c +MxU16 g_sep = TWOCC(',', ' '); + +// FUNCTION: LEGO1 0x100ad810 +// FUNCTION: BETA10 0x1012afd0 +MxDSAction::MxDSAction() +{ + m_type = e_action; + m_flags = MxDSAction::c_enabled; + m_extraLength = 0; + m_extraData = NULL; + m_startTime = INT_MIN; + m_duration = INT_MIN; + m_loopCount = -1; + m_location.Fill(FLT_MAX); + m_direction.Fill(FLT_MAX); + m_up.Fill(FLT_MAX); + m_unk0x84 = NULL; + m_unk0x88 = 0; + m_origin = NULL; + m_unk0x90 = INT_MIN; +} + +// FUNCTION: LEGO1 0x100ad940 +// FUNCTION: BETA10 0x1012bc50 +MxLong MxDSAction::GetDuration() +{ + return m_duration; +} + +// FUNCTION: LEGO1 0x100ad950 +// FUNCTION: BETA10 0x1012bc90 +void MxDSAction::SetDuration(MxLong p_duration) +{ + m_duration = p_duration; +} + +// FUNCTION: LEGO1 0x100ad960 +// FUNCTION: BETA10 0x1012bcc0 +MxBool MxDSAction::HasId(MxU32 p_objectId) +{ + return m_objectId == p_objectId; +} + +// FUNCTION: LEGO1 0x100ada40 +// FUNCTION: BETA10 0x1012bdf0 +void MxDSAction::SetUnknown90(MxLong p_unk0x90) +{ + m_unk0x90 = p_unk0x90; +} + +// FUNCTION: LEGO1 0x100ada50 +// FUNCTION: BETA10 0x1012be20 +MxLong MxDSAction::GetUnknown90() +{ + return m_unk0x90; +} + +// FUNCTION: LEGO1 0x100ada80 +// FUNCTION: BETA10 0x1012b144 +MxDSAction::~MxDSAction() +{ + delete[] m_extraData; +} + +// FUNCTION: LEGO1 0x100adaf0 +// FUNCTION: BETA10 0x1012b1c7 +void MxDSAction::CopyFrom(MxDSAction& p_dsAction) +{ + m_objectId = p_dsAction.m_objectId; + m_flags = p_dsAction.m_flags; + m_startTime = p_dsAction.m_startTime; + m_duration = p_dsAction.m_duration; + m_loopCount = p_dsAction.m_loopCount; + m_location = p_dsAction.m_location; + m_direction = p_dsAction.m_direction; + m_up = p_dsAction.m_up; + AppendExtra(p_dsAction.m_extraLength, p_dsAction.m_extraData); + m_unk0x84 = p_dsAction.m_unk0x84; + m_unk0x88 = p_dsAction.m_unk0x88; + m_origin = p_dsAction.m_origin; + m_unk0x90 = p_dsAction.m_unk0x90; +} + +// FUNCTION: BETA10 0x1012b2b3 +MxDSAction::MxDSAction(MxDSAction& p_dsAction) : MxDSObject(p_dsAction) +{ + CopyFrom(p_dsAction); +} + +// FUNCTION: LEGO1 0x100adbd0 +// FUNCTION: BETA10 0x1012b355 +undefined4 MxDSAction::VTable0x14() +{ + return MxDSObject::VTable0x14(); +} + +// FUNCTION: LEGO1 0x100adbe0 +// FUNCTION: BETA10 0x1012b373 +MxU32 MxDSAction::GetSizeOnDisk() +{ + MxU32 size = MxDSObject::GetSizeOnDisk(); + size += sizeof(m_flags); + size += sizeof(m_startTime); + size += sizeof(m_duration); + size += sizeof(m_loopCount); + size += sizeof(double) * 3; // m_location + size += sizeof(double) * 3; // m_direction + size += sizeof(double) * 3; // m_up + size += sizeof(m_extraLength); + size += m_extraLength; + + m_sizeOnDisk = size - MxDSObject::GetSizeOnDisk(); + + return size; +} + +// FUNCTION: LEGO1 0x100adc10 +// FUNCTION: BETA10 0x1012b3d9 +MxDSAction& MxDSAction::operator=(MxDSAction& p_dsAction) +{ + if (this == &p_dsAction) { + return *this; + } + + MxDSObject::operator=(p_dsAction); + CopyFrom(p_dsAction); + return *this; +} + +// FUNCTION: LEGO1 0x100adc40 +// FUNCTION: BETA10 0x1012b420 +MxDSAction* MxDSAction::Clone() +{ + MxDSAction* clone = new MxDSAction(); + + if (clone) { + *clone = *this; + } + + return clone; +} + +// FUNCTION: LEGO1 0x100adcd0 +// FUNCTION: BETA10 0x1012b4ca +MxLong MxDSAction::GetElapsedTime() +{ + return Timer()->GetTime() - m_unk0x90; +} + +// FUNCTION: LEGO1 0x100add00 +// FUNCTION: BETA10 0x1012b4f5 +void MxDSAction::MergeFrom(MxDSAction& p_dsAction) +{ + if (p_dsAction.GetStartTime() != INT_MIN) { + m_startTime = p_dsAction.GetStartTime(); + } + + if (p_dsAction.GetDuration() != INT_MIN) { + m_duration = p_dsAction.GetDuration(); + } + + if (p_dsAction.GetLoopCount() != -1) { + m_loopCount = p_dsAction.GetLoopCount(); + } + + if (p_dsAction.GetLocation()[0] != FLT_MAX) { + m_location[0] = p_dsAction.GetLocation()[0]; + } + if (p_dsAction.GetLocation()[1] != FLT_MAX) { + m_location[1] = p_dsAction.GetLocation()[1]; + } + if (p_dsAction.GetLocation()[2] != FLT_MAX) { + m_location[2] = p_dsAction.GetLocation()[2]; + } + + if (p_dsAction.GetDirection()[0] != FLT_MAX) { + m_direction[0] = p_dsAction.GetDirection()[0]; + } + if (p_dsAction.GetDirection()[1] != FLT_MAX) { + m_direction[1] = p_dsAction.GetDirection()[1]; + } + if (p_dsAction.GetDirection()[2] != FLT_MAX) { + m_direction[2] = p_dsAction.GetUp()[2]; // This is correct + } + + if (p_dsAction.GetUp()[0] != FLT_MAX) { + m_up[0] = p_dsAction.GetUp()[0]; + } + if (p_dsAction.GetUp()[1] != FLT_MAX) { + m_up[1] = p_dsAction.GetUp()[1]; + } + if (p_dsAction.GetUp()[2] != FLT_MAX) { + m_up[2] = p_dsAction.GetUp()[2]; + } + + MxU16 extraLength; + char* extraData; + p_dsAction.GetExtra(extraLength, extraData); + + if (extraLength && extraData) { + if (!m_extraData || !strncmp("XXX", m_extraData, 3)) { + delete[] m_extraData; + m_extraLength = 0; + AppendExtra(extraLength, extraData); + } + } +} + +// FUNCTION: LEGO1 0x100ade60 +// FUNCTION: BETA10 0x1012b8a9 +void MxDSAction::AppendExtra(MxU16 p_extraLength, const char* p_extraData) +{ + if (m_extraData == p_extraData) { + return; + } + + if (p_extraData) { + if (m_extraLength) { + char* newExtra = new char[p_extraLength + m_extraLength + sizeof(g_sep)]; + assert(newExtra); + memcpy(newExtra, m_extraData, m_extraLength); + memcpy(&newExtra[m_extraLength], &g_sep, sizeof(g_sep)); + memcpy(&newExtra[m_extraLength + sizeof(g_sep)], p_extraData, p_extraLength); + + m_extraLength += p_extraLength + sizeof(g_sep); + delete[] m_extraData; + m_extraData = newExtra; + } + else { + m_extraData = new char[p_extraLength]; + + if (m_extraData) { + m_extraLength = p_extraLength; + memcpy(m_extraData, p_extraData, p_extraLength); + } + else { + assert(0); + } + } + } +} + +// FUNCTION: LEGO1 0x100adf70 +// FUNCTION: BETA10 0x1012ba6a +void MxDSAction::Deserialize(MxU8*& p_source, MxS16 p_unk0x24) +{ + MxDSObject::Deserialize(p_source, p_unk0x24); + + // clang-format off + m_flags = *( MxU32*) p_source; p_source += sizeof(m_flags); + m_startTime = *(MxLong*) p_source; p_source += sizeof(m_startTime); + m_duration = *(MxLong*) p_source; p_source += sizeof(m_duration); + m_loopCount = *( MxS32*) p_source; p_source += sizeof(m_loopCount); + m_location[0] = *(double*) p_source; p_source += sizeof(double); + m_location[1] = *(double*) p_source; p_source += sizeof(double); + m_location[2] = *(double*) p_source; p_source += sizeof(double); + m_direction[0] = *(double*) p_source; p_source += sizeof(double); + m_direction[1] = *(double*) p_source; p_source += sizeof(double); + m_direction[2] = *(double*) p_source; p_source += sizeof(double); + m_up[0] = *(double*) p_source; p_source += sizeof(double); + m_up[1] = *(double*) p_source; p_source += sizeof(double); + m_up[2] = *(double*) p_source; p_source += sizeof(double); + + MxU16 extraLength = *( MxU16*) p_source; p_source += sizeof(extraLength); + // clang-format on + + if (extraLength) { + AppendExtra(extraLength, (char*) p_source); + p_source += extraLength; + } +} diff --git a/LEGO1/omni/src/action/mxdsanim.cpp b/LEGO1/omni/src/action/mxdsanim.cpp new file mode 100644 index 00000000..fd15ce70 --- /dev/null +++ b/LEGO1/omni/src/action/mxdsanim.cpp @@ -0,0 +1,44 @@ +#include "mxdsanim.h" + +DECOMP_SIZE_ASSERT(MxDSAnim, 0xb8) + +// FUNCTION: LEGO1 0x100c8ff0 +// FUNCTION: BETA10 0x1015cd71 +MxDSAnim::MxDSAnim() +{ + this->SetType(e_anim); +} + +// FUNCTION: LEGO1 0x100c91a0 +MxDSAnim::~MxDSAnim() +{ +} + +// FUNCTION: LEGO1 0x100c91f0 +void MxDSAnim::CopyFrom(MxDSAnim& p_dsAnim) +{ +} + +// FUNCTION: LEGO1 0x100c9200 +MxDSAnim& MxDSAnim::operator=(MxDSAnim& p_dsAnim) +{ + if (this == &p_dsAnim) { + return *this; + } + + MxDSMediaAction::operator=(p_dsAnim); + this->CopyFrom(p_dsAnim); + return *this; +} + +// FUNCTION: LEGO1 0x100c9230 +MxDSAction* MxDSAnim::Clone() +{ + MxDSAnim* clone = new MxDSAnim(); + + if (clone) { + *clone = *this; + } + + return clone; +} diff --git a/LEGO1/omni/src/action/mxdsevent.cpp b/LEGO1/omni/src/action/mxdsevent.cpp new file mode 100644 index 00000000..fbbc2bdb --- /dev/null +++ b/LEGO1/omni/src/action/mxdsevent.cpp @@ -0,0 +1,44 @@ +#include "mxdsevent.h" + +DECOMP_SIZE_ASSERT(MxDSEvent, 0xb8) + +// FUNCTION: LEGO1 0x100c95f0 +// FUNCTION: BETA10 0x1015d2e5 +MxDSEvent::MxDSEvent() +{ + this->SetType(e_event); +} + +// FUNCTION: LEGO1 0x100c97a0 +MxDSEvent::~MxDSEvent() +{ +} + +// FUNCTION: LEGO1 0x100c97f0 +void MxDSEvent::CopyFrom(MxDSEvent& p_dsEvent) +{ +} + +// FUNCTION: LEGO1 0x100c9800 +MxDSEvent& MxDSEvent::operator=(MxDSEvent& p_dsEvent) +{ + if (this == &p_dsEvent) { + return *this; + } + + MxDSMediaAction::operator=(p_dsEvent); + this->CopyFrom(p_dsEvent); + return *this; +} + +// FUNCTION: LEGO1 0x100c9830 +MxDSAction* MxDSEvent::Clone() +{ + MxDSEvent* clone = new MxDSEvent(); + + if (clone) { + *clone = *this; + } + + return clone; +} diff --git a/LEGO1/omni/src/action/mxdsmediaaction.cpp b/LEGO1/omni/src/action/mxdsmediaaction.cpp new file mode 100644 index 00000000..9ae76166 --- /dev/null +++ b/LEGO1/omni/src/action/mxdsmediaaction.cpp @@ -0,0 +1,144 @@ +#include "mxdsmediaaction.h" + +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(MxDSMediaAction, 0xb8) + +// FUNCTION: LEGO1 0x100c8b40 +// FUNCTION: BETA10 0x1015c760 +MxDSMediaAction::MxDSMediaAction() +{ + m_type = e_mediaAction; + m_mediaSrcPath = NULL; + m_unk0x9c.SetUnk0x00(0); + m_unk0x9c.SetUnk0x04(0); + m_framesPerSecond = 0; + m_mediaFormat = 0; + m_unk0xb4 = -1; + m_paletteManagement = 1; + m_sustainTime = 0; +} + +// FUNCTION: LEGO1 0x100c8cf0 +// FUNCTION: BETA10 0x1015c846 +MxDSMediaAction::~MxDSMediaAction() +{ + delete[] m_mediaSrcPath; +} + +// FUNCTION: LEGO1 0x100c8d60 +// FUNCTION: BETA10 0x1015c8cc +void MxDSMediaAction::CopyFrom(MxDSMediaAction& p_dsMediaAction) +{ + CopyMediaSrcPath(p_dsMediaAction.m_mediaSrcPath); + + m_unk0x9c = p_dsMediaAction.m_unk0x9c; + m_framesPerSecond = p_dsMediaAction.m_framesPerSecond; + m_mediaFormat = p_dsMediaAction.m_mediaFormat; + m_paletteManagement = p_dsMediaAction.m_paletteManagement; + m_sustainTime = p_dsMediaAction.m_sustainTime; +} + +// FUNCTION: BETA10 0x1015c959 +MxDSMediaAction::MxDSMediaAction(MxDSMediaAction& p_dsMediaAction) : MxDSAction(p_dsMediaAction) +{ + CopyFrom(p_dsMediaAction); +} + +// FUNCTION: LEGO1 0x100c8dc0 +// FUNCTION: BETA10 0x1015c9da +MxDSMediaAction& MxDSMediaAction::operator=(MxDSMediaAction& p_dsMediaAction) +{ + if (this == &p_dsMediaAction) { + return *this; + } + + MxDSAction::operator=(p_dsMediaAction); + CopyFrom(p_dsMediaAction); + return *this; +} + +// FUNCTION: LEGO1 0x100c8df0 +// FUNCTION: BETA10 0x1015ca21 +MxDSAction* MxDSMediaAction::Clone() +{ + MxDSMediaAction* clone = new MxDSMediaAction(); + + if (clone) { + *clone = *this; + } + + return clone; +} + +// FUNCTION: LEGO1 0x100c8e80 +// FUNCTION: BETA10 0x1015cacb +void MxDSMediaAction::CopyMediaSrcPath(const char* p_mediaSrcPath) +{ + if (m_mediaSrcPath == p_mediaSrcPath) { + return; + } + + delete[] m_mediaSrcPath; + + if (p_mediaSrcPath) { + m_mediaSrcPath = new char[strlen(p_mediaSrcPath) + 1]; + if (m_mediaSrcPath) { + strcpy(m_mediaSrcPath, p_mediaSrcPath); + } + } + else { + m_mediaSrcPath = NULL; + } +} + +// FUNCTION: LEGO1 0x100c8f00 +// FUNCTION: BETA10 0x1015cbf5 +undefined4 MxDSMediaAction::VTable0x14() +{ + return MxDSAction::VTable0x14(); +} + +// FUNCTION: LEGO1 0x100c8f10 +// FUNCTION: BETA10 0x1015cc13 +MxU32 MxDSMediaAction::GetSizeOnDisk() +{ + MxU32 totalSizeOnDisk = MxDSAction::GetSizeOnDisk(); + + if (m_mediaSrcPath) { + totalSizeOnDisk += strlen(m_mediaSrcPath) + 1; + } + else { + totalSizeOnDisk++; + } + + totalSizeOnDisk += sizeof(m_unk0x9c.m_unk0x00); + totalSizeOnDisk += sizeof(m_unk0x9c.m_unk0x04); + totalSizeOnDisk += sizeof(m_framesPerSecond); + totalSizeOnDisk += sizeof(m_mediaFormat); + totalSizeOnDisk += sizeof(m_paletteManagement); + totalSizeOnDisk += sizeof(m_sustainTime); + + m_sizeOnDisk = totalSizeOnDisk - MxDSAction::GetSizeOnDisk(); + return totalSizeOnDisk; +} + +// FUNCTION: LEGO1 0x100c8f60 +// FUNCTION: BETA10 0x1015cc93 +void MxDSMediaAction::Deserialize(MxU8*& p_source, MxS16 p_unk0x24) +{ + MxDSAction::Deserialize(p_source, p_unk0x24); + + CopyMediaSrcPath((char*) p_source); + p_source += strlen(m_mediaSrcPath) + 1; + + // clang-format off + m_unk0x9c.SetUnk0x00(*(MxU32*) p_source); p_source += sizeof(m_unk0x9c.m_unk0x00); + m_unk0x9c.SetUnk0x04(*(MxU32*) p_source); p_source += sizeof(m_unk0x9c.m_unk0x04); + + m_framesPerSecond = *(MxS32*) p_source; p_source += sizeof(m_framesPerSecond); + m_mediaFormat = *(MxS32*) p_source; p_source += sizeof(m_mediaFormat); + m_paletteManagement = *(MxS32*) p_source; p_source += sizeof(m_paletteManagement); + m_sustainTime = *(MxS32*) p_source; p_source += sizeof(m_sustainTime); + // clang-format on +} diff --git a/LEGO1/omni/src/action/mxdsmultiaction.cpp b/LEGO1/omni/src/action/mxdsmultiaction.cpp new file mode 100644 index 00000000..edf01c1d --- /dev/null +++ b/LEGO1/omni/src/action/mxdsmultiaction.cpp @@ -0,0 +1,168 @@ +#include "mxdsmultiaction.h" + +DECOMP_SIZE_ASSERT(MxDSMultiAction, 0x9c) +DECOMP_SIZE_ASSERT(MxDSActionList, 0x1c); +DECOMP_SIZE_ASSERT(MxDSActionListCursor, 0x10); + +// FUNCTION: LEGO1 0x100c9b90 +// FUNCTION: BETA10 0x10159410 +MxDSMultiAction::MxDSMultiAction() +{ + this->SetType(e_multiAction); + this->m_actions = new MxDSActionList; + this->m_actions->SetDestroy(MxDSActionList::Destroy); +} + +// FUNCTION: LEGO1 0x100ca060 +MxDSMultiAction::~MxDSMultiAction() +{ + if (this->m_actions) { + delete this->m_actions; + } +} + +// FUNCTION: LEGO1 0x100ca0d0 +void MxDSMultiAction::CopyFrom(MxDSMultiAction& p_dsMultiAction) +{ + this->m_actions->DeleteAll(); + + MxDSActionListCursor cursor(p_dsMultiAction.m_actions); + MxDSAction* action; + while (cursor.Next(action)) { + this->m_actions->Append(action->Clone()); + } +} + +// FUNCTION: LEGO1 0x100ca260 +MxDSMultiAction& MxDSMultiAction::operator=(MxDSMultiAction& p_dsMultiAction) +{ + if (this == &p_dsMultiAction) { + return *this; + } + + MxDSAction::operator=(p_dsMultiAction); + this->CopyFrom(p_dsMultiAction); + return *this; +} + +// FUNCTION: LEGO1 0x100ca290 +void MxDSMultiAction::SetUnknown90(MxLong p_unk0x90) +{ + this->m_unk0x90 = p_unk0x90; + + MxDSActionListCursor cursor(this->m_actions); + MxDSAction* action; + while (cursor.Next(action)) { + action->SetUnknown90(p_unk0x90); + } +} + +// FUNCTION: LEGO1 0x100ca370 +void MxDSMultiAction::MergeFrom(MxDSAction& p_dsMultiAction) +{ + MxDSAction::MergeFrom(p_dsMultiAction); + + MxDSActionListCursor cursor(this->m_actions); + MxDSAction* action; + while (cursor.Next(action)) { + action->MergeFrom(p_dsMultiAction); + } +} + +// FUNCTION: LEGO1 0x100ca450 +MxBool MxDSMultiAction::HasId(MxU32 p_objectId) +{ + if (this->GetObjectId() == p_objectId) { + return TRUE; + } + + MxDSActionListCursor cursor(this->m_actions); + MxDSAction* action; + while (cursor.Next(action)) { + if (action->HasId(p_objectId)) { + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x100ca550 +MxDSAction* MxDSMultiAction::Clone() +{ + MxDSMultiAction* clone = new MxDSMultiAction(); + + if (clone) { + *clone = *this; + } + + return clone; +} + +// FUNCTION: LEGO1 0x100ca5e0 +undefined4 MxDSMultiAction::VTable0x14() +{ + undefined4 result = MxDSAction::VTable0x14(); + + MxDSActionListCursor cursor(this->m_actions); + MxDSAction* action; + while (cursor.Next(action)) { + result += action->VTable0x14(); + } + + return result; +} + +// FUNCTION: LEGO1 0x100ca6c0 +MxU32 MxDSMultiAction::GetSizeOnDisk() +{ + MxU32 totalSizeOnDisk = MxDSAction::GetSizeOnDisk() + 16; + + MxDSActionListCursor cursor(this->m_actions); + MxDSAction* action; + while (cursor.Next(action)) { + totalSizeOnDisk += action->GetSizeOnDisk(); + } + + this->m_sizeOnDisk = totalSizeOnDisk - MxDSAction::GetSizeOnDisk(); + + return totalSizeOnDisk; +} + +// FUNCTION: LEGO1 0x100ca7b0 +void MxDSMultiAction::Deserialize(MxU8*& p_source, MxS16 p_unk0x24) +{ + MxDSAction::Deserialize(p_source, p_unk0x24); + + MxU32 extraFlag = *(MxU32*) (p_source + 4) & 1; + p_source += 12; + + MxU32 count = *(MxU32*) p_source; + p_source += sizeof(count); + + if (count) { + while (count--) { + MxU32 extraFlag = *(MxU32*) (p_source + 4) & 1; + p_source += 8; + + MxDSAction* action = (MxDSAction*) DeserializeDSObjectDispatch(p_source, p_unk0x24); + p_source += extraFlag; + + this->m_actions->Append(action); + } + } + + p_source += extraFlag; +} + +// FUNCTION: LEGO1 0x100ca8c0 +void MxDSMultiAction::SetAtomId(MxAtomId p_atomId) +{ + MxDSAction::SetAtomId(p_atomId); + + MxDSActionListCursor cursor(this->m_actions); + MxDSAction* action; + while (cursor.Next(action)) { + action->SetAtomId(p_atomId); + } +} diff --git a/LEGO1/omni/src/action/mxdsobject.cpp b/LEGO1/omni/src/action/mxdsobject.cpp new file mode 100644 index 00000000..ae266fe0 --- /dev/null +++ b/LEGO1/omni/src/action/mxdsobject.cpp @@ -0,0 +1,229 @@ +#include "mxdsobject.h" + +#include "mxdsaction.h" +#include "mxdsanim.h" +#include "mxdsevent.h" +#include "mxdsmediaaction.h" +#include "mxdsmultiaction.h" +#include "mxdsobjectaction.h" +#include "mxdsparallelaction.h" +#include "mxdsselectaction.h" +#include "mxdsserialaction.h" +#include "mxdssound.h" +#include "mxdsstill.h" +#include "mxutilities.h" + +#include +#include + +DECOMP_SIZE_ASSERT(MxDSObject, 0x2c); + +// FUNCTION: LEGO1 0x100bf6a0 +// FUNCTION: BETA10 0x101478c0 +MxDSObject::MxDSObject() +{ + m_type = e_object; + m_sourceName = NULL; + m_unk0x14 = 0; + m_objectName = NULL; + m_objectId = -1; + m_unk0x24 = -1; + m_unk0x28 = NULL; +} + +// FUNCTION: LEGO1 0x100bf7e0 +// FUNCTION: BETA10 0x1014798e +MxDSObject::~MxDSObject() +{ + delete[] m_objectName; + delete[] m_sourceName; +} + +// FUNCTION: LEGO1 0x100bf870 +// FUNCTION: BETA10 0x10147a45 +void MxDSObject::CopyFrom(MxDSObject& p_dsObject) +{ + SetSourceName(p_dsObject.m_sourceName); + m_unk0x14 = p_dsObject.m_unk0x14; + SetObjectName(p_dsObject.m_objectName); + m_objectId = p_dsObject.m_objectId; + m_unk0x24 = p_dsObject.m_unk0x24; + m_atomId = p_dsObject.m_atomId; + m_unk0x28 = p_dsObject.m_unk0x28; +} + +// FUNCTION: BETA10 0x10147abf +MxDSObject::MxDSObject(MxDSObject& p_dsObject) +{ + CopyFrom(p_dsObject); +} + +// FUNCTION: LEGO1 0x100bf8c0 +// FUNCTION: BETA10 0x10147b57 +MxDSObject& MxDSObject::operator=(MxDSObject& p_dsObject) +{ + if (this == &p_dsObject) { + return *this; + } + + CopyFrom(p_dsObject); + return *this; +} + +// FUNCTION: LEGO1 0x100bf8e0 +// FUNCTION: BETA10 0x10147b92 +void MxDSObject::SetObjectName(const char* p_objectName) +{ + if (p_objectName == m_objectName) { + return; + } + + delete[] m_objectName; + + if (p_objectName) { + m_objectName = new char[strlen(p_objectName) + 1]; + + if (m_objectName) { + strcpy(m_objectName, p_objectName); + } + } + else { + m_objectName = NULL; + } +} + +// FUNCTION: LEGO1 0x100bf950 +// FUNCTION: BETA10 0x10147c2e +void MxDSObject::SetSourceName(const char* p_sourceName) +{ + if (p_sourceName == m_sourceName) { + return; + } + + delete[] m_sourceName; + + if (p_sourceName) { + m_sourceName = new char[strlen(p_sourceName) + 1]; + + if (m_sourceName) { + strcpy(m_sourceName, p_sourceName); + } + } + else { + m_sourceName = NULL; + } +} + +// FUNCTION: LEGO1 0x100bf9c0 +// FUNCTION: BETA10 0x10147cca +undefined4 MxDSObject::VTable0x14() +{ + // DECOMP: Rendered as 8 + 2 in beta. Maybe a sizeof() call? + return 10; +} + +// FUNCTION: LEGO1 0x100bf9d0 +// FUNCTION: BETA10 0x10147cee +MxU32 MxDSObject::GetSizeOnDisk() +{ + MxU32 sizeOnDisk = 0; + + sizeOnDisk += 2; + + if (m_sourceName) { + sizeOnDisk += strlen(m_sourceName) + 1; + } + else { + sizeOnDisk++; + } + + sizeOnDisk += sizeof(m_unk0x14); + + if (m_objectName) { + sizeOnDisk += strlen(m_objectName) + 1; + } + else { + sizeOnDisk++; + } + + sizeOnDisk += sizeof(m_objectId); + + m_sizeOnDisk = sizeOnDisk; + return sizeOnDisk; +} + +// FUNCTION: LEGO1 0x100bfa20 +// FUNCTION: BETA10 0x10147d73 +void MxDSObject::Deserialize(MxU8*& p_source, MxS16 p_unk0x24) +{ + SetSourceName((char*) p_source); + p_source += strlen(m_sourceName) + 1; + + m_unk0x14 = *(undefined4*) p_source; + p_source += sizeof(m_unk0x14); + + SetObjectName((char*) p_source); + p_source += strlen(m_objectName) + 1; + + m_objectId = *(MxU32*) p_source; + p_source += sizeof(m_objectId); + + m_unk0x24 = p_unk0x24; +} + +// FUNCTION: LEGO1 0x100bfb30 +// FUNCTION: BETA10 0x10147f35 +MxDSObject* DeserializeDSObjectDispatch(MxU8*& p_source, MxS16 p_flags) +{ + MxDSObject* obj = NULL; + + MxU16 type = *(MxU16*) p_source; + p_source += 2; + + switch (type) { + case MxDSObject::e_object: + obj = new MxDSObject(); + break; + case MxDSObject::e_action: + obj = new MxDSAction(); + break; + case MxDSObject::e_mediaAction: + obj = new MxDSMediaAction(); + break; + case MxDSObject::e_anim: + obj = new MxDSAnim(); + break; + case MxDSObject::e_sound: + obj = new MxDSSound(); + break; + case MxDSObject::e_event: + obj = new MxDSEvent(); + break; + case MxDSObject::e_still: + obj = new MxDSStill(); + break; + case MxDSObject::e_objectAction: + obj = new MxDSObjectAction(); + break; + case MxDSObject::e_multiAction: + obj = new MxDSMultiAction(); + break; + case MxDSObject::e_serialAction: + obj = new MxDSSerialAction(); + break; + case MxDSObject::e_parallelAction: + obj = new MxDSParallelAction(); + break; + case MxDSObject::e_selectAction: + obj = new MxDSSelectAction(); + break; + default: + return NULL; + } + + if (obj) { + obj->Deserialize(p_source, p_flags); + } + + return obj; +} diff --git a/LEGO1/omni/src/action/mxdsobjectaction.cpp b/LEGO1/omni/src/action/mxdsobjectaction.cpp new file mode 100644 index 00000000..dbfcce10 --- /dev/null +++ b/LEGO1/omni/src/action/mxdsobjectaction.cpp @@ -0,0 +1,44 @@ +#include "mxdsobjectaction.h" + +DECOMP_SIZE_ASSERT(MxDSObjectAction, 0xb8) + +// FUNCTION: LEGO1 0x100c8870 +// FUNCTION: BETA10 0x1015c3b0 +MxDSObjectAction::MxDSObjectAction() +{ + this->SetType(e_objectAction); +} + +// FUNCTION: LEGO1 0x100c8a20 +MxDSObjectAction::~MxDSObjectAction() +{ +} + +// FUNCTION: LEGO1 0x100c8a70 +void MxDSObjectAction::CopyFrom(MxDSObjectAction& p_dsObjectAction) +{ +} + +// FUNCTION: LEGO1 0x100c8a80 +MxDSObjectAction& MxDSObjectAction::operator=(MxDSObjectAction& p_dsObjectAction) +{ + if (this == &p_dsObjectAction) { + return *this; + } + + MxDSMediaAction::operator=(p_dsObjectAction); + this->CopyFrom(p_dsObjectAction); + return *this; +} + +// FUNCTION: LEGO1 0x100c8ab0 +MxDSAction* MxDSObjectAction::Clone() +{ + MxDSObjectAction* clone = new MxDSObjectAction(); + + if (clone) { + *clone = *this; + } + + return clone; +} diff --git a/LEGO1/omni/src/action/mxdsparallelaction.cpp b/LEGO1/omni/src/action/mxdsparallelaction.cpp new file mode 100644 index 00000000..4ea4f6ea --- /dev/null +++ b/LEGO1/omni/src/action/mxdsparallelaction.cpp @@ -0,0 +1,96 @@ +#include "mxdsparallelaction.h" + +#include "mxdsmediaaction.h" + +DECOMP_SIZE_ASSERT(MxDSParallelAction, 0x9c) + +// FUNCTION: LEGO1 0x100cae80 +// FUNCTION: BETA10 0x1015a14d +MxDSParallelAction::MxDSParallelAction() +{ + this->SetType(e_parallelAction); +} + +// FUNCTION: LEGO1 0x100cb040 +MxDSParallelAction::~MxDSParallelAction() +{ +} + +// FUNCTION: LEGO1 0x100cb090 +void MxDSParallelAction::CopyFrom(MxDSParallelAction& p_dsParallelAction) +{ +} + +// FUNCTION: LEGO1 0x100cb0a0 +MxDSParallelAction& MxDSParallelAction::operator=(MxDSParallelAction& p_dsParallelAction) +{ + if (this == &p_dsParallelAction) { + return *this; + } + + MxDSMultiAction::operator=(p_dsParallelAction); + this->CopyFrom(p_dsParallelAction); + return *this; +} + +// FUNCTION: LEGO1 0x100cb0d0 +MxDSAction* MxDSParallelAction::Clone() +{ + MxDSParallelAction* clone = new MxDSParallelAction(); + + if (clone) { + *clone = *this; + } + + return clone; +} + +// FUNCTION: LEGO1 0x100cb160 +MxLong MxDSParallelAction::GetDuration() +{ + if (this->m_duration) { + return this->m_duration; + } + + MxDSActionListCursor cursor(this->m_actions); + MxDSAction* action; + + while (cursor.Next(action)) { + if (!action) { + continue; + } + + MxLong duration = action->GetDuration(); + if (duration == -1) { + this->m_duration = -1; + break; + } + + duration += action->GetStartTime(); + if (action->IsA("MxDSMediaAction")) { + MxLong sustainTime = ((MxDSMediaAction*) action)->GetSustainTime(); + + if (sustainTime == -1) { + duration = -1; + } + else if (sustainTime) { + duration += sustainTime; + } + } + + if (duration == -1) { + this->m_duration = -1; + break; + } + + if (this->m_duration < duration) { + this->m_duration = duration; + } + } + + if (this->IsBit3()) { + this->m_duration *= this->m_loopCount; + } + + return this->m_duration; +} diff --git a/LEGO1/omni/src/action/mxdsselectaction.cpp b/LEGO1/omni/src/action/mxdsselectaction.cpp new file mode 100644 index 00000000..0aa5f053 --- /dev/null +++ b/LEGO1/omni/src/action/mxdsselectaction.cpp @@ -0,0 +1,144 @@ +#include "mxdsselectaction.h" + +#include "mxmisc.h" +#include "mxtimer.h" +#include "mxvariabletable.h" + +DECOMP_SIZE_ASSERT(MxDSSelectAction, 0xb0) +DECOMP_SIZE_ASSERT(MxStringList, 0x18) +DECOMP_SIZE_ASSERT(MxStringListCursor, 0x10) +DECOMP_SIZE_ASSERT(MxListEntry, 0x18) + +// FUNCTION: LEGO1 0x100cb2b0 +// FUNCTION: BETA10 0x1015a515 +MxDSSelectAction::MxDSSelectAction() +{ + this->SetType(e_selectAction); + this->m_unk0xac = new MxStringList; +} + +// FUNCTION: LEGO1 0x100cb8d0 +MxDSSelectAction::~MxDSSelectAction() +{ + if (this->m_unk0xac) { + delete this->m_unk0xac; + } +} + +// FUNCTION: LEGO1 0x100cb950 +void MxDSSelectAction::CopyFrom(MxDSSelectAction& p_dsSelectAction) +{ + this->m_unk0x9c = p_dsSelectAction.m_unk0x9c; + + this->m_unk0xac->DeleteAll(); + + MxStringListCursor cursor(p_dsSelectAction.m_unk0xac); + MxString string; + while (cursor.Next(string)) { + this->m_unk0xac->Append(string); + } +} + +// FUNCTION: LEGO1 0x100cbd50 +MxDSSelectAction& MxDSSelectAction::operator=(MxDSSelectAction& p_dsSelectAction) +{ + if (this != &p_dsSelectAction) { + MxDSParallelAction::operator=(p_dsSelectAction); + this->CopyFrom(p_dsSelectAction); + } + return *this; +} + +// FUNCTION: LEGO1 0x100cbd80 +MxDSAction* MxDSSelectAction::Clone() +{ + MxDSSelectAction* clone = new MxDSSelectAction(); + + if (clone) { + *clone = *this; + } + + return clone; +} + +// FUNCTION: LEGO1 0x100cbe10 +MxU32 MxDSSelectAction::GetSizeOnDisk() +{ + MxU32 totalSizeOnDisk = MxDSParallelAction::GetSizeOnDisk(); + + totalSizeOnDisk += strlen(this->m_unk0x9c.GetData()) + 1; + + MxStringListCursor cursor(this->m_unk0xac); + MxString string; + while (cursor.Next(string)) { + totalSizeOnDisk += strlen(string.GetData()) + 1; + } + + // Note: unlike the other classes, MxDSSelectAction does not have its own + // sizeOnDisk member. Instead, it overrides the one from MxDSMultiAction. + this->m_sizeOnDisk = totalSizeOnDisk; + + return totalSizeOnDisk; +} + +// FUNCTION: LEGO1 0x100cbf60 +void MxDSSelectAction::Deserialize(MxU8*& p_source, MxS16 p_unk0x24) +{ + MxString string; + MxDSAction::Deserialize(p_source, p_unk0x24); + + MxU32 extraFlag = *(MxU32*) (p_source + 4) & 1; + p_source += 12; + + this->m_unk0x9c = (char*) p_source; + + if (!strnicmp(this->m_unk0x9c.GetData(), "RANDOM_", strlen("RANDOM_"))) { + char buffer[10]; + MxS16 value = atoi(&this->m_unk0x9c.GetData()[strlen("RANDOM_")]); + + srand(Timer()->GetTime()); + MxS32 random = rand() % value; + string = itoa((MxS16) random, buffer, 10); + } + else { + string = VariableTable()->GetVariable((char*) p_source); + } + + p_source += strlen((char*) p_source) + 1; + + MxU32 count = *(MxU32*) p_source; + p_source += sizeof(MxU32); + + if (count) { + MxS32 index = -1; + this->m_unk0xac->DeleteAll(); + + MxU32 i; + for (i = 0; i < count; i++) { + if (!strcmp(string.GetData(), (char*) p_source)) { + index = i; + } + + this->m_unk0xac->Append((char*) p_source); + p_source += strlen((char*) p_source) + 1; + } + + for (i = 0; i < count; i++) { + MxU32 extraFlag = *(MxU32*) (p_source + 4) & 1; + p_source += 8; + + MxDSAction* action = (MxDSAction*) DeserializeDSObjectDispatch(p_source, p_unk0x24); + + if (index == i) { + this->m_actions->Append(action); + } + else { + delete action; + } + + p_source += extraFlag; + } + } + + p_source += extraFlag; +} diff --git a/LEGO1/omni/src/action/mxdsserialaction.cpp b/LEGO1/omni/src/action/mxdsserialaction.cpp new file mode 100644 index 00000000..d258dee8 --- /dev/null +++ b/LEGO1/omni/src/action/mxdsserialaction.cpp @@ -0,0 +1,88 @@ +#include "mxdsserialaction.h" + +#include "mxdsmediaaction.h" + +DECOMP_SIZE_ASSERT(MxDSSerialAction, 0xa8) + +// FUNCTION: LEGO1 0x100ca9d0 +// FUNCTION: BETA10 0x10159cf3 +MxDSSerialAction::MxDSSerialAction() +{ + this->SetType(e_serialAction); + this->m_cursor = new MxDSActionListCursor(this->m_actions); + this->m_unk0xa0 = 0; +} + +// FUNCTION: LEGO1 0x100caac0 +void MxDSSerialAction::SetDuration(MxLong p_duration) +{ + this->m_duration = p_duration; +} + +// FUNCTION: LEGO1 0x100cac10 +MxDSSerialAction::~MxDSSerialAction() +{ + if (this->m_cursor) { + delete this->m_cursor; + } + + this->m_cursor = NULL; +} + +// FUNCTION: LEGO1 0x100cac90 +void MxDSSerialAction::CopyFrom(MxDSSerialAction& p_dsSerialAction) +{ +} + +// FUNCTION: LEGO1 0x100caca0 +MxDSSerialAction& MxDSSerialAction::operator=(MxDSSerialAction& p_dsSerialAction) +{ + if (this == &p_dsSerialAction) { + return *this; + } + + MxDSMultiAction::operator=(p_dsSerialAction); + this->CopyFrom(p_dsSerialAction); + return *this; +} + +// FUNCTION: LEGO1 0x100cacd0 +MxDSAction* MxDSSerialAction::Clone() +{ + MxDSSerialAction* clone = new MxDSSerialAction(); + + if (clone) { + *clone = *this; + } + + return clone; +} + +// FUNCTION: LEGO1 0x100cad60 +MxLong MxDSSerialAction::GetDuration() +{ + if (this->m_duration) { + return this->m_duration; + } + + MxDSActionListCursor cursor(this->m_actions); + MxDSAction* action; + + while (cursor.Next(action)) { + if (!action) { + continue; + } + + this->m_duration += action->GetDuration() + action->GetStartTime(); + + if (action->IsA("MxDSMediaAction")) { + MxLong sustainTime = ((MxDSMediaAction*) action)->GetSustainTime(); + + if (sustainTime && sustainTime != -1) { + this->m_duration += sustainTime; + } + } + } + + return this->m_duration; +} diff --git a/LEGO1/omni/src/action/mxdssound.cpp b/LEGO1/omni/src/action/mxdssound.cpp new file mode 100644 index 00000000..7dc8d69a --- /dev/null +++ b/LEGO1/omni/src/action/mxdssound.cpp @@ -0,0 +1,66 @@ +#include "mxdssound.h" + +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(MxDSSound, 0xc0) + +// FUNCTION: LEGO1 0x100c92c0 +// FUNCTION: BETA10 0x1015cfdb +MxDSSound::MxDSSound() +{ + this->m_volume = 0x4f; + this->SetType(e_sound); +} + +// FUNCTION: LEGO1 0x100c9470 +MxDSSound::~MxDSSound() +{ +} + +// FUNCTION: LEGO1 0x100c94c0 +void MxDSSound::CopyFrom(MxDSSound& p_dsSound) +{ + this->SetType(p_dsSound.GetType()); + this->m_volume = p_dsSound.m_volume; +} + +// FUNCTION: LEGO1 0x100c94e0 +MxDSSound& MxDSSound::operator=(MxDSSound& p_dsSound) +{ + if (this == &p_dsSound) { + return *this; + } + + MxDSMediaAction::operator=(p_dsSound); + this->CopyFrom(p_dsSound); + return *this; +} + +// FUNCTION: LEGO1 0x100c9510 +MxDSAction* MxDSSound::Clone() +{ + MxDSSound* clone = new MxDSSound(); + + if (clone) { + *clone = *this; + } + + return clone; +} + +// FUNCTION: LEGO1 0x100c95a0 +void MxDSSound::Deserialize(MxU8*& p_source, MxS16 p_unk0x24) +{ + MxDSMediaAction::Deserialize(p_source, p_unk0x24); + + GetScalar(p_source, this->m_volume); +} + +// FUNCTION: LEGO1 0x100c95d0 +MxU32 MxDSSound::GetSizeOnDisk() +{ + MxU32 totalSizeOnDisk = MxDSMediaAction::GetSizeOnDisk(); + + this->m_sizeOnDisk = sizeof(this->m_volume); + return totalSizeOnDisk + 4; +} diff --git a/LEGO1/omni/src/action/mxdsstill.cpp b/LEGO1/omni/src/action/mxdsstill.cpp new file mode 100644 index 00000000..7e6df18b --- /dev/null +++ b/LEGO1/omni/src/action/mxdsstill.cpp @@ -0,0 +1,44 @@ +#include "mxdsstill.h" + +DECOMP_SIZE_ASSERT(MxDSStill, 0xb8) + +// FUNCTION: LEGO1 0x100c98c0 +// FUNCTION: BETA10 0x1015d54f +MxDSStill::MxDSStill() +{ + this->SetType(e_still); +} + +// FUNCTION: LEGO1 0x100c9a70 +MxDSStill::~MxDSStill() +{ +} + +// FUNCTION: LEGO1 0x100c9ac0 +void MxDSStill::CopyFrom(MxDSStill& p_dsStill) +{ +} + +// FUNCTION: LEGO1 0x100c9ad0 +MxDSStill& MxDSStill::operator=(MxDSStill& p_dsStill) +{ + if (this == &p_dsStill) { + return *this; + } + + MxDSMediaAction::operator=(p_dsStill); + this->CopyFrom(p_dsStill); + return *this; +} + +// FUNCTION: LEGO1 0x100c9b00 +MxDSAction* MxDSStill::Clone() +{ + MxDSStill* clone = new MxDSStill(); + + if (clone) { + *clone = *this; + } + + return clone; +} diff --git a/LEGO1/omni/src/action/mxdsstreamingaction.cpp b/LEGO1/omni/src/action/mxdsstreamingaction.cpp new file mode 100644 index 00000000..85759897 --- /dev/null +++ b/LEGO1/omni/src/action/mxdsstreamingaction.cpp @@ -0,0 +1,98 @@ +#include "mxdsstreamingaction.h" + +#include "mxdsbuffer.h" + +DECOMP_SIZE_ASSERT(MxDSStreamingAction, 0xb4) + +// FUNCTION: LEGO1 0x100cd010 +MxDSStreamingAction::MxDSStreamingAction(MxDSAction& p_dsAction, MxU32 p_offset) +{ + Init(); + + *this = p_dsAction; + this->m_unk0x94 = p_offset; + this->m_bufferOffset = p_offset; +} + +// FUNCTION: LEGO1 0x100cd090 +MxBool MxDSStreamingAction::HasId(MxU32 p_objectId) +{ + if (this->m_internalAction) { + return this->m_internalAction->HasId(p_objectId); + } + return FALSE; +} + +// FUNCTION: LEGO1 0x100cd0d0 +MxDSStreamingAction::MxDSStreamingAction(MxDSStreamingAction& p_dsStreamingAction) +{ + Init(); + CopyFrom(p_dsStreamingAction); +} + +// FUNCTION: LEGO1 0x100cd150 +MxDSStreamingAction::~MxDSStreamingAction() +{ + if (this->m_unk0xa0) { + delete this->m_unk0xa0; + } + if (this->m_unk0xa4) { + delete this->m_unk0xa4; + } + if (this->m_internalAction) { + delete this->m_internalAction; + } +} + +// FUNCTION: LEGO1 0x100cd1e0 +MxResult MxDSStreamingAction::Init() +{ + this->m_unk0x94 = 0; + this->m_bufferOffset = 0; + this->m_unk0x9c = 0; + this->m_unk0xa0 = NULL; + this->m_unk0xa4 = NULL; + this->m_unk0xa8 = 0; + this->m_unk0xac = 2; + this->m_internalAction = NULL; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100cd220 +MxDSStreamingAction* MxDSStreamingAction::CopyFrom(MxDSStreamingAction& p_dsStreamingAction) +{ + *this = p_dsStreamingAction; + this->m_unk0x94 = p_dsStreamingAction.m_unk0x94; + this->m_bufferOffset = p_dsStreamingAction.m_bufferOffset; + this->m_unk0x9c = p_dsStreamingAction.m_unk0x9c; + this->m_unk0xa0 = NULL; + this->m_unk0xa4 = NULL; + this->m_unk0xac = p_dsStreamingAction.m_unk0xac; + this->m_unk0xa8 = p_dsStreamingAction.m_unk0xa8; + SetInternalAction(p_dsStreamingAction.m_internalAction ? p_dsStreamingAction.m_internalAction->Clone() : NULL); + + return this; +} + +// FUNCTION: LEGO1 0x100cd2a0 +void MxDSStreamingAction::SetInternalAction(MxDSAction* p_dsAction) +{ + if (this->m_internalAction) { + delete this->m_internalAction; + } + this->m_internalAction = p_dsAction; +} + +// FUNCTION: LEGO1 0x100cd2d0 +void MxDSStreamingAction::FUN_100cd2d0() +{ + if (this->m_duration == -1) { + return; + } + + MxLong duration = this->m_duration / this->m_loopCount; + this->m_loopCount--; + + this->m_duration -= duration; + this->m_unk0xa8 += duration; +} diff --git a/LEGO1/omni/src/audio/mxaudiomanager.cpp b/LEGO1/omni/src/audio/mxaudiomanager.cpp new file mode 100644 index 00000000..0be79a24 --- /dev/null +++ b/LEGO1/omni/src/audio/mxaudiomanager.cpp @@ -0,0 +1,75 @@ +#include "mxaudiomanager.h" + +DECOMP_SIZE_ASSERT(MxAudioManager, 0x30); + +// GLOBAL: LEGO1 0x10102108 +MxS32 MxAudioManager::g_count = 0; + +// FUNCTION: LEGO1 0x100b8d00 +MxAudioManager::MxAudioManager() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100b8d90 +MxAudioManager::~MxAudioManager() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100b8df0 +void MxAudioManager::Init() +{ + this->m_volume = 100; +} + +// FUNCTION: LEGO1 0x100b8e00 +void MxAudioManager::Destroy(MxBool p_fromDestructor) +{ + this->m_criticalSection.Enter(); + g_count--; + Init(); + this->m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxMediaManager::Destroy(); + } +} + +// FUNCTION: LEGO1 0x100b8e40 +MxResult MxAudioManager::InitPresenters() +{ + MxResult result = FAILURE; + MxBool success = FALSE; + + if (MxMediaManager::InitPresenters() == SUCCESS) { + this->m_criticalSection.Enter(); + success = TRUE; + result = SUCCESS; + g_count++; + } + + if (result) { + Destroy(); + } + + if (success) { + this->m_criticalSection.Leave(); + } + + return result; +} + +// FUNCTION: LEGO1 0x100b8e90 +void MxAudioManager::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x100b8ea0 +void MxAudioManager::SetVolume(MxS32 p_volume) +{ + this->m_criticalSection.Enter(); + this->m_volume = p_volume; + this->m_criticalSection.Leave(); +} diff --git a/LEGO1/omni/src/audio/mxaudiopresenter.cpp b/LEGO1/omni/src/audio/mxaudiopresenter.cpp new file mode 100644 index 00000000..ac634362 --- /dev/null +++ b/LEGO1/omni/src/audio/mxaudiopresenter.cpp @@ -0,0 +1,5 @@ +#include "mxaudiopresenter.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxAudioPresenter, 0x54); diff --git a/LEGO1/omni/src/audio/mxloopingmidipresenter.cpp b/LEGO1/omni/src/audio/mxloopingmidipresenter.cpp new file mode 100644 index 00000000..51c305fe --- /dev/null +++ b/LEGO1/omni/src/audio/mxloopingmidipresenter.cpp @@ -0,0 +1,51 @@ +#include "mxloopingmidipresenter.h" + +#include "decomp.h" +#include "mxdssound.h" +#include "mxmisc.h" +#include "mxmusicmanager.h" + +DECOMP_SIZE_ASSERT(MxLoopingMIDIPresenter, 0x58); + +// FUNCTION: LEGO1 0x100c2a80 +void MxLoopingMIDIPresenter::StreamingTickle() +{ + if (m_action->GetLoopCount()) { + MxMIDIPresenter::StreamingTickle(); + return; + } + + if (!m_chunk) { + m_chunk = NextChunk(); + return; + } + + if (m_chunk->GetTime() + m_action->GetDuration() <= m_action->GetElapsedTime()) { + ProgressTickleState(e_done); + } +} + +// FUNCTION: LEGO1 0x100c2ae0 +void MxLoopingMIDIPresenter::DoneTickle() +{ + if (m_action->GetLoopCount()) { + MxMIDIPresenter::DoneTickle(); + } + else { + EndAction(); + } +} + +// FUNCTION: LEGO1 0x100c2b00 +MxResult MxLoopingMIDIPresenter::PutData() +{ + m_criticalSection.Enter(); + + if (m_currentTickleState == e_streaming && m_chunk && !MusicManager()->GetMIDIInitialized()) { + SetVolume(((MxDSSound*) m_action)->GetVolume()); + MusicManager()->InitializeMIDI(m_chunk->GetData(), !m_action->GetLoopCount() ? -1 : m_action->GetLoopCount()); + } + + m_criticalSection.Leave(); + return SUCCESS; +} diff --git a/LEGO1/omni/src/audio/mxmidipresenter.cpp b/LEGO1/omni/src/audio/mxmidipresenter.cpp new file mode 100644 index 00000000..d3c990c5 --- /dev/null +++ b/LEGO1/omni/src/audio/mxmidipresenter.cpp @@ -0,0 +1,131 @@ +#include "mxmidipresenter.h" + +#include "decomp.h" +#include "mxautolock.h" +#include "mxdssound.h" +#include "mxdssubscriber.h" +#include "mxmisc.h" +#include "mxmusicmanager.h" + +DECOMP_SIZE_ASSERT(MxMIDIPresenter, 0x58); + +// FUNCTION: LEGO1 0x100c25e0 +MxMIDIPresenter::MxMIDIPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100c27c0 +MxMIDIPresenter::~MxMIDIPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100c2820 +void MxMIDIPresenter::Init() +{ + m_chunk = NULL; +} + +// FUNCTION: LEGO1 0x100c2830 +void MxMIDIPresenter::Destroy(MxBool p_fromDestructor) +{ + if (MusicManager()) { + MusicManager()->DeinitializeMIDI(); + } + + m_criticalSection.Enter(); + + if (m_subscriber && m_chunk) { + m_subscriber->FreeDataChunk(m_chunk); + } + Init(); + + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxMusicPresenter::Destroy(); + } +} + +// FUNCTION: LEGO1 0x100c2890 +void MxMIDIPresenter::ReadyTickle() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk) { + m_subscriber->FreeDataChunk(chunk); + ParseExtra(); + ProgressTickleState(e_starting); + } +} + +// FUNCTION: LEGO1 0x100c28d0 +void MxMIDIPresenter::StartingTickle() +{ + MxStreamChunk* chunk = CurrentChunk(); + + if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) { + ProgressTickleState(e_streaming); + } +} + +// FUNCTION: LEGO1 0x100c2910 +void MxMIDIPresenter::StreamingTickle() +{ + if (m_chunk) { + ProgressTickleState(e_done); + } + else { + m_chunk = NextChunk(); + } +} + +// FUNCTION: LEGO1 0x100c2940 +void MxMIDIPresenter::DoneTickle() +{ + if (!MusicManager()->GetMIDIInitialized()) { + EndAction(); + } +} + +// FUNCTION: LEGO1 0x100c2960 +void MxMIDIPresenter::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x100c2970 +MxResult MxMIDIPresenter::PutData() +{ + m_criticalSection.Enter(); + + if (m_currentTickleState == e_streaming && m_chunk && !MusicManager()->GetMIDIInitialized()) { + SetVolume(((MxDSSound*) m_action)->GetVolume()); + + if (MusicManager()->InitializeMIDI(m_chunk->GetData(), 1) != SUCCESS) { + EndAction(); + } + } + + m_criticalSection.Leave(); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c29e0 +void MxMIDIPresenter::EndAction() +{ + if (m_action) { + AUTOLOCK(m_criticalSection); + + MxMediaPresenter::EndAction(); + MusicManager()->DeinitializeMIDI(); + } +} + +// FUNCTION: LEGO1 0x100c2a60 +void MxMIDIPresenter::SetVolume(MxS32 p_volume) +{ + m_volume = p_volume; + MusicManager()->SetMultiplier(p_volume); +} diff --git a/LEGO1/omni/src/audio/mxmusicmanager.cpp b/LEGO1/omni/src/audio/mxmusicmanager.cpp new file mode 100644 index 00000000..fa8bdcbe --- /dev/null +++ b/LEGO1/omni/src/audio/mxmusicmanager.cpp @@ -0,0 +1,294 @@ +#include "mxmusicmanager.h" + +#include "mxmisc.h" +#include "mxthread.h" +#include "mxticklemanager.h" + +#include + +DECOMP_SIZE_ASSERT(MxMusicManager, 0x58); + +// FUNCTION: LEGO1 0x100c05a0 +MxMusicManager::MxMusicManager() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100c0630 +MxMusicManager::~MxMusicManager() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100c0690 +void MxMusicManager::Init() +{ + m_multiplier = 100; + InitData(); +} + +// FUNCTION: LEGO1 0x100c06a0 +void MxMusicManager::InitData() +{ + m_midiStreamH = 0; + m_midiInitialized = FALSE; + m_bufferSize = 0; + m_bufferCurrentSize = 0; + m_bufferOffset = 0; + m_bufferCurrentOffset = 0; + m_loopCount = 0; + m_midiHdrP = NULL; +} + +// FUNCTION: LEGO1 0x100c06c0 +void MxMusicManager::Destroy(MxBool p_fromDestructor) +{ + if (m_thread) { + m_thread->Terminate(); + if (m_thread) { + delete m_thread; + } + } + else { + TickleManager()->UnregisterClient(this); + } + + m_criticalSection.Enter(); + DeinitializeMIDI(); + Init(); + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxAudioManager::Destroy(); + } +} + +// FUNCTION: LEGO1 0x100c0720 +MxResult MxMusicManager::ResetStream() +{ + MxResult result = FAILURE; + + if (m_midiInitialized) { + if (m_bufferCurrentSize == 0) { + if (m_loopCount != -1) { + m_loopCount += -1; + + if (!m_loopCount) { + DeinitializeMIDI(); + goto done; + } + } + + ResetBuffer(); + } + + if (m_midiHdrP->dwFlags & MHDR_DONE || m_midiHdrP->dwFlags & MHDR_PREPARED) { + if (midiOutUnprepareHeader((HMIDIOUT) m_midiStreamH, m_midiHdrP, sizeof(MIDIHDR)) != MMSYSERR_NOERROR) { + goto done; + } + + memset(m_midiHdrP, 0, sizeof(MIDIHDR)); + } + + m_bufferCurrentOffset += 4; + DWORD length = *((DWORD*) m_bufferCurrentOffset); + m_bufferCurrentOffset += sizeof(DWORD); + + m_midiHdrP->lpData = (LPSTR) m_bufferCurrentOffset; + m_midiHdrP->dwBufferLength = length; + m_midiHdrP->dwBytesRecorded = length; + + if (!midiOutPrepareHeader((HMIDIOUT) m_midiStreamH, m_midiHdrP, sizeof(MIDIHDR))) { + if (!midiStreamOut(m_midiStreamH, m_midiHdrP, sizeof(MIDIHDR))) { + result = SUCCESS; + m_bufferCurrentOffset += length; + m_bufferCurrentSize--; + } + } + } + +done: + return result; +} + +// FUNCTION: LEGO1 0x100c07e0 +void MxMusicManager::ResetBuffer() +{ + m_bufferCurrentOffset = m_bufferOffset; + m_bufferCurrentSize = m_bufferSize; +} + +// FUNCTION: LEGO1 0x100c07f0 +void MxMusicManager::SetMIDIVolume() +{ + MxS32 result = (m_volume * m_multiplier) / 0x64; + HMIDISTRM streamHandle = m_midiStreamH; + + if (streamHandle) { + MxS32 volume = CalculateVolume(result); + midiOutSetVolume((HMIDIOUT) streamHandle, volume); + } +} + +// FUNCTION: LEGO1 0x100c0820 +void CALLBACK MxMusicManager::MidiCallbackProc(HDRVR p_hdrvr, UINT p_uMsg, DWORD p_dwUser, DWORD p_dw1, DWORD p_dw2) +{ + if (p_uMsg == MOM_DONE) { + ((MxMusicManager*) p_dwUser)->ResetStream(); + } +} + +// FUNCTION: LEGO1 0x100c0840 +MxResult MxMusicManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) +{ + MxResult status = FAILURE; + MxBool locked = FALSE; + + if (MxAudioManager::InitPresenters() == SUCCESS) { + if (p_createThread) { + m_criticalSection.Enter(); + locked = TRUE; + m_thread = new MxTickleThread(this, p_frequencyMS); + + if (!m_thread || m_thread->Start(0, 0) != SUCCESS) { + goto done; + } + } + else { + TickleManager()->RegisterClient(this, p_frequencyMS); + } + + status = SUCCESS; + } + +done: + if (status != SUCCESS) { + Destroy(); + } + + if (locked) { + m_criticalSection.Leave(); + } + + return status; +} + +// FUNCTION: LEGO1 0x100c0930 +void MxMusicManager::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x100c0940 +void MxMusicManager::SetVolume(MxS32 p_volume) +{ + MxAudioManager::SetVolume(p_volume); + m_criticalSection.Enter(); + SetMIDIVolume(); + m_criticalSection.Leave(); +} + +// FUNCTION: LEGO1 0x100c0970 +void MxMusicManager::SetMultiplier(MxS32 p_multiplier) +{ + m_criticalSection.Enter(); + m_multiplier = p_multiplier; + SetMIDIVolume(); + m_criticalSection.Leave(); +} + +// FUNCTION: LEGO1 0x100c09a0 +MxS32 MxMusicManager::CalculateVolume(MxS32 p_volume) +{ + MxS32 result = (p_volume * 0xffff) / 100; + return (result << 0x10) | result; +} + +// FUNCTION: LEGO1 0x100c09c0 +MxResult MxMusicManager::InitializeMIDI(MxU8* p_data, MxS32 p_loopCount) +{ + MxResult result = FAILURE; + + m_criticalSection.Enter(); + + if (!m_midiInitialized) { + MxU32 total = midiOutGetNumDevs(); + MxU32 device = 0; + + for (; device < total; device++) { + MIDIOUTCAPSA caps; + midiOutGetDevCapsA(device, &caps, sizeof(MIDIOUTCAPSA)); + if (caps.wTechnology == MOD_FMSYNTH) { + break; + } + } + + if (device >= total) { + device = -1; + } + + if (midiStreamOpen(&m_midiStreamH, &device, 1, (DWORD) MidiCallbackProc, (DWORD) this, CALLBACK_FUNCTION) != + MMSYSERR_NOERROR) { + goto done; + } + + GetMIDIVolume(m_midiVolume); + + m_midiHdrP = new MIDIHDR(); + if (!m_midiHdrP) { + goto done; + } + + memset(m_midiHdrP, 0, sizeof(MIDIHDR)); + + MIDIPROPTIMEDIV timediv; + timediv.cbStruct = 8; + m_bufferOffset = p_data; + m_bufferOffset += 0x14; + timediv.dwTimeDiv = *((DWORD*) m_bufferOffset); + + if (midiStreamProperty(m_midiStreamH, (LPBYTE) &timediv, MIDIPROP_SET | MIDIPROP_TIMEDIV) != MMSYSERR_NOERROR) { + goto done; + } + + m_bufferOffset += 0x14; + m_bufferSize = *((MxU32*) m_bufferOffset); + m_bufferOffset += sizeof(MxU32); + m_loopCount = p_loopCount; + m_midiInitialized = TRUE; + + ResetBuffer(); + if (ResetStream() != SUCCESS) { + goto done; + } + + SetMIDIVolume(); + if (midiStreamRestart(m_midiStreamH) != MMSYSERR_NOERROR) { + goto done; + } + + result = SUCCESS; + } + +done: + m_criticalSection.Leave(); + return result; +} + +// FUNCTION: LEGO1 0x100c0b20 +void MxMusicManager::DeinitializeMIDI() +{ + m_criticalSection.Enter(); + + if (m_midiInitialized) { + m_midiInitialized = FALSE; + midiStreamStop(m_midiStreamH); + midiOutUnprepareHeader((HMIDIOUT) m_midiStreamH, m_midiHdrP, sizeof(MIDIHDR)); + midiOutSetVolume((HMIDIOUT) m_midiStreamH, m_midiVolume); + midiStreamClose(m_midiStreamH); + delete m_midiHdrP; + InitData(); + } + + m_criticalSection.Leave(); +} diff --git a/LEGO1/omni/src/audio/mxmusicpresenter.cpp b/LEGO1/omni/src/audio/mxmusicpresenter.cpp new file mode 100644 index 00000000..9f327ae4 --- /dev/null +++ b/LEGO1/omni/src/audio/mxmusicpresenter.cpp @@ -0,0 +1,59 @@ +#include "mxmusicpresenter.h" + +#include "decomp.h" +#include "mxmisc.h" +#include "mxmusicmanager.h" + +DECOMP_SIZE_ASSERT(MxMusicPresenter, 0x54); + +// FUNCTION: LEGO1 0x100c22c0 +MxMusicPresenter::MxMusicPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100c24e0 +MxMusicPresenter::~MxMusicPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100c2540 +void MxMusicPresenter::Init() +{ +} + +// FUNCTION: LEGO1 0x100c2550 +void MxMusicPresenter::Destroy(MxBool p_fromDestructor) +{ + if (MusicManager()) { + MusicManager()->UnregisterPresenter(*this); + } + + m_criticalSection.Enter(); + Init(); + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxMediaPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x100c25a0 +MxResult MxMusicPresenter::AddToManager() +{ + MxResult result = FAILURE; + + if (MusicManager()) { + result = SUCCESS; + MusicManager()->RegisterPresenter(*this); + } + + return result; +} + +// FUNCTION: LEGO1 0x100c25d0 +void MxMusicPresenter::Destroy() +{ + Destroy(FALSE); +} diff --git a/LEGO1/omni/src/audio/mxsoundmanager.cpp b/LEGO1/omni/src/audio/mxsoundmanager.cpp new file mode 100644 index 00000000..33dd2bad --- /dev/null +++ b/LEGO1/omni/src/audio/mxsoundmanager.cpp @@ -0,0 +1,238 @@ +#include "mxsoundmanager.h" + +#include "mxautolock.h" +#include "mxdsaction.h" +#include "mxmisc.h" +#include "mxomni.h" +#include "mxpresenter.h" +#include "mxthread.h" +#include "mxticklemanager.h" +#include "mxwavepresenter.h" + +DECOMP_SIZE_ASSERT(MxSoundManager, 0x3c); + +// GLOBAL LEGO1 0x10101420 +MxS32 g_volumeAttenuation[100] = {-6643, -5643, -5058, -4643, -4321, -4058, -3836, -3643, -3473, -3321, -3184, -3058, + -2943, -2836, -2736, -2643, -2556, -2473, -2395, -2321, -2251, -2184, -2120, -2058, + -2000, -1943, -1888, -1836, -1785, -1736, -1689, -1643, -1599, -1556, -1514, -1473, + -1434, -1395, -1358, -1321, -1286, -1251, -1217, -1184, -1152, -1120, -1089, -1058, + -1029, -1000, -971, -943, -915, -888, -862, -836, -810, -785, -761, -736, + -713, -689, -666, -643, -621, -599, -577, -556, -535, -514, -494, -473, + -454, -434, -415, -395, -377, -358, -340, -321, -304, -286, -268, -251, + -234, -217, -200, -184, -168, -152, -136, -120, -104, -89, -74, -58, + -43, -29, -14, 0}; + +// FUNCTION: LEGO1 0x100ae740 +MxSoundManager::MxSoundManager() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100ae7d0 +MxSoundManager::~MxSoundManager() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100ae830 +void MxSoundManager::Init() +{ + m_directSound = NULL; + m_dsBuffer = NULL; +} + +// FUNCTION: LEGO1 0x100ae840 +void MxSoundManager::Destroy(MxBool p_fromDestructor) +{ + if (this->m_thread) { + this->m_thread->Terminate(); + delete this->m_thread; + } + else { + TickleManager()->UnregisterClient(this); + } + + this->m_criticalSection.Enter(); + + if (this->m_dsBuffer) { + this->m_dsBuffer->Release(); + } + + Init(); + this->m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxAudioManager::Destroy(); + } +} + +// FUNCTION: LEGO1 0x100ae8b0 +MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) +{ + MxResult status = FAILURE; + MxBool locked = FALSE; + + if (MxAudioManager::InitPresenters() != SUCCESS) { + goto done; + } + + m_criticalSection.Enter(); + locked = TRUE; + + if (DirectSoundCreate(NULL, &m_directSound, NULL) != DS_OK) { + goto done; + } + + if (m_directSound->SetCooperativeLevel(MxOmni::GetInstance()->GetWindowHandle(), DSSCL_PRIORITY) != DS_OK) { + goto done; + } + + DSBUFFERDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (MxOmni::IsSound3D()) { + desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRL3D; + } + else { + desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; + } + + if (m_directSound->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) { + if (!MxOmni::IsSound3D()) { + goto done; + } + + MxOmni::SetSound3D(FALSE); + desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME; + + if (m_directSound->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) { + goto done; + } + } + + WAVEFORMATEX format; + + format.wFormatTag = WAVE_FORMAT_PCM; + + if (MxOmni::IsSound3D()) { + format.nChannels = 2; + } + else { + format.nChannels = 1; + } + + format.nSamplesPerSec = 11025; // KHz + format.wBitsPerSample = 16; + format.nBlockAlign = format.nChannels * 2; + format.nAvgBytesPerSec = format.nBlockAlign * 11025; + format.cbSize = 0; + + status = m_dsBuffer->SetFormat(&format); + + if (p_createThread) { + m_thread = new MxTickleThread(this, p_frequencyMS); + + if (!m_thread || m_thread->Start(0, 0) != SUCCESS) { + goto done; + } + } + else { + TickleManager()->RegisterClient(this, p_frequencyMS); + } + + status = SUCCESS; + +done: + if (status != SUCCESS) { + Destroy(); + } + + if (locked) { + m_criticalSection.Leave(); + } + return status; +} + +// FUNCTION: LEGO1 0x100aeab0 +void MxSoundManager::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x100aeac0 +void MxSoundManager::SetVolume(MxS32 p_volume) +{ + MxAudioManager::SetVolume(p_volume); + + m_criticalSection.Enter(); + + MxPresenter* presenter; + MxPresenterListCursor cursor(m_presenters); + + while (cursor.Next(presenter)) { + ((MxAudioPresenter*) presenter)->SetVolume(((MxAudioPresenter*) presenter)->GetVolume()); + } + + m_criticalSection.Leave(); +} + +// FUNCTION: LEGO1 0x100aebd0 +MxPresenter* MxSoundManager::FUN_100aebd0(const MxAtomId& p_atomId, MxU32 p_objectId) +{ + AUTOLOCK(m_criticalSection); + + MxPresenter* presenter; + MxPresenterListCursor cursor(m_presenters); + + while (cursor.Next(presenter)) { + if (presenter->GetAction()->GetAtomId().GetInternal() == p_atomId.GetInternal() && + presenter->GetAction()->GetObjectId() == p_objectId) { + return presenter; + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x100aecf0 +MxS32 MxSoundManager::GetAttenuation(MxU32 p_volume) +{ + // The unit for p_volume is percent, rounded to integer. + // Convert to DSOUND attenuation units: -10000 (silent) to 0 (loudest). + if (p_volume == 0) { + return DSBVOLUME_MIN; + } + + return g_volumeAttenuation[p_volume - 1]; +} + +// FUNCTION: LEGO1 0x100aed10 +void MxSoundManager::Pause() +{ + AUTOLOCK(m_criticalSection); + + MxPresenter* presenter; + MxPresenterListCursor cursor(m_presenters); + + while (cursor.Next(presenter)) { + if (presenter->IsA("MxWavePresenter")) { + ((MxWavePresenter*) presenter)->Pause(); + } + } +} + +// FUNCTION: LEGO1 0x100aee10 +void MxSoundManager::Resume() +{ + AUTOLOCK(m_criticalSection); + + MxPresenter* presenter; + MxPresenterListCursor cursor(m_presenters); + + while (cursor.Next(presenter)) { + if (presenter->IsA("MxWavePresenter")) { + ((MxWavePresenter*) presenter)->Resume(); + } + } +} diff --git a/LEGO1/omni/src/audio/mxsoundpresenter.cpp b/LEGO1/omni/src/audio/mxsoundpresenter.cpp new file mode 100644 index 00000000..aa0435a2 --- /dev/null +++ b/LEGO1/omni/src/audio/mxsoundpresenter.cpp @@ -0,0 +1,36 @@ +#include "mxsoundpresenter.h" + +#include "decomp.h" +#include "mxmisc.h" +#include "mxsoundmanager.h" + +DECOMP_SIZE_ASSERT(MxSoundPresenter, 0x54) + +// FUNCTION: LEGO1 0x100b1a50 +void MxSoundPresenter::Destroy(MxBool p_fromDestructor) +{ + if (MSoundManager()) { + MSoundManager()->UnregisterPresenter(*this); + } + + this->m_criticalSection.Enter(); + MxMediaPresenter::Init(); + this->m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxMediaPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x100b1aa0 +MxResult MxSoundPresenter::AddToManager() +{ + MxResult ret = FAILURE; + + if (MSoundManager()) { + ret = SUCCESS; + MSoundManager()->RegisterPresenter(*this); + } + + return ret; +} diff --git a/LEGO1/omni/src/audio/mxwavepresenter.cpp b/LEGO1/omni/src/audio/mxwavepresenter.cpp new file mode 100644 index 00000000..bc6f0683 --- /dev/null +++ b/LEGO1/omni/src/audio/mxwavepresenter.cpp @@ -0,0 +1,378 @@ +#include "mxwavepresenter.h" + +#include "decomp.h" +#include "define.h" +#include "mxautolock.h" +#include "mxdssound.h" +#include "mxdssubscriber.h" +#include "mxmisc.h" +#include "mxomni.h" +#include "mxsoundmanager.h" +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(MxWavePresenter, 0x6c); +DECOMP_SIZE_ASSERT(MxWavePresenter::WaveFormat, 0x18); + +// FUNCTION: LEGO1 0x100b1ad0 +void MxWavePresenter::Init() +{ + m_waveFormat = NULL; + m_dsBuffer = NULL; + m_chunkLength = 0; + m_lockSize = 0; + m_writtenChunks = 0; + m_started = FALSE; + m_is3d = FALSE; + m_paused = FALSE; +} + +// FUNCTION: LEGO1 0x100b1af0 +MxResult MxWavePresenter::AddToManager() +{ + MxResult result = MxSoundPresenter::AddToManager(); + Init(); + return result; +} + +// FUNCTION: LEGO1 0x100b1b10 +void MxWavePresenter::Destroy(MxBool p_fromDestructor) +{ + if (m_dsBuffer) { + m_dsBuffer->Stop(); + m_dsBuffer->Release(); + } + + if (m_waveFormat) { + delete[] ((MxU8*) m_waveFormat); + } + + Init(); + + if (!p_fromDestructor) { + MxSoundPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x100b1b60 +MxS8 MxWavePresenter::GetPlayedChunks() +{ + DWORD dwCurrentPlayCursor, dwCurrentWriteCursor; + MxS8 playedChunks = -1; + + if (m_dsBuffer->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor) == DS_OK) { + playedChunks = dwCurrentPlayCursor / m_chunkLength; + } + + return playedChunks; +} + +// FUNCTION: LEGO1 0x100b1ba0 +MxBool MxWavePresenter::FUN_100b1ba0() +{ + return !m_started || GetPlayedChunks() != m_writtenChunks; +} + +// FUNCTION: LEGO1 0x100b1bd0 +void MxWavePresenter::WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length) +{ + DWORD dwStatus; + LPVOID pvAudioPtr1; + DWORD dwOffset; + LPVOID pvAudioPtr2; + DWORD dwAudioBytes1; + DWORD dwAudioBytes2; + + dwOffset = m_chunkLength * m_writtenChunks; + m_dsBuffer->GetStatus(&dwStatus); + + if (dwStatus == DSBSTATUS_BUFFERLOST) { + m_dsBuffer->Restore(); + m_dsBuffer->GetStatus(&dwStatus); + } + + if (dwStatus != DSBSTATUS_BUFFERLOST) { + if (m_action->GetFlags() & MxDSAction::c_looping) { + m_writtenChunks++; + m_lockSize = p_length; + } + else { + m_writtenChunks = 1 - m_writtenChunks; + m_lockSize = m_chunkLength; + } + + if (m_dsBuffer->Lock(dwOffset, m_lockSize, &pvAudioPtr1, &dwAudioBytes1, &pvAudioPtr2, &dwAudioBytes2, 0) == + DS_OK) { + memcpy(pvAudioPtr1, p_audioPtr, p_length); + + if (m_lockSize > p_length && !(m_action->GetFlags() & MxDSAction::c_looping)) { + memset((MxU8*) pvAudioPtr1 + p_length, m_silenceData, m_lockSize - p_length); + } + + m_dsBuffer->Unlock(pvAudioPtr1, m_lockSize, pvAudioPtr2, 0); + } + } +} + +// FUNCTION: LEGO1 0x100b1cf0 +void MxWavePresenter::ReadyTickle() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk) { + m_waveFormat = (WaveFormat*) new MxU8[chunk->GetLength()]; + memcpy(m_waveFormat, chunk->GetData(), chunk->GetLength()); + m_subscriber->FreeDataChunk(chunk); + ParseExtra(); + ProgressTickleState(e_starting); + } +} + +// FUNCTION: LEGO1 0x100b1d50 +void MxWavePresenter::StartingTickle() +{ + MxStreamChunk* chunk = CurrentChunk(); + + if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) { + MxU32 length = chunk->GetLength(); + WAVEFORMATEX waveFormatEx; + + m_chunkLength = length; + memset(&waveFormatEx, 0, sizeof(waveFormatEx)); + + waveFormatEx.wFormatTag = m_waveFormat->m_pcmWaveFormat.wf.wFormatTag; + waveFormatEx.nChannels = m_waveFormat->m_pcmWaveFormat.wf.nChannels; + waveFormatEx.nSamplesPerSec = m_waveFormat->m_pcmWaveFormat.wf.nSamplesPerSec; + waveFormatEx.nAvgBytesPerSec = m_waveFormat->m_pcmWaveFormat.wf.nAvgBytesPerSec; + waveFormatEx.nBlockAlign = m_waveFormat->m_pcmWaveFormat.wf.nBlockAlign; + waveFormatEx.wBitsPerSample = m_waveFormat->m_pcmWaveFormat.wBitsPerSample; + + if (waveFormatEx.wBitsPerSample == 8) { + m_silenceData = 0x7F; + } + + if (waveFormatEx.wBitsPerSample == 16) { + m_silenceData = 0; + } + + DSBUFFERDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + + if (m_is3d) { + desc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME; + } + else { + desc.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME; + } + + if (m_action->GetFlags() & MxDSAction::c_looping) { + desc.dwBufferBytes = m_waveFormat->m_pcmWaveFormat.wf.nAvgBytesPerSec * + (m_action->GetDuration() / m_action->GetLoopCount()) / 1000; + } + else { + desc.dwBufferBytes = 2 * length; + } + + desc.lpwfxFormat = &waveFormatEx; + + if (MSoundManager()->GetDirectSound()->CreateSoundBuffer(&desc, &m_dsBuffer, NULL) != DS_OK) { + EndAction(); + } + else { + SetVolume(((MxDSSound*) m_action)->GetVolume()); + ProgressTickleState(e_streaming); + } + } +} + +// FUNCTION: LEGO1 0x100b1ea0 +void MxWavePresenter::StreamingTickle() +{ + if (!m_currentChunk) { + if (!(m_action->GetFlags() & MxDSAction::c_looping)) { + MxStreamChunk* chunk = CurrentChunk(); + + if (chunk && chunk->GetChunkFlags() & DS_CHUNK_END_OF_STREAM && + !(chunk->GetChunkFlags() & DS_CHUNK_BIT16)) { + chunk->SetChunkFlags(chunk->GetChunkFlags() | DS_CHUNK_BIT16); + + m_currentChunk = new MxStreamChunk; + MxU8* data = new MxU8[m_chunkLength]; + + memset(data, m_silenceData, m_chunkLength); + + m_currentChunk->SetLength(m_chunkLength); + m_currentChunk->SetData(data); + m_currentChunk->SetTime(chunk->GetTime() + 1000); + m_currentChunk->SetChunkFlags(DS_CHUNK_BIT1); + } + } + + MxMediaPresenter::StreamingTickle(); + } +} + +// FUNCTION: LEGO1 0x100b20c0 +void MxWavePresenter::DoneTickle() +{ + if (m_dsBuffer) { + DWORD dwCurrentPlayCursor, dwCurrentWriteCursor; + m_dsBuffer->GetCurrentPosition(&dwCurrentPlayCursor, &dwCurrentWriteCursor); + + MxS8 playedChunks = dwCurrentPlayCursor / m_chunkLength; + if (m_action->GetFlags() & MxDSAction::c_bit7 || m_action->GetFlags() & MxDSAction::c_looping || + (!(m_action->GetFlags() & MxDSAction::c_looping) && + (m_writtenChunks != playedChunks || m_lockSize + (m_chunkLength * playedChunks) <= dwCurrentPlayCursor))) { + MxMediaPresenter::DoneTickle(); + } + } + else { + MxMediaPresenter::DoneTickle(); + } +} + +// FUNCTION: LEGO1 0x100b2130 +void MxWavePresenter::LoopChunk(MxStreamChunk* p_chunk) +{ + WriteToSoundBuffer(p_chunk->GetData(), p_chunk->GetLength()); + if (IsEnabled()) { + m_subscriber->FreeDataChunk(p_chunk); + } +} + +// FUNCTION: LEGO1 0x100b2160 +MxResult MxWavePresenter::PutData() +{ + AUTOLOCK(m_criticalSection); + + if (IsEnabled()) { + switch (m_currentTickleState) { + case e_streaming: + if (m_currentChunk && FUN_100b1ba0()) { + WriteToSoundBuffer(m_currentChunk->GetData(), m_currentChunk->GetLength()); + m_subscriber->FreeDataChunk(m_currentChunk); + m_currentChunk = NULL; + } + + if (!m_started) { + m_dsBuffer->SetCurrentPosition(0); + + if (m_dsBuffer->Play(0, 0, DSBPLAY_LOOPING) == DS_OK) { + m_started = TRUE; + } + } + break; + case e_repeating: + if (m_started) { + break; + } + + m_dsBuffer->SetCurrentPosition(0); + + if (m_dsBuffer->Play(0, 0, m_action->GetLoopCount() > 1) == DS_OK) { + m_started = TRUE; + } + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b2280 +void MxWavePresenter::EndAction() +{ + if (m_action) { + AUTOLOCK(m_criticalSection); + MxMediaPresenter::EndAction(); + + if (m_dsBuffer) { + m_dsBuffer->Stop(); + } + } +} + +// FUNCTION: LEGO1 0x100b2300 +void MxWavePresenter::SetVolume(MxS32 p_volume) +{ + m_criticalSection.Enter(); + + m_volume = p_volume; + if (m_dsBuffer != NULL) { + MxS32 volume = p_volume * MxOmni::GetInstance()->GetSoundManager()->GetVolume() / 100; + MxS32 otherVolume = MxOmni::GetInstance()->GetSoundManager()->GetAttenuation(volume); + m_dsBuffer->SetVolume(otherVolume); + } + + m_criticalSection.Leave(); +} + +// FUNCTION: LEGO1 0x100b2360 +void MxWavePresenter::Enable(MxBool p_enable) +{ + if (IsEnabled() != p_enable) { + MxSoundPresenter::Enable(p_enable); + + if (p_enable) { + m_writtenChunks = 0; + m_started = FALSE; + } + else if (m_dsBuffer) { + m_dsBuffer->Stop(); + } + } +} + +// FUNCTION: LEGO1 0x100b23a0 +void MxWavePresenter::ParseExtra() +{ + MxSoundPresenter::ParseExtra(); + + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[512]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char soundValue[512]; + if (KeyValueStringParse(soundValue, g_strSOUND, extraCopy)) { + if (!strcmpi(soundValue, "FALSE")) { + Enable(FALSE); + } + } + } +} + +// FUNCTION: LEGO1 0x100b2440 +void MxWavePresenter::Pause() +{ + if (!m_paused && m_started) { + if (m_dsBuffer) { + m_dsBuffer->Stop(); + } + m_paused = TRUE; + } +} + +// FUNCTION: LEGO1 0x100b2470 +void MxWavePresenter::Resume() +{ + if (m_paused) { + if (m_dsBuffer && m_started) { + switch (m_currentTickleState) { + case e_streaming: + m_dsBuffer->Play(0, 0, DSBPLAY_LOOPING); + break; + case e_repeating: + m_dsBuffer->Play(0, 0, m_action->GetLoopCount() > 1); + break; + case e_done: + m_dsBuffer->Play(0, 0, 0); + } + } + + m_paused = FALSE; + } +} diff --git a/LEGO1/omni/src/common/mxatom.cpp b/LEGO1/omni/src/common/mxatom.cpp new file mode 100644 index 00000000..e242ebb0 --- /dev/null +++ b/LEGO1/omni/src/common/mxatom.cpp @@ -0,0 +1,143 @@ +#include "mxatom.h" + +#include "decomp.h" +#include "mxmisc.h" +#include "mxomni.h" + +#include + +DECOMP_SIZE_ASSERT(MxAtomId, 0x04); +DECOMP_SIZE_ASSERT(MxAtom, 0x14); +DECOMP_SIZE_ASSERT(MxAtomSet, 0x10); + +// FUNCTION: LEGO1 0x100acf90 +// FUNCTION: BETA10 0x1012308b +MxAtomId::MxAtomId(const char* p_str, LookupMode p_mode) +{ + if (!MxOmni::GetInstance()) { + return; + } + + if (!AtomSet()) { + return; + } + + MxAtom* atom = GetAtom(p_str, p_mode); + *this = atom->GetKey(); + atom->Inc(); +} + +// FUNCTION: LEGO1 0x100acfd0 +// FUNCTION: BETA10 0x10123130 +MxAtomId::~MxAtomId() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100acfe0 +// FUNCTION: BETA10 0x101231a6 +void MxAtomId::Destroy() +{ + if (!m_internal) { + return; + } + + if (!MxOmni::GetInstance()) { + return; + } + + if (!AtomSet()) { + return; + } + +#ifdef COMPAT_MODE + MxAtomSet::iterator it; + { + MxAtom idAtom(m_internal); + it = AtomSet()->find(&idAtom); + } +#else + MxAtomSet::iterator it = AtomSet()->find(&MxAtom(m_internal)); +#endif + assert(it != AtomSet()->end()); + + MxAtom* atom = (MxAtom*) (*it); + atom->Dec(); +} + +// FUNCTION: LEGO1 0x100ad1c0 +// FUNCTION: BETA10 0x101232b9 +MxAtomId& MxAtomId::operator=(const MxAtomId& p_atomId) +{ + if (m_internal) { + Destroy(); + } + + if (p_atomId.m_internal && MxOmni::GetInstance() && AtomSet()) { + MxAtom* atom = GetAtom(p_atomId.m_internal, e_exact); + atom->Inc(); + } + + m_internal = p_atomId.m_internal; + + return *this; +} + +// FUNCTION: LEGO1 0x100ad210 +// FUNCTION: BETA10 0x10123378 +MxAtom* MxAtomId::GetAtom(const char* p_str, LookupMode p_mode) +{ + MxAtomId unused; + MxAtom* atom = new MxAtom(p_str); + assert(atom); + + switch (p_mode) { + case e_exact: + break; + case e_upperCase: + atom->GetKey().ToUpperCase(); + break; + case e_lowerCase: + case e_lowerCase2: + atom->GetKey().ToLowerCase(); + break; + } + + MxAtomSet::iterator it = AtomSet()->find(atom); + if (it != AtomSet()->end()) { + // Atom already in the set. Delete temp value and return it. + delete atom; + atom = *it; + } + else { + // Atom is not in the set. Add it. + AtomSet()->insert(atom); + } + + return atom; +} + +// FUNCTION: LEGO1 0x100ad7e0 +// FUNCTION: BETA10 0x100553e0 +void MxAtomId::Clear() +{ + // Reset but do not delete MxAtomId object. + Destroy(); + m_internal = NULL; +} + +// FUNCTION: LEGO1 0x100ad7f0 +// FUNCTION: BETA10 0x101235d5 +void MxAtom::Inc() +{ + m_value++; +} + +// FUNCTION: LEGO1 0x100ad800 +// FUNCTION: BETA10 0x1012364a +void MxAtom::Dec() +{ + if (m_value) { + m_value--; + } +} diff --git a/LEGO1/omni/src/common/mxcompositepresenter.cpp b/LEGO1/omni/src/common/mxcompositepresenter.cpp new file mode 100644 index 00000000..a88279ac --- /dev/null +++ b/LEGO1/omni/src/common/mxcompositepresenter.cpp @@ -0,0 +1,268 @@ +#include "mxcompositepresenter.h" + +#include "decomp.h" +#include "mxactionnotificationparam.h" +#include "mxautolock.h" +#include "mxdsmultiaction.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxobjectfactory.h" + +DECOMP_SIZE_ASSERT(MxCompositePresenter, 0x4c); + +// FUNCTION: LEGO1 0x100b60b0 +MxCompositePresenter::MxCompositePresenter() +{ + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x100b6390 +MxCompositePresenter::~MxCompositePresenter() +{ + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x100b6410 +MxResult MxCompositePresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + + MxResult result = FAILURE; + MxDSActionList* actions = ((MxDSMultiAction*) p_action)->GetActionList(); + MxObjectFactory* factory = ObjectFactory(); + MxDSActionListCursor cursor(actions); + MxDSAction* action; + + if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) { + cursor.Head(); + + while (cursor.Current(action)) { + MxBool success = FALSE; + const char* presenterName; + MxPresenter* presenter = NULL; + + cursor.Next(); + + if (m_action->GetFlags() & MxDSAction::c_looping) { + action->SetFlags(action->GetFlags() | MxDSAction::c_looping); + } + else if (m_action->GetFlags() & MxDSAction::c_bit3) { + action->SetFlags(action->GetFlags() | MxDSAction::c_bit3); + } + + presenterName = PresenterNameDispatch(*action); + presenter = (MxPresenter*) factory->Create(presenterName); + + if (presenter && presenter->AddToManager() == SUCCESS) { + presenter->SetCompositePresenter(this); + if (presenter->StartAction(p_controller, action) == SUCCESS) { + success = TRUE; + } + } + + if (success) { + action->SetOrigin(this); + m_list.push_back(presenter); + } + else if (presenter) { + delete presenter; + } + } + + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x100b65e0 +void MxCompositePresenter::EndAction() +{ + AUTOLOCK(m_criticalSection); + + if (!m_action) { + return; + } + + ((MxDSMultiAction*) m_action)->GetActionList()->DeleteAll(FALSE); + + while (!m_list.empty()) { + MxPresenter* presenter = m_list.front(); + m_list.pop_front(); + presenter->SetCompositePresenter(NULL); + presenter->EndAction(); + } + + MxDSAction* action = m_action; + MxPresenter::EndAction(); + + if (action && action->GetOrigin()) { + NotificationManager()->Send( + action->GetOrigin(), + MxEndActionNotificationParam(c_notificationEndAction, this, action, FALSE) + ); + } +} + +// FUNCTION: LEGO1 0x100b6760 +MxLong MxCompositePresenter::Notify(MxParam& p_param) +{ + AUTOLOCK(m_criticalSection); + + switch (((MxNotificationParam&) p_param).GetNotification()) { + case c_notificationEndAction: + VTable0x58((MxEndActionNotificationParam&) p_param); + break; + case c_notificationPresenter: + VTable0x5c((MxNotificationParam&) p_param); + } + + return 0; +} + +// FUNCTION: LEGO1 0x100b67f0 +void MxCompositePresenter::VTable0x58(MxEndActionNotificationParam& p_param) +{ + MxPresenter* presenter = (MxPresenter*) p_param.GetSender(); + MxDSAction* action = p_param.GetAction(); + MxCompositePresenterList::iterator it; + + if (!m_list.empty()) { + for (it = m_list.begin(); it != m_list.end(); it++) { + if (*it == presenter) { + m_list.erase(it++); + break; + } + } + } + + if (m_action) { + MxDSActionList* actions = ((MxDSMultiAction*) m_action)->GetActionList(); + MxDSActionListCursor cursor(actions); + + if (cursor.Find(action)) { + cursor.Detach(); + } + } + + if (presenter) { + delete presenter; + } + + if (action) { + delete action; + } + + if (m_list.empty()) { + EndAction(); + } + else { + if (m_action->IsA("MxDSSerialAction") && it != m_list.end()) { + MxPresenter* presenter = *it; + if (presenter->GetCurrentTickleState() == e_idle) { + presenter->SetTickleState(e_ready); + } + } + } +} + +// FUNCTION: LEGO1 0x100b69b0 +void MxCompositePresenter::VTable0x5c(MxNotificationParam& p_param) +{ + if (!m_list.empty()) { + MxPresenter* presenter = (MxPresenter*) p_param.GetSender(); + + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + if (*it == presenter) { + m_list.erase(it++); + + if (presenter->GetCurrentTickleState() == e_idle) { + presenter->SetTickleState(e_ready); + } + + MxDSActionList* actions = ((MxDSMultiAction*) m_action)->GetActionList(); + MxDSActionListCursor cursor(actions); + + if (cursor.Find(presenter->GetAction())) { + cursor.Detach(); + } + + if (m_list.empty()) { + EndAction(); + } + else { + if (m_action->IsA("MxDSSerialAction")) { + MxPresenter* presenter = *it; + if (presenter->GetCurrentTickleState() == e_idle) { + presenter->SetTickleState(e_ready); + } + } + } + + return; + } + } + + NotificationManager()->Send(this, p_param); + } +} + +// FUNCTION: LEGO1 0x100b6b40 +void MxCompositePresenter::VTable0x60(MxPresenter* p_presenter) +{ + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + if (*it == p_presenter) { + if (++it == m_list.end()) { + if (m_compositePresenter) { + m_compositePresenter->VTable0x60(this); + } + } + else if (m_action->IsA("MxDSSerialAction")) { + MxPresenter* presenter = *it; + if (presenter->GetCurrentTickleState() == e_idle) { + presenter->SetTickleState(e_ready); + } + } + return; + } + } +} + +// FUNCTION: LEGO1 0x100b6bc0 +void MxCompositePresenter::SetTickleState(TickleState p_tickleState) +{ + ProgressTickleState(p_tickleState); + + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + MxPresenter* presenter = *it; + presenter->SetTickleState(p_tickleState); + + if (m_action->IsA("MxDSSerialAction") && p_tickleState == e_ready) { + return; + } + } +} + +// FUNCTION: LEGO1 0x100b6c30 +void MxCompositePresenter::Enable(MxBool p_enable) +{ + MxPresenter::Enable(p_enable); + + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + MxPresenter* presenter = *it; + presenter->Enable(p_enable); + } +} + +// FUNCTION: LEGO1 0x100b6c80 +MxBool MxCompositePresenter::HasTickleStatePassed(TickleState p_tickleState) +{ + for (MxCompositePresenterList::iterator it = m_list.begin(); it != m_list.end(); it++) { + MxPresenter* presenter = *it; + if (!presenter->HasTickleStatePassed(p_tickleState)) { + return FALSE; + } + } + + return TRUE; +} diff --git a/LEGO1/omni/src/common/mxcore.cpp b/LEGO1/omni/src/common/mxcore.cpp new file mode 100644 index 00000000..cb315432 --- /dev/null +++ b/LEGO1/omni/src/common/mxcore.cpp @@ -0,0 +1,29 @@ +#include "mxcore.h" + +#include + +// GLOBAL: LEGO1 0x1010141c +// GLOBAL: BETA10 0x10201f88 +MxU32 MxCore::g_nextCoreId = 0; + +// FUNCTION: LEGO1 0x100ae1a0 +// FUNCTION: BETA10 0x1012c020 +MxCore::MxCore() +{ + m_id = g_nextCoreId++; + assert(g_nextCoreId); +} + +// FUNCTION: LEGO1 0x100ae1e0 +// FUNCTION: BETA10 0x1012c077 +MxCore::~MxCore() +{ +} + +// FUNCTION: LEGO1 0x100ae1f0 +// FUNCTION: BETA10 0x1012c096 +MxLong MxCore::Notify(MxParam& p_param) +{ + assert(0); + return 0; +} diff --git a/LEGO1/omni/src/common/mxmediamanager.cpp b/LEGO1/omni/src/common/mxmediamanager.cpp new file mode 100644 index 00000000..bd32c70b --- /dev/null +++ b/LEGO1/omni/src/common/mxmediamanager.cpp @@ -0,0 +1,109 @@ +#include "mxmediamanager.h" + +#include "decomp.h" +#include "mxautolock.h" +#include "mxomni.h" +#include "mxpresenter.h" +#include "mxticklemanager.h" + +DECOMP_SIZE_ASSERT(MxMediaManager, 0x2c); +DECOMP_SIZE_ASSERT(MxPresenterList, 0x18); +DECOMP_SIZE_ASSERT(MxPresenterListCursor, 0x10); + +// FUNCTION: LEGO1 0x100b84c0 +MxMediaManager::MxMediaManager() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100b8560 +MxMediaManager::~MxMediaManager() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100b85d0 +MxResult MxMediaManager::Init() +{ + this->m_presenters = NULL; + this->m_thread = NULL; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b85e0 +MxResult MxMediaManager::InitPresenters() +{ + AUTOLOCK(m_criticalSection); + + this->m_presenters = new MxPresenterList; + + if (!this->m_presenters) { + this->Destroy(); + return FAILURE; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b8710 +void MxMediaManager::Destroy() +{ + AUTOLOCK(m_criticalSection); + + if (this->m_presenters) { + delete this->m_presenters; + } + + Init(); +} + +// FUNCTION: LEGO1 0x100b8790 +MxResult MxMediaManager::Tickle() +{ + AUTOLOCK(m_criticalSection); + MxPresenter* presenter; + MxPresenterListCursor cursor(this->m_presenters); + + while (cursor.Next(presenter)) { + presenter->Tickle(); + } + + cursor.Reset(); + + while (cursor.Next(presenter)) { + presenter->PutData(); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b88c0 +void MxMediaManager::RegisterPresenter(MxPresenter& p_presenter) +{ + AUTOLOCK(m_criticalSection); + + this->m_presenters->Append(&p_presenter); +} + +// FUNCTION: LEGO1 0x100b8980 +void MxMediaManager::UnregisterPresenter(MxPresenter& p_presenter) +{ + AUTOLOCK(m_criticalSection); + MxPresenterListCursor cursor(this->m_presenters); + + if (cursor.Find(&p_presenter)) { + cursor.Detach(); + } +} + +// FUNCTION: LEGO1 0x100b8ac0 +void MxMediaManager::StopPresenters() +{ + AUTOLOCK(m_criticalSection); + MxPresenter* presenter; + MxPresenterListCursor cursor(this->m_presenters); + + while (cursor.Next(presenter)) { + presenter->EndAction(); + } +} diff --git a/LEGO1/omni/src/common/mxmediapresenter.cpp b/LEGO1/omni/src/common/mxmediapresenter.cpp new file mode 100644 index 00000000..462b8987 --- /dev/null +++ b/LEGO1/omni/src/common/mxmediapresenter.cpp @@ -0,0 +1,264 @@ +#include "mxmediapresenter.h" + +#include "mxactionnotificationparam.h" +#include "mxautolock.h" +#include "mxcompositepresenter.h" +#include "mxdssubscriber.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxstreamchunk.h" +#include "mxtimer.h" + +DECOMP_SIZE_ASSERT(MxMediaPresenter, 0x50); +DECOMP_SIZE_ASSERT(MxStreamChunkList, 0x18); +DECOMP_SIZE_ASSERT(MxStreamChunkListCursor, 0x10); + +// FUNCTION: LEGO1 0x100b54e0 +void MxMediaPresenter::Init() +{ + this->m_subscriber = NULL; + this->m_loopingChunks = NULL; + this->m_loopingChunkCursor = NULL; + this->m_currentChunk = NULL; +} + +// FUNCTION: LEGO1 0x100b54f0 +void MxMediaPresenter::Destroy(MxBool p_fromDestructor) +{ + { + AUTOLOCK(m_criticalSection); + + if (m_currentChunk && m_subscriber) { + m_subscriber->FreeDataChunk(m_currentChunk); + } + + if (m_subscriber) { + delete m_subscriber; + } + + if (m_loopingChunkCursor) { + delete m_loopingChunkCursor; + } + + if (m_loopingChunks) { + MxStreamChunkListCursor cursor(m_loopingChunks); + MxStreamChunk* chunk; + + while (cursor.Next(chunk)) { + chunk->Release(); + } + + delete m_loopingChunks; + } + + Init(); + } + + if (!p_fromDestructor) { + MxPresenter::Destroy(); + } +} + +// FUNCTION: LEGO1 0x100b5650 +MxStreamChunk* MxMediaPresenter::CurrentChunk() +{ + MxStreamChunk* chunk = NULL; + + if (m_subscriber) { + chunk = m_subscriber->PeekData(); + + if (chunk && chunk->GetChunkFlags() & DS_CHUNK_BIT3) { + m_action->SetFlags(m_action->GetFlags() | MxDSAction::c_bit7); + m_subscriber->PopData(); + m_subscriber->FreeDataChunk(chunk); + chunk = NULL; + ProgressTickleState(e_done); + } + } + + return chunk; +} + +// FUNCTION: LEGO1 0x100b56b0 +MxStreamChunk* MxMediaPresenter::NextChunk() +{ + MxStreamChunk* chunk = NULL; + + if (m_subscriber) { + chunk = m_subscriber->PopData(); + + if (chunk && chunk->GetChunkFlags() & DS_CHUNK_BIT3) { + m_action->SetFlags(m_action->GetFlags() | MxDSAction::c_bit7); + m_subscriber->FreeDataChunk(chunk); + chunk = NULL; + ProgressTickleState(e_done); + } + } + + return chunk; +} + +// FUNCTION: LEGO1 0x100b5700 +MxResult MxMediaPresenter::StartAction(MxStreamController* p_controller, MxDSAction* p_action) +{ + MxResult result = FAILURE; + AUTOLOCK(m_criticalSection); + + if (MxPresenter::StartAction(p_controller, p_action) == SUCCESS) { + if (m_action->GetFlags() & MxDSAction::c_looping) { + m_loopingChunks = new MxStreamChunkList; + m_loopingChunkCursor = new MxStreamChunkListCursor(m_loopingChunks); + + if (!m_loopingChunks && !m_loopingChunkCursor) { + goto done; + } + } + + if (p_controller) { + m_subscriber = new MxDSSubscriber; + + if (!m_subscriber || + m_subscriber->Create(p_controller, p_action->GetObjectId(), p_action->GetUnknown24()) != SUCCESS) { + goto done; + } + } + + result = SUCCESS; + } + +done: + return result; +} + +// FUNCTION: LEGO1 0x100b5bc0 +void MxMediaPresenter::EndAction() +{ + AUTOLOCK(m_criticalSection); + + if (!m_action) { + return; + } + + m_currentChunk = NULL; + + if (m_action->GetFlags() & MxDSAction::c_world && (!m_compositePresenter || !m_compositePresenter->VTable0x64(2))) { + MxPresenter::Enable(FALSE); + SetTickleState(e_idle); + } + else { + MxDSAction* action = m_action; + MxPresenter::EndAction(); + + if (m_subscriber) { + delete m_subscriber; + m_subscriber = NULL; + } + + if (action && action->GetOrigin()) { + NotificationManager()->Send( + action->GetOrigin(), + MxEndActionNotificationParam(c_notificationEndAction, this, action, FALSE) + ); + } + } +} + +// FUNCTION: LEGO1 0x100b5d10 +MxResult MxMediaPresenter::Tickle() +{ + AUTOLOCK(m_criticalSection); + + CurrentChunk(); + + return MxPresenter::Tickle(); +} + +// FUNCTION: LEGO1 0x100b5d90 +void MxMediaPresenter::StreamingTickle() +{ + if (!m_currentChunk) { + m_currentChunk = NextChunk(); + + if (m_currentChunk) { + if (m_currentChunk->GetChunkFlags() & DS_CHUNK_END_OF_STREAM) { + m_subscriber->FreeDataChunk(m_currentChunk); + m_currentChunk = NULL; + ProgressTickleState(e_repeating); + } + else if (m_action->GetFlags() & MxDSAction::c_looping) { + LoopChunk(m_currentChunk); + + if (!IsEnabled()) { + m_subscriber->FreeDataChunk(m_currentChunk); + m_currentChunk = NULL; + } + } + } + } +} + +// FUNCTION: LEGO1 0x100b5e10 +void MxMediaPresenter::RepeatingTickle() +{ + if (IsEnabled() && !m_currentChunk) { + if (m_loopingChunkCursor) { + if (!m_loopingChunkCursor->Next(m_currentChunk)) { + m_loopingChunkCursor->Next(m_currentChunk); + } + } + + if (m_currentChunk) { + MxLong time = m_currentChunk->GetTime(); + if (time <= m_action->GetElapsedTime() % m_action->GetLoopCount()) { + ProgressTickleState(e_freezing); + } + } + else { + if (m_action->GetElapsedTime() >= m_action->GetStartTime() + m_action->GetDuration()) { + ProgressTickleState(e_freezing); + } + } + } +} + +// FUNCTION: LEGO1 0x100b5ef0 +void MxMediaPresenter::DoneTickle() +{ + ProgressTickleState(e_idle); + EndAction(); +} + +// FUNCTION: LEGO1 0x100b5f10 +void MxMediaPresenter::LoopChunk(MxStreamChunk* p_chunk) +{ + MxStreamChunk* chunk = new MxStreamChunk; + + MxU32 length = p_chunk->GetLength(); + chunk->SetLength(length); + chunk->SetData(new MxU8[length]); + chunk->SetTime(p_chunk->GetTime()); + + memcpy(chunk->GetData(), p_chunk->GetData(), chunk->GetLength()); + m_loopingChunks->Append(chunk); +} + +// FUNCTION: LEGO1 0x100b6030 +void MxMediaPresenter::Enable(MxBool p_enable) +{ + if (IsEnabled() != p_enable) { + MxPresenter::Enable(p_enable); + + if (p_enable) { + MxLong time = Timer()->GetTime(); + m_action->SetUnknown90(time); + SetTickleState(e_repeating); + } + else { + if (m_loopingChunkCursor) { + m_loopingChunkCursor->Reset(); + } + m_currentChunk = NULL; + SetTickleState(e_done); + } + } +} diff --git a/LEGO1/omni/src/common/mxmisc.cpp b/LEGO1/omni/src/common/mxmisc.cpp new file mode 100644 index 00000000..8dbab329 --- /dev/null +++ b/LEGO1/omni/src/common/mxmisc.cpp @@ -0,0 +1,109 @@ +#include "mxmisc.h" + +#include "mxomni.h" + +#include + +// FUNCTION: LEGO1 0x100acea0 +// FUNCTION: BETA10 0x10124d30 +MxObjectFactory* ObjectFactory() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetObjectFactory(); +} + +// FUNCTION: LEGO1 0x100aceb0 +// FUNCTION: BETA10 0x10124d77 +MxNotificationManager* NotificationManager() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetNotificationManager(); +} + +// FUNCTION: LEGO1 0x100acec0 +// FUNCTION: BETA10 0x10124dbe +MxTickleManager* TickleManager() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetTickleManager(); +} + +// FUNCTION: LEGO1 0x100aced0 +// FUNCTION: BETA10 0x10124e05 +MxTimer* Timer() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetTimer(); +} + +// FUNCTION: LEGO1 0x100acee0 +// FUNCTION: BETA10 0x10124e4c +MxAtomSet* AtomSet() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetAtomSet(); +} + +// FUNCTION: LEGO1 0x100acef0 +// FUNCTION: BETA10 0x10124e93 +MxStreamer* Streamer() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetStreamer(); +} + +// FUNCTION: LEGO1 0x100acf00 +// FUNCTION: BETA10 0x10124eda +MxSoundManager* MSoundManager() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetSoundManager(); +} + +// FUNCTION: LEGO1 0x100acf10 +// FUNCTION: BETA10 0x10124f21 +MxVideoManager* MVideoManager() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetVideoManager(); +} + +// FUNCTION: LEGO1 0x100acf20 +// FUNCTION: BETA10 0x10124f68 +MxVariableTable* VariableTable() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetVariableTable(); +} + +// FUNCTION: LEGO1 0x100acf30 +// FUNCTION: BETA10 0x10124faf +MxMusicManager* MusicManager() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetMusicManager(); +} + +// FUNCTION: LEGO1 0x100acf40 +// FUNCTION: BETA10 0x10124ff6 +MxEventManager* EventManager() +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->GetEventManager(); +} + +// FUNCTION: LEGO1 0x100acf50 +// FUNCTION: BETA10 0x1012503d +MxResult Start(MxDSAction* p_dsAction) +{ + assert(MxOmni::GetInstance()); + return MxOmni::GetInstance()->Start(p_dsAction); +} + +// FUNCTION: LEGO1 0x100acf70 +// FUNCTION: BETA10 0x10125098 +void DeleteObject(MxDSAction& p_dsAction) +{ + assert(MxOmni::GetInstance()); + MxOmni::GetInstance()->DeleteObject(p_dsAction); +} diff --git a/LEGO1/omni/src/common/mxobjectfactory.cpp b/LEGO1/omni/src/common/mxobjectfactory.cpp new file mode 100644 index 00000000..93f2e0a0 --- /dev/null +++ b/LEGO1/omni/src/common/mxobjectfactory.cpp @@ -0,0 +1,49 @@ +#include "mxobjectfactory.h" + +#include "decomp.h" +#include "mxcompositepresenter.h" +#include "mxeventpresenter.h" +#include "mxflcpresenter.h" +#include "mxloopingflcpresenter.h" +#include "mxloopingmidipresenter.h" +#include "mxloopingsmkpresenter.h" +#include "mxmidipresenter.h" +#include "mxpresenter.h" +#include "mxsmkpresenter.h" +#include "mxstillpresenter.h" +#include "mxvideopresenter.h" +#include "mxwavepresenter.h" + +DECOMP_SIZE_ASSERT(MxObjectFactory, 0x38); // 100af1db + +// FUNCTION: LEGO1 0x100b0d80 +MxObjectFactory::MxObjectFactory() +{ +#define X(V) this->m_id##V = MxAtomId(#V, e_exact); + FOR_MXOBJECTFACTORY_OBJECTS(X) +#undef X +} + +// FUNCTION: LEGO1 0x100b12c0 +MxCore* MxObjectFactory::Create(const char* p_name) +{ + MxCore* object = NULL; + MxAtomId atom(p_name, e_exact); + + if (0) { + } +#define X(V) \ + else if (this->m_id##V == atom) \ + { \ + object = new V; \ + } + FOR_MXOBJECTFACTORY_OBJECTS(X) +#undef X + return object; +} + +// FUNCTION: LEGO1 0x100b1a30 +void MxObjectFactory::Destroy(MxCore* p_object) +{ + delete p_object; +} diff --git a/LEGO1/omni/src/common/mxpresenter.cpp b/LEGO1/omni/src/common/mxpresenter.cpp new file mode 100644 index 00000000..be530f58 --- /dev/null +++ b/LEGO1/omni/src/common/mxpresenter.cpp @@ -0,0 +1,255 @@ +#include "mxpresenter.h" + +#include "decomp.h" +#include "define.h" +#include "mxactionnotificationparam.h" +#include "mxautolock.h" +#include "mxcompositepresenter.h" +#include "mxdsanim.h" +#include "mxdssound.h" +#include "mxentity.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxobjectfactory.h" +#include "mxomni.h" +#include "mxparam.h" +#include "mxstreamer.h" +#include "mxutilities.h" + +#include + +DECOMP_SIZE_ASSERT(MxPresenter, 0x40); + +// FUNCTION: LEGO1 0x100b4d50 +void MxPresenter::Init() +{ + m_currentTickleState = e_idle; + m_action = NULL; + m_location = MxPoint32(0, 0); + m_displayZ = 0; + m_compositePresenter = NULL; + m_previousTickleStates = 0; +} + +// FUNCTION: LEGO1 0x100b4d80 +MxResult MxPresenter::StartAction(MxStreamController*, MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + + this->m_action = p_action; + + const Mx3DPointFloat& location = this->m_action->GetLocation(); + MxS32 previousTickleState = this->m_currentTickleState; + + this->m_location = MxPoint32(this->m_action->GetLocation()[0], this->m_action->GetLocation()[1]); + this->m_displayZ = this->m_action->GetLocation()[2]; + ProgressTickleState(e_ready); + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b4e40 +void MxPresenter::EndAction() +{ + if (this->m_action == NULL) { + return; + } + + AUTOLOCK(m_criticalSection); + + if (!this->m_compositePresenter) { + MxOmni::GetInstance()->NotifyCurrentEntity( + MxEndActionNotificationParam(c_notificationEndAction, NULL, this->m_action, TRUE) + ); + } + + this->m_action = NULL; + MxS32 previousTickleState = 1 << m_currentTickleState; + this->m_previousTickleStates |= previousTickleState; + this->m_currentTickleState = e_idle; +} + +// FUNCTION: LEGO1 0x100b4fc0 +void MxPresenter::ParseExtra() +{ + AUTOLOCK(m_criticalSection); + + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[512]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char worldValue[512]; + if (KeyValueStringParse(worldValue, g_strWORLD, extraCopy)) { + char* token = strtok(worldValue, g_parseExtraTokens); + char buf[256]; + strcpy(buf, token); + + token = strtok(NULL, g_parseExtraTokens); + MxS32 val = token ? atoi(token) : 0; + MxEntity* result = MxOmni::GetInstance()->AddToWorld(buf, val, this); + + m_action->SetFlags(m_action->GetFlags() | MxDSAction::c_world); + + if (result) { + SendToCompositePresenter(MxOmni::GetInstance()); + } + } + } +} + +// FUNCTION: LEGO1 0x100b5120 +void MxPresenter::SendToCompositePresenter(MxOmni* p_omni) +{ + if (m_compositePresenter) { + AUTOLOCK(m_criticalSection); + + NotificationManager()->Send(m_compositePresenter, MxNotificationParam(c_notificationPresenter, this)); + m_action->SetOrigin(p_omni ? p_omni : MxOmni::GetInstance()); + m_compositePresenter = NULL; + } +} + +// FUNCTION: LEGO1 0x100b5200 +MxResult MxPresenter::Tickle() +{ + AUTOLOCK(m_criticalSection); + + switch (this->m_currentTickleState) { + case e_ready: + this->ReadyTickle(); + + if (m_currentTickleState != e_starting) { + break; + } + case e_starting: + this->StartingTickle(); + + if (m_currentTickleState != e_streaming) { + break; + } + case e_streaming: + this->StreamingTickle(); + + if (m_currentTickleState != e_repeating) { + break; + } + case e_repeating: + this->RepeatingTickle(); + + if (m_currentTickleState != e_freezing) { + break; + } + case e_freezing: + this->FreezingTickle(); + + if (m_currentTickleState != e_done) { + break; + } + case e_done: + this->DoneTickle(); + default: + break; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b52d0 +void MxPresenter::Enable(MxBool p_enable) +{ + if (this->m_action && this->IsEnabled() != p_enable) { + MxU32 flags = this->m_action->GetFlags(); + + if (p_enable) { + this->m_action->SetFlags(flags | MxDSAction::c_enabled); + } + else { + this->m_action->SetFlags(flags & ~MxDSAction::c_enabled); + } + } +} + +// FUNCTION: LEGO1 0x100b5310 +const char* PresenterNameDispatch(const MxDSAction& p_action) +{ + const char* name = p_action.GetSourceName(); + MxS32 format; + + if (!name || strlen(name) == 0) { + switch (p_action.GetType()) { + case MxDSObject::e_anim: + format = ((MxDSAnim&) p_action).GetMediaFormat(); + switch (format) { + case FOURCC(' ', 'F', 'L', 'C'): + name = !p_action.IsLooping() ? "MxFlcPresenter" : "MxLoopingFlcPresenter"; + break; + case FOURCC(' ', 'S', 'M', 'K'): + name = !p_action.IsLooping() ? "MxSmkPresenter" : "MxLoopingSmkPresenter"; + break; + } + break; + + case MxDSObject::e_sound: + format = ((MxDSSound&) p_action).GetMediaFormat(); + switch (format) { + case FOURCC(' ', 'M', 'I', 'D'): + name = !p_action.IsLooping() ? "MxMIDIPresenter" : "MxLoopingMIDIPresenter"; + break; + case FOURCC(' ', 'W', 'A', 'V'): + name = "MxWavePresenter"; + break; + } + break; + + case MxDSObject::e_serialAction: + case MxDSObject::e_parallelAction: + case MxDSObject::e_selectAction: + name = "MxCompositePresenter"; + break; + + case MxDSObject::e_event: + name = "MxEventPresenter"; + break; + + case MxDSObject::e_still: + name = "MxStillPresenter"; + break; + } + } + + return name; +} + +// FUNCTION: LEGO1 0x100b5410 +MxEntity* MxPresenter::CreateEntity(const char* p_defaultName) +{ + // create an object from LegoObjectFactory based on OBJECT: value in extra data. + // If that is missing, p_defaultName is used + + char objectName[512]; + strcpy(objectName, p_defaultName); + + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[512]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + KeyValueStringParse(objectName, g_strOBJECT, extraCopy); + } + + return (MxEntity*) ObjectFactory()->Create(objectName); +} + +// FUNCTION: LEGO1 0x100b54c0 +MxBool MxPresenter::IsEnabled() +{ + return this->m_action && this->m_action->GetFlags() & MxDSAction::c_enabled; +} diff --git a/LEGO1/omni/src/common/mxstring.cpp b/LEGO1/omni/src/common/mxstring.cpp new file mode 100644 index 00000000..b33a7f10 --- /dev/null +++ b/LEGO1/omni/src/common/mxstring.cpp @@ -0,0 +1,187 @@ +#include "mxstring.h" + +#include "decomp.h" + +#include +#include + +DECOMP_SIZE_ASSERT(MxString, 0x10) + +// FUNCTION: LEGO1 0x100ae200 +// FUNCTION: BETA10 0x1012c110 +MxString::MxString() +{ + // Set string to one char in length and set that char to null terminator + this->m_data = new char[1]; + this->m_data[0] = 0; + this->m_length = 0; +} + +// FUNCTION: LEGO1 0x100ae2a0 +// FUNCTION: BETA10 0x1012c1a1 +MxString::MxString(const MxString& p_str) +{ + this->m_length = p_str.m_length; + this->m_data = new char[this->m_length + 1]; + strcpy(this->m_data, p_str.m_data); +} + +// FUNCTION: LEGO1 0x100ae350 +// FUNCTION: BETA10 0x1012c24f +MxString::MxString(const char* p_str) +{ + if (p_str) { + this->m_length = strlen(p_str); + this->m_data = new char[this->m_length + 1]; + strcpy(this->m_data, p_str); + } + else { + this->m_data = new char[1]; + this->m_data[0] = 0; + this->m_length = 0; + } +} + +// FUNCTION: BETA10 0x1012c330 +MxString::MxString(const char* p_str, MxU16 p_maxlen) +{ + if (p_str) { + if (strlen(p_str) <= p_maxlen) { + this->m_length = strlen(p_str); + } + else { + this->m_length = p_maxlen; + } + + // Basically strncpy + this->m_data = new char[this->m_length + 1]; + memcpy(this->m_data, p_str, this->m_length); + this->m_data[this->m_length] = '\0'; + } + else { + this->m_data = new char[1]; + this->m_data[0] = 0; + this->m_length = 0; + } +} + +// FUNCTION: LEGO1 0x100ae420 +// FUNCTION: BETA10 0x1012c45b +MxString::~MxString() +{ + delete[] this->m_data; +} + +// FUNCTION: BETA10 0x1012c4de +void MxString::Reverse() +{ + char* start = this->m_data; + char* end = this->m_data + this->m_length - 1; + + while (start < end) { + CharSwap(start, end); + start++; + end--; + } +} + +// FUNCTION: LEGO1 0x100ae490 +// FUNCTION: BETA10 0x1012c537 +void MxString::ToUpperCase() +{ + strupr(this->m_data); +} + +// FUNCTION: LEGO1 0x100ae4a0 +// FUNCTION: BETA10 0x1012c55c +void MxString::ToLowerCase() +{ + strlwr(this->m_data); +} + +// FUNCTION: LEGO1 0x100ae4b0 +// FUNCTION: BETA10 0x1012c581 +MxString& MxString::operator=(const MxString& p_str) +{ + if (this->m_data != p_str.m_data) { + delete[] this->m_data; + this->m_length = p_str.m_length; + this->m_data = new char[this->m_length + 1]; + strcpy(this->m_data, p_str.m_data); + } + + return *this; +} + +// FUNCTION: LEGO1 0x100ae510 +// FUNCTION: BETA10 0x1012c606 +const MxString& MxString::operator=(const char* p_str) +{ + if (this->m_data != p_str) { + delete[] this->m_data; + this->m_length = strlen(p_str); + this->m_data = new char[this->m_length + 1]; + strcpy(this->m_data, p_str); + } + + return *this; +} + +// FUNCTION: BETA10 0x1012c68a +MxString MxString::operator+(const MxString& p_str) const +{ + MxString tmp; + delete[] tmp.m_data; + + tmp.m_length = p_str.m_length + this->m_length; + tmp.m_data = new char[tmp.m_length + 1]; + + strcpy(tmp.m_data, this->m_data); + strcpy(tmp.m_data + this->m_length, p_str.m_data); + + return MxString(tmp); +} + +// Return type is intentionally just MxString, not MxString&. +// This forces MSVC to add $ReturnUdt$ to the stack for 100% match. +// FUNCTION: LEGO1 0x100ae580 +// FUNCTION: BETA10 0x1012c78d +MxString MxString::operator+(const char* p_str) const +{ + // MxString constructor allocates 1 byte for m_data, so free that first + MxString tmp; + delete[] tmp.m_data; + + tmp.m_length = strlen(p_str) + this->m_length; + tmp.m_data = new char[tmp.m_length + 1]; + + strcpy(tmp.m_data, this->m_data); + strcpy(tmp.m_data + this->m_length, p_str); + + return MxString(tmp); +} + +// FUNCTION: LEGO1 0x100ae690 +// FUNCTION: BETA10 0x1012c92f +MxString& MxString::operator+=(const char* p_str) +{ + int newlen = this->m_length + strlen(p_str); + + char* tmp = new char[newlen + 1]; + strcpy(tmp, this->m_data); + strcpy(tmp + this->m_length, p_str); + + delete[] this->m_data; + this->m_data = tmp; + this->m_length = newlen; + + return *this; +} + +// FUNCTION: BETA10 0x1012ca10 +void MxString::CharSwap(char* p_a, char* p_b) +{ + char t = *p_a; + *p_a = *p_b; + *p_b = t; +} diff --git a/LEGO1/omni/src/common/mxticklemanager.cpp b/LEGO1/omni/src/common/mxticklemanager.cpp new file mode 100644 index 00000000..59fae3f3 --- /dev/null +++ b/LEGO1/omni/src/common/mxticklemanager.cpp @@ -0,0 +1,115 @@ +#include "mxticklemanager.h" + +#include "decomp.h" +#include "mxmisc.h" +#include "mxtimer.h" +#include "mxtypes.h" + +#define TICKLE_MANAGER_FLAG_DESTROY 0x01 + +DECOMP_SIZE_ASSERT(MxTickleClient, 0x10); +DECOMP_SIZE_ASSERT(MxTickleManager, 0x14); + +// FUNCTION: LEGO1 0x100bdd10 +MxTickleClient::MxTickleClient(MxCore* p_client, MxTime p_interval) +{ + m_flags = 0; + m_client = p_client; + m_interval = p_interval; + m_lastUpdateTime = -m_interval; +} + +// FUNCTION: LEGO1 0x100bdd30 +MxTickleManager::~MxTickleManager() +{ + while (m_clients.size() != 0) { + MxTickleClient* client = m_clients.front(); + m_clients.pop_front(); + delete client; + } +} + +// FUNCTION: LEGO1 0x100bdde0 +MxResult MxTickleManager::Tickle() +{ + MxTime time = Timer()->GetTime(); + MxTickleClientPtrList::iterator it; + + for (it = m_clients.begin(); !(it == m_clients.end());) { + MxTickleClient* client = *it; + + if ((MxBool) client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) { + m_clients.erase(it++); + delete client; + } + else { + it++; + + if (client->GetLastUpdateTime() > time) { + client->SetLastUpdateTime(-client->GetTickleInterval()); + } + + if ((client->GetTickleInterval() + client->GetLastUpdateTime()) < time) { + client->GetClient()->Tickle(); + client->SetLastUpdateTime(time); + } + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100bde80 +void MxTickleManager::RegisterClient(MxCore* p_client, MxTime p_interval) +{ + MxTime interval = GetClientTickleInterval(p_client); + if (interval == TICKLE_MANAGER_NOT_FOUND) { + MxTickleClient* client = new MxTickleClient(p_client, p_interval); + if (client != NULL) { + m_clients.push_back(client); + } + } +} + +// FUNCTION: LEGO1 0x100bdf60 +void MxTickleManager::UnregisterClient(MxCore* p_client) +{ + MxTickleClientPtrList::iterator it = m_clients.begin(); + while (it != m_clients.end()) { + MxTickleClient* client = *it; + if (client->GetClient() == p_client) { + client->SetFlags(client->GetFlags() | TICKLE_MANAGER_FLAG_DESTROY); + return; + } + + it++; + } +} + +// FUNCTION: LEGO1 0x100bdfa0 +void MxTickleManager::SetClientTickleInterval(MxCore* p_client, MxTime p_interval) +{ + for (MxTickleClientPtrList::iterator it = m_clients.begin(); it != m_clients.end(); it++) { + MxTickleClient* client = *it; + if ((client->GetClient() == p_client) && ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0)) { + client->SetTickleInterval(p_interval); + return; + } + } +} + +// FUNCTION: LEGO1 0x100be000 +MxTime MxTickleManager::GetClientTickleInterval(MxCore* p_client) +{ + MxTickleClientPtrList::iterator it = m_clients.begin(); + while (it != m_clients.end()) { + MxTickleClient* client = *it; + if ((client->GetClient() == p_client) && ((client->GetFlags() & TICKLE_MANAGER_FLAG_DESTROY) == 0)) { + return client->GetTickleInterval(); + } + + it++; + } + + return TICKLE_MANAGER_NOT_FOUND; +} diff --git a/LEGO1/omni/src/common/mxtimer.cpp b/LEGO1/omni/src/common/mxtimer.cpp new file mode 100644 index 00000000..0d6d00f1 --- /dev/null +++ b/LEGO1/omni/src/common/mxtimer.cpp @@ -0,0 +1,42 @@ +#include "mxtimer.h" + +#include + +// GLOBAL: LEGO1 0x10101414 +MxLong MxTimer::g_lastTimeCalculated = 0; + +// GLOBAL: LEGO1 0x10101418 +MxLong MxTimer::g_lastTimeTimerStarted = 0; + +// FUNCTION: LEGO1 0x100ae060 +MxTimer::MxTimer() +{ + this->m_isRunning = FALSE; + m_startTime = timeGetTime(); + // yeah this is somehow what the asm is + g_lastTimeCalculated = m_startTime; +} + +// FUNCTION: LEGO1 0x100ae140 +MxLong MxTimer::GetRealTime() +{ + MxTimer::g_lastTimeCalculated = timeGetTime(); + return MxTimer::g_lastTimeCalculated - this->m_startTime; +} + +// FUNCTION: LEGO1 0x100ae160 +void MxTimer::Start() +{ + g_lastTimeTimerStarted = this->GetRealTime(); + this->m_isRunning = TRUE; +} + +// FUNCTION: LEGO1 0x100ae180 +void MxTimer::Stop() +{ + MxLong elapsed = this->GetRealTime(); + MxLong startTime = elapsed - MxTimer::g_lastTimeTimerStarted; + this->m_isRunning = FALSE; + // this feels very stupid but it's what the assembly does + this->m_startTime = this->m_startTime + startTime - 5; +} diff --git a/LEGO1/omni/src/common/mxutilities.cpp b/LEGO1/omni/src/common/mxutilities.cpp new file mode 100644 index 00000000..fe45327e --- /dev/null +++ b/LEGO1/omni/src/common/mxutilities.cpp @@ -0,0 +1,196 @@ +#include "mxutilities.h" + +#include "mxcompositepresenter.h" +#include "mxdsaction.h" +#include "mxdsactionlist.h" +#include "mxdsfile.h" +#include "mxdsmultiaction.h" +#include "mxdsobject.h" +#include "mxpresenterlist.h" +#include "mxrect32.h" + +#include + +// GLOBAL: LEGO1 0x101020e8 +void (*g_omniUserMessage)(const char*, int) = NULL; + +// FUNCTION: LEGO1 0x100b6e10 +MxBool GetRectIntersection( + MxS32 p_rect1Width, + MxS32 p_rect1Height, + MxS32 p_rect2Width, + MxS32 p_rect2Height, + MxS32* p_rect1Left, + MxS32* p_rect1Top, + MxS32* p_rect2Left, + MxS32* p_rect2Top, + MxS32* p_width, + MxS32* p_height +) +{ + MxPoint32 rect1Origin(*p_rect1Left, *p_rect1Top); + MxRect32 rect1(MxPoint32(0, 0), MxSize32(p_rect1Width, p_rect1Height)); + + MxPoint32 rect2Origin(*p_rect2Left, *p_rect2Top); + MxRect32 rect2(MxPoint32(0, 0), MxSize32(p_rect2Width, p_rect2Height)); + + MxRect32 rect(0, 0, *p_width, *p_height); + rect.AddPoint(rect1Origin); + + if (!rect.IntersectsWith(rect1)) { + return FALSE; + } + + rect.Intersect(rect1); + rect.SubtractPoint(rect1Origin); + rect.AddPoint(rect2Origin); + + if (!rect.IntersectsWith(rect2)) { + return FALSE; + } + + rect.Intersect(rect2); + rect.SubtractPoint(rect2Origin); + + *p_rect1Left += rect.GetLeft(); + *p_rect1Top += rect.GetTop(); + *p_rect2Left += rect.GetLeft(); + *p_rect2Top += rect.GetTop(); + *p_width = rect.GetWidth(); + *p_height = rect.GetHeight(); + return TRUE; +} + +// FUNCTION: LEGO1 0x100b6ff0 +void MakeSourceName(char* p_output, const char* p_input) +{ + const char* cln = strchr(p_input, ':'); + if (cln) { + p_input = cln + 1; + } + + strcpy(p_output, p_input); + + strlwr(p_output); + + char* extLoc = strstr(p_output, ".si"); + if (extLoc) { + *extLoc = 0; + } +} + +// FUNCTION: LEGO1 0x100b7050 +MxBool KeyValueStringParse(char* p_output, const char* p_command, const char* p_string) +{ + MxBool didMatch = FALSE; + assert(p_string); + assert(p_command); + + MxS16 len = strlen(p_string); + char* string = new char[len + 1]; + assert(string); + strcpy(string, p_string); + + for (char* token = strtok(string, ", \t\r\n:"); token; token = strtok(NULL, ", \t\r\n:")) { + len -= (strlen(token) + 1); + + if (strcmpi(token, p_command) == 0) { + if (p_output && len > 0) { + char* output = p_output; + char* cur = &token[strlen(p_command)]; + cur++; + while (*cur != ',' && *cur != ' ' && *cur != '\0' && *cur != '\t' && *cur != '\n' && *cur != '\r') { + *output++ = *cur++; + } + *output = '\0'; + } + + didMatch = TRUE; + break; + } + } + + delete[] string; + return didMatch; +} + +// FUNCTION: LEGO1 0x100b7170 +MxBool ContainsPresenter(MxCompositePresenterList& p_presenterList, MxPresenter* p_presenter) +{ + for (MxCompositePresenterList::iterator it = p_presenterList.begin(); it != p_presenterList.end(); it++) { + if (p_presenter == *it || ((*it)->IsA("MxCompositePresenter") && + ContainsPresenter(*((MxCompositePresenter*) *it)->GetList(), p_presenter))) { + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x100b71e0 +void OmniError(const char* p_message, MxS32 p_status) +{ + if (g_omniUserMessage) { + g_omniUserMessage(p_message, p_status); + } + else if (p_status) { + abort(); + } +} + +// FUNCTION: LEGO1 0x100b7210 +void SetOmniUserMessage(void (*p_omniUserMessage)(const char*, MxS32)) +{ + g_omniUserMessage = p_omniUserMessage; +} + +// FUNCTION: LEGO1 0x100b7220 +void FUN_100b7220(MxDSAction* p_action, MxU32 p_newFlags, MxBool p_setFlags) +{ + p_action->SetFlags(!p_setFlags ? p_action->GetFlags() & ~p_newFlags : p_action->GetFlags() | p_newFlags); + + if (p_action->IsA("MxDSMultiAction")) { + MxDSActionListCursor cursor(((MxDSMultiAction*) p_action)->GetActionList()); + MxDSAction* action; + + while (cursor.Next(action)) { + FUN_100b7220(action, p_newFlags, p_setFlags); + } + } +} + +// Should probably be somewhere else +// FUNCTION: LEGO1 0x100c0280 +MxDSObject* CreateStreamObject(MxDSFile* p_file, MxS16 p_ofs) +{ + MxU8* buf; + _MMCKINFO tmpChunk; + + if (p_file->Seek(((MxLong*) p_file->GetBuffer())[p_ofs], 0)) { + return NULL; + } + + if (p_file->Read((MxU8*) &tmpChunk.ckid, 8) == 0 && tmpChunk.ckid == FOURCC('M', 'x', 'S', 't')) { + if (p_file->Read((MxU8*) &tmpChunk.ckid, 8) == 0 && tmpChunk.ckid == FOURCC('M', 'x', 'O', 'b')) { + + buf = new MxU8[tmpChunk.cksize]; + if (!buf) { + return NULL; + } + + if (p_file->Read(buf, tmpChunk.cksize) != 0) { + return NULL; + } + + // Save a copy so we can clean up properly, because + // this function will alter the pointer value. + MxU8* copy = buf; + MxDSObject* obj = DeserializeDSObjectDispatch(buf, -1); + delete[] copy; + return obj; + } + return NULL; + } + + return NULL; +} diff --git a/LEGO1/omni/src/common/mxvariable.cpp b/LEGO1/omni/src/common/mxvariable.cpp new file mode 100644 index 00000000..7b0a46c1 --- /dev/null +++ b/LEGO1/omni/src/common/mxvariable.cpp @@ -0,0 +1,6 @@ +#include "mxvariable.h" + +#include "decomp.h" +#include "mxstring.h" + +DECOMP_SIZE_ASSERT(MxVariable, 0x24) diff --git a/LEGO1/omni/src/common/mxvariabletable.cpp b/LEGO1/omni/src/common/mxvariabletable.cpp new file mode 100644 index 00000000..6e76ddc4 --- /dev/null +++ b/LEGO1/omni/src/common/mxvariabletable.cpp @@ -0,0 +1,73 @@ +#include "mxvariabletable.h" + +// FUNCTION: LEGO1 0x100b7330 +// FUNCTION: BETA10 0x1012a470 +MxS8 MxVariableTable::Compare(MxVariable* p_var0, MxVariable* p_var1) +{ + return p_var0->GetKey()->Compare(*p_var1->GetKey()); +} + +// FUNCTION: LEGO1 0x100b7370 +// FUNCTION: BETA10 0x1012a4a0 +MxU32 MxVariableTable::Hash(MxVariable* p_var) +{ + const char* str = p_var->GetKey()->GetData(); + MxU32 value = 0; + + for (MxS32 i = 0; str[i]; i++) { + value += str[i]; + } + + return value; +} + +// FUNCTION: LEGO1 0x100b73a0 +// FUNCTION: BETA10 0x1012a507 +void MxVariableTable::SetVariable(const char* p_key, const char* p_value) +{ + MxHashTableCursor cursor(this); + MxVariable* var = new MxVariable(p_key, p_value); + + if (cursor.Find(var)) { + delete var; + cursor.Current(var); + var->SetValue(p_value); + } + else { + MxHashTable::Add(var); + } +} + +// FUNCTION: LEGO1 0x100b7740 +// FUNCTION: BETA10 0x1012a629 +void MxVariableTable::SetVariable(MxVariable* p_var) +{ + MxHashTableCursor cursor(this); + + if (cursor.Find(p_var)) { + cursor.DeleteMatch(); + } + + MxHashTable::Add(p_var); +} + +// FUNCTION: LEGO1 0x100b78f0 +// FUNCTION: BETA10 0x1012a6bd +const char* MxVariableTable::GetVariable(const char* p_key) +{ + // STRING: ISLE 0x41008c + // STRING: LEGO1 0x100f01d4 + const char* value = ""; + MxHashTableCursor cursor(this); + MxVariable* var = new MxVariable(p_key); + + MxBool found = cursor.Find(var); + delete var; + + if (found) { + cursor.Current(var); + value = var->GetValue()->GetData(); + } + + return value; +} diff --git a/LEGO1/omni/src/entity/mxentity.cpp b/LEGO1/omni/src/entity/mxentity.cpp new file mode 100644 index 00000000..2edc65f6 --- /dev/null +++ b/LEGO1/omni/src/entity/mxentity.cpp @@ -0,0 +1,3 @@ +#include "mxentity.h" + +DECOMP_SIZE_ASSERT(MxEntity, 0x10) diff --git a/LEGO1/omni/src/event/mxeventmanager.cpp b/LEGO1/omni/src/event/mxeventmanager.cpp new file mode 100644 index 00000000..7e269ce6 --- /dev/null +++ b/LEGO1/omni/src/event/mxeventmanager.cpp @@ -0,0 +1,82 @@ +#include "mxeventmanager.h" + +#include "mxcriticalsection.h" +#include "mxmisc.h" +#include "mxthread.h" +#include "mxticklemanager.h" + +// FUNCTION: LEGO1 0x100c0360 +MxEventManager::MxEventManager() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100c03f0 +MxEventManager::~MxEventManager() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100c0450 +void MxEventManager::Init() +{ + // This is intentionally left blank +} + +// FUNCTION: LEGO1 0x100c0460 +void MxEventManager::Destroy(MxBool p_fromDestructor) +{ + if (m_thread != NULL) { + m_thread->Terminate(); + delete m_thread; + } + else { + TickleManager()->UnregisterClient(this); + } + + if (!p_fromDestructor) { + MxMediaManager::Destroy(); + } +} + +// FUNCTION: LEGO1 0x100c04a0 +MxResult MxEventManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) +{ + MxResult status = FAILURE; + MxBool locked = FALSE; + + MxResult result = MxMediaManager::InitPresenters(); + if (result == SUCCESS) { + if (p_createThread) { + this->m_criticalSection.Enter(); + locked = TRUE; + this->m_thread = new MxTickleThread(this, p_frequencyMS); + + if (!this->m_thread || this->m_thread->Start(0, 0) != SUCCESS) { + goto done; + } + } + else { + TickleManager()->RegisterClient(this, p_frequencyMS); + } + + status = SUCCESS; + } + +done: + if (status != SUCCESS) { + Destroy(); + } + + if (locked) { + this->m_criticalSection.Leave(); + } + + return status; +} + +// FUNCTION: LEGO1 0x100c0590 +void MxEventManager::Destroy() +{ + Destroy(FALSE); +} diff --git a/LEGO1/omni/src/event/mxeventpresenter.cpp b/LEGO1/omni/src/event/mxeventpresenter.cpp new file mode 100644 index 00000000..05c94de0 --- /dev/null +++ b/LEGO1/omni/src/event/mxeventpresenter.cpp @@ -0,0 +1,120 @@ +#include "mxeventpresenter.h" + +#include "decomp.h" +#include "mxautolock.h" +#include "mxdsaction.h" +#include "mxdssubscriber.h" +#include "mxeventmanager.h" +#include "mxmisc.h" +#include "mxvariabletable.h" + +DECOMP_SIZE_ASSERT(MxEventPresenter, 0x54); + +// FUNCTION: LEGO1 0x100c2b70 +MxEventPresenter::MxEventPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100c2d40 +MxEventPresenter::~MxEventPresenter() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100c2da0 +void MxEventPresenter::Init() +{ + m_data = NULL; +} + +// FUNCTION: LEGO1 0x100c2db0 +MxResult MxEventPresenter::AddToManager() +{ + MxResult ret = FAILURE; + + if (EventManager()) { + ret = SUCCESS; + EventManager()->RegisterPresenter(*this); + } + + return ret; +} + +// FUNCTION: LEGO1 0x100c2de0 +void MxEventPresenter::Destroy() +{ + if (EventManager()) { + EventManager()->UnregisterPresenter(*this); + } + + m_criticalSection.Enter(); + + if (m_data) { + delete[] m_data; + } + + Init(); + + m_criticalSection.Leave(); +} + +// FUNCTION: LEGO1 0x100c2e30 +void MxEventPresenter::CopyData(MxStreamChunk* p_chunk) +{ + m_data = new MxU8[p_chunk->GetLength()]; + memcpy(m_data, p_chunk->GetData(), p_chunk->GetLength()); +} + +// FUNCTION: LEGO1 0x100c2e70 +void MxEventPresenter::ReadyTickle() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk) { + CopyData(chunk); + m_subscriber->FreeDataChunk(chunk); + ParseExtra(); + ProgressTickleState(e_starting); + } +} + +// FUNCTION: LEGO1 0x100c2eb0 +void MxEventPresenter::StartingTickle() +{ + MxStreamChunk* chunk = CurrentChunk(); + + if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) { + ProgressTickleState(e_streaming); + } +} + +// FUNCTION: LEGO1 0x100c2ef0 +MxResult MxEventPresenter::PutData() +{ + AUTOLOCK(m_criticalSection); + + if (IsEnabled()) { + if (m_currentTickleState >= e_streaming && + (m_currentTickleState <= e_repeating || m_currentTickleState == e_done)) { + if (m_currentChunk && m_currentChunk->GetLength()) { + if (m_data[12] == 2) { + const char* data = (const char*) m_currentChunk->GetData(); + MxVariableTable* variableTable = VariableTable(); + + const char* key = data; + const char* value = &data[strlen(data) + 1]; + strlen(value); + variableTable->SetVariable(key, value); + } + + if (m_currentTickleState == e_streaming) { + m_subscriber->FreeDataChunk(m_currentChunk); + } + m_currentChunk = NULL; + } + } + } + + return SUCCESS; +} diff --git a/LEGO1/omni/src/main/mxomni.cpp b/LEGO1/omni/src/main/mxomni.cpp new file mode 100644 index 00000000..29196431 --- /dev/null +++ b/LEGO1/omni/src/main/mxomni.cpp @@ -0,0 +1,429 @@ +#include "mxomni.h" + +#include "mxactionnotificationparam.h" +#include "mxatom.h" +#include "mxautolock.h" +#include "mxdsmultiaction.h" +#include "mxeventmanager.h" +#include "mxmisc.h" +#include "mxmusicmanager.h" +#include "mxnotificationmanager.h" +#include "mxobjectfactory.h" +#include "mxomnicreateparam.h" +#include "mxpresenter.h" +#include "mxsoundmanager.h" +#include "mxstreamer.h" +#include "mxticklemanager.h" +#include "mxtimer.h" +#include "mxvariabletable.h" +#include "mxvideomanager.h" + +// GLOBAL: LEGO1 0x101015b8 +char g_hdPath[1024] = ""; + +// GLOBAL: LEGO1 0x101019b8 +char g_cdPath[1024] = "E:"; + +// GLOBAL: LEGO1 0x10101db8 +MxBool g_use3dSound = FALSE; + +// GLOBAL: LEGO1 0x101015b0 +MxOmni* MxOmni::g_instance = NULL; + +// FUNCTION: LEGO1 0x100aef10 +MxOmni::MxOmni() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100aefb0 +MxEntity* MxOmni::AddToWorld(const char*, MxS32, MxPresenter*) +{ + return NULL; +} + +// FUNCTION: LEGO1 0x100aefc0 +void MxOmni::NotifyCurrentEntity(const MxNotificationParam& p_param) +{ +} + +// FUNCTION: LEGO1 0x100aeff0 +MxOmni::~MxOmni() +{ + Destroy(); +} + +// FUNCTION: LEGO1 0x100af080 +void MxOmni::Init() +{ + m_windowHandle = NULL; + m_objectFactory = NULL; + m_variableTable = NULL; + m_tickleManager = NULL; + m_notificationManager = NULL; + m_videoManager = NULL; + m_soundManager = NULL; + m_musicManager = NULL; + m_eventManager = NULL; + m_timer = NULL; + m_streamer = NULL; + m_atomSet = NULL; + m_timerRunning = FALSE; +} + +// FUNCTION: LEGO1 0x100af0b0 +void MxOmni::SetInstance(MxOmni* p_instance) +{ + g_instance = p_instance; +} + +// FUNCTION: LEGO1 0x100af0c0 +// FUNCTION: BETA10 0x1012f3ff +MxResult MxOmni::Create(MxOmniCreateParam& p_param) +{ + MxResult result = FAILURE; + + if (!(m_atomSet = new MxAtomSet())) { + goto done; + } + + m_mediaPath = p_param.GetMediaPath(); + m_windowHandle = p_param.GetWindowHandle(); + + if (p_param.CreateFlags().CreateObjectFactory()) { + if (!(m_objectFactory = new MxObjectFactory())) { + goto done; + } + } + + if (p_param.CreateFlags().CreateVariableTable()) { + if (!(m_variableTable = new MxVariableTable())) { + goto done; + } + } + + if (p_param.CreateFlags().CreateTimer()) { + if (!(m_timer = new MxTimer())) { + goto done; + } + } + + if (p_param.CreateFlags().CreateTickleManager()) { + if (!(m_tickleManager = new MxTickleManager())) { + goto done; + } + } + + if (p_param.CreateFlags().CreateNotificationManager()) { + if ((m_notificationManager = new MxNotificationManager())) { + if (m_notificationManager->Create(100, 0) != SUCCESS) { + goto done; + } + } + else { + goto done; + } + } + + if (p_param.CreateFlags().CreateStreamer()) { + if (!(m_streamer = new MxStreamer()) || m_streamer->Create() != SUCCESS) { + goto done; + } + } + + if (p_param.CreateFlags().CreateVideoManager()) { + if ((m_videoManager = new MxVideoManager())) { + if (m_videoManager->Create(p_param.GetVideoParam(), 100, 0) != SUCCESS) { + delete m_videoManager; + m_videoManager = NULL; + } + } + } + + if (p_param.CreateFlags().CreateSoundManager()) { + if ((m_soundManager = new MxSoundManager())) { + if (m_soundManager->Create(10, 0) != SUCCESS) { + delete m_soundManager; + m_soundManager = NULL; + } + } + } + + if (p_param.CreateFlags().CreateMusicManager()) { + if ((m_musicManager = new MxMusicManager())) { + if (m_musicManager->Create(50, 0) != SUCCESS) { + delete m_musicManager; + m_musicManager = NULL; + } + } + } + + if (p_param.CreateFlags().CreateEventManager()) { + if ((m_eventManager = new MxEventManager())) { + if (m_eventManager->Create(50, 0) != SUCCESS) { + delete m_eventManager; + m_eventManager = NULL; + } + } + } + + result = SUCCESS; + +done: + if (result != SUCCESS) { + Destroy(); + } + + return result; +} + +// FUNCTION: LEGO1 0x100afe90 +// FUNCTION: BETA10 0x1012fe5b +void MxOmni::Destroy() +{ + { + MxDSAction action; + action.SetObjectId(-1); + action.SetUnknown24(-2); + DeleteObject(action); + } + + if (m_notificationManager) { + while (!m_notificationManager->IsEmpty()) { + m_notificationManager->Tickle(); + } + + m_notificationManager->SetActive(FALSE); + } + + delete m_eventManager; + delete m_soundManager; + delete m_musicManager; + delete m_videoManager; + delete m_streamer; + delete m_timer; + delete m_objectFactory; + delete m_variableTable; + delete m_notificationManager; + delete m_tickleManager; + + if (m_atomSet) { + while (m_atomSet->size() != 0) { + // Pop each node and delete its value + MxAtomSet::iterator begin = m_atomSet->begin(); + MxAtom* value = *begin; + m_atomSet->erase(begin); + delete value; + } + + delete m_atomSet; + } + + Init(); +} + +// FUNCTION: LEGO1 0x100b0090 +MxResult MxOmni::Start(MxDSAction* p_dsAction) +{ + MxResult result = FAILURE; + if (p_dsAction->GetAtomId().GetInternal() != NULL && p_dsAction->GetObjectId() != -1 && m_streamer != NULL) { + result = m_streamer->FUN_100b99b0(p_dsAction); + } + + return result; +} + +// FUNCTION: LEGO1 0x100b00c0 +void MxOmni::DeleteObject(MxDSAction& p_dsAction) +{ + if (m_streamer != NULL) { + m_streamer->DeleteObject(&p_dsAction); + } +} + +// FUNCTION: LEGO1 0x100b00e0 +MxResult MxOmni::CreatePresenter(MxStreamController* p_controller, MxDSAction& p_action) +{ + MxResult result = FAILURE; + const char* name = PresenterNameDispatch(p_action); + MxPresenter* object = (MxPresenter*) m_objectFactory->Create(name); + + if (object) { + if (object->AddToManager() == SUCCESS) { + MxPresenter* sender = p_action.GetUnknown28(); + if (!sender) { + sender = p_controller->FUN_100c1e70(p_action); + } + + if (sender) { + p_action.SetOrigin(sender); + object->SetCompositePresenter((MxCompositePresenter*) sender); + } + else { + if (!p_action.GetOrigin()) { + p_action.SetOrigin(this); + } + object->SetCompositePresenter(NULL); + } + + if (object->StartAction(p_controller, &p_action) == SUCCESS) { + if (sender) { + NotificationManager()->Send(sender, MxType4NotificationParam(this, &p_action, object)); + } + + if (p_action.GetUnknown84()) { + NotificationManager()->Send( + p_action.GetUnknown84(), + MxStartActionNotificationParam(c_notificationStartAction, object, &p_action, FALSE) + ); + } + result = SUCCESS; + } + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100b0680 +MxOmni* MxOmni::GetInstance() +{ + return g_instance; +} + +// FUNCTION: LEGO1 0x100b0690 +void MxOmni::DestroyInstance() +{ + if (g_instance != NULL) { + delete g_instance; + g_instance = NULL; + } +} + +// FUNCTION: LEGO1 0x100b06b0 +MxBool MxOmni::ActionSourceEquals(MxDSAction* p_action, const char* p_name) +{ + if (!strcmp(p_action->GetSourceName(), p_name)) { + return TRUE; + } + + if (p_action->IsA("MxDSMultiAction")) { + MxDSActionListCursor cursor(((MxDSMultiAction*) p_action)->GetActionList()); + MxDSAction* action; + + while (cursor.Next(action)) { + if (ActionSourceEquals(action, p_name)) { + return TRUE; + } + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x100b07f0 +MxLong MxOmni::Notify(MxParam& p_param) +{ + AUTOLOCK(m_criticalSection); + + if (((MxNotificationParam&) p_param).GetNotification() != c_notificationEndAction) { + return 0; + } + + return HandleEndAction(p_param); +} + +// FUNCTION: LEGO1 0x100b0880 +MxLong MxOmni::HandleEndAction(MxParam& p_param) +{ + MxDSAction* action = ((MxEndActionNotificationParam&) p_param).GetAction(); + MxStreamController* controller = Streamer()->GetOpenStream(action->GetAtomId().GetInternal()); + + if (controller != NULL) { + action = controller->GetUnk0x54().Find(action, FALSE); + if (action) { + if (ActionSourceEquals(action, "LegoLoopingAnimPresenter") == FALSE) { + delete controller->GetUnk0x54().Find(action, TRUE); + } + } + } + + if (((MxEndActionNotificationParam&) p_param).GetSender()) { + delete ((MxEndActionNotificationParam&) p_param).GetSender(); + } + + if (((MxEndActionNotificationParam&) p_param).GetAction()) { + delete ((MxEndActionNotificationParam&) p_param).GetAction(); + } + + return 1; +} + +// FUNCTION: LEGO1 0x100b0900 +const char* MxOmni::GetHD() +{ + return g_hdPath; +} + +// FUNCTION: LEGO1 0x100b0910 +void MxOmni::SetHD(const char* p_hd) +{ + strcpy(g_hdPath, p_hd); +} + +// FUNCTION: LEGO1 0x100b0940 +const char* MxOmni::GetCD() +{ + return g_cdPath; +} + +// FUNCTION: LEGO1 0x100b0950 +void MxOmni::SetCD(const char* p_cd) +{ + strcpy(g_cdPath, p_cd); +} + +// FUNCTION: LEGO1 0x100b0980 +MxBool MxOmni::IsSound3D() +{ + return g_use3dSound; +} + +// FUNCTION: LEGO1 0x100b0990 +void MxOmni::SetSound3D(MxBool p_use3dSound) +{ + g_use3dSound = p_use3dSound; +} + +// FUNCTION: LEGO1 0x100b09a0 +MxBool MxOmni::DoesEntityExist(MxDSAction& p_dsAction) +{ + if (m_streamer->FUN_100b9b30(p_dsAction)) { + MxNotificationPtrList* queue = m_notificationManager->GetQueue(); + + if (!queue || queue->size() == 0) { + return TRUE; + } + } + return FALSE; +} + +// FUNCTION: LEGO1 0x100b09d0 +void MxOmni::StartTimer() +{ + if (m_timerRunning == FALSE && m_timer != NULL && m_soundManager != NULL) { + m_timer->Start(); + m_soundManager->Pause(); + m_timerRunning = TRUE; + } +} + +// FUNCTION: LEGO1 0x100b0a00 +void MxOmni::StopTimer() +{ + if (m_timerRunning != FALSE && m_timer != NULL && m_soundManager != NULL) { + m_timer->Stop(); + m_soundManager->Resume(); + m_timerRunning = FALSE; + } +} diff --git a/LEGO1/omni/src/main/mxomnicreateflags.cpp b/LEGO1/omni/src/main/mxomnicreateflags.cpp new file mode 100644 index 00000000..916c7bcd --- /dev/null +++ b/LEGO1/omni/src/main/mxomnicreateflags.cpp @@ -0,0 +1,22 @@ +#include "mxomnicreateflags.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxOmniCreateFlags, 0x02) + +// FUNCTION: LEGO1 0x100b0a30 +// FUNCTION: BETA10 0x10130a1c +MxOmniCreateFlags::MxOmniCreateFlags() +{ + this->m_flags1.m_bit0 = TRUE; // CreateObjectFactory + this->m_flags1.m_bit1 = TRUE; // CreateVariableTable + this->m_flags1.m_bit2 = TRUE; // CreateTickleManager + this->m_flags1.m_bit3 = TRUE; // CreateNotificationManager + this->m_flags1.m_bit4 = TRUE; // CreateVideoManager + this->m_flags1.m_bit5 = TRUE; // CreateSoundManager + this->m_flags1.m_bit6 = TRUE; // CreateMusicManager + this->m_flags1.m_bit7 = TRUE; // CreateEventManager + + this->m_flags2.m_bit1 = TRUE; // CreateTimer + this->m_flags2.m_bit2 = TRUE; // CreateStreamer +} diff --git a/LEGO1/omni/src/main/mxomnicreateparam.cpp b/LEGO1/omni/src/main/mxomnicreateparam.cpp new file mode 100644 index 00000000..7f84fbc1 --- /dev/null +++ b/LEGO1/omni/src/main/mxomnicreateparam.cpp @@ -0,0 +1,20 @@ +#include "mxomnicreateparam.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxOmniCreateParam, 0x40) + +// FUNCTION: LEGO1 0x100b0b00 +// FUNCTION: BETA10 0x10130b6b +MxOmniCreateParam::MxOmniCreateParam( + const char* p_mediaPath, + struct HWND__* p_windowHandle, + MxVideoParam& p_vparam, + MxOmniCreateFlags p_flags +) +{ + this->m_mediaPath = p_mediaPath; + this->m_windowHandle = (HWND) p_windowHandle; + this->m_videoParam = p_vparam; + this->m_createFlags = p_flags; +} diff --git a/LEGO1/omni/src/notify/mxactionnotificationparam.cpp b/LEGO1/omni/src/notify/mxactionnotificationparam.cpp new file mode 100644 index 00000000..3024268c --- /dev/null +++ b/LEGO1/omni/src/notify/mxactionnotificationparam.cpp @@ -0,0 +1,21 @@ +#include "mxactionnotificationparam.h" + +DECOMP_SIZE_ASSERT(MxActionNotificationParam, 0x14) +DECOMP_SIZE_ASSERT(MxEndActionNotificationParam, 0x14) + +// FUNCTION: LEGO1 0x100b0300 +MxNotificationParam* MxStartActionNotificationParam::Clone() const +{ + return new MxStartActionNotificationParam( + c_notificationStartAction, + this->m_sender, + this->m_action, + this->m_realloc + ); +} + +// FUNCTION: LEGO1 0x100b04f0 +MxNotificationParam* MxType4NotificationParam::Clone() const +{ + return new MxType4NotificationParam(this->m_sender, this->m_action, this->m_unk0x14); +} diff --git a/LEGO1/omni/src/notify/mxnotificationmanager.cpp b/LEGO1/omni/src/notify/mxnotificationmanager.cpp new file mode 100644 index 00000000..58c97e38 --- /dev/null +++ b/LEGO1/omni/src/notify/mxnotificationmanager.cpp @@ -0,0 +1,190 @@ +#include "mxnotificationmanager.h" + +#include "compat.h" +#include "decomp.h" +#include "mxautolock.h" +#include "mxmisc.h" +#include "mxnotificationparam.h" +#include "mxparam.h" +#include "mxticklemanager.h" +#include "mxtypes.h" + +DECOMP_SIZE_ASSERT(MxNotification, 0x08); +DECOMP_SIZE_ASSERT(MxNotificationManager, 0x40); + +// FUNCTION: LEGO1 0x100ac220 +MxNotification::MxNotification(MxCore* p_target, const MxNotificationParam& p_param) +{ + m_target = p_target; + m_param = p_param.Clone(); +} + +// FUNCTION: LEGO1 0x100ac240 +MxNotification::~MxNotification() +{ + delete m_param; +} + +// FUNCTION: LEGO1 0x100ac250 +// FUNCTION: BETA10 0x10125805 +MxNotificationManager::MxNotificationManager() : MxCore(), m_lock(), m_listenerIds() +{ + m_unk0x2c = 0; + m_queue = NULL; + m_active = TRUE; + m_sendList = NULL; +} + +// FUNCTION: LEGO1 0x100ac450 +MxNotificationManager::~MxNotificationManager() +{ + AUTOLOCK(m_lock); + Tickle(); + delete m_queue; + m_queue = NULL; + + TickleManager()->UnregisterClient(this); +} + +// FUNCTION: LEGO1 0x100ac600 +MxResult MxNotificationManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) +{ + MxResult result = SUCCESS; + m_queue = new MxNotificationPtrList(); + + if (m_queue == NULL) { + result = FAILURE; + } + else { + TickleManager()->RegisterClient(this, 10); + } + + return result; +} + +// FUNCTION: LEGO1 0x100ac6c0 +MxResult MxNotificationManager::Send(MxCore* p_listener, const MxNotificationParam& p_param) +{ + AUTOLOCK(m_lock); + + if (!m_active) { + return FAILURE; + } + + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + if (it == m_listenerIds.end()) { + return FAILURE; + } + + MxNotification* notif = new MxNotification(p_listener, p_param); + if (notif != NULL) { + m_queue->push_back(notif); + return SUCCESS; + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x100ac800 +MxResult MxNotificationManager::Tickle() +{ + m_sendList = new MxNotificationPtrList(); + if (m_sendList == NULL) { + return FAILURE; + } + else { + { + AUTOLOCK(m_lock); + MxNotificationPtrList* temp1 = m_queue; + MxNotificationPtrList* temp2 = m_sendList; + m_queue = temp2; + m_sendList = temp1; + } + + while (m_sendList->size() != 0) { + MxNotification* notif = m_sendList->front(); + m_sendList->pop_front(); + notif->GetTarget()->Notify(*notif->GetParam()); + delete notif; + } + + delete m_sendList; + m_sendList = NULL; + return SUCCESS; + } +} + +// FUNCTION: LEGO1 0x100ac990 +void MxNotificationManager::FlushPending(MxCore* p_listener) +{ + MxNotificationPtrList pending; + MxNotification* notif; + + { + AUTOLOCK(m_lock); + + // Find all notifications from, and addressed to, p_listener. + if (m_sendList != NULL) { + MxNotificationPtrList::iterator it = m_sendList->begin(); + while (it != m_sendList->end()) { + notif = *it; + if (notif->GetTarget()->GetId() == p_listener->GetId() || + (notif->GetParam()->GetSender() && notif->GetParam()->GetSender()->GetId() == p_listener->GetId() + )) { + m_sendList->erase(it++); + pending.push_back(notif); + } + else { + it++; + } + } + } + + MxNotificationPtrList::iterator it = m_queue->begin(); + while (it != m_queue->end()) { + notif = *it; + if (notif->GetTarget()->GetId() == p_listener->GetId() || + (notif->GetParam()->GetSender() && notif->GetParam()->GetSender()->GetId() == p_listener->GetId())) { + m_queue->erase(it++); + pending.push_back(notif); + } + else { + it++; + } + } + } + + // Deliver those notifications. + while (pending.size() != 0) { + notif = pending.front(); + pending.pop_front(); + notif->GetTarget()->Notify(*notif->GetParam()); + delete notif; + } +} + +// FUNCTION: LEGO1 0x100acd20 +void MxNotificationManager::Register(MxCore* p_listener) +{ + AUTOLOCK(m_lock); + + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + if (it != m_listenerIds.end()) { + return; + } + + m_listenerIds.push_back(p_listener->GetId()); +} + +// FUNCTION: LEGO1 0x100acdf0 +void MxNotificationManager::Unregister(MxCore* p_listener) +{ + AUTOLOCK(m_lock); + + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + + if (it != m_listenerIds.end()) { + m_listenerIds.erase(it); + FlushPending(p_listener); + } +} diff --git a/LEGO1/omni/src/notify/mxnotificationparam.cpp b/LEGO1/omni/src/notify/mxnotificationparam.cpp new file mode 100644 index 00000000..cf5bf8b9 --- /dev/null +++ b/LEGO1/omni/src/notify/mxnotificationparam.cpp @@ -0,0 +1,5 @@ +#include "mxnotificationparam.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxNotificationParam, 0x0c); diff --git a/LEGO1/omni/src/stream/mxdiskstreamcontroller.cpp b/LEGO1/omni/src/stream/mxdiskstreamcontroller.cpp new file mode 100644 index 00000000..c90e377c --- /dev/null +++ b/LEGO1/omni/src/stream/mxdiskstreamcontroller.cpp @@ -0,0 +1,464 @@ +#include "mxdiskstreamcontroller.h" + +#include "mxactionnotificationparam.h" +#include "mxautolock.h" +#include "mxdiskstreamprovider.h" +#include "mxdsstreamingaction.h" +#include "mxmisc.h" +#include "mxomni.h" +#include "mxticklemanager.h" + +DECOMP_SIZE_ASSERT(MxDiskStreamController, 0xc8); + +// FUNCTION: LEGO1 0x100c7120 +MxDiskStreamController::MxDiskStreamController() +{ + m_unk0x8c = 0; +} + +// FUNCTION: LEGO1 0x100c7530 +MxDiskStreamController::~MxDiskStreamController() +{ + AUTOLOCK(m_criticalSection); + + m_unk0xc4 = FALSE; + m_unk0x70 = FALSE; + + if (m_provider) { +#ifdef COMPAT_MODE + { + MxDSAction action; + m_provider->VTable0x20(&action); + } +#else + m_provider->VTable0x20(&MxDSAction()); +#endif + } + + MxDSAction* action; + while (m_unk0x3c.PopFront(action)) { + delete action; + } + + if (m_provider) { + delete m_provider; + m_provider = NULL; + } + + FUN_100c8720(); + + while (m_list0x80.PopFront(action)) { + FUN_100c7cb0((MxDSStreamingAction*) action); + } + + while (m_list0x64.PopFront(action)) { + FUN_100c7cb0((MxDSStreamingAction*) action); + } + + while (!m_list0x74.empty()) { + MxDSBuffer* buffer = m_list0x74.front(); + m_list0x74.pop_front(); + FUN_100c7ce0(buffer); + } + + TickleManager()->UnregisterClient(this); +} + +// FUNCTION: LEGO1 0x100c7790 +MxResult MxDiskStreamController::Open(const char* p_filename) +{ + AUTOLOCK(m_criticalSection); + MxResult result = MxStreamController::Open(p_filename); + + if (result == SUCCESS) { + m_provider = new MxDiskStreamProvider(); + if (m_provider == NULL) { + result = FAILURE; + } + else { + result = m_provider->SetResourceToGet(this); + if (result != SUCCESS) { + delete m_provider; + m_provider = NULL; + } + else { + TickleManager()->RegisterClient(this, 10); + } + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100c7880 +MxResult MxDiskStreamController::VTable0x18(undefined4, undefined4) +{ + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c7890 +MxResult MxDiskStreamController::FUN_100c7890(MxDSStreamingAction* p_action) +{ + AUTOLOCK(m_criticalSection); + if (p_action == NULL) { + return FAILURE; + } + + m_list0x80.push_back(p_action); + FUN_100c7970(); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c7960 +MxResult MxDiskStreamController::VTable0x34(undefined4) +{ + return FAILURE; +} + +// FUNCTION: LEGO1 0x100c7970 +void MxDiskStreamController::FUN_100c7970() +{ + // Empty +} + +// FUNCTION: LEGO1 0x100c7980 +void MxDiskStreamController::FUN_100c7980() +{ + MxDSBuffer* buffer; + MxDSStreamingAction* action = NULL; + + { + AUTOLOCK(m_criticalSection); + + if (m_unk0x3c.size() && m_unk0x8c < m_provider->GetStreamBuffersNum()) { + buffer = new MxDSBuffer(); + + if (buffer->AllocateBuffer(m_provider->GetFileSize(), MxDSBuffer::e_chunk) != SUCCESS) { + if (buffer) { + delete buffer; + } + return; + } + + action = VTable0x28(); + if (!action) { + if (buffer) { + delete buffer; + } + return; + } + + action->SetUnknowna0(buffer); + m_unk0x8c++; + } + } + + if (action) { + ((MxDiskStreamProvider*) m_provider)->FUN_100d1780(action); + } +} + +// FUNCTION: LEGO1 0x100c7ac0 +MxDSStreamingAction* MxDiskStreamController::VTable0x28() +{ + AUTOLOCK(m_criticalSection); + MxDSAction* oldAction; + MxDSStreamingAction* result = NULL; + MxU32 filesize = m_provider->GetFileSize(); + + if (m_unk0x3c.PopFront(oldAction)) { + result = new MxDSStreamingAction((MxDSStreamingAction&) *oldAction); + if (result) { + MxU32 offset = result->GetBufferOffset() + filesize; + ((MxDSStreamingAction*) oldAction)->SetUnknown94(offset); + ((MxDSStreamingAction*) oldAction)->SetBufferOffset(offset); + m_unk0x3c.push_back(oldAction); + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100c7c00 +MxResult MxDiskStreamController::VTable0x30(MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + MxResult result = MxStreamController::VTable0x30(p_action); + + MxDSStreamingAction* item; + while (TRUE) { + item = (MxDSStreamingAction*) m_list0x90.Find(p_action, TRUE); + if (item == NULL) { + break; + } + FUN_100c7cb0(item); + } + + while (TRUE) { + item = (MxDSStreamingAction*) m_list0x64.Find(p_action, TRUE); + if (item == NULL) { + break; + } + FUN_100c7cb0(item); + } + + return result; +} + +// FUNCTION: LEGO1 0x100c7cb0 +void MxDiskStreamController::FUN_100c7cb0(MxDSStreamingAction* p_action) +{ + if (p_action->GetUnknowna0()) { + FUN_100c7ce0(p_action->GetUnknowna0()); + } + p_action->SetUnknowna0(NULL); + delete p_action; +} + +// FUNCTION: LEGO1 0x100c7ce0 +void MxDiskStreamController::FUN_100c7ce0(MxDSBuffer* p_buffer) +{ + switch (p_buffer->GetMode()) { + case MxDSBuffer::e_chunk: + m_unk0x8c--; + case MxDSBuffer::e_allocate: + case MxDSBuffer::e_unknown: + delete p_buffer; + break; + } +} + +// FUNCTION: LEGO1 0x100c7d10 +MxResult MxDiskStreamController::FUN_100c7d10() +{ + AUTOLOCK(m_criticalSection); + MxDSStreamingAction* action = FUN_100c7db0(); + + if (!action) { + return FAILURE; + } + + if (FUN_100c8360(action) != SUCCESS) { + VTable0x24(action); + FUN_100c7cb0(action); + return FAILURE; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c7db0 +MxDSStreamingAction* MxDiskStreamController::FUN_100c7db0() +{ + AUTOLOCK(m_criticalSection); + + for (MxStreamListMxNextActionDataStart::iterator it = m_nextActionList.begin(); it != m_nextActionList.end(); + it++) { + MxNextActionDataStart* data = *it; + for (MxStreamListMxDSAction::iterator it2 = m_list0x64.begin(); it2 != m_list0x64.end(); it2++) { + MxDSStreamingAction* streamingAction = (MxDSStreamingAction*) *it2; + if (streamingAction->GetObjectId() == data->GetObjectId() && + streamingAction->GetUnknown24() == data->GetUnknown24() && + streamingAction->GetBufferOffset() == data->GetData()) { + m_nextActionList.erase(it); + + data->SetData(m_provider->GetFileSize() + data->GetData()); + m_nextActionList.push_back(data); + + m_list0x64.erase(it2); + return streamingAction; + } + } + } + return NULL; +} + +// FUNCTION: LEGO1 0x100c7f40 +void MxDiskStreamController::FUN_100c7f40(MxDSStreamingAction* p_streamingaction) +{ + AUTOLOCK(m_criticalSection); + if (p_streamingaction) { + m_list0x64.push_back(p_streamingaction); + } +} + +// FUNCTION: LEGO1 0x100c7ff0 +MxResult MxDiskStreamController::VTable0x20(MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + MxDSStreamingAction* entry = + (MxDSStreamingAction*) m_list0x80.Find(p_action, FALSE); // TODO: is this a seperate class? + if (entry) { + MxDSStreamingAction* action = new MxDSStreamingAction(*p_action, 0); + action->SetUnknown28(entry->GetUnknown28()); + action->SetUnknown84(entry->GetUnknown84()); + action->SetOrigin(entry->GetOrigin()); + action->SetUnknowna0(entry->GetUnknowna4()); + + FUN_100c7f40(action); + + if (VTable0x2c(p_action, entry->GetUnknown94()) != SUCCESS) { + return FAILURE; + } + } + else if (MxStreamController::VTable0x20(p_action) != SUCCESS) { + return FAILURE; + } + + m_unk0x70 = TRUE; + m_unk0xc4 = TRUE; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c8120 +void MxDiskStreamController::FUN_100c8120(MxDSAction* p_action) +{ + VTable0x30(p_action); + + if (m_provider) { + m_provider->VTable0x20(p_action); + } + + while (TRUE) { + MxDSAction* found = m_unk0x54.Find(p_action, TRUE); + if (!found) { + break; + } + delete found; + } +} + +// FUNCTION: LEGO1 0x100c8160 +MxResult MxDiskStreamController::VTable0x24(MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + if (m_unk0x54.Find(p_action, FALSE) == NULL) { + if (VTable0x30(p_action) == SUCCESS) { + MxOmni::GetInstance()->NotifyCurrentEntity( + MxEndActionNotificationParam(c_notificationEndAction, NULL, p_action, TRUE) + ); + } + } + + MxDSAction action; + if (m_provider) { + m_provider->VTable0x20(p_action); + } + + do { + if (m_action0x60 != NULL) { + delete m_action0x60; + m_action0x60 = NULL; + } + + action = *p_action; + MxStreamController::VTable0x24(&action); + } while (m_action0x60 != NULL); + + if (m_unk0x3c.empty()) { + m_unk0x70 = FALSE; + m_unk0xc4 = FALSE; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c8360 +MxResult MxDiskStreamController::FUN_100c8360(MxDSStreamingAction* p_action) +{ + AUTOLOCK(m_criticalSection); + MxDSBuffer* buffer = p_action->GetUnknowna0(); + MxDSStreamingAction* action2 = (MxDSStreamingAction*) m_list0x90.Find(p_action, TRUE); + buffer->FUN_100c6f80(p_action->GetUnknown94() - p_action->GetBufferOffset()); + buffer->FUN_100c67b0(this, p_action, &action2); + + if (buffer->GetRefCount()) { + p_action->SetUnknowna0(NULL); + InsertToList74(buffer); + } + + if (action2) { + if (action2->GetUnknowna0() == NULL) { + FUN_100c7cb0(action2); + } + else { + if (action2->GetObjectId() == -1) { + action2->SetObjectId(p_action->GetObjectId()); + } + + m_list0x90.push_back(action2); + } + } + + FUN_100c7cb0(p_action); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c84a0 +void MxDiskStreamController::InsertToList74(MxDSBuffer* p_buffer) +{ + AUTOLOCK(m_criticalSection); + m_list0x74.push_back(p_buffer); +} + +// FUNCTION: LEGO1 0x100c8540 +void MxDiskStreamController::FUN_100c8540() +{ + AUTOLOCK(m_criticalSection); + for (list::iterator it = m_list0x74.begin(); it != m_list0x74.end();) { + MxDSBuffer* buf = *it; + if (buf->GetRefCount() == 0) { + m_list0x74.erase(it++); + FUN_100c7ce0(buf); + } + else { + it++; + } + } + + if (m_nextActionList.empty()) { + while (!m_list0x64.empty()) { + MxDSStreamingAction* action = (MxDSStreamingAction*) m_list0x64.front(); + m_list0x64.pop_front(); + FUN_100c7cb0(action); + } + } +} + +// FUNCTION: LEGO1 0x100c8640 +MxResult MxDiskStreamController::Tickle() +{ + if (m_unk0xc4) { + FUN_100c7d10(); + } + + FUN_100c8540(); + FUN_100c8720(); + + if (m_unk0x70) { + FUN_100c7980(); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c8670 +void MxDiskStreamController::FUN_100c8670(MxDSStreamingAction* p_streamingAction) +{ + AUTOLOCK(m_critical9c); + m_list0xb8.push_back(p_streamingAction); +} + +// FUNCTION: LEGO1 0x100c8720 +void MxDiskStreamController::FUN_100c8720() +{ + AUTOLOCK(m_critical9c); + + MxDSStreamingAction* action; + while (!m_list0xb8.empty()) { + action = (MxDSStreamingAction*) m_list0xb8.front(); + m_list0xb8.pop_front(); + + FUN_100c7cb0(action); + } +} diff --git a/LEGO1/omni/src/stream/mxdiskstreamprovider.cpp b/LEGO1/omni/src/stream/mxdiskstreamprovider.cpp new file mode 100644 index 00000000..d6b73a9b --- /dev/null +++ b/LEGO1/omni/src/stream/mxdiskstreamprovider.cpp @@ -0,0 +1,415 @@ +#include "mxdiskstreamprovider.h" + +#include "mxautolock.h" +#include "mxdiskstreamcontroller.h" +#include "mxdsbuffer.h" +#include "mxdsfile.h" +#include "mxdsstreamingaction.h" +#include "mxomni.h" +#include "mxramstreamprovider.h" +#include "mxstreamcontroller.h" +#include "mxstring.h" +#include "mxthread.h" + +DECOMP_SIZE_ASSERT(MxDiskStreamProviderThread, 0x1c) +DECOMP_SIZE_ASSERT(MxDiskStreamProvider, 0x60); + +// GLOBAL: LEGO1 0x10102878 +MxU32 g_unk0x10102878 = 0; + +// FUNCTION: LEGO1 0x100d0f30 +MxResult MxDiskStreamProviderThread::Run() +{ + if (m_target) { + ((MxDiskStreamProvider*) m_target)->WaitForWorkToComplete(); + } + MxThread::Run(); + // They should probably have writen "return MxThread::Run()" but they didn't. + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100d0f50 +MxResult MxDiskStreamProviderThread::StartWithTarget(MxDiskStreamProvider* p_target) +{ + m_target = p_target; + return Start(0x1000, 0); +} + +// FUNCTION: LEGO1 0x100d0f70 +MxDiskStreamProvider::MxDiskStreamProvider() +{ + this->m_pFile = NULL; + this->m_remainingWork = FALSE; + this->m_unk0x35 = FALSE; +} + +// FUNCTION: LEGO1 0x100d1240 +MxDiskStreamProvider::~MxDiskStreamProvider() +{ + MxDSStreamingAction* action; + m_unk0x35 = FALSE; + + do { + action = NULL; + + { + AUTOLOCK(m_criticalSection); + m_list.PopFrontStreamingAction(action); + } + + if (!action) { + break; + } + + if (action->GetUnknowna0()->GetWriteOffset() < 0x20000) { + g_unk0x10102878--; + } + + ((MxDiskStreamController*) m_pLookup)->FUN_100c8670(action); + } while (action); + + if (m_remainingWork) { + m_remainingWork = FALSE; + m_busySemaphore.Release(1); + m_thread.Terminate(); + } + + if (m_pFile) { + delete m_pFile; + } + + m_pFile = NULL; +} + +// FUNCTION: LEGO1 0x100d13d0 +MxResult MxDiskStreamProvider::SetResourceToGet(MxStreamController* p_resource) +{ + MxResult result = FAILURE; + MxString path; + m_pLookup = p_resource; + + path = (MxString(MxOmni::GetHD()) + p_resource->GetAtom().GetInternal() + ".si"); + + m_pFile = new MxDSFile(path.GetData(), 0); + if (m_pFile != NULL) { + if (m_pFile->Open(0) != 0) { + path = MxString(MxOmni::GetCD()) + p_resource->GetAtom().GetInternal() + ".si"; + m_pFile->SetFileName(path.GetData()); + + if (m_pFile->Open(0) != 0) { + goto done; + } + } + + m_remainingWork = TRUE; + m_busySemaphore.Init(0, 100); + + if (m_thread.StartWithTarget(this) == SUCCESS && p_resource != NULL) { + result = SUCCESS; + } + } + +done: + return result; +} + +// FUNCTION: LEGO1 0x100d15e0 +void MxDiskStreamProvider::VTable0x20(MxDSAction* p_action) +{ + MxDSStreamingAction* action; + + if (p_action->GetObjectId() == -1) { + m_unk0x35 = FALSE; + + do { + action = NULL; + + { + AUTOLOCK(m_criticalSection); + m_list.PopFrontStreamingAction(action); + } + + if (!action) { + return; + } + + if (action->GetUnknowna0()->GetWriteOffset() < 0x20000) { + g_unk0x10102878--; + } + + ((MxDiskStreamController*) m_pLookup)->FUN_100c8670(action); + } while (action); + } + else { + do { + { + AUTOLOCK(m_criticalSection); + action = (MxDSStreamingAction*) m_list.Find(p_action, TRUE); + } + + if (!action) { + return; + } + + if (action->GetUnknowna0()->GetWriteOffset() < 0x20000) { + g_unk0x10102878--; + } + + ((MxDiskStreamController*) m_pLookup)->FUN_100c8670(action); + } while (action); + } +} + +// FUNCTION: LEGO1 0x100d1750 +MxResult MxDiskStreamProvider::WaitForWorkToComplete() +{ + while (m_remainingWork) { + m_busySemaphore.Wait(INFINITE); + if (m_unk0x35) { + PerformWork(); + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100d1780 +MxResult MxDiskStreamProvider::FUN_100d1780(MxDSStreamingAction* p_action) +{ + if (!m_remainingWork) { + return FAILURE; + } + + if (p_action->GetUnknown9c() > 0 && !p_action->GetUnknowna0()) { + MxDSBuffer* buffer = new MxDSBuffer(); + + if (!buffer) { + return FAILURE; + } + + if (buffer->AllocateBuffer(GetFileSize(), MxDSBuffer::e_allocate) != SUCCESS) { + delete buffer; + return FAILURE; + } + + p_action->SetUnknowna0(buffer); + } + + if (p_action->GetUnknowna0()->GetWriteOffset() < 0x20000) { + g_unk0x10102878++; + } + + { + AUTOLOCK(m_criticalSection); + m_list.push_back(p_action); + } + + m_unk0x35 = TRUE; + m_busySemaphore.Release(1); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100d18f0 +void MxDiskStreamProvider::PerformWork() +{ + MxDiskStreamController* controller = (MxDiskStreamController*) m_pLookup; + MxDSStreamingAction* streamingAction = NULL; + + { + AUTOLOCK(m_criticalSection); + if (!m_list.empty()) { + streamingAction = (MxDSStreamingAction*) m_list.front(); + + if (streamingAction && !FUN_100d1af0(streamingAction)) { + m_thread.Sleep(500); + m_busySemaphore.Release(1); + return; + } + } + } + + MxDSBuffer* buffer; + + { + AUTOLOCK(m_criticalSection); + + if (!m_list.PopFrontStreamingAction(streamingAction)) { + goto done; + } + } + + if (streamingAction->GetUnknowna0()->GetWriteOffset() < 0x20000) { + g_unk0x10102878--; + } + + buffer = streamingAction->GetUnknowna0(); + + if (m_pFile->GetPosition() == streamingAction->GetBufferOffset() || + m_pFile->Seek(streamingAction->GetBufferOffset(), 0) == 0) { + buffer->SetUnknown14(m_pFile->GetPosition()); + + if (m_pFile->ReadToBuffer(buffer) == SUCCESS) { + buffer->SetUnknown1c(m_pFile->GetPosition()); + + if (streamingAction->GetUnknown9c() > 0) { + FUN_100d1b20(streamingAction); + } + else { + if (m_pLookup == NULL || !((MxDiskStreamController*) m_pLookup)->GetUnk0xc4()) { + controller->FUN_100c8670(streamingAction); + } + else { + controller->FUN_100c7f40(streamingAction); + } + } + + streamingAction = NULL; + } + } + +done: + if (streamingAction) { + controller->FUN_100c8670(streamingAction); + } + + m_thread.Sleep(0); +} + +// FUNCTION: LEGO1 0x100d1af0 +MxBool MxDiskStreamProvider::FUN_100d1af0(MxDSStreamingAction* p_action) +{ + if (p_action->GetUnknowna0()->GetWriteOffset() == 0x20000) { + return g_unk0x10102878 == 0; + } + + return TRUE; +} + +// FUNCTION: LEGO1 0x100d1b20 +MxResult MxDiskStreamProvider::FUN_100d1b20(MxDSStreamingAction* p_action) +{ + MxDSBuffer* buffer = new MxDSBuffer(); + + if (!buffer) { + return FAILURE; + } + + MxU32 size = p_action->GetUnknowna0()->GetWriteOffset() - p_action->GetUnknown94() + p_action->GetBufferOffset() + + (p_action->GetUnknowna4() ? p_action->GetUnknowna4()->GetWriteOffset() : 0); + + if (buffer->AllocateBuffer(size, MxDSBuffer::e_allocate) != SUCCESS) { + if (!buffer) { + return FAILURE; + } + + delete buffer; + return FAILURE; + } + + MxDSBuffer* buffer2 = p_action->GetUnknowna4(); + MxU8** pdata; + MxU8* data; + + if (buffer2 == NULL) { + pdata = buffer->GetBufferRef(); + + memcpy( + data = *pdata, + p_action->GetUnknowna0()->GetBuffer() - p_action->GetBufferOffset() + p_action->GetUnknown94(), + size + ); + } + else { + buffer->FUN_100c7090(buffer2); + pdata = buffer->GetBufferRef(); + + memcpy( + data = (p_action->GetUnknowna4()->GetWriteOffset() + *pdata), + p_action->GetUnknowna0()->GetBuffer(), + p_action->GetUnknowna0()->GetWriteOffset() + ); + + delete p_action->GetUnknowna4(); + } + + p_action->SetUnknowna4(buffer); + + while (data) { + if (*MxDSChunk::IntoType(data) != FOURCC('M', 'x', 'O', 'b')) { + if (*MxStreamChunk::IntoTime(data) > p_action->GetUnknown9c()) { + *MxDSChunk::IntoType(data) = FOURCC('p', 'a', 'd', ' '); + + memcpy(data + 8, *pdata, buffer->GetWriteOffset() + *pdata - data - 8); + size = ReadData(*pdata, buffer->GetWriteOffset()); + + MxDSBuffer* buffer3 = new MxDSBuffer(); + if (!buffer3) { + return FAILURE; + } + + if (buffer3->AllocateBuffer(size, MxDSBuffer::e_allocate) == SUCCESS) { + memcpy(buffer3->GetBuffer(), p_action->GetUnknowna4()->GetBuffer(), size); + p_action->GetUnknowna4()->SetMode(MxDSBuffer::e_allocate); + delete p_action->GetUnknowna4(); + + buffer3->SetMode(MxDSBuffer::e_unknown); + p_action->SetUnknowna4(buffer3); + MxDSBuffer* buffer4 = p_action->GetUnknowna0(); + MxU32 unk0x14 = buffer4->GetUnknown14(); + MxU8* data2 = buffer4->GetBuffer(); + + while (TRUE) { + if (*MxStreamChunk::IntoTime(data2) > p_action->GetUnknown9c()) { + break; + } + + data += MxDSChunk::Size(*MxDSChunk::IntoLength(data)); + unk0x14 += MxDSChunk::Size(*MxDSChunk::IntoLength(data)); + } + + p_action->SetUnknown94(unk0x14); + p_action->SetBufferOffset(p_action->GetUnknowna0()->GetUnknown14()); + delete p_action->GetUnknowna0(); + p_action->SetUnknowna0(NULL); + ((MxDiskStreamController*) m_pLookup)->FUN_100c7890(p_action); + return SUCCESS; + } + else { + delete buffer3; + return FAILURE; + } + } + } + + data = buffer->FUN_100c6fa0(data); + } + + p_action->SetUnknown94(GetFileSize() + p_action->GetBufferOffset()); + p_action->SetBufferOffset(GetFileSize() + p_action->GetBufferOffset()); + FUN_100d1780(p_action); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100d1e90 +MxU32 MxDiskStreamProvider::GetFileSize() +{ + return m_pFile->GetBufferSize(); +} + +// FUNCTION: LEGO1 0x100d1ea0 +MxS32 MxDiskStreamProvider::GetStreamBuffersNum() +{ + return m_pFile->GetStreamBuffersNum(); +} + +// FUNCTION: LEGO1 0x100d1eb0 +MxU32 MxDiskStreamProvider::GetLengthInDWords() +{ + return m_pFile->GetLengthInDWords(); +} + +// FUNCTION: LEGO1 0x100d1ec0 +MxU32* MxDiskStreamProvider::GetBufferForDWords() +{ + return m_pFile->GetBuffer(); +} diff --git a/LEGO1/omni/src/stream/mxdsbuffer.cpp b/LEGO1/omni/src/stream/mxdsbuffer.cpp new file mode 100644 index 00000000..e5e69c55 --- /dev/null +++ b/LEGO1/omni/src/stream/mxdsbuffer.cpp @@ -0,0 +1,501 @@ +#include "mxdsbuffer.h" + +#include "mxdiskstreamcontroller.h" +#include "mxdschunk.h" +#include "mxdsstreamingaction.h" +#include "mxmisc.h" +#include "mxomni.h" +#include "mxstreamchunk.h" +#include "mxstreamcontroller.h" +#include "mxstreamer.h" +#include "mxstreamprovider.h" + +DECOMP_SIZE_ASSERT(MxDSBuffer, 0x34); + +// FUNCTION: LEGO1 0x100c6470 +MxDSBuffer::MxDSBuffer() +{ + m_referenceCount = 0; + m_pBuffer = NULL; + m_pIntoBuffer = NULL; + m_pIntoBuffer2 = NULL; + m_unk0x14 = 0; + m_unk0x18 = 0; + m_unk0x1c = 0; + m_writeOffset = 0; + m_bytesRemaining = 0; + m_mode = e_preallocated; + m_unk0x30 = 0; +} + +// FUNCTION: LEGO1 0x100c6530 +MxDSBuffer::~MxDSBuffer() +{ + assert(m_referenceCount == 0); + + if (m_pBuffer != NULL) { + switch (m_mode) { + case e_allocate: + case e_unknown: + delete[] m_pBuffer; + break; + + case e_chunk: + Streamer()->ReleaseMemoryBlock(m_pBuffer, m_writeOffset / 1024); + break; + + case e_preallocated: + break; + } + } + + m_unk0x14 = 0; + m_unk0x1c = 0; +} + +// FUNCTION: LEGO1 0x100c6640 +MxResult MxDSBuffer::AllocateBuffer(MxU32 p_bufferSize, Type p_mode) +{ + MxResult result = FAILURE; + + switch (p_mode) { + case e_allocate: + m_pBuffer = new MxU8[p_bufferSize]; + assert(m_pBuffer); // m_firstRiffChunk? + break; + + case e_chunk: + m_pBuffer = Streamer()->GetMemoryBlock(p_bufferSize / 1024); + break; + } + + m_pIntoBuffer = m_pBuffer; + m_pIntoBuffer2 = m_pBuffer; + + if (m_pBuffer != NULL) { + m_bytesRemaining = p_bufferSize; + m_writeOffset = m_bytesRemaining; + m_mode = p_mode; + result = SUCCESS; + } + + return result; +} + +// FUNCTION: LEGO1 0x100c6780 +MxResult MxDSBuffer::SetBufferPointer(MxU8* p_buffer, MxU32 p_size) +{ + m_pBuffer = p_buffer; + m_pIntoBuffer = p_buffer; + m_pIntoBuffer2 = p_buffer; + m_bytesRemaining = p_size; + m_writeOffset = p_size; + m_mode = e_preallocated; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c67b0 +MxResult MxDSBuffer::FUN_100c67b0( + MxStreamController* p_controller, + MxDSAction* p_action, + MxDSStreamingAction** p_streamingAction +) +{ + MxResult result = FAILURE; + + m_unk0x30 = (MxDSStreamingAction*) p_controller->GetUnk0x3c().Find(p_action, FALSE); + if (m_unk0x30 == NULL) { + return FAILURE; + } + + MxU8* data; + while ((data = (MxU8*) SkipToData())) { + if (*p_streamingAction == NULL) { + result = CreateObject(p_controller, (MxU32*) data, p_action, p_streamingAction); + + if (result == FAILURE) { + return result; + } + // TODO: Not a MxResult value? + if (result == 1) { + break; + } + } + else { + MxDSBuffer* buffer = (*p_streamingAction)->GetUnknowna0(); + + if (buffer->CalcBytesRemaining(data) != SUCCESS) { + return result; + } + + if (buffer->GetBytesRemaining() == 0) { + buffer->SetUnk30(m_unk0x30); + + result = buffer->CreateObject(p_controller, (MxU32*) buffer->GetBuffer(), p_action, p_streamingAction); + if (result != SUCCESS) { + return result; + } + + if (buffer->GetRefCount() != 0) { + // Note: *p_streamingAction is always null in MxRamStreamProvider + ((MxDiskStreamController*) p_controller)->InsertToList74(buffer); + (*p_streamingAction)->SetUnknowna0(NULL); + } + + ((MxDiskStreamController*) p_controller)->FUN_100c7cb0(*p_streamingAction); + *p_streamingAction = NULL; + } + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c68a0 +MxResult MxDSBuffer::CreateObject( + MxStreamController* p_controller, + MxU32* p_data, + MxDSAction* p_action, + MxDSStreamingAction** p_streamingAction +) +{ + if (p_data == NULL) { + return FAILURE; + } + + MxCore* header = ReadChunk(this, p_data, p_action->GetUnknown24()); + + if (header == NULL) { + return FAILURE; + } + + if (*p_data == FOURCC('M', 'x', 'O', 'b')) { + return StartPresenterFromAction(p_controller, p_action, (MxDSAction*) header); + } + else if (*p_data == FOURCC('M', 'x', 'C', 'h')) { + MxStreamChunk* chunk = (MxStreamChunk*) header; + if (!m_unk0x30->HasId((chunk)->GetObjectId())) { + delete header; + return SUCCESS; + } + + return ParseChunk(p_controller, p_data, p_action, p_streamingAction, chunk); + } + + delete header; + return FAILURE; +} + +// FUNCTION: LEGO1 0x100c6960 +MxResult MxDSBuffer::StartPresenterFromAction( + MxStreamController* p_controller, + MxDSAction* p_action1, + MxDSAction* p_objectheader +) +{ + if (!m_unk0x30->GetInternalAction()) { + p_objectheader->SetAtomId(p_action1->GetAtomId()); + p_objectheader->SetUnknown28(p_action1->GetUnknown28()); + p_objectheader->SetUnknown84(p_action1->GetUnknown84()); + p_objectheader->SetOrigin(p_action1->GetOrigin()); + p_objectheader->SetUnknown90(p_action1->GetUnknown90()); + p_objectheader->MergeFrom(*p_action1); + + m_unk0x30->SetInternalAction(p_objectheader->Clone()); + + p_controller->InsertActionToList54(p_objectheader); + + if (MxOmni::GetInstance()->CreatePresenter(p_controller, *p_objectheader) != SUCCESS) { + return FAILURE; + } + + m_unk0x30->SetLoopCount(p_objectheader->GetLoopCount()); + m_unk0x30->SetFlags(p_objectheader->GetFlags()); + m_unk0x30->SetDuration(p_objectheader->GetDuration()); + + if (m_unk0x30->GetInternalAction() == NULL) { + return FAILURE; + } + } + else if (p_objectheader) { + delete p_objectheader; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c6a50 +MxResult MxDSBuffer::ParseChunk( + MxStreamController* p_controller, + MxU32* p_data, + MxDSAction* p_action, + MxDSStreamingAction** p_streamingAction, + MxStreamChunk* p_header +) +{ + MxResult result = SUCCESS; + + if (m_unk0x30->GetFlags() & MxDSAction::c_bit3 && m_unk0x30->GetUnknowna8() && p_header->GetTime() < 0) { + delete p_header; + return SUCCESS; + } + + p_header->SetTime(p_header->GetTime() + m_unk0x30->GetUnknowna8()); + + if (p_header->GetChunkFlags() & DS_CHUNK_SPLIT) { + MxU32 length = p_header->GetLength() + MxDSChunk::GetHeaderSize() + 8; + MxDSBuffer* buffer = new MxDSBuffer(); + + if (buffer && buffer->AllocateBuffer(length, e_allocate) == SUCCESS && + buffer->CalcBytesRemaining((MxU8*) p_data) == SUCCESS) { + *p_streamingAction = new MxDSStreamingAction((MxDSStreamingAction&) *p_action); + + if (*p_streamingAction) { + MxU16* flags = MxStreamChunk::IntoFlags(buffer->GetBuffer()); + *flags = p_header->GetChunkFlags() & ~DS_CHUNK_SPLIT; + + delete p_header; + (*p_streamingAction)->SetUnknowna0(buffer); + goto done; + } + } + + if (buffer) { + delete buffer; + } + + delete p_header; + return FAILURE; + } + else { + if (p_header->GetChunkFlags() & DS_CHUNK_END_OF_STREAM) { + if (m_unk0x30->HasId(p_header->GetObjectId())) { + if (m_unk0x30->GetFlags() & MxDSAction::c_bit3 && + (m_unk0x30->GetLoopCount() > 1 || m_unk0x30->GetDuration() == -1)) { + + if (p_action->GetObjectId() == p_header->GetObjectId()) { + MxU32 val = p_controller->GetProvider()->GetBufferForDWords()[m_unk0x30->GetObjectId()]; + + m_unk0x30->SetUnknown94(val); + m_unk0x30->SetBufferOffset(m_writeOffset * (val / m_writeOffset)); + + MxNextActionDataStart* data = + p_controller->FindNextActionDataStartFromStreamingAction(m_unk0x30); + + if (data) { + data->SetData(m_unk0x30->GetBufferOffset()); + } + + m_unk0x30->FUN_100cd2d0(); + } + + delete p_header; + p_header = NULL; + } + else { + if (p_action->GetObjectId() == p_header->GetObjectId() && + p_controller->VTable0x30(p_action) == SUCCESS) { + p_controller->GetProvider()->VTable0x20(p_action); + result = 1; + } + } + } + } + + if (p_header) { + if (p_header->SendChunk(p_controller->GetSubscriberList(), TRUE, p_action->GetUnknown24()) != SUCCESS) { + delete p_header; + } + } + } + +done: + return result; +} + +// FUNCTION: LEGO1 0x100c6d00 +MxCore* MxDSBuffer::ReadChunk(MxDSBuffer* p_buffer, MxU32* p_chunkData, MxU16 p_flags) +{ + // This function reads a chunk. If it is an object, this function returns an MxDSObject. If it is a chunk, + // returns a MxDSChunk. + MxCore* result = NULL; + MxU8* dataStart = (MxU8*) p_chunkData + 8; + + switch (*p_chunkData) { + case FOURCC('M', 'x', 'O', 'b'): + result = DeserializeDSObjectDispatch(dataStart, p_flags); + break; + case FOURCC('M', 'x', 'C', 'h'): + result = new MxStreamChunk(); + if (result != NULL && ((MxStreamChunk*) result)->ReadChunk(p_buffer, (MxU8*) p_chunkData) != SUCCESS) { + delete result; + result = NULL; + } + return result; + } + + return result; +} + +// FUNCTION: LEGO1 0x100c6df0 +MxU8* MxDSBuffer::SkipToData() +{ + MxU8* result = NULL; + + if (m_pIntoBuffer != NULL) { + do { + MxU32* ptr = (MxU32*) m_pIntoBuffer; + switch (*ptr) { + case FOURCC('L', 'I', 'S', 'T'): + case FOURCC('R', 'I', 'F', 'F'): + m_pIntoBuffer = (MxU8*) (ptr + 3); + break; + case FOURCC('M', 'x', 'O', 'b'): + case FOURCC('M', 'x', 'C', 'h'): + result = m_pIntoBuffer; + m_pIntoBuffer = (MxU8*) ((ptr[1] & 1) + ptr[1] + (MxU32) ptr); + m_pIntoBuffer = (MxU8*) ((MxU32*) m_pIntoBuffer + 2); + if (m_pBuffer + (m_writeOffset - 8) < m_pIntoBuffer) { + m_pIntoBuffer2 = result; + m_pIntoBuffer = NULL; + return result; + } + goto done; + case FOURCC('M', 'x', 'D', 'a'): + case FOURCC('M', 'x', 'S', 't'): + m_pIntoBuffer = (MxU8*) (ptr + 2); + break; + case FOURCC('M', 'x', 'H', 'd'): + m_pIntoBuffer = (MxU8*) ((MxU32) ptr + ptr[1] + 8); + break; + default: + m_pIntoBuffer = NULL; + m_pIntoBuffer2 = NULL; + return NULL; + } + } while (m_pIntoBuffer <= m_pBuffer + (m_writeOffset - 8)); + } +done: + m_pIntoBuffer2 = result; + return result; +} + +// FUNCTION: LEGO1 0x100c6ec0 +MxU8 MxDSBuffer::ReleaseRef(MxDSChunk*) +{ + if (m_referenceCount != 0) { + m_referenceCount--; + } + return 0; +} + +// FUNCTION: LEGO1 0x100c6ee0 +void MxDSBuffer::AddRef(MxDSChunk* p_chunk) +{ + if (p_chunk) { + m_referenceCount++; + } +} + +// FUNCTION: LEGO1 0x100c6ef0 +MxResult MxDSBuffer::CalcBytesRemaining(MxU8* p_data) +{ + MxResult result = FAILURE; + + if (m_mode == e_allocate && m_bytesRemaining != 0) { + MxU32 bytesRead; + MxU8* ptr; + + if (m_writeOffset == m_bytesRemaining) { + bytesRead = *(MxU32*) (p_data + 4) + 8; + ptr = p_data; + } + else { + ptr = &p_data[MxStreamChunk::GetHeaderSize() + 8]; + bytesRead = (*(MxU32*) (p_data + 4)) - MxStreamChunk::GetHeaderSize(); + } + + if (bytesRead <= m_bytesRemaining) { + memcpy(m_pBuffer + m_writeOffset - m_bytesRemaining, ptr, bytesRead); + + if (m_writeOffset == m_bytesRemaining) { + *(MxU32*) (m_pBuffer + 4) = *MxStreamChunk::IntoLength(m_pBuffer) + MxStreamChunk::GetHeaderSize(); + } + + m_bytesRemaining -= bytesRead; + result = SUCCESS; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100c6f80 +void MxDSBuffer::FUN_100c6f80(MxU32 p_writeOffset) +{ + if (p_writeOffset < m_writeOffset) { + m_pIntoBuffer2 = m_pBuffer + p_writeOffset; + m_pIntoBuffer = m_pBuffer + p_writeOffset; + } +} + +// FUNCTION: LEGO1 0x100c6fa0 +MxU8* MxDSBuffer::FUN_100c6fa0(MxU8* p_data) +{ + MxU8* current = p_data ? p_data : m_pBuffer; + MxU8* end = m_writeOffset + m_pBuffer - 8; + + while (current <= end) { + switch (*((MxU32*) current)) { + case FOURCC('L', 'I', 'S', 'T'): + case FOURCC('R', 'I', 'F', 'F'): + current += 12; + break; + case FOURCC('M', 'x', 'D', 'a'): + case FOURCC('M', 'x', 'S', 't'): + current += 8; + break; + case FOURCC('M', 'x', 'O', 'b'): + case FOURCC('M', 'x', 'C', 'h'): + if (current != p_data) { + return current; + } + current = ((MxU32) current & 1) + current; + current += 8; + break; + case FOURCC('M', 'x', 'H', 'd'): + current += (((MxU32*) current)[1] + 8); + break; + default: + return NULL; + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x100c7090 +MxResult MxDSBuffer::FUN_100c7090(MxDSBuffer* p_buf) +{ + MxResult result = FAILURE; + + if (m_writeOffset >= p_buf->m_writeOffset) { + memcpy(m_pBuffer, p_buf->m_pBuffer, p_buf->m_writeOffset); + result = SUCCESS; + } + + m_unk0x1c = p_buf->m_unk0x1c; + return result; +} + +// FUNCTION: LEGO1 0x100c70d0 +MxResult MxDSBuffer::Append(MxU8* p_buffer1, MxU8* p_buffer2) +{ + if (p_buffer1 && p_buffer2) { + MxU32 size = ((MxU32*) p_buffer2)[1] - MxDSChunk::GetHeaderSize(); + memcpy(p_buffer1 + ((MxU32*) p_buffer1)[1] + 8, p_buffer2 + MxDSChunk::GetHeaderSize() + 8, size); + ((MxU32*) p_buffer1)[1] += size; + return SUCCESS; + } + return FAILURE; +} diff --git a/LEGO1/omni/src/stream/mxdschunk.cpp b/LEGO1/omni/src/stream/mxdschunk.cpp new file mode 100644 index 00000000..60dfb10e --- /dev/null +++ b/LEGO1/omni/src/stream/mxdschunk.cpp @@ -0,0 +1,27 @@ +#include "mxdschunk.h" + +DECOMP_SIZE_ASSERT(MxDSChunk, 0x1c); + +// FUNCTION: LEGO1 0x100be050 +MxDSChunk::MxDSChunk() +{ + m_flags = 0; + m_data = NULL; + m_objectId = -1; + m_time = 0; + m_length = 0; +} + +// FUNCTION: LEGO1 0x100be170 +MxDSChunk::~MxDSChunk() +{ + if (m_flags & DS_CHUNK_BIT1) { + delete[] m_data; + } +} + +// FUNCTION: LEGO1 0x100be1e0 +MxU32 MxDSChunk::GetHeaderSize() +{ + return 0x0e; +} diff --git a/LEGO1/omni/src/stream/mxdsfile.cpp b/LEGO1/omni/src/stream/mxdsfile.cpp new file mode 100644 index 00000000..9b6fa661 --- /dev/null +++ b/LEGO1/omni/src/stream/mxdsfile.cpp @@ -0,0 +1,124 @@ +#include "mxdsfile.h" + +#include "decomp.h" + +#include + +#define SI_MAJOR_VERSION 2 +#define SI_MINOR_VERSION 2 + +DECOMP_SIZE_ASSERT(MxDSFile::ChunkHeader, 0x0c) +DECOMP_SIZE_ASSERT(MxDSFile, 0x7c) + +// FUNCTION: LEGO1 0x100cc4b0 +MxDSFile::MxDSFile(const char* p_filename, MxULong p_skipReadingChunks) +{ + m_filename = p_filename; + m_skipReadingChunks = p_skipReadingChunks; +} + +// FUNCTION: LEGO1 0x100cc590 +MxLong MxDSFile::Open(MxULong p_uStyle) +{ + MXIOINFO& io = m_io; + MxLong longResult = 1; + memset(&io, 0, sizeof(MXIOINFO)); + + if (io.Open(m_filename.GetData(), p_uStyle) != 0) { + return -1; + } + + io.SetBuffer(NULL, 0, 0); + m_position = 0; + + if (m_skipReadingChunks == 0) { + longResult = ReadChunks(); + } + + if (longResult != 0) { + Close(); + } + else { + Seek(0, 0); + } + + return longResult; +} + +// FUNCTION: LEGO1 0x100cc620 +MxLong MxDSFile::ReadChunks() +{ + _MMCKINFO topChunk; + _MMCKINFO childChunk; + char tempBuffer[80]; + + topChunk.fccType = FOURCC('O', 'M', 'N', 'I'); + if (m_io.Descend(&topChunk, NULL, MMIO_FINDRIFF) != 0) { + return -1; + } + childChunk.ckid = FOURCC('M', 'x', 'H', 'd'); + if (m_io.Descend(&childChunk, &topChunk, 0) != 0) { + return -1; + } + + m_io.Read(&m_header, 0x0c); + if ((m_header.m_majorVersion == SI_MAJOR_VERSION) && (m_header.m_minorVersion == SI_MINOR_VERSION)) { + childChunk.ckid = FOURCC('M', 'x', 'O', 'f'); + if (m_io.Descend(&childChunk, &topChunk, 0) != 0) { + return -1; + } + MxULong* pLengthInDWords = &m_lengthInDWords; + m_io.Read(pLengthInDWords, 4); + m_pBuffer = new MxU32[*pLengthInDWords]; + m_io.Read(m_pBuffer, *pLengthInDWords * 4); + return 0; + } + else { + sprintf(tempBuffer, "Wrong SI file version. %d.%d expected.", SI_MAJOR_VERSION, SI_MINOR_VERSION); + MessageBoxA(NULL, tempBuffer, NULL, MB_ICONERROR); + return -1; + } +} + +// FUNCTION: LEGO1 0x100cc740 +MxLong MxDSFile::Close() +{ + m_io.Close(0); + m_position = -1; + memset(&m_header, 0, sizeof(m_header)); + if (m_lengthInDWords != 0) { + m_lengthInDWords = 0; + delete[] m_pBuffer; + m_pBuffer = NULL; + } + return 0; +} + +// FUNCTION: LEGO1 0x100cc780 +MxResult MxDSFile::Read(unsigned char* p_buf, MxULong p_nbytes) +{ + if (m_io.Read(p_buf, p_nbytes) != p_nbytes) { + return FAILURE; + } + + m_position += p_nbytes; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100cc7b0 +MxLong MxDSFile::Seek(MxLong p_lOffset, MxS32 p_iOrigin) +{ + return (m_position = m_io.Seek(p_lOffset, p_iOrigin)) == -1 ? -1 : 0; +} + +// FUNCTION: LEGO1 0x100cc7e0 +MxULong MxDSFile::GetBufferSize() +{ + return m_header.m_bufferSize; +} + +// FUNCTION: LEGO1 0x100cc7f0 +MxULong MxDSFile::GetStreamBuffersNum() +{ + return m_header.m_streamBuffersNum; +} diff --git a/LEGO1/omni/src/stream/mxdssource.cpp b/LEGO1/omni/src/stream/mxdssource.cpp new file mode 100644 index 00000000..c2d86abb --- /dev/null +++ b/LEGO1/omni/src/stream/mxdssource.cpp @@ -0,0 +1,23 @@ +#include "mxdssource.h" + +#include "mxdsbuffer.h" + +DECOMP_SIZE_ASSERT(MxDSSource, 0x14) + +// FUNCTION: LEGO1 0x100bffd0 +MxResult MxDSSource::ReadToBuffer(MxDSBuffer* p_buffer) +{ + return Read(p_buffer->GetBuffer(), p_buffer->GetWriteOffset()); +} + +// FUNCTION: LEGO1 0x100bfff0 +MxLong MxDSSource::GetLengthInDWords() +{ + return m_lengthInDWords; +} + +// FUNCTION: LEGO1 0x100c0000 +MxU32* MxDSSource::GetBuffer() +{ + return m_pBuffer; +} diff --git a/LEGO1/omni/src/stream/mxdssubscriber.cpp b/LEGO1/omni/src/stream/mxdssubscriber.cpp new file mode 100644 index 00000000..8900ff69 --- /dev/null +++ b/LEGO1/omni/src/stream/mxdssubscriber.cpp @@ -0,0 +1,137 @@ +#include "mxdssubscriber.h" + +#include "mxstreamcontroller.h" + +DECOMP_SIZE_ASSERT(MxDSSubscriber, 0x4c); + +// FUNCTION: LEGO1 0x100b7bb0 +MxDSSubscriber::MxDSSubscriber() +{ + m_unk0x48 = -1; + m_objectId = -1; + m_pendingChunkCursor = NULL; + m_consumedChunkCursor = NULL; +} + +// FUNCTION: LEGO1 0x100b7e00 +MxDSSubscriber::~MxDSSubscriber() +{ + if (m_controller) { + m_controller->RemoveSubscriber(this); + } + + DestroyData(); + + if (m_pendingChunkCursor) { + delete m_pendingChunkCursor; + } + m_pendingChunkCursor = NULL; + + if (m_consumedChunkCursor) { + delete m_consumedChunkCursor; + } + m_consumedChunkCursor = NULL; +} + +// FUNCTION: LEGO1 0x100b7ed0 +MxResult MxDSSubscriber::Create(MxStreamController* p_controller, MxU32 p_objectId, MxS16 p_unk0x48) +{ + m_objectId = p_objectId; + m_unk0x48 = p_unk0x48; + + if (!p_controller) { + return FAILURE; + } + m_controller = p_controller; + + m_pendingChunkCursor = new MxStreamChunkListCursor(&m_pendingChunks); + if (!m_pendingChunkCursor) { + return FAILURE; + } + + m_consumedChunkCursor = new MxStreamChunkListCursor(&m_consumedChunks); + if (!m_consumedChunkCursor) { + return FAILURE; + } + + m_controller->AddSubscriber(this); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b8030 +void MxDSSubscriber::DestroyData() +{ + if (m_controller) { + MxStreamChunk* chunk = NULL; + + while (m_pendingChunkCursor->First(chunk)) { + m_pendingChunkCursor->Detach(); + delete chunk; + } + + while (m_consumedChunkCursor->First(chunk)) { + m_consumedChunkCursor->Detach(); + delete chunk; + } + } +} + +// FUNCTION: LEGO1 0x100b8150 +MxResult MxDSSubscriber::AddData(MxStreamChunk* p_chunk, MxBool p_append) +{ + if (m_pendingChunkCursor) { + if (p_append) { + m_pendingChunks.Append(p_chunk); + } + else { + m_pendingChunks.Prepend(p_chunk); + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b8250 +MxStreamChunk* MxDSSubscriber::PopData() +{ + MxStreamChunk* chunk = NULL; + + if (m_pendingChunkCursor) { + m_pendingChunkCursor->First(chunk); + } + + if (chunk) { + m_pendingChunkCursor->Detach(); + m_consumedChunks.Append(chunk); + } + + return chunk; +} + +// FUNCTION: LEGO1 0x100b8360 +MxStreamChunk* MxDSSubscriber::PeekData() +{ + MxStreamChunk* chunk = NULL; + + if (m_pendingChunkCursor) { + m_pendingChunkCursor->First(chunk); + } + + return chunk; +} + +// FUNCTION: LEGO1 0x100b8390 +void MxDSSubscriber::FreeDataChunk(MxStreamChunk* p_chunk) +{ + if (p_chunk) { + if (m_consumedChunkCursor->Find(p_chunk)) { + m_consumedChunkCursor->Detach(); + if (p_chunk) { + delete p_chunk; + } + } + else if (p_chunk->GetChunkFlags() & DS_CHUNK_BIT1 && p_chunk) { + delete p_chunk; + } + } +} diff --git a/LEGO1/omni/src/stream/mxio.cpp b/LEGO1/omni/src/stream/mxio.cpp new file mode 100644 index 00000000..518b60f9 --- /dev/null +++ b/LEGO1/omni/src/stream/mxio.cpp @@ -0,0 +1,603 @@ +#include "mxio.h" + +#include "decomp.h" + +#include + +// This class should be 72 bytes in size, same as the MMIOINFO struct. +// The current implementation has MMIOINFO as the only member of the class, +// but this assert will enforce the size if we decide to change that. +DECOMP_SIZE_ASSERT(MXIOINFO, sizeof(MMIOINFO)); + +// FUNCTION: LEGO1 0x100cc800 +// FUNCTION: BETA10 0x1015e140 +MXIOINFO::MXIOINFO() +{ + memset(&m_info, 0, sizeof(m_info)); +} + +// FUNCTION: LEGO1 0x100cc820 +// FUNCTION: BETA10 0x1015e169 +MXIOINFO::~MXIOINFO() +{ + Close(0); +} + +// FUNCTION: LEGO1 0x100cc830 +// FUNCTION: BETA10 0x1015e189 +MxU16 MXIOINFO::Open(const char* p_filename, MxULong p_flags) +{ + OFSTRUCT unused; + MxU16 result = 0; + + m_info.lDiskOffset = m_info.lBufOffset = 0; + + // DECOMP: Cast of p_flags to u16 forces the `movzx` instruction + m_info.hmmio = (HMMIO) OpenFile(p_filename, &unused, (MxU16) p_flags); + + if ((HFILE) m_info.hmmio != HFILE_ERROR) { + m_info.dwFlags = p_flags; + if (m_info.dwFlags & MMIO_ALLOCBUF) { + + // Default buffer length of 8k if none specified + MxLong len = m_info.cchBuffer; + if (len == 0) { + len = 8192; + } + + char* buf = new char[len]; + + if (!buf) { + m_info.dwFlags &= ~MMIO_ALLOCBUF; + m_info.cchBuffer = 0; + m_info.pchBuffer = 0; + result = MMIOERR_OUTOFMEMORY; + } + else { + m_info.cchBuffer = len; + m_info.pchBuffer = (HPSTR) buf; + } + + m_info.pchNext = m_info.pchEndRead = m_info.pchBuffer; + m_info.pchEndWrite = m_info.pchBuffer + m_info.cchBuffer; + } + } + else { + result = MMIOERR_CANNOTOPEN; + } + + return result; +} + +// FUNCTION: LEGO1 0x100cc8e0 +// FUNCTION: BETA10 0x1015e30b +MxU16 MXIOINFO::Close(MxLong p_unused) +{ + MxU16 result = 0; + + if (m_info.hmmio) { + result = Flush(0); + _lclose((HFILE) m_info.hmmio); + m_info.hmmio = 0; + + if (m_info.dwFlags & MMIO_ALLOCBUF) { + delete[] m_info.pchBuffer; + } + + m_info.pchBuffer = m_info.pchEndRead = m_info.pchEndWrite = NULL; + m_info.dwFlags = 0; + } + + return result; +} + +// FUNCTION: LEGO1 0x100cc930 +// FUNCTION: BETA10 0x1015e3b2 +MxLong MXIOINFO::Read(void* p_buf, MxLong p_len) +{ + MxLong bytesRead = 0; + + if (m_info.pchBuffer) { + + MxLong bytesLeft = m_info.pchEndRead - m_info.pchNext; + while (p_len > 0) { + + if (bytesLeft > 0) { + if (p_len < bytesLeft) { + bytesLeft = p_len; + } + + memcpy(p_buf, m_info.pchNext, bytesLeft); + + m_info.pchNext += bytesLeft; + bytesRead += bytesLeft; + p_len -= bytesLeft; + } + + if (p_len > 0) { + if (Advance(MMIO_READ)) { + break; + } + else { + bytesLeft = m_info.pchEndRead - m_info.pchNext; + if (bytesLeft <= 0) { + break; + } + } + } + } + } + else if (m_info.hmmio && p_len > 0) { + bytesRead = _hread((HFILE) m_info.hmmio, p_buf, p_len); + + if (bytesRead == -1) { + bytesRead = 0; + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + m_info.lDiskOffset += bytesRead; + } + } + + return bytesRead; +} + +// FUNCTION: BETA10 0x1015e4fc +MxLong MXIOINFO::Write(void* p_buf, MxLong p_len) +{ + MxLong bytesWritten = 0; + + if (m_info.pchBuffer) { + + MxLong bytesLeft = m_info.pchEndWrite - m_info.pchNext; + while (p_len > 0) { + + if (bytesLeft > 0) { + if (p_len < bytesLeft) { + bytesLeft = p_len; + } + + memcpy(m_info.pchNext, p_buf, bytesLeft); + m_info.dwFlags |= MMIO_DIRTY; + + m_info.pchNext += bytesLeft; + bytesWritten += bytesLeft; + p_len -= bytesLeft; + } + + if (p_len > 0) { + if (Advance(MMIO_WRITE)) { + assert(0); + break; + } + else { + bytesLeft = m_info.pchEndWrite - m_info.pchNext; + if (bytesLeft <= 0) { + assert(0); + break; + } + } + } + } + } + else if (m_info.hmmio && p_len > 0) { + bytesWritten = _hwrite((HFILE) m_info.hmmio, (const char*) p_buf, p_len); + + if (bytesWritten == -1) { + bytesWritten = 0; + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + m_info.lDiskOffset += bytesWritten; + } + } + + // DECOMP: This assert is just "pchNext <= pchEndWrite" + // That would suggest that MXIOINFO directly extends MMIOINFO. + // TODO: Change that if we still have entropy at the end. + assert(m_info.pchNext <= m_info.pchEndWrite); + return bytesWritten; +} + +// FUNCTION: LEGO1 0x100cca00 +// FUNCTION: BETA10 0x1015e6c4 +MxLong MXIOINFO::Seek(MxLong p_offset, MxLong p_origin) +{ + MxLong result = -1; + MxLong bytesRead; + + // If buffered I/O + if (m_info.pchBuffer) { + if (p_origin == SEEK_CUR) { + if (!p_offset) { + // don't seek at all and just return where we are. + return m_info.lBufOffset + (m_info.pchNext - m_info.pchBuffer); + } + + // With SEEK_CUR, p_offset is a relative offset. + // Get the absolute position instead and use SEEK_SET. + p_offset += m_info.lBufOffset + (m_info.pchNext - m_info.pchBuffer); + p_origin = SEEK_SET; + } + else if (p_origin == SEEK_END) { + // not possible with buffered I/O + return -1; + } + + // else p_origin == SEEK_SET. + + // is p_offset between the start and end of the buffer? + // i.e. can we do the seek without reading more from disk? + if (p_offset >= m_info.lBufOffset && p_offset < m_info.lBufOffset + m_info.cchBuffer) { + m_info.pchNext = m_info.pchBuffer + (p_offset - m_info.lBufOffset); + result = p_offset; + } + else { + // we have to read another chunk from disk. + if (m_info.hmmio && !Flush(0)) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, p_offset, p_origin); + + if (m_info.lDiskOffset == -1) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + + // align offset to buffer size + m_info.lBufOffset = p_offset - (p_offset % m_info.cchBuffer); + + // do we need to seek again? + // (i.e. are we already aligned to buffer size?) + if (p_offset != m_info.lBufOffset) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET); + + if (m_info.lDiskOffset == -1) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + } + + if (m_info.lBufOffset == m_info.lDiskOffset) { + // is the file open for writing only? + if ((m_info.dwFlags & MMIO_RWMODE) == 0 || (m_info.dwFlags & MMIO_RWMODE) == MMIO_READWRITE) { + // We can read from the file. Fill the buffer. + bytesRead = _hread((HFILE) m_info.hmmio, m_info.pchBuffer, m_info.cchBuffer); + + if (bytesRead == -1) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + m_info.lDiskOffset += bytesRead; + m_info.pchNext = p_offset - m_info.lBufOffset + m_info.pchBuffer; + m_info.pchEndRead = m_info.pchBuffer + bytesRead; + + if (m_info.pchNext < m_info.pchEndRead) { + result = p_offset; + } + } + } + else { + m_info.pchNext = p_offset - m_info.lBufOffset + m_info.pchBuffer; + result = p_offset; + } + } + } + } + } + } + else if (m_info.hmmio) { + // No buffer so just seek the file directly (if we have a valid handle) + // i.e. if we just want to get the current file position + if (p_origin == SEEK_CUR && p_offset == 0) { + return m_info.lDiskOffset; + } + + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, p_offset, p_origin); + + result = m_info.lDiskOffset; + + if (result == -1) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100ccbc0 +// FUNCTION: BETA10 0x1015e9ad +MxU16 MXIOINFO::SetBuffer(char* p_buf, MxLong p_len, MxLong p_unused) +{ + MxU16 result = 0; + result = Flush(0); + + if (m_info.dwFlags & MMIO_ALLOCBUF) { + m_info.dwFlags &= ~MMIO_ALLOCBUF; + delete[] m_info.pchBuffer; + } + + m_info.pchBuffer = p_buf; + m_info.cchBuffer = p_len; + m_info.pchEndWrite = m_info.pchBuffer + m_info.cchBuffer; + m_info.pchEndRead = m_info.pchBuffer; + + return result; +} + +// FUNCTION: LEGO1 0x100ccc10 +// FUNCTION: BETA10 0x1015ea3e +MxU16 MXIOINFO::Flush(MxU16 p_unused) +{ + MxU16 result = 0; + MxLong bytesWritten; + + // if buffer is dirty + if (m_info.dwFlags & MMIO_DIRTY) { + // if we have allocated an IO buffer + if (m_info.pchBuffer) { + // if we have a file open for writing + if (m_info.hmmio && (m_info.dwFlags & MMIO_RWMODE)) { + // DECOMP: pulling this value out into a variable forces it into EBX + MxLong cchBuffer = m_info.cchBuffer; + if (cchBuffer > 0) { + if (m_info.lBufOffset != m_info.lDiskOffset) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET); + } + + // Was the previous seek (if required) successful? + if (m_info.lBufOffset != m_info.lDiskOffset) { + result = MMIOERR_CANNOTSEEK; + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + bytesWritten = _hwrite((HFILE) m_info.hmmio, m_info.pchBuffer, cchBuffer); + + if (bytesWritten == -1 || bytesWritten != cchBuffer) { + result = MMIOERR_CANNOTWRITE; + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + m_info.lDiskOffset += bytesWritten; + m_info.pchNext = m_info.pchBuffer; + m_info.dwFlags &= ~MMIO_DIRTY; + } + } + } + } + else { + result = MMIOERR_CANNOTWRITE; + } + } + else { + result = MMIOERR_UNBUFFERED; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100ccd00 +// FUNCTION: BETA10 0x1015eb8f +MxU16 MXIOINFO::Advance(MxU16 p_option) +{ + MxU16 result = 0; + MxULong rwmode = m_info.dwFlags & MMIO_RWMODE; + + if (m_info.pchBuffer) { + MxLong cch = m_info.cchBuffer; + MxLong bytesCounter; + + // If we can and should write to the file, + // if we are being asked to write to the file, + // and if there is a buffer *to* write: + if ((rwmode == MMIO_WRITE || rwmode == MMIO_READWRITE) && (m_info.dwFlags & MMIO_DIRTY) && + ((p_option & MMIO_WRITE) || (rwmode == MMIO_READWRITE)) && cch > 0) { + + if (m_info.lBufOffset != m_info.lDiskOffset) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET); + } + + if (m_info.lBufOffset != m_info.lDiskOffset) { + result = MMIOERR_CANNOTSEEK; + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + bytesCounter = _hwrite((HFILE) m_info.hmmio, m_info.pchBuffer, cch); + + if (bytesCounter == -1 || bytesCounter != cch) { + result = MMIOERR_CANNOTWRITE; + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + m_info.lDiskOffset += bytesCounter; + m_info.pchNext = m_info.pchBuffer; + m_info.pchEndRead = m_info.pchBuffer; + m_info.dwFlags &= ~MMIO_DIRTY; + } + } + } + + m_info.lBufOffset += cch; + if ((!rwmode || rwmode == MMIO_READWRITE) && cch > 0) { + if (m_info.lBufOffset != m_info.lDiskOffset) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET); + } + + // if previous seek failed + if (m_info.lBufOffset != m_info.lDiskOffset) { + result = MMIOERR_CANNOTSEEK; + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + bytesCounter = _hread((HFILE) m_info.hmmio, m_info.pchBuffer, cch); + + if (bytesCounter == -1) { + result = MMIOERR_CANNOTREAD; + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + } + else { + m_info.lDiskOffset += bytesCounter; + m_info.pchNext = m_info.pchBuffer; + m_info.pchEndRead = m_info.pchBuffer + bytesCounter; + } + } + } + } + else { + result = MMIOERR_UNBUFFERED; + } + + return result; +} + +// FUNCTION: LEGO1 0x100cce60 +// FUNCTION: BETA10 0x1015edef +MxU16 MXIOINFO::Descend(MMCKINFO* p_chunkInfo, const MMCKINFO* p_parentInfo, MxU16 p_descend) +{ + MxU16 result = 0; + MxULong ofs; + BOOL readOk; + + if (!p_chunkInfo) { + return MMIOERR_BASE; // ? + } + + if (!p_descend) { + p_chunkInfo->dwFlags = 0; + if (Read(p_chunkInfo, 8) != 8) { + result = MMIOERR_CANNOTREAD; + } + else { + if (m_info.pchBuffer) { + p_chunkInfo->dwDataOffset = m_info.pchNext - m_info.pchBuffer + m_info.lBufOffset; + } + else { + p_chunkInfo->dwDataOffset = m_info.lDiskOffset; + } + + if ((p_chunkInfo->ckid == FOURCC_RIFF || p_chunkInfo->ckid == FOURCC_LIST) && + Read(&p_chunkInfo->fccType, 4) != 4) { + result = MMIOERR_CANNOTREAD; + } + } + } + else { + ofs = MAXLONG; + + if (p_parentInfo) { + ofs = p_parentInfo->cksize + p_parentInfo->dwDataOffset; + } + + BOOL running = TRUE; + readOk = FALSE; + MMCKINFO tmp; + tmp.dwFlags = 0; + + while (running) { + if (Read(&tmp, 8) != 8) { + // If the first read fails, report read error. Else EOF. + result = readOk ? MMIOERR_CHUNKNOTFOUND : MMIOERR_CANNOTREAD; + running = FALSE; + } + else { + readOk = TRUE; + if (m_info.pchBuffer) { + tmp.dwDataOffset = m_info.pchNext - m_info.pchBuffer + m_info.lBufOffset; + } + else { + tmp.dwDataOffset = m_info.lDiskOffset; + } + + if (ofs < tmp.dwDataOffset) { + result = MMIOERR_CHUNKNOTFOUND; + running = FALSE; + } + else if ((p_descend == MMIO_FINDLIST && tmp.ckid == FOURCC_LIST) || (p_descend == MMIO_FINDRIFF && tmp.ckid == FOURCC_RIFF)) { + if (Read(&tmp.fccType, 4) != 4) { + result = MMIOERR_CANNOTREAD; + running = FALSE; + } + else if (p_chunkInfo->fccType == tmp.fccType) { + running = FALSE; + } + } + else if (p_chunkInfo->ckid == tmp.ckid) { + running = FALSE; + } + else if (Seek((tmp.cksize & 1) + tmp.cksize, SEEK_CUR) == -1) { + result = MMIOERR_CANNOTSEEK; + running = FALSE; + } + } + } + + if (!result) { + // implicit memcpy + *p_chunkInfo = tmp; + } + } + + return result; +} + +// FUNCTION: BETA10 0x1015f08b +MxU16 MXIOINFO::Ascend(MMCKINFO* p_chunkInfo, MxU16 p_ascend) +{ + MxLong ofs; + MxULong size; + MxU16 result = 0; + + if (p_chunkInfo == NULL) { + return MMIOERR_BASE; + } + + if (m_info.dwFlags & MMIO_RWMODE) { + if (m_info.pchBuffer) { + size = (MxULong) (m_info.pchNext - m_info.pchBuffer) + m_info.lBufOffset - p_chunkInfo->dwDataOffset; + } + else { + size = m_info.lDiskOffset - p_chunkInfo->dwDataOffset; + } + + // Write a zero byte if the chunk size is odd + if (size & 1) { + Write(&result, 1); + } + + if ((p_chunkInfo->dwFlags & MMIO_DIRTY) && p_chunkInfo->cksize != size) { + ofs = p_chunkInfo->dwDataOffset - 4; + // Correct chunk size + p_chunkInfo->cksize = size; + p_chunkInfo->dwFlags &= ~MMIO_DIRTY; + + // Now write the corrected size + if (m_info.pchBuffer && ofs >= m_info.lBufOffset && m_info.cchBuffer + m_info.lBufOffset > ofs) { + memcpy(m_info.pchBuffer + (ofs - m_info.lBufOffset), (char*) &size, 4); + m_info.dwFlags |= MMIO_DIRTY; + } + else { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, ofs, SEEK_SET); + + if (m_info.lDiskOffset == ofs) { + if (_lwrite((HFILE) m_info.hmmio, (char*) &size, 4) != 4) { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + result = MMIOERR_CANNOTWRITE; + } + else { + m_info.lDiskOffset += 4; // TODO: compiler weirdness? + } + } + else { + m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR); + result = MMIOERR_CANNOTSEEK; + } + } + } + } + + // Seek past the end of the chunk (plus optional pad byte if size is odd) + if (result == 0 && + Seek((p_chunkInfo->cksize & 1) + p_chunkInfo->cksize + p_chunkInfo->dwDataOffset, SEEK_SET) == -1) { + result = MMIOERR_CANNOTSEEK; + } + + return result; +} diff --git a/LEGO1/omni/src/stream/mxramstreamcontroller.cpp b/LEGO1/omni/src/stream/mxramstreamcontroller.cpp new file mode 100644 index 00000000..dea72610 --- /dev/null +++ b/LEGO1/omni/src/stream/mxramstreamcontroller.cpp @@ -0,0 +1,95 @@ +#include "mxramstreamcontroller.h" + +#include "mxautolock.h" +#include "mxdsstreamingaction.h" +#include "mxramstreamprovider.h" + +DECOMP_SIZE_ASSERT(MxRAMStreamController, 0x98); + +// FUNCTION: LEGO1 0x100c6110 +MxResult MxRAMStreamController::Open(const char* p_filename) +{ + AUTOLOCK(m_criticalSection); + if (MxStreamController::Open(p_filename) != SUCCESS) { + return FAILURE; + } + + m_provider = new MxRAMStreamProvider(); + if (((MxRAMStreamProvider*) m_provider) != NULL) { + if (m_provider->SetResourceToGet(this) != SUCCESS) { + return FAILURE; + } + + ReadData( + ((MxRAMStreamProvider*) m_provider)->GetBufferOfFileSize(), + ((MxRAMStreamProvider*) m_provider)->GetFileSize() + ); + m_buffer.SetBufferPointer( + ((MxRAMStreamProvider*) m_provider)->GetBufferOfFileSize(), + ((MxRAMStreamProvider*) m_provider)->GetFileSize() + ); + return SUCCESS; + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x100c6210 +MxResult MxRAMStreamController::VTable0x20(MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + MxS32 unk0x24 = 0; + MxResult result = FAILURE; + + if (p_action->GetUnknown24() == -1) { + p_action->SetUnknown24(-3); + MxDSAction* action = m_unk0x54.Find(p_action, FALSE); + if (action != NULL) { + unk0x24 = action->GetUnknown24() + 1; + } + p_action->SetUnknown24(unk0x24); + } + else { + if (m_unk0x54.Find(p_action, FALSE)) { + return FAILURE; + } + } + + if (MxStreamController::VTable0x20(p_action) == SUCCESS) { + MxDSStreamingAction* action = (MxDSStreamingAction*) m_unk0x3c.Find(p_action, FALSE); + MxDSStreamingAction streamingaction(*action); + result = DeserializeObject(streamingaction); + } + return result; +} + +// FUNCTION: LEGO1 0x100c6320 +MxResult MxRAMStreamController::VTable0x24(MxDSAction* p_action) +{ + MxDSAction action; + do { + if (m_action0x60 != NULL) { + delete m_action0x60; + m_action0x60 = NULL; + } + action = *p_action; + MxStreamController::VTable0x24(&action); + } while (m_action0x60 != NULL); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c63c0 +MxResult MxRAMStreamController::DeserializeObject(MxDSStreamingAction& p_action) +{ + AUTOLOCK(m_criticalSection); + MxResult result; + MxDSStreamingAction* value = NULL; + + do { + m_buffer.FUN_100c6f80(p_action.GetUnknown94()); + // Probably not MxResult, see below + result = m_buffer.FUN_100c67b0(this, &p_action, &value); + } while (m_unk0x3c.Find(&p_action, FALSE) != NULL); + + return result == SUCCESS ? SUCCESS : FAILURE; +} diff --git a/LEGO1/omni/src/stream/mxramstreamprovider.cpp b/LEGO1/omni/src/stream/mxramstreamprovider.cpp new file mode 100644 index 00000000..55d282b3 --- /dev/null +++ b/LEGO1/omni/src/stream/mxramstreamprovider.cpp @@ -0,0 +1,162 @@ +#include "mxramstreamprovider.h" + +#include "decomp.h" +#include "mxdsbuffer.h" +#include "mxdsfile.h" +#include "mxomni.h" +#include "mxstreamcontroller.h" + +DECOMP_SIZE_ASSERT(MxRAMStreamProvider, 0x24); + +// FUNCTION: LEGO1 0x100d0730 +MxRAMStreamProvider::MxRAMStreamProvider() +{ + m_bufferSize = 0; + m_fileSize = 0; + m_pBufferOfFileSize = NULL; + m_lengthInDWords = 0; + m_bufferForDWords = NULL; +} + +// FUNCTION: LEGO1 0x100d0930 +MxU32 MxRAMStreamProvider::GetFileSize() +{ + return m_fileSize; +} + +// FUNCTION: LEGO1 0x100d0940 +MxS32 MxRAMStreamProvider::GetStreamBuffersNum() +{ + return 1; +} + +// FUNCTION: LEGO1 0x100d0950 +MxU32 MxRAMStreamProvider::GetLengthInDWords() +{ + return m_lengthInDWords; +} + +// FUNCTION: LEGO1 0x100d0960 +MxU32* MxRAMStreamProvider::GetBufferForDWords() +{ + return m_bufferForDWords; +} + +// FUNCTION: LEGO1 0x100d0a50 +MxRAMStreamProvider::~MxRAMStreamProvider() +{ + m_bufferSize = 0; + m_fileSize = 0; + + delete[] m_pBufferOfFileSize; + m_pBufferOfFileSize = NULL; + + m_lengthInDWords = 0; + + delete[] m_bufferForDWords; + m_bufferForDWords = NULL; +} + +// FUNCTION: LEGO1 0x100d0ae0 +MxResult MxRAMStreamProvider::SetResourceToGet(MxStreamController* p_resource) +{ + MxResult result = FAILURE; + MxString path; + m_pLookup = p_resource; + + path = (MxString(MxOmni::GetHD()) + p_resource->GetAtom().GetInternal() + ".si"); + + m_pFile = new MxDSFile(path.GetData(), 0); + if (m_pFile != NULL) { + if (m_pFile->Open(0) != 0) { + path = MxString(MxOmni::GetCD()) + p_resource->GetAtom().GetInternal() + ".si"; + m_pFile->SetFileName(path.GetData()); + + if (m_pFile->Open(0) != 0) { + goto done; + } + } + + m_fileSize = m_pFile->CalcFileSize(); + if (m_fileSize != 0) { + m_bufferSize = m_pFile->GetBufferSize(); + m_pBufferOfFileSize = new MxU8[m_fileSize]; + if (m_pBufferOfFileSize != NULL && + m_pFile->Read((unsigned char*) m_pBufferOfFileSize, m_fileSize) == SUCCESS) { + m_lengthInDWords = m_pFile->GetLengthInDWords(); + m_bufferForDWords = new MxU32[m_lengthInDWords]; + + if (m_bufferForDWords != NULL) { + memcpy(m_bufferForDWords, m_pFile->GetBuffer(), m_lengthInDWords * sizeof(MxU32)); + result = SUCCESS; + } + } + } + } + +done: + delete m_pFile; + m_pFile = NULL; + return result; +} + +// FUNCTION: LEGO1 0x100d0d80 +MxU32 ReadData(MxU8* p_buffer, MxU32 p_size) +{ + MxU32 id; + MxU8* data = p_buffer; + MxU8* end = p_buffer + p_size; + MxU8* data2; + + if (p_buffer < end) { + do { + if (*MxDSChunk::IntoType(data) == FOURCC('M', 'x', 'O', 'b')) { + data2 = data; + data += 8; + + MxDSObject* obj = DeserializeDSObjectDispatch(data, -1); + id = obj->GetObjectId(); + delete obj; + + data = MxDSChunk::End(data2); + while (data < end) { + if (*MxDSChunk::IntoType(data) == FOURCC('M', 'x', 'C', 'h')) { + MxU8* data3 = data; + MxU32* psize = MxDSChunk::IntoLength(data); + data += MxDSChunk::Size(*psize); + + if ((*MxDSChunk::IntoType(data2) == FOURCC('M', 'x', 'C', 'h')) && + (*MxStreamChunk::IntoFlags(data2) & DS_CHUNK_SPLIT)) { + if (*MxStreamChunk::IntoObjectId(data2) == *MxStreamChunk::IntoObjectId(data3) && + (*MxStreamChunk::IntoFlags(data3) & DS_CHUNK_SPLIT) && + *MxStreamChunk::IntoTime(data2) == *MxStreamChunk::IntoTime(data3)) { + MxDSBuffer::Append(data2, data3); + continue; + } + else { + *MxStreamChunk::IntoFlags(data2) &= ~DS_CHUNK_SPLIT; + } + } + + data2 += MxDSChunk::Size(*MxDSChunk::IntoLength(data2)); + memcpy(data2, data3, MxDSChunk::Size(*psize)); + + if (*MxStreamChunk::IntoObjectId(data2) == id && + (*MxStreamChunk::IntoFlags(data2) & DS_CHUNK_END_OF_STREAM)) { + break; + } + } + else { + data++; + } + } + } + else { + data++; + } + } while (data < end); + } + + *MxStreamChunk::IntoFlags(data2) &= ~DS_CHUNK_SPLIT; + return MxDSChunk::End(data2) - p_buffer; +} diff --git a/LEGO1/omni/src/stream/mxstreamchunk.cpp b/LEGO1/omni/src/stream/mxstreamchunk.cpp new file mode 100644 index 00000000..98503096 --- /dev/null +++ b/LEGO1/omni/src/stream/mxstreamchunk.cpp @@ -0,0 +1,106 @@ +#include "mxstreamchunk.h" + +#include "mxdsbuffer.h" +#include "mxstreamlist.h" +#include "mxutilities.h" + +// FUNCTION: LEGO1 0x100c2fe0 +MxStreamChunk::~MxStreamChunk() +{ + if (m_buffer) { + m_buffer->ReleaseRef(this); + } +} + +// FUNCTION: LEGO1 0x100c3050 +MxResult MxStreamChunk::ReadChunk(MxDSBuffer* p_buffer, MxU8* p_chunkData) +{ + MxResult result = FAILURE; + + if (p_chunkData != NULL && *(MxU32*) p_chunkData == FOURCC('M', 'x', 'C', 'h')) { + if (ReadChunkHeader(p_chunkData + 8)) { + if (p_buffer) { + SetBuffer(p_buffer); + p_buffer->AddRef(this); + } + result = SUCCESS; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100c30a0 +MxU32 MxStreamChunk::ReadChunkHeader(MxU8* p_chunkData) +{ + MxU32 headersize = 0; + if (p_chunkData) { + MxU8* chunkData = p_chunkData; + + memcpy(&m_flags, p_chunkData, sizeof(m_flags)); + p_chunkData += sizeof(m_flags); + + memcpy(&m_objectId, p_chunkData, sizeof(m_objectId)); + p_chunkData += sizeof(m_objectId); + + memcpy(&m_time, p_chunkData, sizeof(m_time)); + p_chunkData += sizeof(m_time); + + memcpy(&m_length, p_chunkData, sizeof(m_length)); + p_chunkData += sizeof(m_length); + + m_data = p_chunkData; + headersize = p_chunkData - chunkData; + } + + return headersize; +} + +// FUNCTION: LEGO1 0x100c30e0 +MxResult MxStreamChunk::SendChunk(MxStreamListMxDSSubscriber& p_subscriberList, MxBool p_append, MxS16 p_obj24val) +{ + for (MxStreamListMxDSSubscriber::iterator it = p_subscriberList.begin(); it != p_subscriberList.end(); it++) { + if ((*it)->GetObjectId() == m_objectId && (*it)->GetUnknown48() == p_obj24val) { + if (m_flags & DS_CHUNK_END_OF_STREAM && m_buffer) { + m_buffer->ReleaseRef(this); + m_buffer = NULL; + } + + (*it)->AddData(this, p_append); + + return SUCCESS; + } + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x100c3170 +void MxStreamChunk::SetBuffer(MxDSBuffer* p_buffer) +{ + m_buffer = p_buffer; +} + +// FUNCTION: LEGO1 0x100c3180 +MxU16* MxStreamChunk::IntoFlags(MxU8* p_buffer) +{ + return (MxU16*) (p_buffer + 0x08); +} + +// FUNCTION: LEGO1 0x100c3190 +MxU32* MxStreamChunk::IntoObjectId(MxU8* p_buffer) +{ + return (MxU32*) (p_buffer + 0x0a); +} + +// FUNCTION: LEGO1 0x100c31a0 +MxLong* MxStreamChunk::IntoTime(MxU8* p_buffer) +{ + return (MxLong*) (p_buffer + 0x0e); +} + +// FUNCTION: LEGO1 0x100c31b0 +MxU32* MxStreamChunk::IntoLength(MxU8* p_buffer) +{ + return (MxU32*) (p_buffer + 0x12); +} diff --git a/LEGO1/omni/src/stream/mxstreamcontroller.cpp b/LEGO1/omni/src/stream/mxstreamcontroller.cpp new file mode 100644 index 00000000..88db08d6 --- /dev/null +++ b/LEGO1/omni/src/stream/mxstreamcontroller.cpp @@ -0,0 +1,335 @@ +#include "mxstreamcontroller.h" + +#include "mxautolock.h" +#include "mxdsmultiaction.h" +#include "mxdsstreamingaction.h" +#include "mxmisc.h" +#include "mxnextactiondatastart.h" +#include "mxstl/stlcompat.h" +#include "mxstreamchunk.h" +#include "mxstreamprovider.h" +#include "mxtimer.h" +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(MxStreamController, 0x64) +DECOMP_SIZE_ASSERT(MxNextActionDataStart, 0x14) + +// FUNCTION: LEGO1 0x100b9400 +MxResult MxStreamController::VTable0x18(undefined4, undefined4) +{ + return FAILURE; +} + +// FUNCTION: LEGO1 0x100b9410 +MxResult MxStreamController::VTable0x1c(undefined4, undefined4) +{ + return FAILURE; +} + +// FUNCTION: LEGO1 0x100b9420 +MxDSStreamingAction* MxStreamController::VTable0x28() +{ + return NULL; +} + +// FUNCTION: LEGO1 0x100c0b90 +MxStreamController::MxStreamController() +{ + m_provider = NULL; + m_unk0x2c = NULL; + m_action0x60 = NULL; +} + +// FUNCTION: LEGO1 0x100c1290 +MxStreamController::~MxStreamController() +{ + AUTOLOCK(m_criticalSection); + + MxDSSubscriber* subscriber; + while (m_subscriberList.PopFront(subscriber)) { + delete subscriber; + } + + MxDSAction* action; + while (m_unk0x3c.PopFront(action)) { + delete action; + } + + if (m_provider) { + MxStreamProvider* provider = m_provider; + m_provider = NULL; +#ifdef COMPAT_MODE + { + MxDSAction action; + provider->VTable0x20(&action); + } +#else + provider->VTable0x20(&MxDSAction()); +#endif + delete provider; + } + + if (m_unk0x2c) { + delete m_unk0x2c; + m_unk0x2c = NULL; + } + + while (m_unk0x54.PopFront(action)) { + delete action; + } +} + +// FUNCTION: LEGO1 0x100c1520 +MxResult MxStreamController::Open(const char* p_filename) +{ + char sourceName[256]; + AUTOLOCK(m_criticalSection); + + MakeSourceName(sourceName, p_filename); + this->m_atom = MxAtomId(sourceName, e_lowerCase2); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c15d0 +void MxStreamController::AddSubscriber(MxDSSubscriber* p_subscriber) +{ + m_subscriberList.push_back(p_subscriber); +} + +// FUNCTION: LEGO1 0x100c1620 +void MxStreamController::RemoveSubscriber(MxDSSubscriber* p_subscriber) +{ + m_subscriberList.remove(p_subscriber); +} + +// FUNCTION: LEGO1 0x100c1690 +MxResult MxStreamController::VTable0x20(MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + + MxResult result; + MxU32 offset = 0; + + MxS32 objectId = p_action->GetObjectId(); + MxStreamProvider* provider = m_provider; + + if ((MxS32) provider->GetLengthInDWords() > objectId) { + offset = provider->GetBufferForDWords()[objectId]; + } + + if (offset) { + result = VTable0x2c(p_action, offset); + } + else { + result = FAILURE; + } + + return result; +} + +// FUNCTION: LEGO1 0x100c1740 +MxResult MxStreamController::VTable0x24(MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + VTable0x30(p_action); + m_action0x60 = m_unk0x54.Find(p_action, TRUE); + if (m_action0x60 == NULL) { + return FAILURE; + } + else { + p_action->SetUnknown24(m_action0x60->GetUnknown24()); + p_action->SetObjectId(m_action0x60->GetObjectId()); + return FUN_100c1f00(m_action0x60); + } +} + +// FUNCTION: LEGO1 0x100c1800 +MxResult MxStreamController::FUN_100c1800(MxDSAction* p_action, MxU32 p_val) +{ + MxNextActionDataStart* dataActionStart = + new MxNextActionDataStart(p_action->GetObjectId(), p_action->GetUnknown24(), p_val); + if (dataActionStart == NULL) { + return FAILURE; + } + + m_nextActionList.push_back(dataActionStart); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c1a00 +MxResult MxStreamController::FUN_100c1a00(MxDSAction* p_action, MxU32 p_offset) +{ + if (p_action->GetUnknown24() == -1) { + MxS16 newUnknown24 = -1; + + // These loops might be a template function in the list classes + for (MxStreamListMxDSAction::iterator it = m_unk0x54.begin(); it != m_unk0x54.end(); it++) { + MxDSAction* action = *it; + + if (action->GetObjectId() == p_action->GetObjectId()) { + newUnknown24 = Max(newUnknown24, action->GetUnknown24()); + } + } + + if (newUnknown24 == -1) { + for (MxStreamListMxDSAction::iterator it = m_unk0x3c.begin(); it != m_unk0x3c.end(); it++) { + MxDSAction* action = *it; + + if (action->GetObjectId() == p_action->GetObjectId()) { + newUnknown24 = Max(newUnknown24, action->GetUnknown24()); + } + } + + if (newUnknown24 == -1) { + for (MxStreamListMxDSSubscriber::iterator it = m_subscriberList.begin(); it != m_subscriberList.end(); + it++) { + MxDSSubscriber* subscriber = *it; + + if (subscriber->GetObjectId() == p_action->GetObjectId()) { + newUnknown24 = Max(newUnknown24, subscriber->GetUnknown48()); + } + } + } + } + + p_action->SetUnknown24(newUnknown24 + 1); + } + else { + if (m_unk0x3c.Find(p_action, FALSE)) { + return FAILURE; + } + } + + MxDSStreamingAction* streamingAction = new MxDSStreamingAction(*p_action, p_offset); + + if (!streamingAction) { + return FAILURE; + } + + MxU32 fileSize = m_provider->GetFileSize(); + streamingAction->SetBufferOffset(fileSize * (p_offset / fileSize)); + streamingAction->SetObjectId(p_action->GetObjectId()); + + MxLong time = Timer()->GetTime(); + streamingAction->SetUnknown90(time); + + m_unk0x3c.push_back(streamingAction); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c1c10 +MxResult MxStreamController::VTable0x2c(MxDSAction* p_action, MxU32 p_bufferval) +{ + AUTOLOCK(m_criticalSection); + if (FUN_100c1a00(p_action, p_bufferval) != SUCCESS) { + return FAILURE; + } + return FUN_100c1800(p_action, (p_bufferval / m_provider->GetFileSize()) * m_provider->GetFileSize()); +} + +// FUNCTION: LEGO1 0x100c1ce0 +MxResult MxStreamController::VTable0x30(MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + MxResult result = FAILURE; + MxDSAction* action = m_unk0x3c.Find(p_action, TRUE); + if (action != NULL) { + MxNextActionDataStart* data = m_nextActionList.FindAndErase(action->GetObjectId(), action->GetUnknown24()); + delete action; + delete data; + result = SUCCESS; + } + return result; +} + +// FUNCTION: LEGO1 0x100c1da0 +MxResult MxStreamController::InsertActionToList54(MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + MxDSAction* action = p_action->Clone(); + + if (action == NULL) { + return FAILURE; + } + else { + m_unk0x54.push_back(action); + return SUCCESS; + } +} + +// FUNCTION: LEGO1 0x100c1e70 +MxPresenter* MxStreamController::FUN_100c1e70(MxDSAction& p_action) +{ + AUTOLOCK(m_criticalSection); + MxPresenter* result = NULL; + if (p_action.GetObjectId() != -1) { + MxDSAction* action = m_unk0x3c.Find(&p_action, FALSE); + if (action != NULL) { + result = action->GetUnknown28(); + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100c1f00 +MxResult MxStreamController::FUN_100c1f00(MxDSAction* p_action) +{ + AUTOLOCK(m_criticalSection); + + MxU32 objectId = p_action->GetObjectId(); + MxStreamChunk* chunk = new MxStreamChunk; + + if (!chunk) { + return FAILURE; + } + + chunk->SetChunkFlags(DS_CHUNK_BIT3); + chunk->SetObjectId(objectId); + + if (chunk->SendChunk(m_subscriberList, FALSE, p_action->GetUnknown24()) != SUCCESS) { + delete chunk; + } + + if (p_action->IsA("MxDSMultiAction")) { + MxDSActionList* actions = ((MxDSMultiAction*) p_action)->GetActionList(); + MxDSActionListCursor cursor(actions); + MxDSAction* action; + + while (cursor.Next(action)) { + if (FUN_100c1f00(action) != SUCCESS) { + return FAILURE; + } + } + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c20b0 +MxNextActionDataStart* MxStreamController::FindNextActionDataStartFromStreamingAction(MxDSStreamingAction* p_action) +{ + return m_nextActionList.Find(p_action->GetObjectId(), p_action->GetUnknown24()); +} + +// FUNCTION: LEGO1 0x100c20d0 +MxBool MxStreamController::FUN_100c20d0(MxDSObject& p_obj) +{ + if (m_subscriberList.Find(&p_obj)) { + return FALSE; + } + + if (p_obj.IsA("MxDSMultiAction")) { + MxDSActionList* actions = ((MxDSMultiAction&) p_obj).GetActionList(); + MxDSActionListCursor cursor(actions); + MxDSAction* action; + + while (cursor.Next(action)) { + if (!FUN_100c20d0(*action)) { + return FALSE; + } + } + } + + return TRUE; +} diff --git a/LEGO1/omni/src/stream/mxstreamer.cpp b/LEGO1/omni/src/stream/mxstreamer.cpp new file mode 100644 index 00000000..d86e87ef --- /dev/null +++ b/LEGO1/omni/src/stream/mxstreamer.cpp @@ -0,0 +1,205 @@ +#include "mxstreamer.h" + +#include "mxdiskstreamcontroller.h" +#include "mxmisc.h" +#include "mxnotificationmanager.h" +#include "mxramstreamcontroller.h" + +#include + +DECOMP_SIZE_ASSERT(MxStreamer, 0x2c); +DECOMP_SIZE_ASSERT(MxMemoryPool64, 0x0c); +DECOMP_SIZE_ASSERT(MxMemoryPool128, 0x0c); +DECOMP_SIZE_ASSERT(MxBitset<22>, 0x04); +DECOMP_SIZE_ASSERT(MxBitset<2>, 0x04); + +// FUNCTION: LEGO1 0x100b8f00 +MxStreamer::MxStreamer() +{ + NotificationManager()->Register(this); +} + +// FUNCTION: LEGO1 0x100b9190 +MxResult MxStreamer::Create() +{ + if (m_pool64.Allocate() || m_pool128.Allocate()) { + return FAILURE; + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b91d0 +MxStreamer::~MxStreamer() +{ + while (!m_openStreams.empty()) { + MxStreamController* c = m_openStreams.front(); + m_openStreams.pop_front(); + delete c; + } + + NotificationManager()->Unregister(this); +} + +// FUNCTION: LEGO1 0x100b92c0 +MxStreamController* MxStreamer::Open(const char* p_name, MxU16 p_lookupType) +{ + MxStreamController* stream = NULL; + + if (!GetOpenStream(p_name)) { + switch (p_lookupType) { + case e_diskStream: + stream = new MxDiskStreamController(); + break; + case e_RAMStream: + stream = new MxRAMStreamController(); + break; + } + + if (stream && (stream->Open(p_name) != SUCCESS || AddStreamControllerToOpenList(stream) != SUCCESS)) { + delete stream; + stream = NULL; + } + } + + return stream; +} + +// FUNCTION: LEGO1 0x100b9570 +MxLong MxStreamer::Close(const char* p_name) +{ + MxDSAction ds; + ds.SetUnknown24(-2); + + for (list::iterator it = m_openStreams.begin(); it != m_openStreams.end(); it++) { + MxStreamController* c = *it; + + if (!p_name || !strcmp(p_name, c->GetAtom().GetInternal())) { + m_openStreams.erase(it); + + if (c->FUN_100c20d0(ds)) { + delete c; + } + else { + NotificationManager()->Send(this, MxStreamerNotification(c_notificationStreamer, NULL, c)); + } + + return SUCCESS; + } + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x100b9700 +MxNotificationParam* MxStreamerNotification::Clone() const +{ + return new MxStreamerNotification(m_type, m_sender, m_controller); +} + +// FUNCTION: LEGO1 0x100b9870 +MxStreamController* MxStreamer::GetOpenStream(const char* p_name) +{ + for (list::iterator it = m_openStreams.begin(); it != m_openStreams.end(); it++) { + MxStreamController* c = *it; + MxAtomId& atom = c->GetAtom(); + if (p_name) { + if (!strcmp(atom.GetInternal(), p_name)) { + return *it; + } + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x100b98f0 +void MxStreamer::FUN_100b98f0(MxDSAction* p_action) +{ + MxStreamController* controller = GetOpenStream(p_action->GetAtomId().GetInternal()); + if (controller && controller->IsA("MxDiskStreamController")) { + ((MxDiskStreamController*) controller)->FUN_100c8120(p_action); + } +} + +// FUNCTION: LEGO1 0x100b9930 +MxResult MxStreamer::AddStreamControllerToOpenList(MxStreamController* p_stream) +{ + if (find(m_openStreams.begin(), m_openStreams.end(), p_stream) == m_openStreams.end()) { + m_openStreams.push_back(p_stream); + return SUCCESS; + } + + return FAILURE; +} + +// FUNCTION: LEGO1 0x100b99b0 +MxResult MxStreamer::FUN_100b99b0(MxDSAction* p_action) +{ + MxStreamController* controller; + if (p_action != NULL && p_action->GetAtomId().GetInternal() != NULL && p_action->GetObjectId() != -1) { + controller = GetOpenStream(p_action->GetAtomId().GetInternal()); + if (controller == NULL) { + return FAILURE; + } + return controller->VTable0x20(p_action); + } + return FAILURE; +} + +// FUNCTION: LEGO1 0x100b99f0 +MxResult MxStreamer::DeleteObject(MxDSAction* p_dsAction) +{ + MxDSAction tempAction; + + if (p_dsAction == NULL) { + tempAction.SetUnknown24(-2); + } + else { + tempAction.SetObjectId(p_dsAction->GetObjectId()); + tempAction.SetAtomId(p_dsAction->GetAtomId()); + tempAction.SetUnknown24(p_dsAction->GetUnknown24()); + } + + MxResult result = FAILURE; + for (list::iterator it = m_openStreams.begin(); it != m_openStreams.end(); it++) { + const char* id = p_dsAction->GetAtomId().GetInternal(); + if (!id || id == (*it)->GetAtom().GetInternal()) { + tempAction.SetAtomId((*it)->GetAtom()); + result = (*it)->VTable0x24(&tempAction); + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100b9b30 +MxBool MxStreamer::FUN_100b9b30(MxDSObject& p_dsObject) +{ + MxStreamController* controller = GetOpenStream(p_dsObject.GetAtomId().GetInternal()); + if (controller) { + return controller->FUN_100c20d0(p_dsObject); + } + return TRUE; +} + +// FUNCTION: LEGO1 0x100b9b60 +MxLong MxStreamer::Notify(MxParam& p_param) +{ + if (((MxNotificationParam&) p_param).GetNotification() == c_notificationStreamer) { + MxDSAction ds; + + ds.SetUnknown24(-2); + + MxStreamController* c = static_cast(p_param).GetController(); + + if (c->FUN_100c20d0(ds)) { + delete c; + } + else { + NotificationManager()->Send(this, MxStreamerNotification(c_notificationStreamer, NULL, c)); + } + } + + return 0; +} diff --git a/LEGO1/omni/src/stream/mxstreamlist.cpp b/LEGO1/omni/src/stream/mxstreamlist.cpp new file mode 100644 index 00000000..effa987a --- /dev/null +++ b/LEGO1/omni/src/stream/mxstreamlist.cpp @@ -0,0 +1,79 @@ +#include "mxstreamlist.h" + +// Wrappers around STL list that are used by the MxStream* classes. +DECOMP_SIZE_ASSERT(MxStreamListMxDSAction, 0x0c); +DECOMP_SIZE_ASSERT(MxStreamListMxNextActionDataStart, 0x0c); +DECOMP_SIZE_ASSERT(MxStreamListMxDSSubscriber, 0x0c); + +// FUNCTION: LEGO1 0x100b8450 +MxDSSubscriber* MxStreamListMxDSSubscriber::Find(MxDSObject* p_object) +{ + for (iterator it = begin(); it != end(); it++) { + if (p_object->GetObjectId() == -1 || p_object->GetObjectId() == (*it)->GetObjectId()) { + if (p_object->GetUnknown24() == -2 || p_object->GetUnknown24() == (*it)->GetUnknown48()) { + return *it; + } + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x100bfa80 +MxDSAction* MxStreamListMxDSAction::Find(MxDSAction* p_action, MxBool p_delete) +{ + // DECOMP ALPHA 0x1008b99d ? + + MxDSAction* found = NULL; + +#ifdef COMPAT_MODE + iterator it; + for (it = begin(); it != end(); it++) { +#else + for (iterator it = begin(); it != end(); it++) { +#endif + if (p_action->GetObjectId() == -1 || p_action->GetObjectId() == (*it)->GetObjectId()) { + if (p_action->GetUnknown24() == -2 || p_action->GetUnknown24() == -3 || + p_action->GetUnknown24() == (*it)->GetUnknown24()) { + found = *it; + if (p_action->GetUnknown24() != -3) { + break; + } + } + } + } + + if (p_delete && found != NULL) { + erase(it); + } + + return found; +} + +// FUNCTION: LEGO1 0x100c21e0 +MxNextActionDataStart* MxStreamListMxNextActionDataStart::Find(MxU32 p_id, MxS16 p_value) +{ + for (iterator it = begin(); it != end(); it++) { + if (p_id == (*it)->GetObjectId() && p_value == (*it)->GetUnknown24()) { + return *it; + } + } + + return NULL; +} + +// FUNCTION: LEGO1 0x100c2240 +MxNextActionDataStart* MxStreamListMxNextActionDataStart::FindAndErase(MxU32 p_id, MxS16 p_value) +{ + MxNextActionDataStart* match = NULL; + + for (iterator it = begin(); it != end(); it++) { + if (p_id == (*it)->GetObjectId() && (p_value == -2 || p_value == (*it)->GetUnknown24())) { + match = *it; + erase(it); + break; + } + } + + return match; +} diff --git a/LEGO1/omni/src/stream/mxstreamprovider.cpp b/LEGO1/omni/src/stream/mxstreamprovider.cpp new file mode 100644 index 00000000..740b2c65 --- /dev/null +++ b/LEGO1/omni/src/stream/mxstreamprovider.cpp @@ -0,0 +1,17 @@ +#include "mxstreamprovider.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxStreamProvider, 0x10); + +// FUNCTION: LEGO1 0x100d07c0 +MxResult MxStreamProvider::SetResourceToGet(MxStreamController* p_resource) +{ + m_pLookup = p_resource; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100d07d0 +void MxStreamProvider::VTable0x20(MxDSAction* p_action) +{ +} diff --git a/LEGO1/omni/src/system/mxautolock.cpp b/LEGO1/omni/src/system/mxautolock.cpp new file mode 100644 index 00000000..a67c382c --- /dev/null +++ b/LEGO1/omni/src/system/mxautolock.cpp @@ -0,0 +1,20 @@ +#include "mxautolock.h" + +#include "mxcriticalsection.h" + +// FUNCTION: LEGO1 0x100b8ed0 +MxAutoLock::MxAutoLock(MxCriticalSection* p_criticalSection) +{ + this->m_criticalSection = p_criticalSection; + if (this->m_criticalSection != 0) { + this->m_criticalSection->Enter(); + } +} + +// FUNCTION: LEGO1 0x100b8ef0 +MxAutoLock::~MxAutoLock() +{ + if (this->m_criticalSection != 0) { + this->m_criticalSection->Leave(); + } +} diff --git a/LEGO1/omni/src/system/mxcriticalsection.cpp b/LEGO1/omni/src/system/mxcriticalsection.cpp new file mode 100644 index 00000000..1038f7ad --- /dev/null +++ b/LEGO1/omni/src/system/mxcriticalsection.cpp @@ -0,0 +1,76 @@ +#include "mxcriticalsection.h" + +#include "decomp.h" + +#include + +DECOMP_SIZE_ASSERT(MxCriticalSection, 0x1c); + +// GLOBAL: LEGO1 0x10101e78 +int g_useMutex = 0; + +// FUNCTION: LEGO1 0x100b6d20 +MxCriticalSection::MxCriticalSection() +{ + HANDLE mutex; + + if (g_useMutex != 0) { + mutex = CreateMutexA(NULL, FALSE, NULL); + this->m_mutex = mutex; + return; + } + + InitializeCriticalSection(&this->m_criticalSection); + this->m_mutex = NULL; +} + +// FUNCTION: LEGO1 0x100b6d60 +MxCriticalSection::~MxCriticalSection() +{ + if (this->m_mutex != NULL) { + CloseHandle(this->m_mutex); + return; + } + + DeleteCriticalSection(&this->m_criticalSection); +} + +// FUNCTION: LEGO1 0x100b6d80 +void MxCriticalSection::Enter() +{ + DWORD result; + FILE* file; + + if (this->m_mutex != NULL) { + result = WaitForSingleObject(this->m_mutex, 5000); + if (result == WAIT_FAILED) { + file = fopen("C:\\DEADLOCK.TXT", "a"); + if (file != NULL) { + fprintf(file, "mutex timeout occurred!\n"); + fclose(file); + } + + abort(); + } + } + else { + EnterCriticalSection(&this->m_criticalSection); + } +} + +// FUNCTION: LEGO1 0x100b6de0 +void MxCriticalSection::Leave() +{ + if (this->m_mutex != NULL) { + ReleaseMutex(this->m_mutex); + return; + } + + LeaveCriticalSection(&this->m_criticalSection); +} + +// FUNCTION: LEGO1 0x100b6e00 +void MxCriticalSection::SetDoMutex() +{ + g_useMutex = 1; +} diff --git a/LEGO1/omni/src/system/mxscheduler.cpp b/LEGO1/omni/src/system/mxscheduler.cpp new file mode 100644 index 00000000..0703782f --- /dev/null +++ b/LEGO1/omni/src/system/mxscheduler.cpp @@ -0,0 +1,14 @@ +#include "mxscheduler.h" + +// FUNCTION: LEGO1 0x100bf4f0 +MxScheduler* MxScheduler::GetInstance() +{ + // Intentionally empty + return 0; +} + +// FUNCTION: LEGO1 0x100bf500 +void MxScheduler::StartMultiTasking(MxULong) +{ + // Intentionally empty +} diff --git a/LEGO1/omni/src/system/mxsemaphore.cpp b/LEGO1/omni/src/system/mxsemaphore.cpp new file mode 100644 index 00000000..daba60f4 --- /dev/null +++ b/LEGO1/omni/src/system/mxsemaphore.cpp @@ -0,0 +1,34 @@ + +#include "mxsemaphore.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxSemaphore, 0x08) + +// FUNCTION: LEGO1 0x100c87d0 +MxSemaphore::MxSemaphore() +{ + m_hSemaphore = NULL; +} + +// FUNCTION: LEGO1 0x100c8800 +MxResult MxSemaphore::Init(MxU32 p_initialCount, MxU32 p_maxCount) +{ + MxResult result = FAILURE; + if ((m_hSemaphore = CreateSemaphoreA(NULL, p_initialCount, p_maxCount, NULL))) { + result = SUCCESS; + } + return result; +} + +// FUNCTION: LEGO1 0x100c8830 +void MxSemaphore::Wait(MxU32 p_timeoutMS) +{ + WaitForSingleObject(m_hSemaphore, p_timeoutMS); +} + +// FUNCTION: LEGO1 0x100c8850 +void MxSemaphore::Release(MxU32 p_releaseCount) +{ + ReleaseSemaphore(m_hSemaphore, p_releaseCount, NULL); +} diff --git a/LEGO1/omni/src/system/mxthread.cpp b/LEGO1/omni/src/system/mxthread.cpp new file mode 100644 index 00000000..fe327f2d --- /dev/null +++ b/LEGO1/omni/src/system/mxthread.cpp @@ -0,0 +1,98 @@ +#include "mxthread.h" + +#include "decomp.h" +#include "mxmisc.h" +#include "mxtimer.h" + +#include + +DECOMP_SIZE_ASSERT(MxThread, 0x1c) +DECOMP_SIZE_ASSERT(MxTickleThread, 0x20) + +// FUNCTION: LEGO1 0x100b8bb0 +MxTickleThread::MxTickleThread(MxCore* p_target, MxS32 p_frequencyMS) +{ + m_target = p_target; + m_frequencyMS = p_frequencyMS; +} + +// Match except for register allocation +// FUNCTION: LEGO1 0x100b8c90 +MxResult MxTickleThread::Run() +{ + MxTimer* timer = Timer(); + MxS32 lastTickled = -m_frequencyMS; + while (IsRunning()) { + MxLong currentTime = timer->GetTime(); + + if (currentTime < lastTickled) { + lastTickled = -m_frequencyMS; + } + + MxS32 timeRemainingMS = (m_frequencyMS - currentTime) + lastTickled; + if (timeRemainingMS <= 0) { + m_target->Tickle(); + timeRemainingMS = 0; + lastTickled = currentTime; + } + Sleep(timeRemainingMS); + } + return MxThread::Run(); +} + +// FUNCTION: LEGO1 0x100bf510 +MxThread::MxThread() +{ + m_hThread = NULL; + m_running = TRUE; + m_threadId = 0; +} + +// FUNCTION: LEGO1 0x100bf5a0 +MxThread::~MxThread() +{ + if (m_hThread) { + CloseHandle((HANDLE) m_hThread); + } +} + +typedef unsigned(__stdcall* ThreadFunc)(void*); + +// FUNCTION: LEGO1 0x100bf610 +MxResult MxThread::Start(MxS32 p_stack, MxS32 p_flag) +{ + MxResult result = FAILURE; + if (m_semaphore.Init(0, 1) == SUCCESS) { + if ((m_hThread = + _beginthreadex(NULL, p_stack << 2, (ThreadFunc) &MxThread::ThreadProc, this, p_flag, &m_threadId))) { + result = SUCCESS; + } + } + return result; +} + +// FUNCTION: LEGO1 0x100bf660 +void MxThread::Sleep(MxS32 p_milliseconds) +{ + ::Sleep(p_milliseconds); +} + +// FUNCTION: LEGO1 0x100bf670 +void MxThread::Terminate() +{ + m_running = FALSE; + m_semaphore.Wait(INFINITE); +} + +// FUNCTION: LEGO1 0x100bf680 +unsigned MxThread::ThreadProc(void* p_thread) +{ + return static_cast(p_thread)->Run(); +} + +// FUNCTION: LEGO1 0x100bf690 +MxResult MxThread::Run() +{ + m_semaphore.Release(1); + return SUCCESS; +} diff --git a/LEGO1/omni/src/video/flic.cpp b/LEGO1/omni/src/video/flic.cpp new file mode 100644 index 00000000..f15f406c --- /dev/null +++ b/LEGO1/omni/src/video/flic.cpp @@ -0,0 +1,432 @@ +#include "flic.h" + +DECOMP_SIZE_ASSERT(FLIC_CHUNK, 0x06) +DECOMP_SIZE_ASSERT(FLIC_HEADER, 0x14) +DECOMP_SIZE_ASSERT(FLIC_FRAME, 0x10) + +void WritePixel(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, short p_column, short p_row, byte p_pixel); +void WritePixels( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + short p_column, + short p_row, + BYTE* p_data, + short p_count +); +int ClampLine(LPBITMAPINFOHEADER p_bitmapHeader, short& p_column, short& p_row, short& p_count); +void WritePixelRun( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + short p_column, + short p_row, + byte p_pixel, + short p_count +); +void WritePixelPairs( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + short p_column, + short p_row, + WORD p_pixel, + short p_count +); +short DecodeChunks( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + FLIC_HEADER* p_flcHeader, + FLIC_FRAME* p_flcFrame, + BYTE* p_flcSubchunks, + BYTE* p_decodedColorMap +); +void DecodeColors256(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_data); +void DecodeColorPackets(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_data); +void DecodeColorPacket(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_data, short p_index, WORD p_count); +void DecodeColors64(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_data); +void DecodeBrun(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader); +void DecodeLC(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader); +void DecodeSS2(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader); +void DecodeBlack(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader); +void DecodeCopy(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader); + +// FUNCTION: LEGO1 0x100bd530 +void WritePixel(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, short p_column, short p_row, byte p_pixel) +{ + if (p_column >= 0 && p_row >= 0 && p_column < p_bitmapHeader->biWidth && p_row < p_bitmapHeader->biHeight) { + *(((p_bitmapHeader->biWidth + 3) & -4) * p_row + p_column + p_pixelData) = p_pixel; + } +} + +// FUNCTION: LEGO1 0x100bd580 +void WritePixels( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + short p_column, + short p_row, + BYTE* p_data, + short p_count +) +{ + short col = p_column; + + if (ClampLine(p_bitmapHeader, p_column, p_row, p_count)) { + short offset = p_column - col; + BYTE* pixels = offset ? p_data + offset : p_data; + memcpy(((p_bitmapHeader->biWidth + 3) & -4) * p_row + p_column + p_pixelData, pixels, p_count); + } +} + +// FUNCTION: LEGO1 0x100bd600 +int ClampLine(LPBITMAPINFOHEADER p_bitmapHeader, short& p_column, short& p_row, short& p_count) +{ + short column = p_column; + short row = p_row; + short count = p_count; + short end = column + count; + int result; + + if (row < 0 || p_bitmapHeader->biHeight <= row || end < 0 || p_bitmapHeader->biWidth <= column) { + result = 0; + } + else { + if (column < 0) { + count += column; + p_count = end; + p_column = 0; + } + + if (p_bitmapHeader->biWidth < end) { + count -= end - p_bitmapHeader->biWidth; + p_count = count; + } + + if (count < 0) { + result = 0; + } + else { + result = 1; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100bd680 +void WritePixelRun( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + short p_column, + short p_row, + byte p_pixel, + short p_count +) +{ + short col = p_column; + + if (ClampLine(p_bitmapHeader, p_column, p_row, p_count)) { + BYTE* dst = ((p_bitmapHeader->biWidth + 3) & -4) * p_row + p_column + p_pixelData; + + while (--p_count >= 0) { + *dst++ = p_pixel; + } + } +} + +// FUNCTION: LEGO1 0x100bd6e0 +void WritePixelPairs( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + short p_column, + short p_row, + WORD p_pixel, + short p_count +) +{ + p_count <<= 1; + + if (ClampLine(p_bitmapHeader, p_column, p_row, p_count)) { + short odd = p_count & 1; + p_count >>= 1; + + WORD* dst = (WORD*) (((p_bitmapHeader->biWidth + 3) & -4) * p_row + p_column + p_pixelData); + while (--p_count >= 0) { + *dst++ = p_pixel; + } + + if (odd) { + *(BYTE*) dst = p_pixel; + } + } +} + +// FUNCTION: LEGO1 0x100bd760 +short DecodeChunks( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + FLIC_HEADER* p_flcHeader, + FLIC_FRAME* p_flcFrame, + BYTE* p_flcSubchunks, + BYTE* p_decodedColorMap +) +{ + *p_decodedColorMap = FALSE; + + for (short subchunk = 0; subchunk < (short) p_flcFrame->chunks; subchunk++) { + FLIC_CHUNK* chunk = (FLIC_CHUNK*) p_flcSubchunks; + p_flcSubchunks += chunk->size; + + switch (chunk->type) { + case FLI_CHUNK_COLOR256: + DecodeColors256(p_bitmapHeader, (BYTE*) (chunk + 1)); + *p_decodedColorMap = TRUE; + break; + case FLI_CHUNK_SS2: + DecodeSS2(p_bitmapHeader, p_pixelData, (BYTE*) (chunk + 1), p_flcHeader); + break; + case FLI_CHUNK_COLOR64: + DecodeColors64(p_bitmapHeader, (BYTE*) (chunk + 1)); + *p_decodedColorMap = TRUE; + break; + case FLI_CHUNK_LC: + DecodeLC(p_bitmapHeader, p_pixelData, (BYTE*) (chunk + 1), p_flcHeader); + break; + case FLI_CHUNK_BLACK: + DecodeBlack(p_bitmapHeader, p_pixelData, (BYTE*) (chunk + 1), p_flcHeader); + break; + case FLI_CHUNK_BRUN: + DecodeBrun(p_bitmapHeader, p_pixelData, (BYTE*) (chunk + 1), p_flcHeader); + break; + case FLI_CHUNK_COPY: + DecodeCopy(p_bitmapHeader, p_pixelData, (BYTE*) (chunk + 1), p_flcHeader); + break; + } + } + + return 0; +} + +// FUNCTION: LEGO1 0x100bd880 +void DecodeColors256(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_data) +{ + DecodeColorPackets(p_bitmapHeader, p_data); +} + +// FUNCTION: LEGO1 0x100bd8a0 +void DecodeColorPackets(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_data) +{ + WORD colorIndex = 0; + BYTE* colors = p_data + 2; + + for (short packet = *((short*) p_data) - 1; packet >= 0; packet--) { + colorIndex += colors[0]; + short colorCount = colors[1]; + + colors++; + colors++; + + if (!colorCount) { + colorCount = 256; + } + + DecodeColorPacket(p_bitmapHeader, colors, colorIndex, colorCount); + colorIndex += colorCount; + colors += colorCount * 3; + } +} + +// FUNCTION: LEGO1 0x100bd8f0 +void DecodeColorPacket(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_data, short index, WORD p_count) +{ + BYTE* palette = (BYTE*) p_bitmapHeader + p_bitmapHeader->biSize + index * 4; + + while (p_count-- > 0) { + palette[2] = p_data[0]; + palette[1] = p_data[1]; + palette[0] = p_data[2]; + + palette += 4; + p_data += 3; + } +} + +// FUNCTION: LEGO1 0x100bd940 +void DecodeColors64(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_data) +{ + DecodeColorPackets(p_bitmapHeader, p_data); +} + +// FUNCTION: LEGO1 0x100bd960 +void DecodeBrun(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader) +{ + BYTE* data = p_data; + short width = p_flcHeader->width; + short height = p_flcHeader->height; + BYTE* offset = ((p_bitmapHeader->biWidth + 3) & -4) * (height - 1) + p_pixelData; + + for (short line = height - 1; line >= 0; line--) { + data++; + + for (short pixel = 0; pixel < width;) { + char count = *data++; + + if (count >= 0) { + for (short i = 0; i < count; i++) { + *offset++ = *data; + } + + data++; + } + else { + count = -count; + for (short i = 0; i < count; i++) { + *offset++ = *data++; + } + } + + pixel += count; + } + + offset -= (((p_bitmapHeader->biWidth + 3) & -4) + width); + } +} + +// FUNCTION: LEGO1 0x100bda10 +void DecodeLC(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader) +{ + short row = (short) p_flcHeader->height - *((short*) p_data) - 1; + BYTE* data = p_data + 4; + + for (short lines = *((short*) (p_data + 2)) - 1; lines >= 0; lines--) { + WORD column = 0; + BYTE packets = *data++; + + for (BYTE i = 0; i < packets; i++) { + column += *data++; + char type = *((char*) data++); + + if (type < 0) { + type = -type; + WritePixelRun(p_bitmapHeader, p_pixelData, column, row, *data++, type); + column += type; + } + else { + WritePixels(p_bitmapHeader, p_pixelData, column, row, data, type); + data += type; + column += type; + } + } + + row--; + } +} + +// FUNCTION: LEGO1 0x100bdac0 +void DecodeSS2(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader) +{ + short width = (short) p_flcHeader->width - 1; + short row = (short) p_flcHeader->height - 1; + short lines = *((short*) p_data); + BYTE* data = p_data + 2; + + while (--lines > 0) { + short token; + + while (TRUE) { + token = *((short*) data); + data += 2; + + if (token < 0) { + if (token & 0x4000) { + row += token; + } + else { + WritePixel(p_bitmapHeader, p_pixelData, width, row, token); + token = *((WORD*) data); + data += 2; + + if (!token) { + row--; + if (--lines <= 0) { + return; + } + } + else { + break; + } + } + } + else { + break; + } + } + + short column = 0; + do { + column += *(data++); + short type = *((char*) data++); + type += type; + + if (type >= 0) { + WritePixels(p_bitmapHeader, p_pixelData, column, row, data, type); + column += type; + data += type; + } + else { + type = -type; + short p_pixel = *((WORD*) data); + data += 2; + WritePixelPairs(p_bitmapHeader, p_pixelData, column, row, p_pixel, type >> 1); + column += type; + } + } while (--token); + + row--; + } +} + +// FUNCTION: LEGO1 0x100bdc00 +void DecodeBlack(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader) +{ + short line = p_flcHeader->height; + short width = p_flcHeader->width; + + BYTE pixel[2]; + pixel[1] = 0; + pixel[0] = 0; + + while (--line >= 0) { + short count = width / 2; + short odd = width & 1; + + WritePixelPairs(p_bitmapHeader, p_pixelData, 0, line, *((WORD*) pixel), count); + + if (odd) { + WritePixel(p_bitmapHeader, p_pixelData, width - 1, line, 0); + } + } +} + +// FUNCTION: LEGO1 0x100bdc90 +void DecodeCopy(LPBITMAPINFOHEADER p_bitmapHeader, BYTE* p_pixelData, BYTE* p_data, FLIC_HEADER* p_flcHeader) +{ + short line = p_flcHeader->height; + short width = p_flcHeader->width; + + while (--line >= 0) { + WritePixels(p_bitmapHeader, p_pixelData, 0, line, p_data, width); + p_data += width; + } +} + +// FUNCTION: LEGO1 0x100bdce0 +void DecodeFLCFrame( + LPBITMAPINFOHEADER p_bitmapHeader, + BYTE* p_pixelData, + FLIC_HEADER* p_flcHeader, + FLIC_FRAME* p_flcFrame, + BYTE* p_decodedColorMap +) +{ + if (p_flcFrame->type == FLI_CHUNK_FRAME) { + DecodeChunks(p_bitmapHeader, p_pixelData, p_flcHeader, p_flcFrame, (BYTE*) (p_flcFrame + 1), p_decodedColorMap); + } +} diff --git a/LEGO1/omni/src/video/mxbitmap.cpp b/LEGO1/omni/src/video/mxbitmap.cpp new file mode 100644 index 00000000..29733d5f --- /dev/null +++ b/LEGO1/omni/src/video/mxbitmap.cpp @@ -0,0 +1,474 @@ +#include "mxbitmap.h" + +#include "decomp.h" +#include "mxpalette.h" +#include "mxutilities.h" + +DECOMP_SIZE_ASSERT(MxBitmap, 0x20); +DECOMP_SIZE_ASSERT(MxBITMAPINFO, 0x428); + +// GLOBAL: LEGO1 0x10102184 +MxU16 g_bitmapSignature = TWOCC('B', 'M'); + +// FUNCTION: LEGO1 0x100bc980 +MxBitmap::MxBitmap() +{ + this->m_info = NULL; + this->m_bmiHeader = NULL; + this->m_paletteData = NULL; + this->m_data = NULL; + this->m_isHighColor = FALSE; + this->m_palette = NULL; +} + +// FUNCTION: LEGO1 0x100bca10 +MxBitmap::~MxBitmap() +{ + if (this->m_info) { + delete m_info; + } + if (this->m_data) { + delete m_data; + } + if (this->m_palette) { + delete m_palette; + } +} + +// FUNCTION: LEGO1 0x100bcaa0 +MxResult MxBitmap::SetSize(MxS32 p_width, MxS32 p_height, MxPalette* p_palette, MxBool p_isHighColor) +{ + MxResult ret = FAILURE; + MxLong size = AlignToFourByte(p_width) * p_height; + + m_info = new MxBITMAPINFO; + if (m_info) { + m_data = new MxU8[size]; + if (m_data) { + m_bmiHeader = &m_info->m_bmiHeader; + m_paletteData = m_info->m_bmiColors; + memset(&m_info->m_bmiHeader, 0, sizeof(m_info->m_bmiHeader)); + + m_bmiHeader->biSize = sizeof(*m_bmiHeader); // should be 40 bytes + m_bmiHeader->biWidth = p_width; + m_bmiHeader->biHeight = p_height; + m_bmiHeader->biPlanes = 1; + m_bmiHeader->biBitCount = 8; + m_bmiHeader->biCompression = 0; + m_bmiHeader->biSizeImage = size; + + if (!ImportColorsToPalette(m_paletteData, p_palette)) { + if (!SetBitDepth(p_isHighColor)) { + ret = SUCCESS; + } + } + } + } + + if (ret) { + if (m_info) { + delete m_info; + m_info = NULL; + } + + if (m_data) { + delete[] m_data; + m_data = NULL; + } + } + + return ret; +} + +// FUNCTION: LEGO1 0x100bcba0 +MxResult MxBitmap::ImportBitmapInfo(MxBITMAPINFO* p_info) +{ + MxResult result = FAILURE; + MxLong width = p_info->m_bmiHeader.biWidth; + MxLong height = p_info->m_bmiHeader.biHeight; + MxLong size = AlignToFourByte(width) * height; + + this->m_info = new MxBITMAPINFO; + if (this->m_info) { + this->m_data = new MxU8[size]; + if (this->m_data) { + memcpy(this->m_info, p_info, sizeof(*this->m_info)); + this->m_bmiHeader = &this->m_info->m_bmiHeader; + this->m_paletteData = this->m_info->m_bmiColors; + result = SUCCESS; + } + } + + if (result != SUCCESS) { + if (this->m_info) { + delete this->m_info; + this->m_info = NULL; + } + + if (this->m_data) { + delete[] this->m_data; + this->m_data = NULL; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100bcc40 +MxResult MxBitmap::ImportBitmap(MxBitmap* p_bitmap) +{ + MxResult result = FAILURE; + + this->m_info = new MxBITMAPINFO; + if (this->m_info) { + this->m_data = new MxU8[p_bitmap->GetDataSize()]; + if (this->m_data) { + memcpy(this->m_info, p_bitmap->GetBitmapInfo(), MxBITMAPINFO::Size()); + memcpy(this->m_data, p_bitmap->GetImage(), p_bitmap->GetDataSize()); + + this->m_bmiHeader = &this->m_info->m_bmiHeader; + this->m_paletteData = this->m_info->m_bmiColors; + result = SUCCESS; + } + } + + if (result != SUCCESS) { + if (this->m_info) { + delete this->m_info; + this->m_info = NULL; + } + + if (this->m_data) { + delete this->m_data; + this->m_data = NULL; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100bcd10 +MxLong MxBitmap::Read(const char* p_filename) +{ + MxResult result = FAILURE; + HANDLE handle = + CreateFileA(p_filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle != INVALID_HANDLE_VALUE && !LoadFile(handle)) { + result = SUCCESS; + } + + if (handle) { + CloseHandle(handle); + } + + return result; +} + +// FUNCTION: LEGO1 0x100bcd60 +MxResult MxBitmap::LoadFile(HANDLE p_handle) +{ + MxResult result = FAILURE; + DWORD bytesRead; + BITMAPFILEHEADER hdr; + + BOOL ret = ReadFile(p_handle, &hdr, sizeof(hdr), &bytesRead, NULL); + if (ret && (hdr.bfType == g_bitmapSignature)) { + this->m_info = new MxBITMAPINFO; + if (this->m_info) { + ret = ReadFile(p_handle, this->m_info, sizeof(*this->m_info), &bytesRead, NULL); + if (ret && (this->m_info->m_bmiHeader.biBitCount == 8)) { + MxLong size = hdr.bfSize - (sizeof(MxBITMAPINFO) + sizeof(BITMAPFILEHEADER)); + this->m_data = new MxU8[size]; + if (this->m_data) { + ret = ReadFile(p_handle, this->m_data, size, &bytesRead, NULL); + if (ret) { + this->m_bmiHeader = &this->m_info->m_bmiHeader; + this->m_paletteData = this->m_info->m_bmiColors; + if (this->m_info->m_bmiHeader.biSizeImage == 0) { + MxLong height = AbsFlipped(this->m_info->m_bmiHeader.biHeight); + this->m_info->m_bmiHeader.biSizeImage = + AlignToFourByte(this->m_info->m_bmiHeader.biWidth) * height; + } + result = SUCCESS; + } + } + } + } + } + + if (result != SUCCESS) { + if (this->m_info) { + delete this->m_info; + this->m_info = NULL; + } + + if (this->m_data) { + delete this->m_data; + this->m_data = NULL; + } + } + + return result; +} + +// FUNCTION: LEGO1 0x100bce70 +void MxBitmap::BitBlt( + MxBitmap* p_src, + MxS32 p_srcLeft, + MxS32 p_srcTop, + MxS32 p_dstLeft, + MxS32 p_dstTop, + MxS32 p_width, + MxS32 p_height +) +{ + MxLong dstHeight = GetBmiHeightAbs(); + MxLong srcHeight = p_src->GetBmiHeightAbs(); + + if (GetRectIntersection( + p_src->GetBmiWidth(), + srcHeight, + GetBmiWidth(), + dstHeight, + &p_srcLeft, + &p_srcTop, + &p_dstLeft, + &p_dstTop, + &p_width, + &p_height + )) { + MxU8* srcStart = p_src->GetStart(p_srcLeft, p_srcTop); + MxU8* dstStart = GetStart(p_dstLeft, p_dstTop); + MxLong srcStride = p_src->GetAdjustedStride(); + MxLong dstStride = GetAdjustedStride(); + + while (p_height--) { + memcpy(dstStart, srcStart, p_width); + dstStart += dstStride; + srcStart += srcStride; + } + } +} + +// FUNCTION: LEGO1 0x100bd020 +void MxBitmap::BitBltTransparent( + MxBitmap* p_src, + MxS32 p_srcLeft, + MxS32 p_srcTop, + MxS32 p_dstLeft, + MxS32 p_dstTop, + MxS32 p_width, + MxS32 p_height +) +{ + MxLong dstHeight = GetBmiHeightAbs(); + MxLong srcHeight = p_src->GetBmiHeightAbs(); + + if (GetRectIntersection( + p_src->GetBmiWidth(), + srcHeight, + GetBmiWidth(), + dstHeight, + &p_srcLeft, + &p_srcTop, + &p_dstLeft, + &p_dstTop, + &p_width, + &p_height + )) { + MxU8* srcStart = p_src->GetStart(p_srcLeft, p_srcTop); + MxU8* dstStart = GetStart(p_dstLeft, p_dstTop); + MxLong srcStride = p_src->GetAdjustedStride() - p_width; + MxLong dstStride = GetAdjustedStride() - p_width; + + for (MxS32 h = 0; h < p_height; h++) { + for (MxS32 w = 0; w < p_width; w++) { + if (*srcStart) { + *dstStart = *srcStart; + } + srcStart++; + dstStart++; + } + + srcStart += srcStride; + dstStart += dstStride; + } + } +} + +// FUNCTION: LEGO1 0x100bd1c0 +MxPalette* MxBitmap::CreatePalette() +{ + MxBool success = FALSE; + MxPalette* palette = NULL; + + switch (this->m_isHighColor) { + case FALSE: + palette = new MxPalette(this->m_paletteData); + + if (!palette) { + goto done; + } + + break; + case TRUE: + palette = this->m_palette->Clone(); + + if (!palette) { + goto done; + } + + break; + default: + goto done; + } + + success = TRUE; + +done: + if (!success && palette) { + delete palette; + palette = NULL; + } + + return palette; +} + +// FUNCTION: LEGO1 0x100bd280 +void MxBitmap::ImportPalette(MxPalette* p_palette) +{ + // Odd to use a switch on a boolean, but it matches. + switch (this->m_isHighColor) { + case FALSE: + ImportColorsToPalette(this->m_paletteData, p_palette); + break; + + case TRUE: + if (this->m_palette) { + delete this->m_palette; + } + this->m_palette = p_palette->Clone(); + break; + } +} + +// FUNCTION: LEGO1 0x100bd2d0 +MxResult MxBitmap::SetBitDepth(MxBool p_isHighColor) +{ + MxResult ret = FAILURE; + MxPalette* pal = NULL; + + if (m_isHighColor == p_isHighColor) { + // no change: do nothing. + ret = SUCCESS; + goto done; + } + + switch (p_isHighColor) { + case FALSE: + ImportColorsToPalette(m_paletteData, m_palette); + if (m_palette) { + delete m_palette; + } + + m_palette = NULL; + break; + case TRUE: { + pal = NULL; + pal = new MxPalette(m_paletteData); + + if (!pal) { + goto done; + } + + m_palette = pal; + + // TODO: what is this? zeroing out top half of palette? + MxU16* buf = (MxU16*) m_paletteData; + for (MxU16 i = 0; i < 256; i++) { + buf[i] = i; + } + break; + } + default: + goto done; + } + + m_isHighColor = p_isHighColor; + ret = SUCCESS; + +done: + // If we were unsuccessful overall but did manage to alloc + // the MxPalette, free it. + if (ret && pal) { + delete pal; + } + + return ret; +} + +// FUNCTION: LEGO1 0x100bd3e0 +MxResult MxBitmap::StretchBits( + HDC p_hdc, + MxS32 p_xSrc, + MxS32 p_ySrc, + MxS32 p_xDest, + MxS32 p_yDest, + MxS32 p_destWidth, + MxS32 p_destHeight +) +{ + // Compression fix? + if ((this->m_bmiHeader->biCompression != BI_RGB_TOPDOWN) && (0 < this->m_bmiHeader->biHeight)) { + p_ySrc = (this->m_bmiHeader->biHeight - p_destHeight) - p_ySrc; + } + + return StretchDIBits( + p_hdc, + p_xDest, + p_yDest, + p_destWidth, + p_destHeight, + p_xSrc, + p_ySrc, + p_destWidth, + p_destHeight, + this->m_data, + (BITMAPINFO*) this->m_info, + this->m_isHighColor, + SRCCOPY + ); +} + +// FUNCTION: LEGO1 0x100bd450 +MxResult MxBitmap::ImportColorsToPalette(RGBQUAD* p_rgbquad, MxPalette* p_palette) +{ + MxResult ret = FAILURE; + PALETTEENTRY entries[256]; + + if (p_palette) { + if (p_palette->GetEntries(entries)) { + goto done; + } + } + else { + MxPalette palette; + if (palette.GetEntries(entries)) { + goto done; + } + } + + MxS32 i; + for (i = 0; i < 256; i++) { + p_rgbquad[i].rgbRed = entries[i].peRed; + p_rgbquad[i].rgbGreen = entries[i].peGreen; + p_rgbquad[i].rgbBlue = entries[i].peBlue; + p_rgbquad[i].rgbReserved = 0; + } + + ret = SUCCESS; + +done: + return ret; +} diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp new file mode 100644 index 00000000..6f3fbe0e --- /dev/null +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -0,0 +1,948 @@ +#include "mxdisplaysurface.h" + +#include "mxbitmap.h" +#include "mxmisc.h" +#include "mxomni.h" +#include "mxpalette.h" +#include "mxutilities.h" +#include "mxvideomanager.h" + +#include + +DECOMP_SIZE_ASSERT(MxDisplaySurface, 0xac); + +// GLOBAL: LEGO1 0x1010215c +MxU32 g_unk0x1010215c = 0; + +// FUNCTION: LEGO1 0x100ba500 +MxDisplaySurface::MxDisplaySurface() +{ + this->Init(); +} + +// FUNCTION: LEGO1 0x100ba5a0 +MxDisplaySurface::~MxDisplaySurface() +{ + this->Destroy(); +} + +// FUNCTION: LEGO1 0x100ba610 +void MxDisplaySurface::Init() +{ + this->m_ddSurface1 = NULL; + this->m_ddSurface2 = NULL; + this->m_ddClipper = NULL; + this->m_16bitPal = NULL; + this->m_initialized = FALSE; + memset(&this->m_surfaceDesc, 0, sizeof(this->m_surfaceDesc)); +} + +// FUNCTION: LEGO1 0x100ba640 +void MxDisplaySurface::ClearScreen() +{ + MxS32 backBuffers; + DDSURFACEDESC desc; + HRESULT hr; + + if (!m_videoParam.Flags().GetFlipSurfaces()) { + backBuffers = 1; + } + else { + backBuffers = m_videoParam.GetBackBuffers() + 1; + } + + for (MxS32 i = 0; i < backBuffers; i++) { + memset(&desc, 0, sizeof(DDSURFACEDESC)); + + desc.dwSize = sizeof(DDSURFACEDESC); + hr = m_ddSurface2->Lock(NULL, &desc, DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) { + m_ddSurface2->Restore(); + hr = m_ddSurface2->Lock(NULL, &desc, DDLOCK_WAIT, NULL); + } + + if (hr != DD_OK) { + return; + } + + MxU8* surface = (MxU8*) desc.lpSurface; + MxS32 height = m_videoParam.GetRect().GetHeight(); + + while (height--) { + memset(surface, 0, m_videoParam.GetRect().GetWidth() * desc.ddpfPixelFormat.dwRGBBitCount / 8); + surface += desc.lPitch; + } + + m_ddSurface2->Unlock(desc.lpSurface); + if (m_videoParam.Flags().GetFlipSurfaces()) { + m_ddSurface1->Flip(NULL, DDFLIP_WAIT); + } + } +} + +// FUNCTION: LEGO1 0x100ba750 +MxU8 MxDisplaySurface::CountTotalBitsSetTo1(MxU32 p_param) +{ + MxU8 count = 0; + + for (; p_param; p_param >>= 1) { + count += ((MxU8) p_param & 1); + } + + return count; +} + +// FUNCTION: LEGO1 0x100ba770 +MxU8 MxDisplaySurface::CountContiguousBitsSetTo1(MxU32 p_param) +{ + MxU8 count = 0; + + for (; (p_param & 1) == 0; p_param >>= 1) { + count++; + } + + return count; +} + +// FUNCTION: LEGO1 0x100ba790 +MxResult MxDisplaySurface::Init( + MxVideoParam& p_videoParam, + LPDIRECTDRAWSURFACE p_ddSurface1, + LPDIRECTDRAWSURFACE p_ddSurface2, + LPDIRECTDRAWCLIPPER p_ddClipper +) +{ + MxResult result = SUCCESS; + + this->m_videoParam = p_videoParam; + this->m_ddSurface1 = p_ddSurface1; + this->m_ddSurface2 = p_ddSurface2; + this->m_ddClipper = p_ddClipper; + this->m_initialized = FALSE; + + memset(&this->m_surfaceDesc, 0, sizeof(this->m_surfaceDesc)); + this->m_surfaceDesc.dwSize = sizeof(this->m_surfaceDesc); + + if (this->m_ddSurface2->GetSurfaceDesc(&this->m_surfaceDesc)) { + result = FAILURE; + } + + return result; +} + +// FUNCTION: LEGO1 0x100ba7f0 +MxResult MxDisplaySurface::Create(MxVideoParam& p_videoParam) +{ + DDSURFACEDESC ddsd; + MxResult result = FAILURE; + LPDIRECTDRAW lpDirectDraw = MVideoManager()->GetDirectDraw(); + HWND hWnd = MxOmni::GetInstance()->GetWindowHandle(); + + this->m_initialized = TRUE; + this->m_videoParam = p_videoParam; + + if (!this->m_videoParam.Flags().GetFullScreen()) { + this->m_videoParam.Flags().SetFlipSurfaces(FALSE); + } + + if (!this->m_videoParam.Flags().GetFlipSurfaces()) { + this->m_videoParam.SetBackBuffers(1); + } + else { + MxU32 backBuffers = this->m_videoParam.GetBackBuffers(); + + if (backBuffers < 1) { + this->m_videoParam.SetBackBuffers(1); + } + else if (backBuffers > 2) { + this->m_videoParam.SetBackBuffers(2); + } + + this->m_videoParam.Flags().SetBackBuffers(TRUE); + } + + if (this->m_videoParam.Flags().GetFullScreen()) { + MxS32 width = this->m_videoParam.GetRect().GetWidth(); + MxS32 height = this->m_videoParam.GetRect().GetHeight(); + + if (lpDirectDraw->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN)) { + goto done; + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + if (lpDirectDraw->GetDisplayMode(&ddsd)) { + goto done; + } + + MxS32 bitdepth = !this->m_videoParam.Flags().Get16Bit() ? 8 : 16; + + if (ddsd.dwWidth != width || ddsd.dwHeight != height || ddsd.ddpfPixelFormat.dwRGBBitCount != bitdepth) { + if (lpDirectDraw->SetDisplayMode(width, height, bitdepth)) { + goto done; + } + } + } + + if (this->m_videoParam.Flags().GetFlipSurfaces()) { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwBackBufferCount = this->m_videoParam.GetBackBuffers(); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; + + if (lpDirectDraw->CreateSurface(&ddsd, &this->m_ddSurface1, NULL)) { + goto done; + } + + ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; + + if (this->m_ddSurface1->GetAttachedSurface(&ddsd.ddsCaps, &this->m_ddSurface2)) { + goto done; + } + } + else { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + + if (lpDirectDraw->CreateSurface(&ddsd, &this->m_ddSurface1, NULL)) { + goto done; + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH | DDSD_CAPS; + ddsd.dwWidth = this->m_videoParam.GetRect().GetWidth(); + ddsd.dwHeight = this->m_videoParam.GetRect().GetHeight(); + ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_3DDEVICE | DDSCAPS_OFFSCREENPLAIN; + + if (!this->m_videoParam.Flags().GetBackBuffers()) { + ddsd.ddsCaps.dwCaps = DDSCAPS_3DDEVICE | DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; + } + + if (lpDirectDraw->CreateSurface(&ddsd, &this->m_ddSurface2, NULL)) { + goto done; + } + } + + memset(&this->m_surfaceDesc, 0, sizeof(this->m_surfaceDesc)); + this->m_surfaceDesc.dwSize = sizeof(this->m_surfaceDesc); + + if (!this->m_ddSurface2->GetSurfaceDesc(&this->m_surfaceDesc)) { + if (!lpDirectDraw->CreateClipper(0, &this->m_ddClipper, NULL) && !this->m_ddClipper->SetHWnd(0, hWnd) && + !this->m_ddSurface1->SetClipper(this->m_ddClipper)) { + result = SUCCESS; + } + } + +done: + return result; +} + +// FUNCTION: LEGO1 0x100baa90 +void MxDisplaySurface::Destroy() +{ + if (this->m_initialized) { + if (this->m_ddSurface2) { + this->m_ddSurface2->Release(); + } + + if (this->m_ddSurface1) { + this->m_ddSurface1->Release(); + } + + if (this->m_ddClipper) { + this->m_ddClipper->Release(); + } + } + + if (this->m_16bitPal) { + delete[] this->m_16bitPal; + } + + this->Init(); +} + +// FUNCTION: LEGO1 0x100baae0 +void MxDisplaySurface::SetPalette(MxPalette* p_palette) +{ + if (m_surfaceDesc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) { + m_ddSurface1->SetPalette(p_palette->CreateNativePalette()); + m_ddSurface2->SetPalette(p_palette->CreateNativePalette()); + + if ((m_videoParam.Flags().GetFullScreen() & 1) == 0) { + struct { + WORD m_palVersion; + WORD m_palNumEntries; + PALETTEENTRY m_palPalEntry[256]; + } lpal; + + lpal.m_palVersion = 0x300; + lpal.m_palNumEntries = 256; + + memset(lpal.m_palPalEntry, 0, sizeof(lpal.m_palPalEntry)); + p_palette->GetEntries(lpal.m_palPalEntry); + + HPALETTE hpal = CreatePalette((LPLOGPALETTE) &lpal); + HDC hdc = ::GetDC(0); + SelectPalette(hdc, hpal, FALSE); + RealizePalette(hdc); + ::ReleaseDC(NULL, hdc); + DeleteObject(hpal); + } + } + + if (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount == 16) { + if (!m_16bitPal) { + m_16bitPal = new MxU16[256]; + } + + PALETTEENTRY palette[256]; + p_palette->GetEntries(palette); + + MxU8 contiguousBitsRed = CountContiguousBitsSetTo1(m_surfaceDesc.ddpfPixelFormat.dwRBitMask); + MxU8 totalBitsRed = CountTotalBitsSetTo1(m_surfaceDesc.ddpfPixelFormat.dwRBitMask); + MxU8 contiguousBitsGreen = CountContiguousBitsSetTo1(m_surfaceDesc.ddpfPixelFormat.dwGBitMask); + MxU8 totalBitsGreen = CountTotalBitsSetTo1(m_surfaceDesc.ddpfPixelFormat.dwGBitMask); + MxU8 contiguousBitsBlue = CountContiguousBitsSetTo1(m_surfaceDesc.ddpfPixelFormat.dwBBitMask); + MxU8 totalBitsBlue = CountTotalBitsSetTo1(m_surfaceDesc.ddpfPixelFormat.dwBBitMask); + + for (MxS32 i = 0; i < 256; i++) { + m_16bitPal[i] = (((palette[i].peRed >> ((8 - totalBitsRed) & 0x1f)) << (contiguousBitsRed & 0x1f))) | + (((palette[i].peGreen >> ((8 - totalBitsGreen) & 0x1f)) << (contiguousBitsGreen & 0x1f))) | + (((palette[i].peBlue >> ((8 - totalBitsBlue) & 0x1f)) << (contiguousBitsBlue & 0x1f))); + } + } +} + +// FUNCTION: LEGO1 0x100bacc0 +void MxDisplaySurface::VTable0x28( + MxBitmap* p_bitmap, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height +) +{ + if (GetRectIntersection( + p_bitmap->GetBmiWidth(), + p_bitmap->GetBmiHeightAbs(), + m_videoParam.GetRect().GetWidth(), + m_videoParam.GetRect().GetHeight(), + &p_left, + &p_top, + &p_right, + &p_bottom, + &p_width, + &p_height + )) { + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) { + m_ddSurface2->Restore(); + hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + } + + if (hr == DD_OK) { + MxU8* data = p_bitmap->GetStart(p_left, p_top); + + if (m_videoParam.Flags().GetF1bit3()) { + p_bottom *= 2; + p_right *= 2; + + switch (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount) { + case 8: { + MxU8* surface = (MxU8*) ddsd.lpSurface + p_right + (p_bottom * ddsd.lPitch); + MxLong stride = p_bitmap->GetAdjustedStride(); + + MxLong v22 = stride - p_width; + MxLong length = ddsd.lPitch - (2 * p_width); + while (p_height--) { + MxU8* surfaceBefore = surface; + + for (MxS32 i = 0; p_width > i; i++) { + MxU8 element = *data; + *surface++ = element; + data++; + *surface++ = *(data - 1); + } + + data += v22; + surface += length; + + memcpy(surface, surfaceBefore, 2 * p_width); + surface += ddsd.lPitch; + } + break; + } + case 16: { + MxU8* surface = (MxU8*) ddsd.lpSurface + (2 * p_right) + (p_bottom * ddsd.lPitch); + MxLong stride = p_bitmap->GetAdjustedStride(); + + // TODO: Match + stride -= p_width; + MxS32 length = p_width * 4; + MxLong v62 = ddsd.lPitch - length; + MxS32 height = p_height; + MxS32 width = p_width; + MxU16* p16BitPal = m_16bitPal; + + if (stride || v62) { + while (height--) { + MxU8* surfaceBefore = surface; + + for (MxS32 i = width; i > 0; i--) { + MxU16 element = p16BitPal[*data++]; + *(MxU16*) surface = element; + surface += 2; + *(MxU16*) surface = element; + surface += 2; + } + + data += stride; + surface += v62; + + // Odd expression for the length? + memcpy(surface, surfaceBefore, 4 * ((MxU32) (4 * p_width) / 4)); + surface += ddsd.lPitch; + } + } + else { + while (height--) { + MxU8* surfaceBefore = surface; + + for (MxS32 i = width; i > 0; i--) { + MxU16 element = p16BitPal[*data++]; + *(MxU16*) surface = element; + surface += 2; + *(MxU16*) surface = element; + surface += 2; + } + + memcpy(surface, surfaceBefore, length); + surface += ddsd.lPitch; + } + } + } + } + } + else { + switch (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount) { + case 8: { + MxU8* surface = (MxU8*) ddsd.lpSurface + p_right + (p_bottom * ddsd.lPitch); + MxLong stride = p_bitmap->GetAdjustedStride(); + + MxLong length = ddsd.lPitch; + while (p_height--) { + memcpy(surface, data, p_width); + data += stride; + surface += length; + } + break; + } + case 16: { + MxU8* surface = (MxU8*) ddsd.lpSurface + (2 * p_right) + (p_bottom * ddsd.lPitch); + MxLong stride = p_bitmap->GetAdjustedStride(); + + MxLong v50 = stride - p_width; + MxLong length = ddsd.lPitch - (2 * p_width); + for (MxS32 i = 0; p_height > i; i++) { + for (MxS32 j = 0; p_width > j; j++) { + *(MxU16*) surface = m_16bitPal[*data++]; + surface += 2; + } + + data += v50; + surface += length; + } + } + } + } + + m_ddSurface2->Unlock(ddsd.lpSurface); + } + } +} + +// FUNCTION: LEGO1 0x100bb1d0 +void MxDisplaySurface::VTable0x30( + MxBitmap* p_bitmap, + MxS32 p_left, + MxS32 p_top, + MxS32 p_right, + MxS32 p_bottom, + MxS32 p_width, + MxS32 p_height, + MxBool p_und +) +{ + if (GetRectIntersection( + p_bitmap->GetBmiWidth(), + p_bitmap->GetBmiHeightAbs(), + m_videoParam.GetRect().GetWidth(), + m_videoParam.GetRect().GetHeight(), + &p_left, + &p_top, + &p_right, + &p_bottom, + &p_width, + &p_height + )) { + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) { + m_ddSurface2->Restore(); + hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + } + + if (hr == DD_OK) { + MxU8* data = p_bitmap->GetStart(p_left, p_top); + + switch (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount) { + case 8: { + MxU8* surface = (MxU8*) ddsd.lpSurface + p_right + (p_bottom * ddsd.lPitch); + if (p_und) { + FUN_100bb500( + &data, + &surface, + p_bitmap->GetBmiHeader()->biSizeImage, + p_width, + p_height, + ddsd.lPitch, + 8 + ); + } + else { + MxLong stride = p_bitmap->GetAdjustedStride(); + + MxLong length = ddsd.lPitch; + for (MxS32 i = 0; p_height > i; i++) { + for (MxS32 j = 0; p_width > j; j++) { + if (*data != 0) { + *(MxU8*) surface = *data; + } + data++; + surface++; + } + + data += stride; + surface += length; + } + } + break; + } + case 16: { + MxU8* surface = (MxU8*) ddsd.lpSurface + (2 * p_right) + (p_bottom * ddsd.lPitch); + if (p_und) { + FUN_100bb500( + &data, + &surface, + p_bitmap->GetBmiHeader()->biSizeImage, + p_width, + p_height, + ddsd.lPitch, + 16 + ); + } + else { + MxLong stride = p_bitmap->GetAdjustedStride(); + + MxLong v50 = stride - p_width; + MxLong length = ddsd.lPitch - (2 * p_width); + for (MxS32 i = 0; p_height > i; i++) { + for (MxS32 j = 0; p_width > j; j++) { + if (*data != 0) { + *(MxU16*) surface = m_16bitPal[*data]; + } + data++; + surface += 2; + } + + data += v50; + surface += length; + } + } + } + } + + m_ddSurface2->Unlock(ddsd.lpSurface); + } + } +} + +// STUB: LEGO1 0x100bb500 +void MxDisplaySurface::FUN_100bb500( + MxU8** p_bitmapData, + MxU8** p_surfaceData, + MxU32 p_bitmapSize, + MxS32 p_width, + MxS32 p_height, + MxLong p_pitch, + MxU32 p_bpp +) +{ + // TODO +} + +// STUB: LEGO1 0x100bb850 +undefined4 MxDisplaySurface::VTable0x34(undefined4, undefined4, undefined4, undefined4, undefined4, undefined4) +{ + return 0; +} + +// FUNCTION: LEGO1 0x100bba50 +void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p_top2, MxS32 p_width, MxS32 p_height) +{ + if (m_videoParam.Flags().GetF2bit1()) { + if (m_videoParam.Flags().GetFlipSurfaces()) { + if (g_unk0x1010215c < 2) { + g_unk0x1010215c++; + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + if (m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK) { + MxU8* surface = (MxU8*) ddsd.lpSurface; + MxS32 height = m_videoParam.GetRect().GetHeight(); + + for (MxU32 i = 0; i < ddsd.dwHeight; i++) { + memset(surface, 0, ddsd.dwWidth * ddsd.ddpfPixelFormat.dwRGBBitCount / 8); + surface += ddsd.lPitch; + } + + m_ddSurface2->Unlock(ddsd.lpSurface); + } + else { + OutputDebugString("MxDisplaySurface::Display error\n"); + } + } + m_ddSurface1->Flip(NULL, DDFLIP_WAIT); + } + else { + MxPoint32 point(0, 0); + ClientToScreen(MxOmni::GetInstance()->GetWindowHandle(), (LPPOINT) &point); + + p_left2 += m_videoParam.GetRect().GetLeft() + point.GetX(); + p_top2 += m_videoParam.GetRect().GetTop() + point.GetY(); + + MxRect32 a(MxPoint32(p_left, p_top), MxSize32(p_width + 1, p_height + 1)); + MxRect32 b(MxPoint32(p_left2, p_top2), MxSize32(p_width + 1, p_height + 1)); + + DDBLTFX data; + memset(&data, 0, sizeof(data)); + data.dwSize = sizeof(data); + data.dwDDFX = 8; + + if (m_ddSurface1->Blt((LPRECT) &b, m_ddSurface2, (LPRECT) &a, 0, &data) == DDERR_SURFACELOST) { + m_ddSurface1->Restore(); + m_ddSurface1->Blt((LPRECT) &b, m_ddSurface2, (LPRECT) &a, 0, &data); + } + } + } +} + +// FUNCTION: LEGO1 0x100bbc10 +void MxDisplaySurface::GetDC(HDC* p_hdc) +{ + if (this->m_ddSurface2 && !this->m_ddSurface2->GetDC(p_hdc)) { + return; + } + + *p_hdc = NULL; +} + +// FUNCTION: LEGO1 0x100bbc40 +void MxDisplaySurface::ReleaseDC(HDC p_hdc) +{ + if (this->m_ddSurface2 && p_hdc) { + this->m_ddSurface2->ReleaseDC(p_hdc); + } +} + +// FUNCTION: LEGO1 0x100bbc60 +LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44( + MxBitmap* p_bitmap, + undefined4* p_ret, + undefined4 p_doNotWriteToSurface, + undefined4 p_transparent +) +{ + LPDIRECTDRAWSURFACE surface = NULL; + LPDIRECTDRAW draw = MVideoManager()->GetDirectDraw(); + MVideoManager(); + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + if (draw->GetDisplayMode(&ddsd)) { + return NULL; + } + + ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT; + ddsd.dwWidth = p_bitmap->GetBmiWidth(); + ddsd.dwHeight = p_bitmap->GetBmiHeightAbs(); + + *p_ret = 0; + ddsd.ddsCaps.dwCaps = DDSCAPS_SYSTEMMEMORY | DDSCAPS_OFFSCREENPLAIN; + + if (draw->CreateSurface(&ddsd, &surface, NULL) != DD_OK) { + if (*p_ret) { + *p_ret = 0; + + // Try creating bitmap surface in vram if system ram ran out + ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + + if (draw->CreateSurface(&ddsd, &surface, NULL) != DD_OK) { + surface = NULL; + } + } + else { + surface = NULL; + } + } + + if (surface) { + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + if (surface->Lock(NULL, &ddsd, DDLOCK_WAIT, 0) != DD_OK) { + surface->Release(); + surface = NULL; + goto done; + } + + if (p_doNotWriteToSurface) { + goto done; + } + + MxU8* bitmapSrcPtr = p_bitmap->GetStart(0, 0); + MxU16* surfaceData = (MxU16*) ddsd.lpSurface; + MxLong widthNormal = p_bitmap->GetBmiWidth(); + MxLong heightAbs = p_bitmap->GetBmiHeightAbs(); + + // TODO: Probably p_bitmap->GetAdjustedStride() + MxS32 rowSeek = p_bitmap->GetBmiStride(); + if (p_bitmap->GetBmiHeader()->biCompression != BI_RGB_TOPDOWN && p_bitmap->GetBmiHeight() >= 0) { + rowSeek = -rowSeek; + } + + MxLong newPitch = ddsd.lPitch; + switch (ddsd.ddpfPixelFormat.dwRGBBitCount) { + case 8: { + for (MxS32 y = heightAbs; y > 0; y--) { + memcpy(surfaceData, bitmapSrcPtr, p_bitmap->GetBmiHeight()); + bitmapSrcPtr += rowSeek; + surfaceData = (MxU16*) ((MxU8*) surfaceData + newPitch); + } + + surface->Unlock(ddsd.lpSurface); + + if (p_transparent && surface) { + DDCOLORKEY key; + key.dwColorSpaceHighValue = 0; + key.dwColorSpaceLowValue = 0; + surface->SetColorKey(DDCKEY_SRCBLT, &key); + } + break; + } + case 16: + if (m_16bitPal == NULL) { + if (surface) { + surface->Release(); + } + return NULL; + } + else { + rowSeek -= p_bitmap->GetBmiWidth(); + newPitch -= 2 * p_bitmap->GetBmiWidth(); + + if (p_transparent) { + for (MxS32 y = heightAbs; y > 0; y--) { + for (MxS32 x = widthNormal; x > 0; x--) { + if (*bitmapSrcPtr) { + *surfaceData = m_16bitPal[*bitmapSrcPtr]; + } + else { + *surfaceData = 31775; + } + bitmapSrcPtr++; + surfaceData++; + } + + bitmapSrcPtr += rowSeek; + surfaceData = (MxU16*) ((MxU8*) surfaceData + newPitch); + } + + DDCOLORKEY key; + key.dwColorSpaceHighValue = 31775; + key.dwColorSpaceLowValue = 31775; + surface->SetColorKey(DDCKEY_SRCBLT, &key); + } + else { + for (MxS32 y = heightAbs; y > 0; y--) { + for (MxS32 x = widthNormal; x > 0; x--) { + *surfaceData++ = m_16bitPal[*bitmapSrcPtr++]; + } + + bitmapSrcPtr += rowSeek; + surfaceData = (MxU16*) ((MxU8*) surfaceData + newPitch); + } + } + + surface->Unlock(ddsd.lpSurface); + } + } + } + +done: + return surface; +} + +// FUNCTION: LEGO1 0x100bbfb0 +LPDIRECTDRAWSURFACE MxDisplaySurface::CopySurface(LPDIRECTDRAWSURFACE p_src) +{ + LPDIRECTDRAWSURFACE newSurface = NULL; + IDirectDraw* draw = MVideoManager()->GetDirectDraw(); + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + p_src->GetSurfaceDesc(&ddsd); + + if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { + return NULL; + } + + RECT rect = {0, 0, (LONG) ddsd.dwWidth, (LONG) ddsd.dwHeight}; + + if (newSurface->BltFast(0, 0, p_src, &rect, 16) != DD_OK) { + newSurface->Release(); + return NULL; + } + + return newSurface; +} + +// FUNCTION: LEGO1 0x100bc070 +LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface() +{ + LPDIRECTDRAWSURFACE newSurface = NULL; + IDirectDraw* draw = MVideoManager()->GetDirectDraw(); + MVideoManager(); + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + if (draw->GetDisplayMode(&ddsd) != DD_OK) { + return NULL; + } + + if (ddsd.ddpfPixelFormat.dwRGBBitCount != 16) { + return NULL; + } + + ddsd.dwWidth = 16; + ddsd.dwHeight = 16; + ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN; + + if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { + ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + + if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { + goto done; + } + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK) { + goto done; + } + else { + MxU16* surface = (MxU16*) ddsd.lpSurface; + MxLong pitch = ddsd.lPitch; + + // draw a simple cursor to the surface + for (MxS32 x = 0; x < 16; x++) { + MxU16* surface2 = surface; + for (MxS32 y = 0; y < 16; y++) { + if ((y > 10 || x) && (x > 10 || y) && x + y != 10) { + if (x + y > 10) { + *surface2 = 31775; + } + else { + *surface2 = -1; + } + } + else { + *surface2 = 0; + } + surface2++; + } + surface = (MxU16*) ((MxU8*) surface + pitch); + } + + newSurface->Unlock(ddsd.lpSurface); + DDCOLORKEY colorkey; + colorkey.dwColorSpaceHighValue = 31775; + colorkey.dwColorSpaceLowValue = 31775; + newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); + + return newSurface; + } + +done: + if (newSurface) { + newSurface->Release(); + } + + return NULL; +} + +// STUB: LEGO1 0x100bc200 +void MxDisplaySurface::VTable0x24( + LPDDSURFACEDESC, + MxBitmap*, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4 +) +{ +} + +// STUB: LEGO1 0x100bc630 +MxBool MxDisplaySurface::VTable0x2c( + LPDDSURFACEDESC, + MxBitmap*, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4, + undefined4, + MxBool +) +{ + return 0; +} diff --git a/LEGO1/omni/src/video/mxflcpresenter.cpp b/LEGO1/omni/src/video/mxflcpresenter.cpp new file mode 100644 index 00000000..ceacb85a --- /dev/null +++ b/LEGO1/omni/src/video/mxflcpresenter.cpp @@ -0,0 +1,83 @@ +#include "mxflcpresenter.h" + +#include "decomp.h" +#include "mxbitmap.h" +#include "mxdsmediaaction.h" +#include "mxmisc.h" +#include "mxpalette.h" +#include "mxvideomanager.h" + +DECOMP_SIZE_ASSERT(MxFlcPresenter, 0x68); + +// FUNCTION: LEGO1 0x100b3310 +MxFlcPresenter::MxFlcPresenter() +{ + m_flcHeader = NULL; + SetBit1(FALSE); + SetBit2(FALSE); +} + +// FUNCTION: LEGO1 0x100b3420 +MxFlcPresenter::~MxFlcPresenter() +{ + if (this->m_flcHeader) { + delete this->m_flcHeader; + } +} + +// FUNCTION: LEGO1 0x100b3490 +void MxFlcPresenter::LoadHeader(MxStreamChunk* p_chunk) +{ + m_flcHeader = (FLIC_HEADER*) new MxU8[p_chunk->GetLength()]; + memcpy(m_flcHeader, p_chunk->GetData(), p_chunk->GetLength()); +} + +// FUNCTION: LEGO1 0x100b34d0 +void MxFlcPresenter::CreateBitmap() +{ + if (m_frameBitmap) { + delete m_frameBitmap; + } + + m_frameBitmap = new MxBitmap; + m_frameBitmap->SetSize(m_flcHeader->width, m_flcHeader->height, NULL, FALSE); +} + +// FUNCTION: LEGO1 0x100b3570 +void MxFlcPresenter::LoadFrame(MxStreamChunk* p_chunk) +{ + MxU8* data = p_chunk->GetData(); + + MxS32 rectCount = *(MxS32*) data; + data += sizeof(MxS32); + + MxRect32* rects = (MxRect32*) data; + data += rectCount * sizeof(MxRect32); + + MxBool decodedColorMap; + DecodeFLCFrame( + &m_frameBitmap->GetBitmapInfo()->m_bmiHeader, + m_frameBitmap->GetImage(), + m_flcHeader, + (FLIC_FRAME*) data, + &decodedColorMap + ); + + if (((MxDSMediaAction*) m_action)->GetPaletteManagement() && decodedColorMap) { + RealizePalette(); + } + + for (MxS32 i = 0; i < rectCount; i++) { + MxRect32 rect(rects[i]); + rect.AddPoint(m_location); + MVideoManager()->InvalidateRect(rect); + } +} + +// FUNCTION: LEGO1 0x100b3620 +void MxFlcPresenter::RealizePalette() +{ + MxPalette* palette = m_frameBitmap->CreatePalette(); + MVideoManager()->RealizePalette(palette); + delete palette; +} diff --git a/LEGO1/omni/src/video/mxloopingflcpresenter.cpp b/LEGO1/omni/src/video/mxloopingflcpresenter.cpp new file mode 100644 index 00000000..a828296c --- /dev/null +++ b/LEGO1/omni/src/video/mxloopingflcpresenter.cpp @@ -0,0 +1,136 @@ +#include "mxloopingflcpresenter.h" + +#include "decomp.h" +#include "mxdsaction.h" +#include "mxdssubscriber.h" + +DECOMP_SIZE_ASSERT(MxLoopingFlcPresenter, 0x6c); + +// FUNCTION: LEGO1 0x100b4310 +MxLoopingFlcPresenter::MxLoopingFlcPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100b43b0 +MxLoopingFlcPresenter::~MxLoopingFlcPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100b4410 +void MxLoopingFlcPresenter::Init() +{ + this->m_elapsedDuration = 0; + SetBit1(FALSE); + SetBit2(FALSE); +} + +// FUNCTION: LEGO1 0x100b4430 +void MxLoopingFlcPresenter::Destroy(MxBool p_fromDestructor) +{ + m_criticalSection.Enter(); + Init(); + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxFlcPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x100b4470 +void MxLoopingFlcPresenter::NextFrame() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk->GetChunkFlags() & DS_CHUNK_END_OF_STREAM) { + ProgressTickleState(e_repeating); + } + else { + LoadFrame(chunk); + LoopChunk(chunk); + m_elapsedDuration += m_flcHeader->speed; + } + + m_subscriber->FreeDataChunk(chunk); +} + +// FUNCTION: LEGO1 0x100b44c0 +void MxLoopingFlcPresenter::VTable0x88() +{ + if (m_action->GetDuration() < m_elapsedDuration) { + ProgressTickleState(e_freezing); + } + else { + MxStreamChunk* chunk; + m_loopingChunkCursor->Current(chunk); + LoadFrame(chunk); + m_elapsedDuration += m_flcHeader->speed; + } +} + +// FUNCTION: LEGO1 0x100b4520 +void MxLoopingFlcPresenter::RepeatingTickle() +{ + for (MxS16 i = 0; i < m_unk0x5c; i++) { + if (!m_loopingChunkCursor->HasMatch()) { + MxStreamChunk* chunk; + MxStreamChunkListCursor cursor(m_loopingChunks); + + cursor.Last(chunk); + MxLong time = chunk->GetTime(); + + cursor.First(chunk); + + time -= chunk->GetTime(); + time += m_flcHeader->speed; + + cursor.Reset(); + while (cursor.Next(chunk)) { + chunk->SetTime(chunk->GetTime() + time); + } + + m_loopingChunkCursor->Next(); + } + + MxStreamChunk* chunk; + m_loopingChunkCursor->Current(chunk); + + if (m_action->GetElapsedTime() < chunk->GetTime()) { + break; + } + + VTable0x88(); + + m_loopingChunkCursor->Next(chunk); + + if (m_currentTickleState != e_repeating) { + break; + } + } +} + +// FUNCTION: LEGO1 0x100b4860 +MxResult MxLoopingFlcPresenter::AddToManager() +{ + MxResult result = FAILURE; + MxBool locked = FALSE; + + if (MxFlcPresenter::AddToManager() == SUCCESS) { + m_criticalSection.Enter(); + locked = TRUE; + result = SUCCESS; + } + + if (locked) { + m_criticalSection.Leave(); + } + + return result; +} + +// FUNCTION: LEGO1 0x100b48a0 +void MxLoopingFlcPresenter::Destroy() +{ + Destroy(FALSE); +} diff --git a/LEGO1/omni/src/video/mxloopingsmkpresenter.cpp b/LEGO1/omni/src/video/mxloopingsmkpresenter.cpp new file mode 100644 index 00000000..ca043243 --- /dev/null +++ b/LEGO1/omni/src/video/mxloopingsmkpresenter.cpp @@ -0,0 +1,134 @@ +#include "mxloopingsmkpresenter.h" + +#include "mxautolock.h" +#include "mxdsmediaaction.h" +#include "mxdssubscriber.h" + +DECOMP_SIZE_ASSERT(MxLoopingSmkPresenter, 0x724); + +// FUNCTION: LEGO1 0x100b48b0 +MxLoopingSmkPresenter::MxLoopingSmkPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100b4950 +MxLoopingSmkPresenter::~MxLoopingSmkPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100b49b0 +void MxLoopingSmkPresenter::Init() +{ + m_elapsedDuration = 0; + SetBit1(FALSE); + SetBit2(FALSE); +} + +// FUNCTION: LEGO1 0x100b49d0 +void MxLoopingSmkPresenter::Destroy(MxBool p_fromDestructor) +{ + m_criticalSection.Enter(); + Init(); + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxSmkPresenter::Destroy(); + } +} + +// FUNCTION: LEGO1 0x100b4a00 +void MxLoopingSmkPresenter::VTable0x88() +{ + if (m_mxSmack.m_smackTag.Frames == m_currentFrame) { + m_currentFrame = 0; + // TODO: struct incorrect, Palette at wrong offset? + memset(&m_mxSmack.m_smackTag.Palette[4], 0, sizeof(m_mxSmack.m_smackTag.Palette)); + } +} + +// FUNCTION: LEGO1 0x100b4a30 +void MxLoopingSmkPresenter::NextFrame() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk->GetChunkFlags() & DS_CHUNK_END_OF_STREAM) { + ProgressTickleState(e_repeating); + } + else { + LoadFrame(chunk); + LoopChunk(chunk); + m_elapsedDuration += 1000 / ((MxDSMediaAction*) m_action)->GetFramesPerSecond(); + } + + m_subscriber->FreeDataChunk(chunk); +} + +// FUNCTION: LEGO1 0x100b4a90 +void MxLoopingSmkPresenter::VTable0x8c() +{ + if (m_action->GetDuration() < m_elapsedDuration) { + ProgressTickleState(e_freezing); + } + else { + MxStreamChunk* chunk; + m_loopingChunkCursor->Current(chunk); + LoadFrame(chunk); + m_elapsedDuration += 1000 / ((MxDSMediaAction*) m_action)->GetFramesPerSecond(); + } +} + +// FUNCTION: LEGO1 0x100b4b00 +void MxLoopingSmkPresenter::RepeatingTickle() +{ + for (MxS16 i = 0; i < m_unk0x5c; i++) { + if (!m_loopingChunkCursor->HasMatch()) { + MxStreamChunk* chunk; + MxStreamChunkListCursor cursor(m_loopingChunks); + + cursor.Last(chunk); + MxLong time = chunk->GetTime(); + + cursor.First(chunk); + + time -= chunk->GetTime(); + time += 1000 / ((MxDSMediaAction*) m_action)->GetFramesPerSecond(); + + cursor.Reset(); + while (cursor.Next(chunk)) { + chunk->SetTime(chunk->GetTime() + time); + } + + m_loopingChunkCursor->Next(); + } + + MxStreamChunk* chunk; + m_loopingChunkCursor->Current(chunk); + + if (m_action->GetElapsedTime() < chunk->GetTime()) { + break; + } + + VTable0x8c(); + + m_loopingChunkCursor->Next(chunk); + + if (m_currentTickleState != e_repeating) { + break; + } + } +} + +// FUNCTION: LEGO1 0x100b4cd0 +MxResult MxLoopingSmkPresenter::AddToManager() +{ + AUTOLOCK(m_criticalSection); + return MxSmkPresenter::AddToManager(); +} + +// FUNCTION: LEGO1 0x100b4d40 +void MxLoopingSmkPresenter::Destroy() +{ + Destroy(FALSE); +} diff --git a/LEGO1/omni/src/video/mxpalette.cpp b/LEGO1/omni/src/video/mxpalette.cpp new file mode 100644 index 00000000..f3a3e599 --- /dev/null +++ b/LEGO1/omni/src/video/mxpalette.cpp @@ -0,0 +1,291 @@ +#include "mxpalette.h" + +#include "mxmisc.h" +#include "mxvideomanager.h" + +// GLOBAL: LEGO1 0x10102188 +PALETTEENTRY g_defaultPaletteEntries[256] = { + {0u, 0u, 0u, 0u}, {128u, 0u, 0u, 0u}, {0u, 128u, 0u, 0u}, {128u, 128u, 0u, 0u}, + {0u, 0u, 128u, 0u}, {128u, 0u, 128u, 0u}, {0u, 128u, 128u, 0u}, {128u, 128u, 128u, 0u}, + {192u, 220u, 192u, 0u}, {166u, 202u, 240u, 0u}, {255u, 255u, 255u, 0u}, {250u, 250u, 250u, 0u}, + {239u, 239u, 239u, 0u}, {228u, 228u, 228u, 0u}, {217u, 217u, 217u, 0u}, {206u, 206u, 206u, 0u}, + {195u, 195u, 195u, 0u}, {185u, 185u, 185u, 0u}, {174u, 174u, 174u, 0u}, {163u, 163u, 163u, 0u}, + {152u, 152u, 152u, 0u}, {141u, 141u, 141u, 0u}, {130u, 130u, 130u, 0u}, {123u, 123u, 123u, 0u}, + {115u, 115u, 115u, 0u}, {108u, 108u, 108u, 0u}, {101u, 101u, 101u, 0u}, {93u, 93u, 93u, 0u}, + {86u, 86u, 86u, 0u}, {79u, 79u, 79u, 0u}, {71u, 71u, 71u, 0u}, {64u, 64u, 64u, 0u}, + {54u, 54u, 54u, 0u}, {43u, 43u, 43u, 0u}, {33u, 33u, 33u, 0u}, {22u, 22u, 22u, 0u}, + {12u, 12u, 12u, 0u}, {8u, 8u, 8u, 0u}, {4u, 4u, 4u, 0u}, {0u, 0u, 0u, 0u}, + {225u, 218u, 217u, 0u}, {195u, 182u, 179u, 0u}, {165u, 145u, 141u, 0u}, {134u, 108u, 102u, 0u}, + {104u, 72u, 64u, 0u}, {74u, 35u, 26u, 0u}, {59u, 28u, 21u, 0u}, {44u, 21u, 16u, 0u}, + {30u, 14u, 10u, 0u}, {15u, 7u, 5u, 0u}, {250u, 231u, 232u, 0u}, {240u, 185u, 189u, 0u}, + {233u, 154u, 160u, 0u}, {226u, 124u, 131u, 0u}, {219u, 93u, 102u, 0u}, {213u, 62u, 73u, 0u}, + {203u, 18u, 32u, 0u}, {172u, 15u, 27u, 0u}, {159u, 14u, 25u, 0u}, {146u, 13u, 23u, 0u}, + {133u, 12u, 21u, 0u}, {120u, 11u, 19u, 0u}, {107u, 10u, 17u, 0u}, {94u, 8u, 15u, 0u}, + {81u, 7u, 13u, 0u}, {68u, 6u, 11u, 0u}, {55u, 5u, 9u, 0u}, {42u, 4u, 7u, 0u}, + {29u, 3u, 5u, 0u}, {10u, 1u, 2u, 0u}, {227u, 236u, 242u, 0u}, {178u, 203u, 220u, 0u}, + {145u, 181u, 205u, 0u}, {112u, 159u, 191u, 0u}, {79u, 137u, 176u, 0u}, {30u, 104u, 154u, 0u}, + {0u, 84u, 140u, 0u}, {0u, 79u, 132u, 0u}, {0u, 72u, 119u, 0u}, {0u, 66u, 110u, 0u}, + {0u, 61u, 101u, 0u}, {0u, 55u, 92u, 0u}, {0u, 47u, 78u, 0u}, {0u, 39u, 65u, 0u}, + {0u, 34u, 56u, 0u}, {0u, 28u, 47u, 0u}, {0u, 23u, 38u, 0u}, {0u, 18u, 29u, 0u}, + {0u, 12u, 20u, 0u}, {0u, 4u, 7u, 0u}, {230u, 242u, 234u, 0u}, {180u, 215u, 193u, 0u}, + {147u, 198u, 166u, 0u}, {113u, 180u, 138u, 0u}, {80u, 162u, 111u, 0u}, {30u, 136u, 70u, 0u}, + {0u, 120u, 45u, 0u}, {0u, 114u, 43u, 0u}, {0u, 102u, 38u, 0u}, {0u, 95u, 35u, 0u}, + {0u, 83u, 31u, 0u}, {0u, 72u, 27u, 0u}, {0u, 63u, 24u, 0u}, {0u, 56u, 21u, 0u}, + {0u, 48u, 18u, 0u}, {0u, 36u, 14u, 0u}, {0u, 25u, 9u, 0u}, {0u, 17u, 6u, 0u}, + {0u, 9u, 3u, 0u}, {0u, 1u, 1u, 0u}, {254u, 244u, 220u, 0u}, {255u, 239u, 181u, 0u}, + {255u, 231u, 156u, 0u}, {255u, 222u, 132u, 0u}, {255u, 222u, 115u, 0u}, {255u, 214u, 99u, 0u}, + {255u, 206u, 66u, 0u}, {255u, 198u, 41u, 0u}, {255u, 185u, 0u, 0u}, {255u, 189u, 8u, 0u}, + {247u, 181u, 0u, 0u}, {222u, 156u, 0u, 0u}, {189u, 140u, 0u, 0u}, {173u, 123u, 0u, 0u}, + {148u, 107u, 0u, 0u}, {132u, 90u, 0u, 0u}, {107u, 74u, 0u, 0u}, {74u, 49u, 0u, 0u}, + {57u, 41u, 0u, 0u}, {33u, 24u, 0u, 0u}, {117u, 52u, 87u, 0u}, {176u, 158u, 50u, 0u}, + {122u, 165u, 29u, 0u}, {242u, 142u, 8u, 0u}, {164u, 43u, 36u, 0u}, {113u, 67u, 20u, 0u}, + {255u, 0u, 255u, 0u}, {255u, 0u, 255u, 0u}, {255u, 0u, 255u, 0u}, {255u, 0u, 255u, 0u}, + {255u, 0u, 255u, 0u}, {57u, 163u, 217u, 0u}, {255u, 255u, 255u, 0u}, {254u, 255u, 247u, 0u}, + {253u, 253u, 239u, 0u}, {248u, 247u, 247u, 0u}, {248u, 247u, 231u, 0u}, {240u, 240u, 240u, 0u}, + {239u, 239u, 218u, 0u}, {227u, 232u, 236u, 0u}, {224u, 221u, 209u, 0u}, {215u, 222u, 215u, 0u}, + {213u, 214u, 215u, 0u}, {214u, 214u, 203u, 0u}, {255u, 219u, 57u, 0u}, {206u, 206u, 206u, 0u}, + {206u, 206u, 198u, 0u}, {255u, 214u, 18u, 0u}, {207u, 203u, 186u, 0u}, {197u, 199u, 199u, 0u}, + {255u, 206u, 0u, 0u}, {207u, 198u, 159u, 0u}, {247u, 204u, 0u, 0u}, {189u, 198u, 189u, 0u}, + {189u, 189u, 189u, 0u}, {238u, 199u, 0u, 0u}, {189u, 189u, 181u, 0u}, {238u, 190u, 24u, 0u}, + {181u, 189u, 184u, 0u}, {161u, 186u, 224u, 0u}, {181u, 181u, 181u, 0u}, {231u, 189u, 0u, 0u}, + {173u, 182u, 173u, 0u}, {222u, 181u, 0u, 0u}, {173u, 173u, 173u, 0u}, {213u, 182u, 0u, 0u}, + {172u, 173u, 160u, 0u}, {214u, 173u, 0u, 0u}, {165u, 165u, 165u, 0u}, {206u, 173u, 0u, 0u}, + {160u, 168u, 151u, 0u}, {206u, 164u, 0u, 0u}, {198u, 165u, 0u, 0u}, {157u, 156u, 156u, 0u}, + {134u, 156u, 200u, 0u}, {153u, 156u, 144u, 0u}, {142u, 156u, 161u, 0u}, {189u, 156u, 0u, 0u}, + {148u, 148u, 148u, 0u}, {146u, 148u, 138u, 0u}, {133u, 143u, 161u, 0u}, {189u, 143u, 0u, 0u}, + {140u, 140u, 140u, 0u}, {177u, 147u, 0u, 0u}, {131u, 140u, 136u, 0u}, {146u, 130u, 126u, 0u}, + {170u, 137u, 0u, 0u}, {132u, 132u, 130u, 0u}, {123u, 125u, 125u, 0u}, {123u, 123u, 133u, 0u}, + {153u, 126u, 0u, 0u}, {114u, 116u, 118u, 0u}, {110u, 112u, 108u, 0u}, {97u, 109u, 136u, 0u}, + {127u, 108u, 6u, 0u}, {0u, 173u, 0u, 0u}, {100u, 99u, 101u, 0u}, {176u, 71u, 41u, 0u}, + {36u, 142u, 33u, 0u}, {98u, 91u, 75u, 0u}, {80u, 88u, 104u, 0u}, {252u, 0u, 0u, 0u}, + {78u, 71u, 73u, 0u}, {73u, 71u, 78u, 0u}, {62u, 63u, 61u, 0u}, {0u, 66u, 211u, 0u}, + {99u, 51u, 14u, 0u}, {198u, 0u, 0u, 0u}, {189u, 0u, 0u, 0u}, {0u, 57u, 206u, 0u}, + {181u, 0u, 0u, 0u}, {0u, 56u, 185u, 0u}, {173u, 0u, 0u, 0u}, {165u, 0u, 0u, 0u}, + {49u, 49u, 49u, 0u}, {0u, 49u, 165u, 0u}, {156u, 0u, 0u, 0u}, {42u, 45u, 60u, 0u}, + {148u, 0u, 0u, 0u}, {140u, 0u, 0u, 0u}, {41u, 41u, 41u, 0u}, {0u, 41u, 144u, 0u}, + {132u, 0u, 0u, 0u}, {123u, 0u, 0u, 0u}, {7u, 35u, 114u, 0u}, {34u, 36u, 32u, 0u}, + {115u, 0u, 0u, 0u}, {107u, 0u, 0u, 0u}, {90u, 0u, 0u, 0u}, {23u, 24u, 27u, 0u}, + {74u, 0u, 0u, 0u}, {15u, 15u, 16u, 0u}, {49u, 0u, 0u, 0u}, {16u, 12u, 4u, 0u}, + {7u, 8u, 8u, 0u}, {0u, 0u, 8u, 0u}, {255u, 251u, 240u, 0u}, {160u, 160u, 164u, 0u}, + {128u, 128u, 128u, 0u}, {255u, 0u, 0u, 0u}, {0u, 255u, 0u, 0u}, {255u, 255u, 0u, 0u}, + {0u, 0u, 255u, 0u}, {255u, 0u, 255u, 0u}, {0u, 255u, 255u, 0u}, {255u, 255u, 255u, 0u} +}; + +// FUNCTION: LEGO1 0x100bee30 +MxPalette::MxPalette() +{ + this->m_overrideSkyColor = FALSE; + this->m_palette = NULL; + GetDefaultPalette(this->m_entries); + this->m_skyColor = this->m_entries[141]; +} + +// FUNCTION: LEGO1 0x100beed0 +MxPalette::MxPalette(const RGBQUAD* p_colors) +{ + this->m_overrideSkyColor = FALSE; + this->m_palette = NULL; + ApplySystemEntriesToPalette(this->m_entries); + + for (MxS32 i = 10; i < 246; i++) { + this->m_entries[i].peRed = p_colors[i].rgbRed; + this->m_entries[i].peGreen = p_colors[i].rgbGreen; + this->m_entries[i].peBlue = p_colors[i].rgbBlue; + this->m_entries[i].peFlags = 0; + } + + this->m_skyColor = this->m_entries[141]; +} + +// FUNCTION: LEGO1 0x100bef90 +MxPalette::~MxPalette() +{ + if (m_palette) { + m_palette->Release(); + } +} + +// FUNCTION: LEGO1 0x100bf000 +LPDIRECTDRAWPALETTE MxPalette::CreateNativePalette() +{ + MxS32 i; + if (this->m_palette == NULL) { + for (i = 0; i < 10; i++) { + this->m_entries[i].peFlags = 0x80; + } + for (i = 10; i < 136; i++) { + this->m_entries[i].peFlags = 0x44; + } + for (i = 136; i < 140; i++) { + this->m_entries[i].peFlags = 0x84; + } + this->m_entries[140].peFlags = 0x84; + this->m_entries[141].peFlags = 0x44; + for (i = 142; i < 246; i++) { + this->m_entries[i].peFlags = 0x84; + } + for (i = 246; i < 256; i++) { + this->m_entries[i].peFlags = 0x80; + } + + if (MVideoManager() && MVideoManager()->GetDirectDraw()) { + MVideoManager()->GetDirectDraw()->CreatePalette(DDPCAPS_8BIT, this->m_entries, &this->m_palette, NULL); + } + } + + return this->m_palette; +} + +// FUNCTION: LEGO1 0x100bf0b0 +MxPalette* MxPalette::Clone() +{ + MxPalette* result = new MxPalette; + this->GetEntries(result->m_entries); + result->m_overrideSkyColor = this->m_overrideSkyColor; + return result; +} + +// FUNCTION: LEGO1 0x100bf150 +MxResult MxPalette::GetEntries(LPPALETTEENTRY p_entries) +{ + memcpy(p_entries, this->m_entries, sizeof(this->m_entries)); + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100bf170 +MxResult MxPalette::SetEntries(LPPALETTEENTRY p_entries) +{ + MxS32 i; + MxResult status = SUCCESS; + + if (this->m_palette) { + for (i = 0; i < 10; i++) { + this->m_entries[i].peFlags = 0x80; + } + for (i = 10; i < 136; i++) { + this->m_entries[i].peFlags = 68; + this->m_entries[i].peRed = p_entries[i].peRed; + this->m_entries[i].peGreen = p_entries[i].peGreen; + this->m_entries[i].peBlue = p_entries[i].peBlue; + } + for (i = 136; i < 140; i++) { + this->m_entries[i].peFlags = 132; + this->m_entries[i].peRed = p_entries[i].peRed; + this->m_entries[i].peGreen = p_entries[i].peGreen; + this->m_entries[i].peBlue = p_entries[i].peBlue; + } + if (!this->m_overrideSkyColor) { + this->m_entries[140].peFlags = 0x44; + this->m_entries[140].peRed = p_entries[140].peRed; + this->m_entries[140].peGreen = p_entries[140].peGreen; + this->m_entries[140].peBlue = p_entries[140].peBlue; + this->m_entries[141].peFlags = 0x84; + this->m_entries[141].peRed = p_entries[141].peRed; + this->m_entries[141].peGreen = p_entries[141].peGreen; + this->m_entries[141].peBlue = p_entries[141].peBlue; + } + + for (i = 142; i < 246; i++) { + this->m_entries[i].peFlags = 132; + this->m_entries[i].peRed = p_entries[i].peRed; + this->m_entries[i].peGreen = p_entries[i].peGreen; + this->m_entries[i].peBlue = p_entries[i].peBlue; + } + + for (i = 246; i < 256; i++) { + this->m_entries[i].peFlags = 0x80; + } + + if (this->m_palette->SetEntries(0, 0, 256, this->m_entries)) { + status = FAILURE; + } + } + + return status; +} + +// FUNCTION: LEGO1 0x100bf2d0 +MxResult MxPalette::SetSkyColor(LPPALETTEENTRY p_skyColor) +{ + MxResult status = 0; + if (this->m_palette != NULL) { + this->m_entries[141].peRed = p_skyColor->peRed; + this->m_entries[141].peGreen = p_skyColor->peGreen; + this->m_entries[141].peBlue = p_skyColor->peBlue; + this->m_skyColor = this->m_entries[141]; + if (this->m_palette->SetEntries(0, 141, 1, &this->m_skyColor)) { + status = -1; + } + } + return status; +} + +// FUNCTION: LEGO1 0x100bf330 +void MxPalette::Detach() +{ + this->m_palette = NULL; +} + +// FUNCTION: LEGO1 0x100bf340 +MxBool MxPalette::operator==(MxPalette& p_other) +{ + for (MxS32 i = 0; i < 256; i++) { + if (this->m_entries[i].peRed != p_other.m_entries[i].peRed) { + return FALSE; + } + if (this->m_entries[i].peGreen != p_other.m_entries[i].peGreen) { + return FALSE; + } + if (this->m_entries[i].peBlue != p_other.m_entries[i].peBlue) { + return FALSE; + } + } + return TRUE; +} + +// FUNCTION: LEGO1 0x100bf390 +void MxPalette::ApplySystemEntriesToPalette(LPPALETTEENTRY p_entries) +{ + HDC hdc; + + hdc = GetDC(0); + if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) { + GetSystemPaletteEntries(hdc, 0, 10, p_entries); + GetSystemPaletteEntries(hdc, 246, 10, &p_entries[246]); + } + else { + memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 10); + memcpy(&p_entries[246], &g_defaultPaletteEntries[246], sizeof(PALETTEENTRY) * 10); + } + ReleaseDC(0, hdc); +} + +// FUNCTION: LEGO1 0x100bf420 +void MxPalette::GetDefaultPalette(LPPALETTEENTRY p_entries) +{ + HDC hdc; + + hdc = GetDC(0); + if ((GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256) { + GetSystemPaletteEntries(hdc, 0, 256, p_entries); + memcpy(&p_entries[10], &g_defaultPaletteEntries[10], sizeof(PALETTEENTRY) * 236); + } + else { + memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 256); + } + + ReleaseDC(0, hdc); +} + +// FUNCTION: LEGO1 0x100bf490 +void MxPalette::Reset(MxBool p_ignoreSkyColor) +{ + if (this->m_palette != NULL) { + GetDefaultPalette(this->m_entries); + if (!p_ignoreSkyColor) { + this->m_entries[140] = this->m_entries[141] = this->m_skyColor; + } + SetEntries(this->m_entries); + this->m_palette->SetEntries(0, 0, 256, this->m_entries); + } +} diff --git a/LEGO1/omni/src/video/mxregion.cpp b/LEGO1/omni/src/video/mxregion.cpp new file mode 100644 index 00000000..ca3698e9 --- /dev/null +++ b/LEGO1/omni/src/video/mxregion.cpp @@ -0,0 +1,208 @@ +#include "mxregion.h" + +#include + +DECOMP_SIZE_ASSERT(MxRegion, 0x1c); +DECOMP_SIZE_ASSERT(MxRegionTopBottom, 0x0c); +DECOMP_SIZE_ASSERT(MxRegionLeftRight, 0x08); + +// FUNCTION: LEGO1 0x100c31c0 +MxRegion::MxRegion() +{ + m_list = new MxRegionTopBottomList; + m_rect = MxRect32(INT_MAX, INT_MAX, -1, -1); +} + +// FUNCTION: LEGO1 0x100c3660 +MxBool MxRegion::VTable0x20() +{ + return m_list->GetCount() == 0; +} + +// FUNCTION: LEGO1 0x100c3690 +MxRegion::~MxRegion() +{ + if (m_list) { + delete m_list; + } +} + +// FUNCTION: LEGO1 0x100c3700 +void MxRegion::Reset() +{ + m_list->DeleteAll(); + m_rect = MxRect32(INT_MAX, INT_MAX, -1, -1); +} + +// FUNCTION: LEGO1 0x100c3750 +void MxRegion::VTable0x18(MxRect32& p_rect) +{ + MxRect32 rect(p_rect); + MxRect32 newRect; + MxRegionTopBottomListCursor cursor(m_list); + MxRegionTopBottom* topBottom; + + while (rect.IsValid() && cursor.Next(topBottom)) { + if (topBottom->GetTop() >= rect.GetBottom()) { + MxRegionTopBottom* newTopBottom = new MxRegionTopBottom(rect); + cursor.Prepend(newTopBottom); + rect.SetTop(rect.GetBottom()); + } + else if (rect.GetTop() < topBottom->GetBottom()) { + if (rect.GetTop() < topBottom->GetTop()) { + newRect = rect; + newRect.SetBottom(topBottom->GetTop()); + MxRegionTopBottom* newTopBottom = new MxRegionTopBottom(newRect); + cursor.Prepend(newTopBottom); + rect.SetTop(topBottom->GetTop()); + } + else if (topBottom->GetTop() < rect.GetTop()) { + MxRegionTopBottom* newTopBottom = topBottom->Clone(); + newTopBottom->SetBottom(rect.GetTop()); + topBottom->SetTop(rect.GetTop()); + cursor.Prepend(newTopBottom); + } + + if (rect.GetBottom() < topBottom->GetBottom()) { + MxRegionTopBottom* newTopBottom = topBottom->Clone(); + newTopBottom->SetBottom(rect.GetBottom()); + topBottom->SetTop(rect.GetBottom()); + newTopBottom->FUN_100c5280(rect.GetLeft(), rect.GetRight()); + cursor.Prepend(newTopBottom); + rect.SetTop(rect.GetBottom()); + } + else { + topBottom->FUN_100c5280(rect.GetLeft(), rect.GetRight()); + rect.SetTop(topBottom->GetBottom()); + } + } + } + + if (rect.IsValid()) { + MxRegionTopBottom* newTopBottom = new MxRegionTopBottom(rect); + m_list->Append(newTopBottom); + } + + m_rect.UpdateBounds(p_rect); +} + +// FUNCTION: LEGO1 0x100c3e20 +MxBool MxRegion::VTable0x1c(MxRect32& p_rect) +{ + if (!m_rect.IntersectsWith(p_rect)) { + return FALSE; + } + + MxRegionTopBottomListCursor cursor(m_list); + MxRegionTopBottom* topBottom; + + while (cursor.Next(topBottom)) { + if (topBottom->GetTop() >= p_rect.GetBottom()) { + return FALSE; + } + if (topBottom->GetBottom() > p_rect.GetTop() && topBottom->FUN_100c57b0(p_rect)) { + return TRUE; + } + } + + return FALSE; +} + +// FUNCTION: LEGO1 0x100c4c90 +MxRegionTopBottom::MxRegionTopBottom(MxS32 p_top, MxS32 p_bottom) +{ + m_top = p_top; + m_bottom = p_bottom; + m_leftRightList = new MxRegionLeftRightList; +} + +// FUNCTION: LEGO1 0x100c50e0 +MxRegionTopBottom::MxRegionTopBottom(MxRect32& p_rect) +{ + m_top = p_rect.GetTop(); + m_bottom = p_rect.GetBottom(); + m_leftRightList = new MxRegionLeftRightList; + + MxRegionLeftRight* leftRight = new MxRegionLeftRight(p_rect.GetLeft(), p_rect.GetRight()); + m_leftRightList->Append(leftRight); +} + +// FUNCTION: LEGO1 0x100c5280 +void MxRegionTopBottom::FUN_100c5280(MxS32 p_left, MxS32 p_right) +{ + MxRegionLeftRightListCursor a(m_leftRightList); + MxRegionLeftRightListCursor b(m_leftRightList); + + MxRegionLeftRight* leftRight; + while (a.Next(leftRight) && leftRight->GetRight() < p_left) { + ; + } + + if (!a.HasMatch()) { + MxRegionLeftRight* copy = new MxRegionLeftRight(p_left, p_right); + m_leftRightList->Append(copy); + } + else { + if (p_left > leftRight->GetLeft()) { + p_left = leftRight->GetLeft(); + } + + while (leftRight->GetLeft() < p_right) { + if (p_right < leftRight->GetRight()) { + p_right = leftRight->GetRight(); + } + + b = a; + b.Next(); + a.Destroy(); + + if (!b.Current(leftRight)) { + break; + } + + a = b; + } + + if (a.HasMatch()) { + MxRegionLeftRight* copy = new MxRegionLeftRight(p_left, p_right); + a.Prepend(copy); + } + else { + MxRegionLeftRight* copy = new MxRegionLeftRight(p_left, p_right); + m_leftRightList->Append(copy); + } + } +} + +// FUNCTION: LEGO1 0x100c55d0 +MxRegionTopBottom* MxRegionTopBottom::Clone() +{ + MxRegionTopBottom* clone = new MxRegionTopBottom(m_top, m_bottom); + + MxRegionLeftRightListCursor cursor(m_leftRightList); + MxRegionLeftRight* leftRight; + + while (cursor.Next(leftRight)) { + clone->m_leftRightList->Append(leftRight->Clone()); + } + + return clone; +} + +// FUNCTION: LEGO1 0x100c57b0 +MxBool MxRegionTopBottom::FUN_100c57b0(MxRect32& p_rect) +{ + MxRegionLeftRightListCursor cursor(m_leftRightList); + MxRegionLeftRight* leftRight; + + while (cursor.Next(leftRight)) { + if (p_rect.GetRight() <= leftRight->GetLeft()) { + return FALSE; + } + if (leftRight->GetRight() > p_rect.GetLeft()) { + return TRUE; + } + } + + return FALSE; +} diff --git a/LEGO1/omni/src/video/mxregioncursor.cpp b/LEGO1/omni/src/video/mxregioncursor.cpp new file mode 100644 index 00000000..6b74ee3f --- /dev/null +++ b/LEGO1/omni/src/video/mxregioncursor.cpp @@ -0,0 +1,297 @@ +#include "mxregioncursor.h" + +DECOMP_SIZE_ASSERT(MxRegionCursor, 0x18); + +// FUNCTION: LEGO1 0x100c3f70 +MxRegionCursor::MxRegionCursor(MxRegion* p_region) +{ + m_region = p_region; + m_rect = NULL; + m_topBottomCursor = new MxRegionTopBottomListCursor(m_region->m_list); + m_leftRightCursor = NULL; +} + +// FUNCTION: LEGO1 0x100c40b0 +MxRegionCursor::~MxRegionCursor() +{ + if (m_rect) { + delete m_rect; + } + + if (m_topBottomCursor) { + delete m_topBottomCursor; + } + + if (m_leftRightCursor) { + delete m_leftRightCursor; + } +} + +// FUNCTION: LEGO1 0x100c4140 +MxRect32* MxRegionCursor::VTable0x18() +{ + m_topBottomCursor->Head(); + + MxRegionTopBottom* topBottom; + if (m_topBottomCursor->Current(topBottom)) { + FUN_100c46c0(*topBottom->m_leftRightList); + + MxRegionLeftRight* leftRight; + m_leftRightCursor->First(leftRight); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + } + else { + Reset(); + } + + return m_rect; +} + +// FUNCTION: LEGO1 0x100c41d0 +MxRect32* MxRegionCursor::VTable0x20() +{ + m_topBottomCursor->Tail(); + + MxRegionTopBottom* topBottom; + if (m_topBottomCursor->Current(topBottom)) { + FUN_100c46c0(*topBottom->m_leftRightList); + + MxRegionLeftRight* leftRight; + m_leftRightCursor->Last(leftRight); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + } + else { + Reset(); + } + + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4260 +MxRect32* MxRegionCursor::VTable0x28() +{ + MxRegionLeftRight* leftRight; + MxRegionTopBottom* topBottom; + + if (m_leftRightCursor && m_leftRightCursor->Next(leftRight)) { + m_topBottomCursor->Current(topBottom); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + return m_rect; + } + + if (m_topBottomCursor->Next(topBottom)) { + FUN_100c46c0(*topBottom->m_leftRightList); + m_leftRightCursor->First(leftRight); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + return m_rect; + } + + Reset(); + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4360 +MxRect32* MxRegionCursor::VTable0x30() +{ + MxRegionLeftRight* leftRight; + MxRegionTopBottom* topBottom; + + if (m_leftRightCursor && m_leftRightCursor->Prev(leftRight)) { + m_topBottomCursor->Current(topBottom); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + return m_rect; + } + + if (m_topBottomCursor->Prev(topBottom)) { + FUN_100c46c0(*topBottom->m_leftRightList); + m_leftRightCursor->Last(leftRight); + + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + return m_rect; + } + + Reset(); + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4460 +MxRect32* MxRegionCursor::VTable0x14(MxRect32& p_rect) +{ + m_topBottomCursor->Reset(); + FUN_100c4a20(p_rect); + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4480 +MxRect32* MxRegionCursor::VTable0x1c(MxRect32& p_rect) +{ + m_topBottomCursor->Reset(); + FUN_100c4b50(p_rect); + return m_rect; +} + +// FUNCTION: LEGO1 0x100c44a0 +MxRect32* MxRegionCursor::VTable0x24(MxRect32& p_rect) +{ + MxRegionLeftRight* leftRight; + + if (m_leftRightCursor && m_leftRightCursor->Next(leftRight)) { + MxRegionTopBottom* topBottom; + + m_topBottomCursor->Current(topBottom); + + if (topBottom->IntersectsWith(p_rect) && leftRight->IntersectsWith(p_rect)) { + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + m_rect->Intersect(p_rect); + } + else { + FUN_100c4a20(p_rect); + } + } + else { + FUN_100c4a20(p_rect); + } + + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4590 +MxRect32* MxRegionCursor::VTable0x2c(MxRect32& p_rect) +{ + MxRegionLeftRight* leftRight; + + if (m_leftRightCursor && m_leftRightCursor->Prev(leftRight)) { + MxRegionTopBottom* topBottom; + + m_topBottomCursor->Current(topBottom); + + if (topBottom->IntersectsWith(p_rect) && leftRight->IntersectsWith(p_rect)) { + UpdateRect(leftRight->GetLeft(), topBottom->GetTop(), leftRight->GetRight(), topBottom->GetBottom()); + m_rect->Intersect(p_rect); + } + else { + FUN_100c4b50(p_rect); + } + } + else { + FUN_100c4b50(p_rect); + } + + return m_rect; +} + +// FUNCTION: LEGO1 0x100c4680 +void MxRegionCursor::Reset() +{ + if (m_rect) { + delete m_rect; + m_rect = NULL; + } + + m_topBottomCursor->Reset(); + + if (m_leftRightCursor) { + delete m_leftRightCursor; + m_leftRightCursor = NULL; + } +} + +// FUNCTION: LEGO1 0x100c46c0 +void MxRegionCursor::FUN_100c46c0(MxRegionLeftRightList& p_leftRightList) +{ + if (m_leftRightCursor) { + delete m_leftRightCursor; + } + + m_leftRightCursor = new MxRegionLeftRightListCursor(&p_leftRightList); +} + +// FUNCTION: LEGO1 0x100c4980 +void MxRegionCursor::UpdateRect(MxS32 p_left, MxS32 p_top, MxS32 p_right, MxS32 p_bottom) +{ + if (!m_rect) { + m_rect = new MxRect32; + } + + m_rect->SetLeft(p_left); + m_rect->SetTop(p_top); + m_rect->SetRight(p_right); + m_rect->SetBottom(p_bottom); +} + +// FUNCTION: LEGO1 0x100c4a20 +void MxRegionCursor::FUN_100c4a20(MxRect32& p_rect) +{ + MxRegionTopBottom* topBottom; + while (m_topBottomCursor->Next(topBottom)) { + if (p_rect.GetBottom() <= topBottom->GetTop()) { + Reset(); + return; + } + + if (p_rect.GetTop() < topBottom->GetBottom()) { + FUN_100c46c0(*topBottom->m_leftRightList); + + MxRegionLeftRight* leftRight; + while (m_leftRightCursor->Next(leftRight)) { + if (p_rect.GetRight() <= leftRight->GetLeft()) { + break; + } + + if (p_rect.GetLeft() < leftRight->GetRight()) { + UpdateRect( + leftRight->GetLeft(), + topBottom->GetTop(), + leftRight->GetRight(), + topBottom->GetBottom() + ); + m_rect->Intersect(p_rect); + return; + } + } + } + } + + Reset(); +} + +// FUNCTION: LEGO1 0x100c4b50 +void MxRegionCursor::FUN_100c4b50(MxRect32& p_rect) +{ + MxRegionTopBottom* topBottom; + while (m_topBottomCursor->Prev(topBottom)) { + if (topBottom->GetBottom() <= p_rect.GetTop()) { + Reset(); + return; + } + + if (topBottom->GetTop() < p_rect.GetBottom()) { + FUN_100c46c0(*topBottom->m_leftRightList); + + MxRegionLeftRight* leftRight; + while (m_leftRightCursor->Prev(leftRight)) { + if (leftRight->GetRight() <= p_rect.GetLeft()) { + break; + } + + if (leftRight->GetLeft() < p_rect.GetRight()) { + UpdateRect( + leftRight->GetLeft(), + topBottom->GetTop(), + leftRight->GetRight(), + topBottom->GetBottom() + ); + m_rect->Intersect(p_rect); + return; + } + } + } + } + + Reset(); +} diff --git a/LEGO1/omni/src/video/mxsmack.cpp b/LEGO1/omni/src/video/mxsmack.cpp new file mode 100644 index 00000000..fd08e8a9 --- /dev/null +++ b/LEGO1/omni/src/video/mxsmack.cpp @@ -0,0 +1,265 @@ +#include "mxsmack.h" + +#include "mxbitmap.h" + +#include + +DECOMP_SIZE_ASSERT(SmackTag, 0x390); +DECOMP_SIZE_ASSERT(MxSmack, 0x6b8); + +// FUNCTION: LEGO1 0x100c5a90 +MxResult MxSmack::LoadHeader(MxU8* p_data, MxSmack* p_mxSmack) +{ +// Macros for readability +#define FRAME_COUNT(mxSmack) (p_mxSmack->m_smackTag.Frames + (p_mxSmack->m_smackTag.SmackerType & 1)) + + MxResult result = SUCCESS; + MxU8* frameTypes = NULL; + MxU8* huffmanTrees = NULL; + + if (!p_data || !p_mxSmack) { + result = FAILURE; + } + else { + p_mxSmack->m_frameTypes = NULL; + p_mxSmack->m_frameSizes = NULL; + p_mxSmack->m_huffmanTrees = NULL; + p_mxSmack->m_huffmanTables = NULL; + + memcpy(&p_mxSmack->m_smackTag, p_data, SmackHeaderSize(&p_mxSmack->m_smackTag)); + p_data += SmackHeaderSize(&p_mxSmack->m_smackTag); + + MxU32* frameSizes = new MxU32[FRAME_COUNT(p_mxSmack)]; + + if (!frameSizes) { + result = FAILURE; + } + else { + memcpy(frameSizes, p_data, FRAME_COUNT(p_mxSmack) * sizeof(MxU32)); + + p_data += FRAME_COUNT(p_mxSmack) * sizeof(MxU32); + p_mxSmack->m_maxFrameSize = 0; + + // TODO + for (MxU32 i = 0; i < FRAME_COUNT(p_mxSmack); i++) { + if (p_mxSmack->m_maxFrameSize < frameSizes[i]) { + p_mxSmack->m_maxFrameSize = frameSizes[i]; + } + } + + frameTypes = new MxU8[FRAME_COUNT(p_mxSmack)]; + + if (!frameTypes) { + result = FAILURE; + } + else { + memcpy(frameTypes, p_data, FRAME_COUNT(p_mxSmack)); + p_data += FRAME_COUNT(p_mxSmack); + + MxU32 treeSize = p_mxSmack->m_smackTag.tablesize + 0x1000; + if (treeSize <= 0x2000) { + treeSize = 0x2000; + } + + huffmanTrees = new MxU8[treeSize]; + + if (!huffmanTrees) { + result = FAILURE; + } + else { + memcpy(huffmanTrees + 0x1000, p_data, p_mxSmack->m_smackTag.tablesize); + + p_mxSmack->m_huffmanTables = new MxU8 + [p_mxSmack->m_smackTag.codesize + p_mxSmack->m_smackTag.absize + + p_mxSmack->m_smackTag.detailsize + p_mxSmack->m_smackTag.typesize + SmackGetSizeTables()]; + + if (!p_mxSmack->m_huffmanTables) { + result = FAILURE; + } + else { + SmackDoTables( + huffmanTrees, + p_mxSmack->m_huffmanTables, + p_mxSmack->m_smackTag.codesize, + p_mxSmack->m_smackTag.absize, + p_mxSmack->m_smackTag.detailsize, + p_mxSmack->m_smackTag.typesize + ); + + MxU32 size = SmackGetSizeDeltas(p_mxSmack->m_smackTag.Width, p_mxSmack->m_smackTag.Height) + 32; + p_mxSmack->m_unk0x6b4 = new MxU8[size]; + memset(p_mxSmack->m_unk0x6b4, 0, size); + + MxS32 width = p_mxSmack->m_smackTag.Width; + MxU32* data = (MxU32*) p_mxSmack->m_unk0x6b4; + + *data = 1; + data++; + *data = NULL; // MxU8* bitmapData + data++; + *data = p_mxSmack->m_smackTag.Width / 4; + data++; + *data = p_mxSmack->m_smackTag.Height / 4; + data++; + *data = width - 4; + data++; + *data = width * 3; + data++; + *data = width; + data++; + *data = width * 4 - p_mxSmack->m_smackTag.Width; + data++; + data++; + *data = p_mxSmack->m_smackTag.Width; + data++; + *data = p_mxSmack->m_smackTag.Height; + } + } + } + } + + p_mxSmack->m_frameTypes = frameTypes; + p_mxSmack->m_frameSizes = frameSizes; + p_mxSmack->m_huffmanTrees = huffmanTrees; + } + + return result; + +#undef FRAME_COUNT +} + +// FUNCTION: LEGO1 0x100c5d40 +void MxSmack::Destroy(MxSmack* p_mxSmack) +{ + if (p_mxSmack->m_frameSizes) { + delete[] p_mxSmack->m_frameSizes; + } + if (p_mxSmack->m_frameTypes) { + delete[] p_mxSmack->m_frameTypes; + } + if (p_mxSmack->m_huffmanTrees) { + delete[] p_mxSmack->m_huffmanTrees; + } + if (p_mxSmack->m_huffmanTables) { + delete[] p_mxSmack->m_huffmanTables; + } + if (p_mxSmack->m_unk0x6b4) { + delete[] p_mxSmack->m_unk0x6b4; + } +} + +// This should be refactored to somewhere else +inline MxLong AbsFlipped(MxLong p_value) +{ + return p_value > 0 ? p_value : -p_value; +} + +// FUNCTION: LEGO1 0x100c5db0 +MxResult MxSmack::LoadFrame( + MxBITMAPINFO* p_bitmapInfo, + MxU8* p_bitmapData, + MxSmack* p_mxSmack, + MxU8* p_chunkData, + MxBool p_paletteChanged, + MxRectList* p_list +) +{ + p_bitmapInfo->m_bmiHeader.biHeight = -AbsFlipped(p_bitmapInfo->m_bmiHeader.biHeight); + *(MxU8**) (p_mxSmack->m_unk0x6b4 + 4) = p_bitmapData; + + // Reference: https://wiki.multimedia.cx/index.php/Smacker#Palette_Chunk + if (p_paletteChanged) { + MxU8 palette[772]; + + MxU8* intoChunk = p_chunkData + 1; + MxU8* intoPalette = palette; + MxU16 paletteIndex = 0; + // TODO: struct incorrect, Palette at wrong offset? + MxU8* currentPalette = &p_mxSmack->m_smackTag.Palette[4]; + + do { + if (*intoChunk & 0x80) { + MxU8 length = (*intoChunk & 0x7f) + 1; + memcpy(intoPalette, ¤tPalette[paletteIndex * 3], length * 3); + intoPalette += length * 3; + paletteIndex += length; + intoChunk++; + } + else { + if (*intoChunk & 0x40) { + MxU8 length = (*intoChunk & 0x3f) + 1; + memcpy(intoPalette, ¤tPalette[*(intoChunk + 1) * 3], length * 3); + intoPalette += length * 3; + paletteIndex += length; + intoChunk += 2; + } + else { + *(MxU32*) intoPalette = *(MxU32*) intoChunk; + intoPalette += 3; + paletteIndex++; + intoChunk += 3; + } + } + } while (paletteIndex < 256); + + for (MxU32 i = 0; i < 256; i++) { + memcpy(currentPalette, &palette[i * 3], 3); + currentPalette += 3; + p_bitmapInfo->m_bmiColors[i].rgbBlue = palette[i * 3 + 2] * 4; + p_bitmapInfo->m_bmiColors[i].rgbGreen = palette[i * 3 + 1] * 4; + p_bitmapInfo->m_bmiColors[i].rgbRed = palette[i * 3] * 4; + } + + p_chunkData += *p_chunkData * 4; + } + + SmackDoFrameToBuffer(p_chunkData, p_mxSmack->m_huffmanTables, p_mxSmack->m_unk0x6b4); + + MxU16 und = 1; + u32 smackRect[4]; + MxRect32 rect; + + while (GetRect(p_mxSmack->m_unk0x6b4, &und, smackRect, &rect)) { + MxRect32* newRect = new MxRect32(rect); + p_list->Append(newRect); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100c6050 +MxBool MxSmack::GetRect(MxU8* p_unk0x6b4, MxU16* p_und, u32* p_smackRect, MxRect32* p_rect) +{ + u32 left, bottom, top, right; + + if (!*p_und) { + return FALSE; + } + + if (*p_und == 1) { + if (!SmackGetRect(p_unk0x6b4, p_smackRect)) { + return FALSE; + } + *p_und = 2; + } + + left = p_smackRect[0]; + top = p_smackRect[1]; + right = p_smackRect[2] + p_smackRect[0]; + bottom = p_smackRect[3] + p_smackRect[1]; + + while (SmackGetRect(p_unk0x6b4, p_smackRect)) { + if (left > p_smackRect[0]) { + left = p_smackRect[0]; + } + if (right < p_smackRect[0] + p_smackRect[2]) { + right = p_smackRect[0] + p_smackRect[2]; + } + + bottom = p_smackRect[1] + p_smackRect[3]; + } + + *p_und = 0; + *p_rect = MxRect32(left, top, right, bottom); + return TRUE; +} diff --git a/LEGO1/omni/src/video/mxsmkpresenter.cpp b/LEGO1/omni/src/video/mxsmkpresenter.cpp new file mode 100644 index 00000000..1ac6bd1e --- /dev/null +++ b/LEGO1/omni/src/video/mxsmkpresenter.cpp @@ -0,0 +1,129 @@ +#include "mxsmkpresenter.h" + +#include "decomp.h" +#include "mxdsmediaaction.h" +#include "mxmisc.h" +#include "mxpalette.h" +#include "mxvideomanager.h" + +DECOMP_SIZE_ASSERT(MxSmkPresenter, 0x720); + +// FUNCTION: LEGO1 0x100b3650 +MxSmkPresenter::MxSmkPresenter() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100b3870 +MxSmkPresenter::~MxSmkPresenter() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100b38d0 +void MxSmkPresenter::Init() +{ + m_currentFrame = 0; + memset(&m_mxSmack, 0, sizeof(m_mxSmack)); + SetBit1(FALSE); + SetBit2(FALSE); +} + +// FUNCTION: LEGO1 0x100b3900 +void MxSmkPresenter::Destroy(MxBool p_fromDestructor) +{ + m_criticalSection.Enter(); + + MxSmack::Destroy(&m_mxSmack); + Init(); + + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxVideoPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x100b3940 +void MxSmkPresenter::LoadHeader(MxStreamChunk* p_chunk) +{ + MxSmack::LoadHeader(p_chunk->GetData(), &m_mxSmack); +} + +// FUNCTION: LEGO1 0x100b3960 +void MxSmkPresenter::CreateBitmap() +{ + if (m_frameBitmap) { + delete m_frameBitmap; + } + + m_frameBitmap = new MxBitmap; + m_frameBitmap->SetSize(m_mxSmack.m_smackTag.Width, m_mxSmack.m_smackTag.Height, NULL, FALSE); +} + +// FUNCTION: LEGO1 0x100b3a00 +void MxSmkPresenter::LoadFrame(MxStreamChunk* p_chunk) +{ + MxBITMAPINFO* bitmapInfo = m_frameBitmap->GetBitmapInfo(); + MxU8* bitmapData = m_frameBitmap->GetImage(); + MxU8* chunkData = p_chunk->GetData(); + + MxBool paletteChanged = m_mxSmack.m_frameTypes[m_currentFrame] & 1; + m_currentFrame++; + VTable0x88(); + + MxRectList list(TRUE); + MxSmack::LoadFrame(bitmapInfo, bitmapData, &m_mxSmack, chunkData, paletteChanged, &list); + + if (((MxDSMediaAction*) m_action)->GetPaletteManagement() && paletteChanged) { + RealizePalette(); + } + + MxRect32 invalidateRect; + MxRectListCursor cursor(&list); + MxRect32* rect; + + while (cursor.Next(rect)) { + invalidateRect = *rect; + invalidateRect.AddPoint(GetLocation()); + MVideoManager()->InvalidateRect(invalidateRect); + } +} + +// FUNCTION: LEGO1 0x100b4260 +void MxSmkPresenter::VTable0x88() +{ + if ((m_mxSmack.m_smackTag.SmackerType & 1) != 0) { + MxU32 und = (m_currentFrame % m_mxSmack.m_smackTag.Frames); + if (1 < m_currentFrame && und == 1) { + m_currentFrame = 1; + } + } + else { + if (m_mxSmack.m_smackTag.Frames == m_currentFrame) { + m_currentFrame = 0; + // TODO: struct incorrect, Palette at wrong offset? + memset(&m_mxSmack.m_smackTag.Palette[4], 0, sizeof(m_mxSmack.m_smackTag.Palette)); + } + } +} + +// FUNCTION: LEGO1 0x100b42c0 +void MxSmkPresenter::RealizePalette() +{ + MxPalette* palette = m_frameBitmap->CreatePalette(); + MVideoManager()->RealizePalette(palette); + delete palette; +} + +// FUNCTION: LEGO1 0x100b42f0 +MxResult MxSmkPresenter::AddToManager() +{ + return MxVideoPresenter::AddToManager(); +} + +// FUNCTION: LEGO1 0x100b4300 +void MxSmkPresenter::Destroy() +{ + Destroy(FALSE); +} diff --git a/LEGO1/omni/src/video/mxstillpresenter.cpp b/LEGO1/omni/src/video/mxstillpresenter.cpp new file mode 100644 index 00000000..53fb3b35 --- /dev/null +++ b/LEGO1/omni/src/video/mxstillpresenter.cpp @@ -0,0 +1,270 @@ +#include "mxstillpresenter.h" + +#include "decomp.h" +#include "define.h" +#include "mxcompositepresenter.h" +#include "mxdisplaysurface.h" +#include "mxdsmediaaction.h" +#include "mxdssubscriber.h" +#include "mxmisc.h" +#include "mxomni.h" +#include "mxpalette.h" +#include "mxutilities.h" +#include "mxvideomanager.h" + +DECOMP_SIZE_ASSERT(MxStillPresenter, 0x6c); + +// FUNCTION: LEGO1 0x100b9c70 +void MxStillPresenter::Destroy(MxBool p_fromDestructor) +{ + m_criticalSection.Enter(); + + if (m_bitmapInfo) { + delete m_bitmapInfo; + } + m_bitmapInfo = NULL; + + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxVideoPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x100b9cc0 +void MxStillPresenter::LoadHeader(MxStreamChunk* p_chunk) +{ + if (m_bitmapInfo) { + delete m_bitmapInfo; + } + + MxU8* data = new MxU8[p_chunk->GetLength()]; + m_bitmapInfo = (MxBITMAPINFO*) data; + memcpy(m_bitmapInfo, p_chunk->GetData(), p_chunk->GetLength()); +} + +// FUNCTION: LEGO1 0x100b9d10 +void MxStillPresenter::CreateBitmap() +{ + if (m_frameBitmap) { + delete m_frameBitmap; + } + + m_frameBitmap = new MxBitmap; + m_frameBitmap->ImportBitmapInfo(m_bitmapInfo); + + delete m_bitmapInfo; + m_bitmapInfo = NULL; +} + +// FUNCTION: LEGO1 0x100b9db0 +void MxStillPresenter::NextFrame() +{ + MxStreamChunk* chunk = NextChunk(); + LoadFrame(chunk); + m_subscriber->FreeDataChunk(chunk); +} + +// FUNCTION: LEGO1 0x100b9dd0 +void MxStillPresenter::LoadFrame(MxStreamChunk* p_chunk) +{ + memcpy(m_frameBitmap->GetImage(), p_chunk->GetData(), p_chunk->GetLength()); + + // MxRect32 rect(m_location, MxSize32(GetWidth(), GetHeight())); + MxS32 height = GetHeight() - 1; + MxS32 width = GetWidth() - 1; + MxS32 x = m_location.GetX(); + MxS32 y = m_location.GetY(); + + MxRect32 rect(x, y, width + x, height + y); + MVideoManager()->InvalidateRect(rect); + + if (GetBit1()) { + undefined4 und = 0; + m_unk0x58 = MxOmni::GetInstance()->GetVideoManager()->GetDisplaySurface()->VTable0x44( + m_frameBitmap, + &und, + GetBit3(), + m_action->GetFlags() & MxDSAction::c_bit4 + ); + + delete m_alpha; + m_alpha = new AlphaMask(*m_frameBitmap); + + delete m_frameBitmap; + m_frameBitmap = NULL; + + if (m_unk0x58 && und) { + SetBit2(TRUE); + } + else { + SetBit2(FALSE); + } + } +} + +// FUNCTION: LEGO1 0x100b9f30 +void MxStillPresenter::RealizePalette() +{ + MxPalette* palette = m_frameBitmap->CreatePalette(); + MVideoManager()->RealizePalette(palette); + delete palette; +} + +// FUNCTION: LEGO1 0x100b9f60 +void MxStillPresenter::StartingTickle() +{ + MxVideoPresenter::StartingTickle(); + + if (m_currentTickleState == e_streaming && ((MxDSMediaAction*) m_action)->GetPaletteManagement()) { + RealizePalette(); + } +} + +// FUNCTION: LEGO1 0x100b9f90 +void MxStillPresenter::StreamingTickle() +{ + MxStreamChunk* chunk = CurrentChunk(); + + if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) { + m_chunkTime = chunk->GetTime(); + NextFrame(); + ProgressTickleState(e_repeating); + + if (m_action->GetDuration() == -1 && m_compositePresenter) { + m_compositePresenter->VTable0x60(this); + } + } +} + +// FUNCTION: LEGO1 0x100b9ff0 +void MxStillPresenter::RepeatingTickle() +{ + if (m_action->GetDuration() != -1) { + if (m_action->GetElapsedTime() >= m_action->GetStartTime() + m_action->GetDuration()) { + ProgressTickleState(e_freezing); + } + } +} + +// FUNCTION: LEGO1 0x100ba040 +void MxStillPresenter::SetPosition(MxS32 p_x, MxS32 p_y) +{ + MxS32 x = m_location.GetX(); + MxS32 y = m_location.GetY(); + m_location.SetX(p_x); + m_location.SetY(p_y); + + if (IsEnabled()) { + // Most likely needs to work with MxSize32 and MxPoint32 + MxS32 height = GetHeight() - 1; + MxS32 width = GetWidth() - 1; + + MxRect32 rectA(x, y, width + x, height + y); + MxRect32 rectB(m_location.GetX(), m_location.GetY(), width + m_location.GetX(), height + m_location.GetY()); + + MVideoManager()->InvalidateRect(rectA); + MVideoManager()->UpdateView(rectA.GetLeft(), rectA.GetTop(), rectA.GetWidth(), rectA.GetHeight()); + + MVideoManager()->InvalidateRect(rectB); + MVideoManager()->UpdateView(rectB.GetLeft(), rectB.GetTop(), rectB.GetWidth(), rectB.GetHeight()); + } +} + +// FUNCTION: LEGO1 0x100ba140 +void MxStillPresenter::Enable(MxBool p_enable) +{ + MxPresenter::Enable(p_enable); + + if (MVideoManager() && (m_alpha || m_frameBitmap)) { + // MxRect32 rect(m_location, MxSize32(GetWidth(), GetHeight())); + MxS32 height = GetHeight(); + MxS32 width = GetWidth(); + MxS32 x = m_location.GetX(); + MxS32 y = m_location.GetY(); + + MxRect32 rect(x, y, width + x, height + y); + MVideoManager()->InvalidateRect(rect); + MVideoManager()->UpdateView(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight()); + } +} + +// FUNCTION: LEGO1 0x100ba1e0 +void MxStillPresenter::ParseExtra() +{ + MxPresenter::ParseExtra(); + + if (m_action->GetFlags() & MxDSAction::c_bit5) { + SetBit3(TRUE); + } + + MxU16 extraLength; + char* extraData; + m_action->GetExtra(extraLength, extraData); + + if (extraLength & MAXWORD) { + char extraCopy[512]; + memcpy(extraCopy, extraData, extraLength & MAXWORD); + extraCopy[extraLength & MAXWORD] = '\0'; + + char output[512]; + if (KeyValueStringParse(output, g_strVISIBILITY, extraCopy)) { + if (strcmpi(output, "FALSE") == 0) { + Enable(FALSE); + } + } + + if (KeyValueStringParse(output, g_strBMP_ISMAP, extraCopy)) { + SetBit4(TRUE); + SetBit1(FALSE); + SetBit2(FALSE); + } + } +} + +// FUNCTION: LEGO1 0x100ba2c0 +MxStillPresenter* MxStillPresenter::Clone() +{ + MxResult result = FAILURE; + MxStillPresenter* presenter = new MxStillPresenter; + + if (presenter) { + if (presenter->AddToManager() == SUCCESS) { + MxDSAction* action = GetAction()->Clone(); + + if (action && presenter->StartAction(NULL, action) == SUCCESS) { + presenter->SetBit0(GetBit0()); + presenter->SetBit1(GetBit1()); + presenter->SetBit2(GetBit2()); + presenter->SetBit3(GetBit3()); + presenter->SetBit4(GetBit4()); + + if (m_frameBitmap) { + presenter->m_frameBitmap = new MxBitmap; + + if (!presenter->m_frameBitmap || presenter->m_frameBitmap->ImportBitmap(m_frameBitmap) != SUCCESS) { + goto done; + } + } + + if (m_unk0x58) { + presenter->m_unk0x58 = MxDisplaySurface::CopySurface(m_unk0x58); + } + + if (m_alpha) { + presenter->m_alpha = new MxVideoPresenter::AlphaMask(*m_alpha); + } + + result = SUCCESS; + } + } + } + +done: + if (result != SUCCESS) { + delete presenter; + presenter = NULL; + } + + return presenter; +} diff --git a/LEGO1/omni/src/video/mxvideomanager.cpp b/LEGO1/omni/src/video/mxvideomanager.cpp new file mode 100644 index 00000000..f3bf04fd --- /dev/null +++ b/LEGO1/omni/src/video/mxvideomanager.cpp @@ -0,0 +1,351 @@ +#include "mxvideomanager.h" + +#include "mxautolock.h" +#include "mxdisplaysurface.h" +#include "mxmisc.h" +#include "mxomni.h" +#include "mxpalette.h" +#include "mxpresenter.h" +#include "mxregion.h" +#include "mxthread.h" +#include "mxticklemanager.h" + +DECOMP_SIZE_ASSERT(MxVideoManager, 0x64) + +// FUNCTION: LEGO1 0x100be1f0 +MxVideoManager::MxVideoManager() +{ + Init(); +} + +// FUNCTION: LEGO1 0x100be270 +void MxVideoManager::UpdateView(MxU32 p_x, MxU32 p_y, MxU32 p_width, MxU32 p_height) +{ +} + +// FUNCTION: LEGO1 0x100be2a0 +MxVideoManager::~MxVideoManager() +{ + Destroy(TRUE); +} + +// FUNCTION: LEGO1 0x100be320 +MxResult MxVideoManager::Init() +{ + this->m_pDirectDraw = NULL; + this->m_pDirect3D = NULL; + this->m_displaySurface = NULL; + this->m_region = NULL; + this->m_videoParam.SetPalette(NULL); + this->m_unk0x60 = FALSE; + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100be340 +void MxVideoManager::Destroy(MxBool p_fromDestructor) +{ + if (m_thread) { + m_thread->Terminate(); + delete m_thread; + } + else { + TickleManager()->UnregisterClient(this); + } + + m_criticalSection.Enter(); + + if (m_displaySurface) { + delete m_displaySurface; + } + + if (m_region) { + delete m_region; + } + + if (m_videoParam.GetPalette()) { + delete m_videoParam.GetPalette(); + } + + if (m_unk0x60) { + if (m_pDirectDraw) { + m_pDirectDraw->Release(); + } + if (m_pDirect3D) { + m_pDirect3D->Release(); + } + } + + Init(); + m_criticalSection.Leave(); + + if (!p_fromDestructor) { + MxMediaManager::Destroy(); + } +} + +// FUNCTION: LEGO1 0x100be3e0 +void MxVideoManager::UpdateRegion() +{ + if (m_region->VTable0x20() == FALSE) { + MxRect32 rect(m_region->GetRect()); + rect.Intersect(m_videoParam.GetRect()); + + m_displaySurface + ->Display(rect.GetLeft(), rect.GetTop(), rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight()); + } +} + +// FUNCTION: LEGO1 0x100be440 +void MxVideoManager::SortPresenterList() +{ + if (this->m_presenters->GetCount() <= 1) { + return; + } + + MxPresenterListCursor a(this->m_presenters); + MxPresenterListCursor b(this->m_presenters); + MxU32 count = this->m_presenters->GetCount() - 1; + MxBool finished; + + if (count != 0) { + do { + a.Reset(); + b.Head(); + + finished = TRUE; + for (MxU32 i = count; i != 0; i--) { + MxPresenter *presenterA, *presenterB; + + a.Next(presenterA); + b.Next(presenterB); + + if (presenterA->GetDisplayZ() < presenterB->GetDisplayZ()) { + a.SetValue(presenterB); + b.SetValue(presenterA); + finished = FALSE; + } + } + } while (!finished && --count != 0); + } +} + +// FUNCTION: LEGO1 0x100be600 +MxResult MxVideoManager::VTable0x28( + MxVideoParam& p_videoParam, + LPDIRECTDRAW p_pDirectDraw, + LPDIRECT3D2 p_pDirect3D, + LPDIRECTDRAWSURFACE p_ddSurface1, + LPDIRECTDRAWSURFACE p_ddSurface2, + LPDIRECTDRAWCLIPPER p_ddClipper, + MxU32 p_frequencyMS, + MxBool p_createThread +) +{ + MxBool locked = FALSE; + MxResult status = FAILURE; + + m_unk0x60 = FALSE; + + if (MxMediaManager::InitPresenters() != SUCCESS) { + goto done; + } + + m_criticalSection.Enter(); + locked = TRUE; + + m_videoParam = p_videoParam; + m_region = new MxRegion(); + + if (!m_region) { + goto done; + } + + m_pDirectDraw = p_pDirectDraw; + m_pDirect3D = p_pDirect3D; + + MxPalette* palette; + if (p_videoParam.GetPalette() == NULL) { + palette = new MxPalette(); + m_videoParam.SetPalette(palette); + + if (!palette) { + goto done; + } + } + else { + palette = p_videoParam.GetPalette()->Clone(); + m_videoParam.SetPalette(palette); + + if (!palette) { + goto done; + } + } + + m_displaySurface = new MxDisplaySurface(); + if (m_displaySurface && m_displaySurface->Init(m_videoParam, p_ddSurface1, p_ddSurface2, p_ddClipper) == SUCCESS) { + m_displaySurface->SetPalette(m_videoParam.GetPalette()); + + if (p_createThread) { + m_thread = new MxTickleThread(this, p_frequencyMS); + + if (!m_thread || m_thread->Start(0, 0) != SUCCESS) { + goto done; + } + } + else { + TickleManager()->RegisterClient(this, p_frequencyMS); + } + + status = SUCCESS; + } + +done: + if (status != SUCCESS) { + Destroy(); + } + + if (locked) { + m_criticalSection.Leave(); + } + + return status; +} + +// FUNCTION: LEGO1 0x100be820 +MxResult MxVideoManager::Create(MxVideoParam& p_videoParam, MxU32 p_frequencyMS, MxBool p_createThread) +{ + MxBool locked = FALSE; + MxResult status = FAILURE; + + m_unk0x60 = TRUE; + + if (MxMediaManager::InitPresenters() != SUCCESS) { + goto done; + } + + m_criticalSection.Enter(); + locked = TRUE; + + m_videoParam = p_videoParam; + m_region = new MxRegion(); + + if (!m_region) { + goto done; + } + + if (DirectDrawCreate(NULL, &m_pDirectDraw, NULL) != DD_OK) { + goto done; + } + + if (m_pDirectDraw->SetCooperativeLevel(MxOmni::GetInstance()->GetWindowHandle(), DDSCL_NORMAL) != DD_OK) { + goto done; + } + + MxPalette* palette; + if (p_videoParam.GetPalette() == NULL) { + palette = new MxPalette(); + m_videoParam.SetPalette(palette); + + if (!palette) { + goto done; + } + } + else { + palette = p_videoParam.GetPalette()->Clone(); + m_videoParam.SetPalette(palette); + + if (!palette) { + goto done; + } + } + + m_displaySurface = new MxDisplaySurface(); + if (m_displaySurface && m_displaySurface->Create(m_videoParam) == SUCCESS) { + m_displaySurface->SetPalette(m_videoParam.GetPalette()); + + if (p_createThread) { + m_thread = new MxTickleThread(this, p_frequencyMS); + + if (!m_thread || m_thread->Start(0, 0) != SUCCESS) { + goto done; + } + } + else { + TickleManager()->RegisterClient(this, p_frequencyMS); + } + + status = SUCCESS; + } + +done: + if (status != SUCCESS) { + Destroy(); + } + + if (locked) { + m_criticalSection.Leave(); + } + + return status; +} + +// FUNCTION: LEGO1 0x100bea50 +void MxVideoManager::Destroy() +{ + Destroy(FALSE); +} + +// FUNCTION: LEGO1 0x100bea60 +void MxVideoManager::InvalidateRect(MxRect32& p_rect) +{ + m_criticalSection.Enter(); + + if (m_region) { + m_region->VTable0x18(p_rect); + } + + m_criticalSection.Leave(); +} + +// FUNCTION: LEGO1 0x100bea90 +MxResult MxVideoManager::Tickle() +{ + AUTOLOCK(m_criticalSection); + + SortPresenterList(); + + MxPresenter* presenter; + MxPresenterListCursor cursor(this->m_presenters); + + while (cursor.Next(presenter)) { + presenter->Tickle(); + } + + cursor.Reset(); + + while (cursor.Next(presenter)) { + presenter->PutData(); + } + + UpdateRegion(); + m_region->Reset(); + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100bebe0 +MxResult MxVideoManager::RealizePalette(MxPalette* p_palette) +{ + PALETTEENTRY paletteEntries[256]; + + this->m_criticalSection.Enter(); + + if (p_palette && this->m_videoParam.GetPalette()) { + p_palette->GetEntries(paletteEntries); + this->m_videoParam.GetPalette()->SetEntries(paletteEntries); + this->m_displaySurface->SetPalette(this->m_videoParam.GetPalette()); + } + + this->m_criticalSection.Leave(); + return SUCCESS; +} diff --git a/LEGO1/omni/src/video/mxvideoparam.cpp b/LEGO1/omni/src/video/mxvideoparam.cpp new file mode 100644 index 00000000..8e48773f --- /dev/null +++ b/LEGO1/omni/src/video/mxvideoparam.cpp @@ -0,0 +1,84 @@ +#include "mxvideoparam.h" + +#include "decomp.h" + +#include +#include + +DECOMP_SIZE_ASSERT(MxVideoParam, 0x24); + +// FUNCTION: LEGO1 0x100bec70 +MxVideoParam::MxVideoParam() +{ + this->m_rect.SetRight(640); + this->m_rect.SetBottom(480); + this->m_rect.SetLeft(0); + this->m_rect.SetTop(0); + this->m_palette = NULL; + this->m_backBuffers = 0; + this->m_unk0x1c = 0; + this->m_deviceId = NULL; +} + +// FUNCTION: LEGO1 0x100beca0 +MxVideoParam::MxVideoParam(MxRect32& p_rect, MxPalette* p_palette, MxULong p_backBuffers, MxVideoParamFlags& p_flags) +{ + this->m_rect = p_rect; + this->m_palette = p_palette; + this->m_backBuffers = p_backBuffers; + this->m_flags = p_flags; + this->m_unk0x1c = 0; + this->m_deviceId = NULL; +} + +// FUNCTION: LEGO1 0x100becf0 +MxVideoParam::MxVideoParam(MxVideoParam& p_videoParam) +{ + this->m_rect = p_videoParam.m_rect; + this->m_palette = p_videoParam.m_palette; + this->m_backBuffers = p_videoParam.m_backBuffers; + this->m_flags = p_videoParam.m_flags; + this->m_unk0x1c = p_videoParam.m_unk0x1c; + this->m_deviceId = NULL; + SetDeviceName(p_videoParam.m_deviceId); +} + +// FUNCTION: LEGO1 0x100bed50 +MxVideoParam::~MxVideoParam() +{ + if (this->m_deviceId != NULL) { + delete[] this->m_deviceId; + } +} + +// FUNCTION: LEGO1 0x100bed70 +void MxVideoParam::SetDeviceName(char* p_deviceId) +{ + if (this->m_deviceId != NULL) { + delete[] this->m_deviceId; + } + + if (p_deviceId != NULL) { + this->m_deviceId = new char[strlen(p_deviceId) + 1]; + + if (this->m_deviceId != NULL) { + strcpy(this->m_deviceId, p_deviceId); + } + } + else { + this->m_deviceId = NULL; + } +} + +// FUNCTION: LEGO1 0x100bede0 +MxVideoParam& MxVideoParam::operator=(const MxVideoParam& p_videoParam) +{ + this->m_rect = p_videoParam.m_rect; + this->m_palette = p_videoParam.m_palette; + this->m_backBuffers = p_videoParam.m_backBuffers; + this->m_flags = p_videoParam.m_flags; + this->m_unk0x1c = p_videoParam.m_unk0x1c; + SetDeviceName(p_videoParam.m_deviceId); + + return *this; +} diff --git a/LEGO1/omni/src/video/mxvideoparamflags.cpp b/LEGO1/omni/src/video/mxvideoparamflags.cpp new file mode 100644 index 00000000..967ec824 --- /dev/null +++ b/LEGO1/omni/src/video/mxvideoparamflags.cpp @@ -0,0 +1,15 @@ +#include "mxvideoparamflags.h" + +// FUNCTION: LEGO1 0x100bec40 +MxVideoParamFlags::MxVideoParamFlags() +{ + this->SetFullScreen(0); + this->SetFlipSurfaces(0); + this->SetBackBuffers(0); + this->SetF1bit3(0); + this->SetF1bit4(0); + this->Set16Bit(0); + this->SetWideViewAngle(1); + this->SetF1bit7(1); + this->SetF2bit1(1); +} diff --git a/LEGO1/omni/src/video/mxvideopresenter.cpp b/LEGO1/omni/src/video/mxvideopresenter.cpp new file mode 100644 index 00000000..c94e656c --- /dev/null +++ b/LEGO1/omni/src/video/mxvideopresenter.cpp @@ -0,0 +1,580 @@ +#include "mxvideopresenter.h" + +#include "mxautolock.h" +#include "mxdisplaysurface.h" +#include "mxdsmediaaction.h" +#include "mxdssubscriber.h" +#include "mxmisc.h" +#include "mxregioncursor.h" +#include "mxvideomanager.h" + +DECOMP_SIZE_ASSERT(MxVideoPresenter, 0x64); +DECOMP_SIZE_ASSERT(MxVideoPresenter::AlphaMask, 0x0c); + +// FUNCTION: LEGO1 0x100b24f0 +MxVideoPresenter::AlphaMask::AlphaMask(const MxBitmap& p_bitmap) +{ + m_width = p_bitmap.GetBmiWidth(); + // DECOMP: ECX becomes word-sized if these are not two separate actions. + MxLong height = p_bitmap.GetBmiHeightAbs(); + m_height = height; + + MxS32 size = ((m_width * m_height) / 8) + 1; + m_bitmask = new MxU8[size]; + memset(m_bitmask, 0, size); + + MxU32 rowsBeforeTop; + MxU8* bitmapSrcPtr; + + // The goal here is to enable us to walk through the bitmap's rows + // in order, regardless of the orientation. We want to end up at the + // start of the first row, which is either at position 0, or at + // (image_stride * biHeight) - 1. + + // Reminder: Negative biHeight means this is a top-down DIB. + // Otherwise it is bottom-up. + + switch (p_bitmap.GetBmiHeader()->biCompression) { + case BI_RGB: { + if (p_bitmap.GetBmiHeight() < 0) { + rowsBeforeTop = 0; + } + else { + rowsBeforeTop = p_bitmap.GetBmiHeightAbs() - 1; + } + bitmapSrcPtr = p_bitmap.GetImage() + (p_bitmap.GetBmiStride() * rowsBeforeTop); + break; + } + case BI_RGB_TOPDOWN: + bitmapSrcPtr = p_bitmap.GetImage(); + break; + default: { + if (p_bitmap.GetBmiHeight() < 0) { + rowsBeforeTop = 0; + } + else { + rowsBeforeTop = p_bitmap.GetBmiHeightAbs() - 1; + } + bitmapSrcPtr = p_bitmap.GetImage() + (p_bitmap.GetBmiStride() * rowsBeforeTop); + } + } + + // How many bytes are there for each row of the bitmap? + // (i.e. the image stride) + // If this is a bottom-up DIB, we will walk it in reverse. + // TODO: Same rounding trick as in MxBitmap + MxS32 rowSeek = ((m_width + 3) & -4); + if (p_bitmap.GetBmiHeader()->biCompression != BI_RGB_TOPDOWN && p_bitmap.GetBmiHeight() > 0) { + rowSeek = -rowSeek; + } + + // The actual offset into the m_bitmask array. The two for-loops + // are just for counting the pixels. + MxS32 offset = 0; + + for (MxS32 j = 0; j < m_height; j++) { + MxU8* tPtr = bitmapSrcPtr; + for (MxS32 i = 0; i < m_width; i++) { + if (*tPtr) { + // TODO: Second CDQ instruction for abs() should not be there. + MxU32 shift = abs(offset) & 7; + m_bitmask[offset / 8] |= (1 << abs((MxS32) shift)); + } + tPtr++; + offset++; + } + // Seek to the start of the next row + bitmapSrcPtr += rowSeek; + tPtr = bitmapSrcPtr; + } +} + +// FUNCTION: LEGO1 0x100b2670 +MxVideoPresenter::AlphaMask::AlphaMask(const MxVideoPresenter::AlphaMask& p_alpha) +{ + m_width = p_alpha.m_width; + m_height = p_alpha.m_height; + + MxS32 size = ((m_width * m_height) / 8) + 1; + m_bitmask = new MxU8[size]; + memcpy(m_bitmask, p_alpha.m_bitmask, size); +} + +// FUNCTION: LEGO1 0x100b26d0 +MxVideoPresenter::AlphaMask::~AlphaMask() +{ + if (m_bitmask) { + delete[] m_bitmask; + } +} + +// FUNCTION: LEGO1 0x100b26f0 +MxS32 MxVideoPresenter::AlphaMask::IsHit(MxU32 p_x, MxU32 p_y) +{ + if (p_x >= m_width || p_y >= m_height) { + return 0; + } + + MxS32 pos = p_y * m_width + p_x; + return m_bitmask[pos / 8] & (1 << abs(abs(pos) & 7)) ? 1 : 0; +} + +// FUNCTION: LEGO1 0x100b2760 +void MxVideoPresenter::Init() +{ + m_frameBitmap = NULL; + m_alpha = NULL; + m_unk0x5c = 1; + m_unk0x58 = NULL; + m_unk0x60 = -1; + SetBit0(FALSE); + + if (MVideoManager() != NULL) { + MVideoManager(); + SetBit1(TRUE); + SetBit2(FALSE); + } + + SetBit3(FALSE); + SetBit4(FALSE); +} + +// FUNCTION: LEGO1 0x100b27b0 +void MxVideoPresenter::Destroy(MxBool p_fromDestructor) +{ + if (MVideoManager() != NULL) { + MVideoManager()->UnregisterPresenter(*this); + } + + if (m_unk0x58) { + m_unk0x58->Release(); + m_unk0x58 = NULL; + SetBit1(FALSE); + SetBit2(FALSE); + } + + if (MVideoManager() && (m_alpha || m_frameBitmap)) { + // MxRect32 rect(m_location, MxSize32(GetWidth(), GetHeight())); + MxS32 height = GetHeight(); + MxS32 width = GetWidth(); + MxS32 x = m_location.GetX(); + MxS32 y = m_location.GetY(); + + MxRect32 rect(x, y, x + width, y + height); + MVideoManager()->InvalidateRect(rect); + MVideoManager()->UpdateView(rect.GetLeft(), rect.GetTop(), rect.GetWidth(), rect.GetHeight()); + } + + delete m_frameBitmap; + delete m_alpha; + + Init(); + + if (!p_fromDestructor) { + MxMediaPresenter::Destroy(FALSE); + } +} + +// FUNCTION: LEGO1 0x100b28b0 +void MxVideoPresenter::NextFrame() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk->GetChunkFlags() & DS_CHUNK_END_OF_STREAM) { + m_subscriber->FreeDataChunk(chunk); + ProgressTickleState(e_repeating); + } + else { + LoadFrame(chunk); + m_subscriber->FreeDataChunk(chunk); + } +} + +// FUNCTION: LEGO1 0x100b2900 +MxBool MxVideoPresenter::IsHit(MxS32 p_x, MxS32 p_y) +{ + MxDSAction* action = GetAction(); + if ((action == NULL) || (((action->GetFlags() & MxDSAction::c_bit11) == 0) && !IsEnabled()) || + (!m_frameBitmap && !m_alpha)) { + return FALSE; + } + + if (!m_frameBitmap) { + return m_alpha->IsHit(p_x - m_location.GetX(), p_y - m_location.GetY()); + } + + MxLong heightAbs = m_frameBitmap->GetBmiHeightAbs(); + + MxLong minX = m_location.GetX(); + MxLong minY = m_location.GetY(); + + MxLong maxY = minY + heightAbs; + MxLong maxX = minX + m_frameBitmap->GetBmiWidth(); + + if (p_x < minX || p_x >= maxX || p_y < minY || p_y >= maxY) { + return FALSE; + } + + MxU8* pixel; + + MxLong biCompression = m_frameBitmap->GetBmiHeader()->biCompression; + MxLong height = m_frameBitmap->GetBmiHeight(); + MxLong seekRow; + + // DECOMP: Same basic layout as AlphaMask constructor + // The idea here is to again seek to the correct place in the bitmap's + // m_data buffer. The x,y args are (most likely) screen x and y, so we + // need to shift that to coordinates local to the bitmap by removing + // the MxPresenter location x and y coordinates. + if (biCompression == BI_RGB) { + if (biCompression == BI_RGB_TOPDOWN || height < 0) { + seekRow = p_y - m_location.GetY(); + } + else { + height = height > 0 ? height : -height; + seekRow = height - p_y - 1 + m_location.GetY(); + } + pixel = m_frameBitmap->GetBmiStride() * seekRow + m_frameBitmap->GetImage() - m_location.GetX() + p_x; + } + else if (biCompression == BI_RGB_TOPDOWN) { + pixel = m_frameBitmap->GetImage(); + } + else { + height = height > 0 ? height : -height; + height--; + pixel = m_frameBitmap->GetBmiStride() * height + m_frameBitmap->GetImage(); + } + + if (GetBit4()) { + return (MxBool) *pixel; + } + + if ((GetAction()->GetFlags() & MxDSAction::c_bit4) && *pixel == 0) { + return FALSE; + } + + return TRUE; +} + +inline MxS32 MxVideoPresenter::PrepareRects(RECT& p_rectDest, RECT& p_rectSrc) +{ + if (p_rectDest.top > 480 || p_rectDest.left > 640 || p_rectSrc.top > 480 || p_rectSrc.left > 640) { + return -1; + } + + if (p_rectDest.bottom > 480) { + p_rectDest.bottom = 480; + } + + if (p_rectDest.right > 640) { + p_rectDest.right = 640; + } + + if (p_rectSrc.bottom > 480) { + p_rectSrc.bottom = 480; + } + + if (p_rectSrc.right > 640) { + p_rectSrc.right = 640; + } + + LONG height, width; + if ((height = (p_rectDest.bottom - p_rectDest.top) + 1) <= 1 || + (width = (p_rectDest.right - p_rectDest.left) + 1) <= 1) { + return -1; + } + else if ((p_rectSrc.right - p_rectSrc.left + 1) == width && (p_rectSrc.bottom - p_rectSrc.top + 1) == height) { + return 1; + } + else { + p_rectSrc.right = (p_rectSrc.left + width) - 1; + p_rectSrc.bottom = (p_rectSrc.top + height) - 1; + return 0; + } +} + +// FUNCTION: LEGO1 0x100b2a70 +void MxVideoPresenter::PutFrame() +{ + MxDisplaySurface* displaySurface = MVideoManager()->GetDisplaySurface(); + MxRegion* region = MVideoManager()->GetRegion(); + MxRect32 rect(MxPoint32(0, 0), MxSize32(GetWidth(), GetHeight())); + rect.AddPoint(GetLocation()); + LPDIRECTDRAWSURFACE ddSurface = displaySurface->GetDirectDrawSurface2(); + + if (m_action->GetFlags() & MxDSAction::c_bit5) { + if (m_unk0x58) { + RECT src, dest; + src.top = 0; + src.left = 0; + src.right = GetWidth(); + src.bottom = GetHeight(); + + dest.left = GetX(); + dest.top = GetY(); + dest.right = dest.left + GetWidth(); + dest.bottom = dest.top + GetHeight(); + + switch (PrepareRects(src, dest)) { + case 0: + ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_KEYSRC, NULL); + break; + case 1: + ddSurface->BltFast(dest.left, dest.top, m_unk0x58, &src, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); + } + } + else { + displaySurface->VTable0x30( + m_frameBitmap, + 0, + 0, + rect.GetLeft(), + rect.GetTop(), + m_frameBitmap->GetBmiWidth(), + m_frameBitmap->GetBmiHeightAbs(), + TRUE + ); + } + } + else { + MxRegionCursor cursor(region); + MxRect32* regionRect; + + while ((regionRect = cursor.VTable0x24(rect))) { + if (regionRect->GetWidth() >= 1 && regionRect->GetHeight() >= 1) { + RECT src, dest; + + if (m_unk0x58) { + src.left = regionRect->GetLeft() - GetX(); + src.top = regionRect->GetTop() - GetY(); + src.right = src.left + regionRect->GetWidth(); + src.bottom = src.top + regionRect->GetHeight(); + + dest.left = regionRect->GetLeft(); + dest.top = regionRect->GetTop(); + dest.right = dest.left + regionRect->GetWidth(); + dest.bottom = dest.top + regionRect->GetHeight(); + } + + if (m_action->GetFlags() & MxDSAction::c_bit4) { + if (m_unk0x58) { + if (PrepareRects(src, dest) >= 0) { + ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_KEYSRC, NULL); + } + } + else { + displaySurface->VTable0x30( + m_frameBitmap, + regionRect->GetLeft() - GetX(), + regionRect->GetTop() - GetY(), + regionRect->GetLeft(), + regionRect->GetTop(), + regionRect->GetWidth(), + regionRect->GetHeight(), + FALSE + ); + } + } + else if (m_unk0x58) { + if (PrepareRects(src, dest) >= 0) { + ddSurface->Blt(&dest, m_unk0x58, &src, 0, NULL); + } + } + else { + displaySurface->VTable0x28( + m_frameBitmap, + regionRect->GetLeft() - GetX(), + regionRect->GetTop() - GetY(), + regionRect->GetLeft(), + regionRect->GetTop(), + regionRect->GetWidth(), + regionRect->GetHeight() + ); + } + } + } + } +} + +// FUNCTION: LEGO1 0x100b2f60 +void MxVideoPresenter::ReadyTickle() +{ + MxStreamChunk* chunk = NextChunk(); + + if (chunk) { + LoadHeader(chunk); + m_subscriber->FreeDataChunk(chunk); + ParseExtra(); + ProgressTickleState(e_starting); + } +} + +// FUNCTION: LEGO1 0x100b2fa0 +void MxVideoPresenter::StartingTickle() +{ + MxStreamChunk* chunk = CurrentChunk(); + + if (chunk && m_action->GetElapsedTime() >= chunk->GetTime()) { + CreateBitmap(); + ProgressTickleState(e_streaming); + } +} + +// FUNCTION: LEGO1 0x100b2fe0 +void MxVideoPresenter::StreamingTickle() +{ + if (m_action->GetFlags() & MxDSAction::c_bit10) { + if (!m_currentChunk) { + MxMediaPresenter::StreamingTickle(); + } + + if (m_currentChunk) { + LoadFrame(m_currentChunk); + m_currentChunk = NULL; + } + } + else { + for (MxS16 i = 0; i < m_unk0x5c; i++) { + if (!m_currentChunk) { + MxMediaPresenter::StreamingTickle(); + + if (!m_currentChunk) { + break; + } + } + + if (m_action->GetElapsedTime() < m_currentChunk->GetTime()) { + break; + } + + LoadFrame(m_currentChunk); + m_subscriber->FreeDataChunk(m_currentChunk); + m_currentChunk = NULL; + SetBit0(TRUE); + + if (m_currentTickleState != e_streaming) { + break; + } + } + + if (GetBit0()) { + m_unk0x5c = 5; + } + } +} + +// FUNCTION: LEGO1 0x100b3080 +void MxVideoPresenter::RepeatingTickle() +{ + if (IsEnabled()) { + if (m_action->GetFlags() & MxDSAction::c_bit10) { + if (!m_currentChunk) { + MxMediaPresenter::RepeatingTickle(); + } + + if (m_currentChunk) { + LoadFrame(m_currentChunk); + m_currentChunk = NULL; + } + } + else { + for (MxS16 i = 0; i < m_unk0x5c; i++) { + if (!m_currentChunk) { + MxMediaPresenter::RepeatingTickle(); + + if (!m_currentChunk) { + break; + } + } + + if (m_action->GetElapsedTime() % m_action->GetLoopCount() < m_currentChunk->GetTime()) { + break; + } + + LoadFrame(m_currentChunk); + m_currentChunk = NULL; + SetBit0(TRUE); + + if (m_currentTickleState != e_repeating) { + break; + } + } + + if (GetBit0()) { + m_unk0x5c = 5; + } + } + } +} + +// FUNCTION: LEGO1 0x100b3130 +void MxVideoPresenter::FreezingTickle() +{ + MxLong sustainTime = ((MxDSMediaAction*) m_action)->GetSustainTime(); + + if (sustainTime != -1) { + if (sustainTime) { + if (m_unk0x60 == -1) { + m_unk0x60 = m_action->GetElapsedTime(); + } + + if (m_action->GetElapsedTime() >= m_unk0x60 + ((MxDSMediaAction*) m_action)->GetSustainTime()) { + ProgressTickleState(e_done); + } + } + else { + ProgressTickleState(e_done); + } + } +} + +// FUNCTION: LEGO1 0x100b31a0 +MxResult MxVideoPresenter::AddToManager() +{ + MxResult result = FAILURE; + + if (MVideoManager()) { + result = SUCCESS; + MVideoManager()->RegisterPresenter(*this); + } + + return result; +} + +// FUNCTION: LEGO1 0x100b31d0 +void MxVideoPresenter::EndAction() +{ + if (m_action) { + MxMediaPresenter::EndAction(); + AUTOLOCK(m_criticalSection); + + if (m_frameBitmap) { + MxLong height = m_frameBitmap->GetBmiHeightAbs(); + MxLong width = m_frameBitmap->GetBmiWidth(); + MxS32 x = m_location.GetX(); + MxS32 y = m_location.GetY(); + + MxRect32 rect(x, y, x + width, y + height); + + MVideoManager()->InvalidateRect(rect); + } + } +} + +// FUNCTION: LEGO1 0x100b3280 +MxResult MxVideoPresenter::PutData() +{ + AUTOLOCK(m_criticalSection); + + if (IsEnabled() && m_currentTickleState >= e_streaming && m_currentTickleState <= e_freezing) { + PutFrame(); + } + + return SUCCESS; +} + +// FUNCTION: LEGO1 0x100b3300 +undefined MxVideoPresenter::VTable0x74() +{ + return 0; +} diff --git a/LEGO1/realtime/lodlist.h b/LEGO1/realtime/lodlist.h new file mode 100644 index 00000000..66854887 --- /dev/null +++ b/LEGO1/realtime/lodlist.h @@ -0,0 +1,218 @@ +#ifndef LODLIST_H +#define LODLIST_H + +#include "assert.h" + +#include // size_t + +class LODObject; + +// disable: identifier was truncated to '255' characters in the debug information +#pragma warning(disable : 4786) + +////////////////////////////////////////////////////////////////////////////// +// +// LODListBase +// +// An LODListBase is an ordered list of LODObjects +// where each successive object in the list has a more complex +// geometric representation than the one preceeding it. +// + +// VTABLE: LEGO1 0x100dbdc8 +// VTABLE: BETA10 0x101c3500 +// SIZE 0x10 +class LODListBase { +protected: + LODListBase(size_t capacity); + + const LODObject* PushBack(const LODObject*); + const LODObject* PopBack(); + +public: + virtual ~LODListBase(); + const LODObject* operator[](int) const; + + // current number of LODObject* in LODListBase + size_t Size() const; + + // maximum number of LODObject* LODListBase can hold + size_t Capacity() const; + + // SYNTHETIC: LEGO1 0x100a77b0 + // SYNTHETIC: BETA10 0x1017b410 + // LODListBase::`scalar deleting destructor' + +#ifdef _DEBUG + virtual void Dump(void (*pTracer)(const char*, ...)) const; +#endif + +private: + // not implemented + LODListBase(const LODListBase&); + LODListBase& operator=(const LODListBase&); + +private: + const LODObject** m_ppLODObject; // 0x04 + size_t m_capacity; // 0x08 + size_t m_size; // 0x0c +}; + +////////////////////////////////////////////////////////////////////////////// +// +// LODList +// + +// SIZE 0x10 +template +class LODList : public LODListBase { +public: + LODList(size_t capacity); + + const T* operator[](int) const; + const T* PushBack(const T*); + const T* PopBack(); +}; + +////////////////////////////////////////////////////////////////////////////// +// +// LODListBase implementation + +// FUNCTION: BETA10 0x1017b390 +inline LODListBase::LODListBase(size_t capacity) + : m_capacity(capacity), m_size(0), m_ppLODObject(new const LODObject*[capacity]) +{ +#ifdef _DEBUG + int i; + + for (i = 0; i < (int) m_capacity; i++) { + m_ppLODObject[i] = 0; + } +#endif +} + +// FUNCTION: LEGO1 0x100a77e0 +// FUNCTION: BETA10 0x1017b450 +inline LODListBase::~LODListBase() +{ + // all LODObject* should have been popped by client + assert(m_size == 0); + + delete[] m_ppLODObject; +} + +// FUNCTION: BETA10 0x1005c480 +inline size_t LODListBase::Size() const +{ + return m_size; +} + +// FUNCTION: BETA10 0x10178b40 +inline size_t LODListBase::Capacity() const +{ + return m_capacity; +} + +// FUNCTION: BETA10 0x1007b6a0 +inline const LODObject* LODListBase::operator[](int i) const +{ + assert((0 <= i) && (i < (int) m_size)); + + return m_ppLODObject[i]; +} + +// FUNCTION: BETA10 0x1007bb40 +inline const LODObject* LODListBase::PushBack(const LODObject* pLOD) +{ + assert(m_size < m_capacity); + + m_ppLODObject[m_size++] = pLOD; + return pLOD; +} + +// FUNCTION: BETA10 0x10178b60 +inline const LODObject* LODListBase::PopBack() +{ + const LODObject* pLOD; + + assert(m_size > 0); + + pLOD = m_ppLODObject[--m_size]; + +#ifdef _DEBUG + m_ppLODObject[m_size] = 0; +#endif + + return pLOD; +} + +#ifdef _DEBUG +// FUNCTION: BETA10 0x1017b4c0 +inline void LODListBase::Dump(void (*pTracer)(const char*, ...)) const +{ + int i; + + pTracer("LODListBase<0x%x>: Capacity=%d, Size=%d\n", (void*) this, m_capacity, m_size); + + for (i = 0; i < (int) m_size; i++) { + pTracer(" [%d]: LOD<0x%x>\n", i, m_ppLODObject[i]); + } + + for (i = (int) m_size; i < (int) m_capacity; i++) { + assert(m_ppLODObject[i] == 0); + } +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// LODList implementation + +template +inline LODList::LODList(size_t capacity) : LODListBase(capacity) +{ +} + +template +inline const T* LODList::operator[](int i) const +{ + return static_cast(LODListBase::operator[](i)); +} + +template +inline const T* LODList::PushBack(const T* pLOD) +{ + return static_cast(LODListBase::PushBack(pLOD)); +} + +template +inline const T* LODList::PopBack() +{ + return static_cast(LODListBase::PopBack()); +} + +// VTABLE: LEGO1 0x100dbdc0 +// VTABLE: BETA10 0x101c34f8 +// class LODList + +// SYNTHETIC: LEGO1 0x100a7740 +// SYNTHETIC: BETA10 0x1017b350 +// LODList::`scalar deleting destructor' + +// TEMPLATE: BETA10 0x10178b20 +// LODList::PopBack + +// TEMPLATE: BETA10 0x1017b2d0 +// LODList::LODList + +// TEMPLATE: LEGO1 0x100a8160 +// TEMPLATE: BETA10 0x1017b5d0 +// LODList::~LODList + +// TEMPLATE: BETA10 0x1007bae0 +// LODList::operator[] + +// re-enable: identifier was truncated to '255' characters in the debug information +#pragma warning(default : 4786) + +#endif // LODLIST_H diff --git a/LEGO1/realtime/matrix.cpp b/LEGO1/realtime/matrix.cpp new file mode 100644 index 00000000..c1de1535 --- /dev/null +++ b/LEGO1/realtime/matrix.cpp @@ -0,0 +1,5 @@ +#include "matrix.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(Matrix4, 0x08); diff --git a/LEGO1/realtime/matrix.h b/LEGO1/realtime/matrix.h new file mode 100644 index 00000000..82c3166a --- /dev/null +++ b/LEGO1/realtime/matrix.h @@ -0,0 +1,244 @@ +#ifndef MATRIX_H +#define MATRIX_H + +#include "vector.h" + +#include + +struct UnknownMatrixType { + float m_data[4][4]; +}; + +// Note: Many functions most likely take const references/pointers instead of non-const. +// The class needs to undergo a very careful refactoring to fix that (no matches should break). + +// VTABLE: LEGO1 0x100d4350 +// SIZE 0x08 +class Matrix4 { +public: + inline Matrix4(float (*p_data)[4]) { SetData(p_data); } + + // Note: virtual function overloads appear in the virtual table + // in reverse order of appearance. + + // FUNCTION: LEGO1 0x10002320 + virtual void Equals(float (*p_data)[4]) { memcpy(m_data, p_data, sizeof(float) * 4 * 4); } // vtable+0x04 + + // FUNCTION: LEGO1 0x10002340 + virtual void Equals(const Matrix4& p_matrix) + { + memcpy(m_data, p_matrix.m_data, sizeof(float) * 4 * 4); + } // vtable+0x00 + + // FUNCTION: LEGO1 0x10002360 + virtual void SetData(float (*p_data)[4]) { m_data = p_data; } // vtable+0x0c + + // FUNCTION: LEGO1 0x10002370 + virtual void SetData(UnknownMatrixType& p_matrix) { m_data = p_matrix.m_data; } // vtable+0x08 + + // FUNCTION: LEGO1 0x10002380 + virtual float (*GetData())[4] { return m_data; } // vtable+0x14 + + // FUNCTION: LEGO1 0x10002390 + virtual float (*GetData() const)[4] { return m_data; } // vtable+0x10 + + // FUNCTION: LEGO1 0x100023a0 + virtual float* Element(int p_row, int p_col) { return &m_data[p_row][p_col]; } // vtable+0x1c + + // FUNCTION: LEGO1 0x100023c0 + virtual const float* Element(int p_row, int p_col) const { return &m_data[p_row][p_col]; } // vtable+0x18 + + // FUNCTION: LEGO1 0x100023e0 + virtual void Clear() { memset(m_data, 0, 16 * sizeof(float)); } // vtable+0x20 + + // FUNCTION: LEGO1 0x100023f0 + virtual void SetIdentity() + { + Clear(); + m_data[0][0] = 1.0f; + m_data[1][1] = 1.0f; + m_data[2][2] = 1.0f; + m_data[3][3] = 1.0f; + } // vtable+0x24 + + // FUNCTION: LEGO1 0x10002420 + virtual void operator=(const Matrix4& p_matrix) { Equals(p_matrix); } // vtable+0x28 + + // FUNCTION: LEGO1 0x10002430 + virtual Matrix4& operator+=(float (*p_data)[4]) + { + for (int i = 0; i < 16; i++) { + ((float*) m_data)[i] += ((float*) p_data)[i]; + } + return *this; + } // vtable+0x2c + + // FUNCTION: LEGO1 0x10002460 + virtual void TranslateBy(const float& p_x, const float& p_y, const float& p_z) + { + m_data[3][0] += p_x; + m_data[3][1] += p_y; + m_data[3][2] += p_z; + } // vtable+0x30 + + // FUNCTION: LEGO1 0x100024a0 + virtual void SetTranslation(const float& p_x, const float& p_y, const float& p_z) + { + m_data[3][0] = p_x; + m_data[3][1] = p_y; + m_data[3][2] = p_z; + } // vtable+0x34 + + // FUNCTION: LEGO1 0x100024d0 + virtual void Product(float (*p_a)[4], float (*p_b)[4]) + { + float* cur = (float*) m_data; + for (int row = 0; row < 4; row++) { + for (int col = 0; col < 4; col++) { + *cur = 0.0f; + for (int k = 0; k < 4; k++) { + *cur += p_a[row][k] * p_b[k][col]; + } + cur++; + } + } + } // vtable+0x3c + + // FUNCTION: LEGO1 0x10002530 + virtual void Product(const Matrix4& p_a, const Matrix4& p_b) { Product(p_a.m_data, p_b.m_data); } // vtable+0x38 + + // FUNCTION: LEGO1 0x100a0ff0 + inline void Scale(const float& p_x, const float& p_y, const float& p_z) + { + for (int i = 0; i < 4; i++) { + m_data[i][0] *= p_x; + m_data[i][1] *= p_y; + m_data[i][2] *= p_z; + } + } + + inline void RotateX(const float& p_angle) + { + float s = sin(p_angle); + float c = cos(p_angle); + float matrix[4][4]; + memcpy(matrix, m_data, sizeof(float) * 16); + for (int i = 0; i < 4; i++) { + m_data[i][1] = matrix[i][1] * c - matrix[i][2] * s; + m_data[i][2] = matrix[i][2] * c + matrix[i][1] * s; + } + } + + inline void RotateZ(const float& p_angle) + { + float s = sin(p_angle); + float c = cos(p_angle); + float matrix[4][4]; + memcpy(matrix, m_data, sizeof(float) * 16); + for (int i = 0; i < 4; i++) { + m_data[i][0] = matrix[i][0] * c - matrix[i][1] * s; + m_data[i][1] = matrix[i][1] * c + matrix[i][0] * s; + } + } + + inline virtual void ToQuaternion(Vector4& p_resultQuat); // vtable+0x40 + inline virtual int FromQuaternion(const Vector4& p_vec); // vtable+0x44 + + float* operator[](int idx) { return m_data[idx]; } + const float* operator[](int idx) const { return m_data[idx]; } + +protected: + float (*m_data)[4]; +}; + +// FUNCTION: LEGO1 0x10002550 +inline void Matrix4::ToQuaternion(Vector4& p_outQuat) +{ + float trace = m_data[0][0] + m_data[1][1] + m_data[2][2]; + if (trace > 0) { + trace = sqrt(trace + 1.0); + p_outQuat[3] = trace * 0.5f; + trace = 0.5f / trace; + p_outQuat[0] = (m_data[2][1] - m_data[1][2]) * trace; + p_outQuat[1] = (m_data[0][2] - m_data[2][0]) * trace; + p_outQuat[2] = (m_data[1][0] - m_data[0][1]) * trace; + } + else { + + // GLOBAL: LEGO1 0x100d4090 + static int rotateIndex[] = {1, 2, 0}; + + // Largest element along the trace + int largest = 0; + if (m_data[0][0] < m_data[1][1]) { + largest = 1; + } + if (*Element(largest, largest) < m_data[2][2]) { + largest = 2; + } + + int next = rotateIndex[largest]; + int nextNext = rotateIndex[next]; + + float trace = sqrt(*Element(largest, largest) - (*Element(nextNext, nextNext) + *Element(next, next)) + 1.0); + + p_outQuat[largest] = trace * 0.5f; + trace = 0.5f / trace; + + p_outQuat[3] = (*Element(nextNext, next) - *Element(next, nextNext)) * trace; + p_outQuat[next] = (*Element(largest, next) + *Element(next, largest)) * trace; + p_outQuat[nextNext] = (*Element(largest, nextNext) + *Element(nextNext, largest)) * trace; + } +} + +// FUNCTION: LEGO1 0x10002710 +inline int Matrix4::FromQuaternion(const Vector4& p_vec) +{ + float len = p_vec.LenSquared(); + + if (len > 0.0f) { + float v7 = 2.0f / len; + + float v9 = p_vec[0] * v7; + float v11 = p_vec[1] * v7; + float v12 = p_vec[2] * v7; + + float v13 = p_vec[3] * v9; + float v14 = p_vec[3] * v11; + float v16 = p_vec[3] * v12; + + float v17 = p_vec[0] * v9; + float v22 = p_vec[0] * v11; + float v23 = p_vec[0] * v12; + + float v18 = p_vec[1] * v11; + float v24 = p_vec[1] * v12; + float v19 = p_vec[2] * v12; + + m_data[0][0] = 1.0f - (v18 + v19); + m_data[1][0] = v22 + v16; + m_data[2][0] = v23 - v14; + + m_data[0][1] = v22 - v16; + m_data[1][1] = 1.0f - (v17 + v19); + m_data[2][1] = v24 + v13; + + m_data[0][2] = v14 + v23; + m_data[1][2] = v24 - v13; + m_data[2][2] = 1.0f - (v18 + v17); + + m_data[3][0] = 0; + m_data[3][1] = 0; + m_data[3][2] = 0; + m_data[3][3] = 1.0f; + + m_data[0][3] = 0; + m_data[1][3] = 0; + m_data[2][3] = 0; + return 0; + } + + return -1; +} + +#endif // MATRIX_H diff --git a/LEGO1/realtime/orientableroi.cpp b/LEGO1/realtime/orientableroi.cpp new file mode 100644 index 00000000..2d86ab5d --- /dev/null +++ b/LEGO1/realtime/orientableroi.cpp @@ -0,0 +1,201 @@ +#include "orientableroi.h" + +#include "decomp.h" + +#include + +DECOMP_SIZE_ASSERT(OrientableROI, 0xdc) + +// FUNCTION: LEGO1 0x100a4420 +OrientableROI::OrientableROI() +{ + FILLVEC3(m_world_bounding_box.Min(), 888888.8); + FILLVEC3(m_world_bounding_box.Max(), -888888.8); + ZEROVEC3(m_world_bounding_sphere.Center()); + m_world_bounding_sphere.Radius() = 0.0; + ZEROVEC3(m_world_velocity); + IDENTMAT4(m_local2world); + + m_parentROI = NULL; + ToggleUnknown0xd8(TRUE); +} + +// Maybe an overload based on MxMatrix type +// FUNCTION: LEGO1 0x100a46a0 +void OrientableROI::WrappedSetLocalTransform(const Matrix4& p_transform) +{ + SetLocalTransform(p_transform); +} + +// FUNCTION: LEGO1 0x100a46b0 +void OrientableROI::FUN_100a46b0(const Matrix4& p_transform) +{ + MxMatrix mat; + + double local2world[4][4]; + double local2parent[4][4]; + int i, j; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + local2world[i][j] = p_transform[i][j]; + local2parent[i][j] = m_local2world[i][j]; + } + } + + double local_inverse[4][4]; + INVERTMAT4d(local_inverse, local2parent); + + double parent2world[4][4]; + MXM4(parent2world, local_inverse, local2world); + + unsigned int k, l; + for (k = 0; k < 4; k++) { + for (l = 0; l < 4; l++) { + mat[k][l] = parent2world[k][l]; + } + } + + UpdateWorldData(mat); +} + +// Maybe an overload based on MxMatrix type +// FUNCTION: LEGO1 0x100a5090 +void OrientableROI::WrappedVTable0x24(const Matrix4& p_transform) +{ + VTable0x24(p_transform); +} + +// FUNCTION: LEGO1 0x100a50a0 +void OrientableROI::GetLocalTransform(Matrix4& p_transform) +{ + MxMatrix mat; + + if (m_parentROI != NULL) { + double local2parent[4][4]; + unsigned int i, j; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + local2parent[i][j] = m_parentROI->GetLocal2World()[i][j]; + } + } + + double local_inverse[4][4]; + INVERTMAT4d(local_inverse, local2parent); + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + mat[i][j] = local_inverse[i][j]; + } + } + + MXM4(p_transform, m_local2world, mat); + } + else { + p_transform = m_local2world; + } +} + +// FUNCTION: LEGO1 0x100a58f0 +void OrientableROI::FUN_100a58f0(const Matrix4& p_transform) +{ + m_local2world = p_transform; + ToggleUnknown0xd8(TRUE); +} + +// FUNCTION: LEGO1 0x100a5910 +void OrientableROI::VTable0x1c() +{ + UpdateWorldBoundingVolumes(); + UpdateWorldVelocity(); +} + +// FUNCTION: LEGO1 0x100a5930 +void OrientableROI::SetLocalTransform(const Matrix4& p_transform) +{ + m_local2world = p_transform; + UpdateWorldBoundingVolumes(); + UpdateWorldVelocity(); +} + +// FUNCTION: LEGO1 0x100a5960 +void OrientableROI::VTable0x24(const Matrix4& p_transform) +{ + MxMatrix l_matrix(m_local2world); + m_local2world.Product(p_transform, l_matrix); + UpdateWorldBoundingVolumes(); + UpdateWorldVelocity(); +} + +// FUNCTION: LEGO1 0x100a59b0 +void OrientableROI::UpdateWorldData(const Matrix4& p_transform) +{ + MxMatrix l_matrix(m_local2world); + m_local2world.Product(l_matrix, p_transform); + UpdateWorldBoundingVolumes(); + UpdateWorldVelocity(); + + // iterate over comps + if (comp) { + for (CompoundObject::iterator iter = comp->begin(); !(iter == comp->end()); iter++) { + ROI* child = *iter; + static_cast(child)->UpdateWorldData(p_transform); + } + } +} + +// FUNCTION: LEGO1 0x100a5a30 +void OrientableROI::FUN_100a5a30(const Vector3& p_world_velocity) +{ + m_world_velocity = p_world_velocity; +} + +// FUNCTION: LEGO1 0x100a5a50 +void OrientableROI::UpdateWorldVelocity() +{ +} + +// FUNCTION: LEGO1 0x100a5a60 +void CalcWorldBoundingVolumes( + const BoundingSphere& modelling_sphere, + const Matrix4& local2world, + BoundingBox& world_bounding_box, + BoundingSphere& world_bounding_sphere +) +{ + // calculate world bounding volumes given a bounding sphere in modelling + // space and local2world transform + + // ??? we need to transform the radius too... if scaling... + + V3XM4(world_bounding_sphere.Center(), modelling_sphere.Center(), local2world); + + world_bounding_sphere.Radius() = modelling_sphere.Radius(); + + // update world_bounding_box + world_bounding_box.Min()[0] = world_bounding_sphere.Center()[0] - world_bounding_sphere.Radius(); + world_bounding_box.Min()[1] = world_bounding_sphere.Center()[1] - world_bounding_sphere.Radius(); + world_bounding_box.Min()[2] = world_bounding_sphere.Center()[2] - world_bounding_sphere.Radius(); + world_bounding_box.Max()[0] = world_bounding_sphere.Center()[0] + world_bounding_sphere.Radius(); + world_bounding_box.Max()[1] = world_bounding_sphere.Center()[1] + world_bounding_sphere.Radius(); + world_bounding_box.Max()[2] = world_bounding_sphere.Center()[2] + world_bounding_sphere.Radius(); +} + +// FUNCTION: LEGO1 0x100a5d80 +const float* OrientableROI::GetWorldVelocity() const +{ + return m_world_velocity.GetData(); +} + +// FUNCTION: LEGO1 0x100a5d90 +const BoundingBox& OrientableROI::GetWorldBoundingBox() const +{ + return m_world_bounding_box; +} + +// FUNCTION: LEGO1 0x100a5da0 +const BoundingSphere& OrientableROI::GetWorldBoundingSphere() const +{ + return m_world_bounding_sphere; +} diff --git a/LEGO1/realtime/orientableroi.h b/LEGO1/realtime/orientableroi.h new file mode 100644 index 00000000..d7b9f998 --- /dev/null +++ b/LEGO1/realtime/orientableroi.h @@ -0,0 +1,76 @@ +#ifndef ORIENTABLEROI_H +#define ORIENTABLEROI_H + +#include "decomp.h" +#include "mxgeometry/mxmatrix.h" +#include "roi.h" + +#include + +// VTABLE: LEGO1 0x100dbc08 +// SIZE 0xdc +class OrientableROI : public ROI { +public: + enum { + c_bit1 = 0x01, + c_bit2 = 0x02 + }; + + OrientableROI(); + + const float* GetWorldVelocity() const override; // vtable+0x08 + const BoundingBox& GetWorldBoundingBox() const override; // vtable+0x0c + const BoundingSphere& GetWorldBoundingSphere() const override; // vtable+0x10 + + // FUNCTION: LEGO1 0x100a5db0 + virtual void VTable0x14() { VTable0x1c(); } // vtable+0x14 + + virtual void UpdateWorldBoundingVolumes() = 0; // vtable+0x18 + virtual void VTable0x1c(); // vtable+0x1c + virtual void SetLocalTransform(const Matrix4& p_transform); // vtable+0x20 + virtual void VTable0x24(const Matrix4& p_transform); // vtable+0x24 + virtual void UpdateWorldData(const Matrix4& p_transform); // vtable+0x28 + virtual void UpdateWorldVelocity(); // vtable+0x2c + + void WrappedSetLocalTransform(const Matrix4& p_transform); + void FUN_100a46b0(const Matrix4& p_transform); + void WrappedVTable0x24(const Matrix4& p_transform); + void GetLocalTransform(Matrix4& p_transform); + void FUN_100a58f0(const Matrix4& p_transform); + void FUN_100a5a30(const Vector3& p_world_velocity); + + const Matrix4& GetLocal2World() const { return m_local2world; } + const float* GetWorldPosition() const { return m_local2world[3]; } + const float* GetWorldDirection() const { return m_local2world[2]; } + const float* GetWorldUp() const { return m_local2world[1]; } + OrientableROI* GetParentROI() const { return m_parentROI; } + + void SetParentROI(OrientableROI* p_parentROI) { m_parentROI = p_parentROI; } + + void ToggleUnknown0xd8(BOOL p_enable) + { + if (p_enable) { + m_unk0xd8 |= c_bit1 | c_bit2; + } + else { + m_unk0xd8 &= ~c_bit1; + } + } + +protected: + MxMatrix m_local2world; // 0x10 + BoundingBox m_world_bounding_box; // 0x58 + BoundingBox m_unk0x80; // 0x80 + BoundingSphere m_world_bounding_sphere; // 0xa8 + Mx3DPointFloat m_world_velocity; // 0xc0 + OrientableROI* m_parentROI; // 0xd4 + undefined4 m_unk0xd8; // 0xd8 +}; + +// SYNTHETIC: LEGO1 0x100a4630 +// OrientableROI::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100aa2f0 +// OrientableROI::~OrientableROI + +#endif // ORIENTABLEROI_H diff --git a/LEGO1/realtime/realtime.cpp b/LEGO1/realtime/realtime.cpp new file mode 100644 index 00000000..829b2271 --- /dev/null +++ b/LEGO1/realtime/realtime.cpp @@ -0,0 +1,20 @@ +#include "realtime.h" + +#include + +// FUNCTION: LEGO1 0x100a5b40 +void CalcLocalTransform(const Vector3& p_posVec, const Vector3& p_dirVec, const Vector3& p_upVec, Matrix4& p_outMatrix) +{ + float x_axis[3], y_axis[3], z_axis[3]; + + NORMVEC3(z_axis, p_dirVec); + NORMVEC3(y_axis, p_upVec) + VXV3(x_axis, y_axis, z_axis); + NORMVEC3(x_axis, x_axis); + VXV3(y_axis, z_axis, x_axis); + NORMVEC3(y_axis, y_axis); + SET4from3(p_outMatrix[0], x_axis, 0); + SET4from3(p_outMatrix[1], y_axis, 0); + SET4from3(p_outMatrix[2], z_axis, 0); + SET4from3(p_outMatrix[3], p_posVec, 1); +} diff --git a/LEGO1/realtime/realtime.h b/LEGO1/realtime/realtime.h new file mode 100644 index 00000000..a9273cfe --- /dev/null +++ b/LEGO1/realtime/realtime.h @@ -0,0 +1,19 @@ +#ifndef REALTIME_H +#define REALTIME_H + +#include "matrix.h" +#include "roi.h" + +#define NORMVEC3(dst, src) \ + { \ + double len = sqrt(NORMSQRD3(src)); \ + VDS3(dst, src, len); \ + } + +void CalcLocalTransform(const Vector3& p_posVec, const Vector3& p_dirVec, const Vector3& p_upVec, Matrix4& p_outMatrix); + +// utility to help derived ROI classes implement +// update_world_bounding_volumes() using a modelling sphere +void CalcWorldBoundingVolumes(const BoundingSphere& modelling_sphere, const Matrix4& local2world, BoundingBox&, BoundingSphere&); + +#endif // REALTIME_H diff --git a/LEGO1/realtime/realtimeview.cpp b/LEGO1/realtime/realtimeview.cpp new file mode 100644 index 00000000..afe0e790 --- /dev/null +++ b/LEGO1/realtime/realtimeview.cpp @@ -0,0 +1,57 @@ +#include "realtimeview.h" + +#include + +// GLOBAL: LEGO1 0x10109598 +float g_userMaxLodPower; + +// GLOBAL: LEGO1 0x10101044 +float g_userMaxBase = 4.0f; + +// GLOBAL: LEGO1 0x10101048 +float g_userMaxLod = 3.6f; + +// GLOBAL: LEGO1 0x1010104c +float g_partsThreshold = 1000.0f; + +// FUNCTION: LEGO1 0x100a5dc0 +RealtimeView::RealtimeView() +{ + UpdateMaxLOD(); +} + +// FUNCTION: LEGO1 0x100a5dd0 +RealtimeView::~RealtimeView() +{ +} + +// FUNCTION: LEGO1 0x100a5de0 +void RealtimeView::SetUserMaxLOD(float p_lod) +{ + g_userMaxLod = p_lod; + UpdateMaxLOD(); +} + +// FUNCTION: LEGO1 0x100a5df0 +void RealtimeView::SetPartsThreshold(float p_threshold) +{ + g_partsThreshold = p_threshold; +} + +// FUNCTION: LEGO1 0x100a5e00 +float RealtimeView::GetUserMaxLOD() +{ + return g_userMaxLod; +} + +// FUNCTION: LEGO1 0x100a5e10 +float RealtimeView::GetPartsThreshold() +{ + return g_partsThreshold; +} + +// FUNCTION: LEGO1 0x100a5e20 +void RealtimeView::UpdateMaxLOD() +{ + g_userMaxLodPower = pow(g_userMaxBase, -g_userMaxLod); +} diff --git a/LEGO1/realtime/realtimeview.h b/LEGO1/realtime/realtimeview.h new file mode 100644 index 00000000..b121514f --- /dev/null +++ b/LEGO1/realtime/realtimeview.h @@ -0,0 +1,20 @@ +#ifndef REALTIMEVIEW_H +#define REALTIMEVIEW_H + +extern float g_userMaxLodPower; + +class RealtimeView { +public: + RealtimeView(); + ~RealtimeView(); + + static float GetPartsThreshold(); + static float GetUserMaxLOD(); + static void SetPartsThreshold(float); + static void UpdateMaxLOD(); + static void SetUserMaxLOD(float); + + inline static float GetUserMaxLodPower() { return g_userMaxLodPower; } +}; + +#endif // REALTIMEVIEW_H diff --git a/LEGO1/realtime/roi.h b/LEGO1/realtime/roi.h new file mode 100644 index 00000000..e0a9a6da --- /dev/null +++ b/LEGO1/realtime/roi.h @@ -0,0 +1,133 @@ +#ifndef ROI_H +#define ROI_H + +// ROI stands for Real-time Object Instance. + +#include "compat.h" +#include "decomp.h" +#include "lodlist.h" +#include "mxgeometry/mxgeometry3d.h" +#include "mxstl/stlcompat.h" + +/* + * A simple bounding box object with Min and Max accessor methods. + */ +// SIZE 0x28 +class BoundingBox { +public: + const Vector3& Min() const { return min; } + Vector3& Min() { return min; } + const Vector3& Max() const { return max; } + Vector3& Max() { return max; } + +private: + Mx3DPointFloat min; // 0x00 + Mx3DPointFloat max; // 0x14 +}; + +/* + * A simple bounding sphere object with center and radius accessor methods. + */ +// SIZE 0x18 +class BoundingSphere { +public: + const Vector3& Center() const { return center; } + Vector3& Center() { return center; } + const float& Radius() const { return radius; } + float& Radius() { return radius; } + +private: + Mx3DPointFloat center; // 0x00 + float radius; // 0x14 +}; + +/* + * Abstract base class representing a single LOD version of + * a geometric object. + */ +// VTABLE: LEGO1 0x100dbd90 +// SIZE 0x04 +class LODObject { +public: + // LODObject(); + + // FUNCTION: LEGO1 0x100a6f00 + virtual ~LODObject() {} + + virtual double AveragePolyArea() const = 0; // vtable+0x04 + virtual int NVerts() const = 0; // vtable+0x08 + virtual int NumPolys() const = 0; // vtable+0x0c + virtual float VTable0x10() = 0; // vtable+0x10 + + // SYNTHETIC: LEGO1 0x100a6f10 + // LODObject::`scalar deleting destructor' +}; + +/* + * A CompoundObject is simply a set of ROI objects which + * all together represent a single object with sub-parts. + */ +class ROI; +// typedef std::set > CompoundObject; +typedef list CompoundObject; + +/* + * A ROIList is a list of ROI objects. + */ +typedef vector ROIList; + +/* + * A simple list of integers. + * Returned by RealtimeView::SelectLODs as indices into an ROIList. + */ +typedef vector IntList; + +// VTABLE: LEGO1 0x100dbc38 +// SIZE 0x10 +class ROI { +public: + ROI() + { + comp = 0; + lods = 0; + m_visible = true; + } + virtual ~ROI() + { + // if derived class set the comp and lods, it should delete them + assert(!comp); + assert(!lods); + } + virtual float IntrinsicImportance() const = 0; // vtable+0x04 + virtual const float* GetWorldVelocity() const = 0; // vtable+0x08 + virtual const BoundingBox& GetWorldBoundingBox() const = 0; // vtable+0x0c + virtual const BoundingSphere& GetWorldBoundingSphere() const = 0; // vtable+0x10 + + const LODListBase* GetLODs() const { return lods; } + const LODObject* GetLOD(int i) const + { + assert(lods); + return (*lods)[i]; + } + int GetLODCount() const { return lods ? lods->Size() : 0; } + const CompoundObject* GetComp() const { return comp; } + + inline unsigned char GetVisibility() { return m_visible; } + inline void SetVisibility(unsigned char p_visible) { m_visible = p_visible; } + + // SYNTHETIC: LEGO1 0x100a5d60 + // ROI::`scalar deleting destructor' + +protected: + CompoundObject* comp; // 0x04 + LODListBase* lods; // 0x08 + unsigned char m_visible; // 0x0c +}; + +// TEMPLATE: LEGO1 0x10084930 +// list >::~list > + +// SYNTHETIC: LEGO1 0x100a5d50 +// ROI::~ROI + +#endif // ROI_H diff --git a/LEGO1/realtime/vector.cpp b/LEGO1/realtime/vector.cpp new file mode 100644 index 00000000..ad09b0b0 --- /dev/null +++ b/LEGO1/realtime/vector.cpp @@ -0,0 +1,7 @@ +#include "vector.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(Vector2, 0x08); +DECOMP_SIZE_ASSERT(Vector3, 0x08); +DECOMP_SIZE_ASSERT(Vector4, 0x08); diff --git a/LEGO1/realtime/vector.h b/LEGO1/realtime/vector.h new file mode 100644 index 00000000..198ed14b --- /dev/null +++ b/LEGO1/realtime/vector.h @@ -0,0 +1,422 @@ +#ifndef VECTOR_H +#define VECTOR_H + +#include "compat.h" + +#include +#include + +// Note: Many functions most likely take const references/pointers instead of non-const. +// The class needs to undergo a very careful refactoring to fix that (no matches should break). + +// VTABLE: LEGO1 0x100d4288 +// SIZE 0x08 +class Vector2 { +public: + // FUNCTION: LEGO1 0x1000c0f0 + inline Vector2(float* p_data) { SetData(p_data); } + + // Note: virtual function overloads appear in the virtual table + // in reverse order of appearance. + + // FUNCTION: LEGO1 0x10001f80 + virtual void AddImpl(float* p_value) + { + m_data[0] += p_value[0]; + m_data[1] += p_value[1]; + } // vtable+0x04 + + // FUNCTION: LEGO1 0x10001fa0 + virtual void AddImpl(float p_value) + { + m_data[0] += p_value; + m_data[1] += p_value; + } // vtable+0x00 + + // FUNCTION: LEGO1 0x10001fc0 + virtual void SubImpl(float* p_value) + { + m_data[0] -= p_value[0]; + m_data[1] -= p_value[1]; + } // vtable+0x08 + + // Those are also overloads in all likelihood, + // but we need a type to do that. + + // FUNCTION: LEGO1 0x10002000 + virtual void MulScalarImpl(float* p_value) + { + m_data[0] *= *p_value; + m_data[1] *= *p_value; + } // vtable+0x0c + + // FUNCTION: LEGO1 0x10001fe0 + virtual void MulVectorImpl(float* p_value) + { + m_data[0] *= p_value[0]; + m_data[1] *= p_value[1]; + } // vtable+0x10 + + // FUNCTION: LEGO1 0x10002020 + virtual void DivScalarImpl(float* p_value) + { + m_data[0] /= *p_value; + m_data[1] /= *p_value; + } // vtable+0x14 + + // FUNCTION: LEGO1 0x10002040 + virtual float DotImpl(float* p_a, float* p_b) const { return p_b[0] * p_a[0] + p_b[1] * p_a[1]; } // vtable+0x18 + + // FUNCTION: LEGO1 0x10002060 + virtual void SetData(float* p_data) { m_data = p_data; } // vtable+0x1c + + // FUNCTION: LEGO1 0x10002070 + virtual void EqualsImpl(float* p_data) { memcpy(m_data, p_data, sizeof(float) * 2); } // vtable+0x20 + + // FUNCTION: LEGO1 0x10002090 + virtual float* GetData() { return m_data; } // vtable+0x28 + + // FUNCTION: LEGO1 0x100020a0 + virtual const float* GetData() const { return m_data; } // vtable+0x24 + + // FUNCTION: LEGO1 0x100020b0 + virtual void Clear() { memset(m_data, 0, sizeof(float) * 2); } // vtable+0x2c + + // FUNCTION: LEGO1 0x100020d0 + virtual float Dot(float* p_a, float* p_b) const { return DotImpl(p_a, p_b); } // vtable+0x3c + + // FUNCTION: LEGO1 0x100020f0 + virtual float Dot(Vector2* p_a, Vector2* p_b) const { return DotImpl(p_a->m_data, p_b->m_data); } // vtable+0x38 + + // FUNCTION: LEGO1 0x10002110 + virtual float Dot(float* p_a, Vector2* p_b) const { return DotImpl(p_a, p_b->m_data); } // vtable+0x34 + + // FUNCTION: LEGO1 0x10002130 + virtual float Dot(Vector2* p_a, float* p_b) const { return DotImpl(p_a->m_data, p_b); } // vtable+0x30 + + // FUNCTION: LEGO1 0x10002150 + virtual float LenSquared() const { return m_data[0] * m_data[0] + m_data[1] * m_data[1]; } // vtable+0x40 + + // FUNCTION: LEGO1 0x10002160 + virtual int Unitize() + { + float sq = LenSquared(); + + if (sq > 0.0f) { + float root = sqrt(sq); + if (root > 0) { + DivScalarImpl(&root); + return 0; + } + } + + return -1; + } // vtable+0x44 + + // FUNCTION: LEGO1 0x100021c0 + virtual void Add(float p_value) { AddImpl(p_value); } // vtable+0x50 + + // FUNCTION: LEGO1 0x100021d0 + virtual void Add(float* p_other) { AddImpl(p_other); } // vtable+0x4c + + // FUNCTION: LEGO1 0x100021e0 + virtual void Add(const Vector2* p_other) { AddImpl((float*) p_other->m_data); } // vtable+0x48 + + // FUNCTION: LEGO1 0x100021f0 + virtual void Sub(const float* p_other) { SubImpl((float*) p_other); } // vtable+0x58 + + // FUNCTION: LEGO1 0x10002200 + virtual void Sub(const Vector2* p_other) { SubImpl((float*) p_other->m_data); } // vtable+0x54 + + // FUNCTION: LEGO1 0x10002210 + virtual void Mul(float* p_other) { MulVectorImpl(p_other); } // vtable+0x64 + + // FUNCTION: LEGO1 0x10002220 + virtual void Mul(Vector2* p_other) { MulVectorImpl(p_other->m_data); } // vtable+0x60 + + // FUNCTION: LEGO1 0x10002230 + virtual void Mul(const float& p_value) { MulScalarImpl((float*) &p_value); } // vtable+0x5c + + // FUNCTION: LEGO1 0x10002240 + virtual void Div(float& p_value) { DivScalarImpl(&p_value); } // vtable+0x68 + + // FUNCTION: LEGO1 0x10002250 + virtual void SetVector(float* p_other) { EqualsImpl(p_other); } // vtable+0x70 + + // FUNCTION: LEGO1 0x10002260 + virtual void SetVector(const Vector2* p_other) { EqualsImpl(p_other->m_data); } // vtable+0x6c + + // SYNTHETIC: LEGO1 0x10010be0 + // Vector3::operator= + + inline Vector2& operator=(const Vector2& p_other) + { + Vector2::SetVector(&p_other); + return *this; + } + inline float& operator[](int idx) { return m_data[idx]; } + inline const float& operator[](int idx) const { return m_data[idx]; } + +protected: + float* m_data; // 0x04 +}; + +// VTABLE: LEGO1 0x100d4518 +// SIZE 0x08 +class Vector3 : public Vector2 { +public: + // FUNCTION: LEGO1 0x1001d150 + inline Vector3(float* p_data) : Vector2(p_data) {} + + // Hack: Some code initializes a Vector3 from a (most likely) const float* source. + // Example: LegoCameraController::GetWorldUp + // Vector3 however is a class that can mutate its underlying source, making + // initialization with a const source fundamentally incompatible. + inline Vector3(const float* p_data) : Vector2((float*) p_data) {} + + // Note: virtual function overloads appear in the virtual table + // in reverse order of appearance. + + // FUNCTION: LEGO1 0x10002270 + virtual void EqualsCrossImpl(float* p_a, float* p_b) + { + m_data[0] = p_a[1] * p_b[2] - p_a[2] * p_b[1]; + m_data[1] = p_a[2] * p_b[0] - p_a[0] * p_b[2]; + m_data[2] = p_a[0] * p_b[1] - p_a[1] * p_b[0]; + } // vtable+0x74 + + // FUNCTION: LEGO1 0x100022c0 + virtual void EqualsCross(Vector3* p_a, Vector3* p_b) { EqualsCrossImpl(p_a->m_data, p_b->m_data); } // vtable+0x80 + + // FUNCTION: LEGO1 0x100022e0 + virtual void EqualsCross(Vector3* p_a, float* p_b) { EqualsCrossImpl(p_a->m_data, p_b); } // vtable+0x7c + + // FUNCTION: LEGO1 0x10002300 + virtual void EqualsCross(float* p_a, Vector3* p_b) { EqualsCrossImpl(p_a, p_b->m_data); } // vtable+0x78 + + // FUNCTION: LEGO1 0x10003bf0 + virtual void Fill(const float& p_value) + { + m_data[0] = p_value; + m_data[1] = p_value; + m_data[2] = p_value; + } // vtable+0x84 + + // Vector2 overrides + + // FUNCTION: LEGO1 0x10003a60 + void AddImpl(float* p_value) override + { + m_data[0] += p_value[0]; + m_data[1] += p_value[1]; + m_data[2] += p_value[2]; + } // vtable+0x04 + + // FUNCTION: LEGO1 0x10003a90 + void AddImpl(float p_value) override + { + m_data[0] += p_value; + m_data[1] += p_value; + m_data[2] += p_value; + } // vtable+0x00 + + // FUNCTION: LEGO1 0x10003ac0 + void SubImpl(float* p_value) override + { + m_data[0] -= p_value[0]; + m_data[1] -= p_value[1]; + m_data[2] -= p_value[2]; + } // vtable+0x08 + + // FUNCTION: LEGO1 0x10003b20 + void MulScalarImpl(float* p_value) override + { + m_data[0] *= *p_value; + m_data[1] *= *p_value; + m_data[2] *= *p_value; + } // vtable+0x0c + + // FUNCTION: LEGO1 0x10003af0 + void MulVectorImpl(float* p_value) override + { + m_data[0] *= p_value[0]; + m_data[1] *= p_value[1]; + m_data[2] *= p_value[2]; + } // vtable+0x10 + + // FUNCTION: LEGO1 0x10003b50 + void DivScalarImpl(float* p_value) override + { + m_data[0] /= *p_value; + m_data[1] /= *p_value; + m_data[2] /= *p_value; + } // vtable+0x14 + + // FUNCTION: LEGO1 0x10003b80 + float DotImpl(float* p_a, float* p_b) const override + { + return p_a[0] * p_b[0] + p_a[2] * p_b[2] + p_a[1] * p_b[1]; + } // vtable+0x18 + + // FUNCTION: LEGO1 0x10003ba0 + void EqualsImpl(float* p_data) override { memcpy(m_data, p_data, sizeof(float) * 3); } // vtable+0x20 + + // FUNCTION: LEGO1 0x10003bc0 + void Clear() override { memset(m_data, 0, sizeof(float) * 3); } // vtable+0x2c + + // FUNCTION: LEGO1 0x10003bd0 + float LenSquared() const override + { + return m_data[0] * m_data[0] + m_data[1] * m_data[1] + m_data[2] * m_data[2]; + } // vtable+0x40 + + friend class Mx3DPointFloat; +}; + +// VTABLE: LEGO1 0x100d45a0 +// SIZE 0x08 +class Vector4 : public Vector3 { +public: + inline Vector4(float* p_data) : Vector3(p_data) {} + + // Note: virtual function overloads appear in the virtual table + // in reverse order of appearance. + + // FUNCTION: LEGO1 0x10002a40 + virtual void SetMatrixProduct(float* p_vec, float* p_mat) + { + m_data[0] = p_vec[0] * p_mat[0] + p_vec[1] * p_mat[4] + p_vec[2] * p_mat[8] + p_vec[3] * p_mat[12]; + m_data[1] = p_vec[0] * p_mat[1] + p_vec[1] * p_mat[5] + p_vec[2] * p_mat[9] + p_vec[4] * p_mat[13]; + m_data[2] = p_vec[0] * p_mat[2] + p_vec[1] * p_mat[6] + p_vec[2] * p_mat[10] + p_vec[4] * p_mat[14]; + m_data[3] = p_vec[0] * p_mat[3] + p_vec[1] * p_mat[7] + p_vec[2] * p_mat[11] + p_vec[4] * p_mat[15]; + } // vtable+0x8c + + // FUNCTION: LEGO1 0x10002ae0 + virtual void SetMatrixProduct(Vector4* p_a, float* p_b) { SetMatrixProduct(p_a->m_data, p_b); } // vtable+0x88 + + inline virtual int NormalizeQuaternion(); // vtable+0x90 + inline virtual void UnknownQuaternionOp(Vector4* p_a, Vector4* p_b); // vtable+0x94 + + // Vector3 overrides + + // FUNCTION: LEGO1 0x10002870 + void AddImpl(float* p_value) override + { + m_data[0] += p_value[0]; + m_data[1] += p_value[1]; + m_data[2] += p_value[2]; + m_data[3] += p_value[3]; + } // vtable+0x04 + + // FUNCTION: LEGO1 0x100028b0 + void AddImpl(float p_value) override + { + m_data[0] += p_value; + m_data[1] += p_value; + m_data[2] += p_value; + m_data[3] += p_value; + } // vtable+0x00 + + // FUNCTION: LEGO1 0x100028f0 + void SubImpl(float* p_value) override + { + m_data[0] -= p_value[0]; + m_data[1] -= p_value[1]; + m_data[2] -= p_value[2]; + m_data[3] -= p_value[3]; + } // vtable+0x08 + + // FUNCTION: LEGO1 0x10002970 + void MulScalarImpl(float* p_value) override + { + m_data[0] *= *p_value; + m_data[1] *= *p_value; + m_data[2] *= *p_value; + m_data[3] *= *p_value; + } // vtable+0x0c + + // FUNCTION: LEGO1 0x10002930 + void MulVectorImpl(float* p_value) override + { + m_data[0] *= p_value[0]; + m_data[1] *= p_value[1]; + m_data[2] *= p_value[2]; + m_data[3] *= p_value[3]; + } // vtable+0x10 + + // FUNCTION: LEGO1 0x100029b0 + void DivScalarImpl(float* p_value) override + { + m_data[0] /= *p_value; + m_data[1] /= *p_value; + m_data[2] /= *p_value; + m_data[3] /= *p_value; + } // vtable+0x14 + + // FUNCTION: LEGO1 0x100029f0 + float DotImpl(float* p_a, float* p_b) const override + { + return p_a[0] * p_b[0] + p_a[2] * p_b[2] + (p_a[1] * p_b[1] + p_a[3] * p_b[3]); + } // vtable+0x18 + + // FUNCTION: LEGO1 0x10002a20 + void EqualsImpl(float* p_data) override { memcpy(m_data, p_data, sizeof(float) * 4); } // vtable+0x20 + + // FUNCTION: LEGO1 0x10002b00 + void Clear() override { memset(m_data, 0, sizeof(float) * 4); } // vtable+0x2c + + // FUNCTION: LEGO1 0x10002b20 + float LenSquared() const override + { + return m_data[1] * m_data[1] + m_data[0] * m_data[0] + m_data[2] * m_data[2] + m_data[3] * m_data[3]; + } // vtable+0x40 + + // FUNCTION: LEGO1 0x10002b40 + void Fill(const float& p_value) override + { + m_data[0] = p_value; + m_data[1] = p_value; + m_data[2] = p_value; + m_data[3] = p_value; + } // vtable+0x84 + + friend class Mx4DPointFloat; +}; + +// Note close yet, included because I'm at least confident I know what operation +// it's trying to do. +// STUB: LEGO1 0x10002b70 +inline int Vector4::NormalizeQuaternion() +{ + float* v = m_data; + float magnitude = v[1] * v[1] + v[2] * v[2] + v[0] * v[0]; + if (magnitude > 0.0f) { + float theta = v[3] * 0.5f; + v[3] = cos(theta); + float frac = sin(theta); + magnitude = frac / sqrt(magnitude); + v[0] *= magnitude; + v[1] *= magnitude; + v[2] *= magnitude; + return 0; + } + return -1; +} + +// FUNCTION: LEGO1 0x10002bf0 +inline void Vector4::UnknownQuaternionOp(Vector4* p_a, Vector4* p_b) +{ + float* bDat = p_b->m_data; + float* aDat = p_a->m_data; + + this->m_data[3] = aDat[3] * bDat[3] - (bDat[0] * aDat[0] + aDat[2] * bDat[2] + aDat[1] * aDat[1]); + this->m_data[0] = bDat[2] * aDat[1] - bDat[1] * aDat[2]; + this->m_data[1] = aDat[2] * bDat[0] - bDat[2] * aDat[0]; + this->m_data[2] = bDat[1] * aDat[0] - aDat[1] * bDat[0]; + + m_data[0] = p_b->m_data[3] * p_a->m_data[0] + p_a->m_data[3] * p_b->m_data[0] + m_data[0]; + m_data[1] = p_b->m_data[1] * p_a->m_data[3] + p_a->m_data[1] * p_b->m_data[3] + m_data[1]; + m_data[2] = p_b->m_data[2] * p_a->m_data[3] + p_a->m_data[2] * p_b->m_data[3] + m_data[2]; +} + +#endif // VECTOR_H diff --git a/LEGO1/res/arrow.cur b/LEGO1/res/arrow.cur new file mode 100644 index 00000000..15f687a1 Binary files /dev/null and b/LEGO1/res/arrow.cur differ diff --git a/LEGO1/res/busy.cur b/LEGO1/res/busy.cur new file mode 100644 index 00000000..2a63b536 Binary files /dev/null and b/LEGO1/res/busy.cur differ diff --git a/LEGO1/res/leaf_0.cur b/LEGO1/res/leaf_0.cur new file mode 100644 index 00000000..e8735671 Binary files /dev/null and b/LEGO1/res/leaf_0.cur differ diff --git a/LEGO1/res/leaf_1.cur b/LEGO1/res/leaf_1.cur new file mode 100644 index 00000000..e7e0cde9 Binary files /dev/null and b/LEGO1/res/leaf_1.cur differ diff --git a/LEGO1/res/leaf_2.cur b/LEGO1/res/leaf_2.cur new file mode 100644 index 00000000..1abce39b Binary files /dev/null and b/LEGO1/res/leaf_2.cur differ diff --git a/LEGO1/res/leaf_3.cur b/LEGO1/res/leaf_3.cur new file mode 100644 index 00000000..25e6935f Binary files /dev/null and b/LEGO1/res/leaf_3.cur differ diff --git a/LEGO1/res/leaf_4.cur b/LEGO1/res/leaf_4.cur new file mode 100644 index 00000000..73ec0799 Binary files /dev/null and b/LEGO1/res/leaf_4.cur differ diff --git a/LEGO1/res/leaf_5.cur b/LEGO1/res/leaf_5.cur new file mode 100644 index 00000000..8d8df94e Binary files /dev/null and b/LEGO1/res/leaf_5.cur differ diff --git a/LEGO1/res/leaf_6.cur b/LEGO1/res/leaf_6.cur new file mode 100644 index 00000000..04615d16 Binary files /dev/null and b/LEGO1/res/leaf_6.cur differ diff --git a/LEGO1/res/leaf_7.cur b/LEGO1/res/leaf_7.cur new file mode 100644 index 00000000..9795b1df Binary files /dev/null and b/LEGO1/res/leaf_7.cur differ diff --git a/LEGO1/res/lego1.rc b/LEGO1/res/lego1.rc new file mode 100644 index 00000000..44e07d7c --- /dev/null +++ b/LEGO1/res/lego1.rc @@ -0,0 +1,39 @@ +#include "resource.h" + +LEGO1_LEAF4 CURSOR "leaf_4.cur" +LEGO1_LEAF7 CURSOR "leaf_7.cur" +LEGO1_LEAF1 CURSOR "leaf_1.cur" +LEGO1_LEAF2 CURSOR "leaf_2.cur" +LEGO1_LEAF6 CURSOR "leaf_6.cur" +LEGO1_LEAF0 CURSOR "leaf_0.cur" +LEGO1_LEAF5 CURSOR "leaf_5.cur" +LEGO1_LEAF3 CURSOR "leaf_3.cur" +LEGO1_ARROW CURSOR "arrow.cur" +LEGO1_BUSY CURSOR "busy.cur" + +1 VERSIONINFO +FILEVERSION 1,1,0,0 +PRODUCTVERSION 1,1,0,0 +FILEOS 0x40004 +FILETYPE 0x2 +{ +BLOCK "StringFileInfo" +{ + BLOCK "040904b0" + { + VALUE "CompanyName", "Mindscape, Inc." + VALUE "FileDescription", "LegoOmni Library" + VALUE "FileVersion", "1, 1, 0, 0" + VALUE "InternalName", "LegoOmni Library" + VALUE "LegalCopyright", "Copyright \xA9 1997" + VALUE "OriginalFilename", "LegoOmni Library" + VALUE "ProductName", "LegoOmni Library" + VALUE "ProductVersion", "1, 1, 0, 0" + } +} + +BLOCK "VarFileInfo" +{ + VALUE "Translation", 0x0409, 0x04B0 +} +} diff --git a/LEGO1/res/resource.h b/LEGO1/res/resource.h new file mode 100644 index 00000000..2402acad --- /dev/null +++ b/LEGO1/res/resource.h @@ -0,0 +1,10 @@ +#define LEGO1_ARROW 101 +#define LEGO1_LEAF4 102 +#define LEGO1_LEAF7 103 +#define LEGO1_LEAF1 104 +#define LEGO1_LEAF2 105 +#define LEGO1_LEAF6 106 +#define LEGO1_LEAF0 107 +#define LEGO1_LEAF5 108 +#define LEGO1_LEAF3 109 +#define LEGO1_BUSY 111 diff --git a/LEGO1/tgl/d3drm/camera.cpp b/LEGO1/tgl/d3drm/camera.cpp new file mode 100644 index 00000000..c7bc06f9 --- /dev/null +++ b/LEGO1/tgl/d3drm/camera.cpp @@ -0,0 +1,30 @@ +#include "impl.h" + +using namespace TglImpl; + +DECOMP_SIZE_ASSERT(Camera, 0x04); +DECOMP_SIZE_ASSERT(CameraImpl, 0x08); + +// FUNCTION: LEGO1 0x100a36f0 +void* CameraImpl::ImplementationDataPtr() +{ + return reinterpret_cast(&m_data); +} + +// FUNCTION: LEGO1 0x100a3700 +Result CameraImpl::SetTransformation(FloatMatrix4& matrix) +{ + D3DRMMATRIX4D helper; + D3DRMMATRIX4D* pTransformation = Translate(matrix, helper); + + D3DVECTOR position; + Result result; + Result result2; + + result2 = ResultVal(m_data->GetPosition(0, &position)); + result = ResultVal(m_data->AddTransform(D3DRMCOMBINE_REPLACE, *pTransformation)); + // The did this second call just to assert on the return value + result2 = ResultVal(m_data->GetPosition(0, &position)); + + return result; +} diff --git a/LEGO1/tgl/d3drm/device.cpp b/LEGO1/tgl/d3drm/device.cpp new file mode 100644 index 00000000..b991d417 --- /dev/null +++ b/LEGO1/tgl/d3drm/device.cpp @@ -0,0 +1,82 @@ +#include "impl.h" + +#include + +using namespace TglImpl; + +// FUNCTION: LEGO1 0x100a2bf0 +void* DeviceImpl::ImplementationDataPtr() +{ + return reinterpret_cast(&m_data); +} + +// FUNCTION: LEGO1 0x100a2c00 +unsigned long DeviceImpl::GetWidth() +{ + return m_data->GetWidth(); +} + +// FUNCTION: LEGO1 0x100a2c10 +unsigned long DeviceImpl::GetHeight() +{ + return m_data->GetHeight(); +} + +// FUNCTION: LEGO1 0x100a2c20 +Result DeviceImpl::SetColorModel(ColorModel) +{ + return Success; +} + +// FUNCTION: LEGO1 0x100a2c30 +Result DeviceImpl::SetShadingModel(ShadingModel model) +{ + // Doesn't match well even though we know this is exactly + // the original code thanks to the jump table. + D3DRMRENDERQUALITY renderQuality = Translate(model); + return ResultVal(m_data->SetQuality(renderQuality)); +} + +// FUNCTION: LEGO1 0x100a2ca0 +Result DeviceImpl::SetShadeCount(unsigned long shadeCount) +{ + return ResultVal(m_data->SetShades(shadeCount)); +} + +// FUNCTION: LEGO1 0x100a2cc0 +Result DeviceImpl::SetDither(int dither) +{ + return ResultVal(m_data->SetDither(dither)); +} + +// Probably wrong, not sure what's going on in this method. +// FUNCTION: LEGO1 0x100a2ce0 +void DeviceImpl::InitFromD3DDevice(Device*) +{ + // Device argument is intentionally unused. + IDirect3DRMWinDevice* winDevice; + if (ResultVal(m_data->QueryInterface(IID_IDirect3DRMWinDevice, (LPVOID*) &winDevice))) { + m_data->InitFromD3D((LPDIRECT3D) &winDevice, (LPDIRECT3DDEVICE) m_data); + winDevice->Release(); + } +} + +// Really don't know what's going on here. Seems it will call down to Init +// but the decomp suggests it otherwise looks the same as InitFromD3D but Init +// takes widly different parameters. +// FUNCTION: LEGO1 0x100a2d20 +void DeviceImpl::InitFromWindowsDevice(Device*) +{ + // Device argument is intentionally unused. + IDirect3DRMWinDevice* winDevice; + if (SUCCEEDED(m_data->QueryInterface(IID_IDirect3DRMWinDevice, (LPVOID*) &winDevice))) { + // m_data->Init(??); + winDevice->Release(); + } +} + +// FUNCTION: LEGO1 0x100a2d60 +Result DeviceImpl::Update() +{ + return ResultVal(m_data->Update()); +} diff --git a/LEGO1/tgl/d3drm/group.cpp b/LEGO1/tgl/d3drm/group.cpp new file mode 100644 index 00000000..a9df8fd6 --- /dev/null +++ b/LEGO1/tgl/d3drm/group.cpp @@ -0,0 +1,119 @@ +#include "impl.h" + +using namespace TglImpl; + +// FUNCTION: LEGO1 0x100a31d0 +void* GroupImpl::ImplementationDataPtr() +{ + return reinterpret_cast(&m_data); +} + +// FUNCTION: LEGO1 0x100a31e0 +Result GroupImpl::SetTransformation(FloatMatrix4& matrix) +{ + D3DRMMATRIX4D helper; + D3DRMMATRIX4D* d3dMatrix = Translate(matrix, helper); + return ResultVal(m_data->AddTransform(D3DRMCOMBINE_REPLACE, *d3dMatrix)); +} + +// FUNCTION: LEGO1 0x100a3240 +Result GroupImpl::SetColor(float r, float g, float b, float a) +{ + // The first instruction makes no sense here: + // cmp dword ptr [esp + 0x10], 0 + // This compares a, which we know is a float because it immediately + // gets passed into D3DRMCreateColorRGBA, but does the comparison + // as though it's an int?? + if (*reinterpret_cast(&a) > 0) { + D3DCOLOR color = D3DRMCreateColorRGBA(r, g, b, a); + return ResultVal(m_data->SetColor(color)); + } + else { + return ResultVal(m_data->SetColorRGB(r, a, b)); + } +} + +// FUNCTION: LEGO1 0x100a32b0 +Result GroupImpl::SetTexture(const Texture* pTexture) +{ + IDirect3DRMTexture* pD3DTexture = pTexture ? static_cast(pTexture)->ImplementationData() : NULL; + return ResultVal(m_data->SetTexture(pD3DTexture)); +} + +// FUNCTION: LEGO1 0x100a32e0 +Result GroupImpl::GetTexture(Texture*& pTexture) +{ + IDirect3DRMTexture* pD3DTexture; + TextureImpl* holder = new TextureImpl(); + Result result = ResultVal(m_data->GetTexture(&pD3DTexture)); + if (result) { + // Seems to actually call the first virtual method of holder here + // but that doesn't make any sense since it passes three arguments + // to the method (self + string constant? + an offset?). + + // This line makes the start of the function match and is what I + // would expect to see there but it clearly isn't what's actually + // there. + holder->SetImplementation(pD3DTexture); + } + pTexture = holder; + return Success; +} + +// FUNCTION: LEGO1 0x100a33c0 +Result GroupImpl::SetMaterialMode(MaterialMode mode) +{ + D3DRMMATERIALMODE d3dMode; + switch (mode) { + case FromParent: + d3dMode = D3DRMMATERIAL_FROMPARENT; + break; + case FromFrame: + d3dMode = D3DRMMATERIAL_FROMFRAME; + break; + case FromMesh: + d3dMode = D3DRMMATERIAL_FROMMESH; + break; + } + return ResultVal(m_data->SetMaterialMode(d3dMode)); +} + +// FUNCTION: LEGO1 0x100a3410 +Result GroupImpl::Add(const Group* pGroup) +{ + const GroupImpl* pGroupImpl = static_cast(pGroup); + return ResultVal(m_data->AddVisual(pGroupImpl->m_data)); +} + +// FUNCTION: LEGO1 0x100a3430 +Result GroupImpl::Add(const MeshBuilder* pMeshBuilder) +{ + const MeshBuilderImpl* pMeshBuilderImpl = static_cast(pMeshBuilder); + return ResultVal(m_data->AddVisual(pMeshBuilderImpl->ImplementationData())); +} + +// FUNCTION: LEGO1 0x100a3450 +Result GroupImpl::Remove(const MeshBuilder* pMeshBuilder) +{ + const MeshBuilderImpl* pMeshBuilderImpl = static_cast(pMeshBuilder); + return ResultVal(m_data->DeleteVisual(pMeshBuilderImpl->ImplementationData())); +} + +// FUNCTION: LEGO1 0x100a3480 +Result GroupImpl::Remove(const Group* pGroup) +{ + const GroupImpl* pGroupImpl = static_cast(pGroup); + return ResultVal(m_data->DeleteVisual(pGroupImpl->m_data)); +} + +// STUB: LEGO1 0x100a34b0 +Result GroupImpl::RemoveAll() +{ + return Error; +} + +// STUB: LEGO1 0x100a3540 +Result GroupImpl::Unknown() +{ + return Error; +} diff --git a/LEGO1/tgl/d3drm/impl.h b/LEGO1/tgl/d3drm/impl.h new file mode 100644 index 00000000..c49ffd1a --- /dev/null +++ b/LEGO1/tgl/d3drm/impl.h @@ -0,0 +1,540 @@ + +#include "compat.h" +#include "decomp.h" +#include "tgl/tgl.h" + +#include + +// Forward declare D3D types +struct IDirect3DRM2; +struct IDirect3DRMDevice2; +struct IDirect3DRMViewport; +struct IDirect3DRMFrame2; +struct IDirect3DRMMesh; +struct IDirect3DRMMeshBuilder; +struct IDirect3DRMTexture; + +namespace TglImpl +{ + +using namespace Tgl; + +// Utility function used by implementations +inline Result ResultVal(HRESULT result) +{ + return SUCCEEDED(result) ? Success : Error; +} + +// Forward declare implementations +class RendererImpl; +class DeviceImpl; +class ViewImpl; +class LightImpl; +class CameraImpl; +class GroupImpl; +class MeshImpl; +class TextureImpl; +class MeshBuilderImpl; + +// VTABLE: LEGO1 0x100db910 +class RendererImpl : public Renderer { +public: + RendererImpl() : m_data(0) {} + ~RendererImpl() override { Destroy(); } + + void* ImplementationDataPtr() override; + + // vtable+0x08 + Device* CreateDevice(const DeviceDirectDrawCreateData&) override; + Device* CreateDevice(const DeviceDirect3DCreateData&) override; + + // vtable+0x10 + View* CreateView( + const Device*, + const Camera*, + unsigned long x, + unsigned long y, + unsigned long width, + unsigned long height + ) override; + Camera* CreateCamera() override; + Light* CreateLight(LightType, float r, float g, float b) override; + Group* CreateGroup(const Group* pParent) override; + + // vtable+0x20 + MeshBuilder* CreateMeshBuilder() override; + Texture* CreateTexture( + int width, + int height, + int bitsPerTexel, + const void* pTexels, + int pTexelsArePersistent, + int paletteEntryCount, + const PaletteEntry* pEntries + ) override; + Texture* CreateTexture() override; + + Result SetTextureDefaultShadeCount(unsigned long) override; + + // vtable+0x30 + Result SetTextureDefaultColorCount(unsigned long) override; + + inline HRESULT CreateTextureFromSurface(LPDIRECTDRAWSURFACE pSurface, LPDIRECT3DRMTEXTURE2* pTexture2) + { + return m_data->CreateTextureFromSurface(pSurface, pTexture2); + } + + inline IDirect3DRM2* ImplementationData() const { return m_data; } + +public: + inline Result Create(); + inline void Destroy(); + +private: + IDirect3DRM2* m_data; +}; + +extern IDirect3DRM2* g_pD3DRM; + +inline void RendererDestroy(IDirect3DRM2* pRenderer) +{ + int refCount = pRenderer->Release(); + if (refCount <= 0) { + g_pD3DRM = NULL; + } +} + +// Inlined only +void RendererImpl::Destroy() +{ + if (m_data) { + RendererDestroy(m_data); + m_data = NULL; + } +} + +// VTABLE: LEGO1 0x100db988 +class DeviceImpl : public Device { +public: + DeviceImpl() : m_data(0) {} + ~DeviceImpl() override + { + if (m_data) { + m_data->Release(); + m_data = NULL; + } + } + + void* ImplementationDataPtr() override; + + // vtable+0x08 + unsigned long GetWidth() override; + unsigned long GetHeight() override; + + // vtable+0x10 + Result SetColorModel(ColorModel) override; + Result SetShadingModel(ShadingModel) override; + Result SetShadeCount(unsigned long) override; + Result SetDither(int) override; + + // vtable+0x20 + Result Update() override; + void InitFromD3DDevice(Device*) override; + void InitFromWindowsDevice(Device*) override; + + inline IDirect3DRMDevice2* ImplementationData() const { return m_data; } + + friend class RendererImpl; + +private: + IDirect3DRMDevice2* m_data; +}; + +// VTABLE: LEGO1 0x100db9e8 +class ViewImpl : public View { +public: + ViewImpl() : m_data(0) {} + ~ViewImpl() override + { + if (m_data) { + m_data->Release(); + m_data = NULL; + } + } + + void* ImplementationDataPtr() override; + + // vtable+0x08 + Result Add(const Light*) override; + Result Remove(const Light*) override; + + // vtable+0x10 + Result SetCamera(const Camera*) override; + Result SetProjection(ProjectionType) override; + Result SetFrustrum(float frontClippingDistance, float backClippingDistance, float degrees) override; + Result SetBackgroundColor(float r, float g, float b) override; + + // vtable+0x20 + Result GetBackgroundColor(float* r, float* g, float* b) override; + Result Clear() override; + Result Render(const Group*) override; + Result ForceUpdate(unsigned long x, unsigned long y, unsigned long width, unsigned long height) override; + + // vtable+0x30 + Result TransformWorldToScreen(const float world[3], float screen[4]) override; + Result TransformScreenToWorld(const float screen[4], float world[3]) override; + Result Pick( + unsigned long x, + unsigned long y, + const Group** ppGroupsToPickFrom, + int groupsToPickFromCount, + const Group**& rppPickedGroups, + int& rPickedGroupCount + ) override; + + inline IDirect3DRMViewport* ImplementationData() const { return m_data; } + + static Result ViewportCreateAppData(IDirect3DRM2*, IDirect3DRMViewport*, IDirect3DRMFrame2*); + + friend class RendererImpl; + +private: + IDirect3DRMViewport* m_data; +}; + +// VTABLE: LEGO1 0x100dbad8 +class CameraImpl : public Camera { +public: + CameraImpl() : m_data(0) {} + ~CameraImpl() override + { + if (m_data) { + m_data->Release(); + m_data = NULL; + } + } + + void* ImplementationDataPtr() override; + + // vtable+0x08 + Result SetTransformation(FloatMatrix4&) override; + + inline IDirect3DRMFrame2* ImplementationData() const { return m_data; } + + friend class RendererImpl; + +private: + IDirect3DRMFrame2* m_data; +}; + +// VTABLE: LEGO1 0x100dbaf8 +class LightImpl : public Light { +public: + LightImpl() : m_data(0) {} + ~LightImpl() override + { + if (m_data) { + m_data->Release(); + m_data = NULL; + } + } + + void* ImplementationDataPtr() override; + + // vtable+0x08 + Result SetTransformation(FloatMatrix4&) override; + Result SetColor(float r, float g, float b) override; + + inline IDirect3DRMFrame2* ImplementationData() const { return m_data; } + + friend class RendererImpl; + +private: + IDirect3DRMFrame2* m_data; +}; + +// VTABLE: LEGO1 0x100dbb88 +class MeshImpl : public Mesh { +public: + MeshImpl() : m_data(0) {} + ~MeshImpl() override + { + if (m_data) { + delete m_data; + m_data = NULL; + } + } + + void* ImplementationDataPtr() override; + + // vtable+0x08 + Result SetColor(float r, float g, float b, float a) override; + Result SetTexture(const Texture*) override; + + // vtable+0x10 + Result GetTexture(Texture*&) override; + Result SetTextureMappingMode(TextureMappingMode) override; + Result SetShadingModel(ShadingModel) override; + Mesh* DeepClone(MeshBuilder*) override; + + // vtable+0x20 + Mesh* ShallowClone(MeshBuilder*) override; + + struct MeshData { + IDirect3DRMMesh* groupMesh; + D3DRMGROUPINDEX groupIndex; + }; + + typedef MeshData* MeshDataType; + + inline const MeshDataType& ImplementationData() const { return m_data; } + inline MeshDataType& ImplementationData() { return m_data; } + + friend class RendererImpl; + +private: + MeshDataType m_data; +}; + +// VTABLE: LEGO1 0x100dba68 +class GroupImpl : public Group { +public: + GroupImpl() : m_data(0) {} + ~GroupImpl() override + { + if (m_data) { + m_data->Release(); + m_data = NULL; + } + } + + void* ImplementationDataPtr() override; + + // vtable+0x08 + Result SetTransformation(FloatMatrix4&) override; + Result SetColor(float r, float g, float b, float a) override; + + // vtable+0x10 + Result SetTexture(const Texture*) override; + Result GetTexture(Texture*&) override; + Result SetMaterialMode(MaterialMode) override; + Result Add(const Group*) override; + + // vtable+0x20 + Result Add(const MeshBuilder*) override; + Result Remove(const Group*) override; + Result Remove(const MeshBuilder*) override; + Result RemoveAll() override; + + // vtable+0x30 + Result Unknown() override; + + inline IDirect3DRMFrame2* ImplementationData() const { return m_data; } + + friend class RendererImpl; + +private: + IDirect3DRMFrame2* m_data; +}; + +// VTABLE: LEGO1 0x100dbb18 +class MeshBuilderImpl : public MeshBuilder { +public: + MeshBuilderImpl() : m_data(0) {} + ~MeshBuilderImpl() override + { + if (m_data) { + m_data->Release(); + m_data = NULL; + } + } + + void* ImplementationDataPtr() override; + + // vtable+0x08 + Mesh* CreateMesh( + unsigned long faceCount, + unsigned long vertexCount, + float (*pPositions)[3], + float (*pNormals)[3], + float (*pTextureCoordinates)[2], + unsigned long (*pFaceIndices)[3], + unsigned long (*pTextureIndices)[3], + ShadingModel shadingModel + ) override; + Result GetBoundingBox(float min[3], float max[3]) const override; + + // vtable+0x10 + MeshBuilder* Clone() override; + + inline IDirect3DRMMesh* ImplementationData() const { return m_data; } + + friend class RendererImpl; + +private: + inline Result CreateMeshImpl( + MeshImpl* pMeshImpl, + unsigned long faceCount, + unsigned long vertexCount, + float (*pPositions)[3], + float (*pNormals)[3], + float (*pTextureCoordinates)[2], + unsigned long (*pFaceIndices)[3], + unsigned long (*pTextureIndices)[3], + ShadingModel shadingModel + ); + + IDirect3DRMMesh* m_data; +}; + +// No vtable, this is just a simple wrapper around D3DRMIMAGE +class TglD3DRMIMAGE { +public: + TglD3DRMIMAGE( + int width, + int height, + int depth, + void* pBuffer, + int useBuffer, + int paletteSize, + PaletteEntry* pEntries + ); + ~TglD3DRMIMAGE() { Destroy(); } + + Result CreateBuffer(int width, int height, int depth, void* pBuffer, int useBuffer); + void Destroy(); + void FillRowsOfTexture(int y, int height, char* content); + Result InitializePalette(int paletteSize, PaletteEntry* pEntries); + + D3DRMIMAGE m_image; + int m_texelsAllocatedByClient; +}; + +// VTABLE: LEGO1 0x100dbb48 +class TextureImpl : public Texture { +public: + TextureImpl() : m_data(0) {} + ~TextureImpl() override + { + if (m_data) { + m_data->Release(); + m_data = NULL; + } + } + + void* ImplementationDataPtr() override; + + // vtable+0x08 + Result SetTexels(int width, int height, int bitsPerTexel, void* pTexels) override; + void FillRowsOfTexture(int y, int height, void* pBuffer) override; + + // vtable+0x10 + Result Changed(int texelsChanged, int paletteChanged) override; + Result GetBufferAndPalette( + int* pWidth, + int* pHeight, + int* pDepth, + void** ppBuffer, + int* ppPaletteSize, + PaletteEntry** ppPalette + ) override; + Result SetPalette(int entryCount, PaletteEntry* entries) override; + + inline IDirect3DRMTexture* ImplementationData() const { return m_data; } + inline void SetImplementation(IDirect3DRMTexture* pData) { m_data = pData; } + + friend class RendererImpl; + + static Result SetImage(IDirect3DRMTexture* pSelf, TglD3DRMIMAGE* pImage); + +private: + IDirect3DRMTexture* m_data; +}; + +// Translation helpers +inline D3DRMRENDERQUALITY Translate(ShadingModel tglShadingModel) +{ + D3DRMRENDERQUALITY renderQuality; + + switch (tglShadingModel) { + case Wireframe: + renderQuality = D3DRMRENDER_WIREFRAME; + break; + case UnlitFlat: + renderQuality = D3DRMRENDER_UNLITFLAT; + break; + case Flat: + renderQuality = D3DRMRENDER_FLAT; + break; + case Gouraud: + renderQuality = D3DRMRENDER_GOURAUD; + break; + case Phong: + renderQuality = D3DRMRENDER_PHONG; + break; + default: + renderQuality = D3DRMRENDER_FLAT; + break; + } + + return renderQuality; +} + +inline D3DRMPROJECTIONTYPE Translate(ProjectionType tglProjectionType) +{ + D3DRMPROJECTIONTYPE projectionType; + switch (tglProjectionType) { + case Perspective: + projectionType = D3DRMPROJECT_PERSPECTIVE; + break; + case Orthographic: + projectionType = D3DRMPROJECT_ORTHOGRAPHIC; + break; + default: + projectionType = D3DRMPROJECT_PERSPECTIVE; + break; + } + return projectionType; +} + +// Yes this function serves no purpose, originally they intended it to +// convert from doubles to floats but ended up using floats throughout +// the software stack. +inline D3DRMMATRIX4D* Translate(FloatMatrix4& tglMatrix4x4, D3DRMMATRIX4D& rD3DRMMatrix4x4) +{ + for (int i = 0; i < (sizeof(rD3DRMMatrix4x4) / sizeof(rD3DRMMatrix4x4[0])); i++) { + for (int j = 0; j < (sizeof(rD3DRMMatrix4x4[0]) / sizeof(rD3DRMMatrix4x4[0][0])); j++) { + rD3DRMMatrix4x4[i][j] = D3DVAL(tglMatrix4x4[i][j]); + } + } + return &rD3DRMMatrix4x4; +} + +// SYNTHETIC: LEGO1 0x100a16d0 +// TglImpl::RendererImpl::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100a22c0 +// TglImpl::DeviceImpl::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100a23a0 +// TglImpl::ViewImpl::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100a2480 +// TglImpl::GroupImpl::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100a2560 +// TglImpl::CameraImpl::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100a2640 +// TglImpl::LightImpl::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100a2720 +// TglImpl::MeshBuilderImpl::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100a2800 +// TglImpl::TextureImpl::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100a3d80 +// TglImpl::MeshImpl::`scalar deleting destructor' + +} /* namespace TglImpl */ diff --git a/LEGO1/tgl/d3drm/light.cpp b/LEGO1/tgl/d3drm/light.cpp new file mode 100644 index 00000000..0fe66bfb --- /dev/null +++ b/LEGO1/tgl/d3drm/light.cpp @@ -0,0 +1,30 @@ +#include "impl.h" + +using namespace TglImpl; + +DECOMP_SIZE_ASSERT(Light, 0x04); +DECOMP_SIZE_ASSERT(LightImpl, 0x08); + +// FUNCTION: LEGO1 0x100a3770 +void* LightImpl::ImplementationDataPtr() +{ + return reinterpret_cast(&m_data); +} + +// FUNCTION: LEGO1 0x100a3780 +Result LightImpl::SetTransformation(FloatMatrix4& matrix) +{ + D3DRMMATRIX4D helper; + D3DRMMATRIX4D* d3dMatrix = Translate(matrix, helper); + return ResultVal(m_data->AddTransform(D3DRMCOMBINE_REPLACE, *d3dMatrix)); +} + +// FUNCTION: LEGO1 0x100a37e0 +Result LightImpl::SetColor(float r, float g, float b) +{ + IDirect3DRMLightArray* lightArray; + IDirect3DRMLight* light; + m_data->GetLights(&lightArray); + lightArray->GetElement(0, &light); + return ResultVal(light->SetColorRGB(r, g, b)); +} diff --git a/LEGO1/tgl/d3drm/mesh.cpp b/LEGO1/tgl/d3drm/mesh.cpp new file mode 100644 index 00000000..9c3f32b4 --- /dev/null +++ b/LEGO1/tgl/d3drm/mesh.cpp @@ -0,0 +1,155 @@ +#include "impl.h" + +using namespace TglImpl; + +DECOMP_SIZE_ASSERT(D3DRMVERTEX, 0x24); + +DECOMP_SIZE_ASSERT(Mesh, 0x04); +DECOMP_SIZE_ASSERT(MeshImpl, 0x08); + +// FUNCTION: LEGO1 0x100a3ed0 +void* MeshImpl::ImplementationDataPtr() +{ + return reinterpret_cast(&m_data); +} + +// FUNCTION: LEGO1 0x100a3ee0 +Result MeshImpl::SetColor(float r, float g, float b, float a) +{ + // The first instruction makes no sense here: + // cmp dword ptr [esp + 0x10], 0 + // This compares a, which we know is a float because it immediately + // gets passed into D3DRMCreateColorRGBA, but does the comparison + // as though it's an int?? + if (*reinterpret_cast(&a) > 0) { + D3DCOLOR color = D3DRMCreateColorRGBA(r, g, b, a); + return ResultVal(m_data->groupMesh->SetGroupColor(m_data->groupIndex, color)); + } + else { + return ResultVal(m_data->groupMesh->SetGroupColorRGB(m_data->groupIndex, r, g, b)); + } +} + +// FUNCTION: LEGO1 0x100a3f50 +Result MeshImpl::SetTexture(const Texture* pTexture) +{ + IDirect3DRMTexture* texture = pTexture ? static_cast(pTexture)->ImplementationData() : NULL; + return ResultVal(m_data->groupMesh->SetGroupTexture(m_data->groupIndex, texture)); +} + +// FUNCTION: LEGO1 0x100a3f80 +Result MeshImpl::SetTextureMappingMode(TextureMappingMode mode) +{ + if (mode == PerspectiveCorrect) { + return ResultVal(m_data->groupMesh->SetGroupMapping(m_data->groupIndex, D3DRMMAP_PERSPCORRECT)); + } + else { + return ResultVal(m_data->groupMesh->SetGroupMapping(m_data->groupIndex, 0)); + } +} + +// FUNCTION: LEGO1 0x100a3fc0 +Result MeshImpl::SetShadingModel(ShadingModel model) +{ + D3DRMRENDERQUALITY mode; + switch (model) { + case Wireframe: + mode = D3DRMRENDER_WIREFRAME; + break; + case UnlitFlat: + mode = D3DRMRENDER_UNLITFLAT; + break; + case Flat: + mode = D3DRMRENDER_FLAT; + break; + case Gouraud: + mode = D3DRMRENDER_GOURAUD; + break; + case Phong: + mode = D3DRMRENDER_PHONG; + break; + } + return ResultVal(m_data->groupMesh->SetGroupQuality(m_data->groupIndex, mode)); +} + +// FUNCTION: LEGO1 0x100a4030 +Mesh* MeshImpl::DeepClone(MeshBuilder* pMeshBuilder) +{ + // Create group + MeshImpl* newMesh = new MeshImpl(); + MeshData* data = new MeshData(); + newMesh->m_data = data; + + // Query information from old group + DWORD dataSize; + unsigned int vcount, fcount, vperface; + m_data->groupMesh->GetGroup(m_data->groupIndex, &vcount, &fcount, &vperface, &dataSize, NULL); + unsigned int* faceBuffer = new unsigned int[dataSize]; + m_data->groupMesh->GetGroup(m_data->groupIndex, &vcount, &fcount, &vperface, &dataSize, faceBuffer); + // We expect vertex to be sized 0x24, checked at start of file. + D3DRMVERTEX* vertexBuffer = new D3DRMVERTEX[vcount]; + m_data->groupMesh->GetVertices(m_data->groupIndex, 0, vcount, vertexBuffer); + LPDIRECT3DRMTEXTURE textureRef; + m_data->groupMesh->GetGroupTexture(m_data->groupIndex, &textureRef); + D3DRMMAPPING mapping = m_data->groupMesh->GetGroupMapping(m_data->groupIndex); + D3DRMRENDERQUALITY quality = m_data->groupMesh->GetGroupQuality(m_data->groupIndex); + D3DCOLOR color = m_data->groupMesh->GetGroupColor(m_data->groupIndex); + + // Push information to new group + MeshBuilderImpl* target = static_cast(pMeshBuilder); + D3DRMGROUPINDEX index; + target->ImplementationData()->AddGroup(vcount, fcount, vperface, faceBuffer, &index); + newMesh->m_data->groupIndex = index; + target->ImplementationData()->SetVertices(index, 0, vcount, vertexBuffer); + target->ImplementationData()->SetGroupTexture(index, textureRef); + target->ImplementationData()->SetGroupMapping(index, mapping); + target->ImplementationData()->SetGroupQuality(index, quality); + Result result = ResultVal(target->ImplementationData()->SetGroupColor(index, color)); + + // Cleanup + delete[] faceBuffer; + delete[] vertexBuffer; + if (result == Error) { + delete newMesh; + newMesh = NULL; + } + + return newMesh; +} + +// FUNCTION: LEGO1 0x100a4240 +Mesh* MeshImpl::ShallowClone(MeshBuilder* pMeshBuilder) +{ + MeshImpl* newGroup = new MeshImpl(); + MeshData* newData = new MeshData(); + newGroup->m_data = newData; + if (newData) { + newData->groupIndex = m_data->groupIndex; + newData->groupMesh = static_cast(pMeshBuilder)->ImplementationData(); + } + else { + delete newGroup; + newGroup = NULL; + } + return newGroup; +} + +// FUNCTION: LEGO1 0x100a4330 +Result MeshImpl::GetTexture(Texture*& rpTexture) +{ + IDirect3DRMTexture* texture; + TextureImpl* holder = new TextureImpl(); + Result result = ResultVal(m_data->groupMesh->GetGroupTexture(m_data->groupIndex, &texture)); + if (result) { + // Seems to actually call the first virtual method of holder here + // but that doesn't make any sense since it passes three arguments + // to the method (self + string constant? + an offset?). + + // This line makes the start of the function match and is what I + // would expect to see there but it clearly isn't what's actually + // there. + holder->SetImplementation(texture); + } + rpTexture = holder; + return Success; +} diff --git a/LEGO1/tgl/d3drm/meshbuilder.cpp b/LEGO1/tgl/d3drm/meshbuilder.cpp new file mode 100644 index 00000000..2766827b --- /dev/null +++ b/LEGO1/tgl/d3drm/meshbuilder.cpp @@ -0,0 +1,187 @@ +#include "impl.h" + +using namespace TglImpl; + +DECOMP_SIZE_ASSERT(MeshBuilder, 0x04); +DECOMP_SIZE_ASSERT(MeshBuilderImpl, 0x08); + +// FUNCTION: LEGO1 0x100a3830 +void* MeshBuilderImpl::ImplementationDataPtr() +{ + return reinterpret_cast(&m_data); +} + +// FUNCTION: LEGO1 0x100a3840 +Mesh* MeshBuilderImpl::CreateMesh( + unsigned long faceCount, + unsigned long vertexCount, + float (*pPositions)[3], + float (*pNormals)[3], + float (*pTextureCoordinates)[2], + unsigned long (*pFaceIndices)[3], + unsigned long (*pTextureIndices)[3], + ShadingModel shadingModel +) +{ + MeshImpl* pMeshImpl = new MeshImpl; + if (CreateMeshImpl( + pMeshImpl, + faceCount, + vertexCount, + pPositions, + pNormals, + pTextureCoordinates, + pFaceIndices, + pTextureIndices, + shadingModel + ) == Error) { + delete pMeshImpl; + pMeshImpl = NULL; + } + + return pMeshImpl; +} + +inline Result MeshSetTextureMappingMode(MeshImpl::MeshData* pMesh, TextureMappingMode mode) +{ + if (mode == PerspectiveCorrect) { + return ResultVal(pMesh->groupMesh->SetGroupMapping(pMesh->groupIndex, D3DRMMAP_PERSPCORRECT)); + } + else { + return ResultVal(pMesh->groupMesh->SetGroupMapping(pMesh->groupIndex, 0)); + } +} + +inline Result CreateMesh( + IDirect3DRMMesh* pD3DRM, + unsigned long faceCount, + unsigned long vertexCount, + float (*pPositions)[3], + float (*pNormals)[3], + float (*pTextureCoordinates)[2], + unsigned long (*pFaceIndices)[3], + unsigned long (*pTextureIndices)[3], + ShadingModel shadingModel, + MeshImpl::MeshDataType& rpMesh +) +{ + unsigned long* faceIndices = (unsigned long*) pFaceIndices; + D3DRMGROUPINDEX groupIndex = 0; + int count = faceCount * 3; + int index = 0; + + unsigned int* fData = new unsigned int[count]; + + D3DRMVERTEX* vertices = new D3DRMVERTEX[vertexCount]; + memset(vertices, 0, sizeof(*vertices) * vertexCount); + + rpMesh = new MeshImpl::MeshData; + rpMesh->groupMesh = pD3DRM; + + for (int i = 0; i < count; i++) { + if ((*((unsigned short*) &faceIndices[i] + 1) >> 0x0f) & 0x01) { + unsigned long j = *(unsigned short*) &faceIndices[i]; + vertices[index].position.x = pPositions[j][0]; + vertices[index].position.y = pPositions[j][1]; + vertices[index].position.z = pPositions[j][2]; + j = *((unsigned short*) &faceIndices[i] + 1) & MAXSHORT; + vertices[index].normal.x = pNormals[j][0]; + vertices[index].normal.y = pNormals[j][1]; + vertices[index].normal.z = pNormals[j][2]; + + if (pTextureIndices != NULL && pTextureCoordinates != NULL) { + j = ((unsigned long*) pTextureIndices)[i]; + vertices[index].tu = pTextureCoordinates[j][0]; + vertices[index].tv = pTextureCoordinates[j][1]; + } + + fData[i] = index; + index++; + } + else { + fData[i] = *(unsigned short*) &faceIndices[i]; + } + } + + Result result; + result = ResultVal(pD3DRM->AddGroup(vertexCount, faceCount, 3, fData, &groupIndex)); + + if (Succeeded(result)) { + rpMesh->groupIndex = groupIndex; + result = ResultVal(pD3DRM->SetVertices(groupIndex, 0, vertexCount, vertices)); + } + + if (!Succeeded(result)) { + if (rpMesh) { + delete rpMesh; + } + rpMesh = NULL; + } + else { + result = MeshSetTextureMappingMode(rpMesh, PerspectiveCorrect); + } + + if (fData != NULL) { + delete[] fData; + } + + if (vertices != NULL) { + delete[] vertices; + } + + return result; +} + +inline Result MeshBuilderImpl::CreateMeshImpl( + MeshImpl* pMeshImpl, + unsigned long faceCount, + unsigned long vertexCount, + float (*pPositions)[3], + float (*pNormals)[3], + float (*pTextureCoordinates)[2], + unsigned long (*pFaceIndices)[3], + unsigned long (*pTextureIndices)[3], + ShadingModel shadingModel +) +{ + return ::CreateMesh( + m_data, + faceCount, + vertexCount, + pPositions, + pNormals, + pTextureCoordinates, + pFaceIndices, + pTextureIndices, + shadingModel, + pMeshImpl->ImplementationData() + ); +} + +// FUNCTION: LEGO1 0x100a3ae0 +Result MeshBuilderImpl::GetBoundingBox(float min[3], float max[3]) const +{ + D3DRMBOX box; + Result result = ResultVal(m_data->GetBox(&box)); + if (result == Success) { + min[0] = box.min.x; + min[1] = box.min.y; + min[2] = box.min.z; + max[0] = box.max.x; + max[1] = box.max.y; + max[2] = box.max.z; + } + return result; +} + +// FUNCTION: LEGO1 0x100a3b40 +MeshBuilder* MeshBuilderImpl::Clone() +{ + MeshBuilderImpl* mesh = new MeshBuilderImpl(); + int ret = m_data->Clone(0, IID_IDirect3DRMMesh, (void**) &mesh->m_data); + if (ret < 0) { + delete mesh; + mesh = NULL; + } + return mesh; +} diff --git a/LEGO1/tgl/d3drm/renderer.cpp b/LEGO1/tgl/d3drm/renderer.cpp new file mode 100644 index 00000000..6a20053a --- /dev/null +++ b/LEGO1/tgl/d3drm/renderer.cpp @@ -0,0 +1,310 @@ +#include "impl.h" + +using namespace TglImpl; + +// FUNCTION: LEGO1 0x100a15e0 +Renderer* Tgl::CreateRenderer() +{ + RendererImpl* renderer = new RendererImpl(); + if (!renderer->Create()) { + delete renderer; + renderer = NULL; + } + return renderer; +} + +namespace TglImpl +{ +// GLOBAL: LEGO1 0x1010103c +IDirect3DRM2* g_pD3DRM = NULL; +} // namespace TglImpl + +// Inlined only +Result RendererImpl::Create() +{ + if (g_pD3DRM) { + g_pD3DRM->AddRef(); + } + else { + LPDIRECT3DRM handle; + Direct3DRMCreate(&handle); + handle->QueryInterface(IID_IDirect3DRM2, (LPVOID*) &g_pD3DRM); + } + m_data = g_pD3DRM; + return (m_data != NULL) ? Success : Error; +} + +// FUNCTION: LEGO1 0x100a1830 +Device* RendererImpl::CreateDevice(const DeviceDirect3DCreateData& data) +{ + DeviceImpl* device = new DeviceImpl(); + HRESULT result = m_data->CreateDeviceFromD3D(data.m_pDirect3D, data.m_pDirect3DDevice, &device->m_data); + if (!SUCCEEDED(result)) { + delete device; + device = NULL; + } + return device; +} + +// GLOBAL: LEGO1 0x10101040 +static int g_SetBufferCount = 1; + +// FUNCTION: LEGO1 0x100a1900 +Device* RendererImpl::CreateDevice(const DeviceDirectDrawCreateData& data) +{ + DeviceImpl* device = new DeviceImpl(); + HRESULT result = m_data->CreateDeviceFromSurface( + const_cast(data.m_driverGUID), + data.m_pDirectDraw, + data.m_pBackBuffer, + &device->m_data + ); + if (SUCCEEDED(result) && data.m_pBackBuffer && g_SetBufferCount) { + device->m_data->SetBufferCount(2); + } + if (!SUCCEEDED(result)) { + delete device; + device = NULL; + } + return device; +} + +inline Result RendererCreateView( + IDirect3DRM2* pRenderer, + IDirect3DRMDevice2* pDevice, + IDirect3DRMFrame2* pCamera, + IDirect3DRMViewport*& rpView, + unsigned long x, + unsigned long y, + unsigned long width, + unsigned long height +) +{ + Result result = ResultVal(pRenderer->CreateViewport(pDevice, pCamera, x, y, width, height, &rpView)); + if (Succeeded(result)) { + result = ViewImpl::ViewportCreateAppData(pRenderer, rpView, pCamera); + if (!Succeeded(result)) { + rpView->Release(); + rpView = NULL; + } + } + return result; +} + +// FUNCTION: LEGO1 0x100a1a00 +View* RendererImpl::CreateView( + const Device* pDevice, + const Camera* pCamera, + unsigned long x, + unsigned long y, + unsigned long width, + unsigned long height +) +{ + ViewImpl* view = new ViewImpl(); + Result result = RendererCreateView( + m_data, + static_cast(pDevice)->m_data, + static_cast(pCamera)->m_data, + view->m_data, + x, + y, + width, + height + ); + if (!result) { + delete view; + view = NULL; + } + return view; +} + +inline Result RendererCreateGroup(IDirect3DRM2* pRenderer, IDirect3DRMFrame2* pParent, IDirect3DRMFrame2*& rpGroup) +{ + Result result = ResultVal(pRenderer->CreateFrame(NULL, &rpGroup)); + if (Succeeded(result) && pParent) { + result = ResultVal(pParent->AddVisual(rpGroup)); + if (!Succeeded(result)) { + rpGroup->Release(); + rpGroup = NULL; + } + } + return result; +} + +// FUNCTION: LEGO1 0x100a1b20 +Group* RendererImpl::CreateGroup(const Group* pParent) +{ + GroupImpl* group = new GroupImpl(); + Result result = + RendererCreateGroup(m_data, pParent ? static_cast(pParent)->m_data : NULL, group->m_data); + if (!result) { + delete group; + group = NULL; + } + return group; +} + +// FUNCTION: LEGO1 0x100a1c30 +Camera* RendererImpl::CreateCamera() +{ + CameraImpl* camera = new CameraImpl(); + if (FAILED(m_data->CreateFrame(NULL, &camera->m_data))) { + delete camera; + camera = NULL; + } + return camera; +} + +// FUNCTION: LEGO1 0x100a1cf0 +Light* RendererImpl::CreateLight(LightType type, float r, float g, float b) +{ + LightImpl* newLight = new LightImpl(); + D3DRMLIGHTTYPE translatedType; + switch (type) { + case Ambient: + translatedType = D3DRMLIGHT_AMBIENT; + break; + case Point: + translatedType = D3DRMLIGHT_POINT; + break; + case Spot: + translatedType = D3DRMLIGHT_SPOT; + break; + case Directional: + translatedType = D3DRMLIGHT_DIRECTIONAL; + break; + case ParallelPoint: + translatedType = D3DRMLIGHT_PARALLELPOINT; + break; + default: + translatedType = D3DRMLIGHT_AMBIENT; + } + + LPDIRECT3DRMFRAME2 frame; + Result result = ResultVal(m_data->CreateFrame(NULL, &frame)); + if (Succeeded(result)) { + LPDIRECT3DRMLIGHT d3dLight; + result = ResultVal(m_data->CreateLightRGB(translatedType, r, g, b, &d3dLight)); + if (!Succeeded(result)) { + frame->Release(); + } + else { + result = ResultVal(frame->AddLight(d3dLight)); + if (!Succeeded(result)) { + d3dLight->Release(); + frame->Release(); + } + else { + d3dLight->Release(); + newLight->m_data = frame; + } + } + } + if (!Succeeded(result)) { + delete newLight; + newLight = NULL; + } + return newLight; +} + +// FUNCTION: LEGO1 0x100a1e90 +MeshBuilder* RendererImpl::CreateMeshBuilder() +{ + MeshBuilderImpl* meshBuilder = new MeshBuilderImpl(); + if (FAILED(m_data->CreateMesh(&meshBuilder->m_data))) { + delete meshBuilder; + meshBuilder = NULL; + } + return meshBuilder; +} + +inline Result RendererCreateTexture( + IDirect3DRM2* renderer, + IDirect3DRMTexture*& texture, + int width, + int height, + int bytesPerPixel, + void* pBuffer, + int useBuffer, + int paletteSize, + PaletteEntry* pEntries +) +{ + TglD3DRMIMAGE* image; + Result result; + + image = new TglD3DRMIMAGE(width, height, bytesPerPixel, pBuffer, useBuffer, paletteSize, pEntries); + // TODO: LPDIRECT3DRMTEXTURE2? + result = ResultVal(renderer->CreateTexture(&image->m_image, (LPDIRECT3DRMTEXTURE2*) &texture)); + if (Succeeded(result)) { + result = TextureImpl::SetImage(texture, image); + if (!Succeeded(result)) { + texture->Release(); + texture = NULL; + delete image; + } + } + else { + delete image; + } + return result; +} + +// FUNCTION: LEGO1 0x100a1f50 +Texture* RendererImpl::CreateTexture( + int width, + int height, + int bitsPerTexel, + const void* pTexels, + int texelsArePersistent, + int paletteEntryCount, + const PaletteEntry* pEntries +) +{ + TextureImpl* texture = new TextureImpl(); + if (!Succeeded(RendererCreateTexture( + m_data, + texture->m_data, + width, + height, + bitsPerTexel, + const_cast(pTexels), + texelsArePersistent, + paletteEntryCount, + const_cast(pEntries) + ))) { + delete texture; + texture = NULL; + } + return texture; +} + +// FUNCTION: LEGO1 0x100a20d0 +Texture* RendererImpl::CreateTexture() +{ + TextureImpl* texture = new TextureImpl(); + if (!Succeeded(RendererCreateTexture(m_data, texture->m_data, 0, 0, 0, NULL, FALSE, 0, NULL))) { + delete texture; + texture = NULL; + } + return texture; +} + +// FUNCTION: LEGO1 0x100a2270 +Result RendererImpl::SetTextureDefaultShadeCount(unsigned long shadeCount) +{ + return ResultVal(m_data->SetDefaultTextureShades(shadeCount)); +} + +// FUNCTION: LEGO1 0x100a2290 +Result RendererImpl::SetTextureDefaultColorCount(unsigned long colorCount) +{ + return ResultVal(m_data->SetDefaultTextureColors(colorCount)); +} + +// FUNCTION: LEGO1 0x100a22b0 +void* RendererImpl::ImplementationDataPtr() +{ + return reinterpret_cast(&m_data); +} diff --git a/LEGO1/tgl/d3drm/texture.cpp b/LEGO1/tgl/d3drm/texture.cpp new file mode 100644 index 00000000..b0ee3813 --- /dev/null +++ b/LEGO1/tgl/d3drm/texture.cpp @@ -0,0 +1,193 @@ +#include "impl.h" + +using namespace TglImpl; + +DECOMP_SIZE_ASSERT(TglD3DRMIMAGE, 0x40); + +inline TglD3DRMIMAGE* TextureGetImage(IDirect3DRMTexture* pTexture) +{ + return reinterpret_cast(pTexture->GetAppData()); +} + +// Forward declare to satisfy order check +void TextureDestroyCallback(IDirect3DRMObject* pObject, void* pArg); + +// FUNCTION: LEGO1 0x100a12a0 +Result TextureImpl::SetImage(IDirect3DRMTexture* pSelf, TglD3DRMIMAGE* pImage) +{ + unsigned long appData; + Result result; + + appData = reinterpret_cast(pImage); + + // This is here because in the original code they asserted + // on the return value being NULL. + TextureGetImage(pSelf); + + result = ResultVal(pSelf->SetAppData(appData)); + if (Succeeded(result) && pImage) { + result = ResultVal(pSelf->AddDestroyCallback(TextureDestroyCallback, NULL)); + if (!Succeeded(result)) { + pSelf->SetAppData(0); + } + } + return result; +} + +// FUNCTION: LEGO1 0x100a1300 +void TextureDestroyCallback(IDirect3DRMObject* pObject, void* pArg) +{ + TglD3DRMIMAGE* pImage = reinterpret_cast(pObject->GetAppData()); + delete pImage; + pObject->SetAppData(0); +} + +// FUNCTION: LEGO1 0x100a1330 +TglD3DRMIMAGE::TglD3DRMIMAGE( + int width, + int height, + int depth, + void* pBuffer, + int useBuffer, + int paletteSize, + PaletteEntry* pEntries +) +{ + m_image.aspectx = 1; + m_image.aspecty = 1; + m_image.width = 0; + m_image.height = 0; + m_image.depth = 0; + m_image.rgb = 0; + m_image.bytes_per_line = 0; + m_image.buffer1 = NULL; + m_image.buffer2 = NULL; + m_image.red_mask = 0xFF; + m_image.green_mask = 0xFF; + m_image.blue_mask = 0xFF; + m_image.alpha_mask = 0xFF; + m_image.palette_size = 0; + m_image.palette = NULL; + m_texelsAllocatedByClient = 0; + if (pBuffer != NULL) { + CreateBuffer(width, height, depth, pBuffer, useBuffer); + } + if (pEntries != NULL) { + InitializePalette(paletteSize, pEntries); + } +} + +// FUNCTION: LEGO1 0x100a13b0 +void TglD3DRMIMAGE::Destroy() +{ + if (m_texelsAllocatedByClient == 0) { + delete m_image.buffer1; + } + delete m_image.palette; +} + +// STUB: LEGO1 0x100a13e0 +Result TglD3DRMIMAGE::CreateBuffer(int width, int height, int depth, void* pBuffer, int useBuffer) +{ + return Error; +} + +// FUNCTION: LEGO1 0x100a1510 +void TglD3DRMIMAGE::FillRowsOfTexture(int y, int height, char* pContent) +{ + // The purpose is clearly this but I can't get the assembly to line up. + memcpy((char*) m_image.buffer1 + (y * m_image.bytes_per_line), pContent, height * m_image.bytes_per_line); +} + +// FUNCTION: LEGO1 0x100a1550 +Result TglD3DRMIMAGE::InitializePalette(int paletteSize, PaletteEntry* pEntries) +{ + // This function is a 100% match if the PaletteEntry class is copied + // into into the TglD3DRMIMAGE class instead of being a global struct. + if (m_image.palette_size != paletteSize) { + if (m_image.palette != NULL) { + delete m_image.palette; + m_image.palette = NULL; + m_image.palette_size = 0; + } + if (paletteSize > 0) { + m_image.palette = new D3DRMPALETTEENTRY[paletteSize]; + m_image.palette_size = paletteSize; + } + } + if (paletteSize > 0) { + for (int i = 0; i < paletteSize; i++) { + m_image.palette[i].red = pEntries[i].m_red; + m_image.palette[i].green = pEntries[i].m_green; + m_image.palette[i].blue = pEntries[i].m_blue; + m_image.palette[i].flags = D3DRMPALETTE_READONLY; + } + } + return Success; +} + +// FUNCTION: LEGO1 0x100a3c10 +Result TextureImpl::SetTexels(int width, int height, int bitsPerTexel, void* pTexels) +{ + TglD3DRMIMAGE* image = TextureGetImage(m_data); + Result result = image->CreateBuffer(width, height, bitsPerTexel, pTexels, TRUE); + if (Succeeded(result)) { + result = ResultVal(m_data->Changed(TRUE, FALSE)); + } + return result; +} + +// FUNCTION: LEGO1 0x100a3c60 +void TextureImpl::FillRowsOfTexture(int y, int height, void* pBuffer) +{ + TglD3DRMIMAGE* image = TextureGetImage(m_data); + image->FillRowsOfTexture(y, height, (char*) pBuffer); +} + +// FUNCTION: LEGO1 0x100a3c90 +Result TextureImpl::Changed(int texelsChanged, int paletteChanged) +{ + return ResultVal(m_data->Changed(texelsChanged, paletteChanged)); +} + +// FUNCTION: LEGO1 0x100a3cc0 +Result TextureImpl::GetBufferAndPalette( + int* width, + int* height, + int* depth, + void** pBuffer, + int* paletteSize, + PaletteEntry** pEntries +) +{ + // Something really doesn't match here, not sure what's up. + TglD3DRMIMAGE* image = TextureGetImage(m_data); + *width = image->m_image.width; + *height = image->m_image.height; + *depth = image->m_image.depth; + *pBuffer = image->m_image.buffer1; + *paletteSize = image->m_image.palette_size; + for (int i = 0; i < image->m_image.palette_size; i++) { + pEntries[i]->m_red = image->m_image.palette[i].red; + pEntries[i]->m_green = image->m_image.palette[i].green; + pEntries[i]->m_blue = image->m_image.palette[i].blue; + } + return Success; +} + +// FUNCTION: LEGO1 0x100a3d40 +Result TextureImpl::SetPalette(int entryCount, PaletteEntry* pEntries) +{ + // Not 100% confident this is supposed to directly be forwarding arguments, + // but it probably is given FillRowsOfTexture matches doing that. + TglD3DRMIMAGE* image = TextureGetImage(m_data); + image->InitializePalette(entryCount, pEntries); + m_data->Changed(FALSE, TRUE); + return Success; +} + +// FUNCTION: LEGO1 0x100a3d70 +void* TextureImpl::ImplementationDataPtr() +{ + return reinterpret_cast(&m_data); +} diff --git a/LEGO1/tgl/d3drm/view.cpp b/LEGO1/tgl/d3drm/view.cpp new file mode 100644 index 00000000..457c54d2 --- /dev/null +++ b/LEGO1/tgl/d3drm/view.cpp @@ -0,0 +1,353 @@ +#include "impl.h" + +using namespace TglImpl; + +struct ViewportAppData { + ViewportAppData(IDirect3DRM2* pRenderer); + ~ViewportAppData(); + + IDirect3DRMFrame2* m_pLightFrame; + IDirect3DRMFrame2* m_pCamera; + IDirect3DRMFrame2* m_pLastRenderedFrame; + float m_backgroundColorRed; + float m_backgroundColorGreen; + float m_backgroundColorBlue; +}; + +DECOMP_SIZE_ASSERT(ViewportAppData, 0x18); + +// FUNCTION: LEGO1 0x100a10b0 +ViewportAppData::ViewportAppData(IDirect3DRM2* pRenderer) +{ + pRenderer->CreateFrame(NULL, &m_pLightFrame); + m_pCamera = NULL; + m_pLastRenderedFrame = NULL; + m_backgroundColorRed = 0.0f; + m_backgroundColorGreen = 0.0f; + m_backgroundColorBlue = 0.0f; +} + +// FUNCTION: LEGO1 0x100a10e0 +ViewportAppData::~ViewportAppData() +{ + IDirect3DRMFrameArray* pChildFrames; + IDirect3DRMFrame* pChildFrame = NULL; + m_pLightFrame->GetChildren(&pChildFrames); + for (int i = 0; i < (int) pChildFrames->GetSize(); i++) { + pChildFrames->GetElement(i, &pChildFrame); + m_pLightFrame->DeleteChild(pChildFrame); + pChildFrame->Release(); // GetElement() does AddRef() + } + pChildFrames->Release(); + m_pLightFrame->Release(); +} + +// Forward declare to satisfy order check +void ViewportDestroyCallback(IDirect3DRMObject* pObject, void* pArg); + +// FUNCTION: LEGO1 0x100a1160 +Result ViewImpl::ViewportCreateAppData(IDirect3DRM2* pDevice, IDirect3DRMViewport* pView, IDirect3DRMFrame2* pCamera) +{ + ViewportAppData* data = new ViewportAppData(pDevice); + data->m_pCamera = pCamera; + Result result = ResultVal(pView->SetAppData(reinterpret_cast(data))); + if (Succeeded(result)) { + result = ResultVal(pView->AddDestroyCallback(ViewportDestroyCallback, data)); + } + if (!Succeeded(result)) { + delete data; + pView->SetAppData(0); + } + return result; +} + +inline Result ViewRestoreFrameAfterRender( + IDirect3DRMFrame* pFrame, + IDirect3DRMFrame* pCamera, + IDirect3DRMFrame* pLightFrame +) +{ + Result result = Success; + if (pFrame) { + // remove camera and light frame from frame that was rendered + // this doesn't destroy the camera as it is still the camera of the viewport... + result = ResultVal(pFrame->DeleteChild(pCamera)); + result = ResultVal(pFrame->DeleteChild(pLightFrame)); + + // decrease frame's ref count (it was increased in ViewPrepareFrameForRender()) + pFrame->Release(); + } + return result; +} + +// FUNCTION: LEGO1 0x100a1240 +void ViewportDestroyCallback(IDirect3DRMObject* pObject, void* pArg) +{ + ViewportAppData* pViewportAppData = reinterpret_cast(pArg); + + ViewRestoreFrameAfterRender( + pViewportAppData->m_pLastRenderedFrame, + pViewportAppData->m_pCamera, + pViewportAppData->m_pLightFrame + ); + + delete pViewportAppData; +} + +// FUNCTION: LEGO1 0x100a1290 +Result ViewportPickImpl( + IDirect3DRMViewport* pViewport, + int x, + int y, + const Group** ppGroupsToPickFrom, + int groupsToPickFromCount, + const Group**& rppPickedGroups, + int& rPickedGroupCount +) +{ + // Left unimplemented in shipped game. + return Error; +} + +inline ViewportAppData* ViewportGetData(IDirect3DRMViewport* pViewport) +{ + return reinterpret_cast(pViewport->GetAppData()); +} + +inline IDirect3DRMFrame* ViewportGetLightFrame(IDirect3DRMViewport* pViewport) +{ + return ViewportGetData(pViewport)->m_pLightFrame; +} + +// FUNCTION: LEGO1 0x100a2d80 +void* ViewImpl::ImplementationDataPtr() +{ + return reinterpret_cast(&m_data); +} + +// FUNCTION: LEGO1 0x100a2d90 +Result ViewImpl::Add(const Light* pLight) +{ + const LightImpl* light = static_cast(pLight); + IDirect3DRMFrame* frame = light->ImplementationData(); + return ResultVal(ViewportGetLightFrame(m_data)->AddChild(frame)); +} + +// FUNCTION: LEGO1 0x100a2dc0 +Result ViewImpl::Remove(const Light* pLight) +{ + const LightImpl* light = static_cast(pLight); + IDirect3DRMFrame* frame = light->ImplementationData(); + return ResultVal(ViewportGetLightFrame(m_data)->DeleteChild(frame)); +} + +// FUNCTION: LEGO1 0x100a2df0 +Result ViewImpl::SetCamera(const Camera* pCamera) +{ + const CameraImpl* camera = static_cast(pCamera); + IDirect3DRMFrame2* frame = camera->ImplementationData(); + + ViewportAppData* pViewportAppData; + Result result; + + pViewportAppData = reinterpret_cast(m_data->GetAppData()); + result = ViewRestoreFrameAfterRender( + pViewportAppData->m_pLastRenderedFrame, + pViewportAppData->m_pCamera, + pViewportAppData->m_pLightFrame + ); + pViewportAppData->m_pCamera = frame; + pViewportAppData->m_pLastRenderedFrame = 0; + + return ResultVal(m_data->SetCamera(frame)); +} + +// FUNCTION: LEGO1 0x100a2e70 +Result ViewImpl::SetProjection(ProjectionType type) +{ + return ResultVal(m_data->SetProjection(Translate(type))); +} + +// FUNCTION: LEGO1 0x100a2eb0 +Result ViewImpl::SetFrustrum(float frontClippingDistance, float backClippingDistance, float degrees) +{ + float field = frontClippingDistance * tan(DegreesToRadians(degrees / 2)); + Result result; + result = ResultVal(m_data->SetFront(frontClippingDistance)); + if (Succeeded(result)) { + result = ResultVal(m_data->SetBack(backClippingDistance)); + } + if (Succeeded(result)) { + result = ResultVal(m_data->SetField(field)); + } + + return result; +} + +// FUNCTION: LEGO1 0x100a2f30 +Result ViewImpl::SetBackgroundColor(float r, float g, float b) +{ + Result ret = Success; + // Note, this method in the shipped game is very diverged from + // the Tgl leak code. + ViewportAppData* data = ViewportGetData(m_data); + data->m_backgroundColorRed = r; + data->m_backgroundColorGreen = g; + data->m_backgroundColorBlue = b; + if (data->m_pLastRenderedFrame) { + ret = ResultVal(data->m_pLastRenderedFrame->SetSceneBackgroundRGB(r, g, b)); + } + return ret; +} + +// FUNCTION: LEGO1 0x100a2f80 +Result ViewImpl::GetBackgroundColor(float* r, float* g, float* b) +{ + ViewportAppData* data = ViewportGetData(m_data); + *r = data->m_backgroundColorRed; + *g = data->m_backgroundColorGreen; + *b = data->m_backgroundColorBlue; + return Success; +} + +// FUNCTION: LEGO1 0x100a2fb0 +Result ViewImpl::Clear() +{ + return ResultVal(m_data->Clear()); +} + +inline Result ViewPrepareFrameForRender( + IDirect3DRMFrame* pFrame, + IDirect3DRMFrame* pCamera, + IDirect3DRMFrame* pLightFrame, + float backgroundRed, + float backgroundGreen, + float backgroundBlue +) +{ + Result result = Success; + + if (pFrame) { + // set background color + result = ResultVal(pFrame->SetSceneBackgroundRGB(backgroundRed, backgroundGreen, backgroundBlue)); + + // add camera to frame to be rendered + result = ResultVal(pFrame->AddChild(pCamera)); + + // add light frame to frame to be rendered + result = ResultVal(pFrame->AddChild(pLightFrame)); + + // increase ref count of frame to ensure it does not get deleted underneath us + pFrame->AddRef(); + } + + return result; +} + +inline Result ViewRender(IDirect3DRMViewport* pViewport, const IDirect3DRMFrame2* pGroup) +{ + ViewportAppData* pViewportAppData; + Result result; + + pViewportAppData = reinterpret_cast(pViewport->GetAppData()); + + if (pViewportAppData->m_pLastRenderedFrame != pGroup) { + result = ViewRestoreFrameAfterRender( + pViewportAppData->m_pLastRenderedFrame, + pViewportAppData->m_pCamera, + pViewportAppData->m_pLightFrame + ); + + pViewportAppData->m_pLastRenderedFrame = const_cast(pGroup); + + result = ViewPrepareFrameForRender( + pViewportAppData->m_pLastRenderedFrame, + pViewportAppData->m_pCamera, + pViewportAppData->m_pLightFrame, + pViewportAppData->m_backgroundColorRed, + pViewportAppData->m_backgroundColorGreen, + pViewportAppData->m_backgroundColorBlue + ); + } + + result = ResultVal(pViewport->Render(const_cast(pGroup))); + return result; +} + +// FUNCTION: LEGO1 0x100a2fd0 +Result ViewImpl::Render(const Group* pGroup) +{ + return ViewRender(m_data, static_cast(pGroup)->ImplementationData()); +} + +// FUNCTION: LEGO1 0x100a3080 +Result ViewImpl::ForceUpdate(unsigned long x, unsigned long y, unsigned long width, unsigned long height) +{ + return ResultVal(m_data->ForceUpdate(x, y, x + width - 1, y + height - 1)); +} + +// FUNCTION: LEGO1 0x100a30c0 +Result ViewImpl::Pick( + unsigned long x, + unsigned long y, + const Group** ppGroupsToPickFrom, + int groupsToPickFromCount, + const Group**& rppPickedGroups, + int& rPickedGroupCount +) +{ + return ViewportPickImpl( + m_data, + x, + y, + ppGroupsToPickFrom, + groupsToPickFromCount, + rppPickedGroups, + rPickedGroupCount + ); +} + +// FUNCTION: LEGO1 0x100a30f0 +Result ViewImpl::TransformWorldToScreen(const float world[3], float screen[4]) +{ + D3DRMVECTOR4D d3dRMScreen; + D3DVECTOR d3dRMWorld; + d3dRMWorld.x = world[0]; + d3dRMWorld.y = world[1]; + d3dRMWorld.z = world[2]; + Result result; + + result = ResultVal(m_data->Transform(&d3dRMScreen, &d3dRMWorld)); + + if (Succeeded(result)) { + screen[0] = d3dRMScreen.x; + screen[1] = d3dRMScreen.y; + screen[2] = d3dRMScreen.z; + screen[3] = d3dRMScreen.w; + } + + return result; +} + +// FUNCTION: LEGO1 0x100a3160 +Result ViewImpl::TransformScreenToWorld(const float screen[4], float world[3]) +{ + // 100% match minus instruction reordering. + D3DVECTOR d3dRMWorld; + D3DRMVECTOR4D d3dScreen; + d3dScreen.x = screen[0]; + d3dScreen.y = screen[1]; + d3dScreen.z = screen[2]; + d3dScreen.w = screen[3]; + Result result; + + result = ResultVal(m_data->InverseTransform(&d3dRMWorld, &d3dScreen)); + + if (Succeeded(result)) { + world[0] = d3dRMWorld.x; + world[1] = d3dRMWorld.y; + world[2] = d3dRMWorld.z; + } + + return result; +} diff --git a/LEGO1/tgl/tgl.h b/LEGO1/tgl/tgl.h new file mode 100644 index 00000000..4c29ed1f --- /dev/null +++ b/LEGO1/tgl/tgl.h @@ -0,0 +1,371 @@ + +#ifndef _tgl_h +#define _tgl_h + +#include "tglvector.h" + +#include +#include +#include + +namespace Tgl +{ + +enum ColorModel { + // Note: Not used in shipped game, no way to verify contents. + Ramp, + RGB +}; + +enum ShadingModel { + Wireframe, + UnlitFlat, + Flat, + Gouraud, + Phong +}; + +enum LightType { + Ambient, + Point, + Spot, + Directional, + ParallelPoint +}; + +enum ProjectionType { + Perspective, + Orthographic +}; + +enum TextureMappingMode { + Linear, + PerspectiveCorrect +}; + +// Not in the Tgl leak, inferred from the assembly +enum MaterialMode { + FromParent, + FromFrame, + FromMesh, +}; + +struct PaletteEntry { + unsigned char m_red; + unsigned char m_green; + unsigned char m_blue; +}; + +struct DeviceDirect3DCreateData { + IDirect3D2* m_pDirect3D; + IDirect3DDevice2* m_pDirect3DDevice; +}; + +struct DeviceDirectDrawCreateData { + const GUID* m_driverGUID; + HWND m_hWnd; + IDirectDraw* m_pDirectDraw; + IDirectDrawSurface* m_pFrontBuffer; + IDirectDrawSurface* m_pBackBuffer; + + // These have possibly been removed in the shipped game + // (Put them back if we can verify when we find a callsite + // which constructs this type) + // IDirectDrawPalette* m_pPalette; + // int m_isFullScreen; +}; + +// Result type used for all methods in the Tgl API +enum Result { + Error = 0, + Success = 1 +}; + +inline int Succeeded(Result result) +{ + return (result == Success); +} + +// Forward declarations +class Renderer; +class Object; +class Device; +class View; +class Light; +class Camera; +class Group; +class Mesh; +class Texture; +class MeshBuilder; + +// VTABLE: LEGO1 0x100db980 +class Object { +public: + // FUNCTION: LEGO1 0x100a2240 + virtual ~Object() {} + + virtual void* ImplementationDataPtr() = 0; + + // SYNTHETIC: LEGO1 0x100a2250 + // Tgl::Object::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100db948 +class Renderer : public Object { +public: + // vtable+0x08 + virtual Device* CreateDevice(const DeviceDirectDrawCreateData&) = 0; + virtual Device* CreateDevice(const DeviceDirect3DCreateData&) = 0; + + // vtable+0x10 + virtual View* CreateView( + const Device*, + const Camera*, + unsigned long x, + unsigned long y, + unsigned long width, + unsigned long height + ) = 0; + virtual Camera* CreateCamera() = 0; + virtual Light* CreateLight(LightType, float r, float g, float b) = 0; + virtual Group* CreateGroup(const Group* pParent = 0) = 0; + + // vtable+0x20 + virtual MeshBuilder* CreateMeshBuilder() = 0; + virtual Texture* CreateTexture( + int width, + int height, + int bitsPerTexel, + const void* pTexels, + int pTexelsArePersistent, + int paletteEntryCount, + const PaletteEntry* pEntries + ) = 0; + virtual Texture* CreateTexture() = 0; + virtual Result SetTextureDefaultShadeCount(unsigned long) = 0; + + // vtable+0x30 + virtual Result SetTextureDefaultColorCount(unsigned long) = 0; + + // SYNTHETIC: LEGO1 0x100a1770 + // Tgl::Renderer::~Renderer + + // SYNTHETIC: LEGO1 0x100a17c0 + // Tgl::Renderer::`scalar deleting destructor' +}; + +Renderer* CreateRenderer(); + +// VTABLE: LEGO1 0x100db9b8 +class Device : public Object { +public: + // vtable+0x08 + virtual unsigned long GetWidth() = 0; + virtual unsigned long GetHeight() = 0; + + // vtable+0x10 + virtual Result SetColorModel(ColorModel) = 0; + virtual Result SetShadingModel(ShadingModel) = 0; + virtual Result SetShadeCount(unsigned long) = 0; + virtual Result SetDither(int) = 0; + + // vtable+0x20 + virtual Result Update() = 0; + virtual void InitFromD3DDevice(Device*) = 0; + virtual void InitFromWindowsDevice(Device*) = 0; + + // SYNTHETIC: LEGO1 0x100a2350 + // Tgl::Device::~Device + + // SYNTHETIC: LEGO1 0x100a28e0 + // Tgl::Device::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dba28 +class View : public Object { +public: + virtual Result Add(const Light*) = 0; + virtual Result Remove(const Light*) = 0; + + // vtable+0x10 + virtual Result SetCamera(const Camera*) = 0; + virtual Result SetProjection(ProjectionType) = 0; + virtual Result SetFrustrum(float frontClippingDistance, float backClippingDistance, float degrees) = 0; + virtual Result SetBackgroundColor(float r, float g, float b) = 0; + + // vtable+0x20 + virtual Result GetBackgroundColor(float* r, float* g, float* b) = 0; + virtual Result Clear() = 0; + virtual Result Render(const Group*) = 0; + virtual Result ForceUpdate(unsigned long x, unsigned long y, unsigned long width, unsigned long height) = 0; + + // vtable+0x30 + virtual Result TransformWorldToScreen(const float world[3], float screen[4]) = 0; + virtual Result TransformScreenToWorld(const float screen[4], float world[3]) = 0; + + // Pick(): + // x, y: + // view coordinates + // + // ppGroupsToPickFrom: + // array of (Group*) in any order + // Groups to pick from + // + // groupsToPickFromCount: + // size of ppGroupsToPickFrom + // + // rppPickedGroups: + // output parameter + // array of (Group*) representing a Group hierarchy + // top-down order (element 0 is root/scene) + // caller must deallocate array + // ref count of each element (Group*) has not been increased + // an element will be 0, if a corresponding Group was not found in ppGroupsToPickFrom + // + // rPickedGroupCount: + // output parameter + // size of rppPickedGroups + virtual Result Pick( + unsigned long x, + unsigned long y, + const Group** ppGroupsToPickFrom, + int groupsToPickFromCount, + const Group**& rppPickedGroups, + int& rPickedGroupCount + ) = 0; + + // SYNTHETIC: LEGO1 0x100a2430 + // Tgl::View::~View + + // SYNTHETIC: LEGO1 0x100a2950 + // Tgl::View::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dbae8 +class Camera : public Object { +public: + virtual Result SetTransformation(FloatMatrix4&) = 0; + + // SYNTHETIC: LEGO1 0x100a25f0 + // Tgl::Camera::~Camera + + // SYNTHETIC: LEGO1 0x100a2a30 + // Tgl::Camera::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dbb08 +class Light : public Object { +public: + virtual Result SetTransformation(FloatMatrix4&) = 0; + virtual Result SetColor(float r, float g, float b) = 0; + + // SYNTHETIC: LEGO1 0x100a26d0 + // Tgl::Light::~Light + + // SYNTHETIC: LEGO1 0x100a2aa0 + // Tgl::Light::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dbbb0 +class Mesh : public Object { +public: + // SYNTHETIC: LEGO1 0x100a3e10 + // Tgl::Mesh::~Mesh + + virtual Result SetColor(float r, float g, float b, float a) = 0; + virtual Result SetTexture(const Texture*) = 0; + virtual Result GetTexture(Texture*&) = 0; + + virtual Result SetTextureMappingMode(TextureMappingMode) = 0; + virtual Result SetShadingModel(ShadingModel) = 0; + + // Clone data in underlying group + virtual Mesh* DeepClone(MeshBuilder*) = 0; + + // Just get another Group pointing to the same underlying data + virtual Mesh* ShallowClone(MeshBuilder*) = 0; + + // SYNTHETIC: LEGO1 0x100a3e60 + // Tgl::Mesh::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dbaa0 +class Group : public Object { +public: + virtual Result SetTransformation(FloatMatrix4&) = 0; + virtual Result SetColor(float r, float g, float b, float a) = 0; + virtual Result SetTexture(const Texture*) = 0; + virtual Result GetTexture(Texture*&) = 0; + virtual Result SetMaterialMode(MaterialMode) = 0; + virtual Result Add(const Group*) = 0; + virtual Result Add(const MeshBuilder*) = 0; + virtual Result Remove(const Group*) = 0; + virtual Result Remove(const MeshBuilder*) = 0; + virtual Result RemoveAll() = 0; + + // This is TransformLocalToWorld in the leak, however it seems + // to have been replaced by something else in the shipped code. + virtual Result Unknown() = 0; + + // SYNTHETIC: LEGO1 0x100a2510 + // Tgl::Group::~Group + + // SYNTHETIC: LEGO1 0x100a29c0 + // Tgl::Group::`scalar deleting destructor' +}; + +// Don't know what this is. Seems like another Tgl object which +// was not in the leaked Tgl code. My suspicion is that it's +// some kind of builder class for creating meshes. +// VTABLE: LEGO1 0x100dbb30 +class MeshBuilder : public Object { +public: + virtual Mesh* CreateMesh( + unsigned long faceCount, + unsigned long vertexCount, + float (*pPositions)[3], + float (*pNormals)[3], + float (*pTextureCoordinates)[2], + unsigned long (*pFaceIndices)[3], + unsigned long (*pTextureIndices)[3], + ShadingModel shadingModel + ) = 0; + virtual Result GetBoundingBox(float min[3], float max[3]) const = 0; + virtual MeshBuilder* Clone() = 0; + + // SYNTHETIC: LEGO1 0x100a27b0 + // Tgl::MeshBuilder::~MeshBuilder + + // SYNTHETIC: LEGO1 0x100a2b10 + // Tgl::MeshBuilder::`scalar deleting destructor' +}; + +// VTABLE: LEGO1 0x100dbb68 +class Texture : public Object { +public: + // vtable+0x08 + virtual Result SetTexels(int width, int height, int bitsPerTexel, void* pTexels) = 0; + virtual void FillRowsOfTexture(int y, int height, void* pBuffer) = 0; + + // vtable+0x10 + virtual Result Changed(int texelsChanged, int paletteChanged) = 0; + virtual Result GetBufferAndPalette( + int* pWidth, + int* pHeight, + int* pDepth, + void** ppBuffer, + int* pPaletteSize, + PaletteEntry** ppPalette + ) = 0; + virtual Result SetPalette(int entryCount, PaletteEntry* pEntries) = 0; + + // SYNTHETIC: LEGO1 0x100a2890 + // Tgl::Texture::~Texture + + // SYNTHETIC: LEGO1 0x100a2b80 + // Tgl::Texture::`scalar deleting destructor' +}; + +} // namespace Tgl + +#endif /* _tgl_h */ diff --git a/LEGO1/tgl/tglvector.h b/LEGO1/tgl/tglvector.h new file mode 100644 index 00000000..8612724f --- /dev/null +++ b/LEGO1/tgl/tglvector.h @@ -0,0 +1,30 @@ +#ifndef _tglVector_h +#define _tglVector_h + +#include "math.h" // sin() in RotateAroundY() + +#include // offsetof() + +namespace Tgl +{ + +namespace Constant +{ +const float Pi = 3.14159265358979323846; +}; + +inline float DegreesToRadians(float degrees) +{ + return Constant::Pi * (degrees / 180.0); +} + +inline float RadiansToDegrees(float radians) +{ + return (radians / Constant::Pi) * 180.0; +} + +typedef float FloatMatrix4[4][4]; + +} // namespace Tgl + +#endif /* _tglVector_h */ diff --git a/LEGO1/viewmanager/viewlod.cpp b/LEGO1/viewmanager/viewlod.cpp new file mode 100644 index 00000000..aa04813e --- /dev/null +++ b/LEGO1/viewmanager/viewlod.cpp @@ -0,0 +1,7 @@ +#include "viewlod.h" + +// FUNCTION: LEGO1 0x100a5e40 +ViewLOD::~ViewLOD() +{ + delete m_meshBuilder; +} diff --git a/LEGO1/viewmanager/viewlod.h b/LEGO1/viewmanager/viewlod.h new file mode 100644 index 00000000..7bf68b52 --- /dev/null +++ b/LEGO1/viewmanager/viewlod.h @@ -0,0 +1,46 @@ +#ifndef VIEWLOD_H +#define VIEWLOD_H + +#include "decomp.h" +#include "realtime/roi.h" +#include "tgl/tgl.h" + +////////////////////////////////////////////////////////////////////////////// +// ViewLOD +// + +// VTABLE: LEGO1 0x100dbd70 +// SIZE 0x0c +class ViewLOD : public LODObject { +public: + enum { + c_bit4 = 0x10 + }; + + ViewLOD(Tgl::Renderer* pRenderer) : m_meshBuilder(NULL), m_unk0x08(3) {} + ~ViewLOD() override; + + // FUNCTION: LEGO1 0x100a6f30 + double AveragePolyArea() const override { return 2 * 3.14159 * 10.0 / NumPolys(); } // vtable+0x04 + + // FUNCTION: LEGO1 0x100a6f50 + int NVerts() const override { return NumPolys() * 2; } // vtable+0x08 + + Tgl::MeshBuilder* GetMeshBuilder() { return m_meshBuilder; } + const Tgl::MeshBuilder* GetMeshBuilder() const { return m_meshBuilder; } + undefined4 GetUnknown0x08() { return m_unk0x08; } + unsigned char GetUnknown0x08Test4() { return m_unk0x08 & 0xffffff04; } + unsigned char GetUnknown0x08Test8() { return m_unk0x08 & 0xffffff08; } + + void SetFlag(unsigned char p_flag) { m_unk0x08 |= p_flag; } + void ClearFlag(unsigned char p_flag) { m_unk0x08 &= ~p_flag; } + + // SYNTHETIC: LEGO1 0x100a6f60 + // ViewLOD::`scalar deleting destructor' + +protected: + Tgl::MeshBuilder* m_meshBuilder; // 0x04 + undefined4 m_unk0x08; // 0x08 +}; + +#endif // VIEWLOD_H diff --git a/LEGO1/viewmanager/viewlodlist.cpp b/LEGO1/viewmanager/viewlodlist.cpp new file mode 100644 index 00000000..ca57bc01 --- /dev/null +++ b/LEGO1/viewmanager/viewlodlist.cpp @@ -0,0 +1,152 @@ +#include "viewlodlist.h" + +#include "decomp.h" +#include "viewlod.h" + +#include + +DECOMP_SIZE_ASSERT(ViewLODListManager, 0x14) +DECOMP_SIZE_ASSERT(LODListBase, 0x10) +DECOMP_SIZE_ASSERT(LODList, 0x10) +DECOMP_SIZE_ASSERT(ViewLODList, 0x18) + +// GLOBAL: LEGO1 0x10101064 +// GLOBAL: BETA10 0x10205d08 +int ViewLODListManager::g_ROINameUID = 0; + +#ifdef _DEBUG +// FUNCTION: BETA10 0x10178310 +inline void ViewLODList::Dump(void (*pTracer)(const char*, ...)) const +{ + pTracer(" ViewLODList<0x%x>: Capacity=%d, Size=%d, RefCount=%d\n", this, Capacity(), Size(), m_refCount); + + for (int i = 0; i < (int) Size(); i++) { + ViewLOD* lod = const_cast(this->operator[](i)); + pTracer(" [%d]: ViewLOD<0x%x>: Vertices=%d\n", i, lod, lod->NVerts()); + } +} +#endif + +// FUNCTION: LEGO1 0x100a6fd0 +// FUNCTION: BETA10 0x101783a3 +ViewLODListManager::ViewLODListManager() +{ +} + +// FUNCTION: LEGO1 0x100a7130 +// FUNCTION: BETA10 0x1017841c +// FUNCTION: ALPHA 0x100e3402 +ViewLODListManager::~ViewLODListManager() +{ + ViewLODListMap::iterator iterator; + + // delete all ViewLODLists + for (iterator = m_map.begin(); !(iterator == m_map.end()); ++iterator) { + const ROIName& rROIName = (*iterator).first; + ViewLODList* pLODList = (*iterator).second; + + // ???who pops and deletes LODObjects + while (pLODList->Size() > 0) { + delete const_cast(pLODList->PopBack()); + } + + delete pLODList; + // ??? for now + delete[] const_cast(rROIName); + } + + // ??? correct way of "emptying" map + m_map.erase(m_map.begin(), m_map.end()); + + assert(m_map.begin() == m_map.end()); +} + +// FUNCTION: LEGO1 0x100a72c0 +// FUNCTION: BETA10 0x101785ef +// FUNCTION: ALPHA 0x100e35d2 +ViewLODList* ViewLODListManager::Create(const ROIName& rROIName, int lodCount) +{ + // returned ViewLODList has a refCount of 1, i.e. caller must call Release() + // when it no longer holds on to the list + + ViewLODList* pLODList; + int refCount; + char* pROIName; + + // assert(!Lookup(rROIName)); // alpha only + + pLODList = new ViewLODList(lodCount, this); + refCount = pLODList->AddRef(); + assert(refCount == 1); + + ViewLODList* list = Lookup(rROIName); + if (list != NULL) { + list->Release(); + + char num[12]; + sprintf(num, "%d", g_ROINameUID); + pROIName = new char[strlen(rROIName) + strlen(num) + 1]; + strcpy(pROIName, rROIName); + strcat(pROIName, num); + g_ROINameUID++; + } + else { + pROIName = new char[strlen(rROIName) + 1]; + strcpy(pROIName, rROIName); + } + + m_map[pROIName] = pLODList; + + // NOTE: Lookup() adds a refCount + assert((Lookup(pROIName) == pLODList) && (pLODList->Release() == 1)); + + return pLODList; +} + +// FUNCTION: LEGO1 0x100a75b0 +// FUNCTION: BETA10 0x101787d8 +ViewLODList* ViewLODListManager::Lookup(const ROIName& p_roiName) const +{ + // returned ViewLODList's refCount is increased, i.e. caller must call Release() + // when it no longer holds on to the list + + ViewLODListMap::const_iterator iterator = m_map.find(p_roiName); + ViewLODList* pLODList = 0; + + if (!(iterator == m_map.end())) { + pLODList = (*iterator).second; + + assert(pLODList); + pLODList->AddRef(); + } + + return pLODList; +} + +// FUNCTION: LEGO1 0x100a7680 +// FUNCTION: BETA10 0x1017886b +unsigned char ViewLODListManager::Destroy(ViewLODList* lodList) +{ + ViewLODListMap::iterator iterator; + char deleted = FALSE; + + for (iterator = m_map.begin(); !(iterator == m_map.end()); ++iterator) { + const ROIName& rROIName = (*iterator).first; + ViewLODList* pLODList = (*iterator).second; + + if (lodList == pLODList) { + while (pLODList->Size() > 0) { + delete const_cast(pLODList->PopBack()); + } + + delete pLODList; + delete[] const_cast(rROIName); + m_map.erase(iterator); + + deleted = TRUE; + break; + } + } + + return deleted; +} diff --git a/LEGO1/viewmanager/viewlodlist.h b/LEGO1/viewmanager/viewlodlist.h new file mode 100644 index 00000000..187d6feb --- /dev/null +++ b/LEGO1/viewmanager/viewlodlist.h @@ -0,0 +1,228 @@ +#ifndef VIEWLODLIST_H +#define VIEWLODLIST_H + +#include "assert.h" +#include "compat.h" +#include "mxstl/stlcompat.h" +#include "realtime/lodlist.h" + +#include + +#pragma warning(disable : 4237) +#pragma warning(disable : 4786) + +class ViewLOD; +class ViewLODListManager; + +////////////////////////////////////////////////////////////////////////////// +// ViewLODList +// +// An ViewLODList is an LODList that is shared among instances of the "same ROI". +// +// ViewLODLists are managed (created and destroyed) by ViewLODListManager. +// + +// VTABLE: LEGO1 0x100dbdc4 +// VTABLE: BETA10 0x101c34f0 +// SIZE 0x18 +class ViewLODList : public LODList { + friend ViewLODListManager; + +protected: + ViewLODList(size_t capacity, ViewLODListManager* owner); + ~ViewLODList() override; + + // SYNTHETIC: LEGO1 0x100a80f0 + // SYNTHETIC: BETA10 0x1017b590 + // ViewLODList::`scalar deleting destructor' + +public: + inline int AddRef(); + inline int Release(); + +#ifdef _DEBUG + void Dump(void (*pTracer)(const char*, ...)) const; +#endif + +private: + int m_refCount; // 0x10 + ViewLODListManager* m_owner; // 0x14 +}; + +////////////////////////////////////////////////////////////////////////////// +// + +// ??? for now, until we have symbol management +typedef const char* ROIName; +struct ROINameComparator { + // FUNCTION: BETA10 0x101794c0 + unsigned char operator()(const ROIName& rName1, const ROIName& rName2) const + { + return strcmp((const char*) rName1, (const char*) rName2) > 0; + } +}; + +////////////////////////////////////////////////////////////////////////////// +// +// ViewLODListManager +// +// ViewLODListManager manages creation and sharing of ViewLODLists. +// It stores ViewLODLists under a name, the name of the ROI where +// the ViewLODList belongs. + +// VTABLE: LEGO1 0x100dbdbc +// VTABLE: BETA10 0x101c34ec +// SIZE 0x14 +class ViewLODListManager { + + typedef map ViewLODListMap; + +public: + ViewLODListManager(); + virtual ~ViewLODListManager(); + + // ??? should LODList be const + + // creates an LODList with room for lodCount LODs for a named ROI + // returned LODList has a refCount of 1, i.e. caller must call Release() + // when it no longer holds on to the list + ViewLODList* Create(const ROIName& rROIName, int lodCount); + + // returns an LODList for a named ROI + // returned LODList's refCount is increased, i.e. caller must call Release() + // when it no longer holds on to the list + ViewLODList* Lookup(const ROIName&) const; + unsigned char Destroy(ViewLODList* lodList); + +#ifdef _DEBUG + void Dump(void (*pTracer)(const char*, ...)) const; +#endif + + // SYNTHETIC: LEGO1 0x100a70c0 + // SYNTHETIC: BETA10 0x10178a80 + // ViewLODListManager::`scalar deleting destructor' + +private: + static int g_ROINameUID; + + ViewLODListMap m_map; +}; + +// clang-format off +// FUNCTION: LEGO1 0x1001dde0 +// FUNCTION: BETA10 0x100223c0 +// _Lockit::~_Lockit + +// TEMPLATE: LEGO1 0x100a70e0 +// TEMPLATE: BETA10 0x10178ac0 +// Map::~Map + +// TEMPLATE: LEGO1 0x100a7800 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::iterator::_Dec + +// TEMPLATE: LEGO1 0x100a7850 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::iterator::_Inc + +// TEMPLATE: LEGO1 0x100a7890 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::~_Tree,map,map >::_Kfn,ROINameComparator,allocator >::erase + +// TEMPLATE: LEGO1 0x100a7db0 +// TEMPLATE: BETA10 0x1017aca0 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::_Erase + +// TEMPLATE: LEGO1 0x100a7df0 +// TEMPLATE: BETA10 0x101796b0 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::_Insert + +// TEMPLATE: LEGO1 0x100a80a0 +// TEMPLATE: BETA10 0x1017b1e0 +// map >::~map > + +// GLOBAL: LEGO1 0x10101068 +// GLOBAL: BETA10 0x10205eb4 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::_Nil + +// TEMPLATE: BETA10 0x101791f0 +// map >::operator[] + +// TEMPLATE: BETA10 0x10178c80 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::iterator::operator== + +// TEMPLATE: BETA10 0x10178ef0 +// map >::begin + +// TEMPLATE: BETA10 0x10179070 +// map >::end + +// TEMPLATE: BETA10 0x10179250 +// pair::pair + +// TEMPLATE: BETA10 0x10179280 +// map >::insert + +// TEMPLATE: BETA10 0x101792c0 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::insert + +// TEMPLATE: BETA10 0x10178c00 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::iterator::operator* + +// TEMPLATE: BETA10 0x1017ab10 +// map >::erase +// Two iterators + +// TEMPLATE: BETA10 0x1017a040 +// map >::erase +// One iterator + +// TEMPLATE: BETA10 0x10178f80 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::_Lmost + +// TEMPLATE: BETA10 0x10179e70 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::_Rmost + +// TEMPLATE: BETA10 0x10179670 +// _Tree,map >::_Kfn,ROINameComparator,allocator >::_Color + +// TEMPLATE: BETA10 0x1017aa30 +// ?swap@@YAXAAW4_Redbl@?$_Tree@PBDU?$pair@QBDPAVViewLODList@@@@U_Kfn@?$map@PBDPAVViewLODList@@UROINameComparator@@V?$allocator@PAVViewLODList@@@@@@UROINameComparator@@V?$allocator@PAVViewLODList@@@@@@0@Z + +// clang-format on + +////////////////////////////////////////////////////////////////////////////// +// +// ViewLODList implementation + +// FUNCTION: BETA10 0x1017b240 +inline ViewLODList::ViewLODList(size_t capacity, ViewLODListManager* owner) : LODList(capacity), m_refCount(0) +{ + m_owner = owner; +} + +inline ViewLODList::~ViewLODList() +{ + assert(m_refCount == 0); +} + +// FUNCTION: BETA10 0x1007b5b0 +inline int ViewLODList::AddRef() +{ + return ++m_refCount; +} + +// FUNCTION: BETA10 0x1007ad70 +inline int ViewLODList::Release() +{ + assert(m_refCount > 0); + if (!--m_refCount) { + m_owner->Destroy(this); + return 0; + } + + return m_refCount; +} + +#endif // VIEWLODLIST_H diff --git a/LEGO1/viewmanager/viewmanager.cpp b/LEGO1/viewmanager/viewmanager.cpp new file mode 100644 index 00000000..9db4ba6f --- /dev/null +++ b/LEGO1/viewmanager/viewmanager.cpp @@ -0,0 +1,528 @@ +#include "viewmanager.h" + +#include "mxdirectx/mxstopwatch.h" +#include "tgl/d3drm/impl.h" +#include "viewlod.h" + +#include + +DECOMP_SIZE_ASSERT(ViewManager, 0x1bc) + +// GLOBAL: LEGO1 0x100dbcd8 +int g_unk0x100dbcd8[18] = {0, 1, 5, 6, 2, 3, 3, 0, 4, 1, 2, 6, 0, 3, 2, 4, 5, 6}; + +// GLOBAL: LEGO1 0x10101050 +float g_unk0x10101050 = 4.0F; + +// GLOBAL: LEGO1 0x10101054 +float g_unk0x10101054 = 0.00097656297; + +// GLOBAL: LEGO1 0x10101058 +int g_unk0x10101058 = 6; + +// GLOBAL: LEGO1 0x1010105c +float g_unk0x1010105c = 0.000125F; + +// GLOBAL: LEGO1 0x10101060 +float g_elapsedSeconds = 0; + +inline void SetAppData(ViewROI* p_roi, DWORD data); +inline undefined4 GetD3DRM(IDirect3DRM2*& d3drm, Tgl::Renderer* pRenderer); +inline undefined4 GetFrame(IDirect3DRMFrame2*& frame, Tgl::Group* scene); + +// FUNCTION: LEGO1 0x100a5eb0 +ViewManager::ViewManager(Tgl::Renderer* pRenderer, Tgl::Group* scene, const OrientableROI* point_of_view) + : scene(scene), flags(c_bit1 | c_bit2 | c_bit3 | c_bit4) +{ + SetPOVSource(point_of_view); + unk0x28 = 0.09; + GetD3DRM(d3drm, pRenderer); + GetFrame(frame, scene); + width = 0.0; + height = 0.0; + view_angle = 0.0; + pov.SetIdentity(); + front = 0.0; + back = 0.0; + + memset(unk0xf0, 0, sizeof(unk0xf0)); + seconds_allowed = 1.0; +} + +// FUNCTION: LEGO1 0x100a60c0 +ViewManager::~ViewManager() +{ + SetPOVSource(NULL); +} + +// STUB: LEGO1 0x100a6150 +// FUNCTION: BETA10 0x10172164 +undefined4 ViewManager::FUN_100a6150(const BoundingBox& p_bounding_box) +{ + return 1; +} + +// FUNCTION: LEGO1 0x100a6410 +void ViewManager::Remove(ViewROI* p_roi) +{ + for (CompoundObject::iterator it = rois.begin(); it != rois.end(); it++) { + if (*it == p_roi) { + rois.erase(it); + + if (p_roi->GetUnknown0xe0() >= 0) { + FUN_100a66a0(p_roi); + } + + const CompoundObject* comp = p_roi->GetComp(); + + if (comp != NULL) { + for (CompoundObject::const_iterator it = comp->begin(); !(it == comp->end()); it++) { + if (((ViewROI*) *it)->GetUnknown0xe0() >= 0) { + FUN_100a66a0((ViewROI*) *it); + } + } + } + + return; + } + } +} + +// FUNCTION: LEGO1 0x100a64d0 +void ViewManager::RemoveAll(ViewROI* p_roi) +{ + if (p_roi == NULL) { + for (CompoundObject::iterator it = rois.begin(); it != rois.end(); it++) { + RemoveAll((ViewROI*) *it); + } + + rois.erase(rois.begin(), rois.end()); + } + else { + if (p_roi->GetUnknown0xe0() >= 0) { + FUN_100a66a0(p_roi); + } + + p_roi->SetUnknown0xe0(-1); + const CompoundObject* comp = p_roi->GetComp(); + + if (comp != NULL) { + for (CompoundObject::const_iterator it = comp->begin(); !(it == comp->end()); it++) { + if ((ViewROI*) *it != NULL) { + RemoveAll((ViewROI*) *it); + } + } + } + } +} + +// FUNCTION: LEGO1 0x100a65b0 +void ViewManager::FUN_100a65b0(ViewROI* p_roi, int p_und) +{ + if (p_roi->GetLODCount() <= p_und) { + p_und = p_roi->GetLODCount() - 1; + } + + int unk0xe0 = p_roi->GetUnknown0xe0(); + + if (unk0xe0 == p_und) { + return; + } + + Tgl::Group* group = p_roi->GetGeometry(); + Tgl::MeshBuilder* meshBuilder; + ViewLOD* lod; + + if (unk0xe0 < 0) { + lod = (ViewLOD*) p_roi->GetLOD(p_und); + + if (lod->GetUnknown0x08() & ViewLOD::c_bit4) { + scene->Add((Tgl::MeshBuilder*) group); + SetAppData(p_roi, (DWORD) p_roi); + } + } + else { + lod = (ViewLOD*) p_roi->GetLOD(unk0xe0); + + if (lod != NULL) { + meshBuilder = lod->GetMeshBuilder(); + + if (meshBuilder != NULL) { + group->Remove(meshBuilder); + } + } + + lod = (ViewLOD*) p_roi->GetLOD(p_und); + } + + if (lod->GetUnknown0x08() & ViewLOD::c_bit4) { + meshBuilder = lod->GetMeshBuilder(); + + if (meshBuilder != NULL) { + group->Add(meshBuilder); + SetAppData(p_roi, (DWORD) p_roi); + p_roi->SetUnknown0xe0(p_und); + return; + } + } + + p_roi->SetUnknown0xe0(-1); +} + +// FUNCTION: LEGO1 0x100a66a0 +void ViewManager::FUN_100a66a0(ViewROI* p_roi) +{ + const ViewLOD* lod = (const ViewLOD*) p_roi->GetLOD(p_roi->GetUnknown0xe0()); + + if (lod != NULL) { + const Tgl::MeshBuilder* meshBuilder = NULL; + Tgl::Group* roiGeometry = p_roi->GetGeometry(); + + meshBuilder = lod->GetMeshBuilder(); + + if (meshBuilder != NULL) { + roiGeometry->Remove(meshBuilder); + } + + scene->Remove(roiGeometry); + } + + p_roi->SetUnknown0xe0(-1); +} + +// FUNCTION: LEGO1 0x100a66f0 +inline void ViewManager::FUN_100a66f0(ViewROI* p_roi, int p_und) +{ + if (!p_roi->GetVisibility() && p_und != -2) { + FUN_100a66f0(p_roi, -2); + } + else { + const CompoundObject* comp = p_roi->GetComp(); + + if (p_und == -1) { + if (p_roi->GetWorldBoundingSphere().Radius() > 0.001F) { + float und = ProjectedSize(p_roi->GetWorldBoundingSphere()); + + if (und < seconds_allowed * g_unk0x1010105c) { + if (p_roi->GetUnknown0xe0() == -2) { + return; + } + + FUN_100a66f0(p_roi, -2); + return; + } + + p_und = Unknown2(und, RealtimeView::GetUserMaxLodPower() * seconds_allowed, p_roi); + } + } + + if (p_und == -2) { + if (p_roi->GetUnknown0xe0() >= 0) { + FUN_100a66a0(p_roi); + p_roi->SetUnknown0xe0(-2); + } + + if (comp != NULL) { + for (CompoundObject::const_iterator it = comp->begin(); !(it == comp->end()); it++) { + FUN_100a66f0((ViewROI*) *it, p_und); + } + } + } + else if (comp == NULL) { + if (p_roi->GetLODs() != NULL && p_roi->GetLODCount() > 0) { + FUN_100a65b0(p_roi, p_und); + return; + } + } + else { + p_roi->SetUnknown0xe0(-1); + + for (CompoundObject::const_iterator it = comp->begin(); !(it == comp->end()); it++) { + FUN_100a66f0((ViewROI*) *it, p_und); + } + } + } +} + +// FUNCTION: LEGO1 0x100a6930 +void ViewManager::Update(float p_previousRenderTime, float) +{ + MxStopWatch stopWatch; + stopWatch.Start(); + + unk0x28 = p_previousRenderTime; + flags |= c_bit1; + + if (flags & c_bit3) { + Unknown(); + } + else if (flags & c_bit2) { + FUN_100a6b90(); + } + + for (CompoundObject::iterator it = rois.begin(); it != rois.end(); it++) { + FUN_100a66f0((ViewROI*) *it, -1); + } + + stopWatch.Stop(); + g_elapsedSeconds = stopWatch.ElapsedSeconds(); +} + +inline int ViewManager::Unknown() +{ + flags &= ~c_bit3; + + if (height == 0.0F || front == 0.0F) { + return -1; + } + else { + float fVar7 = tan(view_angle / 2.0F); + view_area_at_one = view_angle * view_angle * 4.0F; + + float fVar1 = front * fVar7; + float fVar2 = (width / height) * fVar1; + float uVar6 = front; + float fVar3 = back + front; + float fVar4 = fVar3 / front; + float fVar5 = fVar4 * fVar1; + fVar4 = fVar4 * fVar2; + + float* unk0x90 = (float*) this->unk0x90; + + // clang-format off + *unk0x90 = fVar2; unk0x90++; + *unk0x90 = fVar1; unk0x90++; + *unk0x90 = uVar6; unk0x90++; + *unk0x90 = fVar2; unk0x90++; + *unk0x90 = -fVar1; unk0x90++; + *unk0x90 = uVar6; unk0x90++; + *unk0x90 = -fVar2; unk0x90++; + *unk0x90 = -fVar1; unk0x90++; + *unk0x90 = uVar6; unk0x90++; + *unk0x90 = -fVar2; unk0x90++; + *unk0x90 = fVar1; unk0x90++; + *unk0x90 = uVar6; unk0x90++; + *unk0x90 = fVar4; unk0x90++; + *unk0x90 = fVar5; unk0x90++; + *unk0x90 = fVar3; unk0x90++; + *unk0x90 = fVar4; unk0x90++; + *unk0x90 = -fVar5; unk0x90++; + *unk0x90 = fVar3; unk0x90++; + *unk0x90 = -fVar4; unk0x90++; + *unk0x90 = -fVar5; unk0x90++; + *unk0x90 = fVar3; unk0x90++; + *unk0x90 = -fVar4; unk0x90++; + *unk0x90 = fVar5; unk0x90++; + *unk0x90 = fVar3; + // clang-format on + + FUN_100a6b90(); + return 0; + } +} + +inline int ViewManager::Unknown2(float p_und1, float p_und2, ViewROI* p_roi) +{ + int result; + float i; + + if (Unknown3(p_roi) != 0) { + if (p_und1 < g_unk0x10101054) { + return 0; + } + + result = 1; + } + else { + result = 0; + } + + for (i = p_und2; result < g_unk0x10101058 && p_und1 >= i; i *= g_unk0x10101050) { + result++; + } + + return result; +} + +inline int ViewManager::Unknown3(ViewROI* p_roi) +{ + const LODListBase* lods = p_roi->GetLODs(); + + if (lods != NULL && lods->Size() > 0) { + if (((ViewLOD*) p_roi->GetLOD(0))->GetUnknown0x08Test8()) { + return 1; + } + + return 0; + } + + const CompoundObject* comp = p_roi->GetComp(); + + if (comp != NULL) { + for (CompoundObject::const_iterator it = comp->begin(); !(it == comp->end()); it++) { + const LODListBase* lods = ((ViewROI*) *it)->GetLODs(); + + if (lods != NULL && lods->Size() > 0) { + if (((ViewLOD*) ((ViewROI*) *it)->GetLOD(0))->GetUnknown0x08Test8()) { + return 1; + } + + return 0; + } + } + } + + return 0; +} + +// FUNCTION: LEGO1 0x100a6b90 +void ViewManager::FUN_100a6b90() +{ + flags &= ~c_bit2; + + int i, j, k; + + for (i = 0; i < 8; i++) { + for (j = 0; j < 3; j++) { + unk0xf0[i][j] = pov[3][j]; + + for (k = 0; k < 3; k++) { + unk0xf0[i][j] += pov[k][j] * unk0x90[i][k]; + } + } + } + + for (i = 0; i < 6; i++) { + Vector3 a(unk0xf0[g_unk0x100dbcd8[i * 3]]); + Vector3 b(unk0xf0[g_unk0x100dbcd8[i * 3 + 1]]); + Vector3 c(unk0xf0[g_unk0x100dbcd8[i * 3 + 2]]); + Mx3DPointFloat x; + Mx3DPointFloat y; + Vector3 u(unk0x150[i]); + + x = c; + ((Vector3&) x).Sub(&b); // TODO: Fix call + + y = a; + ((Vector3&) y).Sub(&b); // TODO: Fix call + + u.EqualsCross(&x, &y); + u.Unitize(); + + unk0x150[i][3] = -u.Dot(&u, &a); + } + + flags |= c_bit4; +} + +// FUNCTION: LEGO1 0x100a6d50 +void ViewManager::SetResolution(int width, int height) +{ + flags |= c_bit3; + this->width = width; + this->height = height; +} + +// FUNCTION: LEGO1 0x100a6d70 +void ViewManager::SetFrustrum(float fov, float front, float back) +{ + this->front = front; + this->back = back; + flags |= c_bit3; + view_angle = fov * 0.017453292519944444; +} + +// FUNCTION: LEGO1 0x100a6da0 +void ViewManager::SetPOVSource(const OrientableROI* point_of_view) +{ + if (point_of_view != NULL) { + pov = point_of_view->GetLocal2World(); + flags |= c_bit2; + } +} + +// FUNCTION: LEGO1 0x100a6dc0 +float ViewManager::ProjectedSize(const BoundingSphere& p_bounding_sphere) +{ + // The algorithm projects the radius of bounding sphere onto the perpendicular + // plane one unit in front of the camera. That value is simply the ratio of the + // radius to the distance from the camera to the sphere center. The projected size + // is then the ratio of the area of that projected circle to the view surface area + // at Z == 1.0. + // + float sphere_projected_area = 3.14159265359 * (p_bounding_sphere.Radius() * p_bounding_sphere.Radius()); + float square_dist_to_sphere = DISTSQRD3(p_bounding_sphere.Center(), pov[3]); + return sphere_projected_area / view_area_at_one / square_dist_to_sphere; +} + +// FUNCTION: LEGO1 0x100a6e00 +ViewROI* ViewManager::Pick(Tgl::View* p_view, unsigned long x, unsigned long y) +{ + LPDIRECT3DRMPICKEDARRAY picked = NULL; + ViewROI* result = NULL; + TglImpl::ViewImpl* view = (TglImpl::ViewImpl*) p_view; + IDirect3DRMViewport* d3drm = view->ImplementationData(); + + if (d3drm->Pick(x, y, &picked) != D3DRM_OK) { + return NULL; + } + + if (picked != NULL) { + if (picked->GetSize() != 0) { + LPDIRECT3DRMVISUAL visual; + LPDIRECT3DRMFRAMEARRAY frameArray; + D3DRMPICKDESC desc; + + if (picked->GetPick(0, &visual, &frameArray, &desc) == D3DRM_OK) { + if (frameArray != NULL) { + int size = frameArray->GetSize(); + + if (size > 1) { + for (int i = 1; i < size; i++) { + LPDIRECT3DRMFRAME frame = NULL; + + if (frameArray->GetElement(i, &frame) == D3DRM_OK) { + result = (ViewROI*) frame->GetAppData(); + + if (result != NULL) { + frame->Release(); + break; + } + + frame->Release(); + } + } + } + + visual->Release(); + frameArray->Release(); + } + } + } + + picked->Release(); + } + + return result; +} + +inline void SetAppData(ViewROI* p_roi, DWORD data) +{ + IDirect3DRMFrame2* frame = NULL; + + if (GetFrame(frame, p_roi->GetGeometry()) == 0) { + frame->SetAppData(data); + } +} + +inline undefined4 GetD3DRM(IDirect3DRM2*& d3drm, Tgl::Renderer* pRenderer) +{ + d3drm = ((TglImpl::RendererImpl*) pRenderer)->ImplementationData(); + return 0; +} + +inline undefined4 GetFrame(IDirect3DRMFrame2*& frame, Tgl::Group* scene) +{ + frame = ((TglImpl::GroupImpl*) scene)->ImplementationData(); + return 0; +} diff --git a/LEGO1/viewmanager/viewmanager.h b/LEGO1/viewmanager/viewmanager.h new file mode 100644 index 00000000..f2fdcdb4 --- /dev/null +++ b/LEGO1/viewmanager/viewmanager.h @@ -0,0 +1,82 @@ +#ifndef VIEWMANAGER_H +#define VIEWMANAGER_H + +#include "decomp.h" +#include "realtime/realtimeview.h" +#include "viewroi.h" + +#include + +// VTABLE: LEGO1 0x100dbd88 +// SIZE 0x1bc +class ViewManager { +public: + enum Flags { + c_bit1 = 0x01, + c_bit2 = 0x02, + c_bit3 = 0x04, + c_bit4 = 0x08 + }; + + ViewManager(Tgl::Renderer* pRenderer, Tgl::Group* scene, const OrientableROI* point_of_view); + virtual ~ViewManager(); + + void Remove(ViewROI* p_roi); + void RemoveAll(ViewROI* p_roi); + undefined4 FUN_100a6150(const BoundingBox& p_bounding_box); + void FUN_100a65b0(ViewROI* p_roi, int p_und); + void FUN_100a66a0(ViewROI* p_roi); + void SetPOVSource(const OrientableROI* point_of_view); + float ProjectedSize(const BoundingSphere& p_bounding_sphere); + ViewROI* Pick(Tgl::View* p_view, unsigned long x, unsigned long y); + void SetResolution(int width, int height); + void SetFrustrum(float fov, float front, float back); + inline void FUN_100a66f0(ViewROI* p_roi, int p_und); + void Update(float p_previousRenderTime, float); + inline int Unknown(); + void FUN_100a6b90(); + + inline static int Unknown2(float p_und1, float p_und2, ViewROI* p_roi); + inline static int Unknown3(ViewROI* p_roi); + + inline const CompoundObject& GetROIs() { return rois; } + inline void Add(ViewROI* p_roi) { rois.push_back(p_roi); } + + // SYNTHETIC: LEGO1 0x100a6000 + // ViewManager::`scalar deleting destructor' + +private: + Tgl::Group* scene; // 0x04 + CompoundObject rois; // 0x08 + RealtimeView rt_view; // 0x14 + ROIList visible_rois; // 0x18 + float unk0x28; // 0x28 + float view_area_at_one; // 0x2c + unsigned int flags; // 0x30 + float width; // 0x34 + float height; // 0x38 + float view_angle; // 0x3c + MxMatrix pov; // 0x40 + float front; // 0x88 + float back; // 0x8c + float unk0x90[8][3]; // 0x90 + float unk0xf0[8][3]; // 0xf0 + float unk0x150[6][4]; // 0x150 + IDirect3DRM2* d3drm; // 0x1b0 + IDirect3DRMFrame2* frame; // 0x1b4 + float seconds_allowed; // 0x1b8 +}; + +// TEMPLATE: LEGO1 0x10022030 +// list >::insert + +// TEMPLATE: LEGO1 0x100a6020 +// List::~List + +// TEMPLATE: LEGO1 0x100a6070 +// Vector::~Vector + +// TEMPLATE: LEGO1 0x100a6f80 +// vector >::~vector > + +#endif // VIEWMANAGER_H diff --git a/LEGO1/viewmanager/viewroi.cpp b/LEGO1/viewmanager/viewroi.cpp new file mode 100644 index 00000000..8d8cbb6b --- /dev/null +++ b/LEGO1/viewmanager/viewroi.cpp @@ -0,0 +1,86 @@ +#include "viewroi.h" + +#include "decomp.h" + +#include + +DECOMP_SIZE_ASSERT(ViewROI, 0xe4) + +// GLOBAL: LEGO1 0x101013d8 +undefined g_unk101013d8 = 0; + +// FUNCTION: LEGO1 0x100a9eb0 +float ViewROI::IntrinsicImportance() const +{ + return .5; +} // for now + +// FUNCTION: LEGO1 0x100a9ec0 +Tgl::Group* ViewROI::GetGeometry() +{ + return geometry; +} + +// FUNCTION: LEGO1 0x100a9ed0 +const Tgl::Group* ViewROI::GetGeometry() const +{ + return geometry; +} + +// FUNCTION: LEGO1 0x100a9ee0 +void ViewROI::UpdateWorldData(const Matrix4& parent2world) +{ + OrientableROI::UpdateWorldData(parent2world); + + if (geometry) { + Tgl::FloatMatrix4 matrix; + Matrix4 in(matrix); + SETMAT4(in, m_local2world); + Tgl::Result result = geometry->SetTransformation(matrix); + // assert(Tgl::Succeeded(result)); + } +} + +// FUNCTION: LEGO1 0x100a9fc0 +void ViewROI::VTable0x24(const Matrix4& p_transform) +{ + OrientableROI::VTable0x24(p_transform); + if (geometry) { + Tgl::FloatMatrix4 matrix; + Matrix4 in(matrix); + SETMAT4(in, m_local2world); + geometry->SetTransformation(matrix); + } +} + +// FUNCTION: LEGO1 0x100aa0a0 +void ViewROI::SetLocalTransform(const Matrix4& p_transform) +{ + OrientableROI::SetLocalTransform(p_transform); + if (geometry) { + Tgl::FloatMatrix4 matrix; + Matrix4 in(matrix); + SETMAT4(in, m_local2world); + geometry->SetTransformation(matrix); + } +} + +// FUNCTION: LEGO1 0x100aa180 +void ViewROI::VTable0x1c() +{ + OrientableROI::VTable0x1c(); + if (geometry) { + Tgl::FloatMatrix4 matrix; + Matrix4 in(matrix); + SETMAT4(in, m_local2world); + geometry->SetTransformation(matrix); + } +} + +// FUNCTION: LEGO1 0x100aa500 +undefined ViewROI::SetUnk101013d8(undefined p_flag) +{ + undefined oldFlag = g_unk101013d8; + g_unk101013d8 = p_flag; + return oldFlag; +} diff --git a/LEGO1/viewmanager/viewroi.h b/LEGO1/viewmanager/viewroi.h new file mode 100644 index 00000000..5a521824 --- /dev/null +++ b/LEGO1/viewmanager/viewroi.h @@ -0,0 +1,74 @@ +#ifndef VIEWROI_H +#define VIEWROI_H + +#include "decomp.h" +#include "realtime/orientableroi.h" +#include "tgl/tgl.h" +#include "viewlodlist.h" + +/* + ViewROI objects represent view objects, collections of view objects, + etc. Basically, anything which can be placed in a scene and manipilated + by the view manager is a ViewROI. +*/ + +// VTABLE: LEGO1 0x100dbe70 +// SIZE 0xe4 +class ViewROI : public OrientableROI { +public: + inline ViewROI(Tgl::Renderer* pRenderer, ViewLODList* lodList) + { + SetLODList(lodList); + geometry = pRenderer->CreateGroup(); + m_unk0xe0 = -1; + } + + // FUNCTION: LEGO1 0x100a9e20 + inline ~ViewROI() override + { + // SetLODList() will decrease refCount of LODList + SetLODList(0); + delete geometry; + } + + inline void SetLODList(ViewLODList* lodList) + { + // ??? inherently type unsafe - kind of... because, now, ROI + // does not expose SetLODs() ... + // solution: create pure virtual LODListBase* ROI::GetLODList() + // and let derived ROI classes hold the LODList + + if (lods) { + reinterpret_cast(lods)->Release(); + } + + lods = lodList; + + if (lods) { + reinterpret_cast(lods)->AddRef(); + } + } + + float IntrinsicImportance() const override; // vtable+0x04 + void VTable0x1c() override; // vtable+0x1c + void SetLocalTransform(const Matrix4& p_transform) override; // vtable+0x20 + void VTable0x24(const Matrix4& p_transform) override; // vtable+0x24 + virtual Tgl::Group* GetGeometry(); // vtable+0x30 + virtual const Tgl::Group* GetGeometry() const; // vtable+0x34 + + inline int GetUnknown0xe0() { return m_unk0xe0; } + inline void SetUnknown0xe0(int p_unk0xe0) { m_unk0xe0 = p_unk0xe0; } + + static undefined SetUnk101013d8(undefined p_flag); + +protected: + void UpdateWorldData(const Matrix4& parent2world) override; // vtable+0x28 + + Tgl::Group* geometry; // 0xdc + int m_unk0xe0; // 0xe0 +}; + +// SYNTHETIC: LEGO1 0x100aa250 +// ViewROI::`scalar deleting destructor' + +#endif // VIEWROI_H diff --git a/README.md b/README.md new file mode 100644 index 00000000..0f7edf0b --- /dev/null +++ b/README.md @@ -0,0 +1,63 @@ +# LEGO Island Decompilation + +[Development Vlog](https://www.youtube.com/playlist?list=PLbpl-gZkNl2COf_bB6cfgTapD5WduAfPz) | [Contributing](/CONTRIBUTING.md) | [Matrix](https://matrix.to/#/#isledecomp:matrix.org) | [Forums](https://forum.mattkc.com/viewforum.php?f=1) | [Patreon](https://www.patreon.com/mattkc) + +This is a **work-in-progress** decompilation of LEGO Island (Version 1.1, English). It aims to be as accurate as possible, matching the recompiled instructions to the original machine code as much as possible. The goal is to provide a workable codebase that can be modified, improved, and ported to other platforms later on. + +## Status + + + +Currently, `ISLE.EXE` is completely decompiled and behaves identically to the original. A handful of stubborn instructions are not yet matching; however, we anticipate they will as more of the overall codebase is implemented. + +`LEGO1.DLL` is still incomplete and cannot be used for gameplay at this time. If you would like to use this, it is instead recommended to pair the recompiled `ISLE.EXE` with the `LEGO1.DLL` from the original game. + +## Building + +This project uses the [CMake](https://cmake.org/) build system, which allows for a high degree of versatility regarding compilers and development environments. For the most accurate results, it is recommended to use Microsoft Visual C++ 4.20 (the same compiler used to build the original game). Since we're trying to match the output of this code to the original executables as closely as possible, all contributions will be graded with the output of this compiler. + + +These instructions will outline how to compile this repository into accurate instruction-matching binaries with Visual C++ 4.2. If you wish, you can try using other compilers, but this is at your own risk and won't be covered in this guide. + +#### Prerequisites + +You will need the following software installed: + +- Microsoft Visual C++ 4.2. This can be found on many abandonware sites, but the installer can be a little iffy on modern versions of Windows. For convenience, a [portable version](https://github.com/itsmattkc/msvc420) is available that can be downloaded and used quickly instead. +- [CMake](https://cmake.org/). A copy is often included with the "Desktop development with C++" workload in newer versions of Visual Studio; however, it can also be installed as a standalone app. + +#### Compiling + +1. Open a Command Prompt (`cmd`). +1. From Visual C++ 4.2, run `BIN/VCVARS32.BAT x86` to populate the path and other environment variables for compiling with MSVC. +1. Make a folder for compiled objects to go, such as a `build` folder inside the source repository (the folder you cloned/downloaded to). +1. In your Command Prompt, `cd` to the build folder. +1. Configure the project with CMake by running: +``` +cmake -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=RelWithDebInfo +``` + - **Visual C++ 4.2 has issues with paths containing spaces**. If you get configure or build errors, make sure neither CMake, the repository, nor Visual C++ 4.2 is in a path that contains spaces. + - Replace `` with the source repository. This can be `..` if your build folder is inside the source repository. + - `RelWithDebInfo` is recommended because it will produce debug symbols useful for further decompilation work. However, you can change this to `Release` if you don't need them. `Debug` builds are not recommended because they are unlikely to be compatible with the retail `LEGO1.DLL`, which is currently the only way to use this decompilation for gameplay. + - `NMake Makefiles` is most recommended because it will be immediately compatible with Visual C++ 4.2. For faster builds, you can use `Ninja` (if you have it installed), however due to limitations in Visual C++ 4.2, you can only build `Release` builds this way (debug symbols cannot be generated with `Ninja`). +1. Build the project by running `nmake` or `cmake --build ` +1. When this is done, there should a recompiled `ISLE.EXE` and `LEGO1.DLL` in the build folder. + +If you have a CMake-compatible IDE, it should be pretty straightforward to use this repository, as long as you can use `VCVARS32.BAT` and set the generator to `NMake Makefiles`. + +## Usage + +Simply place the compiled `ISLE.EXE` into LEGO Island's install folder (usually `C:\Program Files\LEGO Island` or `C:\Program Files (x86)\LEGO Island`). Unless you're a developer, disregard the compiled `LEGO1.DLL` for now as it is too incomplete to be usable. Alternatively, LEGO Island can run from any directory as long as `ISLE.EXE` and `LEGO1.DLL` are in the same directory, and the registry keys (usually `HKEY_LOCAL_MACHINE\Software\Mindscape\LEGO Island` or `HKEY_LOCAL_MACHINE\Software\Wow6432Node\Mindscape\LEGO Island`) point to the correct location for the asset files. + +## Contributing + +If you're interested in helping or contributing to this project, check out the [CONTRIBUTING](/CONTRIBUTING.md) page. + +## Additional Information + +### Which version of LEGO Island do I have? + +Right click on `LEGO1.DLL`, select `Properties`, and switch to the `Details` tab. Under `Version` you should either see `1.0.0.0` (1.0) or `1.1.0.0` (1.1). Additionally, you can look at the game disc files; 1.0's files will all say August 8, 1997, and 1.1's files will all say September 8, 1997. Version 1.1 is by far the most common, especially if you're not using the English or Japanese versions, so that's most likely the version you have. Please note that some localized versions of LEGO Island were recompiled with small changes despite maintaining a version number parallel with other versions; this decompilation is specifically targeting the English release of version 1.1 of LEGO Island. You can verify you have the correct version using the checksums below: + +* ISLE.EXE `md5: f6da12249e03eed1c74810cd23beb9f5` +* LEGO1.DLL `md5: 4e2f6d969ea2ef8655ba3fc221a0c8fe` diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..6deafc26 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 120 diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 00000000..0c6b4112 --- /dev/null +++ b/tools/README.md @@ -0,0 +1,200 @@ +# LEGO Island Decompilation Tools + +Accuracy to the game's original code is the main goal of this project. To facilitate the decompilation effort and maintain overall quality, we have devised a set of annotations, to be embedded in the source code, which allow us to automatically verify the accuracy of re-compiled functions' assembly, virtual tables, variable offsets and more. + +In order for contributions to be accepted, the annotations must be used in accordance to the rules outlined here. Proper use is enforced by [GitHub Actions](/.github/workflows) which run the Python tools found in this folder. It is recommended to integrate these tools into your local development workflow as well. + +# Overview + +We are continually working on extending the capabilities of our "decompilation language" and the toolset around it. Some of the following annotations have not made it into formal verification and thus are not technically enforced on the source code level yet (marked as **WIP**). Nevertheless, it is recommended to use them since it is highly likely they will eventually be fully integrated. + +## Functions + +All non-inlined functions in the code base with the exception of [3rd party code](/3rdparty) must be annotated with one of the following markers, which include the module name and address of the function as found in the original binaries. This information is then used to compare the recompiled assembly with the original assembly, resulting in an accuracy score. Functions in a given compilation unit must be ordered by their address in ascending order. + +The annotations can be attached to the function implementation, which is the most common case, or use the "comment" syntax (see examples below) for functions that cannot be referred to directly (such as templated, synthetic or non-inlined inline functions). The latter should only ever appear in `.h` files. + +### `FUNCTION` + +Functions with a reasonably complete implementation which are not templated or synthetic (see below) should be annotated with `FUNCTION`. + +``` +// FUNCTION: LEGO1 0x100b12c0 +MxCore* MxObjectFactory::Create(const char* p_name) +{ + // implementation +} + +// FUNCTION: LEGO1 0x100140d0 +// MxCore::IsA +``` + +### `STUB` + +Functions with no or a very incomplete implementation should be annotated with `STUB`. These will not be compared to the original assembly. + +``` +// STUB: LEGO1 0x10011d50 +LegoCameraController::LegoCameraController() +{ + // TODO +} +``` + +### `TEMPLATE` + +Templated functions should be annotated with `TEMPLATE`. Since the goal is to eventually have a full accounting of all the functions present in the binaries, please make an effort to find and annotate every function of a templated class. + +``` +// TEMPLATE: LEGO1 0x100c0ee0 +// list >::_Buynode + +// TEMPLATE: LEGO1 0x100c0fc0 +// MxStreamListMxDSSubscriber::~MxStreamListMxDSSubscriber + +// TEMPLATE: LEGO1 0x100c1010 +// MxStreamListMxDSAction::~MxStreamListMxDSAction +``` + +### `SYNTHETIC` + +Synthetic functions should be annotated with `SYNTHETIC`. A synthetic function is generated by the compiler; most common is the "scalar deleting destructor" found in virtual tables. Other cases include default destructors and assignment operators. Note: `SYNTHETIC` takes precedence over `TEMPLATE`. + +``` +// SYNTHETIC: LEGO1 0x10003210 +// Helicopter::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c4f50 +// MxCollection::`scalar deleting destructor' + +// SYNTHETIC: LEGO1 0x100c4fc0 +// MxList::`scalar deleting destructor' +``` + +### `LIBRARY` + +Functions located in 3rd party libraries should be annotated with `LIBRARY`. Since the goal is to eventually have a full accounting of all the functions present in the binaries, please make an effort to find and annotate every function of every statically linked library, including the MSVC standard libraries. + +``` +// LIBRARY: ISLE 0x4061b0 +// _MemPoolInit@4 + +// LIBRARY: ISLE 0x406520 +// _MemPoolSetPageSize@8 + +// LIBRARY: ISLE 0x406630 +// _MemPoolSetBlockSizeFS@8 +``` + +## Virtual tables + +Classes with a virtual table should be annotated using the `VTABLE` marker, which includes the module name and address of the virtual table. Additionally, virtual function declarations should be annotated with a comment indicating their relative offset. Please use the following example as a reference. + +``` +// VTABLE: LEGO1 0x100dc900 +class MxEventManager : public MxMediaManager { +public: + MxEventManager(); + virtual ~MxEventManager() override; + + virtual void Destroy() override; // vtable+0x18 + virtual MxResult Create(MxU32 p_frequencyMS, MxBool p_createThread); // vtable+0x28 +``` + +## Class size (**WIP**) + +Classes should be annotated using the `SIZE` marker to indicate their size. If you are unsure about the class size in the original binary, please use the currently available information (known member variables) and detail the circumstances in an extra comment if necessary. + +``` +// SIZE 0x1c +class MxCriticalSection { +public: + MxCriticalSection(); + ~MxCriticalSection(); + static void SetDoMutex(); +``` + +## Member variables (**WIP**) + +Member variables should be annotated with their relative offsets. + +``` +class MxDSObject : public MxCore { +private: + MxU32 m_sizeOnDisk; // 0x8 + MxU16 m_type; // 0xc + char* m_sourceName; // 0x10 + undefined4 m_unk0x14; // 0x14 +``` + +## Global variables + +Global variables should be annotated using the `GLOBAL` marker, which includes the module name and address of the variable. + +``` +// GLOBAL: LEGO1 0x100f456c +MxAtomId* g_jukeboxScript = NULL; + +// GLOBAL: LEGO1 0x100f4570 +MxAtomId* g_pz5Script = NULL; + +// GLOBAL: LEGO1 0x100f4574 +MxAtomId* g_introScript = NULL; +``` + +## Strings + +String values should be annotated using the `STRING` marker, which includes the module name and address of the string. + +``` +inline virtual const char* ClassName() const override // vtable+0x0c +{ + // STRING: LEGO1 0x100f03fc + return "Act2PoliceStation"; +} +``` + +# Tooling + +Use `pip` to install the required packages to be able to use the Python tools found in this folder: + +``` +pip install -r tools/requirements.txt +``` + +* [`decomplint`](/tools/decomplint): Checks the decompilation annotations (see above) +* [`isledecomp`](/tools/isledecomp): A library that implements a parser to identify the decompilation annotations (see above) +* [`ncc`](/tools/ncc): Checks naming conventions based on a set of rules +* [`reccmp`](/tools/reccmp): Compares an original binary with a recompiled binary, provided a PDB file +* [`roadmap`](/tools/roadmap): Compares symbol locations in an original binary with the same symbol locations of a recompiled binary +* [`verexp`](/tools/verexp): Verifies exports by comparing the exports of the original DLL and the recompiled DLL +* [`vtable`](/tools/vtable): Asserts virtual table correctness by comparing a recompiled binary with the original +* [`datacmp.py`](/tools/datacmp.py): Compares global data found in the original with the recompiled version +* [`patch_c2.py`](/tools/patch_c2.py): Patches `C2.EXE` (part of MSVC 4.20) to get rid of a bugged warning + +## Testing + +`isledecomp` comes with a suite of tests. Install `pylint` and run it, passing in the directory: + +``` +pip install pytest +pytest tools/isledecomp/tests/ +``` + +## Development + +In order to keep the code clean and consistent, we use `pylint` and `black`: + +`pip install black pylint` + +### Run pylint (ignores build and virtualenv) + +`pylint tools/ --ignore=build,bin,lib` + +### Check code formatting without rewriting files + +`black --check tools/` + +### Apply code formatting + +`black tools/` diff --git a/tools/datacmp.py b/tools/datacmp.py new file mode 100644 index 00000000..7073fc09 --- /dev/null +++ b/tools/datacmp.py @@ -0,0 +1,361 @@ +# (New) Data comparison. + +import os +import argparse +import logging +from enum import Enum +from typing import Iterable, List, NamedTuple, Optional, Tuple +from struct import unpack +from isledecomp.compare import Compare as IsleCompare +from isledecomp.compare.db import MatchInfo +from isledecomp.cvdump import Cvdump +from isledecomp.cvdump.types import ( + CvdumpKeyError, + CvdumpIntegrityError, +) +from isledecomp.bin import Bin as IsleBin +import colorama + +colorama.just_fix_windows_console() + + +# Ignore all compare-db messages. +logging.getLogger("isledecomp.compare").addHandler(logging.NullHandler()) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Comparing data values.") + parser.add_argument( + "original", metavar="original-binary", help="The original binary" + ) + parser.add_argument( + "recompiled", metavar="recompiled-binary", help="The recompiled binary" + ) + parser.add_argument( + "pdb", metavar="recompiled-pdb", help="The PDB of the recompiled binary" + ) + parser.add_argument( + "decomp_dir", metavar="decomp-dir", help="The decompiled source tree" + ) + parser.add_argument( + "-v", + "--verbose", + action=argparse.BooleanOptionalAction, + default=False, + help="", + ) + parser.add_argument( + "--no-color", "-n", action="store_true", help="Do not color the output" + ) + parser.add_argument( + "--all", + "-a", + dest="show_all", + action="store_true", + help="Only show variables with a problem", + ) + parser.add_argument( + "--print-rec-addr", + action="store_true", + help="Print addresses of recompiled functions too", + ) + + (args, _) = parser.parse_known_args() + + if not os.path.isfile(args.original): + parser.error(f"Original binary {args.original} does not exist") + + if not os.path.isfile(args.recompiled): + parser.error(f"Recompiled binary {args.recompiled} does not exist") + + if not os.path.isfile(args.pdb): + parser.error(f"Symbols PDB {args.pdb} does not exist") + + if not os.path.isdir(args.decomp_dir): + parser.error(f"Source directory {args.decomp_dir} does not exist") + + return args + + +class CompareResult(Enum): + MATCH = 1 + DIFF = 2 + ERROR = 3 + WARN = 4 + + +class ComparedOffset(NamedTuple): + offset: int + # name is None for scalar types + name: Optional[str] + match: bool + values: Tuple[str, str] + + +class ComparisonItem(NamedTuple): + """Each variable that was compared""" + + orig_addr: int + recomp_addr: int + name: str + + # The list of items that were compared. + # For a complex type, these are the members. + # For a scalar type, this is a list of size one. + # If we could not retrieve type information, this is + # a list of size one but without any specific type. + compared: List[ComparedOffset] + + # If present, the error message from the types parser. + error: Optional[str] = None + + # If true, there is no type specified for this variable. (i.e. non-public) + # In this case, we can only compare the raw bytes. + # This is different from the situation where a type id _is_ given, but + # we could not retrieve it for some reason. (This is an error.) + raw_only: bool = False + + @property + def result(self) -> CompareResult: + if self.error is not None: + return CompareResult.ERROR + + if all(c.match for c in self.compared): + return CompareResult.MATCH + + # Prefer WARN for a diff without complete type information. + return CompareResult.WARN if self.raw_only else CompareResult.DIFF + + +def create_comparison_item( + var: MatchInfo, + compared: Optional[List[ComparedOffset]] = None, + error: Optional[str] = None, + raw_only: bool = False, +) -> ComparisonItem: + """Helper to create the ComparisonItem from the fields in MatchInfo.""" + if compared is None: + compared = [] + + return ComparisonItem( + orig_addr=var.orig_addr, + recomp_addr=var.recomp_addr, + name=var.name, + compared=compared, + error=error, + raw_only=raw_only, + ) + + +def do_the_comparison(args: argparse.Namespace) -> Iterable[ComparisonItem]: + """Run through each variable in our compare DB, then do the comparison + according to the variable's type. Emit the result.""" + with IsleBin(args.original, find_str=True) as origfile, IsleBin( + args.recompiled + ) as recompfile: + isle_compare = IsleCompare(origfile, recompfile, args.pdb, args.decomp_dir) + + # TODO: We don't currently retain the type information of each variable + # in our compare DB. To get those, we build this mini-lookup table that + # maps recomp addresses to their type. + # We still need to build the full compare DB though, because we may + # need the matched symbols to compare pointers (e.g. on strings) + mini_cvdump = Cvdump(args.pdb).globals().types().run() + + recomp_type_reference = { + recompfile.get_abs_addr(g.section, g.offset): g.type + for g in mini_cvdump.globals + if recompfile.is_valid_section(g.section) + } + + for var in isle_compare.get_variables(): + type_name = recomp_type_reference.get(var.recomp_addr) + + # Start by assuming we can only compare the raw bytes + data_size = var.size + is_type_aware = type_name is not None + + if is_type_aware: + try: + # If we are type-aware, we can get the precise + # data size for the variable. + data_type = mini_cvdump.types.get(type_name) + data_size = data_type.size + except (CvdumpKeyError, CvdumpIntegrityError) as ex: + yield create_comparison_item(var, error=repr(ex)) + continue + + orig_raw = origfile.read(var.orig_addr, data_size) + recomp_raw = recompfile.read(var.recomp_addr, data_size) + + # If either read exceeded the raw data size for the section, + # assume the entire variable is uninitialized. + # TODO: This is not correct, strictly speaking. However, + # it is probably impossible for a variable to exceed + # the virtual size of the section, so all that is left is + # the uninitialized data. + # If the variable falls at the end of the section like this, + # it is highly likely to be uninitialized. + if orig_raw is not None and len(orig_raw) < data_size: + orig_raw = None + + if recomp_raw is not None and len(recomp_raw) < data_size: + recomp_raw = None + + # If both variables are uninitialized, we consider them equal. + # Otherwise, this is a diff but there is nothing to compare. + if orig_raw is None or recomp_raw is None: + match = orig_raw is None and recomp_raw is None + orig_value = "(uninitialized)" if orig_raw is None else "(initialized)" + recomp_value = ( + "(uninitialized)" if recomp_raw is None else "(initialized)" + ) + yield create_comparison_item( + var, + compared=[ + ComparedOffset( + offset=0, + name=None, + match=match, + values=(orig_value, recomp_value), + ) + ], + ) + continue + + if not is_type_aware: + # If there is no specific type information available + # (i.e. if this is a static or non-public variable) + # then we can only compare the raw bytes. + yield create_comparison_item( + var, + compared=[ + ComparedOffset( + offset=0, + name="(raw)", + match=orig_raw == recomp_raw, + values=(orig_raw, recomp_raw), + ) + ], + raw_only=True, + ) + continue + + # If we are here, we can do the type-aware comparison. + compared = [] + compare_items = mini_cvdump.types.get_scalars_gapless(type_name) + format_str = mini_cvdump.types.get_format_string(type_name) + + orig_data = unpack(format_str, orig_raw) + recomp_data = unpack(format_str, recomp_raw) + + def pointer_display(addr: int, is_orig: bool) -> str: + """Helper to streamline pointer textual display.""" + if addr == 0: + return "nullptr" + + ptr_match = ( + isle_compare.get_by_orig(addr) + if is_orig + else isle_compare.get_by_recomp(addr) + ) + + if ptr_match is not None: + return f"Pointer to {ptr_match.match_name()}" + + # This variable did not match if we do not have + # the pointer target in our DB. + return f"Unknown pointer 0x{addr:x}" + + # Could zip here + for i, member in enumerate(compare_items): + if member.is_pointer: + match = isle_compare.is_pointer_match(orig_data[i], recomp_data[i]) + + value_a = pointer_display(orig_data[i], True) + value_b = pointer_display(recomp_data[i], False) + + values = (value_a, value_b) + else: + match = orig_data[i] == recomp_data[i] + values = (orig_data[i], recomp_data[i]) + + compared.append( + ComparedOffset( + offset=member.offset, + name=member.name, + match=match, + values=values, + ) + ) + + yield create_comparison_item(var, compared=compared) + + +def value_get(value: Optional[str], default: str): + return value if value is not None else default + + +def main(): + args = parse_args() + + def display_match(result: CompareResult) -> str: + """Helper to return color string or not, depending on user preference""" + if args.no_color: + return result.name + + match_color = ( + colorama.Fore.GREEN + if result == CompareResult.MATCH + else ( + colorama.Fore.YELLOW + if result == CompareResult.WARN + else colorama.Fore.RED + ) + ) + return f"{match_color}{result.name}{colorama.Style.RESET_ALL}" + + var_count = 0 + problems = 0 + + for item in do_the_comparison(args): + var_count += 1 + if item.result in (CompareResult.DIFF, CompareResult.ERROR): + problems += 1 + + if not args.show_all and item.result == CompareResult.MATCH: + continue + + address_display = ( + f"0x{item.orig_addr:x} / 0x{item.recomp_addr:x}" + if args.print_rec_addr + else f"0x{item.orig_addr:x}" + ) + + print(f"{item.name[:80]} ({address_display}) ... {display_match(item.result)} ") + if item.error is not None: + print(f" {item.error}") + + for c in item.compared: + if not args.verbose and c.match: + continue + + (value_a, value_b) = c.values + if c.match: + print(f" {c.offset:5} {value_get(c.name, '(value)'):30} {value_a}") + else: + print( + f" {c.offset:5} {value_get(c.name, '(value)'):30} {value_a} : {value_b}" + ) + + if args.verbose: + print() + + print( + f"{os.path.basename(args.original)} - Variables: {var_count}. Issues: {problems}" + ) + return 0 if problems == 0 else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/decomplint/decomplint.py b/tools/decomplint/decomplint.py new file mode 100644 index 00000000..4ff28168 --- /dev/null +++ b/tools/decomplint/decomplint.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 + +import os +import sys +import argparse +import colorama +from isledecomp.dir import walk_source_dir, is_file_cpp +from isledecomp.parser import DecompLinter + +colorama.just_fix_windows_console() + + +def display_errors(alerts, filename): + sorted_alerts = sorted(alerts, key=lambda a: a.line_number) + + for alert in sorted_alerts: + error_type = ( + f"{colorama.Fore.RED}error: " + if alert.is_error() + else f"{colorama.Fore.YELLOW}warning: " + ) + components = [ + colorama.Fore.LIGHTWHITE_EX, + filename, + ":", + str(alert.line_number), + " : ", + error_type, + colorama.Fore.LIGHTWHITE_EX, + alert.code.name.lower(), + ] + print("".join(components)) + + if alert.line is not None: + print(f"{colorama.Fore.WHITE} {alert.line}") + + +def parse_args() -> argparse.Namespace: + p = argparse.ArgumentParser( + description="Syntax checking and linting for decomp annotation markers." + ) + p.add_argument("target", help="The file or directory to check.") + p.add_argument( + "--module", + required=False, + type=str, + help="If present, run targeted checks for markers from the given module.", + ) + p.add_argument( + "--warnfail", + action=argparse.BooleanOptionalAction, + default=False, + help="Fail if syntax warnings are found.", + ) + + (args, _) = p.parse_known_args() + return args + + +def process_files(files, module=None): + warning_count = 0 + error_count = 0 + + linter = DecompLinter() + for filename in files: + success = linter.check_file(filename, module) + + warnings = [a for a in linter.alerts if a.is_warning()] + errors = [a for a in linter.alerts if a.is_error()] + + error_count += len(errors) + warning_count += len(warnings) + + if not success: + display_errors(linter.alerts, filename) + print() + + return (warning_count, error_count) + + +def main(): + args = parse_args() + + files_to_check = [] + if os.path.isdir(args.target): + files_to_check = list(walk_source_dir(args.target)) + elif os.path.isfile(args.target) and is_file_cpp(args.target): + files_to_check = [args.target] + else: + sys.exit("Invalid target") + + (warning_count, error_count) = process_files(files_to_check, module=args.module) + + print(colorama.Style.RESET_ALL, end="") + + would_fail = error_count > 0 or (warning_count > 0 and args.warnfail) + if would_fail: + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/isledecomp/.gitignore b/tools/isledecomp/.gitignore new file mode 100644 index 00000000..a7c50887 --- /dev/null +++ b/tools/isledecomp/.gitignore @@ -0,0 +1,2 @@ +isledecomp.egg-info/ +build \ No newline at end of file diff --git a/tools/isledecomp/isledecomp/__init__.py b/tools/isledecomp/isledecomp/__init__.py new file mode 100644 index 00000000..59c55869 --- /dev/null +++ b/tools/isledecomp/isledecomp/__init__.py @@ -0,0 +1,4 @@ +from .bin import * +from .dir import * +from .parser import * +from .utils import * diff --git a/tools/isledecomp/isledecomp/bin.py b/tools/isledecomp/isledecomp/bin.py new file mode 100644 index 00000000..05ecfa92 --- /dev/null +++ b/tools/isledecomp/isledecomp/bin.py @@ -0,0 +1,558 @@ +import logging +import struct +import bisect +from functools import cached_property +from typing import Iterator, List, Optional, Tuple +from dataclasses import dataclass +from collections import namedtuple + + +class MZHeaderNotFoundError(Exception): + """MZ magic string not found at the start of the binary.""" + + +class PEHeaderNotFoundError(Exception): + """PE magic string not found at the offset given in 0x3c.""" + + +class SectionNotFoundError(KeyError): + """The specified section was not found in the file.""" + + +class InvalidVirtualAddressError(IndexError): + """The given virtual address is too high or low + to point to something in the binary file.""" + + +PEHeader = namedtuple( + "PEHeader", + [ + "Signature", + "Machine", + "NumberOfSections", + "TimeDateStamp", + "PointerToSymbolTable", # deprecated + "NumberOfSymbols", # deprecated + "SizeOfOptionalHeader", + "Characteristics", + ], +) + +ImageSectionHeader = namedtuple( + "ImageSectionHeader", + [ + "name", + "virtual_size", + "virtual_address", + "size_of_raw_data", + "pointer_to_raw_data", + "pointer_to_relocations", + "pointer_to_line_numbers", + "number_of_relocations", + "number_of_line_numbers", + "characteristics", + ], +) + + +@dataclass +class Section: + name: str + virtual_size: int + virtual_address: int + view: memoryview + + @cached_property + def size_of_raw_data(self) -> int: + return len(self.view) + + @cached_property + def extent(self): + """Get the highest possible offset of this section""" + return max(self.size_of_raw_data, self.virtual_size) + + def match_name(self, name: str) -> bool: + return self.name == name + + def contains_vaddr(self, vaddr: int) -> bool: + return self.virtual_address <= vaddr < self.virtual_address + self.extent + + def read_virtual(self, vaddr: int, size: int) -> memoryview: + ofs = vaddr - self.virtual_address + + # Negative index will read from the end, which we don't want + if ofs < 0: + raise InvalidVirtualAddressError + + try: + return self.view[ofs : ofs + size] + except IndexError as ex: + raise InvalidVirtualAddressError from ex + + def addr_is_uninitialized(self, vaddr: int) -> bool: + """We cannot rely on the IMAGE_SCN_CNT_UNINITIALIZED_DATA flag (0x80) in + the characteristics field so instead we determine it this way.""" + if not self.contains_vaddr(vaddr): + return False + + # Should include the case where size_of_raw_data == 0, + # meaning the entire section is uninitialized + return (self.virtual_size > self.size_of_raw_data) and ( + vaddr - self.virtual_address >= self.size_of_raw_data + ) + + +logger = logging.getLogger(__name__) + + +class Bin: + """Parses a PE format EXE and allows reading data from a virtual address. + Reference: https://learn.microsoft.com/en-us/windows/win32/debug/pe-format""" + + # pylint: disable=too-many-instance-attributes + + def __init__(self, filename: str, find_str: bool = False) -> None: + logger.debug('Parsing headers of "%s"... ', filename) + self.filename = filename + self.view: memoryview = None + self.imagebase = None + self.entry = None + self.sections: List[Section] = [] + self._section_vaddr: List[int] = [] + self.find_str = find_str + self._potential_strings = {} + self._relocations = set() + self._relocated_addrs = set() + self.imports = [] + self.thunks = [] + self.exports: List[Tuple[int, str]] = [] + self.is_debug: bool = False + + def __enter__(self): + logger.debug("Bin %s Enter", self.filename) + with open(self.filename, "rb") as f: + self.view = memoryview(f.read()) + + (mz_str,) = struct.unpack("2s", self.view[0:2]) + if mz_str != b"MZ": + raise MZHeaderNotFoundError + + # Skip to PE header offset in MZ header. + (pe_header_start,) = struct.unpack(" List[int]: + return sorted(self._relocated_addrs) + + def find_string(self, target: str) -> Optional[int]: + # Pad with null terminator to make sure we don't + # match on a subset of the full string + if not target.endswith(b"\x00"): + target += b"\x00" + + c = target[0] + if c not in self._potential_strings: + return None + + for addr in self._potential_strings[c]: + if target == self.read(addr, len(target)): + return addr + + return None + + def is_relocated_addr(self, vaddr) -> bool: + return vaddr in self._relocated_addrs + + def _prepare_string_search(self): + """We are intersted in deduplicated string constants found in the + .rdata and .data sections. For each relocated address in these sections, + read the first byte and save the address if that byte is an ASCII character. + When we search for an arbitrary string later, we can narrow down the list + of potential locations by a lot.""" + + def is_ascii(b): + return b" " <= b < b"\x7f" + + sect_data = self.get_section_by_name(".data") + sect_rdata = self.get_section_by_name(".rdata") + potentials = filter( + lambda a: sect_data.contains_vaddr(a) or sect_rdata.contains_vaddr(a), + self.get_relocated_addresses(), + ) + + for addr in potentials: + c = self.read(addr, 1) + if c is not None and is_ascii(c): + k = ord(c) + if k not in self._potential_strings: + self._potential_strings[k] = set() + + self._potential_strings[k].add(addr) + + def _populate_relocations(self): + """The relocation table in .reloc gives each virtual address where the next four + bytes are, itself, another virtual address. During loading, these values will be + patched according to the virtual address space for the image, as provided by Windows. + We can use this information to get a list of where each significant "thing" + in the file is located. Anything that is referenced absolutely (i.e. excluding + jump destinations given by local offset) will be here. + One use case is to tell whether an immediate value in an operand represents + a virtual address or just a big number.""" + + reloc = self.get_section_by_name(".reloc").view + ofs = 0 + reloc_addrs = [] + + # Parse the structure in .reloc to get the list locations to check. + # The first 8 bytes are 2 dwords that give the base page address + # and the total block size (including this header). + # The page address is used to compact the list; each entry is only + # 2 bytes, and these are added to the base to get the full location. + # If the entry read in is zero, we are at the end of this section and + # these are padding bytes. + while True: + (page_base, block_size) = struct.unpack("<2I", reloc[ofs : ofs + 8]) + if block_size == 0: + break + + # HACK: ignore the relocation type for now (the top 4 bits of the value). + values = list(struct.iter_unpack(" Iterator[Tuple[int, int, float]]: + """Floating point instructions that refer to a memory address can + point to constant values. Search the code sections to find FP + instructions and check whether the pointer address refers to + read-only data.""" + + # TODO: Should check any section that has code, not just .text + text = self.get_section_by_name(".text") + rdata = self.get_section_by_name(".rdata") + + # These are the addresses where a relocation occurs. + # Meaning: it points to an absolute address of something + for addr in self._relocations: + if not text.contains_vaddr(addr): + continue + + # Read the two bytes before the relocated address. + # We will check against possible float opcodes + raw = text.read_virtual(addr - 2, 6) + (opcode, opcode_ext, const_addr) = struct.unpack(" Section: + section = next( + filter(lambda section: section.match_name(name), self.sections), + None, + ) + + if section is None: + raise SectionNotFoundError + + return section + + def get_section_by_index(self, index: int) -> Section: + """Convert 1-based index into 0-based.""" + return self.sections[index - 1] + + def get_section_extent_by_index(self, index: int) -> int: + return self.get_section_by_index(index).extent + + def get_section_offset_by_index(self, index: int) -> int: + """The symbols output from cvdump gives addresses in this format: AAAA.BBBBBBBB + where A is the index (1-based) into the section table and B is the local offset. + This will return the virtual address for the start of the section at the given index + so you can get the virtual address for whatever symbol you are looking at. + """ + return self.get_section_by_index(index).virtual_address + + def get_section_offset_by_name(self, name: str) -> int: + """Same as above, but use the section name as the lookup""" + + section = self.get_section_by_name(name) + return section.virtual_address + + def get_abs_addr(self, section: int, offset: int) -> int: + """Convenience function for converting section:offset pairs from cvdump + into an absolute vaddr.""" + return self.get_section_offset_by_index(section) + offset + + def get_relative_addr(self, addr: int) -> Tuple[int, int]: + """Convert an absolute address back into a (section, offset) pair.""" + i = bisect.bisect_right(self._section_vaddr, addr) - 1 + i = max(0, i) + + section = self.sections[i] + if section.contains_vaddr(addr): + return (i + 1, addr - section.virtual_address) + + raise InvalidVirtualAddressError(f"{self.filename} : {hex(addr)}") + + def is_valid_section(self, section_id: int) -> bool: + """The PDB will refer to sections that are not listed in the headers + and so should ignore these references.""" + try: + _ = self.get_section_by_index(section_id) + return True + except IndexError: + return False + + def is_valid_vaddr(self, vaddr: int) -> bool: + """Does this virtual address point to anything in the exe?""" + try: + (_, __) = self.get_relative_addr(vaddr) + except InvalidVirtualAddressError: + return False + + return True + + def read_string(self, offset: int, chunk_size: int = 1000) -> Optional[bytes]: + """Read until we find a zero byte.""" + b = self.read(offset, chunk_size) + if b is None: + return None + + try: + return b[: b.index(b"\x00")] + except ValueError: + # No terminator found, just return what we have + return b + + def read(self, vaddr: int, size: int) -> Optional[bytes]: + """Read (at most) the given number of bytes at the given virtual address. + If we return None, the given address points to uninitialized data.""" + (section_id, offset) = self.get_relative_addr(vaddr) + section = self.sections[section_id - 1] + + if section.addr_is_uninitialized(vaddr): + return None + + # Clamp the read within the extent of the current section. + # Reading off the end will most likely misrepresent the virtual addressing. + _size = min(size, section.size_of_raw_data - offset) + return bytes(section.view[offset : offset + _size]) diff --git a/tools/isledecomp/isledecomp/compare/__init__.py b/tools/isledecomp/isledecomp/compare/__init__.py new file mode 100644 index 00000000..f8d18500 --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/__init__.py @@ -0,0 +1 @@ +from .core import Compare diff --git a/tools/isledecomp/isledecomp/compare/asm/__init__.py b/tools/isledecomp/isledecomp/compare/asm/__init__.py new file mode 100644 index 00000000..3fd22f6e --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/asm/__init__.py @@ -0,0 +1,2 @@ +from .parse import ParseAsm +from .swap import can_resolve_register_differences diff --git a/tools/isledecomp/isledecomp/compare/asm/const.py b/tools/isledecomp/isledecomp/compare/asm/const.py new file mode 100644 index 00000000..7c715c0c --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/asm/const.py @@ -0,0 +1,27 @@ +# Duplicates removed, according to the mnemonics capstone uses. +# e.g. je and jz are the same instruction. capstone uses je. +# See: /arch/X86/X86GenAsmWriter.inc in the capstone repo. +JUMP_MNEMONICS = { + "ja", + "jae", + "jb", + "jbe", + "jcxz", # unused? + "je", + "jecxz", + "jg", + "jge", + "jl", + "jle", + "jmp", + "jne", + "jno", + "jnp", + "jns", + "jo", + "jp", + "js", +} + +# Guaranteed to be a single operand. +SINGLE_OPERAND_INSTS = {"push", "call", *JUMP_MNEMONICS} diff --git a/tools/isledecomp/isledecomp/compare/asm/fixes.py b/tools/isledecomp/isledecomp/compare/asm/fixes.py new file mode 100644 index 00000000..bca22681 --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/asm/fixes.py @@ -0,0 +1,302 @@ +import re +from typing import List, Tuple, Set + +DiffOpcode = Tuple[str, int, int, int, int] + +REG_FIND = re.compile(r"(?: |\[)(e?[a-d]x|e?[s,d]i|[a-d][l,h]|e?[b,s]p)") + +ALLOWED_JUMP_SWAPS = ( + ("ja", "jb"), + ("jae", "jbe"), + ("jb", "ja"), + ("jbe", "jae"), + ("jg", "jl"), + ("jge", "jle"), + ("jl", "jg"), + ("jle", "jge"), + ("je", "je"), + ("jne", "jne"), +) + + +def jump_swap_ok(a: str, b: str) -> bool: + """For the instructions a,b, are they both jump instructions + that are compatible with a swapped cmp operand order?""" + # Grab the mnemonic + (jmp_a, _, __) = a.partition(" ") + (jmp_b, _, __) = b.partition(" ") + + return (jmp_a, jmp_b) in ALLOWED_JUMP_SWAPS + + +def is_operand_swap(a: str, b: str) -> bool: + """This is a hack to avoid parsing the operands. It's not as simple as + breaking on the comma because templates or string literals interfere + with this. Instead we check: + 1. Do both strings use the exact same set of characters? + 2. If we do break on ', ', is the first token of each different? + 2 is needed to catch an edge case like: + cmp eax, dword ptr [ecx + 0x1234] + cmp ecx, dword ptr [eax + 0x1234] + """ + return a.partition(", ")[0] != b.partition(", ")[0] and sorted(a) == sorted(b) + + +def can_cmp_swap(orig: List[str], recomp: List[str]) -> bool: + # Make sure we have 1 cmp and 1 jmp for both + if len(orig) != 2 or len(recomp) != 2: + return False + + if not orig[0].startswith("cmp") or not recomp[0].startswith("cmp"): + return False + + if not orig[1].startswith("j") or not recomp[1].startswith("j"): + return False + + # Checking two things: + # Are the cmp operands flipped? + # Is the jump instruction compatible with a flip? + return is_operand_swap(orig[0], recomp[0]) and jump_swap_ok(orig[1], recomp[1]) + + +def patch_jump(a: str, b: str) -> str: + """For jump instructions a, b, return `(mnemonic_a) (operand_b)`. + The reason to do it this way (instead of just returning `a`) is that + the jump instructions might use different displacement offsets + or labels. If we just replace `b` with `a`, this diff would be + incorrectly eliminated.""" + (mnemonic_a, _, __) = a.partition(" ") + (_, __, operand_b) = b.partition(" ") + + return mnemonic_a + " " + operand_b + + +def patch_cmp_swaps( + codes: List[DiffOpcode], orig_asm: List[str], recomp_asm: List[str] +) -> Set[int]: + """Can we resolve the diffs between orig and recomp by patching + swapped cmp instructions? + For example: + cmp eax, ebx cmp ebx, eax + je .label je .label + + cmp eax, ebx cmp ebx, eax + ja .label jb .label + """ + + fixed_lines = set() + + for code, i1, i2, j1, j2 in codes: + # To save us the trouble of finding "compatible" cmp instructions + # use the diff information we already have. + if code != "replace": + continue + + # If the ranges in orig and recomp are not equal, use the shorter one + for i, j in zip(range(i1, i2), range(j1, j2)): + if can_cmp_swap(orig_asm[i : i + 2], recomp_asm[j : j + 2]): + # Patch cmp + fixed_lines.add(j) + + # Patch the jump if necessary + patched = patch_jump(orig_asm[i + 1], recomp_asm[j + 1]) + # We only register a fix if it actually matches + if orig_asm[i + 1] == patched: + fixed_lines.add(j + 1) + + return fixed_lines + + +def effective_match_possible(orig_asm: List[str], recomp_asm: List[str]) -> bool: + # We can only declare an effective match based on the text + # so you need the same amount of "stuff" in each + if len(orig_asm) != len(recomp_asm): + return False + + # mnemonic_orig = [inst.partition(" ")[0] for inst in orig_asm] + # mnemonic_recomp = [inst.partition(" ")[0] for inst in recomp_asm] + + # Cannot change mnemonics. Must be same starting list + # TODO: Fine idea but this will exclude jump swaps for cmp operand order + # if sorted(mnemonic_orig) != sorted(mnemonic_recomp): + # return False + + return True + + +def find_regs_used(inst: str) -> List[str]: + return REG_FIND.findall(inst) + + +def find_regs_changed(a: str, b: str) -> List[Tuple[str, str]]: + """For instructions a, b, return the pairs of registers that were used. + This is not a very precise way to compare the instructions, so it depends + on the input being two instructions that would match *except* for + the register choice.""" + return zip(REG_FIND.findall(a), REG_FIND.findall(b)) + + +def bad_register_swaps( + swaps: Set[int], orig_asm: List[str], recomp_asm: List[str] +) -> Set[int]: + """The list of recomp indices in `swaps` tells which instructions are + a match for orig except for the registers used. From that list, check + whether a register swap should not be allowed. + For now, this means checking for `push` instructions where the register + was not used in any other register swaps on previous instructions.""" + rejects = set() + + # Foreach `push` instruction where we have excused the diff + pushes = [j for j in swaps if recomp_asm[j].startswith("push")] + + for j in pushes: + okay = False + # Get the operands in each + reg = (orig_asm[j].partition(" ")[2], recomp_asm[j].partition(" ")[2]) + # If this isn't a register at all, ignore it + try: + int(reg[0], 16) + continue + except ValueError: + pass + + # For every other excused diff that is *not* a push: + # Assumes same index in orig as in recomp, but so does our naive match + for k in swaps.difference(pushes): + changed_regs = find_regs_changed(orig_asm[k], recomp_asm[k]) + if reg in changed_regs or reg[::-1] in changed_regs: + okay = True + break + + if not okay: + rejects.add(j) + + return rejects + + +# Instructions that result in a change to the first operand +MODIFIER_INSTRUCTIONS = ("adc", "add", "lea", "mov", "neg", "sbb", "sub", "pop", "xor") + + +def instruction_alters_regs(inst: str, regs: Set[str]) -> bool: + (mnemonic, _, op_str) = inst.partition(" ") + (first_operand, _, __) = op_str.partition(", ") + + return (mnemonic in MODIFIER_INSTRUCTIONS and first_operand in regs) or ( + mnemonic == "call" and "eax" in regs + ) + + +def relocate_instructions( + codes: List[DiffOpcode], orig_asm: List[str], recomp_asm: List[str] +) -> Set[int]: + """Collect the list of instructions deleted from orig and inserted + into recomp, according to the diff opcodes. Using this list, match up + any pairs of instructions that we assume to be relocated and return + the indices in recomp where this has occurred. + For now, we are checking only for an exact match on the instruction. + We are not checking whether the given instruction can be moved from + point A to B. (i.e. does this set a register that is used by the + instructions between A and B?)""" + deletes = { + i for code, i1, i2, _, __ in codes for i in range(i1, i2) if code == "delete" + } + inserts = [ + j for code, _, __, j1, j2 in codes for j in range(j1, j2) if code == "insert" + ] + + relocated = set() + + for j in inserts: + line = recomp_asm[j] + recomp_regs_used = set(find_regs_used(line)) + for i in deletes: + # Check for exact match. + # TODO: This will grab the first instruction that matches. + # We should probably use the nearest index instead, if it matters + if orig_asm[i] == line: + # To account for a move in either direction + reloc_start = min(i, j) + reloc_end = max(i, j) + if not any( + instruction_alters_regs(orig_asm[k], recomp_regs_used) + for k in range(reloc_start, reloc_end) + ): + relocated.add(j) + deletes.remove(i) + break + + return relocated + + +DWORD_REGS = ("eax", "ebx", "ecx", "edx", "esi", "edi", "ebp", "esp") +WORD_REGS = ("ax", "bx", "cx", "dx", "si", "di", "bp", "sp") +BYTE_REGS = ("ah", "al", "bh", "bl", "ch", "cl", "dh", "dl") + + +def naive_register_replacement(orig_asm: List[str], recomp_asm: List[str]) -> Set[int]: + """Replace all registers of the same size with a placeholder string. + After doing that, compare orig and recomp again. + Return indices from recomp that are now equal to the same index in orig. + This requires orig and recomp to have the same number of instructions, + but this is already a requirement for effective match.""" + orig_raw = "\n".join(orig_asm) + recomp_raw = "\n".join(recomp_asm) + + # TODO: hardly the most elegant way to do this. + for rdw in DWORD_REGS: + orig_raw = orig_raw.replace(rdw, "~reg4") + recomp_raw = recomp_raw.replace(rdw, "~reg4") + + for rw in WORD_REGS: + orig_raw = orig_raw.replace(rw, "~reg2") + recomp_raw = recomp_raw.replace(rw, "~reg2") + + for rb in BYTE_REGS: + orig_raw = orig_raw.replace(rb, "~reg1") + recomp_raw = recomp_raw.replace(rb, "~reg1") + + orig_scrubbed = orig_raw.split("\n") + recomp_scrubbed = recomp_raw.split("\n") + + return { + j for j in range(len(recomp_scrubbed)) if orig_scrubbed[j] == recomp_scrubbed[j] + } + + +def find_effective_match( + codes: List[DiffOpcode], orig_asm: List[str], recomp_asm: List[str] +) -> bool: + """Check whether the two sequences of instructions are an effective match. + Meaning: do they differ only by instruction order or register selection?""" + if not effective_match_possible(orig_asm, recomp_asm): + return False + + already_equal = { + j for code, _, __, j1, j2 in codes for j in range(j1, j2) if code == "equal" + } + + # We need to come up with some answer for each of these lines + recomp_lines_disputed = { + j + for code, _, __, j1, j2 in codes + for j in range(j1, j2) + if code in ("insert", "replace") + } + + cmp_swaps = patch_cmp_swaps(codes, orig_asm, recomp_asm) + # This naive result includes lines that already match, so remove those + naive_swaps = naive_register_replacement(orig_asm, recomp_asm).difference( + already_equal + ) + relocates = relocate_instructions(codes, orig_asm, recomp_asm) + + bad_swaps = bad_register_swaps(naive_swaps, orig_asm, recomp_asm) + + corrections = set().union( + naive_swaps.difference(bad_swaps), + cmp_swaps, + relocates, + ) + + return corrections.issuperset(recomp_lines_disputed) diff --git a/tools/isledecomp/isledecomp/compare/asm/instgen.py b/tools/isledecomp/isledecomp/compare/asm/instgen.py new file mode 100644 index 00000000..3eeb6313 --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/asm/instgen.py @@ -0,0 +1,235 @@ +"""Pre-parser for x86 instructions. Will identify data/jump tables used with +switch statements and local jump/call destinations.""" +import re +import bisect +import struct +from enum import Enum, auto +from collections import namedtuple +from typing import List, NamedTuple, Optional, Tuple, Union +from capstone import Cs, CS_ARCH_X86, CS_MODE_32 +from .const import JUMP_MNEMONICS + +disassembler = Cs(CS_ARCH_X86, CS_MODE_32) + +DisasmLiteInst = namedtuple("DisasmLiteInst", "address, size, mnemonic, op_str") + +displacement_regex = re.compile(r".*\+ (0x[0-9a-f]+)\]") + + +class SectionType(Enum): + CODE = auto() + DATA_TAB = auto() + ADDR_TAB = auto() + + +class FuncSection(NamedTuple): + type: SectionType + contents: List[Union[DisasmLiteInst, Tuple[str, int]]] + + +class InstructGen: + # pylint: disable=too-many-instance-attributes + def __init__(self, blob: bytes, start: int) -> None: + self.blob = blob + self.start = start + self.end = len(blob) + start + self.section_end: int = self.end + self.code_tracks: List[List[DisasmLiteInst]] = [] + + # Todo: Could be refactored later + self.cur_addr: int = 0 + self.cur_section_type: SectionType = SectionType.CODE + self.section_start = start + + self.sections: List[FuncSection] = [] + + self.confirmed_addrs = {} + self.analysis() + + def _finish_section(self, type_: SectionType, stuff): + sect = FuncSection(type_, stuff) + self.sections.append(sect) + + def _insert_confirmed_addr(self, addr: int, type_: SectionType): + # Ignore address outside the bounds of the function + if not self.start <= addr < self.end: + return + + self.confirmed_addrs[addr] = type_ + + # This newly inserted address might signal the end of this section. + # For example, a jump table at the end of the function means we should + # stop reading instructions once we hit that address. + # However, if there is a jump table in between code sections, we might + # read a jump to an address back to the beginning of the function + # (e.g. a loop that spans the entire function) + # so ignore this address because we have already passed it. + if type_ != self.cur_section_type and addr > self.cur_addr: + self.section_end = min(self.section_end, addr) + + def _next_section(self, addr: int) -> Optional[SectionType]: + """We have reached the start of a new section. Tell what kind of + data we are looking at (code or other) and how much we should read.""" + + # Assume the start of every function is code. + if addr == self.start: + self.section_end = self.end + return SectionType.CODE + + # The start of a new section must be an address that we've seen. + new_type = self.confirmed_addrs.get(addr) + if new_type is None: + return None + + self.cur_section_type = new_type + + # The confirmed addrs dict is sorted by insertion order + # i.e. the order in which we read the addresses + # So we have to sort and then find the next item + # to see where this section should end. + + # If we are in a CODE section, ignore contiguous CODE addresses. + # These are not the start of a new section. + # However: if we are not in CODE, any upcoming address is a new section. + # Do this so we can detect contiguous non-CODE sections. + confirmed = [ + conf_addr + for (conf_addr, conf_type) in sorted(self.confirmed_addrs.items()) + if self.cur_section_type != SectionType.CODE + or conf_type != self.cur_section_type + ] + + index = bisect.bisect_right(confirmed, addr) + if index < len(confirmed): + self.section_end = confirmed[index] + else: + self.section_end = self.end + + return new_type + + def _get_code_for(self, addr: int) -> List[DisasmLiteInst]: + """Start disassembling at the given address.""" + # If we are reading a code block beyond the first, see if we already + # have disassembled instructions beginning at the specified address. + # For a CODE/ADDR/CODE function, we might get lucky and produce the + # correct instruction after the jump table's junk instructions. + for track in self.code_tracks: + for i, inst in enumerate(track): + if inst.address == addr: + return track[i:] + + # If we are here, we don't have the instructions. + # Todo: Could try to be clever here and disassemble only + # as much as we probably need (i.e. if a jump table is between CODE + # blocks, there are probably only a few bad instructions after the + # jump table is finished. We could disassemble up to the next verified + # code address and stitch it together) + + blob_cropped = self.blob[addr - self.start :] + instructions = [ + DisasmLiteInst(*inst) + for inst in disassembler.disasm_lite(blob_cropped, addr) + ] + self.code_tracks.append(instructions) + return instructions + + def _handle_jump(self, inst: DisasmLiteInst): + # If this is a regular jump and its destination is within the + # bounds of the binary data (i.e. presumed function size) + # add it to our list of confirmed addresses. + if inst.op_str[0] == "0": + value = int(inst.op_str, 16) + self._insert_confirmed_addr(value, SectionType.CODE) + + # If this is jumping into a table of addresses, save the destination + elif (match := displacement_regex.match(inst.op_str)) is not None: + value = int(match.group(1), 16) + self._insert_confirmed_addr(value, SectionType.ADDR_TAB) + + def analysis(self): + self.cur_addr = self.start + + while (sect_type := self._next_section(self.cur_addr)) is not None: + self.section_start = self.cur_addr + + if sect_type == SectionType.CODE: + instructions = self._get_code_for(self.cur_addr) + + # If we didn't get any instructions back, something is wrong. + # i.e. We can only read part of the full instruction that is up next. + if len(instructions) == 0: + # Nudge the current addr so we will eventually move on to the + # next section. + # Todo: Maybe we could just call it quits here + self.cur_addr += 1 + break + + for inst in instructions: + # section_end is updated as we read instructions. + # If we are into a jump/data table and would read + # a junk instruction, stop here. + if self.cur_addr >= self.section_end: + break + + # print(f"{inst.address:x} : {inst.mnemonic} {inst.op_str}") + + if inst.mnemonic in JUMP_MNEMONICS: + self._handle_jump(inst) + # Todo: log calls too (unwind section) + elif inst.mnemonic == "mov": + # Todo: maintain pairing of data/jump tables + if (match := displacement_regex.match(inst.op_str)) is not None: + value = int(match.group(1), 16) + self._insert_confirmed_addr(value, SectionType.DATA_TAB) + + # Do this instead of copying instruction address. + # If there is only one instruction, we would get stuck here. + self.cur_addr += inst.size + + # End of for loop on instructions. + # We are at the end of the section or the entire function. + # Cut out only the valid instructions for this section + # and save it for later. + + # Todo: don't need to iter on every instruction here. + # They are already in order. + instruction_slice = [ + inst for inst in instructions if inst.address < self.section_end + ] + self._finish_section(SectionType.CODE, instruction_slice) + + elif sect_type == SectionType.ADDR_TAB: + # Clamp to multiple of 4 (dwords) + read_size = ((self.section_end - self.cur_addr) // 4) * 4 + offsets = range(self.section_start, self.section_start + read_size, 4) + dwords = self.blob[ + self.cur_addr - self.start : self.cur_addr - self.start + read_size + ] + addrs = [addr for addr, in struct.iter_unpack(" {t1:x}") + + self._finish_section(SectionType.ADDR_TAB, jump_table) + self.cur_addr = self.section_end + + else: + # Todo: variable data size? + read_size = self.section_end - self.cur_addr + offsets = range(self.section_start, self.section_start + read_size) + bytes_ = self.blob[ + self.cur_addr - self.start : self.cur_addr - self.start + read_size + ] + data = [b for b, in struct.iter_unpack(" Optional[int]: + try: + return int(string, 16) + except ValueError: + pass + + return None + + +def bytes_to_dword(b: bytes) -> Optional[int]: + if len(b) == 4: + return struct.unpack(" None: + self.relocate_lookup = relocate_lookup + self.name_lookup = name_lookup + self.bin_lookup = bin_lookup + self.replacements = {} + self.number_placeholders = True + + def reset(self): + self.replacements = {} + + def is_relocated(self, addr: int) -> bool: + if callable(self.relocate_lookup): + return self.relocate_lookup(addr) + + return False + + def lookup( + self, addr: int, use_cache: bool = True, exact: bool = False + ) -> Optional[str]: + """Return a replacement name for this address if we find one.""" + if use_cache and (cached := self.replacements.get(addr, None)) is not None: + return cached + + if callable(self.name_lookup): + if (name := self.name_lookup(addr, exact)) is not None: + if use_cache: + self.replacements[addr] = name + + return name + + return None + + def replace(self, addr: int) -> str: + """Same function as lookup above, but here we return a placeholder + if there is no better name to use.""" + if (name := self.lookup(addr)) is not None: + return name + + # The placeholder number corresponds to the number of addresses we have + # already replaced. This is so the number will be consistent across the diff + # if we can replace some symbols with actual names in recomp but not orig. + idx = len(self.replacements) + 1 + placeholder = f"" if self.number_placeholders else "" + self.replacements[addr] = placeholder + return placeholder + + def hex_replace_always(self, match: re.Match) -> str: + """If a pointer value was matched, always insert a placeholder""" + value = int(match.group(1), 16) + return match.group(0).replace(match.group(1), self.replace(value)) + + def hex_replace_relocated(self, match: re.Match) -> str: + """For replacing immediate value operands. We only want to + use the placeholder if we are certain that this is a valid address. + We can check the relocation table to find out.""" + value = int(match.group(1), 16) + if self.is_relocated(value): + return match.group(0).replace(match.group(1), self.replace(value)) + + return match.group(0) + + def hex_replace_annotated(self, match: re.Match) -> str: + """For replacing immediate value operands. Here we replace the value + only if the name lookup returns something. Do not use a placeholder.""" + value = int(match.group(1), 16) + placeholder = self.lookup(value, use_cache=False) + if placeholder is not None: + return match.group(0).replace(match.group(1), placeholder) + + return match.group(0) + + def hex_replace_indirect(self, match: re.Match) -> str: + """Edge case for hex_replace_always. The context of the instruction + tells us that the pointer value is an absolute indirect. + So we go to that location in the binary to get the address. + If we cannot identify the indirect address, fall back to a lookup + on the original pointer value so we might display something useful.""" + value = int(match.group(1), 16) + indirect_value = None + + if callable(self.bin_lookup): + indirect_value = self.bin_lookup(value, 4) + + if indirect_value is not None: + indirect_addr = bytes_to_dword(indirect_value) + if ( + indirect_addr is not None + and self.lookup(indirect_addr, use_cache=False) is not None + ): + return match.group(0).replace( + match.group(1), "->" + self.replace(indirect_addr) + ) + + return match.group(0).replace(match.group(1), self.replace(value)) + + def sanitize(self, inst: DisasmLiteInst) -> Tuple[str, str]: + # For jumps or calls, if the entire op_str is a hex number, the value + # is a relative offset. + # Otherwise (i.e. it looks like `dword ptr [address]`) it is an + # absolute indirect that we will handle below. + # Providing the starting address of the function to capstone.disasm has + # automatically resolved relative offsets to an absolute address. + # We will have to undo this for some of the jumps or they will not match. + + if ( + inst.mnemonic in SINGLE_OPERAND_INSTS + and (op_str_address := from_hex(inst.op_str)) is not None + ): + if inst.mnemonic == "call": + return (inst.mnemonic, self.replace(op_str_address)) + + if inst.mnemonic == "push": + if self.is_relocated(op_str_address): + return (inst.mnemonic, self.replace(op_str_address)) + + # To avoid falling into jump handling + return (inst.mnemonic, inst.op_str) + + if inst.mnemonic == "jmp": + # The unwind section contains JMPs to other functions. + # If we have a name for this address, use it. If not, + # do not create a new placeholder. We will instead + # fall through to generic jump handling below. + potential_name = self.lookup(op_str_address, exact=True) + if potential_name is not None: + return (inst.mnemonic, potential_name) + + # Else: this is any jump + # Show the jump offset rather than the absolute address + jump_displacement = op_str_address - (inst.address + inst.size) + return (inst.mnemonic, hex(jump_displacement)) + + if inst.mnemonic == "call": + # Special handling for absolute indirect CALL. + op_str = ptr_replace_regex.sub(self.hex_replace_indirect, inst.op_str) + else: + op_str = ptr_replace_regex.sub(self.hex_replace_always, inst.op_str) + + # We only want relocated addresses for pointer displacement. + # i.e. ptr [register + something] + # Otherwise we would use a placeholder for every stack variable, + # vtable call, or this->member access. + op_str = displace_replace_regex.sub(self.hex_replace_relocated, op_str) + + # In the event of pointer comparison, only replace the immediate value + # if it is a known address. + if inst.mnemonic == "cmp": + op_str = immediate_replace_regex.sub(self.hex_replace_annotated, op_str) + else: + op_str = immediate_replace_regex.sub(self.hex_replace_relocated, op_str) + + return (inst.mnemonic, op_str) + + def parse_asm(self, data: bytes, start_addr: Optional[int] = 0) -> List[str]: + asm = [] + + ig = InstructGen(data, start_addr) + + for sect_type, sect_contents in ig.sections: + if sect_type == SectionType.CODE: + for inst in sect_contents: + # Use heuristics to disregard some differences that aren't representative + # of the accuracy of a function (e.g. global offsets) + + # If there is no pointer or immediate value in the op_str, + # there is nothing to sanitize. + # This leaves us with cases where a small immediate value or + # small displacement (this.member or vtable calls) appears. + # If we assume that instructions we want to sanitize need to be 5 + # bytes -- 1 for the opcode and 4 for the address -- exclude cases + # where the hex value could not be an address. + # The exception is jumps which are as small as 2 bytes + # but are still useful to sanitize. + if "0x" in inst.op_str and ( + inst.mnemonic in JUMP_MNEMONICS or inst.size > 4 + ): + result = self.sanitize(inst) + else: + result = (inst.mnemonic, inst.op_str) + + # mnemonic + " " + op_str + asm.append((hex(inst.address), " ".join(result))) + elif sect_type == SectionType.ADDR_TAB: + asm.append(("", "Jump table:")) + for i, (ofs, _) in enumerate(sect_contents): + asm.append((hex(ofs), f"Jump_dest_{i}")) + + elif sect_type == SectionType.DATA_TAB: + asm.append(("", "Data table:")) + for ofs, b in sect_contents: + asm.append((hex(ofs), hex(b))) + + return asm diff --git a/tools/isledecomp/isledecomp/compare/asm/swap.py b/tools/isledecomp/isledecomp/compare/asm/swap.py new file mode 100644 index 00000000..599444cf --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/asm/swap.py @@ -0,0 +1,80 @@ +import re + +REGISTER_LIST = set( + [ + "ax", + "bp", + "bx", + "cx", + "di", + "dx", + "eax", + "ebp", + "ebx", + "ecx", + "edi", + "edx", + "esi", + "esp", + "si", + "sp", + ] +) +WORDS = re.compile(r"\w+") + + +def get_registers(line: str): + to_replace = [] + # use words regex to find all matching positions: + for match in WORDS.finditer(line): + reg = match.group(0) + if reg in REGISTER_LIST: + to_replace.append((reg, match.start())) + return to_replace + + +def replace_register( + lines: list[str], start_line: int, reg: str, replacement: str +) -> list[str]: + return [ + line.replace(reg, replacement) if i >= start_line else line + for i, line in enumerate(lines) + ] + + +# Is it possible to make new_asm the same as original_asm by swapping registers? +def can_resolve_register_differences(original_asm, new_asm): + # Split the ASM on spaces to get more granularity, and so + # that we don't modify the original arrays passed in. + original_asm = [part for line in original_asm for part in line.split()] + new_asm = [part for line in new_asm for part in line.split()] + + # Swapping ain't gonna help if the lengths are different + if len(original_asm) != len(new_asm): + return False + + # Look for the mismatching lines + for i, original_line in enumerate(original_asm): + new_line = new_asm[i] + if new_line != original_line: + # Find all the registers to replace + to_replace = get_registers(original_line) + + for replace in to_replace: + (reg, reg_index) = replace + replacing_reg = new_line[reg_index : reg_index + len(reg)] + if replacing_reg in REGISTER_LIST: + if replacing_reg != reg: + # Do a three-way swap replacing in all the subsequent lines + temp_reg = "&" * len(reg) + new_asm = replace_register(new_asm, i, replacing_reg, temp_reg) + new_asm = replace_register(new_asm, i, reg, replacing_reg) + new_asm = replace_register(new_asm, i, temp_reg, reg) + else: + # No replacement to do, different code, bail out + return False + # Check if the lines are now the same + for i, original_line in enumerate(original_asm): + if new_asm[i] != original_line: + return False + return True diff --git a/tools/isledecomp/isledecomp/compare/core.py b/tools/isledecomp/isledecomp/compare/core.py new file mode 100644 index 00000000..b49600d0 --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/core.py @@ -0,0 +1,766 @@ +import os +import logging +import difflib +import struct +import uuid +from dataclasses import dataclass +from typing import Callable, Iterable, List, Optional +from isledecomp.bin import Bin as IsleBin, InvalidVirtualAddressError +from isledecomp.cvdump.demangler import demangle_string_const +from isledecomp.cvdump import Cvdump, CvdumpAnalysis +from isledecomp.parser import DecompCodebase +from isledecomp.dir import walk_source_dir +from isledecomp.types import SymbolType +from isledecomp.compare.asm import ParseAsm +from isledecomp.compare.asm.fixes import find_effective_match +from .db import CompareDb, MatchInfo +from .diff import combined_diff +from .lines import LinesDb + + +logger = logging.getLogger(__name__) + + +@dataclass +class DiffReport: + # pylint: disable=too-many-instance-attributes + match_type: SymbolType + orig_addr: int + recomp_addr: int + name: str + udiff: Optional[List[str]] = None + ratio: float = 0.0 + is_effective_match: bool = False + is_stub: bool = False + + @property + def effective_ratio(self) -> float: + return 1.0 if self.is_effective_match else self.ratio + + def __str__(self) -> str: + """For debug purposes. Proper diff printing (with coloring) is in another module.""" + return f"{self.name} (0x{self.orig_addr:x}) {self.ratio*100:.02f}%{'*' if self.is_effective_match else ''}" + + +def create_reloc_lookup(bin_file: IsleBin) -> Callable[[int], bool]: + """Function generator for relocation table lookup""" + + def lookup(addr: int) -> bool: + return addr > bin_file.imagebase and bin_file.is_relocated_addr(addr) + + return lookup + + +def create_bin_lookup(bin_file: IsleBin) -> Callable[[int, int], Optional[str]]: + """Function generator for reading from the bin file""" + + def lookup(addr: int, size: int) -> Optional[bytes]: + try: + return bin_file.read(addr, size) + except InvalidVirtualAddressError: + return None + + return lookup + + +class Compare: + # pylint: disable=too-many-instance-attributes + def __init__( + self, orig_bin: IsleBin, recomp_bin: IsleBin, pdb_file: str, code_dir: str + ): + self.orig_bin = orig_bin + self.recomp_bin = recomp_bin + self.pdb_file = pdb_file + self.code_dir = code_dir + # Controls whether we dump the asm output to a file + self.debug: bool = False + self.runid: str = uuid.uuid4().hex[:8] + + self._lines_db = LinesDb(code_dir) + self._db = CompareDb() + + self._load_cvdump() + self._load_markers() + self._find_original_strings() + self._find_float_const() + self._match_imports() + self._match_exports() + self._match_thunks() + self._find_vtordisp() + + def _load_cvdump(self): + logger.info("Parsing %s ...", self.pdb_file) + cv = ( + Cvdump(self.pdb_file) + .lines() + .globals() + .publics() + .symbols() + .section_contributions() + .types() + .run() + ) + res = CvdumpAnalysis(cv) + + for sym in res.nodes: + # The PDB might contain sections that do not line up with the + # actual binary. The symbol "__except_list" is one example. + # In these cases, just skip this symbol and move on because + # we can't do much with it. + if not self.recomp_bin.is_valid_section(sym.section): + continue + + addr = self.recomp_bin.get_abs_addr(sym.section, sym.offset) + + # If this symbol is the final one in its section, we were not able to + # estimate its size because we didn't have the total size of that section. + # We can get this estimate now and assume that the final symbol occupies + # the remainder of the section. + if sym.estimated_size is None: + sym.estimated_size = ( + self.recomp_bin.get_section_extent_by_index(sym.section) + - sym.offset + ) + + if sym.node_type == SymbolType.STRING: + string_info = demangle_string_const(sym.decorated_name) + if string_info is None: + logger.debug( + "Could not demangle string symbol: %s", sym.decorated_name + ) + continue + + # TODO: skip unicode for now. will need to handle these differently. + if string_info.is_utf16: + continue + + raw = self.recomp_bin.read(addr, sym.size()) + try: + # We use the string length reported in the mangled symbol as the + # data size, but this is not always accurate with respect to the + # null terminator. + # e.g. ??_C@_0BA@EFDM@MxObjectFactory?$AA@ + # reported length: 16 (includes null terminator) + # c.f. ??_C@_03DPKJ@enz?$AA@ + # reported length: 3 (does NOT include terminator) + # This will handle the case where the entire string contains "\x00" + # because those are distinct from the empty string of length 0. + decoded_string = raw.decode("latin1") + rstrip_string = decoded_string.rstrip("\x00") + + if decoded_string != "" and rstrip_string != "": + sym.friendly_name = rstrip_string + else: + sym.friendly_name = decoded_string + + except UnicodeDecodeError: + pass + + self._db.set_recomp_symbol( + addr, sym.node_type, sym.name(), sym.decorated_name, sym.size() + ) + + for (section, offset), (filename, line_no) in res.verified_lines.items(): + addr = self.recomp_bin.get_abs_addr(section, offset) + self._lines_db.add_line(filename, line_no, addr) + + # The _entry symbol is referenced in the PE header so we get this match for free. + self._db.set_function_pair(self.orig_bin.entry, self.recomp_bin.entry) + + def _load_markers(self): + # Assume module name is the base filename of the original binary. + (module, _) = os.path.splitext(os.path.basename(self.orig_bin.filename)) + + codefiles = list(walk_source_dir(self.code_dir)) + codebase = DecompCodebase(codefiles, module.upper()) + + def orig_bin_checker(addr: int) -> bool: + return self.orig_bin.is_valid_vaddr(addr) + + # If the address of any annotation would cause an exception, + # remove it and report an error. + bad_annotations = codebase.prune_invalid_addrs(orig_bin_checker) + + for sym in bad_annotations: + logger.error( + "Invalid address 0x%x on %s annotation in file: %s", + sym.offset, + sym.type.name, + sym.filename, + ) + + # Match lineref functions first because this is a guaranteed match. + # If we have two functions that share the same name, and one is + # a lineref, we can match the nameref correctly because the lineref + # was already removed from consideration. + for fun in codebase.iter_line_functions(): + recomp_addr = self._lines_db.search_line(fun.filename, fun.line_number) + if recomp_addr is not None: + self._db.set_function_pair(fun.offset, recomp_addr) + if fun.should_skip(): + self._db.mark_stub(fun.offset) + + for fun in codebase.iter_name_functions(): + self._db.match_function(fun.offset, fun.name) + if fun.should_skip(): + self._db.mark_stub(fun.offset) + + for var in codebase.iter_variables(): + if var.is_static and var.parent_function is not None: + self._db.match_static_variable( + var.offset, var.name, var.parent_function + ) + else: + self._db.match_variable(var.offset, var.name) + + for tbl in codebase.iter_vtables(): + self._db.match_vtable(tbl.offset, tbl.name, tbl.base_class) + + for string in codebase.iter_strings(): + # Not that we don't trust you, but we're checking the string + # annotation to make sure it is accurate. + try: + # TODO: would presumably fail for wchar_t strings + orig = self.orig_bin.read_string(string.offset).decode("latin1") + string_correct = string.name == orig + except UnicodeDecodeError: + string_correct = False + + if not string_correct: + logger.error( + "Data at 0x%x does not match string %s", + string.offset, + repr(string.name), + ) + continue + + self._db.match_string(string.offset, string.name) + + def _find_original_strings(self): + """Go to the original binary and look for the specified string constants + to find a match. This is a (relatively) expensive operation so we only + look at strings that we have not already matched via a STRING annotation.""" + + for string in self._db.get_unmatched_strings(): + addr = self.orig_bin.find_string(string.encode("latin1")) + if addr is None: + escaped = repr(string) + logger.debug("Failed to find this string in the original: %s", escaped) + continue + + self._db.match_string(addr, string) + + def _find_float_const(self): + """Add floating point constants in each binary to the database. + We are not matching anything right now because these values are not + deduped like strings.""" + for addr, size, float_value in self.orig_bin.find_float_consts(): + self._db.set_orig_symbol(addr, SymbolType.FLOAT, str(float_value), size) + + for addr, size, float_value in self.recomp_bin.find_float_consts(): + self._db.set_recomp_symbol( + addr, SymbolType.FLOAT, str(float_value), None, size + ) + + def _match_imports(self): + """We can match imported functions based on the DLL name and + function symbol name.""" + orig_byaddr = { + addr: (dll.upper(), name) for (dll, name, addr) in self.orig_bin.imports + } + recomp_byname = { + (dll.upper(), name): addr for (dll, name, addr) in self.recomp_bin.imports + } + # Combine these two dictionaries. We don't care about imports from recomp + # not found in orig because: + # 1. They shouldn't be there + # 2. They are already identified via cvdump + orig_to_recomp = { + addr: recomp_byname.get(pair, None) for addr, pair in orig_byaddr.items() + } + + # Now: we have the IAT offset in each matched up, so we need to make + # the connection between the thunk functions. + # We already have the symbol name we need from the PDB. + for orig, recomp in orig_to_recomp.items(): + if orig is None or recomp is None: + continue + + # Match the __imp__ symbol + self._db.set_pair(orig, recomp, SymbolType.POINTER) + + # Read the relative address from .idata + try: + (recomp_rva,) = struct.unpack(" DiffReport: + # Detect when the recomp function size would cause us to read + # enough bytes from the original function that we cross into + # the next annotated function. + next_orig = self._db.get_next_orig_addr(match.orig_addr) + if next_orig is not None: + orig_size = min(next_orig - match.orig_addr, match.size) + else: + orig_size = match.size + + orig_raw = self.orig_bin.read(match.orig_addr, orig_size) + recomp_raw = self.recomp_bin.read(match.recomp_addr, match.size) + + # It's unlikely that a function other than an adjuster thunk would + # start with a SUB instruction, so alert to a possible wrong + # annotation here. + # There's probably a better place to do this, but we're reading + # the function bytes here already. + try: + if orig_raw[0] == 0x2B and recomp_raw[0] != 0x2B: + logger.warning( + "Possible thunk at 0x%x (%s)", match.orig_addr, match.name + ) + except IndexError: + pass + + def orig_lookup(addr: int, exact: bool) -> Optional[str]: + m = self._db.get_by_orig(addr, exact) + if m is None: + return None + + if m.orig_addr == addr: + return m.match_name() + + offset = addr - m.orig_addr + if m.compare_type != SymbolType.DATA or offset >= m.size: + return None + + return m.offset_name(offset) + + def recomp_lookup(addr: int, exact: bool) -> Optional[str]: + m = self._db.get_by_recomp(addr, exact) + if m is None: + return None + + if m.recomp_addr == addr: + return m.match_name() + + offset = addr - m.recomp_addr + if m.compare_type != SymbolType.DATA or offset >= m.size: + return None + + return m.offset_name(offset) + + orig_should_replace = create_reloc_lookup(self.orig_bin) + recomp_should_replace = create_reloc_lookup(self.recomp_bin) + + orig_bin_lookup = create_bin_lookup(self.orig_bin) + recomp_bin_lookup = create_bin_lookup(self.recomp_bin) + + orig_parse = ParseAsm( + relocate_lookup=orig_should_replace, + name_lookup=orig_lookup, + bin_lookup=orig_bin_lookup, + ) + recomp_parse = ParseAsm( + relocate_lookup=recomp_should_replace, + name_lookup=recomp_lookup, + bin_lookup=recomp_bin_lookup, + ) + + orig_combined = orig_parse.parse_asm(orig_raw, match.orig_addr) + recomp_combined = recomp_parse.parse_asm(recomp_raw, match.recomp_addr) + + if self.debug: + self._dump_asm(orig_combined, recomp_combined) + + # Detach addresses from asm lines for the text diff. + orig_asm = [x[1] for x in orig_combined] + recomp_asm = [x[1] for x in recomp_combined] + + diff = difflib.SequenceMatcher(None, orig_asm, recomp_asm) + ratio = diff.ratio() + + if ratio != 1.0: + # Check whether we can resolve register swaps which are actually + # perfect matches modulo compiler entropy. + codes = diff.get_opcodes() + is_effective_match = find_effective_match(codes, orig_asm, recomp_asm) + unified_diff = combined_diff( + diff, orig_combined, recomp_combined, context_size=10 + ) + else: + is_effective_match = False + unified_diff = [] + + return DiffReport( + match_type=SymbolType.FUNCTION, + orig_addr=match.orig_addr, + recomp_addr=match.recomp_addr, + name=match.name, + udiff=unified_diff, + ratio=ratio, + is_effective_match=is_effective_match, + ) + + def _compare_vtable(self, match: MatchInfo) -> DiffReport: + vtable_size = match.size + + # The vtable size should always be a multiple of 4 because that + # is the pointer size. If it is not (for whatever reason) + # it would cause iter_unpack to blow up so let's just fix it. + if vtable_size % 4 != 0: + logger.warning( + "Vtable for class %s has irregular size %d", match.name, vtable_size + ) + vtable_size = 4 * (vtable_size // 4) + + orig_table = self.orig_bin.read(match.orig_addr, vtable_size) + recomp_table = self.recomp_bin.read(match.recomp_addr, vtable_size) + + raw_addrs = zip( + [t for (t,) in struct.iter_unpack(" str: + """Format the function reference at this vtable index as text. + If we have not identified this function, we have the option to + display the raw address. This is only worth doing for the original addr + because we should always be able to identify the recomp function. + If the original function is missing then this probably means that the class + should override the given function from the superclass, but we have not + implemented this yet. + """ + + if m is not None: + orig = hex(m.orig_addr) if m.orig_addr is not None else "no orig" + recomp = ( + hex(m.recomp_addr) if m.recomp_addr is not None else "no recomp" + ) + return f"({orig} / {recomp}) : {m.name}" + + if raw_addr is not None: + return f"0x{raw_addr:x} from orig not annotated." + + return "(no match)" + + orig_text = [] + recomp_text = [] + ratio = 0 + n_entries = 0 + + # Now compare each pointer from the two vtables. + for i, (raw_orig, raw_recomp) in enumerate(raw_addrs): + orig = self._db.get_by_orig(raw_orig) + recomp = self._db.get_by_recomp(raw_recomp) + + if ( + orig is not None + and recomp is not None + and orig.recomp_addr == recomp.recomp_addr + ): + ratio += 1 + + n_entries += 1 + index = f"vtable0x{i*4:02x}" + orig_text.append((index, match_text(orig, raw_orig))) + recomp_text.append((index, match_text(recomp))) + + ratio = ratio / float(n_entries) if n_entries > 0 else 0 + + # n=100: Show the entire table if there is a diff to display. + # Otherwise it would be confusing if the table got cut off. + + sm = difflib.SequenceMatcher( + None, + [x[1] for x in orig_text], + [x[1] for x in recomp_text], + ) + + unified_diff = combined_diff(sm, orig_text, recomp_text, context_size=100) + + return DiffReport( + match_type=SymbolType.VTABLE, + orig_addr=match.orig_addr, + recomp_addr=match.recomp_addr, + name=match.name, + udiff=unified_diff, + ratio=ratio, + ) + + def _compare_match(self, match: MatchInfo) -> Optional[DiffReport]: + """Router for comparison type""" + + if match.size is None or match.size == 0: + return None + + options = self._db.get_match_options(match.orig_addr) + if options.get("skip", False): + return None + + if options.get("stub", False): + return DiffReport( + match_type=match.compare_type, + orig_addr=match.orig_addr, + recomp_addr=match.recomp_addr, + name=match.name, + is_stub=True, + ) + + if match.compare_type == SymbolType.FUNCTION: + return self._compare_function(match) + + if match.compare_type == SymbolType.VTABLE: + return self._compare_vtable(match) + + return None + + ## Public API + + def is_pointer_match(self, orig_addr, recomp_addr) -> bool: + """Check whether these pointers point at the same thing""" + + # Null pointers considered matching + if orig_addr == 0 and recomp_addr == 0: + return True + + match = self._db.get_by_orig(orig_addr) + if match is None: + return False + + return match.recomp_addr == recomp_addr + + def get_by_orig(self, addr: int) -> Optional[MatchInfo]: + return self._db.get_by_orig(addr) + + def get_by_recomp(self, addr: int) -> Optional[MatchInfo]: + return self._db.get_by_recomp(addr) + + def get_all(self) -> List[MatchInfo]: + return self._db.get_all() + + def get_functions(self) -> List[MatchInfo]: + return self._db.get_matches_by_type(SymbolType.FUNCTION) + + def get_vtables(self) -> List[MatchInfo]: + return self._db.get_matches_by_type(SymbolType.VTABLE) + + def get_variables(self) -> List[MatchInfo]: + return self._db.get_matches_by_type(SymbolType.DATA) + + def compare_address(self, addr: int) -> Optional[DiffReport]: + match = self._db.get_one_match(addr) + if match is None: + return None + + return self._compare_match(match) + + def compare_all(self) -> Iterable[DiffReport]: + for match in self._db.get_matches(): + diff = self._compare_match(match) + if diff is not None: + yield diff + + def compare_functions(self) -> Iterable[DiffReport]: + for match in self.get_functions(): + diff = self._compare_match(match) + if diff is not None: + yield diff + + def compare_variables(self): + pass + + def compare_pointers(self): + pass + + def compare_strings(self): + pass + + def compare_vtables(self) -> Iterable[DiffReport]: + for match in self.get_vtables(): + diff = self._compare_match(match) + if diff is not None: + yield self._compare_match(match) diff --git a/tools/isledecomp/isledecomp/compare/db.py b/tools/isledecomp/isledecomp/compare/db.py new file mode 100644 index 00000000..634cf455 --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/db.py @@ -0,0 +1,549 @@ +"""Wrapper for database (here an in-memory sqlite database) that collects the +addresses/symbols that we want to compare between the original and recompiled binaries.""" +import sqlite3 +import logging +from typing import List, Optional +from isledecomp.types import SymbolType +from isledecomp.cvdump.demangler import get_vtordisp_name + +_SETUP_SQL = """ + DROP TABLE IF EXISTS `symbols`; + DROP TABLE IF EXISTS `match_options`; + + CREATE TABLE `symbols` ( + compare_type int, + orig_addr int, + recomp_addr int, + name text, + decorated_name text, + size int + ); + + CREATE TABLE `match_options` ( + addr int not null, + name text not null, + value text, + primary key (addr, name) + ) without rowid; + + CREATE VIEW IF NOT EXISTS `match_info` + (compare_type, orig_addr, recomp_addr, name, size) AS + SELECT compare_type, orig_addr, recomp_addr, name, size + FROM `symbols` + ORDER BY orig_addr NULLS LAST; + + CREATE INDEX `symbols_or` ON `symbols` (orig_addr); + CREATE INDEX `symbols_re` ON `symbols` (recomp_addr); + CREATE INDEX `symbols_na` ON `symbols` (name); +""" + + +class MatchInfo: + def __init__( + self, + ctype: Optional[int], + orig: Optional[int], + recomp: Optional[int], + name: Optional[str], + size: Optional[int], + ) -> None: + self.compare_type = SymbolType(ctype) if ctype is not None else None + self.orig_addr = orig + self.recomp_addr = recomp + self.name = name + self.size = size + + def match_name(self) -> Optional[str]: + """Combination of the name and compare type. + Intended for name substitution in the diff. If there is a diff, + it will be more obvious what this symbol indicates.""" + if self.name is None: + return None + + ctype = self.compare_type.name if self.compare_type is not None else "UNK" + name = repr(self.name) if ctype == "STRING" else self.name + return f"{name} ({ctype})" + + def offset_name(self, ofs: int) -> Optional[str]: + if self.name is None: + return None + + return f"{self.name}+{ofs} (OFFSET)" + + +def matchinfo_factory(_, row): + return MatchInfo(*row) + + +logger = logging.getLogger(__name__) + + +class CompareDb: + # pylint: disable=too-many-public-methods + def __init__(self): + self._db = sqlite3.connect(":memory:") + self._db.executescript(_SETUP_SQL) + + def set_orig_symbol( + self, + addr: int, + compare_type: Optional[SymbolType], + name: Optional[str], + size: Optional[int], + ): + # Ignore collisions here. + if self._orig_used(addr): + return + + compare_value = compare_type.value if compare_type is not None else None + self._db.execute( + "INSERT INTO `symbols` (orig_addr, compare_type, name, size) VALUES (?,?,?,?)", + (addr, compare_value, name, size), + ) + + def set_recomp_symbol( + self, + addr: int, + compare_type: Optional[SymbolType], + name: Optional[str], + decorated_name: Optional[str], + size: Optional[int], + ): + # Ignore collisions here. The same recomp address can have + # multiple names (e.g. _strlwr and __strlwr) + if self._recomp_used(addr): + return + + compare_value = compare_type.value if compare_type is not None else None + self._db.execute( + "INSERT INTO `symbols` (recomp_addr, compare_type, name, decorated_name, size) VALUES (?,?,?,?,?)", + (addr, compare_value, name, decorated_name, size), + ) + + def get_unmatched_strings(self) -> List[str]: + """Return any strings not already identified by STRING markers.""" + + cur = self._db.execute( + "SELECT name FROM `symbols` WHERE compare_type = ? AND orig_addr IS NULL", + (SymbolType.STRING.value,), + ) + + return [string for (string,) in cur.fetchall()] + + def get_all(self) -> List[MatchInfo]: + cur = self._db.execute("SELECT * FROM `match_info`") + cur.row_factory = matchinfo_factory + + return cur.fetchall() + + def get_matches(self) -> Optional[MatchInfo]: + cur = self._db.execute( + """SELECT * FROM `match_info` + WHERE orig_addr IS NOT NULL + AND recomp_addr IS NOT NULL + """, + ) + cur.row_factory = matchinfo_factory + + return cur.fetchall() + + def get_one_match(self, addr: int) -> Optional[MatchInfo]: + cur = self._db.execute( + """SELECT * FROM `match_info` + WHERE orig_addr = ? + AND recomp_addr IS NOT NULL + """, + (addr,), + ) + cur.row_factory = matchinfo_factory + return cur.fetchone() + + def _get_closest_orig(self, addr: int) -> Optional[int]: + value = self._db.execute( + """SELECT max(orig_addr) FROM `symbols` + WHERE ? >= orig_addr + LIMIT 1 + """, + (addr,), + ).fetchone() + return value[0] if value is not None else None + + def _get_closest_recomp(self, addr: int) -> Optional[int]: + value = self._db.execute( + """SELECT max(recomp_addr) FROM `symbols` + WHERE ? >= recomp_addr + LIMIT 1 + """, + (addr,), + ).fetchone() + return value[0] if value is not None else None + + def get_by_orig(self, addr: int, exact: bool = True) -> Optional[MatchInfo]: + if not exact and not self._orig_used(addr): + addr = self._get_closest_orig(addr) + if addr is None: + return None + + cur = self._db.execute( + """SELECT * FROM `match_info` + WHERE orig_addr = ? + """, + (addr,), + ) + cur.row_factory = matchinfo_factory + return cur.fetchone() + + def get_by_recomp(self, addr: int, exact: bool = True) -> Optional[MatchInfo]: + if not exact and not self._recomp_used(addr): + addr = self._get_closest_recomp(addr) + if addr is None: + return None + + cur = self._db.execute( + """SELECT * FROM `match_info` + WHERE recomp_addr = ? + """, + (addr,), + ) + cur.row_factory = matchinfo_factory + return cur.fetchone() + + def get_matches_by_type(self, compare_type: SymbolType) -> List[MatchInfo]: + cur = self._db.execute( + """SELECT * FROM `match_info` + WHERE compare_type = ? + AND orig_addr IS NOT NULL + AND recomp_addr IS NOT NULL + """, + (compare_type.value,), + ) + cur.row_factory = matchinfo_factory + + return cur.fetchall() + + def _orig_used(self, addr: int) -> bool: + cur = self._db.execute("SELECT 1 FROM symbols WHERE orig_addr = ?", (addr,)) + return cur.fetchone() is not None + + def _recomp_used(self, addr: int) -> bool: + cur = self._db.execute("SELECT 1 FROM symbols WHERE recomp_addr = ?", (addr,)) + return cur.fetchone() is not None + + def set_pair( + self, orig: int, recomp: int, compare_type: Optional[SymbolType] = None + ) -> bool: + if self._orig_used(orig): + logger.error("Original address %s not unique!", hex(orig)) + return False + + compare_value = compare_type.value if compare_type is not None else None + cur = self._db.execute( + "UPDATE `symbols` SET orig_addr = ?, compare_type = ? WHERE recomp_addr = ?", + (orig, compare_value, recomp), + ) + + return cur.rowcount > 0 + + def set_pair_tentative( + self, orig: int, recomp: int, compare_type: Optional[SymbolType] = None + ) -> bool: + """Declare a match for the original and recomp addresses given, but only if: + 1. The original address is not used elsewhere (as with set_pair) + 2. The recomp address has not already been matched + If the compare_type is given, update this also, but only if NULL in the db. + + The purpose here is to set matches found via some automated analysis + but to not overwrite a match provided by the human operator.""" + if self._orig_used(orig): + # Probable and expected situation. Just ignore it. + return False + + compare_value = compare_type.value if compare_type is not None else None + + cur = self._db.execute( + """UPDATE `symbols` + SET orig_addr = ?, compare_type = coalesce(compare_type, ?) + WHERE recomp_addr = ? + AND orig_addr IS NULL""", + (orig, compare_value, recomp), + ) + + return cur.rowcount > 0 + + def set_function_pair(self, orig: int, recomp: int) -> bool: + """For lineref match or _entry""" + return self.set_pair(orig, recomp, SymbolType.FUNCTION) + + def create_orig_thunk(self, addr: int, name: str) -> bool: + """Create a thunk function reference using the orig address. + We are here because we have a match on the thunked function, + but it is not thunked in the recomp build.""" + + if self._orig_used(addr): + return False + + thunk_name = f"Thunk of '{name}'" + + # Assuming relative jump instruction for thunks (5 bytes) + cur = self._db.execute( + """INSERT INTO `symbols` + (orig_addr, compare_type, name, size) + VALUES (?,?,?,?)""", + (addr, SymbolType.FUNCTION.value, thunk_name, 5), + ) + + return cur.rowcount > 0 + + def create_recomp_thunk(self, addr: int, name: str) -> bool: + """Create a thunk function reference using the recomp address. + We start from the recomp side for this because we are guaranteed + to have full information from the PDB. We can use a regular function + match later to pull in the orig address.""" + + if self._recomp_used(addr): + return False + + thunk_name = f"Thunk of '{name}'" + + # Assuming relative jump instruction for thunks (5 bytes) + cur = self._db.execute( + """INSERT INTO `symbols` + (recomp_addr, compare_type, name, size) + VALUES (?,?,?,?)""", + (addr, SymbolType.FUNCTION.value, thunk_name, 5), + ) + + return cur.rowcount > 0 + + def _set_opt_bool(self, addr: int, option: str, enabled: bool = True): + if enabled: + self._db.execute( + """INSERT OR IGNORE INTO `match_options` + (addr, name) + VALUES (?, ?)""", + (addr, option), + ) + else: + self._db.execute( + """DELETE FROM `match_options` WHERE addr = ? AND name = ?""", + (addr, option), + ) + + def mark_stub(self, orig: int): + self._set_opt_bool(orig, "stub") + + def skip_compare(self, orig: int): + self._set_opt_bool(orig, "skip") + + def get_match_options(self, addr: int) -> Optional[dict]: + cur = self._db.execute( + """SELECT name, value FROM `match_options` WHERE addr = ?""", (addr,) + ) + + return { + option: value if value is not None else True + for (option, value) in cur.fetchall() + } + + def is_vtordisp(self, recomp_addr: int) -> bool: + """Check whether this function is a vtordisp based on its + decorated name. If its demangled name is missing the vtordisp + indicator, correct that.""" + row = self._db.execute( + """SELECT name, decorated_name + FROM `symbols` + WHERE recomp_addr = ?""", + (recomp_addr,), + ).fetchone() + + if row is None: + return False + + (name, decorated_name) = row + if "`vtordisp" in name: + return True + + new_name = get_vtordisp_name(decorated_name) + if new_name is None: + return False + + self._db.execute( + """UPDATE `symbols` + SET name = ? + WHERE recomp_addr = ?""", + (new_name, recomp_addr), + ) + + return True + + def _find_potential_match( + self, name: str, compare_type: SymbolType + ) -> Optional[int]: + """Name lookup""" + match_decorate = compare_type != SymbolType.STRING and name.startswith("?") + if match_decorate: + sql = """ + SELECT recomp_addr + FROM `symbols` + WHERE orig_addr IS NULL + AND decorated_name = ? + AND (compare_type IS NULL OR compare_type = ?) + LIMIT 1 + """ + else: + sql = """ + SELECT recomp_addr + FROM `symbols` + WHERE orig_addr IS NULL + AND name = ? + AND (compare_type IS NULL OR compare_type = ?) + LIMIT 1 + """ + + row = self._db.execute(sql, (name, compare_type.value)).fetchone() + return row[0] if row is not None else None + + def _find_static_variable( + self, variable_name: str, function_sym: str + ) -> Optional[int]: + """Get the recomp address of a static function variable. + Matches using a LIKE clause on the combination of: + 1. The variable name read from decomp marker. + 2. The decorated name of the enclosing function. + For example, the variable "g_startupDelay" from function "IsleApp::Tick" + has symbol: `?g_startupDelay@?1??Tick@IsleApp@@QAEXH@Z@4HA` + The function's decorated name is: `?Tick@IsleApp@@QAEXH@Z`""" + + row = self._db.execute( + """SELECT recomp_addr FROM `symbols` + WHERE decorated_name LIKE '%' || ? || '%' || ? || '%' + AND orig_addr IS NULL + AND (compare_type = ? OR compare_type = ? OR compare_type IS NULL)""", + ( + variable_name, + function_sym, + SymbolType.DATA.value, + SymbolType.POINTER.value, + ), + ).fetchone() + return row[0] if row is not None else None + + def _match_on(self, compare_type: SymbolType, addr: int, name: str) -> bool: + # Update the compare_type here too since the marker tells us what we should do + + # Truncate the name to 255 characters. It will not be possible to match a name + # longer than that because MSVC truncates the debug symbols to this length. + # See also: warning C4786. + name = name[:255] + + logger.debug("Looking for %s %s", compare_type.name.lower(), name) + recomp_addr = self._find_potential_match(name, compare_type) + if recomp_addr is None: + return False + + return self.set_pair(addr, recomp_addr, compare_type) + + def get_next_orig_addr(self, addr: int) -> Optional[int]: + """Return the original address (matched or not) that follows + the one given. If our recomp function size would cause us to read + too many bytes for the original function, we can adjust it.""" + result = self._db.execute( + """SELECT orig_addr + FROM `symbols` + WHERE orig_addr > ? + ORDER BY orig_addr + LIMIT 1""", + (addr,), + ).fetchone() + + return result[0] if result is not None else None + + def match_function(self, addr: int, name: str) -> bool: + did_match = self._match_on(SymbolType.FUNCTION, addr, name) + if not did_match: + logger.error("Failed to find function symbol with name: %s", name) + + return did_match + + def match_vtable( + self, addr: int, name: str, base_class: Optional[str] = None + ) -> bool: + # Set up our potential match names + bare_vftable = f"{name}::`vftable'" + for_name = base_class if base_class is not None else name + for_vftable = f"{name}::`vftable'{{for `{for_name}'}}" + + # Only allow a match against "Class:`vftable'" + # if this is the derived class. + if base_class is None or base_class == name: + name_options = (for_vftable, bare_vftable) + else: + name_options = (for_vftable, for_vftable) + + row = self._db.execute( + """ + SELECT recomp_addr + FROM `symbols` + WHERE orig_addr IS NULL + AND (name = ? OR name = ?) + AND (compare_type = ?) + LIMIT 1 + """, + (*name_options, SymbolType.VTABLE.value), + ).fetchone() + + if row is not None and self.set_pair(addr, row[0], SymbolType.VTABLE): + return True + + logger.error("Failed to find vtable for class: %s", name) + return False + + def match_static_variable(self, addr: int, name: str, function_addr: int) -> bool: + """Matching a static function variable by combining the variable name + with the decorated (mangled) name of its parent function.""" + + cur = self._db.execute( + """SELECT name, decorated_name + FROM `symbols` + WHERE orig_addr = ?""", + (function_addr,), + ) + + if (result := cur.fetchone()) is None: + logger.error("No function for static variable: %s", name) + return False + + # Get the friendly name for the "failed to match" error message + (function_name, decorated_name) = result + + recomp_addr = self._find_static_variable(name, decorated_name) + if recomp_addr is not None: + # TODO: This variable could be a pointer, but I don't think we + # have a way to tell that right now. + if self.set_pair(addr, recomp_addr, SymbolType.DATA): + return True + + logger.error( + "Failed to match static variable %s from function %s", + name, + function_name, + ) + + return False + + def match_variable(self, addr: int, name: str) -> bool: + did_match = self._match_on(SymbolType.DATA, addr, name) or self._match_on( + SymbolType.POINTER, addr, name + ) + if not did_match: + logger.error("Failed to find variable: %s", name) + + return did_match + + def match_string(self, addr: int, value: str) -> bool: + did_match = self._match_on(SymbolType.STRING, addr, value) + if not did_match: + escaped = repr(value) + logger.error("Failed to find string: %s", escaped) + + return did_match diff --git a/tools/isledecomp/isledecomp/compare/diff.py b/tools/isledecomp/isledecomp/compare/diff.py new file mode 100644 index 00000000..ad453191 --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/diff.py @@ -0,0 +1,98 @@ +from difflib import SequenceMatcher +from typing import Dict, List, Tuple + +CombinedDiffInput = List[Tuple[str, str]] +CombinedDiffOutput = List[Tuple[str, List[Dict[str, Tuple[str, str]]]]] + + +def combined_diff( + diff: SequenceMatcher, + orig_combined: CombinedDiffInput, + recomp_combined: CombinedDiffInput, + context_size: int = 3, +) -> CombinedDiffOutput: + """We want to diff the original and recomp assembly. The "combined" assembly + input has two components: the address of the instruction and the assembly text. + We have already diffed the text only. This is the SequenceMatcher object. + The SequenceMatcher can generate "opcodes" that describe how to turn "Text A" + into "Text B". These refer to list indices of the original arrays, so we can + use those to create the final diff and include the address for each line of assembly. + This is almost the same procedure as the difflib.unified_diff function, but we + are reusing the already generated SequenceMatcher object. + """ + + unified_diff = [] + + for group in diff.get_grouped_opcodes(context_size): + subgroups = [] + + # Keep track of the addresses we've seen in this diff group. + # This helps create the "@@" line. (Does this have a name?) + # Do it this way because not every line in each list will have an + # address. If our context begins or ends on a line that does not + # have one, we will have an incomplete range string. + orig_addrs = set() + recomp_addrs = set() + + first, last = group[0], group[-1] + orig_range = len(orig_combined[first[1] : last[2]]) + recomp_range = len(recomp_combined[first[3] : last[4]]) + + for code, i1, i2, j1, j2 in group: + if code == "equal": + # The sections are equal, so the list slices are guaranteed + # to have the same length. We only need the diffed value (asm text) + # from one of the lists, but we need the addresses from both. + # Use zip to put the two lists together and then take out what we want. + both = [ + (a, b, c) + for ((a, b), (c, _)) in zip( + orig_combined[i1:i2], recomp_combined[j1:j2] + ) + ] + + for orig_addr, _, recomp_addr in both: + if orig_addr is not None: + orig_addrs.add(orig_addr) + + if recomp_addr is not None: + recomp_addrs.add(recomp_addr) + + subgroups.append({"both": both}) + else: + for orig_addr, _ in orig_combined[i1:i2]: + if orig_addr is not None: + orig_addrs.add(orig_addr) + + for recomp_addr, _ in recomp_combined[j1:j2]: + if recomp_addr is not None: + recomp_addrs.add(recomp_addr) + + subgroups.append( + { + "orig": orig_combined[i1:i2], + "recomp": recomp_combined[j1:j2], + } + ) + + orig_sorted = sorted(orig_addrs) + recomp_sorted = sorted(recomp_addrs) + + # We could get a diff group that has no original addresses. + # This might happen for a stub function where we are not able to + # produce even a single instruction from the original. + # In that case, show the best slug line that we can. + def peek_front(list_, default=""): + try: + return list_[0] + except IndexError: + return default + + orig_first = peek_front(orig_sorted) + recomp_first = peek_front(recomp_sorted) + + diff_slug = f"@@ -{orig_first},{orig_range} +{recomp_first},{recomp_range} @@" + + unified_diff.append((diff_slug, subgroups)) + + return unified_diff diff --git a/tools/isledecomp/isledecomp/compare/lines.py b/tools/isledecomp/isledecomp/compare/lines.py new file mode 100644 index 00000000..0e9c4332 --- /dev/null +++ b/tools/isledecomp/isledecomp/compare/lines.py @@ -0,0 +1,69 @@ +"""Database used to match (filename, line_number) pairs +between FUNCTION markers and PDB analysis.""" +import sqlite3 +import logging +from functools import cache +from typing import Optional +from pathlib import Path +from isledecomp.dir import PathResolver + + +_SETUP_SQL = """ + DROP TABLE IF EXISTS `lineref`; + CREATE TABLE `lineref` ( + path text not null, + filename text not null, + line int not null, + addr int not null + ); + CREATE INDEX `file_line` ON `lineref` (filename, line); +""" + + +logger = logging.getLogger(__name__) + + +@cache +def my_samefile(path: str, source_path: str) -> bool: + return Path(path).samefile(source_path) + + +@cache +def my_basename_lower(path: str) -> str: + return Path(path).name.lower() + + +class LinesDb: + def __init__(self, code_dir) -> None: + self._db = sqlite3.connect(":memory:") + self._db.executescript(_SETUP_SQL) + self._path_resolver = PathResolver(code_dir) + + def add_line(self, path: str, line_no: int, addr: int): + """To be added from the LINES section of cvdump.""" + sourcepath = self._path_resolver.resolve_cvdump(path) + filename = my_basename_lower(sourcepath) + + self._db.execute( + "INSERT INTO `lineref` (path, filename, line, addr) VALUES (?,?,?,?)", + (sourcepath, filename, line_no, addr), + ) + + def search_line(self, path: str, line_no: int) -> Optional[int]: + """Using path and line number from FUNCTION marker, + get the address of this function in the recomp.""" + filename = my_basename_lower(path) + cur = self._db.execute( + "SELECT path, addr FROM `lineref` WHERE filename = ? AND line = ?", + (filename, line_no), + ) + for source_path, addr in cur.fetchall(): + if my_samefile(path, source_path): + return addr + + logger.error( + "Failed to find function symbol with filename and line: %s:%d", + path, + line_no, + ) + return None diff --git a/tools/isledecomp/isledecomp/cvdump/__init__.py b/tools/isledecomp/isledecomp/cvdump/__init__.py new file mode 100644 index 00000000..8e1fd78a --- /dev/null +++ b/tools/isledecomp/isledecomp/cvdump/__init__.py @@ -0,0 +1,4 @@ +from .analysis import CvdumpAnalysis +from .parser import CvdumpParser +from .runner import Cvdump +from .types import CvdumpTypesParser diff --git a/tools/isledecomp/isledecomp/cvdump/analysis.py b/tools/isledecomp/isledecomp/cvdump/analysis.py new file mode 100644 index 00000000..bd8734fa --- /dev/null +++ b/tools/isledecomp/isledecomp/cvdump/analysis.py @@ -0,0 +1,178 @@ +"""For collating the results from parsing cvdump.exe into a more directly useful format.""" +from typing import Dict, List, Tuple, Optional +from isledecomp.types import SymbolType +from .parser import CvdumpParser +from .demangler import demangle_string_const, demangle_vtable +from .types import CvdumpKeyError, CvdumpIntegrityError + + +class CvdumpNode: + # pylint: disable=too-many-instance-attributes + # These two are required and allow us to identify the symbol + section: int + offset: int + # aka the mangled name from the PUBLICS section + decorated_name: Optional[str] = None + # optional "nicer" name (e.g. of a function from SYMBOLS section) + friendly_name: Optional[str] = None + # To be determined by context after inserting data, unless the decorated + # name makes this obvious. (i.e. string constants or vtables) + # We choose not to assume that section 1 (probably ".text") contains only + # functions. Smacker functions are linked to their own section "_UNSTEXT" + node_type: Optional[SymbolType] = None + # Function size can be read from the LINES section so use this over any + # other value if we have it. + # TYPES section can tell us the size of structs and other complex types. + confirmed_size: Optional[int] = None + # Estimated by reading the distance between this symbol and the one that + # follows in the same section. + # If this is the last symbol in the section, we cannot estimate a size. + estimated_size: Optional[int] = None + # Size as reported by SECTION CONTRIBUTIONS section. Not guaranteed to be + # accurate. + section_contribution: Optional[int] = None + + def __init__(self, section: int, offset: int) -> None: + self.section = section + self.offset = offset + + def set_decorated(self, name: str): + self.decorated_name = name + + if self.decorated_name.startswith("??_7"): + self.node_type = SymbolType.VTABLE + self.friendly_name = demangle_vtable(self.decorated_name) + + elif self.decorated_name.startswith("??_8"): + # This is the `vbtable' symbol for virtual inheritance. + # Should be okay to reuse demangle_vtable. We still want to + # remove things like "const" from the output. + self.node_type = SymbolType.DATA + self.friendly_name = demangle_vtable(self.decorated_name) + + elif self.decorated_name.startswith("??_C@"): + self.node_type = SymbolType.STRING + (strlen, _) = demangle_string_const(self.decorated_name) + self.confirmed_size = strlen + + elif not self.decorated_name.startswith("?") and "@" in self.decorated_name: + # C mangled symbol. The trailing at-sign with number tells the number of bytes + # in the parameter list for __stdcall, __fastcall, or __vectorcall + # For __cdecl it is more ambiguous and we would have to know which section we are in. + # https://learn.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170#FormatC + self.node_type = SymbolType.FUNCTION + + def name(self) -> Optional[str]: + """Prefer "friendly" name if we have it. + This is what we have been using to match functions.""" + return ( + self.friendly_name + if self.friendly_name is not None + else self.decorated_name + ) + + def size(self) -> Optional[int]: + if self.confirmed_size is not None: + return self.confirmed_size + + # Better to undershoot the size because we can identify a comparison gap easily + if self.estimated_size is not None and self.section_contribution is not None: + return min(self.estimated_size, self.section_contribution) + + # Return whichever one we have, or neither + return self.estimated_size or self.section_contribution + + +class CvdumpAnalysis: + """Collects the results from CvdumpParser into a list of nodes (i.e. symbols). + These can then be analyzed by a downstream tool.""" + + nodes = List[CvdumpNode] + verified_lines = Dict[Tuple[str, str], Tuple[str, str]] + + def __init__(self, parser: CvdumpParser): + """Read in as much information as we have from the parser. + The more sections we have, the better our information will be.""" + node_dict = {} + + # PUBLICS is our roadmap for everything that follows. + for pub in parser.publics: + key = (pub.section, pub.offset) + if key not in node_dict: + node_dict[key] = CvdumpNode(*key) + + node_dict[key].set_decorated(pub.name) + + for sizeref in parser.sizerefs: + key = (sizeref.section, sizeref.offset) + if key not in node_dict: + node_dict[key] = CvdumpNode(*key) + + node_dict[key].section_contribution = sizeref.size + + for glo in parser.globals: + key = (glo.section, glo.offset) + if key not in node_dict: + node_dict[key] = CvdumpNode(*key) + + node_dict[key].node_type = SymbolType.DATA + node_dict[key].friendly_name = glo.name + + try: + # Check our types database for type information. + # If we did not parse the TYPES section, we can only + # get information for built-in "T_" types. + g_info = parser.types.get(glo.type) + node_dict[key].confirmed_size = g_info.size + # Previously we set the symbol type to POINTER here if + # the variable was known to be a pointer. We can derive this + # information later when it's time to compare the variable, + # so let's set these to symbol type DATA instead. + # POINTER will be reserved for non-variable pointer data. + # e.g. thunks, unwind section. + except (CvdumpKeyError, CvdumpIntegrityError): + # No big deal if we don't have complete type information. + pass + + for key, _ in parser.lines.items(): + # Here we only set if the section:offset already exists + # because our values include offsets inside of the function. + if key in node_dict: + node_dict[key].node_type = SymbolType.FUNCTION + + # The LINES section contains every code line in the file, naturally. + # There isn't an obvious separation between functions, so we have to + # read everything. However, any function that would be in LINES + # has to be somewhere else in the PDB (probably PUBLICS). + # Isolate the lines that we actually care about for matching. + self.verified_lines = { + key: value for (key, value) in parser.lines.items() if key in node_dict + } + + for sym in parser.symbols: + key = (sym.section, sym.offset) + if key not in node_dict: + node_dict[key] = CvdumpNode(*key) + + if sym.type == "S_GPROC32": + node_dict[key].friendly_name = sym.name + node_dict[key].confirmed_size = sym.size + node_dict[key].node_type = SymbolType.FUNCTION + + self.nodes = [v for _, v in dict(sorted(node_dict.items())).items()] + self._estimate_size() + + def _estimate_size(self): + """Get the distance between one section:offset value and the next one + in the same section. This gives a rough estimate of the size of the symbol. + If we have information from SECTION CONTRIBUTIONS, take whichever one is + less to get the best approximate size.""" + for i in range(len(self.nodes) - 1): + this_node = self.nodes[i] + next_node = self.nodes[i + 1] + + # If they are in different sections, we can't compare them + if this_node.section != next_node.section: + continue + + this_node.estimated_size = next_node.offset - this_node.offset diff --git a/tools/isledecomp/isledecomp/cvdump/demangler.py b/tools/isledecomp/isledecomp/cvdump/demangler.py new file mode 100644 index 00000000..9b2445da --- /dev/null +++ b/tools/isledecomp/isledecomp/cvdump/demangler.py @@ -0,0 +1,121 @@ +"""For demangling a subset of MSVC mangled symbols. +Some unofficial information about the mangling scheme is here: +https://en.wikiversity.org/wiki/Visual_C%2B%2B_name_mangling +""" +import re +from collections import namedtuple +from typing import Optional +import pydemangler + + +class InvalidEncodedNumberError(Exception): + pass + + +_encoded_number_translate = str.maketrans("ABCDEFGHIJKLMNOP", "0123456789ABCDEF") + + +def parse_encoded_number(string: str) -> int: + # TODO: assert string ends in "@"? + if string.endswith("@"): + string = string[:-1] + + try: + return int(string.translate(_encoded_number_translate), 16) + except ValueError as e: + raise InvalidEncodedNumberError(string) from e + + +string_const_regex = re.compile( + r"\?\?_C@\_(?P[0-1])(?P\d|[A-P]+@)(?P\w+)@(?P.+)@" +) +StringConstInfo = namedtuple("StringConstInfo", "len is_utf16") + + +def demangle_string_const(symbol: str) -> Optional[StringConstInfo]: + """Don't bother to decode the string text from the symbol. + We can just read it from the binary once we have the length.""" + match = string_const_regex.match(symbol) + if match is None: + return None + + try: + strlen = ( + parse_encoded_number(match.group("len")) + if "@" in match.group("len") + else int(match.group("len")) + ) + except (ValueError, InvalidEncodedNumberError): + return None + + is_utf16 = match.group("is_utf16") == "1" + return StringConstInfo(len=strlen, is_utf16=is_utf16) + + +def get_vtordisp_name(symbol: str) -> Optional[str]: + # pylint: disable=c-extension-no-member + """For adjuster thunk functions, the PDB will sometimes use a name + that contains "vtordisp" but often will just reuse the name of the + function being thunked. We want to use the vtordisp name if possible.""" + name = pydemangler.demangle(symbol) + if name is None: + return None + + if "`vtordisp" not in name: + return None + + # Now we remove the parts of the friendly name that we don't need + try: + # Assuming this is the last of the function prefixes + thiscall_idx = name.index("__thiscall") + # To match the end of the `vtordisp{x,y}' string + end_idx = name.index("}'") + return name[thiscall_idx + 11 : end_idx + 2] + except ValueError: + return name + + +def demangle_vtable(symbol: str) -> str: + # pylint: disable=c-extension-no-member + """Get the class name referenced in the vtable symbol.""" + raw = pydemangler.demangle(symbol) + + if raw is None: + pass # TODO: This shouldn't happen if MSVC behaves + + # Remove storage class and other stuff we don't care about + return ( + raw.replace(" str: + """Parked implementation of MSVC symbol demangling. + We only use this for vtables and it works okay with the simple cases or + templates that refer to other classes/structs. Some namespace support. + Does not support backrefs, primitive types, or vtables with + virtual inheritance.""" + + # Seek ahead 4 chars to strip off "??_7" prefix + t = symbol[4:].split("@") + # "?$" indicates a template class + if t[0].startswith("?$"): + class_name = t[0][2:] + # PA = Pointer/reference + # V or U = class or struct + if t[1].startswith("PA"): + generic = f"{t[1][3:]} *" + else: + generic = t[1][1:] + + return f"{class_name}<{generic}>::`vftable'" + + # If we have two classes listed, it is a namespace hierarchy. + # @@6B@ is a common generic suffix for these vtable symbols. + if t[1] != "" and t[1] != "6B": + return t[1] + "::" + t[0] + "::`vftable'" + + return t[0] + "::`vftable'" diff --git a/tools/isledecomp/isledecomp/cvdump/parser.py b/tools/isledecomp/isledecomp/cvdump/parser.py new file mode 100644 index 00000000..1b1eb3fd --- /dev/null +++ b/tools/isledecomp/isledecomp/cvdump/parser.py @@ -0,0 +1,199 @@ +import re +from typing import Iterable, Tuple +from collections import namedtuple +from .types import CvdumpTypesParser + +# e.g. `*** PUBLICS` +_section_change_regex = re.compile(r"\*\*\* (?P
[A-Z/ ]{2,})") + +# e.g. ` 27 00034EC0 28 00034EE2 29 00034EE7 30 00034EF4` +_line_addr_pairs_findall = re.compile(r"\s+(?P\d+) (?P[A-F0-9]{8})") + +# We assume no spaces in the file name +# e.g. ` Z:\lego-island\isle\LEGO1\viewmanager\viewroi.cpp (None), 0001:00034E90-00034E97, line/addr pairs = 2` +_lines_subsection_header = re.compile( + r"^\s*(?P\S+).*?, (?P
[A-F0-9]{4}):(?P[A-F0-9]{8})-(?P[A-F0-9]{8}), line/addr pairs = (?P\d+)" +) + +# e.g. `S_PUB32: [0001:0003FF60], Flags: 00000000, __read` +_publics_line_regex = re.compile( + r"^(?P\w+): \[(?P
\w{4}):(?P\w{8})], Flags: (?P\w{8}), (?P\S+)" +) + +# e.g. `(00008C) S_GPROC32: [0001:00034E90], Cb: 00000007, Type: 0x1024, ViewROI::IntrinsicImportance` +_symbol_line_regex = re.compile( + r"\(\w+\) (?P\S+): \[(?P
\w{4}):(?P\w{8})\], Cb: (?P\w+), Type:\s+\S+, (?P.+)" +) + +# e.g. ` Debug start: 00000008, Debug end: 0000016E` +_gproc_debug_regex = re.compile( + r"\s*Debug start: (?P\w{8}), Debug end: (?P\w{8})" +) + +# e.g. ` 00DA 0001:00000000 00000073 60501020` +_section_contrib_regex = re.compile( + r"\s*(?P\w{4}) (?P
\w{4}):(?P\w{8}) (?P\w{8}) (?P\w{8})" +) + +# e.g. `S_GDATA32: [0003:000004A4], Type: T_32PRCHAR(0470), g_set` +_gdata32_regex = re.compile( + r"S_GDATA32: \[(?P
\w{4}):(?P\w{8})\], Type:\s*(?P\S+), (?P.+)" +) + +# e.g. 0003 "CMakeFiles/isle.dir/ISLE/res/isle.rc.res" +# e.g. 0004 "C:\work\lego-island\isle\3rdparty\smartheap\SHLW32MT.LIB" "check.obj" +_module_regex = re.compile(r"(?P\w{4})(?: \"(?P.+?)\")?(?: \"(?P.+?)\")") + +# User functions only +LinesEntry = namedtuple("LinesEntry", "filename line_no section offset") + +# Strings, vtables, functions +# superset of everything else +# only place you can find the C symbols (library functions, smacker, etc) +PublicsEntry = namedtuple("PublicsEntry", "type section offset flags name") + +# S_GPROC32 = functions +SymbolsEntry = namedtuple("SymbolsEntry", "type section offset size name") + +# (Estimated) size of any symbol +SizeRefEntry = namedtuple("SizeRefEntry", "module section offset size") + +# global variables +GdataEntry = namedtuple("GdataEntry", "section offset type name") + +ModuleEntry = namedtuple("ModuleEntry", "id lib obj") + + +class CvdumpParser: + # pylint: disable=too-many-instance-attributes + def __init__(self) -> None: + self._section: str = "" + self._lines_function: Tuple[str, int] = ("", 0) + + self.lines = {} + self.publics = [] + self.symbols = [] + self.sizerefs = [] + self.globals = [] + self.modules = [] + + self.types = CvdumpTypesParser() + + def _lines_section(self, line: str): + """Parsing entries from the LINES section. We only care about the pairs of + line_number and address and the subsection header to indicate which code file + we are in.""" + + # Subheader indicates a new function and possibly a new code filename. + # Save the section here because it is not given on the lines that follow. + if (match := _lines_subsection_header.match(line)) is not None: + self._lines_function = ( + match.group("filename"), + int(match.group("section"), 16), + ) + return + + # Match any pairs as we find them + for line_no, offset in _line_addr_pairs_findall.findall(line): + key = (self._lines_function[1], int(offset, 16)) + self.lines[key] = (self._lines_function[0], int(line_no)) + + def _publics_section(self, line: str): + """Match each line from PUBLICS and pull out the symbol information. + These are MSVC mangled symbol names. String constants and vtable + addresses can only be found here.""" + if (match := _publics_line_regex.match(line)) is not None: + self.publics.append( + PublicsEntry( + type=match.group("type"), + section=int(match.group("section"), 16), + offset=int(match.group("offset"), 16), + flags=int(match.group("flags"), 16), + name=match.group("name"), + ) + ) + + def _globals_section(self, line: str): + """S_PROCREF may be useful later. + Right now we just want S_GDATA32 symbols because it is the simplest + way to access global variables.""" + if (match := _gdata32_regex.match(line)) is not None: + self.globals.append( + GdataEntry( + section=int(match.group("section"), 16), + offset=int(match.group("offset"), 16), + type=match.group("type"), + name=match.group("name"), + ) + ) + + def _symbols_section(self, line: str): + """We are interested in S_GPROC32 symbols only.""" + if (match := _symbol_line_regex.match(line)) is not None: + if match.group("type") == "S_GPROC32": + self.symbols.append( + SymbolsEntry( + type=match.group("type"), + section=int(match.group("section"), 16), + offset=int(match.group("offset"), 16), + size=int(match.group("size"), 16), + name=match.group("name"), + ) + ) + + def _section_contributions(self, line: str): + """Gives the size of elements across all sections of the binary. + This is the easiest way to get the data size for .data and .rdata + members that do not have a primitive data type.""" + if (match := _section_contrib_regex.match(line)) is not None: + self.sizerefs.append( + SizeRefEntry( + module=int(match.group("module"), 16), + section=int(match.group("section"), 16), + offset=int(match.group("offset"), 16), + size=int(match.group("size"), 16), + ) + ) + + def _modules_section(self, line: str): + """Record the object file (and lib file, if used) linked into the binary. + The auto-incrementing id is cross-referenced in SECTION CONTRIBUTIONS + (and perhaps other locations)""" + if (match := _module_regex.match(line)) is not None: + self.modules.append( + ModuleEntry( + id=int(match.group("id"), 16), + lib=match.group("lib"), + obj=match.group("obj"), + ) + ) + + def read_line(self, line: str): + if (match := _section_change_regex.match(line)) is not None: + self._section = match.group(1) + return + + if self._section == "TYPES": + self.types.read_line(line) + + elif self._section == "SYMBOLS": + self._symbols_section(line) + + elif self._section == "LINES": + self._lines_section(line) + + elif self._section == "PUBLICS": + self._publics_section(line) + + elif self._section == "SECTION CONTRIBUTIONS": + self._section_contributions(line) + + elif self._section == "GLOBALS": + self._globals_section(line) + + elif self._section == "MODULES": + self._modules_section(line) + + def read_lines(self, lines: Iterable[str]): + for line in lines: + self.read_line(line) diff --git a/tools/isledecomp/isledecomp/cvdump/runner.py b/tools/isledecomp/isledecomp/cvdump/runner.py new file mode 100644 index 00000000..9463acfa --- /dev/null +++ b/tools/isledecomp/isledecomp/cvdump/runner.py @@ -0,0 +1,83 @@ +import io +from os import name as os_name +from enum import Enum +from typing import List +import subprocess +from isledecomp.lib import lib_path_join +from isledecomp.dir import winepath_unix_to_win +from .parser import CvdumpParser + + +class DumpOpt(Enum): + LINES = 0 + SYMBOLS = 1 + GLOBALS = 2 + PUBLICS = 3 + SECTION_CONTRIB = 4 + MODULES = 5 + TYPES = 6 + + +cvdump_opt_map = { + DumpOpt.LINES: "-l", + DumpOpt.SYMBOLS: "-s", + DumpOpt.GLOBALS: "-g", + DumpOpt.PUBLICS: "-p", + DumpOpt.SECTION_CONTRIB: "-seccontrib", + DumpOpt.MODULES: "-m", + DumpOpt.TYPES: "-t", +} + + +class Cvdump: + def __init__(self, pdb: str) -> None: + self._pdb: str = pdb + self._options = set() + + def lines(self): + self._options.add(DumpOpt.LINES) + return self + + def symbols(self): + self._options.add(DumpOpt.SYMBOLS) + return self + + def globals(self): + self._options.add(DumpOpt.GLOBALS) + return self + + def publics(self): + self._options.add(DumpOpt.PUBLICS) + return self + + def section_contributions(self): + self._options.add(DumpOpt.SECTION_CONTRIB) + return self + + def modules(self): + self._options.add(DumpOpt.MODULES) + return self + + def types(self): + self._options.add(DumpOpt.TYPES) + return self + + def cmd_line(self) -> List[str]: + cvdump_exe = lib_path_join("cvdump.exe") + flags = [cvdump_opt_map[opt] for opt in self._options] + + if os_name == "nt": + return [cvdump_exe, *flags, self._pdb] + + return ["wine", cvdump_exe, *flags, winepath_unix_to_win(self._pdb)] + + def run(self) -> CvdumpParser: + parser = CvdumpParser() + call = self.cmd_line() + with subprocess.Popen(call, stdout=subprocess.PIPE) as proc: + for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): + # Blank lines are there to help the reader; they have no context significance + if line != "\n": + parser.read_line(line) + + return parser diff --git a/tools/isledecomp/isledecomp/cvdump/types.py b/tools/isledecomp/isledecomp/cvdump/types.py new file mode 100644 index 00000000..547d3ce9 --- /dev/null +++ b/tools/isledecomp/isledecomp/cvdump/types.py @@ -0,0 +1,453 @@ +import re +from typing import Dict, List, NamedTuple, Optional + + +class CvdumpTypeError(Exception): + pass + + +class CvdumpKeyError(KeyError): + pass + + +class CvdumpIntegrityError(Exception): + pass + + +class FieldListItem(NamedTuple): + """Member of a class or structure""" + + offset: int + name: str + type: str + + +class ScalarType(NamedTuple): + offset: int + name: Optional[str] + type: str + + @property + def size(self) -> int: + return scalar_type_size(self.type) + + @property + def format_char(self) -> str: + return scalar_type_format_char(self.type) + + @property + def is_pointer(self) -> bool: + return scalar_type_pointer(self.type) + + +class TypeInfo(NamedTuple): + key: str + size: int + name: Optional[str] = None + members: Optional[List[FieldListItem]] = None + + def is_scalar(self) -> bool: + # TODO: distinction between a class with zero members and no vtable? + return self.members is None + + +def normalize_type_id(key: str) -> str: + """Helper for TYPES parsing to ensure a consistent format. + If key begins with "T_" it is a built-in type. + Else it is a hex string. We prefer lower case letters and + no leading zeroes. (UDT identifier pads to 8 characters.)""" + if key[0] == "0": + return f"0x{key[-4:].lower()}" + + # Remove numeric value for "T_" type. We don't use this. + return key.partition("(")[0] + + +def scalar_type_pointer(type_name: str) -> bool: + return type_name.startswith("T_32P") + + +def scalar_type_size(type_name: str) -> int: + if scalar_type_pointer(type_name): + return 4 + + if "CHAR" in type_name: + return 2 if "WCHAR" in type_name else 1 + + if "SHORT" in type_name: + return 2 + + if "QUAD" in type_name or "64" in type_name: + return 8 + + return 4 + + +def scalar_type_signed(type_name: str) -> bool: + if scalar_type_pointer(type_name): + return False + + # According to cvinfo.h, T_WCHAR is unsigned + return not type_name.startswith("T_U") and not type_name.startswith("T_W") + + +def scalar_type_format_char(type_name: str) -> str: + if scalar_type_pointer(type_name): + return "L" + + # "Really a char" + if type_name.startswith("T_RCHAR"): + return "c" + + # floats + if type_name.startswith("T_REAL"): + return "d" if "64" in type_name else "f" + + size = scalar_type_size(type_name) + char = ({1: "b", 2: "h", 4: "l", 8: "q"}).get(size, "l") + + return char if scalar_type_signed(type_name) else char.upper() + + +def member_list_to_struct_string(members: List[ScalarType]) -> str: + """Create a string for use with struct.unpack""" + + format_string = "".join(m.format_char for m in members) + if len(format_string) > 0: + return "<" + format_string + + return "" + + +def join_member_names(parent: str, child: Optional[str]) -> str: + """Helper method to combine parent/child member names. + Child member name is None if the child is a scalar type.""" + + if child is None: + return parent + + # If the child is an array index, join without the dot + if child.startswith("["): + return f"{parent}{child}" + + return f"{parent}.{child}" + + +class CvdumpTypesParser: + """Parser for cvdump output, TYPES section. + Tricky enough that it demands its own parser.""" + + # Marks the start of a new type + INDEX_RE = re.compile(r"(?P0x\w+) : .* (?PLF_\w+)") + + # LF_FIELDLIST class/struct member (1/2) + LIST_RE = re.compile( + r"\s+list\[\d+\] = LF_MEMBER, (?P\w+), type = (?P.*), offset = (?P\d+)" + ) + + # LF_FIELDLIST vtable indicator + VTABLE_RE = re.compile(r"^\s+list\[\d+\] = LF_VFUNCTAB") + + # LF_FIELDLIST superclass indicator + SUPERCLASS_RE = re.compile( + r"^\s+list\[\d+\] = LF_BCLASS, (?P\w+), type = (?P.*), offset = (?P\d+)" + ) + + # LF_FIELDLIST member name (2/2) + MEMBER_RE = re.compile(r"^\s+member name = '(?P.*)'$") + + # LF_ARRAY element type + ARRAY_ELEMENT_RE = re.compile(r"^\s+Element type = (?P.*)") + + # LF_ARRAY total array size + ARRAY_LENGTH_RE = re.compile(r"^\s+length = (?P\d+)") + + # LF_CLASS/LF_STRUCTURE field list reference + CLASS_FIELD_RE = re.compile( + r"^\s+# members = \d+, field list type (?P0x\w+)," + ) + + # LF_CLASS/LF_STRUCTURE name and other info + CLASS_NAME_RE = re.compile( + r"^\s+Size = (?P\d+), class name = (?P.+), UDT\((?P0x\w+)\)" + ) + + # LF_MODIFIER, type being modified + MODIFIES_RE = re.compile(r".*modifies type (?P.*)$") + + MODES_OF_INTEREST = { + "LF_ARRAY", + "LF_CLASS", + "LF_ENUM", + "LF_FIELDLIST", + "LF_MODIFIER", + "LF_POINTER", + "LF_STRUCTURE", + } + + def __init__(self) -> None: + self.mode: Optional[str] = None + self.last_key = "" + self.keys = {} + + def _new_type(self): + """Prepare a new dict for the type we just parsed. + The id is self.last_key and the "type" of type is self.mode. + e.g. LF_CLASS""" + self.keys[self.last_key] = {"type": self.mode} + + def _set(self, key: str, value): + self.keys[self.last_key][key] = value + + def _add_member(self, offset: int, type_: str): + obj = self.keys[self.last_key] + if "members" not in obj: + obj["members"] = [] + + obj["members"].append({"offset": offset, "type": type_}) + + def _set_member_name(self, name: str): + """Set name for most recently added member.""" + obj = self.keys[self.last_key] + obj["members"][-1]["name"] = name + + def _get_field_list(self, type_obj: Dict) -> List[FieldListItem]: + """Return the field list for the given LF_CLASS/LF_STRUCTURE reference""" + + if type_obj.get("type") == "LF_FIELDLIST": + field_obj = type_obj + else: + field_list_type = type_obj.get("field_list_type") + field_obj = self.keys[field_list_type] + + members: List[FieldListItem] = [] + + super_id = field_obj.get("super") + if super_id is not None: + # May need to resolve forward ref. + superclass = self.get(super_id) + if superclass.members is not None: + members = superclass.members + + raw_members = field_obj.get("members", []) + members += [ + FieldListItem( + offset=m["offset"], + type=m["type"], + name=m["name"], + ) + for m in raw_members + ] + + return sorted(members, key=lambda m: m.offset) + + def _mock_array_members(self, type_obj: Dict) -> List[FieldListItem]: + """LF_ARRAY elements provide the element type and the total size. + We want the list of "members" as if this was a struct.""" + + if type_obj.get("type") != "LF_ARRAY": + raise CvdumpTypeError("Type is not an LF_ARRAY") + + array_type = type_obj.get("array_type") + if array_type is None: + raise CvdumpIntegrityError("No array element type") + + array_element_size = self.get(array_type).size + + n_elements = type_obj["size"] // array_element_size + + return [ + FieldListItem( + offset=i * array_element_size, + type=array_type, + name=f"[{i}]", + ) + for i in range(n_elements) + ] + + def get(self, type_key: str) -> TypeInfo: + """Convert our dictionary values read from the cvdump output + into a consistent format for the given type.""" + + # Scalar type. Handled here because it makes the recursive steps + # much simpler. + if type_key.startswith("T_"): + size = scalar_type_size(type_key) + return TypeInfo( + key=type_key, + size=size, + ) + + # Go to our dictionary to find it. + obj = self.keys.get(type_key.lower()) + if obj is None: + raise CvdumpKeyError(type_key) + + # These type references are just a wrapper around a scalar + if obj.get("type") == "LF_ENUM": + return self.get("T_INT4") + + if obj.get("type") == "LF_POINTER": + return self.get("T_32PVOID") + + if obj.get("is_forward_ref", False): + # Get the forward reference to follow. + # If this is LF_CLASS/LF_STRUCTURE, it is the UDT value. + # For LF_MODIFIER, it is the type being modified. + forward_ref = obj.get("udt", None) or obj.get("modifies", None) + if forward_ref is None: + raise CvdumpIntegrityError(f"Null forward ref for type {type_key}") + + return self.get(forward_ref) + + # Else it is not a forward reference, so build out the object here. + if obj.get("type") == "LF_ARRAY": + members = self._mock_array_members(obj) + else: + members = self._get_field_list(obj) + + return TypeInfo( + key=type_key, + size=obj.get("size"), + name=obj.get("name"), + members=members, + ) + + def get_by_name(self, name: str) -> TypeInfo: + """Find the complex type with the given name.""" + # TODO + raise NotImplementedError + + def get_scalars(self, type_key: str) -> List[ScalarType]: + """Reduce the given type to a list of scalars so we can + compare each component value.""" + + obj = self.get(type_key) + if obj.is_scalar(): + # Use obj.key here for alias types like LF_POINTER + return [ScalarType(offset=0, type=obj.key, name=None)] + + # mypy? + assert obj.members is not None + + # Dedupe repeated offsets if this is a union type + unique_offsets = {m.offset: m for m in obj.members} + unique_members = [m for _, m in unique_offsets.items()] + + return [ + ScalarType( + offset=m.offset + cm.offset, + type=cm.type, + name=join_member_names(m.name, cm.name), + ) + for m in unique_members + for cm in self.get_scalars(m.type) + ] + + def get_scalars_gapless(self, type_key: str) -> List[ScalarType]: + """Reduce the given type to a list of scalars so we can + compare each component value.""" + + obj = self.get(type_key) + total_size = obj.size + + scalars = self.get_scalars(type_key) + + output = [] + last_extent = total_size + + # Walk the scalar list in reverse; we assume a gap could not + # come at the start of the struct. + for scalar in scalars[::-1]: + this_extent = scalar.offset + scalar_type_size(scalar.type) + size_diff = last_extent - this_extent + # We need to add the gap fillers in reverse here + for i in range(size_diff - 1, -1, -1): + # Push to front + output.insert( + 0, + ScalarType( + offset=this_extent + i, + name="(padding)", + type="T_UCHAR", + ), + ) + + output.insert(0, scalar) + last_extent = scalar.offset + + return output + + def get_format_string(self, type_key: str) -> str: + members = self.get_scalars_gapless(type_key) + return member_list_to_struct_string(members) + + def read_line(self, line: str): + if (match := self.INDEX_RE.match(line)) is not None: + type_ = match.group(2) + if type_ not in self.MODES_OF_INTEREST: + self.mode = None + return + + # Don't need to normalize, it's already in the format we want + self.last_key = match.group(1) + self.mode = type_ + self._new_type() + return + + if self.mode is None: + return + + if self.mode == "LF_MODIFIER": + if (match := self.MODIFIES_RE.match(line)) is not None: + # For convenience, because this is essentially the same thing + # as an LF_CLASS forward ref. + self._set("is_forward_ref", True) + self._set("modifies", normalize_type_id(match.group("type"))) + + elif self.mode == "LF_ARRAY": + if (match := self.ARRAY_ELEMENT_RE.match(line)) is not None: + self._set("array_type", normalize_type_id(match.group("type"))) + + elif (match := self.ARRAY_LENGTH_RE.match(line)) is not None: + self._set("size", int(match.group("length"))) + + elif self.mode == "LF_FIELDLIST": + # If this class has a vtable, create a mock member at offset 0 + if (match := self.VTABLE_RE.match(line)) is not None: + # For our purposes, any pointer type will do + self._add_member(0, "T_32PVOID") + self._set_member_name("vftable") + + # Superclass is set here in the fieldlist rather than in LF_CLASS + elif (match := self.SUPERCLASS_RE.match(line)) is not None: + self._set("super", normalize_type_id(match.group("type"))) + + # Member offset and type given on the first of two lines. + elif (match := self.LIST_RE.match(line)) is not None: + self._add_member( + int(match.group("offset")), normalize_type_id(match.group("type")) + ) + + # Name of the member read on the second of two lines. + elif (match := self.MEMBER_RE.match(line)) is not None: + self._set_member_name(match.group("name")) + + else: # LF_CLASS or LF_STRUCTURE + # Match the reference to the associated LF_FIELDLIST + if (match := self.CLASS_FIELD_RE.match(line)) is not None: + if match.group("field_type") == "0x0000": + # Not redundant. UDT might not match the key. + # These cases get reported as UDT mismatch. + self._set("is_forward_ref", True) + else: + field_list_type = normalize_type_id(match.group("field_type")) + self._set("field_list_type", field_list_type) + + # Last line has the vital information. + # If this is a FORWARD REF, we need to follow the UDT pointer + # to get the actual class details. + elif (match := self.CLASS_NAME_RE.match(line)) is not None: + self._set("name", match.group("name")) + self._set("udt", normalize_type_id(match.group("udt"))) + self._set("size", int(match.group("size"))) diff --git a/tools/isledecomp/isledecomp/dir.py b/tools/isledecomp/isledecomp/dir.py new file mode 100644 index 00000000..ca7e3fd5 --- /dev/null +++ b/tools/isledecomp/isledecomp/dir.py @@ -0,0 +1,103 @@ +import os +import subprocess +import sys +import pathlib +from typing import Iterator + + +def winepath_win_to_unix(path: str) -> str: + return subprocess.check_output(["winepath", path], text=True).strip() + + +def winepath_unix_to_win(path: str) -> str: + return subprocess.check_output(["winepath", "-w", path], text=True).strip() + + +class PathResolver: + """Intended to resolve Windows/Wine paths used in the PDB (cvdump) output + into a "canonical" format to be matched against code file paths from os.walk. + MSVC may include files from the parent dir using `..`. We eliminate those and create + an absolute path so that information about the same file under different names + will be combined into the same record. (i.e. line_no/addr pairs from LINES section.) + """ + + def __init__(self, basedir) -> None: + """basedir is the root path of the code directory in the format for your OS. + We will convert it to a PureWindowsPath to be platform-independent + and match that to the paths from the PDB.""" + + # Memoize the converted paths. We will need to do this for each path + # in the PDB, for each function in that file. (i.e. lots of repeated work) + self._memo = {} + + # Convert basedir to an absolute path if it is not already. + # If it is not absolute, we cannot do the path swap on unix. + self._realdir = pathlib.Path(basedir).resolve() + + self._is_unix = os.name != "nt" + if self._is_unix: + self._basedir = pathlib.PureWindowsPath( + winepath_unix_to_win(str(self._realdir)) + ) + else: + self._basedir = self._realdir + + def _memo_wrapper(self, path_str: str) -> str: + """Wrapper so we can memoize from the public caller method""" + path = pathlib.PureWindowsPath(path_str) + if not path.is_absolute(): + # pathlib syntactic sugar for path concat + path = self._basedir / path + + if self._is_unix: + # If the given path is relative to the basedir, deconstruct the path + # and swap in our unix path to avoid an expensive call to winepath. + try: + # Will raise ValueError if we are not relative to the base. + section = path.relative_to(self._basedir) + # Should combine to pathlib.PosixPath + mockpath = (self._realdir / section).resolve() + if mockpath.is_file(): + return str(mockpath) + except ValueError: + pass + + # We are not relative to the basedir, or our path swap attempt + # did not point at an actual file. Either way, we are forced + # to call winepath using our original path. + return winepath_win_to_unix(str(path)) + + # We must be on Windows. Convert back to WindowsPath. + # The resolve() call will eliminate intermediate backdir references. + return str(pathlib.Path(path).resolve()) + + def resolve_cvdump(self, path_str: str) -> str: + """path_str is in Windows/Wine path format. + We will return a path in the format for the host OS.""" + if path_str not in self._memo: + self._memo[path_str] = self._memo_wrapper(path_str) + + return self._memo[path_str] + + +def is_file_cpp(filename: str) -> bool: + (_, ext) = os.path.splitext(filename) + return ext.lower() in (".h", ".cpp") + + +def walk_source_dir(source: str, recursive: bool = True) -> Iterator[str]: + """Generator to walk the given directory recursively and return + any C++ files found.""" + + source = os.path.abspath(source) + for subdir, _, files in os.walk(source): + for file in files: + if is_file_cpp(file): + yield os.path.join(subdir, file) + + if not recursive: + break + + +def get_file_in_script_dir(fn): + return os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), fn) diff --git a/tools/isledecomp/isledecomp/lib/DUMPBIN.EXE b/tools/isledecomp/isledecomp/lib/DUMPBIN.EXE new file mode 100644 index 00000000..c57ed02c Binary files /dev/null and b/tools/isledecomp/isledecomp/lib/DUMPBIN.EXE differ diff --git a/tools/isledecomp/isledecomp/lib/LINK.EXE b/tools/isledecomp/isledecomp/lib/LINK.EXE new file mode 100644 index 00000000..9d35a899 Binary files /dev/null and b/tools/isledecomp/isledecomp/lib/LINK.EXE differ diff --git a/tools/isledecomp/isledecomp/lib/MSPDB41.DLL b/tools/isledecomp/isledecomp/lib/MSPDB41.DLL new file mode 100644 index 00000000..9d2953e2 Binary files /dev/null and b/tools/isledecomp/isledecomp/lib/MSPDB41.DLL differ diff --git a/tools/isledecomp/isledecomp/lib/__init__.py b/tools/isledecomp/isledecomp/lib/__init__.py new file mode 100644 index 00000000..f1081a81 --- /dev/null +++ b/tools/isledecomp/isledecomp/lib/__init__.py @@ -0,0 +1,13 @@ +"""Provides a reference point for redistributed tools found in this directory. +This allows you to get the path for these tools from a script run anywhere.""" +from os.path import join, dirname + + +def lib_path() -> str: + """Returns the directory for this module.""" + return dirname(__file__) + + +def lib_path_join(name: str) -> str: + """Convenience wrapper for os.path.join.""" + return join(lib_path(), name) diff --git a/tools/isledecomp/isledecomp/lib/cvdump.exe b/tools/isledecomp/isledecomp/lib/cvdump.exe new file mode 100644 index 00000000..8c1eff6e Binary files /dev/null and b/tools/isledecomp/isledecomp/lib/cvdump.exe differ diff --git a/tools/isledecomp/isledecomp/parser/__init__.py b/tools/isledecomp/isledecomp/parser/__init__.py new file mode 100644 index 00000000..14549700 --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/__init__.py @@ -0,0 +1,3 @@ +from .codebase import DecompCodebase +from .parser import DecompParser +from .linter import DecompLinter diff --git a/tools/isledecomp/isledecomp/parser/codebase.py b/tools/isledecomp/isledecomp/parser/codebase.py new file mode 100644 index 00000000..bae0d122 --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/codebase.py @@ -0,0 +1,57 @@ +"""For aggregating decomp markers read from an entire directory and for a single module.""" +from typing import Callable, Iterable, Iterator, List +from .parser import DecompParser +from .node import ( + ParserSymbol, + ParserFunction, + ParserVtable, + ParserVariable, + ParserString, +) + + +class DecompCodebase: + def __init__(self, filenames: Iterable[str], module: str) -> None: + self._symbols: List[ParserSymbol] = [] + + parser = DecompParser() + for filename in filenames: + parser.reset() + with open(filename, "r", encoding="utf-8") as f: + parser.read_lines(f) + + for sym in parser.iter_symbols(module): + sym.filename = filename + self._symbols.append(sym) + + def prune_invalid_addrs(self, is_valid: Callable[int, bool]) -> List[ParserSymbol]: + """Some decomp annotations might have an invalid address. + Return the list of addresses where we fail the is_valid check, + and remove those from our list of symbols.""" + invalid_symbols = [sym for sym in self._symbols if not is_valid(sym.offset)] + self._symbols = [sym for sym in self._symbols if is_valid(sym.offset)] + + return invalid_symbols + + def iter_line_functions(self) -> Iterator[ParserFunction]: + """Return lineref functions separately from nameref. Assuming the PDB matches + the state of the source code, a line reference is a guaranteed match, even if + multiple functions share the same name. (i.e. polymorphism)""" + return filter( + lambda s: isinstance(s, ParserFunction) and not s.is_nameref(), + self._symbols, + ) + + def iter_name_functions(self) -> Iterator[ParserFunction]: + return filter( + lambda s: isinstance(s, ParserFunction) and s.is_nameref(), self._symbols + ) + + def iter_vtables(self) -> Iterator[ParserVtable]: + return filter(lambda s: isinstance(s, ParserVtable), self._symbols) + + def iter_variables(self) -> Iterator[ParserVariable]: + return filter(lambda s: isinstance(s, ParserVariable), self._symbols) + + def iter_strings(self) -> Iterator[ParserString]: + return filter(lambda s: isinstance(s, ParserString), self._symbols) diff --git a/tools/isledecomp/isledecomp/parser/error.py b/tools/isledecomp/isledecomp/parser/error.py new file mode 100644 index 00000000..9ced1498 --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/error.py @@ -0,0 +1,97 @@ +from enum import Enum +from typing import Optional +from dataclasses import dataclass + + +# TODO: poorly chosen name, should be AlertType or AlertCode or something +class ParserError(Enum): + # WARN: Stub function exceeds some line number threshold + UNLIKELY_STUB = 100 + + # WARN: Decomp marker is close enough to be recognized, but does not follow syntax exactly + BAD_DECOMP_MARKER = 101 + + # WARN: Multiple markers in sequence do not have distinct modules + DUPLICATE_MODULE = 102 + + # WARN: Detected a dupcliate module/offset pair in the current file + DUPLICATE_OFFSET = 103 + + # WARN: We read a line that matches the decomp marker pattern, but we are not set up + # to handle it + BOGUS_MARKER = 104 + + # WARN: New function marker appeared while we were inside a function + MISSED_END_OF_FUNCTION = 105 + + # WARN: If we find a curly brace right after the function declaration + # this is wrong but we still have enough to make a match with reccmp + MISSED_START_OF_FUNCTION = 106 + + # WARN: A blank line appeared between the end of FUNCTION markers + # and the start of the function. We can ignore it, but the line shouldn't be there + UNEXPECTED_BLANK_LINE = 107 + + # WARN: We called the finish() method for the parser but had not reached the starting + # state of SEARCH + UNEXPECTED_END_OF_FILE = 108 + + # WARN: We found a marker to be referenced by name outside of a header file. + BYNAME_FUNCTION_IN_CPP = 109 + + # WARN: A GLOBAL marker appeared over a variable without the g_ prefix + GLOBAL_MISSING_PREFIX = 110 + + # WARN: GLOBAL marker points at something other than variable declaration. + # We can't match global variables based on position, but the goal here is + # to ignore things like string literal that are not variables. + GLOBAL_NOT_VARIABLE = 111 + + # WARN: A marked static variable inside a function needs to have its + # function marked too, and in the same module. + ORPHANED_STATIC_VARIABLE = 112 + + # This code or higher is an error, not a warning + DECOMP_ERROR_START = 200 + + # ERROR: We found a marker unexpectedly + UNEXPECTED_MARKER = 200 + + # ERROR: We found a marker where we expected to find one, but it is incompatible + # with the preceding markers. + # For example, a GLOBAL cannot follow FUNCTION/STUB + INCOMPATIBLE_MARKER = 201 + + # ERROR: The line following an explicit by-name marker was not a comment + # We assume a syntax error here rather than try to use the next line + BAD_NAMEREF = 202 + + # ERROR: This function offset comes before the previous offset from the same module + # This hopefully gives some hint about which functions need to be rearranged. + FUNCTION_OUT_OF_ORDER = 203 + + # ERROR: The line following an explicit by-name marker that does _not_ expect + # a comment -- i.e. VTABLE or GLOBAL -- could not extract the name + NO_SUITABLE_NAME = 204 + + # ERROR: Two STRING markers have the same module and offset, but the strings + # they annotate are different. + WRONG_STRING = 205 + + # ERROR: This lineref FUNCTION marker is next to a function declaration or + # forward reference. The correct place for the marker is where the function + # is implemented so we can match with the PDB. + NO_IMPLEMENTATION = 206 + + +@dataclass +class ParserAlert: + code: ParserError + line_number: int + line: Optional[str] = None + + def is_warning(self) -> bool: + return self.code.value < ParserError.DECOMP_ERROR_START.value + + def is_error(self) -> bool: + return self.code.value >= ParserError.DECOMP_ERROR_START.value diff --git a/tools/isledecomp/isledecomp/parser/linter.py b/tools/isledecomp/isledecomp/parser/linter.py new file mode 100644 index 00000000..b44487df --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/linter.py @@ -0,0 +1,144 @@ +from typing import List, Optional +from .parser import DecompParser +from .error import ParserAlert, ParserError +from .node import ParserSymbol, ParserString + + +def get_checkorder_filter(module): + """Return a filter function on implemented functions in the given module""" + return lambda fun: fun.module == module and not fun.lookup_by_name + + +class DecompLinter: + def __init__(self) -> None: + self.alerts: List[ParserAlert] = [] + self._parser = DecompParser() + self._filename: str = "" + self._module: Optional[str] = None + # Set of (str, int) tuples for each module/offset pair seen while scanning. + # This is _not_ reset between files and is intended to report offset reuse + # when scanning the entire directory. + self._offsets_used = set() + # Keep track of strings we have seen. Persists across files. + # Module/offset can be repeated for string markers but the strings must match. + self._strings = {} + + def reset(self, full_reset: bool = False): + self.alerts = [] + self._parser.reset() + self._filename = "" + self._module = None + + if full_reset: + self._offsets_used.clear() + self._strings = {} + + def file_is_header(self): + return self._filename.lower().endswith(".h") + + def _load_offsets_from_list(self, marker_list: List[ParserSymbol]): + """Helper for loading (module, offset) tuples while the DecompParser + has them broken up into three different lists.""" + for marker in marker_list: + is_string = isinstance(marker, ParserString) + + value = (marker.module, marker.offset) + if value in self._offsets_used: + if is_string: + if self._strings[value] != marker.name: + self.alerts.append( + ParserAlert( + code=ParserError.WRONG_STRING, + line_number=marker.line_number, + line=f"0x{marker.offset:08x}, {repr(self._strings[value])} vs. {repr(marker.name)}", + ) + ) + else: + self.alerts.append( + ParserAlert( + code=ParserError.DUPLICATE_OFFSET, + line_number=marker.line_number, + line=f"0x{marker.offset:08x}", + ) + ) + else: + self._offsets_used.add(value) + if is_string: + self._strings[value] = marker.name + + def _check_function_order(self): + """Rules: + 1. Only markers that are implemented in the file are considered. This means we + only look at markers that are cross-referenced with cvdump output by their line + number. Markers with the lookup_by_name flag set are ignored because we cannot + directly influence their order. + + 2. Order should be considered for a single module only. If we have multiple + markers for a single function (i.e. for LEGO1 functions linked statically to + ISLE) then the virtual address space will be very different. If we don't check + for one module only, we would incorrectly report that the file is out of order. + """ + + if self._module is None: + return + + checkorder_filter = get_checkorder_filter(self._module) + last_offset = None + for fun in filter(checkorder_filter, self._parser.functions): + if last_offset is not None: + if fun.offset < last_offset: + self.alerts.append( + ParserAlert( + code=ParserError.FUNCTION_OUT_OF_ORDER, + line_number=fun.line_number, + ) + ) + + last_offset = fun.offset + + def _check_offset_uniqueness(self): + self._load_offsets_from_list(self._parser.functions) + self._load_offsets_from_list(self._parser.vtables) + self._load_offsets_from_list(self._parser.variables) + self._load_offsets_from_list(self._parser.strings) + + def _check_byname_allowed(self): + if self.file_is_header(): + return + + for fun in self._parser.functions: + if fun.lookup_by_name: + self.alerts.append( + ParserAlert( + code=ParserError.BYNAME_FUNCTION_IN_CPP, + line_number=fun.line_number, + ) + ) + + def check_lines(self, lines, filename, module=None): + """`lines` is a generic iterable to allow for testing with a list of strings. + We assume lines has the entire contents of the compilation unit.""" + + self.reset(False) + self._filename = filename + self._module = module + + self._parser.read_lines(lines) + + self._parser.finish() + self.alerts = self._parser.alerts[::] + + self._check_offset_uniqueness() + + if self._module is not None: + self._check_byname_allowed() + + if not self.file_is_header(): + self._check_function_order() + + return len(self.alerts) == 0 + + def check_file(self, filename, module=None): + """Convenience method for decomplint cli tool""" + with open(filename, "r", encoding="utf-8") as f: + return self.check_lines(f, filename, module) diff --git a/tools/isledecomp/isledecomp/parser/marker.py b/tools/isledecomp/isledecomp/parser/marker.py new file mode 100644 index 00000000..8108ac46 --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/marker.py @@ -0,0 +1,146 @@ +import re +from typing import Optional, Tuple +from enum import Enum + + +class MarkerCategory(Enum): + """For the purposes of grouping multiple different DecompMarkers together, + assign a rough "category" for the MarkerType values below. + It's really only the function types that have to get folded down, but + we'll do that in a structured way to permit future expansion.""" + + FUNCTION = 1 + VARIABLE = 2 + STRING = 3 + VTABLE = 4 + ADDRESS = 100 # i.e. no comparison required or possible + + +class MarkerType(Enum): + UNKNOWN = -100 + FUNCTION = 1 + STUB = 2 + SYNTHETIC = 3 + TEMPLATE = 4 + GLOBAL = 5 + VTABLE = 6 + STRING = 7 + LIBRARY = 8 + + +markerRegex = re.compile( + r"\s*//\s*(?P\w+):\s*(?P\w+)\s+(?P0x[a-f0-9]+) *(?P\S.+\S)?", + flags=re.I, +) + + +markerExactRegex = re.compile( + r"\s*// (?P[A-Z]+): (?P[A-Z0-9]+) (?P0x[a-f0-9]+)(?: (?P\S.+\S))?\n?$" +) + + +class DecompMarker: + def __init__( + self, marker_type: str, module: str, offset: int, extra: Optional[str] = None + ) -> None: + try: + self._type = MarkerType[marker_type.upper()] + except KeyError: + self._type = MarkerType.UNKNOWN + + # Convert to upper here. A lot of other analysis depends on this name + # being consistent and predictable. If the name is _not_ capitalized + # we will emit a syntax error. + self._module: str = module.upper() + self._offset: int = offset + self._extra: Optional[str] = extra + + @property + def type(self) -> MarkerType: + return self._type + + @property + def module(self) -> str: + return self._module + + @property + def offset(self) -> int: + return self._offset + + @property + def extra(self) -> Optional[str]: + return self._extra + + @property + def category(self) -> MarkerCategory: + if self.is_vtable(): + return MarkerCategory.VTABLE + + if self.is_variable(): + return MarkerCategory.VARIABLE + + if self.is_string(): + return MarkerCategory.STRING + + # TODO: worth another look if we add more types, but this covers it + if self.is_regular_function() or self.is_explicit_byname(): + return MarkerCategory.FUNCTION + + return MarkerCategory.ADDRESS + + @property + def key(self) -> Tuple[str, str, Optional[str]]: + """For use with the MarkerDict. To detect/avoid marker collision.""" + return (self.category, self.module, self.extra) + + def is_regular_function(self) -> bool: + """Regular function, meaning: not an explicit byname lookup. FUNCTION + markers can be _implicit_ byname. + FUNCTION and STUB markers are (currently) the only heterogenous marker types that + can be lumped together, although the reasons for doing so are a little vague.""" + return self._type in (MarkerType.FUNCTION, MarkerType.STUB) + + def is_explicit_byname(self) -> bool: + return self._type in ( + MarkerType.SYNTHETIC, + MarkerType.TEMPLATE, + MarkerType.LIBRARY, + ) + + def is_variable(self) -> bool: + return self._type == MarkerType.GLOBAL + + def is_synthetic(self) -> bool: + return self._type == MarkerType.SYNTHETIC + + def is_template(self) -> bool: + return self._type == MarkerType.TEMPLATE + + def is_vtable(self) -> bool: + return self._type == MarkerType.VTABLE + + def is_library(self) -> bool: + return self._type == MarkerType.LIBRARY + + def is_string(self) -> bool: + return self._type == MarkerType.STRING + + def allowed_in_func(self) -> bool: + return self._type in (MarkerType.GLOBAL, MarkerType.STRING) + + +def match_marker(line: str) -> Optional[DecompMarker]: + match = markerRegex.match(line) + if match is None: + return None + + return DecompMarker( + marker_type=match.group("type"), + module=match.group("module"), + offset=int(match.group("offset"), 16), + extra=match.group("extra"), + ) + + +def is_marker_exact(line: str) -> bool: + return markerExactRegex.match(line) is not None diff --git a/tools/isledecomp/isledecomp/parser/node.py b/tools/isledecomp/isledecomp/parser/node.py new file mode 100644 index 00000000..21e4c382 --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/node.py @@ -0,0 +1,63 @@ +from typing import Optional +from dataclasses import dataclass +from .marker import MarkerType + + +@dataclass +class ParserSymbol: + """Exported decomp marker with all information (except the code filename) required to + cross-reference with cvdump data.""" + + type: MarkerType + line_number: int + module: str + offset: int + name: str + + # The parser doesn't (currently) know about the code filename, but if you + # wanted to set it here after the fact, here's the spot. + filename: Optional[str] = None + + def should_skip(self) -> bool: + """The default is to compare any symbols we have""" + return False + + def is_nameref(self) -> bool: + """All symbols default to name lookup""" + return True + + +@dataclass +class ParserFunction(ParserSymbol): + # We are able to detect the closing line of a function with some reliability. + # This isn't used for anything right now, but perhaps later it will be. + end_line: Optional[int] = None + + # All marker types are referenced by name except FUNCTION/STUB. These can also be + # referenced by name, but only if this flag is true. + lookup_by_name: bool = False + + def should_skip(self) -> bool: + return self.type == MarkerType.STUB + + def is_nameref(self) -> bool: + return ( + self.type in (MarkerType.SYNTHETIC, MarkerType.TEMPLATE, MarkerType.LIBRARY) + or self.lookup_by_name + ) + + +@dataclass +class ParserVariable(ParserSymbol): + is_static: bool = False + parent_function: Optional[int] = None + + +@dataclass +class ParserVtable(ParserSymbol): + base_class: Optional[str] = None + + +@dataclass +class ParserString(ParserSymbol): + pass diff --git a/tools/isledecomp/isledecomp/parser/parser.py b/tools/isledecomp/isledecomp/parser/parser.py new file mode 100644 index 00000000..92e41dd3 --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/parser.py @@ -0,0 +1,556 @@ +# C++ file parser + +from typing import List, Iterable, Iterator, Optional +from enum import Enum +from .util import ( + get_class_name, + get_variable_name, + get_synthetic_name, + remove_trailing_comment, + get_string_contents, + sanitize_code_line, + scopeDetectRegex, +) +from .marker import ( + DecompMarker, + MarkerCategory, + match_marker, + is_marker_exact, +) +from .node import ( + ParserSymbol, + ParserFunction, + ParserVariable, + ParserVtable, + ParserString, +) +from .error import ParserAlert, ParserError + + +class ReaderState(Enum): + SEARCH = 0 + WANT_SIG = 1 + IN_FUNC = 2 + IN_TEMPLATE = 3 + WANT_CURLY = 4 + IN_GLOBAL = 5 + IN_FUNC_GLOBAL = 6 + IN_VTABLE = 7 + IN_SYNTHETIC = 8 + IN_LIBRARY = 9 + DONE = 100 + + +class MarkerDict: + def __init__(self) -> None: + self.markers: dict = {} + + def insert(self, marker: DecompMarker) -> bool: + """Return True if this insert would overwrite""" + if marker.key in self.markers: + return True + + self.markers[marker.key] = marker + return False + + def query( + self, category: MarkerCategory, module: str, extra: Optional[str] = None + ) -> Optional[DecompMarker]: + return self.markers.get((category, module, extra)) + + def iter(self) -> Iterator[DecompMarker]: + for _, marker in self.markers.items(): + yield marker + + def empty(self): + self.markers = {} + + +class CurlyManager: + """Overly simplified scope manager""" + + def __init__(self): + self._stack = [] + + def reset(self): + self._stack = [] + + def _pop(self): + """Pop stack safely""" + try: + self._stack.pop() + except IndexError: + pass + + def get_prefix(self, name: Optional[str] = None) -> str: + """Return the prefix for where we are.""" + + scopes = [t for t in self._stack if t != "{"] + if len(scopes) == 0: + return name if name is not None else "" + + if name is not None and name not in scopes: + scopes.append(name) + + return "::".join(scopes) + + def read_line(self, raw_line: str): + """Read a line of code and update the stack.""" + line = sanitize_code_line(raw_line) + if (match := scopeDetectRegex.match(line)) is not None: + if not line.endswith(";"): + self._stack.append(match.group("name")) + + change = line.count("{") - line.count("}") + if change > 0: + for _ in range(change): + self._stack.append("{") + elif change < 0: + for _ in range(-change): + self._pop() + + if len(self._stack) == 0: + return + + last = self._stack[-1] + if last != "{": + self._pop() + + +class DecompParser: + # pylint: disable=too-many-instance-attributes + # Could combine output lists into a single list to get under the limit, + # but not right now + def __init__(self) -> None: + # The lists to be populated as we parse + self._symbols: List[ParserSymbol] = [] + self.alerts: List[ParserAlert] = [] + + self.line_number: int = 0 + self.state: ReaderState = ReaderState.SEARCH + + self.last_line: str = "" + + self.curly = CurlyManager() + + # To allow for multiple markers where code is shared across different + # modules, save lists of compatible markers that appear in sequence + self.fun_markers = MarkerDict() + self.var_markers = MarkerDict() + self.tbl_markers = MarkerDict() + + # To handle functions that are entirely indented (i.e. those defined + # in class declarations), remember how many whitespace characters + # came before the opening curly brace and match that up at the end. + # This should give us the same or better accuracy for a well-formed file. + # The alternative is counting the curly braces on each line + # but that's probably too cumbersome. + self.curly_indent_stops: int = 0 + + # For non-synthetic functions, save the line number where the function begins + # (i.e. where we see the curly brace) along with the function signature. + # We will need both when we reach the end of the function. + self.function_start: int = 0 + self.function_sig: str = "" + + def reset(self): + self._symbols = [] + self.alerts = [] + + self.line_number = 0 + self.state = ReaderState.SEARCH + + self.last_line = "" + + self.fun_markers.empty() + self.var_markers.empty() + self.tbl_markers.empty() + + self.curly_indent_stops = 0 + self.function_start = 0 + self.function_sig = "" + + self.curly.reset() + + @property + def functions(self) -> List[ParserFunction]: + return [s for s in self._symbols if isinstance(s, ParserFunction)] + + @property + def vtables(self) -> List[ParserVtable]: + return [s for s in self._symbols if isinstance(s, ParserVtable)] + + @property + def variables(self) -> List[ParserVariable]: + return [s for s in self._symbols if isinstance(s, ParserVariable)] + + @property + def strings(self) -> List[ParserString]: + return [s for s in self._symbols if isinstance(s, ParserString)] + + def iter_symbols(self, module: Optional[str] = None) -> Iterator[ParserSymbol]: + for s in self._symbols: + if module is None or s.module == module: + yield s + + def _recover(self): + """We hit a syntax error and need to reset temp structures""" + self.state = ReaderState.SEARCH + self.fun_markers.empty() + self.var_markers.empty() + self.tbl_markers.empty() + + def _syntax_warning(self, code): + self.alerts.append( + ParserAlert( + line_number=self.line_number, + code=code, + line=self.last_line.strip(), + ) + ) + + def _syntax_error(self, code): + self._syntax_warning(code) + self._recover() + + def _function_starts_here(self): + self.function_start = self.line_number + + def _function_marker(self, marker: DecompMarker): + if self.fun_markers.insert(marker): + self._syntax_warning(ParserError.DUPLICATE_MODULE) + self.state = ReaderState.WANT_SIG + + def _nameref_marker(self, marker: DecompMarker): + """Functions explicitly referenced by name are set here""" + if self.fun_markers.insert(marker): + self._syntax_warning(ParserError.DUPLICATE_MODULE) + + if marker.is_template(): + self.state = ReaderState.IN_TEMPLATE + elif marker.is_synthetic(): + self.state = ReaderState.IN_SYNTHETIC + else: + self.state = ReaderState.IN_LIBRARY + + def _function_done(self, lookup_by_name: bool = False, unexpected: bool = False): + end_line = self.line_number + if unexpected: + # If we missed the end of the previous function, assume it ended + # on the previous line and that whatever we are tracking next + # begins on the current line. + end_line -= 1 + + for marker in self.fun_markers.iter(): + self._symbols.append( + ParserFunction( + type=marker.type, + line_number=self.function_start, + module=marker.module, + offset=marker.offset, + name=self.function_sig, + lookup_by_name=lookup_by_name, + end_line=end_line, + ) + ) + + self.fun_markers.empty() + self.curly_indent_stops = 0 + self.state = ReaderState.SEARCH + + def _vtable_marker(self, marker: DecompMarker): + if self.tbl_markers.insert(marker): + self._syntax_warning(ParserError.DUPLICATE_MODULE) + self.state = ReaderState.IN_VTABLE + + def _vtable_done(self, class_name: str = None): + if class_name is None: + # Best we can do + class_name = self.last_line.strip() + + for marker in self.tbl_markers.iter(): + self._symbols.append( + ParserVtable( + type=marker.type, + line_number=self.line_number, + module=marker.module, + offset=marker.offset, + name=self.curly.get_prefix(class_name), + base_class=marker.extra, + ) + ) + + self.tbl_markers.empty() + self.state = ReaderState.SEARCH + + def _variable_marker(self, marker: DecompMarker): + if self.var_markers.insert(marker): + self._syntax_warning(ParserError.DUPLICATE_MODULE) + + if self.state in (ReaderState.IN_FUNC, ReaderState.IN_FUNC_GLOBAL): + self.state = ReaderState.IN_FUNC_GLOBAL + else: + self.state = ReaderState.IN_GLOBAL + + def _variable_done( + self, variable_name: Optional[str] = None, string_value: Optional[str] = None + ): + if variable_name is None and string_value is None: + self._syntax_error(ParserError.NO_SUITABLE_NAME) + return + + for marker in self.var_markers.iter(): + if marker.is_string(): + self._symbols.append( + ParserString( + type=marker.type, + line_number=self.line_number, + module=marker.module, + offset=marker.offset, + name=string_value, + ) + ) + else: + parent_function = None + is_static = self.state == ReaderState.IN_FUNC_GLOBAL + + # If this is a static variable, we need to get the function + # where it resides so that we can match it up later with the + # mangled names of both variable and function from cvdump. + if is_static: + fun_marker = self.fun_markers.query( + MarkerCategory.FUNCTION, marker.module + ) + + if fun_marker is None: + self._syntax_warning(ParserError.ORPHANED_STATIC_VARIABLE) + continue + + parent_function = fun_marker.offset + + self._symbols.append( + ParserVariable( + type=marker.type, + line_number=self.line_number, + module=marker.module, + offset=marker.offset, + name=self.curly.get_prefix(variable_name), + is_static=is_static, + parent_function=parent_function, + ) + ) + + self.var_markers.empty() + if self.state == ReaderState.IN_FUNC_GLOBAL: + self.state = ReaderState.IN_FUNC + else: + self.state = ReaderState.SEARCH + + def _handle_marker(self, marker: DecompMarker): + # Cannot handle any markers between function sig and opening curly brace + if self.state == ReaderState.WANT_CURLY: + self._syntax_error(ParserError.UNEXPECTED_MARKER) + return + + # If we are inside a function, the only markers we accept are: + # GLOBAL, indicating a static variable + # STRING, indicating a literal string. + # Otherwise we assume that the parser missed the end of the function + # and we have moved on to something else. + # This is unlikely to occur with well-formed code, but + # we can recover easily by just ending the function here. + if self.state == ReaderState.IN_FUNC and not marker.allowed_in_func(): + self._syntax_warning(ParserError.MISSED_END_OF_FUNCTION) + self._function_done(unexpected=True) + + # TODO: How uncertain are we of detecting the end of a function + # in a clang-formatted file? For now we assume we have missed the + # end if we detect a non-GLOBAL marker while state is IN_FUNC. + # Maybe these cases should be syntax errors instead + + if marker.is_regular_function(): + if self.state in ( + ReaderState.SEARCH, + ReaderState.WANT_SIG, + ): + # We will allow multiple offsets if we have just begun + # the code block, but not after we hit the curly brace. + self._function_marker(marker) + else: + self._syntax_error(ParserError.INCOMPATIBLE_MARKER) + + elif marker.is_template(): + if self.state in (ReaderState.SEARCH, ReaderState.IN_TEMPLATE): + self._nameref_marker(marker) + else: + self._syntax_error(ParserError.INCOMPATIBLE_MARKER) + + elif marker.is_synthetic(): + if self.state in (ReaderState.SEARCH, ReaderState.IN_SYNTHETIC): + self._nameref_marker(marker) + else: + self._syntax_error(ParserError.INCOMPATIBLE_MARKER) + + elif marker.is_library(): + if self.state in (ReaderState.SEARCH, ReaderState.IN_LIBRARY): + self._nameref_marker(marker) + else: + self._syntax_error(ParserError.INCOMPATIBLE_MARKER) + + # Strings and variables are almost the same thing + elif marker.is_string() or marker.is_variable(): + if self.state in ( + ReaderState.SEARCH, + ReaderState.IN_GLOBAL, + ReaderState.IN_FUNC, + ReaderState.IN_FUNC_GLOBAL, + ): + self._variable_marker(marker) + else: + self._syntax_error(ParserError.INCOMPATIBLE_MARKER) + + elif marker.is_vtable(): + if self.state in (ReaderState.SEARCH, ReaderState.IN_VTABLE): + self._vtable_marker(marker) + else: + self._syntax_error(ParserError.INCOMPATIBLE_MARKER) + + else: + self._syntax_warning(ParserError.BOGUS_MARKER) + + def read_line(self, line: str): + if self.state == ReaderState.DONE: + return + + self.last_line = line # TODO: Useful or hack for error reporting? + self.line_number += 1 + + marker = match_marker(line) + if marker is not None: + # TODO: what's the best place for this? + # Does it belong with reading or marker handling? + if not is_marker_exact(self.last_line): + self._syntax_warning(ParserError.BAD_DECOMP_MARKER) + self._handle_marker(marker) + return + + self.curly.read_line(line) + + line_strip = line.strip() + if self.state in ( + ReaderState.IN_SYNTHETIC, + ReaderState.IN_TEMPLATE, + ReaderState.IN_LIBRARY, + ): + # Explicit nameref functions provide the function name + # on the next line (in a // comment) + name = get_synthetic_name(line) + if name is None: + self._syntax_error(ParserError.BAD_NAMEREF) + else: + self.function_sig = name + self._function_starts_here() + self._function_done(lookup_by_name=True) + + elif self.state == ReaderState.WANT_SIG: + # Ignore blanks on the way to function start or function name + if len(line_strip) == 0: + self._syntax_warning(ParserError.UNEXPECTED_BLANK_LINE) + + elif line_strip.startswith("//"): + # If we found a comment, assume implicit lookup-by-name + # function and end here. We know this is not a decomp marker + # because it would have been handled already. + self.function_sig = get_synthetic_name(line) + self._function_starts_here() + self._function_done(lookup_by_name=True) + + elif line_strip == "{": + # We missed the function signature but we can recover from this + self.function_sig = "(unknown)" + self._function_starts_here() + self._syntax_warning(ParserError.MISSED_START_OF_FUNCTION) + self.state = ReaderState.IN_FUNC + + else: + # Inline functions may end with a comment. Strip that out + # to help parsing. + self.function_sig = remove_trailing_comment(line_strip) + + # Now check to see if the opening curly bracket is on the + # same line. clang-format should prevent this (BraceWrapping) + # but it is easy to detect. + # If the entire function is on one line, handle that too. + if self.function_sig.endswith("{"): + self._function_starts_here() + self.state = ReaderState.IN_FUNC + elif self.function_sig.endswith("}") or self.function_sig.endswith( + "};" + ): + self._function_starts_here() + self._function_done() + elif self.function_sig.endswith(");"): + # Detect forward reference or declaration + self._syntax_error(ParserError.NO_IMPLEMENTATION) + else: + self.state = ReaderState.WANT_CURLY + + elif self.state == ReaderState.WANT_CURLY: + if line_strip == "{": + self.curly_indent_stops = line.index("{") + self._function_starts_here() + self.state = ReaderState.IN_FUNC + + elif self.state == ReaderState.IN_FUNC: + if line_strip.startswith("}") and line[self.curly_indent_stops] == "}": + self._function_done() + + elif self.state in (ReaderState.IN_GLOBAL, ReaderState.IN_FUNC_GLOBAL): + # TODO: Known problem that an error here will cause us to abandon a + # function we have already parsed if state == IN_FUNC_GLOBAL. + # However, we are not tolerant of _any_ syntax problems in our + # CI actions, so the solution is to just fix the invalid marker. + variable_name = None + + global_markers_queued = any( + m.is_variable() for m in self.var_markers.iter() + ) + + if len(line_strip) == 0: + self._syntax_warning(ParserError.UNEXPECTED_BLANK_LINE) + return + + if global_markers_queued: + # Not the greatest solution, but a consequence of combining GLOBAL and + # STRING markers together. If the marker precedes a return statement, it is + # valid for a STRING marker to be here, but not a GLOBAL. We need to look + # ahead and tell whether this *would* fail. + if line_strip.startswith("return"): + self._syntax_error(ParserError.GLOBAL_NOT_VARIABLE) + return + if line_strip.startswith("//"): + # If we found a comment, assume implicit lookup-by-name + # function and end here. We know this is not a decomp marker + # because it would have been handled already. + variable_name = get_synthetic_name(line) + else: + variable_name = get_variable_name(line) + + string_name = get_string_contents(line) + + self._variable_done(variable_name, string_name) + + elif self.state == ReaderState.IN_VTABLE: + vtable_class = get_class_name(line) + if vtable_class is not None: + self._vtable_done(class_name=vtable_class) + + def read_lines(self, lines: Iterable): + for line in lines: + self.read_line(line) + + def finish(self): + if self.state != ReaderState.SEARCH: + self._syntax_warning(ParserError.UNEXPECTED_END_OF_FILE) + + self.state = ReaderState.DONE diff --git a/tools/isledecomp/isledecomp/parser/util.py b/tools/isledecomp/isledecomp/parser/util.py new file mode 100644 index 00000000..fbc78e10 --- /dev/null +++ b/tools/isledecomp/isledecomp/parser/util.py @@ -0,0 +1,141 @@ +# C++ Parser utility functions and data structures +import re +from typing import Optional +from ast import literal_eval + +# The goal here is to just read whatever is on the next line, so some +# flexibility in the formatting seems OK +templateCommentRegex = re.compile(r"\s*//\s+(.*)") + +# To remove any comment (//) or block comment (/*) and its leading spaces +# from the end of a code line +trailingCommentRegex = re.compile(r"(\s*(?://|/\*).*)$") + +# Get char contents, ignore escape characters +singleQuoteRegex = re.compile(r"('(?:[^\'\\]|\\.)')") + +# Match contents of block comment on one line +blockCommentRegex = re.compile(r"(/\*.*?\*/)") + +# Match contents of single comment on one line +regularCommentRegex = re.compile(r"(//.*)") + +# Get string contents, ignore escape characters that might interfere +doubleQuoteRegex = re.compile(r"(\"(?:[^\"\\]|\\.)*\")") + +# Detect a line that would cause us to enter a new scope +scopeDetectRegex = re.compile(r"(?:class|struct|namespace) (?P\w+).*(?:{)?") + + +def get_synthetic_name(line: str) -> Optional[str]: + """Synthetic names appear on a single line comment on the line after the marker. + If that's not what we have, return None""" + template_match = templateCommentRegex.match(line) + + if template_match is not None: + return template_match.group(1) + + return None + + +def sanitize_code_line(line: str) -> str: + """Helper for scope manager. Removes sections from a code line + that would cause us to incorrectly detect curly brackets. + This is a very naive implementation and fails entirely on multi-line + strings or comments.""" + + line = singleQuoteRegex.sub("''", line) + line = doubleQuoteRegex.sub('""', line) + line = blockCommentRegex.sub("", line) + line = regularCommentRegex.sub("", line) + + return line.strip() + + +def remove_trailing_comment(line: str) -> str: + return trailingCommentRegex.sub("", line) + + +def is_blank_or_comment(line: str) -> bool: + """Helper to read ahead after the offset comment is matched. + There could be blank lines or other comments before the + function signature, and we want to skip those.""" + line_strip = line.strip() + return ( + len(line_strip) == 0 + or line_strip.startswith("//") + or line_strip.startswith("/*") + or line_strip.endswith("*/") + ) + + +template_regex = re.compile(r"<(?P[\w]+)\s*(?P\*+)?\s*>") + + +class_decl_regex = re.compile( + r"\s*(?:\/\/)?\s*(?:class|struct) ((?:\w+(?:<.+>)?(?:::)?)+)" +) + + +def template_replace(match: re.Match) -> str: + (type_name, asterisks) = match.groups() + if asterisks is None: + return f"<{type_name}>" + + return f"<{type_name} {asterisks}>" + + +def fix_template_type(class_name: str) -> str: + """For template classes, we should reformat the class name so it matches + the output from cvdump: one space between the template type and any asterisks + if it is a pointer type.""" + if "<" not in class_name: + return class_name + + return template_regex.sub(template_replace, class_name) + + +def get_class_name(line: str) -> Optional[str]: + """For VTABLE markers, extract the class name from the code line or comment + where it appears.""" + + match = class_decl_regex.match(line) + if match is not None: + return fix_template_type(match.group(1)) + + return None + + +global_regex = re.compile(r"(?P(?:\w+::)*g_\w+)") +less_strict_global_regex = re.compile(r"(?P(?:\w+::)*\w+)(?:\)\(|\[.*|\s*=.*|;)") + + +def get_variable_name(line: str) -> Optional[str]: + """Grab the name of the variable annotated with the GLOBAL marker. + Correct syntax would have the variable start with the prefix "g_" + but we will try to match regardless.""" + + if (match := global_regex.search(line)) is not None: + return match.group("name") + + if (match := less_strict_global_regex.search(line)) is not None: + return match.group("name") + + return None + + +def get_string_contents(line: str) -> Optional[str]: + """Return the first C string seen on this line. + We have to unescape the string, and a simple way to do that is to use + python's ast.literal_eval. I'm sure there are many pitfalls to doing + it this way, but hopefully the regex will ensure reasonably sane input.""" + + try: + if (match := doubleQuoteRegex.search(line)) is not None: + return literal_eval(match.group(1)) + # pylint: disable=broad-exception-caught + # No way to predict what kind of exception could occur. + except Exception: + pass + + return None diff --git a/tools/isledecomp/isledecomp/types.py b/tools/isledecomp/isledecomp/types.py new file mode 100644 index 00000000..31829c65 --- /dev/null +++ b/tools/isledecomp/isledecomp/types.py @@ -0,0 +1,13 @@ +"""Types shared by other modules""" +from enum import Enum + + +class SymbolType(Enum): + """Broadly tells us what kind of comparison is required for this symbol.""" + + FUNCTION = 1 + DATA = 2 + POINTER = 3 + STRING = 4 + VTABLE = 5 + FLOAT = 6 diff --git a/tools/isledecomp/isledecomp/utils.py b/tools/isledecomp/isledecomp/utils.py new file mode 100644 index 00000000..a8c6033b --- /dev/null +++ b/tools/isledecomp/isledecomp/utils.py @@ -0,0 +1,308 @@ +import os +import sys +from datetime import datetime +import logging +import colorama + + +def print_combined_diff(udiff, plain: bool = False, show_both: bool = False): + if udiff is None: + return + + # We don't know how long the address string will be ahead of time. + # Set this value for each address to try to line things up. + padding_size = 0 + + for slug, subgroups in udiff: + if plain: + print("---") + print("+++") + print(slug) + else: + print(f"{colorama.Fore.RED}---") + print(f"{colorama.Fore.GREEN}+++") + print(f"{colorama.Fore.BLUE}{slug}") + print(colorama.Style.RESET_ALL, end="") + + for subgroup in subgroups: + equal = subgroup.get("both") is not None + + if equal: + for orig_addr, line, recomp_addr in subgroup["both"]: + padding_size = max(padding_size, len(orig_addr)) + if show_both: + print(f"{orig_addr} / {recomp_addr} : {line}") + else: + print(f"{orig_addr} : {line}") + else: + for orig_addr, line in subgroup["orig"]: + padding_size = max(padding_size, len(orig_addr)) + addr_prefix = ( + f"{orig_addr} / {'':{padding_size}}" if show_both else orig_addr + ) + + if plain: + print(f"{addr_prefix} : -{line}") + else: + print( + f"{addr_prefix} : {colorama.Fore.RED}-{line}{colorama.Style.RESET_ALL}" + ) + + for recomp_addr, line in subgroup["recomp"]: + padding_size = max(padding_size, len(recomp_addr)) + addr_prefix = ( + f"{'':{padding_size}} / {recomp_addr}" + if show_both + else " " * padding_size + ) + + if plain: + print(f"{addr_prefix} : +{line}") + else: + print( + f"{addr_prefix} : {colorama.Fore.GREEN}+{line}{colorama.Style.RESET_ALL}" + ) + + # Newline between each diff subgroup. + print() + + +def print_diff(udiff, plain): + """Print diff in difflib.unified_diff format.""" + if udiff is None: + return False + + has_diff = False + for line in udiff: + has_diff = True + color = "" + if line.startswith("++") or line.startswith("@@") or line.startswith("--"): + # Skip unneeded parts of the diff for the brief view + continue + # Work out color if we are printing color + if not plain: + if line.startswith("+"): + color = colorama.Fore.GREEN + elif line.startswith("-"): + color = colorama.Fore.RED + print(color + line) + # Reset color if we're printing in color + if not plain: + print(colorama.Style.RESET_ALL, end="") + return has_diff + + +def get_percent_color(value: float) -> str: + """Return colorama ANSI escape character for the given decimal value.""" + if value == 1.0: + return colorama.Fore.GREEN + if value > 0.8: + return colorama.Fore.YELLOW + + return colorama.Fore.RED + + +def percent_string( + ratio: float, is_effective: bool = False, is_plain: bool = False +) -> str: + """Helper to construct a percentage string from the given ratio. + If is_effective (i.e. effective match), indicate that with the asterisk. + If is_plain, don't use colorama ANSI codes.""" + + percenttext = f"{(ratio * 100):.2f}%" + effective_star = "*" if is_effective else "" + + if is_plain: + return percenttext + effective_star + + return "".join( + [ + get_percent_color(ratio), + percenttext, + colorama.Fore.RED if is_effective else "", + effective_star, + colorama.Style.RESET_ALL, + ] + ) + + +def diff_json_display(show_both_addrs: bool = False, is_plain: bool = False): + """Generate a function that will display the diff according to + the reccmp display preferences.""" + + def formatter(orig_addr, saved, new) -> str: + old_pct = "new" + new_pct = "gone" + name = "" + recomp_addr = "n/a" + + if new is not None: + new_pct = ( + "stub" + if new.get("stub", False) + else percent_string( + new["matching"], new.get("effective", False), is_plain + ) + ) + + # Prefer the current name of this function if we have it. + # We are using the original address as the key. + # A function being renamed is not of interest here. + name = new.get("name", "") + recomp_addr = new.get("recomp", "n/a") + + if saved is not None: + old_pct = ( + "stub" + if saved.get("stub", False) + else percent_string( + saved["matching"], saved.get("effective", False), is_plain + ) + ) + + if name == "": + name = saved.get("name", "") + + if show_both_addrs: + addr_string = f"{orig_addr} / {recomp_addr:10}" + else: + addr_string = orig_addr + + # The ANSI codes from colorama counted towards string length, + # so displaying this as an ascii-like spreadsheet + # (using f-string formatting) would take some effort. + return f"{addr_string} - {name} ({old_pct} -> {new_pct})" + + return formatter + + +def diff_json( + saved_data, + new_data, + orig_file: str, + show_both_addrs: bool = False, + is_plain: bool = False, +): + """Using a saved copy of the diff summary and the current data, print a + report showing which functions/symbols have changed match percentage.""" + + # Don't try to diff a report generated for a different binary file + base_file = os.path.basename(orig_file).lower() + + if saved_data.get("file") != base_file: + logging.getLogger().error( + "Diff report for '%s' does not match current file '%s'", + saved_data.get("file"), + base_file, + ) + return + + if "timestamp" in saved_data: + now = datetime.now().replace(microsecond=0) + then = datetime.fromtimestamp(saved_data["timestamp"]).replace(microsecond=0) + + print( + " ".join( + [ + "Saved diff report generated", + then.strftime("%B %d %Y, %H:%M:%S"), + f"({str(now - then)} ago)", + ] + ) + ) + + print() + + # Convert to dict, using orig_addr as key + saved_invert = {obj["address"]: obj for obj in saved_data["data"]} + new_invert = {obj["address"]: obj for obj in new_data} + + all_addrs = set(saved_invert.keys()).union(new_invert.keys()) + + # Put all the information in one place so we can decide how each item changed. + combined = { + addr: ( + saved_invert.get(addr), + new_invert.get(addr), + ) + for addr in sorted(all_addrs) + } + + # The criteria for diff judgement is in these dict comprehensions: + # Any function not in the saved file + new_functions = { + key: (saved, new) for key, (saved, new) in combined.items() if saved is None + } + + # Any function now missing from the saved file + # or a non-stub -> stub conversion + dropped_functions = { + key: (saved, new) + for key, (saved, new) in combined.items() + if new is None + or ( + new is not None + and saved is not None + and new.get("stub", False) + and not saved.get("stub", False) + ) + } + + # TODO: move these two into functions if the assessment gets more complex + # Any function with increased match percentage + # or stub -> non-stub conversion + improved_functions = { + key: (saved, new) + for key, (saved, new) in combined.items() + if saved is not None + and new is not None + and ( + new["matching"] > saved["matching"] + or (not new.get("stub", False) and saved.get("stub", False)) + ) + } + + # Any non-stub function with decreased match percentage + degraded_functions = { + key: (saved, new) + for key, (saved, new) in combined.items() + if saved is not None + and new is not None + and new["matching"] < saved["matching"] + and not saved.get("stub") + and not new.get("stub") + } + + # Any function with former or current "effective" match + entropy_functions = { + key: (saved, new) + for key, (saved, new) in combined.items() + if saved is not None + and new is not None + and new["matching"] == 1.0 + and saved["matching"] == 1.0 + and new.get("effective", False) != saved.get("effective", False) + } + + get_diff_str = diff_json_display(show_both_addrs, is_plain) + + for diff_name, diff_dict in [ + ("New", new_functions), + ("Increased", improved_functions), + ("Decreased", degraded_functions), + ("Dropped", dropped_functions), + ("Compiler entropy", entropy_functions), + ]: + if len(diff_dict) == 0: + continue + + print(f"{diff_name} ({len(diff_dict)}):") + + for addr, (saved, new) in diff_dict.items(): + print(get_diff_str(addr, saved, new)) + + print() + + +def get_file_in_script_dir(fn): + return os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), fn) diff --git a/tools/isledecomp/setup.py b/tools/isledecomp/setup.py new file mode 100644 index 00000000..bf3e05dc --- /dev/null +++ b/tools/isledecomp/setup.py @@ -0,0 +1,11 @@ +from setuptools import setup, find_packages + +setup( + name="isledecomp", + version="0.1.0", + description="Python tools for the isledecomp project", + packages=find_packages(), + tests_require=["pytest"], + include_package_data=True, + package_data={"isledecomp.lib": ["*.exe", "*.dll"]}, +) diff --git a/tools/isledecomp/tests/__init__.py b/tools/isledecomp/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tools/isledecomp/tests/conftest.py b/tools/isledecomp/tests/conftest.py new file mode 100644 index 00000000..9f56b8a7 --- /dev/null +++ b/tools/isledecomp/tests/conftest.py @@ -0,0 +1,3 @@ +def pytest_addoption(parser): + """Allow the option to run tests against the original LEGO1.DLL.""" + parser.addoption("--lego1", action="store", help="Path to LEGO1.DLL") diff --git a/tools/isledecomp/tests/samples/basic_class.cpp b/tools/isledecomp/tests/samples/basic_class.cpp new file mode 100644 index 00000000..4316ad4a --- /dev/null +++ b/tools/isledecomp/tests/samples/basic_class.cpp @@ -0,0 +1,30 @@ +// Sample for python unit tests +// Not part of the decomp + +// A very simple class + +// VTABLE: TEST 0x1001002 +class TestClass { +public: + TestClass(); + virtual ~TestClass() override; + + virtual MxResult Tickle() override; // vtable+08 + + // FUNCTION: TEST 0x12345678 + inline const char* ClassName() const // vtable+0c + { + // 0xabcd1234 + return "TestClass"; + } + + // FUNCTION: TEST 0xdeadbeef + inline MxBool IsA(const char* name) const override // vtable+10 + { + return !strcmp(name, TestClass::ClassName()); + } + +private: + int m_hello; + int m_hiThere; +}; diff --git a/tools/isledecomp/tests/samples/basic_file.cpp b/tools/isledecomp/tests/samples/basic_file.cpp new file mode 100644 index 00000000..99930de8 --- /dev/null +++ b/tools/isledecomp/tests/samples/basic_file.cpp @@ -0,0 +1,22 @@ +// Sample for python unit tests +// Not part of the decomp + +// A very simple well-formed code file + +// FUNCTION: TEST 0x1234 +void function01() +{ + // TODO +} + +// FUNCTION: TEST 0x2345 +void function02() +{ + // TODO +} + +// FUNCTION: TEST 0x3456 +void function03() +{ + // TODO +} diff --git a/tools/isledecomp/tests/samples/global_variables.cpp b/tools/isledecomp/tests/samples/global_variables.cpp new file mode 100644 index 00000000..3be0316a --- /dev/null +++ b/tools/isledecomp/tests/samples/global_variables.cpp @@ -0,0 +1,14 @@ +// Sample for python unit tests +// Not part of the decomp + +// Global variables inside and outside of functions + +// GLOBAL: TEST 0x1000 +const char *g_message = "test"; + +// FUNCTION: TEST 0x1234 +void function01() +{ + // GLOBAL: TEST 0x5555 + static int g_hello = 123; +} diff --git a/tools/isledecomp/tests/samples/inline.cpp b/tools/isledecomp/tests/samples/inline.cpp new file mode 100644 index 00000000..8a36c89a --- /dev/null +++ b/tools/isledecomp/tests/samples/inline.cpp @@ -0,0 +1,8 @@ +// Sample for python unit tests +// Not part of the decomp + +// FUNCTION: TEST 0x10000001 +inline const char* OneLineWithComment() const { return "MxDSObject"; }; // hi there + +// FUNCTION: TEST 0x10000002 +inline const char* OneLine() const { return "MxDSObject"; }; diff --git a/tools/isledecomp/tests/samples/missing_offset.cpp b/tools/isledecomp/tests/samples/missing_offset.cpp new file mode 100644 index 00000000..3f6b3811 --- /dev/null +++ b/tools/isledecomp/tests/samples/missing_offset.cpp @@ -0,0 +1,16 @@ +// Sample for python unit tests +// Not part of the decomp + +#include + +int no_offset_comment() +{ + static int dummy = 123; + return -1; +} + +// FUNCTION: TEST 0xdeadbeef +void regular_ole_function() +{ + printf("hi there"); +} diff --git a/tools/isledecomp/tests/samples/multiple_offsets.cpp b/tools/isledecomp/tests/samples/multiple_offsets.cpp new file mode 100644 index 00000000..dc3c5bfa --- /dev/null +++ b/tools/isledecomp/tests/samples/multiple_offsets.cpp @@ -0,0 +1,25 @@ +// Sample for python unit tests +// Not part of the decomp + +// Handling multiple offset markers + +// FUNCTION: TEST 0x1234 +// FUNCTION: HELLO 0x5555 +void different_modules() +{ + // TODO +} + +// FUNCTION: TEST 0x2345 +// FUNCTION: TEST 0x1234 +void same_module() +{ + // TODO +} + +// FUNCTION: TEST 0x2002 +// FUNCTION: test 0x1001 +void same_case_insensitive() +{ + // TODO +} diff --git a/tools/isledecomp/tests/samples/oneline_function.cpp b/tools/isledecomp/tests/samples/oneline_function.cpp new file mode 100644 index 00000000..feb82314 --- /dev/null +++ b/tools/isledecomp/tests/samples/oneline_function.cpp @@ -0,0 +1,12 @@ +// Sample for python unit tests +// Not part of the decomp + +// FUNCTION: TEST 0x1234 +void short_function() { static char* msg = "oneliner"; } + +// FUNCTION: TEST 0x5555 +void function_after_one_liner() +{ + // This function comes after the previous that is on a single line. + // Do we report the offset for this one correctly? +} diff --git a/tools/isledecomp/tests/samples/out_of_order.cpp b/tools/isledecomp/tests/samples/out_of_order.cpp new file mode 100644 index 00000000..951c99e7 --- /dev/null +++ b/tools/isledecomp/tests/samples/out_of_order.cpp @@ -0,0 +1,20 @@ +// Sample for python unit tests +// Not part of the decomp + +// FUNCTION: TEST 0x1001 +void function_order01() +{ + // TODO +} + +// FUNCTION: TEST 0x1003 +void function_order03() +{ + // TODO +} + +// FUNCTION: TEST 0x1002 +void function_order02() +{ + // TODO +} diff --git a/tools/isledecomp/tests/samples/poorly_formatted.cpp b/tools/isledecomp/tests/samples/poorly_formatted.cpp new file mode 100644 index 00000000..69f365ec --- /dev/null +++ b/tools/isledecomp/tests/samples/poorly_formatted.cpp @@ -0,0 +1,23 @@ +// Sample for python unit tests +// Not part of the decomp + +// While it's reasonable to expect a well-formed file (and clang-format +// will make sure we get one), this will put the parser through its paces. + +// FUNCTION: TEST 0x1234 +void curly_with_spaces() + { + static char* msg = "hello"; + } + +// FUNCTION: TEST 0x5555 +void weird_closing_curly() +{ + int x = 123; } + +// FUNCTION: HELLO 0x5656 +void bad_indenting() { + if (0) +{ + int y = 5; +}} diff --git a/tools/isledecomp/tests/test_compare_db.py b/tools/isledecomp/tests/test_compare_db.py new file mode 100644 index 00000000..55cb75a5 --- /dev/null +++ b/tools/isledecomp/tests/test_compare_db.py @@ -0,0 +1,82 @@ +"""Testing compare database behavior, particularly matching""" +import pytest +from isledecomp.compare.db import CompareDb + + +@pytest.fixture(name="db") +def fixture_db(): + return CompareDb() + + +def test_ignore_recomp_collision(db): + """Duplicate recomp addresses are ignored""" + db.set_recomp_symbol(0x1234, None, "hello", None, 100) + db.set_recomp_symbol(0x1234, None, "alias_for_hello", None, 100) + syms = db.get_all() + assert len(syms) == 1 + + +def test_orig_collision(db): + """Don't match if the original address is not unique""" + db.set_recomp_symbol(0x1234, None, "hello", None, 100) + assert db.match_function(0x5555, "hello") is True + + # Second run on same address fails + assert db.match_function(0x5555, "hello") is False + + # Call set_pair directly without wrapper + assert db.set_pair(0x5555, 0x1234) is False + + +def test_name_match(db): + db.set_recomp_symbol(0x1234, None, "hello", None, 100) + assert db.match_function(0x5555, "hello") is True + + match = db.get_by_orig(0x5555) + assert match.name == "hello" + assert match.recomp_addr == 0x1234 + + +def test_match_decorated(db): + """Should match using decorated name even though regular name is null""" + db.set_recomp_symbol(0x1234, None, None, "?_hello", 100) + assert db.match_function(0x5555, "?_hello") is True + match = db.get_by_orig(0x5555) + assert match is not None + + +def test_duplicate_name(db): + """If recomp name is not unique, match only one row""" + db.set_recomp_symbol(0x100, None, "_Construct", None, 100) + db.set_recomp_symbol(0x200, None, "_Construct", None, 100) + db.set_recomp_symbol(0x300, None, "_Construct", None, 100) + db.match_function(0x5555, "_Construct") + matches = db.get_matches() + # We aren't testing _which_ one would be matched, just that only one _was_ matched + assert len(matches) == 1 + + +def test_static_variable_match(db): + """Set up a situation where we can match a static function variable, then match it.""" + + # We need a matched function to start with. + db.set_recomp_symbol(0x1234, None, "Isle::Tick", "?Tick@IsleApp@@QAEXH@Z", 100) + db.match_function(0x5555, "Isle::Tick") + + # Decorated variable name from PDB. + db.set_recomp_symbol( + 0x2000, None, None, "?g_startupDelay@?1??Tick@IsleApp@@QAEXH@Z@4HA", 4 + ) + + # Provide variable name and orig function address from decomp markers + assert db.match_static_variable(0xBEEF, "g_startupDelay", 0x5555) is True + + +def test_match_options_bool(db): + """Test handling of boolean match options""" + + # You don't actually need an existing orig addr for this. + assert db.get_match_options(0x1234) == {} + + db.mark_stub(0x1234) + assert "stub" in db.get_match_options(0x1234) diff --git a/tools/isledecomp/tests/test_curly.py b/tools/isledecomp/tests/test_curly.py new file mode 100644 index 00000000..8328f5e9 --- /dev/null +++ b/tools/isledecomp/tests/test_curly.py @@ -0,0 +1,73 @@ +# nyuk nyuk nyuk +import pytest +from isledecomp.parser.parser import CurlyManager +from isledecomp.parser.util import sanitize_code_line + + +@pytest.fixture(name="curly") +def fixture_curly(): + return CurlyManager() + + +def test_simple(curly): + curly.read_line("namespace Test {") + assert curly.get_prefix() == "Test" + curly.read_line("}") + assert curly.get_prefix() == "" + + +def test_oneliner(curly): + """Should not go down into a scope for a class forward reference""" + curly.read_line("class LegoEntity;") + assert curly.get_prefix() == "" + # Now make sure that we still would not consider that class name + # even after reading the opening curly brace + curly.read_line("if (true) {") + assert curly.get_prefix() == "" + + +def test_ignore_comments(curly): + curly.read_line("namespace Test {") + curly.read_line("// }") + assert curly.get_prefix() == "Test" + + +@pytest.mark.xfail(reason="todo: need a real lexer") +def test_ignore_multiline_comments(curly): + curly.read_line("namespace Test {") + curly.read_line("/*") + curly.read_line("}") + curly.read_line("*/") + assert curly.get_prefix() == "Test" + curly.read_line("}") + assert curly.get_prefix() == "" + + +def test_nested(curly): + curly.read_line("namespace Test {") + curly.read_line("namespace Foo {") + assert curly.get_prefix() == "Test::Foo" + curly.read_line("}") + assert curly.get_prefix() == "Test" + + +sanitize_cases = [ + ("", ""), + (" ", ""), + ("{", "{"), + ("// comments {", ""), + ("{ // why comment here", "{"), + ("/* comments */ {", "{"), + ('"curly in a string {"', '""'), + ('if (!strcmp("hello { there }", g_test)) {', 'if (!strcmp("", g_test)) {'), + ("'{'", "''"), + ("weird_function('\"', hello, '\"')", "weird_function('', hello, '')"), +] + + +@pytest.mark.parametrize("start, end", sanitize_cases) +def test_sanitize(start: str, end: str): + """Make sure that we can remove curly braces in places where they should + not be considered as part of the semantic structure of the file. + i.e. inside strings or chars, and inside comments""" + assert sanitize_code_line(start) == end diff --git a/tools/isledecomp/tests/test_cvdump.py b/tools/isledecomp/tests/test_cvdump.py new file mode 100644 index 00000000..3670e495 --- /dev/null +++ b/tools/isledecomp/tests/test_cvdump.py @@ -0,0 +1,59 @@ +import pytest +from isledecomp.cvdump.types import ( + scalar_type_size, + scalar_type_pointer, + scalar_type_signed, +) + +# These are all the types seen in the cvdump. +# We have char, short, int, long, long long, float, and double all represented +# in both signed and unsigned. +# We can also identify a 4 byte pointer with the T_32 prefix. +# The type T_VOID is used to designate a function's return type. +# T_NOTYPE is specified as the type of "this" for a static function in a class. + +# For reference: https://github.com/microsoft/microsoft-pdb/blob/master/include/cvinfo.h + +# fmt: off +# Fields are: type_name, size, is_signed, is_pointer +type_check_cases = ( + ("T_32PINT4", 4, False, True), + ("T_32PLONG", 4, False, True), + ("T_32PRCHAR", 4, False, True), + ("T_32PREAL32", 4, False, True), + ("T_32PUCHAR", 4, False, True), + ("T_32PUINT4", 4, False, True), + ("T_32PULONG", 4, False, True), + ("T_32PUSHORT", 4, False, True), + ("T_32PVOID", 4, False, True), + ("T_CHAR", 1, True, False), + ("T_INT4", 4, True, False), + ("T_LONG", 4, True, False), + ("T_QUAD", 8, True, False), + ("T_RCHAR", 1, True, False), + ("T_REAL32", 4, True, False), + ("T_REAL64", 8, True, False), + ("T_SHORT", 2, True, False), + ("T_UCHAR", 1, False, False), + ("T_UINT4", 4, False, False), + ("T_ULONG", 4, False, False), + ("T_UQUAD", 8, False, False), + ("T_USHORT", 2, False, False), + ("T_WCHAR", 2, False, False), +) +# fmt: on + + +@pytest.mark.parametrize("type_name, size, _, __", type_check_cases) +def test_scalar_size(type_name: str, size: int, _, __): + assert scalar_type_size(type_name) == size + + +@pytest.mark.parametrize("type_name, _, is_signed, __", type_check_cases) +def test_scalar_signed(type_name: str, _, is_signed: bool, __): + assert scalar_type_signed(type_name) == is_signed + + +@pytest.mark.parametrize("type_name, _, __, is_pointer", type_check_cases) +def test_scalar_pointer(type_name: str, _, __, is_pointer: bool): + assert scalar_type_pointer(type_name) == is_pointer diff --git a/tools/isledecomp/tests/test_cvdump_types.py b/tools/isledecomp/tests/test_cvdump_types.py new file mode 100644 index 00000000..e90cff0f --- /dev/null +++ b/tools/isledecomp/tests/test_cvdump_types.py @@ -0,0 +1,465 @@ +"""Specifically testing the Cvdump TYPES parser +and type dependency tree walker.""" + +import pytest +from isledecomp.cvdump.types import ( + CvdumpTypesParser, + CvdumpKeyError, + CvdumpIntegrityError, +) + +TEST_LINES = """ +0x1028 : Length = 10, Leaf = 0x1001 LF_MODIFIER + const, modifies type T_REAL32(0040) + +0x103b : Length = 14, Leaf = 0x1503 LF_ARRAY + Element type = T_REAL32(0040) + Index type = T_SHORT(0011) + length = 16 + Name = + +0x103c : Length = 14, Leaf = 0x1503 LF_ARRAY + Element type = 0x103B + Index type = T_SHORT(0011) + length = 64 + Name = + +0x10e0 : Length = 86, Leaf = 0x1203 LF_FIELDLIST + list[0] = LF_MEMBER, public, type = T_REAL32(0040), offset = 0 + member name = 'x' + list[1] = LF_MEMBER, public, type = T_REAL32(0040), offset = 0 + member name = 'dvX' + list[2] = LF_MEMBER, public, type = T_REAL32(0040), offset = 4 + member name = 'y' + list[3] = LF_MEMBER, public, type = T_REAL32(0040), offset = 4 + member name = 'dvY' + list[4] = LF_MEMBER, public, type = T_REAL32(0040), offset = 8 + member name = 'z' + list[5] = LF_MEMBER, public, type = T_REAL32(0040), offset = 8 + member name = 'dvZ' + +0x10e1 : Length = 34, Leaf = 0x1505 LF_STRUCTURE + # members = 6, field list type 0x10e0, + Derivation list type 0x0000, VT shape type 0x0000 + Size = 12, class name = _D3DVECTOR, UDT(0x000010e1) + +0x10e4 : Length = 14, Leaf = 0x1503 LF_ARRAY + Element type = T_UCHAR(0020) + Index type = T_SHORT(0011) + length = 8 + Name = + +0x10ea : Length = 14, Leaf = 0x1503 LF_ARRAY + Element type = 0x1028 + Index type = T_SHORT(0011) + length = 12 + Name = + +0x11f0 : Length = 30, Leaf = 0x1504 LF_CLASS + # members = 0, field list type 0x0000, FORWARD REF, + Derivation list type 0x0000, VT shape type 0x0000 + Size = 0, class name = MxRect32, UDT(0x00001214) + +0x11f2 : Length = 10, Leaf = 0x1001 LF_MODIFIER + const, modifies type 0x11F0 + +0x1213 : Length = 530, Leaf = 0x1203 LF_FIELDLIST + list[0] = LF_METHOD, count = 5, list = 0x1203, name = 'MxRect32' + list[1] = LF_ONEMETHOD, public, VANILLA, index = 0x1205, name = 'operator=' + list[2] = LF_ONEMETHOD, public, VANILLA, index = 0x11F5, name = 'Intersect' + list[3] = LF_ONEMETHOD, public, VANILLA, index = 0x1207, name = 'SetPoint' + list[4] = LF_ONEMETHOD, public, VANILLA, index = 0x1207, name = 'AddPoint' + list[5] = LF_ONEMETHOD, public, VANILLA, index = 0x1207, name = 'SubtractPoint' + list[6] = LF_ONEMETHOD, public, VANILLA, index = 0x11F5, name = 'UpdateBounds' + list[7] = LF_ONEMETHOD, public, VANILLA, index = 0x1209, name = 'IsValid' + list[8] = LF_ONEMETHOD, public, VANILLA, index = 0x120A, name = 'IntersectsWith' + list[9] = LF_ONEMETHOD, public, VANILLA, index = 0x120B, name = 'GetWidth' + list[10] = LF_ONEMETHOD, public, VANILLA, index = 0x120B, name = 'GetHeight' + list[11] = LF_ONEMETHOD, public, VANILLA, index = 0x120C, name = 'GetPoint' + list[12] = LF_ONEMETHOD, public, VANILLA, index = 0x120D, name = 'GetSize' + list[13] = LF_ONEMETHOD, public, VANILLA, index = 0x120B, name = 'GetLeft' + list[14] = LF_ONEMETHOD, public, VANILLA, index = 0x120B, name = 'GetTop' + list[15] = LF_ONEMETHOD, public, VANILLA, index = 0x120B, name = 'GetRight' + list[16] = LF_ONEMETHOD, public, VANILLA, index = 0x120B, name = 'GetBottom' + list[17] = LF_ONEMETHOD, public, VANILLA, index = 0x120E, name = 'SetLeft' + list[18] = LF_ONEMETHOD, public, VANILLA, index = 0x120E, name = 'SetTop' + list[19] = LF_ONEMETHOD, public, VANILLA, index = 0x120E, name = 'SetRight' + list[20] = LF_ONEMETHOD, public, VANILLA, index = 0x120E, name = 'SetBottom' + list[21] = LF_METHOD, count = 3, list = 0x1211, name = 'CopyFrom' + list[22] = LF_ONEMETHOD, private, STATIC, index = 0x1212, name = 'Min' + list[23] = LF_ONEMETHOD, private, STATIC, index = 0x1212, name = 'Max' + list[24] = LF_MEMBER, private, type = T_INT4(0074), offset = 0 + member name = 'm_left' + list[25] = LF_MEMBER, private, type = T_INT4(0074), offset = 4 + member name = 'm_top' + list[26] = LF_MEMBER, private, type = T_INT4(0074), offset = 8 + member name = 'm_right' + list[27] = LF_MEMBER, private, type = T_INT4(0074), offset = 12 + member name = 'm_bottom' + +0x1214 : Length = 30, Leaf = 0x1504 LF_CLASS + # members = 34, field list type 0x1213, CONSTRUCTOR, OVERLOAD, + Derivation list type 0x0000, VT shape type 0x0000 + Size = 16, class name = MxRect32, UDT(0x00001214) + +0x1220 : Length = 30, Leaf = 0x1504 LF_CLASS + # members = 0, field list type 0x0000, FORWARD REF, + Derivation list type 0x0000, VT shape type 0x0000 + Size = 0, class name = MxCore, UDT(0x00004060) + +0x14db : Length = 30, Leaf = 0x1504 LF_CLASS + # members = 0, field list type 0x0000, FORWARD REF, + Derivation list type 0x0000, VT shape type 0x0000 + Size = 0, class name = MxString, UDT(0x00004db6) + +0x19b0 : Length = 34, Leaf = 0x1505 LF_STRUCTURE + # members = 0, field list type 0x0000, FORWARD REF, + Derivation list type 0x0000, VT shape type 0x0000 + Size = 0, class name = ROIColorAlias, UDT(0x00002a76) + +0x19b1 : Length = 14, Leaf = 0x1503 LF_ARRAY + Element type = 0x19B0 + Index type = T_SHORT(0011) + length = 440 + Name = + +0x2a75 : Length = 98, Leaf = 0x1203 LF_FIELDLIST + list[0] = LF_MEMBER, public, type = T_32PRCHAR(0470), offset = 0 + member name = 'm_name' + list[1] = LF_MEMBER, public, type = T_INT4(0074), offset = 4 + member name = 'm_red' + list[2] = LF_MEMBER, public, type = T_INT4(0074), offset = 8 + member name = 'm_green' + list[3] = LF_MEMBER, public, type = T_INT4(0074), offset = 12 + member name = 'm_blue' + list[4] = LF_MEMBER, public, type = T_INT4(0074), offset = 16 + member name = 'm_unk0x10' + +0x2a76 : Length = 34, Leaf = 0x1505 LF_STRUCTURE + # members = 5, field list type 0x2a75, + Derivation list type 0x0000, VT shape type 0x0000 + Size = 20, class name = ROIColorAlias, UDT(0x00002a76) + +0x22d4 : Length = 154, Leaf = 0x1203 LF_FIELDLIST + list[0] = LF_VFUNCTAB, type = 0x20FC + list[1] = LF_METHOD, count = 3, list = 0x22D0, name = 'MxVariable' + list[2] = LF_ONEMETHOD, public, INTRODUCING VIRTUAL, index = 0x1F0F, + vfptr offset = 0, name = 'GetValue' + list[3] = LF_ONEMETHOD, public, INTRODUCING VIRTUAL, index = 0x1F10, + vfptr offset = 4, name = 'SetValue' + list[4] = LF_ONEMETHOD, public, INTRODUCING VIRTUAL, index = 0x1F11, + vfptr offset = 8, name = '~MxVariable' + list[5] = LF_ONEMETHOD, public, VANILLA, index = 0x22D3, name = 'GetKey' + list[6] = LF_MEMBER, protected, type = 0x14DB, offset = 4 + member name = 'm_key' + list[7] = LF_MEMBER, protected, type = 0x14DB, offset = 20 + member name = 'm_value' + +0x22d5 : Length = 34, Leaf = 0x1504 LF_CLASS + # members = 10, field list type 0x22d4, CONSTRUCTOR, + Derivation list type 0x0000, VT shape type 0x20fb + Size = 36, class name = MxVariable, UDT(0x00004041) + +0x3cc2 : Length = 38, Leaf = 0x1507 LF_ENUM + # members = 64, type = T_INT4(0074) field list type 0x3cc1 +NESTED, enum name = JukeBox::JukeBoxScript, UDT(0x00003cc2) + +0x3fab : Length = 10, Leaf = 0x1002 LF_POINTER + Pointer (NEAR32), Size: 0 + Element type : 0x3FAA + +0x405f : Length = 158, Leaf = 0x1203 LF_FIELDLIST + list[0] = LF_VFUNCTAB, type = 0x2090 + list[1] = LF_ONEMETHOD, public, VANILLA, index = 0x176A, name = 'MxCore' + list[2] = LF_ONEMETHOD, public, INTRODUCING VIRTUAL, index = 0x176A, + vfptr offset = 0, name = '~MxCore' + list[3] = LF_ONEMETHOD, public, INTRODUCING VIRTUAL, index = 0x176B, + vfptr offset = 4, name = 'Notify' + list[4] = LF_ONEMETHOD, public, INTRODUCING VIRTUAL, index = 0x2087, + vfptr offset = 8, name = 'Tickle' + list[5] = LF_ONEMETHOD, public, INTRODUCING VIRTUAL, index = 0x202F, + vfptr offset = 12, name = 'ClassName' + list[6] = LF_ONEMETHOD, public, INTRODUCING VIRTUAL, index = 0x2030, + vfptr offset = 16, name = 'IsA' + list[7] = LF_ONEMETHOD, public, VANILLA, index = 0x2091, name = 'GetId' + list[8] = LF_MEMBER, private, type = T_UINT4(0075), offset = 4 + member name = 'm_id' + +0x4060 : Length = 30, Leaf = 0x1504 LF_CLASS + # members = 9, field list type 0x405f, CONSTRUCTOR, + Derivation list type 0x0000, VT shape type 0x1266 + Size = 8, class name = MxCore, UDT(0x00004060) + +0x4262 : Length = 14, Leaf = 0x1503 LF_ARRAY + Element type = 0x3CC2 + Index type = T_SHORT(0011) + length = 24 + Name = + +0x432f : Length = 14, Leaf = 0x1503 LF_ARRAY + Element type = T_INT4(0074) + Index type = T_SHORT(0011) + length = 12 + Name = + +0x4db5 : Length = 246, Leaf = 0x1203 LF_FIELDLIST + list[0] = LF_BCLASS, public, type = 0x1220, offset = 0 + list[1] = LF_METHOD, count = 3, list = 0x14E3, name = 'MxString' + list[2] = LF_ONEMETHOD, public, VIRTUAL, index = 0x14DE, name = '~MxString' + list[3] = LF_METHOD, count = 2, list = 0x14E7, name = 'operator=' + list[4] = LF_ONEMETHOD, public, VANILLA, index = 0x14DE, name = 'ToUpperCase' + list[5] = LF_ONEMETHOD, public, VANILLA, index = 0x14DE, name = 'ToLowerCase' + list[6] = LF_ONEMETHOD, public, VANILLA, index = 0x14E8, name = 'operator+' + list[7] = LF_ONEMETHOD, public, VANILLA, index = 0x14E9, name = 'operator+=' + list[8] = LF_ONEMETHOD, public, VANILLA, index = 0x14EB, name = 'Compare' + list[9] = LF_ONEMETHOD, public, VANILLA, index = 0x14EC, name = 'GetData' + list[10] = LF_ONEMETHOD, public, VANILLA, index = 0x4DB4, name = 'GetLength' + list[11] = LF_MEMBER, private, type = T_32PRCHAR(0470), offset = 8 + member name = 'm_data' + list[12] = LF_MEMBER, private, type = T_USHORT(0021), offset = 12 + member name = 'm_length' + +0x4db6 : Length = 30, Leaf = 0x1504 LF_CLASS + # members = 16, field list type 0x4db5, CONSTRUCTOR, OVERLOAD, + Derivation list type 0x0000, VT shape type 0x1266 + Size = 16, class name = MxString, UDT(0x00004db6) +""" + + +@pytest.fixture(name="parser") +def types_parser_fixture(): + parser = CvdumpTypesParser() + for line in TEST_LINES.split("\n"): + parser.read_line(line) + + return parser + + +def test_basic_parsing(parser): + obj = parser.keys["0x4db6"] + assert obj["type"] == "LF_CLASS" + assert obj["name"] == "MxString" + assert obj["udt"] == "0x4db6" + + assert len(parser.keys["0x4db5"]["members"]) == 2 + + +def test_scalar_types(parser): + """Full tests on the scalar_* methods are in another file. + Here we are just testing the passthrough of the "T_" types.""" + assert parser.get("T_CHAR").name is None + assert parser.get("T_CHAR").size == 1 + + assert parser.get("T_32PVOID").name is None + assert parser.get("T_32PVOID").size == 4 + + +def test_resolve_forward_ref(parser): + # Non-forward ref + assert parser.get("0x22d5").name == "MxVariable" + # Forward ref + assert parser.get("0x14db").name == "MxString" + assert parser.get("0x14db").size == 16 + + +def test_members(parser): + """Return the list of items to compare for a given complex type. + If the class has a superclass, add those members too.""" + # MxCore field list + mxcore_members = parser.get_scalars("0x405f") + assert mxcore_members == [ + (0, "vftable", "T_32PVOID"), + (4, "m_id", "T_UINT4"), + ] + + # MxCore class id. Should be the same members + assert mxcore_members == parser.get_scalars("0x4060") + + # MxString field list. Should add inherited members from MxCore + assert parser.get_scalars("0x4db5") == [ + (0, "vftable", "T_32PVOID"), + (4, "m_id", "T_UINT4"), + (8, "m_data", "T_32PRCHAR"), + (12, "m_length", "T_USHORT"), + ] + + +def test_members_recursive(parser): + """Make sure that we unwrap the dependency tree correctly.""" + # MxVariable field list + assert parser.get_scalars("0x22d4") == [ + (0, "vftable", "T_32PVOID"), + (4, "m_key.vftable", "T_32PVOID"), + (8, "m_key.m_id", "T_UINT4"), + (12, "m_key.m_data", "T_32PRCHAR"), + (16, "m_key.m_length", "T_USHORT"), # with padding + (20, "m_value.vftable", "T_32PVOID"), + (24, "m_value.m_id", "T_UINT4"), + (28, "m_value.m_data", "T_32PRCHAR"), + (32, "m_value.m_length", "T_USHORT"), # with padding + ] + + +def test_struct(parser): + """Basic test for converting type into struct.unpack format string.""" + # MxCore: vftable and uint32. The vftable pointer is read as uint32. + assert parser.get_format_string("0x4060") == "::`vftable'"), + ( + "??_7?$MxPtrList@VLegoPathController@@@@6B@", + "MxPtrList::`vftable'", + ), + ("??_7Renderer@Tgl@@6B@", "Tgl::Renderer::`vftable'"), + ("??_7LegoExtraActor@@6B0@@", "LegoExtraActor::`vftable'{for `LegoExtraActor'}"), + ( + "??_7LegoExtraActor@@6BLegoAnimActor@@@", + "LegoExtraActor::`vftable'{for `LegoAnimActor'}", + ), + ( + "??_7LegoAnimActor@@6B?$LegoContainer@PAM@@@", + "LegoAnimActor::`vftable'{for `LegoContainer'}", + ), +] + + +@pytest.mark.parametrize("symbol, class_name", vtable_cases) +def test_vtable(symbol, class_name): + assert demangle_vtable(symbol) == class_name + + +def test_vtordisp(): + """Make sure we can accurately detect an adjuster thunk symbol""" + assert get_vtordisp_name("") is None + assert get_vtordisp_name("?ClassName@LegoExtraActor@@UBEPBDXZ") is None + assert ( + get_vtordisp_name("?ClassName@LegoExtraActor@@$4PPPPPPPM@A@BEPBDXZ") is not None + ) + + # A function called vtordisp + assert get_vtordisp_name("?vtordisp@LegoExtraActor@@UBEPBDXZ") is None diff --git a/tools/isledecomp/tests/test_instgen.py b/tools/isledecomp/tests/test_instgen.py new file mode 100644 index 00000000..060d46d9 --- /dev/null +++ b/tools/isledecomp/tests/test_instgen.py @@ -0,0 +1,212 @@ +from isledecomp.compare.asm.instgen import InstructGen, SectionType + + +def test_ret(): + """Make sure we can handle a function with one instruction.""" + ig = InstructGen(b"\xc3", 0) + assert len(ig.sections) == 1 + + +SCORE_NOTIFY = ( + b"\x53\x56\x57\x8b\xd9\x33\xff\x8b\x74\x24\x10\x56\xe8\xbf\xe1\x01" + b"\x00\x80\xbb\xf6\x00\x00\x00\x00\x0f\x84\x9c\x00\x00\x00\x8b\x4e" + b"\x04\x49\x83\xf9\x17\x0f\x87\x8f\x00\x00\x00\x33\xc0\x8a\x81\xec" + b"\x14\x00\x10\xff\x24\x85\xd4\x14\x00\x10\x8b\xcb\xbf\x01\x00\x00" + b"\x00\xe8\x7a\x05\x00\x00\x8b\xc7\x5f\x5e\x5b\xc2\x04\x00\x56\x8b" + b"\xcb\xe8\xaa\x00\x00\x00\x8b\xf8\x8b\xc7\x5f\x5e\x5b\xc2\x04\x00" + b"\x80\x7e\x18\x20\x75\x07\x8b\xcb\xe8\xc3\xfe\xff\xff\xbf\x01\x00" + b"\x00\x00\x8b\xc7\x5f\x5e\x5b\xc2\x04\x00\x56\x8b\xcb\xe8\x3e\x02" + b"\x00\x00\x8b\xf8\x8b\xc7\x5f\x5e\x5b\xc2\x04\x00\x6a\x09\xa1\x4c" + b"\x45\x0f\x10\x6a\x07\x50\xe8\x35\x45\x01\x00\x83\xc4\x0c\x8b\x83" + b"\xf8\x00\x00\x00\x85\xc0\x74\x0d\x50\xe8\xa2\x42\x01\x00\x8b\xc8" + b"\xe8\x9b\x9b\x03\x00\xbf\x01\x00\x00\x00\x8b\xc7\x5f\x5e\x5b\xc2" + b"\x04\x00\x8b\xff\x4a\x14\x00\x10\x5e\x14\x00\x10\x70\x14\x00\x10" + b"\x8a\x14\x00\x10\x9c\x14\x00\x10\xca\x14\x00\x10\x00\x01\x05\x05" + b"\x05\x05\x02\x05\x05\x05\x05\x05\x05\x05\x05\x05\x03\x05\x05\x05" + b"\x05\x05\x05\x04\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc" +) + + +def test_score_notify(): + """Score::Notify function from 0x10001410 in LEGO1. + Good representative function for jump table (at 0x100014d4) + and switch data (at 0x100014ec).""" + ig = InstructGen(SCORE_NOTIFY, 0x10001410) + + # Did we get everything? + assert len(ig.sections) == 3 + types_only = tuple(s.type for s in ig.sections) + assert types_only == (SectionType.CODE, SectionType.ADDR_TAB, SectionType.DATA_TAB) + + # CODE section stopped at correct place? + instructions = ig.sections[0].contents + assert instructions[-1].address == 0x100014D2 + # n.b. 0x100014d2 is the dummy instruction `mov edi, edi` + # Ghidra does more thorough analysis and ignores this. + # The last real instruction should be at 0x100014cf. Not a big deal + # to include this because it is not junk data. + + # 6 switch addresses + assert len(ig.sections[1].contents) == 6 + + # TODO: The data table at the end includes all of the 0xCC padding bytes. + + +SMACK_CASE = ( + # LEGO1: 0x100cdc43 (modified so jump table points at +0x1016) + b"\x2e\xff\x24\x8d\x16\x10\x00\x00" + # LEGO1: 0x100cdb62 (instructions before and after jump table) + b"\x8b\xf8\xeb\x1a\x87\xdb\x87\xc9\x87\xdb\x87\xc9\x87\xdb\x50\xdc" + b"\x0c\x10\xd0\xe2\x0c\x10\xb0\xe8\x0c\x10\x50\xe9\x0c\x10\xa0\x10" + b"\x27\x10\x10\x3c\x11\x77\x17\x8a\xc8" +) + + +def test_smack_case(): + """Case where we have code / jump table / code. + Need to properly separate code sections, eliminate junk instructions + and continue disassembling at the proper address following the data.""" + ig = InstructGen(SMACK_CASE, 0x1000) + assert len(ig.sections) == 3 + assert ig.sections[0].type == ig.sections[2].type == SectionType.CODE + + # Make sure we captured the instruction immediately after + assert ig.sections[2].contents[0].mnemonic == "mov" + + +# BETA10 0x1004c9cc +BETA_FUNC = ( + b"\x55\x8b\xec\x83\xec\x08\x53\x56\x57\x89\x4d\xfc\x8b\x45\xfc\x33" + b"\xc9\x8a\x88\x19\x02\x00\x00\x89\x4d\xf8\xe9\x1e\x00\x00\x00\xe9" + b"\x41\x00\x00\x00\xe9\x3c\x00\x00\x00\xe9\x37\x00\x00\x00\xe9\x32" + b"\x00\x00\x00\xe9\x2d\x00\x00\x00\xe9\x28\x00\x00\x00\x83\x7d\xf8" + b"\x04\x0f\x87\x1e\x00\x00\x00\x8b\x45\xf8\xff\x24\x85\x1d\xca\x04" + b"\x10\xeb\xc9\x04\x10\xf0\xc9\x04\x10\xf5\xc9\x04\x10\xfa\xc9\x04" + b"\x10\xff\xc9\x04\x10\xb0\x01\xe9\x00\x00\x00\x00\x5f\x5e\x5b\xc9" + b"\xc2\x04\x00" +) + + +def test_beta_case(): + """Complete (and short) function with CODE / ADDR / CODE""" + ig = InstructGen(BETA_FUNC, 0x1004C9CC) + # The JMP into the jump table immediately precedes the jump table. + # We have to detect this and switch sections correctly or we will only + # get 1 section. + assert len(ig.sections) == 3 + assert ig.sections[0].type == ig.sections[2].type == SectionType.CODE + + # Make sure we captured the instruction immediately after + assert ig.sections[2].contents[0].mnemonic == "mov" + + +# LEGO1 0x1000fb50 +# TODO: The test data here is longer than it needs to be. +THUNK_TEST = ( + b"\x2b\x49\xfc\xe9\x08\x00\x00\x00\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc" + b"\x56\x8b\xf1\xe8\xd8\xc5\x00\x00\x8b\xce\xe8\xb1\xdc\x01\x00\xf6" + b"\x44\x24\x08\x01\x74\x0c\x8d\x46\xe0\x50\xe8\xe1\x66\x07\x00\x83" + b"\xc4\x04\x8d\x46\xe0\x5e\xc2\x04\x00\xcc\xcc\xcc\xcc\xcc\xcc\xcc" + b"\x2b\x49\xfc\xe9\x08\x00\x00\x00\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc" + b"\xb8\x7c\x05\x0f\x10\xc3\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc" + b"\x2b\x49\xfc\xe9\x08\x00\x00\x00\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc" + b"\x8b\x54" + # The problem is here: the last two bytes are the start of the next + # function 0x1000fbc0. This is not enough data to read an instruction. +) + + +def test_thunk_case(): + """Adjuster thunk incorrectly annotated. + We are reading way more bytes than we should for this function.""" + ig = InstructGen(THUNK_TEST, 0x1000FB50) + # No switch cases here, so the only section is code. + # This caused an infinite loop during testing so the goal is just to finish. + assert len(ig.sections) == 1 + + # TODO: We might detect the 0xCC padding bytes and cut off the function. + # If we did that, we would correctly read only 2 instructions. + # assert len(ig.sections[0].contents) == 2 + + +# LEGO1 0x1006f080, Infocenter::HandleEndAction +HANDLE_END_ACTION = ( + b"\x53\x56\x57\x8b\xf1\x8b\x5c\x24\x10\x8b\x0d\x84\x45\x0f\x10\x8b" + b"\x7b\x0c\x8b\x47\x20\x39\x01\x75\x29\x81\x7f\x1c\xf3\x01\x00\x00" + b"\x75\x20\xe8\x59\x66\xfa\xff\x6a\x00\x8b\x40\x18\x6a\x00\x6a\x10" + b"\x50\xff\x15\x38\xb5\x10\x10\xb8\x01\x00\x00\x00\x5f\x5e\x5b\xc2" + b"\x04\x00\x39\x46\x0c\x0f\x85\xa2\x00\x00\x00\x8b\x47\x1c\x83\xf8" + b"\x28\x74\x18\x83\xf8\x29\x74\x13\x83\xf8\x2a\x74\x0e\x83\xf8\x2b" + b"\x74\x09\x83\xf8\x2c\x0f\x85\x82\x00\x00\x00\x66\x8b\x86\xd4\x01" + b"\x00\x00\x66\x85\xc0\x74\x09\x66\x48\x66\x89\x86\xd4\x01\x00\x00" + b"\x66\x83\xbe\xd4\x01\x00\x00\x00\x75\x63\x6a\x0b\xe8\xff\x67\xfa" + b"\xff\x66\x8b\x86\xfc\x00\x00\x00\x83\xc4\x04\x50\xe8\x3f\x66\xfa" + b"\xff\x8b\xc8\xe8\x58\xa6\xfc\xff\x0f\xbf\x86\xfc\x00\x00\x00\x48" + b"\x83\xf8\x04\x77\x2f\xff\x24\x85\x78\xf4\x06\x10\x68\x1d\x02\x00" + b"\x00\xeb\x1a\x68\x1e\x02\x00\x00\xeb\x13\x68\x1f\x02\x00\x00\xeb" + b"\x0c\x68\x20\x02\x00\x00\xeb\x05\x68\x21\x02\x00\x00\x8b\xce\xe8" + b"\x9c\x21\x00\x00\x6a\x01\x8b\xce\xe8\x53\x1c\x00\x00\x8d\x8e\x0c" + b"\x01\x00\x00\x53\x8b\x01\xff\x50\x04\x85\xc0\x0f\x85\xef\x02\x00" + b"\x00\x8b\x56\x0c\x8b\x4f\x20\x3b\xd1\x74\x0e\x8b\x1d\x74\x45\x0f" + b"\x10\x39\x0b\x0f\x85\xd7\x02\x00\x00\x81\x7f\x1c\x02\x02\x00\x00" + b"\x75\x1a\x6a\x00\x52\x6a\x10\xe8\xa4\x65\xfa\xff\x8b\xc8\xe8\x0d" + b"\xa2\xfb\xff\x66\xc7\x86\xd6\x01\x00\x00\x00\x00\x8b\x96\x00\x01" + b"\x00\x00\x8d\x42\x74\x8b\x18\x83\xfb\x0c\x0f\x87\x9b\x02\x00\x00" + b"\x33\xc9\x8a\x8b\xac\xf4\x06\x10\xff\x24\x8d\x8c\xf4\x06\x10\x8b" + b"\x86\x08\x01\x00\x00\x83\xf8\x05\x77\x07\xff\x24\x85\xbc\xf4\x06" + b"\x10\x8b\xce\xe8\xb8\x1a\x00\x00\x8b\x86\x00\x01\x00\x00\x68\xf4" + b"\x01\x00\x00\x8b\xce\xc7\x40\x74\x0b\x00\x00\x00\xe8\xef\x20\x00" + b"\x00\x8b\x86\x00\x01\x00\x00\xc7\x86\x08\x01\x00\x00\xff\xff\xff" + b"\xff\x83\x78\x78\x00\x0f\x85\x40\x02\x00\x00\xb8\x01\x00\x00\x00" + b"\x5f\x66\xc7\x86\xd2\x01\x00\x00\x01\x00\x5e\x5b\xc2\x04\x00\x6a" + b"\x00\x8b\xce\x6a\x01\xe8\xd6\x19\x00\x00\xb8\x01\x00\x00\x00\x5f" + b"\x5e\x5b\xc2\x04\x00\x6a\x01\x8b\xce\x6a\x02\xe8\xc0\x19\x00\x00" + b"\xb8\x01\x00\x00\x00\x5f\x5e\x5b\xc2\x04\x00\x8b\xce\xe8\x3e\x1a" + b"\x00\x00\x8b\x86\x00\x01\x00\x00\x68\x1c\x02\x00\x00\x8b\xce\xc7" + b"\x40\x74\x0b\x00\x00\x00\xe8\x75\x20\x00\x00\xb8\x01\x00\x00\x00" + b"\x5f\xc7\x86\x08\x01\x00\x00\xff\xff\xff\xff\x5e\x5b\xc2\x04\x00" + b"\x8b\xce\xe8\x09\x1a\x00\x00\x8b\x86\x00\x01\x00\x00\x68\x1b\x02" + b"\x00\x00\x8b\xce\xc7\x40\x74\x0b\x00\x00\x00\xe8\x40\x20\x00\x00" + b"\xb8\x01\x00\x00\x00\x5f\xc7\x86\x08\x01\x00\x00\xff\xff\xff\xff" + b"\x5e\x5b\xc2\x04\x00\xc7\x00\x0b\x00\x00\x00\x8b\x86\x08\x01\x00" + b"\x00\x83\xf8\x04\x74\x0c\x83\xf8\x05\x74\x0e\x68\xf4\x01\x00\x00" + b"\xeb\x0c\x68\x1c\x02\x00\x00\xeb\x05\x68\x1b\x02\x00\x00\x8b\xce" + b"\xe8\xfb\x1f\x00\x00\xb8\x01\x00\x00\x00\x5f\xc7\x86\x08\x01\x00" + b"\x00\xff\xff\xff\xff\x5e\x5b\xc2\x04\x00\x6a\x00\xa1\xa0\x76\x0f" + b"\x10\x50\xe8\x39\x65\xfa\xff\x83\xc4\x08\xa1\xa4\x76\x0f\x10\x6a" + b"\x00\x50\xe8\x29\x65\xfa\xff\x83\xc4\x08\xe8\xf1\x63\xfa\xff\x8b" + b"\xc8\xe8\x6a\x02\x01\x00\xb8\x01\x00\x00\x00\x5f\x5e\x5b\xc2\x04" + b"\x00\x8b\x47\x1c\x83\xf8\x46\x74\x09\x83\xf8\x47\x0f\x85\x09\x01" + b"\x00\x00\x6a\x00\x6a\x00\x6a\x32\x6a\x03\xe8\x91\x65\xfa\xff\x8b" + b"\xc8\xe8\xfa\xc7\xfd\xff\x8b\x86\x00\x01\x00\x00\x5f\x5e\x5b\xc7" + b"\x40\x74\x0e\x00\x00\x00\xb8\x01\x00\x00\x00\xc2\x04\x00\x8b\x47" + b"\x1c\x39\x86\xf8\x00\x00\x00\x0f\x85\xce\x00\x00\x00\xe8\xbe\x63" + b"\xfa\xff\x83\x78\x10\x02\x74\x19\x66\x8b\x86\xfc\x00\x00\x00\x66" + b"\x85\xc0\x74\x0d\x50\xe8\xa6\x63\xfa\xff\x8b\xc8\xe8\xbf\xa3\xfc" + b"\xff\x6a\x00\x6a\x00\x6a\x32\x6a\x03\xe8\x32\x65\xfa\xff\x8b\xc8" + b"\xe8\x9b\xc7\xfd\xff\x8b\x86\x00\x01\x00\x00\x5f\x5e\x5b\xc7\x40" + b"\x74\x0e\x00\x00\x00\xb8\x01\x00\x00\x00\xc2\x04\x00\x83\x7a\x78" + b"\x00\x75\x32\x8b\x86\xf8\x00\x00\x00\x83\xf8\x28\x74\x27\x83\xf8" + b"\x29\x74\x22\x83\xf8\x2a\x74\x1d\x83\xf8\x2b\x74\x18\x83\xf8\x2c" + b"\x74\x13\x66\xc7\x86\xd0\x01\x00\x00\x01\x00\x6a\x0b\xe8\xee\x64" + b"\xfa\xff\x83\xc4\x04\x8b\x86\x00\x01\x00\x00\x6a\x01\x68\xdc\x44" + b"\x0f\x10\xc7\x40\x74\x02\x00\x00\x00\xe8\x22\x64\xfa\xff\x83\xc4" + b"\x08\xb8\x01\x00\x00\x00\x5f\x5e\x5b\xc2\x04\x00\x8b\x47\x1c\x39" + b"\x86\xf8\x00\x00\x00\x75\x14\x6a\x00\x6a\x00\x6a\x32\x6a\x03\xe8" + b"\x9c\x64\xfa\xff\x8b\xc8\xe8\x05\xc7\xfd\xff\xb8\x01\x00\x00\x00" + b"\x5f\x5e\x5b\xc2\x04\x00\x8b\xff\x3c\xf1\x06\x10\x43\xf1\x06\x10" + b"\x4a\xf1\x06\x10\x51\xf1\x06\x10\x58\xf1\x06\x10\xdf\xf1\x06\x10" + b"\xd5\xf2\x06\x10\x1a\xf3\x06\x10\x51\xf3\x06\x10\x8e\xf3\x06\x10" + b"\xed\xf3\x06\x10\x4c\xf4\x06\x10\x6b\xf4\x06\x10\x00\x01\x02\x07" + b"\x03\x04\x07\x07\x07\x07\x07\x05\x06\x8d\x49\x00\x3f\xf2\x06\x10" + b"\x55\xf2\x06\x10\xf1\xf1\x06\x10\xf1\xf1\x06\x10\x6b\xf2\x06\x10" + b"\xa0\xf2\x06\x10\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc\xcc" +) + + +def test_action_case(): + """3 switches: 3 jump tables, 1 data table""" + ig = InstructGen(HANDLE_END_ACTION, 0x1006F080) + # Two of the jump tables (0x1006f478 with 5, 0x1006f48c with 8) + # are contiguous. + assert len(ig.sections) == 5 diff --git a/tools/isledecomp/tests/test_islebin.py b/tools/isledecomp/tests/test_islebin.py new file mode 100644 index 00000000..14fb85b4 --- /dev/null +++ b/tools/isledecomp/tests/test_islebin.py @@ -0,0 +1,152 @@ +"""Tests for the Bin (or IsleBin) module that: +1. Parses relevant data from the PE header and other structures. +2. Provides an interface to read from the DLL or EXE using a virtual address. +These are some basic smoke tests.""" + +import hashlib +from typing import Tuple +import pytest +from isledecomp.bin import ( + Bin as IsleBin, + SectionNotFoundError, + InvalidVirtualAddressError, +) + + +# LEGO1.DLL: v1.1 English, September +LEGO1_SHA256 = "14645225bbe81212e9bc1919cd8a692b81b8622abb6561280d99b0fc4151ce17" + + +@pytest.fixture(name="binfile", scope="session") +def fixture_binfile(pytestconfig) -> IsleBin: + filename = pytestconfig.getoption("--lego1") + + # Skip this if we have not provided the path to LEGO1.dll. + if filename is None: + pytest.skip(allow_module_level=True, reason="No path to LEGO1") + + with open(filename, "rb") as f: + digest = hashlib.sha256(f.read()).hexdigest() + if digest != LEGO1_SHA256: + pytest.fail(reason="Did not match expected LEGO1.DLL") + + with IsleBin(filename, find_str=True) as islebin: + yield islebin + + +def test_basic(binfile: IsleBin): + assert binfile.entry == 0x1008C860 + assert len(binfile.sections) == 6 + + with pytest.raises(SectionNotFoundError): + binfile.get_section_by_name(".hello") + + +SECTION_INFO = ( + (".text", 0x10001000, 0xD2A66, 0xD2C00), + (".rdata", 0x100D4000, 0x1B5B6, 0x1B600), + (".data", 0x100F0000, 0x1A734, 0x12C00), + (".idata", 0x1010B000, 0x1006, 0x1200), + (".rsrc", 0x1010D000, 0x21D8, 0x2200), + (".reloc", 0x10110000, 0x10C58, 0x10E00), +) + + +@pytest.mark.parametrize("name, v_addr, v_size, raw_size", SECTION_INFO) +def test_sections(name: str, v_addr: int, v_size: int, raw_size: int, binfile: IsleBin): + section = binfile.get_section_by_name(name) + assert section.virtual_address == v_addr + assert section.virtual_size == v_size + assert section.size_of_raw_data == raw_size + + +DOUBLE_PI_BYTES = b"\x18\x2d\x44\x54\xfb\x21\x09\x40" + +# Now that's a lot of pi +PI_ADDRESSES = ( + 0x100D4000, + 0x100D4700, + 0x100D7180, + 0x100DB8F0, + 0x100DC030, +) + + +@pytest.mark.parametrize("addr", PI_ADDRESSES) +def test_read_pi(addr: int, binfile: IsleBin): + assert binfile.read(addr, 8) == DOUBLE_PI_BYTES + + +def test_unusual_reads(binfile: IsleBin): + """Reads that return an error or some specific value based on context""" + # Reading an address earlier than the imagebase + with pytest.raises(InvalidVirtualAddressError): + binfile.read(0, 1) + + # Really big address + with pytest.raises(InvalidVirtualAddressError): + binfile.read(0xFFFFFFFF, 1) + + # Uninitialized part of .data + assert binfile.read(0x1010A600, 4) is None + + # Past the end of virtual size in .text + assert binfile.read(0x100D3A70, 4) == b"\x00\x00\x00\x00" + + +STRING_ADDRESSES = ( + (0x100DB588, b"November"), + (0x100F0130, b"Helicopter"), + (0x100F0144, b"HelicopterState"), + (0x100F0BE4, b"valerie"), + (0x100F4080, b"TARGET"), +) + + +@pytest.mark.parametrize("addr, string", STRING_ADDRESSES) +def test_strings(addr: int, string: bytes, binfile: IsleBin): + """Test string read utility function and the string search feature""" + assert binfile.read_string(addr) == string + assert binfile.find_string(string) == addr + + +def test_relocation(binfile: IsleBin): + # n.b. This is not the number of *relocations* read from .reloc. + # It is the set of unique addresses in the binary that get relocated. + assert len(binfile.get_relocated_addresses()) == 14066 + + # Score::Score is referenced only by CALL instructions. No need to relocate. + assert binfile.is_relocated_addr(0x10001000) is False + + # MxEntity::SetEntityId is in the vtable and must be relocated. + assert binfile.is_relocated_addr(0x10001070) is True + + +# Not sanitizing dll name case. Do we care? +IMPORT_REFS = ( + ("KERNEL32.dll", "CreateMutexA", 0x1010B3D0), + ("WINMM.dll", "midiOutPrepareHeader", 0x1010B550), +) + + +@pytest.mark.parametrize("import_ref", IMPORT_REFS) +def test_imports(import_ref: Tuple[str, str, int], binfile: IsleBin): + assert import_ref in binfile.imports + + +# Location of the JMP instruction and the import address. +THUNKS = ( + (0x100D3728, 0x1010B32C), # DirectDrawCreate + (0x10098F9E, 0x1010B3D4), # RtlUnwind +) + + +@pytest.mark.parametrize("thunk_ref", THUNKS) +def test_thunks(thunk_ref: Tuple[int, int], binfile: IsleBin): + assert thunk_ref in binfile.thunks + + +def test_exports(binfile: IsleBin): + assert len(binfile.exports) == 130 + assert (0x1003BFB0, b"??0LegoBackgroundColor@@QAE@PBD0@Z") in binfile.exports + assert (0x10091EE0, b"_DllMain@12") in binfile.exports diff --git a/tools/isledecomp/tests/test_linter.py b/tools/isledecomp/tests/test_linter.py new file mode 100644 index 00000000..95d19515 --- /dev/null +++ b/tools/isledecomp/tests/test_linter.py @@ -0,0 +1,144 @@ +import pytest +from isledecomp.parser import DecompLinter +from isledecomp.parser.error import ParserError + + +@pytest.fixture(name="linter") +def fixture_linter(): + return DecompLinter() + + +def test_simple_in_order(linter): + lines = [ + "// FUNCTION: TEST 0x1000", + "void function1() {}", + "// FUNCTION: TEST 0x2000", + "void function2() {}", + "// FUNCTION: TEST 0x3000", + "void function3() {}", + ] + assert linter.check_lines(lines, "test.cpp", "TEST") is True + + +def test_simple_not_in_order(linter): + lines = [ + "// FUNCTION: TEST 0x1000", + "void function1() {}", + "// FUNCTION: TEST 0x3000", + "void function3() {}", + "// FUNCTION: TEST 0x2000", + "void function2() {}", + ] + assert linter.check_lines(lines, "test.cpp", "TEST") is False + assert len(linter.alerts) == 1 + + assert linter.alerts[0].code == ParserError.FUNCTION_OUT_OF_ORDER + # N.B. Line number given is the start of the function, not the marker + assert linter.alerts[0].line_number == 6 + + +def test_byname_ignored(linter): + """Should ignore lookup-by-name markers when checking order.""" + lines = [ + "// FUNCTION: TEST 0x1000", + "void function1() {}", + "// FUNCTION: TEST 0x3000", + "// MyClass::MyMethod", + "// FUNCTION: TEST 0x2000", + "void function2() {}", + ] + # This will fail because byname lookup does not belong in the cpp file + assert linter.check_lines(lines, "test.cpp", "TEST") is False + # but it should not fail for function order. + assert all( + alert.code != ParserError.FUNCTION_OUT_OF_ORDER for alert in linter.alerts + ) + + +def test_module_isolation(linter): + """Should check the order of markers from a single module only.""" + lines = [ + "// FUNCTION: ALPHA 0x0001", + "// FUNCTION: TEST 0x1000", + "void function1() {}", + "// FUNCTION: ALPHA 0x0002", + "// FUNCTION: TEST 0x2000", + "void function2() {}", + "// FUNCTION: ALPHA 0x0003", + "// FUNCTION: TEST 0x3000", + "void function3() {}", + ] + + assert linter.check_lines(lines, "test.cpp", "TEST") is True + linter.reset(True) + assert linter.check_lines(lines, "test.cpp", "ALPHA") is True + + +def test_byname_headers_only(linter): + """Markers that ar referenced by name with cvdump belong in header files only.""" + lines = [ + "// FUNCTION: TEST 0x1000", + "// MyClass::~MyClass", + ] + + assert linter.check_lines(lines, "test.h", "TEST") is True + linter.reset(True) + assert linter.check_lines(lines, "test.cpp", "TEST") is False + assert linter.alerts[0].code == ParserError.BYNAME_FUNCTION_IN_CPP + + +def test_duplicate_offsets(linter): + """The linter will retain module/offset pairs found until we do a full reset.""" + lines = [ + "// FUNCTION: TEST 0x1000", + "// FUNCTION: HELLO 0x1000", + "// MyClass::~MyClass", + ] + + # Should not fail for duplicate offset 0x1000 because the modules are unique. + assert linter.check_lines(lines, "test.h", "TEST") is True + + # Simulate a failure by reading the same file twice. + assert linter.check_lines(lines, "test.h", "TEST") is False + + # Two errors because offsets from both modules are duplicated + assert len(linter.alerts) == 2 + assert all(a.code == ParserError.DUPLICATE_OFFSET for a in linter.alerts) + + # Partial reset will retain the list of seen offsets. + linter.reset(False) + assert linter.check_lines(lines, "test.h", "TEST") is False + + # Full reset will forget seen offsets. + linter.reset(True) + assert linter.check_lines(lines, "test.h", "TEST") is True + + +def test_duplicate_strings(linter): + """Duplicate string markers are okay if the string value is the same.""" + string_lines = [ + "// STRING: TEST 0x1000", + 'return "hello world";', + ] + + # No problem to use this marker twice. + assert linter.check_lines(string_lines, "test.h", "TEST") is True + assert linter.check_lines(string_lines, "test.h", "TEST") is True + + different_string = [ + "// STRING: TEST 0x1000", + 'return "hi there";', + ] + + # Same address but the string is different + assert linter.check_lines(different_string, "greeting.h", "TEST") is False + assert len(linter.alerts) == 1 + assert linter.alerts[0].code == ParserError.WRONG_STRING + + same_addr_reused = [ + "// GLOBAL:TEXT 0x1000", + "int g_test = 123;", + ] + + # This will fail like any other offset reuse. + assert linter.check_lines(same_addr_reused, "other.h", "TEST") is False diff --git a/tools/isledecomp/tests/test_parser.py b/tools/isledecomp/tests/test_parser.py new file mode 100644 index 00000000..c7905627 --- /dev/null +++ b/tools/isledecomp/tests/test_parser.py @@ -0,0 +1,773 @@ +import pytest +from isledecomp.parser.parser import ( + ReaderState, + DecompParser, +) +from isledecomp.parser.error import ParserError + + +@pytest.fixture(name="parser") +def fixture_parser(): + return DecompParser() + + +def test_missing_sig(parser): + """In the hopefully rare scenario that the function signature and marker + are swapped, we still have enough to match witch reccmp""" + parser.read_lines( + [ + "void my_function()", + "// FUNCTION: TEST 0x1234", + "{", + "}", + ] + ) + assert parser.state == ReaderState.SEARCH + assert len(parser.functions) == 1 + assert parser.functions[0].line_number == 3 + + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.MISSED_START_OF_FUNCTION + + +def test_not_exact_syntax(parser): + """Alert to inexact syntax right here in the parser instead of kicking it downstream. + Doing this means we don't have to save the actual text.""" + parser.read_line("// function: test 0x1234") + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.BAD_DECOMP_MARKER + + +def test_invalid_marker(parser): + """We matched a decomp marker, but it's not one we care about""" + parser.read_line("// BANANA: TEST 0x1234") + assert parser.state == ReaderState.SEARCH + + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.BOGUS_MARKER + + +def test_incompatible_marker(parser): + """The marker we just read cannot be handled in the current parser state""" + parser.read_lines( + [ + "// FUNCTION: TEST 0x1234", + "// GLOBAL: TEST 0x5000", + ] + ) + assert parser.state == ReaderState.SEARCH + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.INCOMPATIBLE_MARKER + + +def test_variable(parser): + """Should identify a global variable""" + parser.read_lines( + [ + "// GLOBAL: HELLO 0x1234", + "int g_value = 5;", + ] + ) + assert len(parser.variables) == 1 + + +def test_synthetic_plus_marker(parser): + """Marker tracking preempts synthetic name detection. + Should fail with error and not log the synthetic""" + parser.read_lines( + [ + "// SYNTHETIC: HEY 0x555", + "// FUNCTION: HOWDY 0x1234", + ] + ) + assert len(parser.functions) == 0 + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.INCOMPATIBLE_MARKER + + +def test_different_markers_different_module(parser): + """Does it make any sense for a function to be a stub in one module, + but not in another? I don't know. But it's no problem for us.""" + parser.read_lines( + [ + "// FUNCTION: HOWDY 0x1234", + "// STUB: SUP 0x5555", + "void interesting_function() {", + "}", + ] + ) + + assert len(parser.alerts) == 0 + assert len(parser.functions) == 2 + + +def test_different_markers_same_module(parser): + """Now, if something is a regular function but then a stub, + what do we say about that?""" + parser.read_lines( + [ + "// FUNCTION: HOWDY 0x1234", + "// STUB: HOWDY 0x5555", + "void interesting_function() {", + "}", + ] + ) + + # Use first marker declaration, don't replace + assert len(parser.functions) == 1 + assert parser.functions[0].should_skip() is False + + # Should alert to this + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.DUPLICATE_MODULE + + +def test_unexpected_synthetic(parser): + """FUNCTION then SYNTHETIC should fail to report either one""" + parser.read_lines( + [ + "// FUNCTION: HOWDY 0x1234", + "// SYNTHETIC: HOWDY 0x5555", + "void interesting_function() {", + "}", + ] + ) + + assert parser.state == ReaderState.SEARCH + assert len(parser.functions) == 0 + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.INCOMPATIBLE_MARKER + + +@pytest.mark.skip(reason="not implemented yet") +def test_duplicate_offset(parser): + """Repeating the same module/offset in the same file is probably a typo""" + parser.read_lines( + [ + "// GLOBAL: HELLO 0x1234", + "int x = 1;", + "// GLOBAL: HELLO 0x1234", + "int y = 2;", + ] + ) + + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.DUPLICATE_OFFSET + + +def test_multiple_variables(parser): + """Theoretically the same global variable can appear in multiple modules""" + parser.read_lines( + [ + "// GLOBAL: HELLO 0x1234", + "// GLOBAL: WUZZUP 0x555", + "const char *g_greeting;", + ] + ) + assert len(parser.alerts) == 0 + assert len(parser.variables) == 2 + + +def test_multiple_variables_same_module(parser): + """Should not overwrite offset""" + parser.read_lines( + [ + "// GLOBAL: HELLO 0x1234", + "// GLOBAL: HELLO 0x555", + "const char *g_greeting;", + ] + ) + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.DUPLICATE_MODULE + assert len(parser.variables) == 1 + assert parser.variables[0].offset == 0x1234 + + +def test_multiple_vtables(parser): + parser.read_lines( + [ + "// VTABLE: HELLO 0x1234", + "// VTABLE: TEST 0x5432", + "class MxString : public MxCore {", + ] + ) + assert len(parser.alerts) == 0 + assert len(parser.vtables) == 2 + assert parser.vtables[0].name == "MxString" + + +def test_multiple_vtables_same_module(parser): + """Should not overwrite offset""" + parser.read_lines( + [ + "// VTABLE: HELLO 0x1234", + "// VTABLE: HELLO 0x5432", + "class MxString : public MxCore {", + ] + ) + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.DUPLICATE_MODULE + assert len(parser.vtables) == 1 + assert parser.vtables[0].offset == 0x1234 + + +def test_synthetic(parser): + parser.read_lines( + [ + "// SYNTHETIC: TEST 0x1234", + "// TestClass::TestMethod", + ] + ) + assert len(parser.functions) == 1 + assert parser.functions[0].lookup_by_name is True + assert parser.functions[0].name == "TestClass::TestMethod" + + +def test_synthetic_same_module(parser): + parser.read_lines( + [ + "// SYNTHETIC: TEST 0x1234", + "// SYNTHETIC: TEST 0x555", + "// TestClass::TestMethod", + ] + ) + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.DUPLICATE_MODULE + assert len(parser.functions) == 1 + assert parser.functions[0].offset == 0x1234 + + +def test_synthetic_no_comment(parser): + """Synthetic marker followed by a code line (i.e. non-comment)""" + parser.read_lines( + [ + "// SYNTHETIC: TEST 0x1234", + "int x = 123;", + ] + ) + assert len(parser.functions) == 0 + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.BAD_NAMEREF + assert parser.state == ReaderState.SEARCH + + +def test_single_line_function(parser): + parser.read_lines( + [ + "// FUNCTION: TEST 0x1234", + "int hello() { return 1234; }", + ] + ) + assert len(parser.functions) == 1 + assert parser.functions[0].line_number == 2 + assert parser.functions[0].end_line == 2 + + +def test_indented_function(parser): + """Track the number of whitespace characters when we begin the function + and check that against each closing curly brace we read. + Should not report a syntax warning if the function is indented""" + parser.read_lines( + [ + " // FUNCTION: TEST 0x1234", + " void indented()", + " {", + " // TODO", + " }", + " // FUNCTION: NEXT 0x555", + ] + ) + assert len(parser.alerts) == 0 + + +@pytest.mark.xfail(reason="todo") +def test_indented_no_curly_hint(parser): + """Same as above, but opening curly brace is on the same line. + Without the hint of how many whitespace characters to check, can we + still identify the end of the function?""" + parser.read_lines( + [ + " // FUNCTION: TEST 0x1234", + " void indented() {", + " }", + " // FUNCTION: NEXT 0x555", + ] + ) + assert len(parser.alerts) == 0 + + +def test_implicit_lookup_by_name(parser): + """FUNCTION (or STUB) offsets must directly precede the function signature. + If we detect a comment instead, we assume that this is a lookup-by-name + function and end here.""" + parser.read_lines( + [ + "// FUNCTION: TEST 0x1234", + "// TestClass::TestMethod()", + ] + ) + assert parser.state == ReaderState.SEARCH + assert len(parser.functions) == 1 + assert parser.functions[0].lookup_by_name is True + assert parser.functions[0].name == "TestClass::TestMethod()" + + +def test_function_with_spaces(parser): + """There should not be any spaces between the end of FUNCTION markers + and the start or name of the function. If it's a blank line, we can safely + ignore but should alert to this.""" + parser.read_lines( + [ + "// FUNCTION: TEST 0x1234", + " ", + "inline void test_function() { };", + ] + ) + assert len(parser.functions) == 1 + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.UNEXPECTED_BLANK_LINE + + +def test_function_with_spaces_implicit(parser): + """Same as above, but for implicit lookup-by-name""" + parser.read_lines( + [ + "// FUNCTION: TEST 0x1234", + " ", + "// Implicit::Method", + ] + ) + assert len(parser.functions) == 1 + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.UNEXPECTED_BLANK_LINE + + +@pytest.mark.xfail(reason="will assume implicit lookup-by-name function") +def test_function_is_commented(parser): + """In an ideal world, we would recognize that there is no code here. + Some editors (or users) might comment the function on each line like this + but hopefully it is rare.""" + parser.read_lines( + [ + "// FUNCTION: TEST 0x1234", + "// int my_function()", + "// {", + "// return 5;", + "// }", + ] + ) + + assert len(parser.functions) == 0 + + +def test_unexpected_eof(parser): + """If a decomp marker finds its way to the last line of the file, + report that we could not get anything from it.""" + parser.read_lines( + [ + "// FUNCTION: TEST 0x1234", + "// Cls::Method", + "// FUNCTION: TEST 0x5555", + ] + ) + parser.finish() + + assert len(parser.functions) == 1 + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.UNEXPECTED_END_OF_FILE + + +@pytest.mark.xfail(reason="no longer applies") +def test_global_variable_prefix(parser): + """Global and static variables should have the g_ prefix.""" + parser.read_lines( + [ + "// GLOBAL: TEST 0x1234", + 'const char* g_msg = "hello";', + ] + ) + assert len(parser.variables) == 1 + assert len(parser.alerts) == 0 + + parser.read_lines( + [ + "// GLOBAL: TEXT 0x5555", + "int test = 5;", + ] + ) + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.GLOBAL_MISSING_PREFIX + # In spite of that, we should still grab the variable name. + assert parser.variables[1].name == "test" + + +def test_global_nomatch(parser): + """We do our best to grab the variable name, even without the g_ prefix + but this (by design) will not match everything.""" + + parser.read_lines( + [ + "// GLOBAL: TEST 0x1234", + "FunctionCall();", + ] + ) + assert len(parser.variables) == 0 + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.NO_SUITABLE_NAME + + +def test_static_variable(parser): + """We can detect whether a variable is a static function variable + based on the parser's state when we detect it. + Checking for the word `static` alone is not a good test. + Static class variables are filed as S_GDATA32, same as regular globals.""" + + parser.read_lines( + [ + "// GLOBAL: TEST 0x1234", + "int g_test = 1234;", + ] + ) + assert len(parser.variables) == 1 + assert parser.variables[0].is_static is False + + parser.read_lines( + [ + "// FUNCTION: TEST 0x5555", + "void test_function() {", + "// GLOBAL: TEST 0x8888", + "static int g_internal = 0;", + "}", + ] + ) + assert len(parser.variables) == 2 + assert parser.variables[1].is_static is True + + +def test_reject_global_return(parser): + """Previously we had annotated strings with the GLOBAL marker. + For example: if a function returned a string. We now want these to be + annotated with the STRING marker.""" + + parser.read_lines( + [ + "// FUNCTION: TEST 0x5555", + "void test_function() {", + " // GLOBAL: TEST 0x8888", + ' return "test";', + "}", + ] + ) + assert len(parser.variables) == 0 + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.GLOBAL_NOT_VARIABLE + + +def test_global_string(parser): + """We now allow GLOBAL and STRING markers for the same item.""" + + parser.read_lines( + [ + "// GLOBAL: TEST 0x1234", + "// STRING: TEXT 0x5555", + 'char* g_test = "hello";', + ] + ) + assert len(parser.variables) == 1 + assert len(parser.strings) == 1 + assert len(parser.alerts) == 0 + + assert parser.variables[0].name == "g_test" + assert parser.strings[0].name == "hello" + + +def test_comment_variables(parser): + """Match on hidden variables from libraries.""" + + parser.read_lines( + [ + "// GLOBAL: TEST 0x1234", + "// g_test", + ] + ) + assert len(parser.variables) == 1 + assert parser.variables[0].name == "g_test" + + +def test_flexible_variable_prefix(parser): + """Don't alert to library variables that lack the g_ prefix. + This is out of our control.""" + + parser.read_lines( + [ + "// GLOBAL: TEST 0x1234", + "// some_other_variable", + ] + ) + assert len(parser.variables) == 1 + assert len(parser.alerts) == 0 + assert parser.variables[0].name == "some_other_variable" + + +def test_string_ignore_g_prefix(parser): + """String annotations above a regular variable should not alert to + the missing g_ prefix. This is only required for GLOBAL markers.""" + + parser.read_lines( + [ + "// STRING: TEST 0x1234", + 'const char* value = "";', + ] + ) + assert len(parser.strings) == 1 + assert len(parser.alerts) == 0 + + +def test_class_variable(parser): + """We should accurately name static variables that are class members.""" + + parser.read_lines( + [ + "class Test {", + "protected:", + " // GLOBAL: TEST 0x1234", + " static int g_test;", + "};", + ] + ) + + assert len(parser.variables) == 1 + assert parser.variables[0].name == "Test::g_test" + + +def test_namespace_variable(parser): + """We should identify a namespace surrounding any global variables""" + + parser.read_lines( + [ + "namespace Test {", + "// GLOBAL: TEST 0x1234", + "int g_test = 1234;", + "}", + "// GLOBAL: TEST 0x5555", + "int g_second = 2;", + ] + ) + + assert len(parser.variables) == 2 + assert parser.variables[0].name == "Test::g_test" + assert parser.variables[1].name == "g_second" + + +def test_namespace_vtable(parser): + parser.read_lines( + [ + "namespace Tgl {", + "// VTABLE: TEST 0x1234", + "class Renderer {", + "};", + "}", + "// VTABLE: TEST 0x5555", + "class Hello { };", + ] + ) + + assert len(parser.vtables) == 2 + assert parser.vtables[0].name == "Tgl::Renderer" + assert parser.vtables[1].name == "Hello" + + +@pytest.mark.xfail(reason="no longer applies") +def test_global_prefix_namespace(parser): + """Should correctly identify namespaces before checking for the g_ prefix""" + + parser.read_lines( + [ + "class Test {", + " // GLOBAL: TEST 0x1234", + " static int g_count = 0;", + " // GLOBAL: TEST 0x5555", + " static int count = 0;", + "};", + ] + ) + + assert len(parser.variables) == 2 + assert parser.variables[0].name == "Test::g_count" + assert parser.variables[1].name == "Test::count" + + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.GLOBAL_MISSING_PREFIX + + +def test_nested_namespace(parser): + parser.read_lines( + [ + "namespace Tgl {", + "class Renderer {", + " // GLOBAL: TEST 0x1234", + " static int g_count = 0;", + "};", + "};", + ] + ) + + assert len(parser.variables) == 1 + assert parser.variables[0].name == "Tgl::Renderer::g_count" + + +def test_match_qualified_variable(parser): + """If a variable belongs to a scope and we use a fully qualified reference + below a GLOBAL marker, make sure we capture the full name.""" + + parser.read_lines( + [ + "// GLOBAL: TEST 0x1234", + "int MxTest::g_count = 0;", + ] + ) + + assert len(parser.variables) == 1 + assert parser.variables[0].name == "MxTest::g_count" + assert len(parser.alerts) == 0 + + +def test_static_variable_parent(parser): + """Report the address of the parent function that contains a static variable.""" + + parser.read_lines( + [ + "// FUNCTION: TEST 0x1234", + "void test()", + "{", + " // GLOBAL: TEST 0x5555", + " static int g_count = 0;", + "}", + ] + ) + + assert len(parser.variables) == 1 + assert parser.variables[0].is_static is True + assert parser.variables[0].parent_function == 0x1234 + + +@pytest.mark.xfail( + reason="""Without the FUNCTION marker we don't know that we are inside a function, + so we do not identify this variable as static.""" +) +def test_static_variable_no_parent(parser): + """If the function that contains a static variable is not marked, we + cannot match it with cvdump so we should skip it and report an error.""" + + parser.read_lines( + [ + "void test()", + "{", + " // GLOBAL: TEST 0x5555", + " static int g_count = 0;", + "}", + ] + ) + + # No way to match this variable so don't report it + assert len(parser.variables) == 0 + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.ORPHANED_STATIC_VARIABLE + + +def test_static_variable_incomplete_coverage(parser): + """If the function that contains a static variable is marked, but + not for each module used for the variable itself, this is an error.""" + + parser.read_lines( + [ + "// FUNCTION: HELLO 0x1234", + "void test()", + "{", + " // GLOBAL: HELLO 0x5555", + " // GLOBAL: TEST 0x5555", + " static int g_count = 0;", + "}", + ] + ) + + # Match for HELLO module + assert len(parser.variables) == 1 + + # Failed for TEST module + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.ORPHANED_STATIC_VARIABLE + + +def test_header_function_declaration(parser): + """This is either a forward reference or a declaration in a header file. + Meaning: The implementation is not here. This is not the correct place + for the FUNCTION marker and it will probably not match anything.""" + + parser.read_lines( + [ + "// FUNCTION: HELLO 0x1234", + "void sample_function(int);", + ] + ) + + assert len(parser.alerts) == 1 + assert parser.alerts[0].code == ParserError.NO_IMPLEMENTATION + + +def test_extra(parser): + """Allow a fourth field in the decomp annotation. Its use will vary + depending on the marker type. Currently this is only used to identify + a vtable with virtual inheritance.""" + + # Intentionally using non-vtable markers here. + # We might want to emit a parser warning for unnecessary extra info. + parser.read_lines( + [ + "// GLOBAL: TEST 0x5555 Haha", + "int g_variable = 0;", + "// FUNCTION: TEST 0x1234 Something", + "void Test() { g_variable++; }", + "// LIBRARY: TEST 0x8080 Printf", + "// _printf", + ] + ) + + # We don't use this information (yet) but this is all fine. + assert len(parser.alerts) == 0 + + +def test_virtual_inheritance(parser): + """Indicate the base class for a vtable where the class uses + virtual inheritance.""" + parser.read_lines( + [ + "// VTABLE: HELLO 0x1234", + "// VTABLE: HELLO 0x1238 Greetings", + "// VTABLE: HELLO 0x123c Howdy", + "class HiThere : public virtual Greetings {", + "};", + ] + ) + + assert len(parser.alerts) == 0 + assert len(parser.vtables) == 3 + assert parser.vtables[0].base_class is None + assert parser.vtables[1].base_class == "Greetings" + assert parser.vtables[2].base_class == "Howdy" + assert all(v.name == "HiThere" for v in parser.vtables) + + +def test_namespace_in_comment(parser): + parser.read_lines( + [ + "// VTABLE: HELLO 0x1234", + "// class Tgl::Object", + "// VTABLE: HELLO 0x5555", + "// class TglImpl::RendererImpl", + ] + ) + + assert len(parser.vtables) == 2 + assert parser.vtables[0].name == "Tgl::Object" + assert parser.vtables[1].name == "TglImpl::RendererImpl" diff --git a/tools/isledecomp/tests/test_parser_samples.py b/tools/isledecomp/tests/test_parser_samples.py new file mode 100644 index 00000000..e74fda0e --- /dev/null +++ b/tools/isledecomp/tests/test_parser_samples.py @@ -0,0 +1,141 @@ +import os +from typing import List, TextIO +import pytest +from isledecomp.parser import DecompParser +from isledecomp.parser.node import ParserSymbol + +SAMPLE_DIR = os.path.join(os.path.dirname(__file__), "samples") + + +def sample_file(filename: str) -> TextIO: + """Wrapper for opening the samples from the directory that does not + depend on the cwd where we run the test""" + full_path = os.path.join(SAMPLE_DIR, filename) + return open(full_path, "r", encoding="utf-8") + + +def code_blocks_are_sorted(blocks: List[ParserSymbol]) -> bool: + """Helper to make this more idiomatic""" + just_offsets = [block.offset for block in blocks] + return just_offsets == sorted(just_offsets) + + +@pytest.fixture(name="parser") +def fixture_parser(): + return DecompParser() + + +# Tests are below # + + +def test_sanity(parser): + """Read a very basic file""" + with sample_file("basic_file.cpp") as f: + parser.read_lines(f) + + assert len(parser.functions) == 3 + assert code_blocks_are_sorted(parser.functions) is True + # n.b. The parser returns line numbers as 1-based + # Function starts when we see the opening curly brace + assert parser.functions[0].line_number == 8 + assert parser.functions[0].end_line == 10 + + +def test_oneline(parser): + """(Assuming clang-format permits this) This sample has a function + on a single line. This will test the end-of-function detection""" + with sample_file("oneline_function.cpp") as f: + parser.read_lines(f) + + assert len(parser.functions) == 2 + assert parser.functions[0].line_number == 5 + assert parser.functions[0].end_line == 5 + + +def test_missing_offset(parser): + """What if the function doesn't have an offset comment?""" + with sample_file("missing_offset.cpp") as f: + parser.read_lines(f) + + # TODO: For now, the function without the offset will just be ignored. + # Would be the same outcome if the comment was present but mangled and + # we failed to match it. We should detect these cases in the future. + assert len(parser.functions) == 1 + + +def test_jumbled_case(parser): + """The parser just reports what it sees. It is the responsibility of + the downstream tools to do something about a jumbled file. + Just verify that we are reading it correctly.""" + with sample_file("out_of_order.cpp") as f: + parser.read_lines(f) + + assert len(parser.functions) == 3 + assert code_blocks_are_sorted(parser.functions) is False + + +def test_bad_file(parser): + with sample_file("poorly_formatted.cpp") as f: + parser.read_lines(f) + + assert len(parser.functions) == 3 + + +def test_indented(parser): + """Offsets for functions inside of a class will probably be indented.""" + with sample_file("basic_class.cpp") as f: + parser.read_lines(f) + + # TODO: We don't properly detect the end of these functions + # because the closing brace is indented. However... knowing where each + # function ends is less important (for now) than capturing + # all the functions that are there. + + assert len(parser.functions) == 2 + assert parser.functions[0].offset == int("0x12345678", 16) + assert parser.functions[0].line_number == 16 + # assert parser.functions[0].end_line == 19 + + assert parser.functions[1].offset == int("0xdeadbeef", 16) + assert parser.functions[1].line_number == 23 + # assert parser.functions[1].end_line == 25 + + +def test_inline(parser): + with sample_file("inline.cpp") as f: + parser.read_lines(f) + + assert len(parser.functions) == 2 + for fun in parser.functions: + assert fun.line_number is not None + assert fun.line_number == fun.end_line + + +def test_multiple_offsets(parser): + """If multiple offset marks appear before for a code block, take them + all but ensure module name (case-insensitive) is distinct. + Use first module occurrence in case of duplicates.""" + with sample_file("multiple_offsets.cpp") as f: + parser.read_lines(f) + + assert len(parser.functions) == 4 + assert parser.functions[0].module == "TEST" + assert parser.functions[0].line_number == 9 + + assert parser.functions[1].module == "HELLO" + assert parser.functions[1].line_number == 9 + + # Duplicate modules are ignored + assert parser.functions[2].line_number == 16 + assert parser.functions[2].offset == 0x2345 + + assert parser.functions[3].module == "TEST" + assert parser.functions[3].offset == 0x2002 + + +def test_variables(parser): + with sample_file("global_variables.cpp") as f: + parser.read_lines(f) + + assert len(parser.functions) == 1 + assert len(parser.variables) == 2 diff --git a/tools/isledecomp/tests/test_parser_statechange.py b/tools/isledecomp/tests/test_parser_statechange.py new file mode 100644 index 00000000..be37e3c8 --- /dev/null +++ b/tools/isledecomp/tests/test_parser_statechange.py @@ -0,0 +1,141 @@ +from typing import Optional +import pytest +from isledecomp.parser.parser import ( + ReaderState as _rs, + DecompParser, +) +from isledecomp.parser.error import ParserError as _pe + +# fmt: off +state_change_marker_cases = [ + (_rs.SEARCH, "FUNCTION", _rs.WANT_SIG, None), + (_rs.SEARCH, "GLOBAL", _rs.IN_GLOBAL, None), + (_rs.SEARCH, "STUB", _rs.WANT_SIG, None), + (_rs.SEARCH, "SYNTHETIC", _rs.IN_SYNTHETIC, None), + (_rs.SEARCH, "TEMPLATE", _rs.IN_TEMPLATE, None), + (_rs.SEARCH, "VTABLE", _rs.IN_VTABLE, None), + (_rs.SEARCH, "LIBRARY", _rs.IN_LIBRARY, None), + (_rs.SEARCH, "STRING", _rs.IN_GLOBAL, None), + + (_rs.WANT_SIG, "FUNCTION", _rs.WANT_SIG, None), + (_rs.WANT_SIG, "GLOBAL", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.WANT_SIG, "STUB", _rs.WANT_SIG, None), + (_rs.WANT_SIG, "SYNTHETIC", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.WANT_SIG, "TEMPLATE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.WANT_SIG, "VTABLE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.WANT_SIG, "LIBRARY", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.WANT_SIG, "STRING", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + + (_rs.IN_FUNC, "FUNCTION", _rs.WANT_SIG, _pe.MISSED_END_OF_FUNCTION), + (_rs.IN_FUNC, "GLOBAL", _rs.IN_FUNC_GLOBAL, None), + (_rs.IN_FUNC, "STUB", _rs.WANT_SIG, _pe.MISSED_END_OF_FUNCTION), + (_rs.IN_FUNC, "SYNTHETIC", _rs.IN_SYNTHETIC, _pe.MISSED_END_OF_FUNCTION), + (_rs.IN_FUNC, "TEMPLATE", _rs.IN_TEMPLATE, _pe.MISSED_END_OF_FUNCTION), + (_rs.IN_FUNC, "VTABLE", _rs.IN_VTABLE, _pe.MISSED_END_OF_FUNCTION), + (_rs.IN_FUNC, "LIBRARY", _rs.IN_LIBRARY, _pe.MISSED_END_OF_FUNCTION), + (_rs.IN_FUNC, "STRING", _rs.IN_FUNC_GLOBAL, None), + + (_rs.IN_TEMPLATE, "FUNCTION", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_TEMPLATE, "GLOBAL", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_TEMPLATE, "STUB", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_TEMPLATE, "SYNTHETIC", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_TEMPLATE, "TEMPLATE", _rs.IN_TEMPLATE, None), + (_rs.IN_TEMPLATE, "VTABLE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_TEMPLATE, "LIBRARY", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_TEMPLATE, "STRING", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + + (_rs.WANT_CURLY, "FUNCTION", _rs.SEARCH, _pe.UNEXPECTED_MARKER), + (_rs.WANT_CURLY, "GLOBAL", _rs.SEARCH, _pe.UNEXPECTED_MARKER), + (_rs.WANT_CURLY, "STUB", _rs.SEARCH, _pe.UNEXPECTED_MARKER), + (_rs.WANT_CURLY, "SYNTHETIC", _rs.SEARCH, _pe.UNEXPECTED_MARKER), + (_rs.WANT_CURLY, "TEMPLATE", _rs.SEARCH, _pe.UNEXPECTED_MARKER), + (_rs.WANT_CURLY, "VTABLE", _rs.SEARCH, _pe.UNEXPECTED_MARKER), + (_rs.WANT_CURLY, "LIBRARY", _rs.SEARCH, _pe.UNEXPECTED_MARKER), + (_rs.WANT_CURLY, "STRING", _rs.SEARCH, _pe.UNEXPECTED_MARKER), + + (_rs.IN_GLOBAL, "FUNCTION", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_GLOBAL, "GLOBAL", _rs.IN_GLOBAL, None), + (_rs.IN_GLOBAL, "STUB", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_GLOBAL, "SYNTHETIC", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_GLOBAL, "TEMPLATE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_GLOBAL, "VTABLE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_GLOBAL, "LIBRARY", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_GLOBAL, "STRING", _rs.IN_GLOBAL, None), + + (_rs.IN_FUNC_GLOBAL, "FUNCTION", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_FUNC_GLOBAL, "GLOBAL", _rs.IN_FUNC_GLOBAL, None), + (_rs.IN_FUNC_GLOBAL, "STUB", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_FUNC_GLOBAL, "SYNTHETIC", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_FUNC_GLOBAL, "TEMPLATE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_FUNC_GLOBAL, "VTABLE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_FUNC_GLOBAL, "LIBRARY", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_FUNC_GLOBAL, "STRING", _rs.IN_FUNC_GLOBAL, None), + + (_rs.IN_VTABLE, "FUNCTION", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_VTABLE, "GLOBAL", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_VTABLE, "STUB", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_VTABLE, "SYNTHETIC", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_VTABLE, "TEMPLATE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_VTABLE, "VTABLE", _rs.IN_VTABLE, None), + (_rs.IN_VTABLE, "LIBRARY", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_VTABLE, "STRING", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + + (_rs.IN_SYNTHETIC, "FUNCTION", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_SYNTHETIC, "GLOBAL", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_SYNTHETIC, "STUB", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_SYNTHETIC, "SYNTHETIC", _rs.IN_SYNTHETIC, None), + (_rs.IN_SYNTHETIC, "TEMPLATE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_SYNTHETIC, "VTABLE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_SYNTHETIC, "LIBRARY", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_SYNTHETIC, "STRING", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + + (_rs.IN_LIBRARY, "FUNCTION", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_LIBRARY, "GLOBAL", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_LIBRARY, "STUB", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_LIBRARY, "SYNTHETIC", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_LIBRARY, "TEMPLATE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_LIBRARY, "VTABLE", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), + (_rs.IN_LIBRARY, "LIBRARY", _rs.IN_LIBRARY, None), + (_rs.IN_LIBRARY, "STRING", _rs.SEARCH, _pe.INCOMPATIBLE_MARKER), +] +# fmt: on + + +@pytest.mark.parametrize( + "state, marker_type, new_state, expected_error", state_change_marker_cases +) +def test_state_change_by_marker( + state: _rs, marker_type: str, new_state: _rs, expected_error: Optional[_pe] +): + p = DecompParser() + p.state = state + mock_line = f"// {marker_type}: TEST 0x1234" + p.read_line(mock_line) + assert p.state == new_state + + if expected_error is not None: + assert len(p.alerts) > 0 + assert p.alerts[0].code == expected_error + + +# Reading any of these lines should have no effect in ReaderState.SEARCH +search_lines_no_effect = [ + "", + "\t", + " ", + "int x = 0;", + "// Comment", + "/*", + "*/", + "/* Block comment */", + "{", + "}", +] + + +@pytest.mark.parametrize("line", search_lines_no_effect) +def test_state_search_line(line: str): + p = DecompParser() + p.read_line(line) + assert p.state == _rs.SEARCH + assert len(p.alerts) == 0 diff --git a/tools/isledecomp/tests/test_parser_util.py b/tools/isledecomp/tests/test_parser_util.py new file mode 100644 index 00000000..e60f505c --- /dev/null +++ b/tools/isledecomp/tests/test_parser_util.py @@ -0,0 +1,209 @@ +import pytest +from isledecomp.parser.parser import MarkerDict +from isledecomp.parser.marker import ( + DecompMarker, + MarkerType, + match_marker, + is_marker_exact, +) +from isledecomp.parser.util import ( + is_blank_or_comment, + get_class_name, + get_variable_name, + get_string_contents, +) + + +blank_or_comment_param = [ + (True, ""), + (True, "\t"), + (True, " "), + (False, "\tint abc=123;"), + (True, "// OFFSET: LEGO1 0xdeadbeef"), + (True, " /* Block comment beginning"), + (True, "Block comment ending */ "), + # TODO: does clang-format have anything to say about these cases? + (False, "x++; // Comment folows"), + (False, "x++; /* Block comment begins"), +] + + +@pytest.mark.parametrize("expected, line", blank_or_comment_param) +def test_is_blank_or_comment(line: str, expected: bool): + assert is_blank_or_comment(line) is expected + + +marker_samples = [ + # (can_parse: bool, exact_match: bool, line: str) + (True, True, "// FUNCTION: LEGO1 0xdeadbeef"), + (True, True, "// FUNCTION: ISLE 0x12345678"), + # No trailing spaces allowed + (True, False, "// FUNCTION: LEGO1 0xdeadbeef "), + # Must have exactly one space between elements + (True, False, "//FUNCTION: ISLE 0xdeadbeef"), + (True, False, "// FUNCTION:ISLE 0xdeadbeef"), + (True, False, "// FUNCTION: ISLE 0xdeadbeef"), + (True, False, "// FUNCTION: ISLE 0xdeadbeef"), + (True, False, "// FUNCTION: ISLE 0xdeadbeef"), + # Must have 0x prefix for hex number to match at all + (False, False, "// FUNCTION: ISLE deadbeef"), + # Offset, module name, and STUB must be uppercase + (True, False, "// function: ISLE 0xdeadbeef"), + (True, False, "// function: isle 0xdeadbeef"), + # Hex string must be lowercase + (True, False, "// FUNCTION: ISLE 0xDEADBEEF"), + # TODO: How flexible should we be with matching the module name? + (True, True, "// FUNCTION: OMNI 0x12345678"), + (True, True, "// FUNCTION: LEG01 0x12345678"), + (True, False, "// FUNCTION: hello 0x12345678"), + # Not close enough to match + (False, False, "// FUNCTION: ISLE0x12345678"), + (False, False, "// FUNCTION: 0x12345678"), + (False, False, "// LEGO1: 0x12345678"), + # Hex string shorter than 8 characters + (True, True, "// FUNCTION: LEGO1 0x1234"), + # TODO: These match but shouldn't. + # (False, False, '// FUNCTION: LEGO1 0'), + # (False, False, '// FUNCTION: LEGO1 0x'), + # Extra field + (True, True, "// VTABLE: HELLO 0x1234 Extra"), + # Extra with spaces + (True, True, "// VTABLE: HELLO 0x1234 Whatever"), + # Extra, no space (if the first non-hex character is not in [a-f]) + (True, False, "// VTABLE: HELLO 0x1234Hello"), + # Extra, many spaces + (True, False, "// VTABLE: HELLO 0x1234 Hello"), +] + + +@pytest.mark.parametrize("match, _, line", marker_samples) +def test_marker_match(line: str, match: bool, _): + did_match = match_marker(line) is not None + assert did_match is match + + +@pytest.mark.parametrize("_, exact, line", marker_samples) +def test_marker_exact(line: str, exact: bool, _): + assert is_marker_exact(line) is exact + + +def test_marker_dict_simple(): + d = MarkerDict() + d.insert(DecompMarker("FUNCTION", "TEST", 0x1234)) + markers = list(d.iter()) + assert len(markers) == 1 + + +def test_marker_dict_ofs_replace(): + d = MarkerDict() + d.insert(DecompMarker("FUNCTION", "TEST", 0x1234)) + d.insert(DecompMarker("FUNCTION", "TEST", 0x555)) + markers = list(d.iter()) + assert len(markers) == 1 + assert markers[0].offset == 0x1234 + + +def test_marker_dict_type_replace(): + d = MarkerDict() + d.insert(DecompMarker("FUNCTION", "TEST", 0x1234)) + d.insert(DecompMarker("STUB", "TEST", 0x1234)) + markers = list(d.iter()) + assert len(markers) == 1 + assert markers[0].type == MarkerType.FUNCTION + + +class_name_match_cases = [ + ("struct MxString {", "MxString"), + ("class MxString {", "MxString"), + ("// class MxString", "MxString"), + ("class MxString : public MxCore {", "MxString"), + ("class MxPtrList", "MxPtrList"), + # If it is possible to match the symbol MxList::`vftable' + # we should get the correct class name if possible. If the template type is a pointer, + # the asterisk and class name are separated by one space. + ("// class MxList", "MxList"), + ("// class MxList", "MxList"), + ("// class MxList", "MxList"), + # I don't know if this would ever come up, but sure, why not? + ("// class MxList", "MxList"), + ("// class Many::Name::Spaces", "Many::Name::Spaces"), +] + + +@pytest.mark.parametrize("line, class_name", class_name_match_cases) +def test_get_class_name(line: str, class_name: str): + assert get_class_name(line) == class_name + + +class_name_no_match_cases = [ + "MxString { ", + "clas MxString", + "// MxPtrList::`scalar deleting destructor'", +] + + +@pytest.mark.parametrize("line", class_name_no_match_cases) +def test_get_class_name_none(line: str): + assert get_class_name(line) is None + + +variable_name_cases = [ + # with prefix for easy access + ("char* g_test;", "g_test"), + ("g_test;", "g_test"), + ("void (*g_test)(int);", "g_test"), + ("char g_test[50];", "g_test"), + ("char g_test[50] = {1234,", "g_test"), + ("int g_test = 500;", "g_test"), + # no prefix + ("char* hello;", "hello"), + ("hello;", "hello"), + ("void (*hello)(int);", "hello"), + ("char hello[50];", "hello"), + ("char hello[50] = {1234,", "hello"), + ("int hello = 500;", "hello"), +] + + +@pytest.mark.parametrize("line,name", variable_name_cases) +def test_get_variable_name(line: str, name: str): + assert get_variable_name(line) == name + + +string_match_cases = [ + ('return "hello world";', "hello world"), + ('"hello\\\\"', "hello\\"), + ('"hello \\"world\\""', 'hello "world"'), + ('"hello\\nworld"', "hello\nworld"), + # Only match first string if there are multiple options + ('Method("hello", "world");', "hello"), +] + + +@pytest.mark.parametrize("line, string", string_match_cases) +def test_get_string_contents(line: str, string: str): + assert get_string_contents(line) == string + + +def test_marker_extra_spaces(): + """The extra field can contain spaces""" + marker = match_marker("// VTABLE: TEST 0x1234 S p a c e s") + assert marker.extra == "S p a c e s" + + # Trailing spaces removed + marker = match_marker("// VTABLE: TEST 0x8888 spaces ") + assert marker.extra == "spaces" + + # Trailing newline removed if present + marker = match_marker("// VTABLE: TEST 0x5555 newline\n") + assert marker.extra == "newline" + + +def test_marker_trailing_spaces(): + """Should ignore trailing spaces. (Invalid extra field) + Offset field not truncated, extra field set to None.""" + + marker = match_marker("// VTABLE: TEST 0x1234 ") + assert marker is not None + assert marker.offset == 0x1234 + assert marker.extra is None diff --git a/tools/isledecomp/tests/test_path_resolver_nt.py b/tools/isledecomp/tests/test_path_resolver_nt.py new file mode 100644 index 00000000..93ddfd17 --- /dev/null +++ b/tools/isledecomp/tests/test_path_resolver_nt.py @@ -0,0 +1,32 @@ +from os import name as os_name +import pytest +from isledecomp.dir import PathResolver + + +if os_name != "nt": + pytest.skip(reason="Skip Windows-only tests", allow_module_level=True) + + +@pytest.fixture(name="resolver") +def fixture_resolver_win(): + yield PathResolver("C:\\isle") + + +def test_identity(resolver): + assert resolver.resolve_cvdump("C:\\isle\\test.h") == "C:\\isle\\test.h" + + +def test_outside_basedir(resolver): + assert resolver.resolve_cvdump("C:\\lego\\test.h") == "C:\\lego\\test.h" + + +def test_relative(resolver): + assert resolver.resolve_cvdump(".\\test.h") == "C:\\isle\\test.h" + assert resolver.resolve_cvdump("..\\test.h") == "C:\\test.h" + + +def test_intermediate_relative(resolver): + """These paths may not register as `relative` paths, but we want to + produce a single absolute path for each.""" + assert resolver.resolve_cvdump("C:\\isle\\test\\..\\test.h") == "C:\\isle\\test.h" + assert resolver.resolve_cvdump(".\\subdir\\..\\test.h") == "C:\\isle\\test.h" diff --git a/tools/isledecomp/tests/test_path_resolver_posix.py b/tools/isledecomp/tests/test_path_resolver_posix.py new file mode 100644 index 00000000..af0c89e5 --- /dev/null +++ b/tools/isledecomp/tests/test_path_resolver_posix.py @@ -0,0 +1,69 @@ +from os import name as os_name +from unittest.mock import patch +import pytest +from isledecomp.dir import PathResolver + + +if os_name == "nt": + pytest.skip(reason="Skip Posix-only tests", allow_module_level=True) + + +@pytest.fixture(name="resolver") +def fixture_resolver_posix(): + # Skip the call to winepath by using a patch, although this is not strictly necessary. + with patch("isledecomp.dir.winepath_unix_to_win", return_value="Z:\\usr\\isle"): + yield PathResolver("/usr/isle") + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_identity(winepath_mock, resolver): + """Test with an absolute Wine path where a path swap is possible.""" + # In this and upcoming tests, patch is_file so we always assume there is + # a file at the given unix path. We want to test the conversion logic only. + with patch("pathlib.Path.is_file", return_value=True): + assert resolver.resolve_cvdump("Z:\\usr\\isle\\test.h") == "/usr/isle/test.h" + winepath_mock.assert_not_called() + + # Without the patch, this should call the winepath_mock, but we have + # memoized the value from the previous run. + assert resolver.resolve_cvdump("Z:\\usr\\isle\\test.h") == "/usr/isle/test.h" + winepath_mock.assert_not_called() + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_file_does_not_exist(winepath_mock, resolver): + """These test files (probably) don't exist, so we always assume + the path swap failed and defer to winepath.""" + resolver.resolve_cvdump("Z:\\usr\\isle\\test.h") + winepath_mock.assert_called_once_with("Z:\\usr\\isle\\test.h") + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_outside_basedir(winepath_mock, resolver): + """Test an absolute path where we cannot do a path swap.""" + with patch("pathlib.Path.is_file", return_value=True): + resolver.resolve_cvdump("Z:\\lego\\test.h") + winepath_mock.assert_called_once_with("Z:\\lego\\test.h") + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_relative(winepath_mock, resolver): + """Test relative paths inside and outside of the base dir.""" + with patch("pathlib.Path.is_file", return_value=True): + assert resolver.resolve_cvdump("./test.h") == "/usr/isle/test.h" + + # This works because we will resolve "/usr/isle/test/../test.h" + assert resolver.resolve_cvdump("../test.h") == "/usr/test.h" + winepath_mock.assert_not_called() + + +@patch("isledecomp.dir.winepath_win_to_unix") +def test_intermediate_relative(winepath_mock, resolver): + """We can resolve intermediate backdirs if they are relative to the basedir.""" + with patch("pathlib.Path.is_file", return_value=True): + assert ( + resolver.resolve_cvdump("Z:\\usr\\isle\\test\\..\\test.h") + == "/usr/isle/test.h" + ) + assert resolver.resolve_cvdump(".\\subdir\\..\\test.h") == "/usr/isle/test.h" + winepath_mock.assert_not_called() diff --git a/tools/isledecomp/tests/test_sanitize.py b/tools/isledecomp/tests/test_sanitize.py new file mode 100644 index 00000000..deb3c825 --- /dev/null +++ b/tools/isledecomp/tests/test_sanitize.py @@ -0,0 +1,296 @@ +from typing import Optional +import pytest +from isledecomp.compare.asm.parse import DisasmLiteInst, ParseAsm + + +def mock_inst(mnemonic: str, op_str: str) -> DisasmLiteInst: + """Mock up the named tuple DisasmLite from just a mnemonic and op_str. + To be used for tests on sanitize that do not require the instruction address + or size. i.e. any non-jump instruction.""" + return DisasmLiteInst(0, 0, mnemonic, op_str) + + +identity_cases = [ + ("", ""), + ("sti", ""), + ("push", "ebx"), + ("ret", ""), + ("ret", "4"), + ("mov", "eax, 0x1234"), +] + + +@pytest.mark.parametrize("mnemonic, op_str", identity_cases) +def test_identity(mnemonic, op_str): + """Confirm that nothing is substituted.""" + p = ParseAsm() + inst = mock_inst(mnemonic, op_str) + result = p.sanitize(inst) + assert result == (mnemonic, op_str) + + +ptr_replace_cases = [ + ("byte ptr [0x5555]", "byte ptr []"), + ("word ptr [0x5555]", "word ptr []"), + ("dword ptr [0x5555]", "dword ptr []"), + ("qword ptr [0x5555]", "qword ptr []"), + ("eax, dword ptr [0x5555]", "eax, dword ptr []"), + ("dword ptr [0x5555], eax", "dword ptr [], eax"), + ("dword ptr [0x5555], 0", "dword ptr [], 0"), + ("dword ptr [0x5555], 8", "dword ptr [], 8"), + # Same value, assumed to be an addr in the first appearance + # because it is designated as 'ptr', but we have not provided the + # relocation table lookup method so we do not replace the second appearance. + ("dword ptr [0x5555], 0x5555", "dword ptr [], 0x5555"), +] + + +@pytest.mark.parametrize("start, end", ptr_replace_cases) +def test_ptr_replace(start, end): + """Anything in square brackets (with the 'ptr' prefix) will always be replaced.""" + p = ParseAsm() + inst = mock_inst("", start) + (_, op_str) = p.sanitize(inst) + assert op_str == end + + +call_replace_cases = [ + ("ebx", "ebx"), + ("0x1234", ""), + ("dword ptr [0x1234]", "dword ptr []"), + ("dword ptr [ecx + 0x10]", "dword ptr [ecx + 0x10]"), +] + + +@pytest.mark.parametrize("start, end", call_replace_cases) +def test_call_replace(start, end): + """Call with hex operand is always replaced. + Otherwise, ptr replacement rules apply, but skip `this` calls.""" + p = ParseAsm() + inst = mock_inst("call", start) + (_, op_str) = p.sanitize(inst) + assert op_str == end + + +def test_jump_displacement(): + """Display jump displacement (offset from end of jump instruction) + instead of destination address.""" + p = ParseAsm() + inst = DisasmLiteInst(0x1000, 2, "je", "0x1000") + (_, op_str) = p.sanitize(inst) + assert op_str == "-0x2" + + +def test_jmp_table(): + """To ignore cases where it would be inappropriate to replace pointer + displacement (i.e. the vast majority of them) we require the address + to be relocated. This excludes any address less than the imagebase.""" + p = ParseAsm() + inst = mock_inst("jmp", "dword ptr [eax*4 + 0x5555]") + (_, op_str) = p.sanitize(inst) + # i.e. no change + assert op_str == "dword ptr [eax*4 + 0x5555]" + + def relocate_lookup(addr: int) -> bool: + return addr == 0x5555 + + # Now add the relocation lookup + p = ParseAsm(relocate_lookup=relocate_lookup) + (_, op_str) = p.sanitize(inst) + # Should replace it now + assert op_str == "dword ptr [eax*4 + ]" + + +name_replace_cases = [ + ("byte ptr [0x5555]", "byte ptr [_substitute_]"), + ("word ptr [0x5555]", "word ptr [_substitute_]"), + ("dword ptr [0x5555]", "dword ptr [_substitute_]"), + ("qword ptr [0x5555]", "qword ptr [_substitute_]"), +] + + +@pytest.mark.parametrize("start, end", name_replace_cases) +def test_name_replace(start, end): + """Make sure the name lookup function is called if present""" + + def substitute(_: int, __: bool) -> str: + return "_substitute_" + + p = ParseAsm(name_lookup=substitute) + inst = mock_inst("mov", start) + (_, op_str) = p.sanitize(inst) + assert op_str == end + + +def test_replacement_cache(): + p = ParseAsm() + inst = mock_inst("inc", "dword ptr [0x1234]") + + (_, op_str) = p.sanitize(inst) + assert op_str == "dword ptr []" + + (_, op_str) = p.sanitize(inst) + assert op_str == "dword ptr []" + + +def test_replacement_numbering(): + """If we can use the name lookup for the first address but not the second, + the second replacement should be not .""" + + def substitute_1234(addr: int, _: bool) -> Optional[str]: + return "_substitute_" if addr == 0x1234 else None + + p = ParseAsm(name_lookup=substitute_1234) + + (_, op_str) = p.sanitize(mock_inst("inc", "dword ptr [0x1234]")) + assert op_str == "dword ptr [_substitute_]" + + (_, op_str) = p.sanitize(mock_inst("inc", "dword ptr [0x5555]")) + assert op_str == "dword ptr []" + + +def test_relocate_lookup(): + """Immediate values would be relocated if they are actually addresses. + So we can use the relocation table to check whether a given value is an + address or just some number.""" + + def relocate_lookup(addr: int) -> bool: + return addr == 0x1234 + + p = ParseAsm(relocate_lookup=relocate_lookup) + (_, op_str) = p.sanitize(mock_inst("mov", "eax, 0x1234")) + assert op_str == "eax, " + + (_, op_str) = p.sanitize(mock_inst("mov", "eax, 0x5555")) + assert op_str == "eax, 0x5555" + + +def test_jump_to_function(): + """A jmp instruction can lead us directly to a function. This can be found + in the unwind section at the end of a function. However: we do not want to + assume this is the case for all jumps. Only replace the jump with a name + if we can find it using our lookup.""" + + def substitute_1234(addr: int, _: bool) -> Optional[str]: + return "_substitute_" if addr == 0x1234 else None + + p = ParseAsm(name_lookup=substitute_1234) + inst = DisasmLiteInst(0x1000, 2, "jmp", "0x1234") + (_, op_str) = p.sanitize(inst) + assert op_str == "_substitute_" + + # Should not replace this jump. + # 0x1000 (start addr) + # + 2 (size of jump instruction) + # + 0x5555 (displacement, the value we want) + # = 0x6557 + inst = DisasmLiteInst(0x1000, 2, "jmp", "0x6557") + (_, op_str) = p.sanitize(inst) + assert op_str == "0x5555" + + +@pytest.mark.skip(reason="changed implementation") +def test_float_replacement(): + """Floating point constants often appear as pointers to data. + A good example is ViewROI::IntrinsicImportance and the subclass override + LegoROI::IntrinsicImportance. Both return 0.5, but this is done via the + FLD instruction and a dword value at 0x100dbdec. In this case it is more + valuable to just read the constant value rather than use a placeholder. + The float constants don't appear to be deduplicated (like strings are) + because there is another 0.5 at 0x100d40b0.""" + + def bin_lookup(addr: int, _: int) -> Optional[bytes]: + return b"\xdb\x0f\x49\x40" if addr == 0x1234 else None + + p = ParseAsm(bin_lookup=bin_lookup) + inst = DisasmLiteInst(0x1000, 6, "fld", "dword ptr [0x1234]") + (_, op_str) = p.sanitize(inst) + # Single-precision float. struct.unpack(" Optional[str]: + return "g_myFloatVariable" if addr == 0x1234 else None + + p = ParseAsm(name_lookup=name_lookup) + inst = DisasmLiteInst(0x1000, 6, "fld", "dword ptr [0x1234]") + (_, op_str) = p.sanitize(inst) + assert op_str == "dword ptr [g_myFloatVariable]" + + +def test_pointer_compare(): + """A loop on an array could get optimized into comparing on the address + that immediately follows the array. This may or may not be a valid address + and it may or may not be annotated. To avoid a situation where an + erroneous address value would get replaced with a placeholder and silently + pass the comparison check, we will only replace an immediate value on the + CMP instruction if it is a known address.""" + + # 0x1234 and 0x5555 are relocated and so are considered to be addresses. + def relocate_lookup(addr: int) -> bool: + return addr in (0x1234, 0x5555) + + # Only 0x5555 is a "known" address + def name_lookup(addr: int, _: bool) -> Optional[str]: + return "hello" if addr == 0x5555 else None + + p = ParseAsm(relocate_lookup=relocate_lookup, name_lookup=name_lookup) + + # Will always replace on MOV instruction + (_, op_str) = p.sanitize(mock_inst("mov", "eax, 0x1234")) + assert op_str == "eax, " + (_, op_str) = p.sanitize(mock_inst("mov", "eax, 0x5555")) + assert op_str == "eax, hello" + + # n.b. We have already cached the replacement for 0x1234, but the + # special handling for CMP should skip the cache and not use it. + + # Do not replace here + (_, op_str) = p.sanitize(mock_inst("cmp", "eax, 0x1234")) + assert op_str == "eax, 0x1234" + # Should replace here + (_, op_str) = p.sanitize(mock_inst("cmp", "eax, 0x5555")) + assert op_str == "eax, hello" + + +def test_absolute_indirect(): + """The instruction `call dword ptr [0x1234]` means we call the function + whose address is at 0x1234. (i.e. absolute indirect addressing mode) + It is probably more useful to show the name of the function itself if + we have it, but there are some circumstances where we want to replace + with the pointer's name (i.e. an import function).""" + + def name_lookup(addr: int, _: bool) -> Optional[str]: + return { + 0x1234: "Hello", + 0x4321: "xyz", + 0x5555: "Test", + }.get(addr) + + def bin_lookup(addr: int, _: int) -> Optional[bytes]: + return ( + { + 0x1234: b"\x55\x55\x00\x00", + 0x4321: b"\x99\x99\x00\x00", + } + ).get(addr) + + p = ParseAsm(name_lookup=name_lookup, bin_lookup=bin_lookup) + + # If we know the indirect address (0x5555) + # Arrow to indicate this is an indirect replacement + (_, op_str) = p.sanitize(mock_inst("call", "dword ptr [0x1234]")) + assert op_str == "dword ptr [->Test]" + + # If we do not know the indirect address (0x9999) + (_, op_str) = p.sanitize(mock_inst("call", "dword ptr [0x4321]")) + assert op_str == "dword ptr [xyz]" + + # If we can't read the indirect address + (_, op_str) = p.sanitize(mock_inst("call", "dword ptr [0x5555]")) + assert op_str == "dword ptr [Test]" diff --git a/tools/ncc/ncc.py b/tools/ncc/ncc.py new file mode 100644 index 00000000..89ad5dbc --- /dev/null +++ b/tools/ncc/ncc.py @@ -0,0 +1,661 @@ +#!/usr/bin/env python + +# MIT License +# +# Copyright (c) 2018 Nithin Nellikunnu (nithin.nn@gmail.com) +# +# 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. + +import logging +import argparse +import yaml +import re +import sys +import difflib +import os +import fnmatch +from clang.cindex import Index +from clang.cindex import CursorKind +from clang.cindex import StorageClass +from clang.cindex import TypeKind +from clang.cindex import Config + + +# Clang cursor kind to ncc Defined cursor map +default_rules_db = {} +clang_to_user_map = {} +special_kind = {CursorKind.STRUCT_DECL: 1, CursorKind.CLASS_DECL: 1} +file_extensions = [".c", ".cpp", ".h", ".hpp"] + + +class Rule(object): + def __init__(self, name, clang_kind, parent_kind=None, pattern_str='^.*$'): + self.name = name + self.clang_kind = clang_kind + self.parent_kind = parent_kind + self.pattern_str = pattern_str + self.pattern = re.compile(pattern_str) + self.includes = [] + self.excludes = [] + + def evaluate(self, node, scope=None): + if not self.pattern.match(node.spelling): + fmt = '{}:{}:{}: "{}" does not match "{}" associated with {}\n' + msg = fmt.format(node.location.file.name, node.location.line, node.location.column, + node.displayname, self.pattern_str, self.name) + sys.stderr.write(msg) + return False + return True + + +class ScopePrefixRule(object): + def __init__(self, pattern_obj): + self.name = "ScopePrefixRule" + self.rule_names = ["Global", "Static", "ClassMember", "StructMember"] + self.global_prefix = "" + self.static_prefix = "" + self.class_member_prefix = "" + self.struct_member_prefix = "" + + try: + for key, value in pattern_obj.items(): + if key == "Global": + self.global_prefix = value + elif key == "Static": + self.static_prefix = value + elif key == "ClassMember": + self.class_member_prefix = value + elif key == "StructMember": + self.struct_member_prefix = value + else: + raise ValueError(key) + except ValueError as e: + sys.stderr.write('{} is not a valid rule name\n'.format(e.message)) + fixit = difflib.get_close_matches(e.message, self.rule_names, n=1, cutoff=0.8) + if fixit: + sys.stderr.write('Did you mean rule name: {} ?\n'.format(fixit[0])) + sys.exit(1) + + +class DataTypePrefixRule(object): + def __init__(self, pattern_obj): + self.name = "DataTypePrefix" + self.rule_names = ["String", "Integer", "Bool", "Pointer"] + self.string_prefix = "" + + try: + for key, value in pattern_obj.items(): + if key == "String": + self.string_prefix = value + elif key == "Integer": + self.integer_prefix = value + elif key == "Bool": + self.bool_prefix = value + elif key == "Pointer": + self.pointer_prefix = value + else: + raise ValueError(key) + except ValueError as e: + sys.stderr.write('{} is not a valid rule name\n'.format(e.message)) + fixit = difflib.get_close_matches(e.message, self.rule_names, n=1, cutoff=0.8) + if fixit: + sys.stderr.write('Did you mean rule name: {} ?\n'.format(fixit[0])) + sys.exit(1) + + +class VariableNameRule(object): + def __init__(self, pattern_obj=None): + self.name = "VariableName" + self.pattern_str = "^.*$" + self.rule_names = ["ScopePrefix", "DataTypePrefix", "Pattern"] + self.scope_prefix_rule = None + self.datatype_prefix_rule = None + + try: + for key, value in pattern_obj.items(): + if key == "ScopePrefix": + self.scope_prefix_rule = ScopePrefixRule(value) + elif key == "DataTypePrefix": + self.datatype_prefix_rule = DataTypePrefixRule(value) + elif key == "Pattern": + self.pattern_str = value + else: + raise ValueError(key) + except ValueError as e: + sys.stderr.write('{} is not a valid rule name\n'.format(e.message)) + fixit = difflib.get_close_matches(e.message, self.rule_names, n=1, cutoff=0.8) + if fixit: + sys.stderr.write('Did you mean rule name: {} ?\n'.format(fixit[0])) + sys.exit(1) + except re.error as e: + sys.stderr.write('{} is not a valid pattern \n'.format(e.message)) + sys.exit(1) + + def get_scope_prefix(self, node, scope=None): + if node.storage_class == StorageClass.STATIC: + return self.scope_prefix_rule.static_prefix + elif (scope is None) and (node.storage_class == StorageClass.EXTERN or + node.storage_class == StorageClass.NONE): + return self.scope_prefix_rule.global_prefix + elif (scope is CursorKind.CLASS_DECL) or (scope is CursorKind.CLASS_TEMPLATE): + return self.scope_prefix_rule.class_member_prefix + elif (scope is CursorKind.STRUCT_DECL): + return self.scope_prefix_rule.struct_member_prefix + return "" + + def get_datatype_prefix(self, node): + if node.type.kind is TypeKind.ELABORATED: + if node.type.spelling.startswith('std::string'): + return self.datatype_prefix_rule.string_prefix + elif (node.type.spelling.startswith('std::unique_ptr') or + node.type.spelling.startswith("std::shared_ptr")): + return self.datatype_prefix_rule.pointer_prefix + elif node.type.kind is TypeKind.POINTER: + return self.datatype_prefix_rule.pointer_prefix + else: + if node.type.spelling == "int": + return self.datatype_prefix_rule.integer_prefix + elif node.type.spelling.startswith('bool'): + return self.datatype_prefix_rule.bool_prefix + return "" + + def evaluate(self, node, scope=None): + pattern_str = self.pattern_str + scope_prefix = self.get_scope_prefix(node, scope) + datatype_prefix = self.get_datatype_prefix(node) + + pattern_str = pattern_str[0] + scope_prefix + datatype_prefix + pattern_str[1:] + + pattern = re.compile(pattern_str) + if not pattern.match(node.spelling): + fmt = '{}:{}:{}: "{}" does not have the pattern {} associated with Variable name\n' + msg = fmt.format(node.location.file.name, node.location.line, node.location.column, + node.displayname, pattern_str) + sys.stderr.write(msg) + return False + + return True + + +# All supported rules +default_rules_db["StructName"] = Rule("StructName", CursorKind.STRUCT_DECL) +default_rules_db["UnionName"] = Rule("UnionName", CursorKind.UNION_DECL) +default_rules_db["ClassName"] = Rule("ClassName", CursorKind.CLASS_DECL) +default_rules_db["EnumName"] = Rule("EnumName", CursorKind.ENUM_DECL) +default_rules_db["EnumConstantName"] = Rule("EnumConstantName", CursorKind.ENUM_CONSTANT_DECL) +default_rules_db["FunctionName"] = Rule("FunctionName", CursorKind.FUNCTION_DECL) +default_rules_db["ParameterName"] = Rule("ParameterName", CursorKind.PARM_DECL) +default_rules_db["TypedefName"] = Rule("TypedefName", CursorKind.TYPEDEF_DECL) +default_rules_db["CppMethod"] = Rule("CppMethod", CursorKind.CXX_METHOD) +default_rules_db["Namespace"] = Rule("Namespace", CursorKind.NAMESPACE) +default_rules_db["ConversionFunction"] = Rule("ConversionFunction", CursorKind.CONVERSION_FUNCTION) +default_rules_db["TemplateTypeParameter"] = Rule( + "TemplateTypeParameter", CursorKind.TEMPLATE_TYPE_PARAMETER) +default_rules_db["TemplateNonTypeParameter"] = Rule( + "TemplateNonTypeParameter", CursorKind.TEMPLATE_NON_TYPE_PARAMETER) +default_rules_db["TemplateTemplateParameter"] = Rule( + "TemplateTemplateParameter", CursorKind.TEMPLATE_TEMPLATE_PARAMETER) +default_rules_db["FunctionTemplate"] = Rule("FunctionTemplate", CursorKind.FUNCTION_TEMPLATE) +default_rules_db["ClassTemplate"] = Rule("ClassTemplate", CursorKind.CLASS_TEMPLATE) +default_rules_db["ClassTemplatePartialSpecialization"] = Rule( + "ClassTemplatePartialSpecialization", CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION) +default_rules_db["NamespaceAlias"] = Rule("NamespaceAlias", CursorKind.NAMESPACE_ALIAS) +default_rules_db["UsingDirective"] = Rule("UsingDirective", CursorKind.USING_DIRECTIVE) +default_rules_db["UsingDeclaration"] = Rule("UsingDeclaration", CursorKind.USING_DECLARATION) +default_rules_db["TypeAliasName"] = Rule("TypeAliasName", CursorKind.TYPE_ALIAS_DECL) +default_rules_db["ClassAccessSpecifier"] = Rule( + "ClassAccessSpecifier", CursorKind.CXX_ACCESS_SPEC_DECL) +default_rules_db["TypeReference"] = Rule("TypeReference", CursorKind.TYPE_REF) +default_rules_db["CxxBaseSpecifier"] = Rule("CxxBaseSpecifier", CursorKind.CXX_BASE_SPECIFIER) +default_rules_db["TemplateReference"] = Rule("TemplateReference", CursorKind.TEMPLATE_REF) +default_rules_db["NamespaceReference"] = Rule("NamespaceReference", CursorKind.NAMESPACE_REF) +default_rules_db["MemberReference"] = Rule("MemberReference", CursorKind.MEMBER_REF) +default_rules_db["LabelReference"] = Rule("LabelReference", CursorKind.LABEL_REF) +default_rules_db["OverloadedDeclarationReference"] = Rule( + "OverloadedDeclarationReference", CursorKind.OVERLOADED_DECL_REF) +default_rules_db["VariableReference"] = Rule("VariableReference", CursorKind.VARIABLE_REF) +default_rules_db["InvalidFile"] = Rule("InvalidFile", CursorKind.INVALID_FILE) +default_rules_db["NoDeclarationFound"] = Rule("NoDeclarationFound", CursorKind.NO_DECL_FOUND) +default_rules_db["NotImplemented"] = Rule("NotImplemented", CursorKind.NOT_IMPLEMENTED) +default_rules_db["InvalidCode"] = Rule("InvalidCode", CursorKind.INVALID_CODE) +default_rules_db["UnexposedExpression"] = Rule("UnexposedExpression", CursorKind.UNEXPOSED_EXPR) +default_rules_db["DeclarationReferenceExpression"] = Rule( + "DeclarationReferenceExpression", CursorKind.DECL_REF_EXPR) +default_rules_db["MemberReferenceExpression"] = Rule( + "MemberReferenceExpression", CursorKind.MEMBER_REF_EXPR) +default_rules_db["CallExpression"] = Rule("CallExpression", CursorKind.CALL_EXPR) +default_rules_db["BlockExpression"] = Rule("BlockExpression", CursorKind.BLOCK_EXPR) +default_rules_db["IntegerLiteral"] = Rule("IntegerLiteral", CursorKind.INTEGER_LITERAL) +default_rules_db["FloatingLiteral"] = Rule("FloatingLiteral", CursorKind.FLOATING_LITERAL) +default_rules_db["ImaginaryLiteral"] = Rule("ImaginaryLiteral", CursorKind.IMAGINARY_LITERAL) +default_rules_db["StringLiteral"] = Rule("StringLiteral", CursorKind.STRING_LITERAL) +default_rules_db["CharacterLiteral"] = Rule("CharacterLiteral", CursorKind.CHARACTER_LITERAL) +default_rules_db["ParenExpression"] = Rule("ParenExpression", CursorKind.PAREN_EXPR) +default_rules_db["UnaryOperator"] = Rule("UnaryOperator", CursorKind.UNARY_OPERATOR) +default_rules_db["ArraySubscriptExpression"] = Rule( + "ArraySubscriptExpression", CursorKind.ARRAY_SUBSCRIPT_EXPR) +default_rules_db["BinaryOperator"] = Rule("BinaryOperator", CursorKind.BINARY_OPERATOR) +default_rules_db["CompoundAssignmentOperator"] = Rule( + "CompoundAssignmentOperator", CursorKind.COMPOUND_ASSIGNMENT_OPERATOR) +default_rules_db["ConditionalOperator"] = Rule( + "ConditionalOperator", CursorKind.CONDITIONAL_OPERATOR) +default_rules_db["CstyleCastExpression"] = Rule( + "CstyleCastExpression", CursorKind.CSTYLE_CAST_EXPR) +default_rules_db["CompoundLiteralExpression"] = Rule( + "CompoundLiteralExpression", CursorKind.COMPOUND_LITERAL_EXPR) +default_rules_db["InitListExpression"] = Rule("InitListExpression", CursorKind.INIT_LIST_EXPR) +default_rules_db["AddrLabelExpression"] = Rule("AddrLabelExpression", CursorKind.ADDR_LABEL_EXPR) +default_rules_db["StatementExpression"] = Rule("StatementExpression", CursorKind.StmtExpr) +default_rules_db["GenericSelectionExpression"] = Rule( + "GenericSelectionExpression", CursorKind.GENERIC_SELECTION_EXPR) +default_rules_db["GnuNullExpression"] = Rule("GnuNullExpression", CursorKind.GNU_NULL_EXPR) +default_rules_db["CxxStaticCastExpression"] = Rule( + "CxxStaticCastExpression", CursorKind.CXX_STATIC_CAST_EXPR) +default_rules_db["CxxDynamicCastExpression"] = Rule( + "CxxDynamicCastExpression", CursorKind.CXX_DYNAMIC_CAST_EXPR) +default_rules_db["CxxReinterpretCastExpression"] = Rule( + "CxxReinterpretCastExpression", CursorKind.CXX_REINTERPRET_CAST_EXPR) +default_rules_db["CxxConstCastExpression"] = Rule( + "CxxConstCastExpression", CursorKind.CXX_CONST_CAST_EXPR) +default_rules_db["CxxFunctionalCastExpression"] = Rule( + "CxxFunctionalCastExpression", CursorKind.CXX_FUNCTIONAL_CAST_EXPR) +default_rules_db["CxxTypeidExpression"] = Rule("CxxTypeidExpression", CursorKind.CXX_TYPEID_EXPR) +default_rules_db["CxxBoolLiteralExpression"] = Rule( + "CxxBoolLiteralExpression", CursorKind.CXX_BOOL_LITERAL_EXPR) +default_rules_db["CxxNullPointerLiteralExpression"] = Rule( + "CxxNullPointerLiteralExpression", CursorKind.CXX_NULL_PTR_LITERAL_EXPR) +default_rules_db["CxxThisExpression"] = Rule("CxxThisExpression", CursorKind.CXX_THIS_EXPR) +default_rules_db["CxxThrowExpression"] = Rule("CxxThrowExpression", CursorKind.CXX_THROW_EXPR) +default_rules_db["CxxNewExpression"] = Rule("CxxNewExpression", CursorKind.CXX_NEW_EXPR) +default_rules_db["CxxDeleteExpression"] = Rule("CxxDeleteExpression", CursorKind.CXX_DELETE_EXPR) +default_rules_db["CxxUnaryExpression"] = Rule("CxxUnaryExpression", CursorKind.CXX_UNARY_EXPR) +default_rules_db["PackExpansionExpression"] = Rule( + "PackExpansionExpression", CursorKind.PACK_EXPANSION_EXPR) +default_rules_db["SizeOfPackExpression"] = Rule( + "SizeOfPackExpression", CursorKind.SIZE_OF_PACK_EXPR) +default_rules_db["LambdaExpression"] = Rule("LambdaExpression", CursorKind.LAMBDA_EXPR) +default_rules_db["ObjectBoolLiteralExpression"] = Rule( + "ObjectBoolLiteralExpression", CursorKind.OBJ_BOOL_LITERAL_EXPR) +default_rules_db["ObjectSelfExpression"] = Rule("ObjectSelfExpression", CursorKind.OBJ_SELF_EXPR) +default_rules_db["UnexposedStatement"] = Rule("UnexposedStatement", CursorKind.UNEXPOSED_STMT) +default_rules_db["LabelStatement"] = Rule("LabelStatement", CursorKind.LABEL_STMT) +default_rules_db["CompoundStatement"] = Rule("CompoundStatement", CursorKind.COMPOUND_STMT) +default_rules_db["CaseStatement"] = Rule("CaseStatement", CursorKind.CASE_STMT) +default_rules_db["DefaultStatement"] = Rule("DefaultStatement", CursorKind.DEFAULT_STMT) +default_rules_db["IfStatement"] = Rule("IfStatement", CursorKind.IF_STMT) +default_rules_db["SwitchStatement"] = Rule("SwitchStatement", CursorKind.SWITCH_STMT) +default_rules_db["WhileStatement"] = Rule("WhileStatement", CursorKind.WHILE_STMT) +default_rules_db["DoStatement"] = Rule("DoStatement", CursorKind.DO_STMT) +default_rules_db["ForStatement"] = Rule("ForStatement", CursorKind.FOR_STMT) +default_rules_db["GotoStatement"] = Rule("GotoStatement", CursorKind.GOTO_STMT) +default_rules_db["IndirectGotoStatement"] = Rule( + "IndirectGotoStatement", CursorKind.INDIRECT_GOTO_STMT) +default_rules_db["ContinueStatement"] = Rule("ContinueStatement", CursorKind.CONTINUE_STMT) +default_rules_db["BreakStatement"] = Rule("BreakStatement", CursorKind.BREAK_STMT) +default_rules_db["ReturnStatement"] = Rule("ReturnStatement", CursorKind.RETURN_STMT) +default_rules_db["AsmStatement"] = Rule("AsmStatement", CursorKind.ASM_STMT) +default_rules_db["CxxCatchStatement"] = Rule("CxxCatchStatement", CursorKind.CXX_CATCH_STMT) +default_rules_db["CxxTryStatement"] = Rule("CxxTryStatement", CursorKind.CXX_TRY_STMT) +default_rules_db["CxxForRangeStatement"] = Rule( + "CxxForRangeStatement", CursorKind.CXX_FOR_RANGE_STMT) +default_rules_db["MsAsmStatement"] = Rule("MsAsmStatement", CursorKind.MS_ASM_STMT) +default_rules_db["NullStatement"] = Rule("NullStatement", CursorKind.NULL_STMT) +default_rules_db["DeclarationStatement"] = Rule("DeclarationStatement", CursorKind.DECL_STMT) +default_rules_db["TranslationUnit"] = Rule("TranslationUnit", CursorKind.TRANSLATION_UNIT) +default_rules_db["UnexposedAttribute"] = Rule("UnexposedAttribute", CursorKind.UNEXPOSED_ATTR) +default_rules_db["CxxFinalAttribute"] = Rule("CxxFinalAttribute", CursorKind.CXX_FINAL_ATTR) +default_rules_db["CxxOverrideAttribute"] = Rule( + "CxxOverrideAttribute", CursorKind.CXX_OVERRIDE_ATTR) +default_rules_db["AnnotateAttribute"] = Rule("AnnotateAttribute", CursorKind.ANNOTATE_ATTR) +default_rules_db["AsmLabelAttribute"] = Rule("AsmLabelAttribute", CursorKind.ASM_LABEL_ATTR) +default_rules_db["PackedAttribute"] = Rule("PackedAttribute", CursorKind.PACKED_ATTR) +default_rules_db["PureAttribute"] = Rule("PureAttribute", CursorKind.PURE_ATTR) +default_rules_db["ConstAttribute"] = Rule("ConstAttribute", CursorKind.CONST_ATTR) +default_rules_db["NoduplicateAttribute"] = Rule( + "NoduplicateAttribute", CursorKind.NODUPLICATE_ATTR) +default_rules_db["PreprocessingDirective"] = Rule( + "PreprocessingDirective", CursorKind.PREPROCESSING_DIRECTIVE) +default_rules_db["MacroDefinition"] = Rule("MacroDefinition", CursorKind.MACRO_DEFINITION) +default_rules_db["MacroInstantiation"] = Rule("MacroInstantiation", CursorKind.MACRO_INSTANTIATION) +default_rules_db["InclusionDirective"] = Rule("InclusionDirective", CursorKind.INCLUSION_DIRECTIVE) +default_rules_db["TypeAliasTeplateDeclaration"] = Rule( + "TypeAliasTeplateDeclaration", CursorKind.TYPE_ALIAS_TEMPLATE_DECL) + +# Reverse lookup map. The parse identifies Clang cursor kinds, which must be mapped +# to user defined types +for key, value in default_rules_db.items(): + clang_to_user_map[value.clang_kind] = key +default_rules_db["VariableName"] = Rule("VariableName", CursorKind.VAR_DECL) +clang_to_user_map[CursorKind.FIELD_DECL] = "VariableName" +clang_to_user_map[CursorKind.VAR_DECL] = "VariableName" + + +class AstNodeStack(object): + def __init__(self): + self.stack = [] + + def pop(self): + return self.stack.pop() + + def push(self, kind): + self.stack.append(kind) + + def peek(self): + if len(self.stack) > 0: + return self.stack[-1] + return None + + +class Options: + def __init__(self): + self.args = None + self._style_file = None + self.file_exclusions = None + self._skip_file = None + + self.parser = argparse.ArgumentParser( + prog="ncc.py", + description="ncc is a development tool to help programmers " + "write C/C++ code that adheres to adhere some naming conventions. It automates the " + "process of checking C code to spare humans of this boring " + "(but important) task. This makes it ideal for projects that want " + "to enforce a coding standard.") + + self.parser.add_argument('--recurse', action='store_true', dest="recurse", + help="Read all files under each directory, recursively") + + self.parser.add_argument('--style', dest="style_file", + help="Read rules from the specified file. If the user does not" + "provide a style file ncc will use all style rules. To print" + "all style rules use --dump option") + + self.parser.add_argument('--include', dest='include', nargs="+", help="User defined " + "header file path, this is same as -I argument to the compiler") + + self.parser.add_argument('--definition', dest='definition', nargs="+", help="User specified " + "definitions, this is same as -D argument to the compiler") + + self.parser.add_argument('--dump', dest='dump', action='store_true', + help="Dump all available options") + + self.parser.add_argument('--output', dest='output', help="output file name where" + "naming convenction vialoations will be stored") + + self.parser.add_argument('--filetype', dest='filetype', help="File extentions type" + "that are applicable for naming convection validation") + + self.parser.add_argument('--clang-lib', dest='clang_lib', + help="Custom location of clang library") + + self.parser.add_argument('--exclude', dest='exclude', nargs="+", help="Skip files " + "matching the pattern specified from recursive searches. It " + "matches a specified pattern according to the rules used by " + "the Unix shell") + + self.parser.add_argument('--skip', '-s', dest="skip_file", + help="Read list of items to ignore during the check. " + "User can use the skip file to specify character sequences that should " + "be ignored by ncc") + + # self.parser.add_argument('--exclude-dir', dest='exclude_dir', help="Skip the directories" + # "matching the pattern specified") + + self.parser.add_argument('--path', dest='path', nargs="+", + help="Path of file or directory") + + def parse_cmd_line(self): + self.args = self.parser.parse_args() + + if self.args.dump: + self.dump_all_rules() + + if self.args.style_file: + self._style_file = self.args.style_file + if not os.path.exists(self._style_file): + sys.stderr.write("Style file '{}' not found!\n".format(self._style_file)) + sys.exit(1) + + if self.args.skip_file: + self._skip_file = self.args.skip_file + if not os.path.exists(self._skip_file): + sys.stderr.write("Skip file '{}' not found!\n".format(self._skip_file)) + + def dump_all_rules(self): + print("----------------------------------------------------------") + print("{:<35} | {}".format("Rule Name", "Pattern")) + print("----------------------------------------------------------") + for (key, value) in default_rules_db.items(): + print("{:<35} : {}".format(key, value.pattern_str)) + +class SkipDb(object): + def __init__(self, skip_file=None): + self.__skip_db = {} + + if skip_file: + self.build_skip_db(skip_file) + + def build_skip_db(self, skip_file): + with open(skip_file) as stylefile: + style_rules = yaml.safe_load(stylefile) + for (skip_string, skip_comment) in style_rules.items(): + self.__skip_db[skip_string] = skip_comment + + def check_skip_db(self, input_query): + if input_query in self.__skip_db.keys(): + return 1 + else: + return 0 + +class RulesDb(object): + def __init__(self, style_file=None): + self.__rule_db = {} + self.__clang_db = {} + + if style_file: + self.build_rules_db(style_file) + else: + self.__rule_db = default_rules_db + self.__clang_db = clang_to_user_map + + def build_rules_db(self, style_file): + with open(style_file) as stylefile: + style_rules = yaml.safe_load(stylefile) + + for (rule_name, pattern_str) in style_rules.items(): + try: + clang_kind = default_rules_db[rule_name].clang_kind + if clang_kind: + if rule_name == "VariableName": + self.__rule_db[rule_name] = VariableNameRule(pattern_str) + self.__clang_db[CursorKind.FIELD_DECL] = rule_name + self.__clang_db[CursorKind.VAR_DECL] = rule_name + else: + self.__rule_db[rule_name] = default_rules_db[rule_name] + self.__rule_db[rule_name].pattern_str = pattern_str + self.__rule_db[rule_name].pattern = re.compile(pattern_str) + self.__clang_db[clang_kind] = rule_name + + except KeyError as e: + sys.stderr.write('{} is not a valid C/C++ construct name\n'.format(e.message)) + fixit = difflib.get_close_matches(e.message, default_rules_db.keys(), + n=1, cutoff=0.8) + if fixit: + sys.stderr.write('Did you mean rule name: {} ?\n'.format(fixit[0])) + sys.exit(1) + except re.error as e: + sys.stderr.write('"{}" pattern {} has {} \n'. + format(rule_name, pattern_str, e.message)) + sys.exit(1) + + def is_rule_enabled(self, kind): + if self.__clang_db.get(kind): + return True + return False + + def get_rule_names(self, kind): + """ + Multiple user defined rules can be configured against one type of ClangKind + For e.g. ClassMemberVariable, StructMemberVariable are types of FIELD_DECL + """ + return self.__clang_db.get(kind) + + def get_rule(self, rule_name): + return self.__rule_db.get(rule_name) + + +class Validator(object): + def __init__(self, rule_db, filename, options, skip_db=None): + self.filename = filename + self.rule_db = rule_db + self.skip_db = skip_db + self.options = options + self.node_stack = AstNodeStack() + + index = Index.create() + args = [] + args.append('-x') + args.append('c++') + args.append('-D_GLIBCXX_USE_CXX11_ABI=0') + if self.options.args.definition: + for item in self.options.args.definition: + defintion = r'-D' + item + args.append(defintion) + if self.options.args.include: + for item in self.options.args.include: + inc = r'-I' + item + args.append(inc) + self.cursor = index.parse(filename, args).cursor + + def validate(self): + return self.check(self.cursor) + + def check(self, node): + """ + Recursively visit all nodes of the AST and match against the patter provided by + the user. Return the total number of errors caught in the file + """ + errors = 0 + for child in node.get_children(): + if self.is_local(child, self.filename): + + # This is the case when typedef of struct is causing double reporting of error + # TODO: Find a better way to handle it + parent = self.node_stack.peek() + if (parent and parent == CursorKind.TYPEDEF_DECL and + child.kind == CursorKind.STRUCT_DECL): + return 0 + + errors += self.evaluate(child) + + # Members struct, class, and unions must be treated differently. + # So parent ast node information is pushed in to the stack. + # Once all its children are validated pop it out of the stack + self.node_stack.push(child.kind) + errors += self.check(child) + self.node_stack.pop() + + return errors + + def evaluate(self, node): + """ + get the node's rule and match the pattern. Report and error if pattern + matching fails + """ + if not self.rule_db.is_rule_enabled(node.kind): + return 0 + + # If the pattern is in the skip list, ignore it + if self.skip_db.check_skip_db(node.displayname): + return 0 + + rule_name = self.rule_db.get_rule_names(node.kind) + rule = self.rule_db.get_rule(rule_name) + if rule.evaluate(node, self.node_stack.peek()) is False: + return 1 + return 0 + + def is_local(self, node, filename): + """ Returns True is node belongs to the file being validated and not an include file """ + if node.location.file and node.location.file.name in filename: + return True + return False + + +def do_validate(options, filename): + """ + Returns true if the file should be validated + - Check if its a c/c++ file + - Check if the file is not excluded + """ + path, extension = os.path.splitext(filename) + if extension not in file_extensions: + return False + + if options.args.exclude: + for item in options.args.exclude: + if fnmatch.fnmatch(filename, item): + return False + + return True + + +if __name__ == "__main__": + logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s', + filename='log.txt', filemode='w') + + """ Parse all command line arguments and validate """ + op = Options() + op.parse_cmd_line() + + if op.args.path is None: + sys.exit(1) + + if op.args.clang_lib: + Config.set_library_file(op.args.clang_lib) + + """ Creating the rules database """ + rules_db = RulesDb(op._style_file) + + """ Creating the skip database """ + skip_db = SkipDb(op._skip_file) + + """ Check the source code against the configured rules """ + errors = 0 + for path in op.args.path: + if os.path.isfile(path): + if do_validate(op, path): + v = Validator(rules_db, path, op, skip_db) + errors += v.validate() + elif os.path.isdir(path): + for (root, subdirs, files) in os.walk(path): + for filename in files: + path = root + '/' + filename + if do_validate(op, path): + v = Validator(rules_db, path, op, skip_db) + errors += v.validate() + + if not op.args.recurse: + break + else: + sys.stderr.write("File '{}' not found!\n".format(path)) + sys.exit(1) + + if errors: + print("Total number of errors = {}".format(errors)) + sys.exit(1) diff --git a/tools/ncc/ncc.style b/tools/ncc/ncc.style new file mode 100644 index 00000000..5147d6bc --- /dev/null +++ b/tools/ncc/ncc.style @@ -0,0 +1,21 @@ +ClassName: '^[A-Z][a-zA-Z0-9]+$' +CppMethod: '^operator|^FUN_[a-f0-9]{8}$|^VTable0x[a-f0-9]{1,8}$|^(?!VTable)[A-Z][a-zA-Z0-9]+$' +EnumName: '^\(unnamed|^[A-Z][a-zA-Z0-9]+$' +EnumConstantName: '^(c_|e_)[a-z][a-zA-Z0-9]+$' +FunctionName: '^operator|^FUN_[a-f0-9]{8}$|^VTable0x[a-f0-9]{1,8}$|^(?!VTable)[A-Z][a-zA-Z0-9]+$' +ParameterName: '^p_(unk0x[a-f0-9]{1,8}$|(?!unk)[a-z][a-zA-Z0-9]*)$|^$' +StructName: '^\(anon|^\(unnamed|^[A-Z][a-zA-Z0-9]+$' +TypedefName: '^[A-Z][a-zA-Z0-9]+$' +UnionName: '^\(anon|^[A-Z][a-zA-Z0-9]+$' +VariableName: + ScopePrefix: + Global: 'g_' + Static: 'g_' + ClassMember: 'm_' + StructMember: 'm_' + DataTypePrefix: + String: '' + Integer: '' + Bool: '' + Pointer: '' + Pattern: '^(unk0x[a-f0-9]{1,8}$|(?!unk)[a-z][a-zA-Z0-9]*|str[a-zA-Z0-9_]*)$' diff --git a/tools/ncc/skip.yml b/tools/ncc/skip.yml new file mode 100644 index 00000000..46229e07 --- /dev/null +++ b/tools/ncc/skip.yml @@ -0,0 +1,32 @@ +configureLegoAnimationManager(MxS32): 'DLL exported function' +configureLegoBuildingManager(MxS32): 'DLL exported function' +configureLegoModelPresenter(MxS32): 'DLL exported function' +configureLegoPartPresenter(MxS32, MxS32): 'DLL exported function' +configureLegoROI(int): 'DLL exported function' +configureLegoWorldPresenter(MxS32): 'DLL exported function' +GetNoCD_SourceName(): 'DLL exported function' +m_3dView: 'Allow this variable name' +m_3dManager: 'Allow this variable name' +m_16bitPal: 'Allow this variable name' +m_HWDesc: 'Allow this variable name' +m_HELDesc: 'Allow this variable name' +p_HWDesc: 'Allow this variable name' +p_HELDesc: 'Allow this variable name' +e_RAMStream: 'Allow this enum constant' +p_milliseconds: 'Probably a bug with function call' +m_increaseAmount: "Can't currently detect member in union" +m_increaseFactor: "Can't currently detect member in union" +delta_rad: "Allow original naming from 1996" +delta_pos: "Allow original naming from 1996" +rot_mat: "Allow original naming from 1996" +new_pos: "Allow original naming from 1996" +new_dir: "Allow original naming from 1996" +p_AnimTreePtr: "Allow original naming from beta" +m_AnimTreePtr: "Allow original naming from beta" +m_BADuration: "Allow original naming from beta" +m_assAnimP: "Allow original naming from beta" +m_disAnimP: "Allow original naming from beta" +i_activity: "Allow original naming from beta" +i_actor: "Allow original naming from beta" +score: "Allow original naming from beta" +c_LOCATIONS_NUM: "Allow original naming from beta" diff --git a/tools/patch_c2.py b/tools/patch_c2.py new file mode 100644 index 00000000..58cc4760 --- /dev/null +++ b/tools/patch_c2.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +import argparse +import hashlib +import pathlib +import shutil + +ORIGINAL_C2_MD5 = "dcd69f1dd28b02dd03dd7ed02984299a" # original C2.EXE + +C2_MD5 = ( + ORIGINAL_C2_MD5, + "e70acde41802ddec06c4263bb357ac30", # patched C2.EXE +) + +C2_SIZE = 549888 + + +def main(): + parser = argparse.ArgumentParser( + allow_abbrev=False, + description="Path to C2.EXE of Microsoft Visual Studio 4.2.0 to disable C4786 warning", + ) + parser.add_argument("path", type=pathlib.Path, help="Path of C2.EXE") + parser.add_argument( + "-f", dest="force", default=False, action="store_true", help="force" + ) + args = parser.parse_args() + + if not args.path.is_file(): + parser.error("Input is not a file") + + binary = bytearray(args.path.open("rb").read()) + md5 = hashlib.md5(binary).hexdigest() + print(md5, C2_MD5) + + msg_cb = parser.error if not args.force else print + if len(binary) != C2_SIZE: + msg_cb("file size is not correct") + if md5 not in C2_MD5: + msg_cb("md5 checksum does not match") + + if md5 == ORIGINAL_C2_MD5: + backup = f"{args.path}.BAK" + print(f'Creating backup "{backup}"') + shutil.copyfile(args.path, backup) + + def nop_patch(start, count, expected=None): + replacement = [0x90] * count + if expected: + current = list(binary[start : start + count]) + assert len(expected) == count + assert current in (expected, replacement) + print(f"Nopping {count} bytes at 0x{start:08x}") + binary[start : start + count] = replacement + + print( + "Disable C4786 warning: '%Fs' : identifier was truncated to '%d' characters in the debug information" + ) + nop_patch(0x52F07, 5, [0xE8, 0x4F, 0xB3, 0xFE, 0xFF]) # 0x00453b07 + nop_patch(0x74832, 5, [0xE8, 0x24, 0x9A, 0xFC, 0xFF]) # 0x00475432 + + args.path.open("wb").write(binary) + print("done") + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/reccmp/config.png b/tools/reccmp/config.png new file mode 100644 index 00000000..1f2050ad Binary files /dev/null and b/tools/reccmp/config.png differ diff --git a/tools/reccmp/isle.png b/tools/reccmp/isle.png new file mode 100644 index 00000000..cfa26a23 Binary files /dev/null and b/tools/reccmp/isle.png differ diff --git a/tools/reccmp/lego1.png b/tools/reccmp/lego1.png new file mode 100644 index 00000000..f76a54da Binary files /dev/null and b/tools/reccmp/lego1.png differ diff --git a/tools/reccmp/reccmp.js b/tools/reccmp/reccmp.js new file mode 100644 index 00000000..4a8e6595 --- /dev/null +++ b/tools/reccmp/reccmp.js @@ -0,0 +1,867 @@ +// reccmp.js +/* global data */ + +// Unwrap array of functions into a dictionary with address as the key. +const dataDict = Object.fromEntries(data.map(row => [row.address, row])); + +function getDataByAddr(addr) { + return dataDict[addr]; +} + +// +// Pure functions +// + +function formatAsm(entries, addrOption) { + const output = []; + + const createTh = (text) => { + const th = document.createElement('th'); + th.innerText = text; + return th; + }; + + const createTd = (text, className = '') => { + const td = document.createElement('td'); + td.innerText = text; + td.className = className; + return td; + }; + + entries.forEach(obj => { + // These won't all be present. You get "both" for an equal node + // and orig/recomp for a diff. + const { both = [], orig = [], recomp = [] } = obj; + + output.push(...both.map(([addr, line, recompAddr]) => { + const tr = document.createElement('tr'); + tr.appendChild(createTh(addr)); + tr.appendChild(createTh(recompAddr)); + tr.appendChild(createTd(line)); + return tr; + })); + + output.push(...orig.map(([addr, line]) => { + const tr = document.createElement('tr'); + tr.appendChild(createTh(addr)); + tr.appendChild(createTh('')); + tr.appendChild(createTd(`-${line}`, 'diffneg')); + return tr; + })); + + output.push(...recomp.map(([addr, line]) => { + const tr = document.createElement('tr'); + tr.appendChild(createTh('')); + tr.appendChild(createTh(addr)); + tr.appendChild(createTd(`+${line}`, 'diffpos')); + return tr; + })); + }); + + return output; +} + +// Special internal values to ensure this sort order for matching column: +// 1. Stub +// 2. Any match percentage [0.0, 1.0) +// 3. Effective match +// 4. Actual 100% match +function matchingColAdjustment(row) { + if ('stub' in row) { + return -1; + } + + if ('effective' in row) { + return 1.0; + } + + if (row.matching === 1.0) { + return 1000; + } + + return row.matching; +} + +function getCppClass(str) { + const idx = str.indexOf('::'); + if (idx !== -1) { + return str.slice(0, idx); + } + + return str; +} + +// Clamp string length to specified length and pad with ellipsis +function stringTruncate(str, maxlen = 20) { + str = getCppClass(str); + if (str.length > maxlen) { + return `${str.slice(0, maxlen)}...`; + } + + return str; +} + +function getMatchPercentText(row) { + if ('stub' in row) { + return 'stub'; + } + + if ('effective' in row) { + return '100.00%*'; + } + + return (row.matching * 100).toFixed(2) + '%'; +} + +function countDiffs(row) { + const { diff = '' } = row; + if (diff === '') { + return ''; + } + + const diffs = diff.map(([slug, subgroups]) => subgroups).flat(); + const diffLength = diffs.filter(d => !('both' in d)).length; + const diffWord = diffLength === 1 ? 'diff' : 'diffs'; + return diffLength === 0 ? '' : `${diffLength} ${diffWord}`; +} + +// Helper for this set/remove attribute block +function setBooleanAttribute(element, attribute, value) { + if (value) { + element.setAttribute(attribute, ''); + } else { + element.removeAttribute(attribute); + } +} + +function copyToClipboard(value) { + navigator.clipboard.writeText(value); +} + +const PAGE_SIZE = 200; + +// +// Global state +// + +class ListingState { + constructor() { + this._query = ''; + this._sortCol = 'address'; + this._filterType = 1; + this._sortDesc = false; + this._hidePerfect = false; + this._hideStub = false; + this._showRecomp = false; + this._expanded = {}; + this._page = 0; + + this._listeners = []; + + this._results = []; + this.updateResults(); + } + + addListener(fn) { + this._listeners.push(fn); + } + + callListeners() { + for (const fn of this._listeners) { + fn(); + } + } + + isExpanded(addr) { + return addr in this._expanded; + } + + toggleExpanded(addr) { + this.setExpanded(addr, !this.isExpanded(addr)); + } + + setExpanded(addr, value) { + if (value) { + this._expanded[addr] = true; + } else { + delete this._expanded[addr]; + } + } + + updateResults() { + const filterFn = this.rowFilterFn.bind(this); + const sortFn = this.rowSortFn.bind(this); + + this._results = data.filter(filterFn).sort(sortFn); + + // Set _page directly to avoid double call to listeners. + this._page = this.pageClamp(this.page); + this.callListeners(); + } + + pageSlice() { + return this._results.slice(this.page * PAGE_SIZE, (this.page + 1) * PAGE_SIZE); + } + + resultsCount() { + return this._results.length; + } + + pageCount() { + return Math.ceil(this._results.length / PAGE_SIZE); + } + + maxPage() { + return Math.max(0, this.pageCount() - 1); + } + + // A list showing the range of each page based on the sort column and direction. + pageHeadings() { + if (this._results.length === 0) { + return []; + } + + const headings = []; + + for (let i = 0; i < this.pageCount(); i++) { + const startIdx = i * PAGE_SIZE; + const endIdx = Math.min(this._results.length, ((i + 1) * PAGE_SIZE)) - 1; + + let start = this._results[startIdx][this.sortCol]; + let end = this._results[endIdx][this.sortCol]; + + if (this.sortCol === 'matching') { + start = getMatchPercentText(this._results[startIdx]); + end = getMatchPercentText(this._results[endIdx]); + } + + headings.push([i, stringTruncate(start), stringTruncate(end)]); + } + + return headings; + } + + rowFilterFn(row) { + // Destructuring sets defaults for optional values from this object. + const { + effective = false, + stub = false, + diff = '', + name, + address, + matching + } = row; + + if (this.hidePerfect && (effective || matching >= 1)) { + return false; + } + + if (this.hideStub && stub) { + return false; + } + + if (this.query === '') { + return true; + } + + // Name/addr search + if (this.filterType === 1) { + return ( + address.includes(this.query) || + name.toLowerCase().includes(this.query) + ); + } + + // no diff for review. + if (diff === '') { + return false; + } + + // special matcher for combined diff + const anyLineMatch = ([addr, line]) => line.toLowerCase().trim().includes(this.query); + + // Flatten all diff groups for the search + const diffs = diff.map(([slug, subgroups]) => subgroups).flat(); + for (const subgroup of diffs) { + const { both = [], orig = [], recomp = [] } = subgroup; + + // If search includes context + if (this.filterType === 2 && both.some(anyLineMatch)) { + return true; + } + + if (orig.some(anyLineMatch) || recomp.some(anyLineMatch)) { + return true; + } + } + + return false; + } + + rowSortFn(rowA, rowB) { + const valA = this.sortCol === 'matching' + ? matchingColAdjustment(rowA) + : rowA[this.sortCol]; + + const valB = this.sortCol === 'matching' + ? matchingColAdjustment(rowB) + : rowB[this.sortCol]; + + if (valA > valB) { + return this.sortDesc ? -1 : 1; + } else if (valA < valB) { + return this.sortDesc ? 1 : -1; + } + + return 0; + } + + pageClamp(page) { + return Math.max(0, Math.min(page, this.maxPage())); + } + + get page() { + return this._page; + } + + set page(page) { + this._page = this.pageClamp(page); + this.callListeners(); + } + + get filterType() { + return parseInt(this._filterType); + } + + set filterType(value) { + value = parseInt(value); + if (value >= 1 && value <= 3) { + this._filterType = value; + } + this.updateResults(); + } + + get query() { + return this._query; + } + + set query(value) { + // Normalize search string + this._query = value.toLowerCase().trim(); + this.updateResults(); + } + + get showRecomp() { + return this._showRecomp; + } + + set showRecomp(value) { + // Don't sort by the recomp column we are about to hide + if (!value && this.sortCol === 'recomp') { + this._sortCol = 'address'; + } + + this._showRecomp = value; + this.callListeners(); + } + + get sortCol() { + return this._sortCol; + } + + set sortCol(column) { + if (column === this._sortCol) { + this._sortDesc = !this._sortDesc; + } else { + this._sortCol = column; + } + + this.updateResults(); + } + + get sortDesc() { + return this._sortDesc; + } + + set sortDesc(value) { + this._sortDesc = value; + this.updateResults(); + } + + get hidePerfect() { + return this._hidePerfect; + } + + set hidePerfect(value) { + this._hidePerfect = value; + this.updateResults(); + } + + get hideStub() { + return this._hideStub; + } + + set hideStub(value) { + this._hideStub = value; + this.updateResults(); + } +} + +const appState = new ListingState(); + +// +// Custom elements +// + +// Sets sort indicator arrow based on element attributes. +class SortIndicator extends window.HTMLElement { + static observedAttributes = ['data-sort']; + + attributeChangedCallback(name, oldValue, newValue) { + if (newValue === null) { + // Reserve space for blank indicator so column width stays the same + this.innerHTML = ' '; + } else { + this.innerHTML = newValue === 'asc' ? '▲' : '▼'; + } + } +} + +class FuncRow extends window.HTMLElement { + connectedCallback() { + if (this.shadowRoot !== null) { + return; + } + + const template = document.querySelector('template#funcrow-template').content; + const shadow = this.attachShadow({ mode: 'open' }); + shadow.appendChild(template.cloneNode(true)); + shadow.querySelector(':host > div[data-col="name"]').addEventListener('click', evt => { + this.dispatchEvent(new Event('name-click')); + }); + } + + get address() { + return this.getAttribute('data-address'); + } +} + +class NoDiffMessage extends window.HTMLElement { + connectedCallback() { + if (this.shadowRoot !== null) { + return; + } + + const template = document.querySelector('template#nodiff-template').content; + const shadow = this.attachShadow({ mode: 'open' }); + shadow.appendChild(template.cloneNode(true)); + } +} + +class CanCopy extends window.HTMLElement { + connectedCallback() { + if (this.shadowRoot !== null) { + return; + } + + const template = document.querySelector('template#can-copy-template').content; + const shadow = this.attachShadow({ mode: 'open' }); + shadow.appendChild(template.cloneNode(true)); + + const el = shadow.querySelector('slot').assignedNodes()[0]; + el.addEventListener('mouseout', evt => { this.copied = false; }); + el.addEventListener('click', evt => { + copyToClipboard(evt.target.textContent); + this.copied = true; + }); + } + + get copied() { + return this.getAttribute('copied'); + } + + set copied(value) { + if (value) { + setTimeout(() => { this.copied = false; }, 2000); + } + setBooleanAttribute(this, 'copied', value); + } +} + +// Displays asm diff for the given @data-address value. +class DiffRow extends window.HTMLElement { + connectedCallback() { + if (this.shadowRoot !== null) { + return; + } + + const template = document.querySelector('template#diffrow-template').content; + const shadow = this.attachShadow({ mode: 'open' }); + shadow.appendChild(template.cloneNode(true)); + } + + get address() { + return this.getAttribute('data-address'); + } + + set address(value) { + this.setAttribute('data-address', value); + } +} + +class DiffDisplayOptions extends window.HTMLElement { + static observedAttributes = ['data-option']; + + connectedCallback() { + if (this.shadowRoot !== null) { + return; + } + + const shadow = this.attachShadow({ mode: 'open' }); + shadow.innerHTML = ` + +
+ Address display: + + + + + + +
`; + + shadow.querySelectorAll('input[type=radio]').forEach(radio => { + const checked = this.option === radio.getAttribute('value'); + setBooleanAttribute(radio, 'checked', checked); + + radio.addEventListener('change', evt => (this.option = evt.target.value)); + }); + } + + set option(value) { + this.setAttribute('data-option', parseInt(value)); + } + + get option() { + return this.getAttribute('data-option') ?? 1; + } + + attributeChangedCallback(name, oldValue, newValue) { + if (name !== 'data-option') { + return; + } + + this.dispatchEvent(new Event('change')); + } +} + +class DiffDisplay extends window.HTMLElement { + static observedAttributes = ['data-option']; + + connectedCallback() { + if (this.querySelector('diff-display-options') !== null) { + return; + } + + const optControl = new DiffDisplayOptions(); + optControl.option = this.option; + optControl.addEventListener('change', evt => (this.option = evt.target.option)); + this.appendChild(optControl); + + const div = document.createElement('div'); + const obj = getDataByAddr(this.address); + + const createHeaderLine = (text, className) => { + const div = document.createElement('div'); + div.textContent = text; + div.className = className; + return div; + }; + + const groups = obj.diff; + groups.forEach(([slug, subgroups]) => { + const secondTable = document.createElement('table'); + secondTable.classList.add('diffTable'); + + const hdr = document.createElement('div'); + hdr.appendChild(createHeaderLine('---', 'diffneg')); + hdr.appendChild(createHeaderLine('+++', 'diffpos')); + hdr.appendChild(createHeaderLine(slug, 'diffslug')); + div.appendChild(hdr); + + const tbody = document.createElement('tbody'); + secondTable.appendChild(tbody); + + const diffs = formatAsm(subgroups, this.option); + for (const el of diffs) { + tbody.appendChild(el); + } + + div.appendChild(secondTable); + }); + + this.appendChild(div); + } + + get address() { + return this.getAttribute('data-address'); + } + + set address(value) { + this.setAttribute('data-address', value); + } + + get option() { + return this.getAttribute('data-option') ?? 1; + } + + set option(value) { + this.setAttribute('data-option', value); + } +} + +class ListingOptions extends window.HTMLElement { + constructor() { + super(); + + // Register to receive updates + appState.addListener(() => this.onUpdate()); + + const input = this.querySelector('input[type=search]'); + input.oninput = evt => (appState.query = evt.target.value); + + const hidePerf = this.querySelector('input#cbHidePerfect'); + hidePerf.onchange = evt => (appState.hidePerfect = evt.target.checked); + hidePerf.checked = appState.hidePerfect; + + const hideStub = this.querySelector('input#cbHideStub'); + hideStub.onchange = evt => (appState.hideStub = evt.target.checked); + hideStub.checked = appState.hideStub; + + const showRecomp = this.querySelector('input#cbShowRecomp'); + showRecomp.onchange = evt => (appState.showRecomp = evt.target.checked); + showRecomp.checked = appState.showRecomp; + + this.querySelector('button#pagePrev').addEventListener('click', evt => { + appState.page = appState.page - 1; + }); + + this.querySelector('button#pageNext').addEventListener('click', evt => { + appState.page = appState.page + 1; + }); + + this.querySelector('select#pageSelect').addEventListener('change', evt => { + appState.page = evt.target.value; + }); + + this.querySelectorAll('input[name=filterType]').forEach(radio => { + const checked = appState.filterType === parseInt(radio.getAttribute('value')); + setBooleanAttribute(radio, 'checked', checked); + + radio.onchange = evt => (appState.filterType = radio.getAttribute('value')); + }); + + this.onUpdate(); + } + + onUpdate() { + // Update input placeholder based on search type + this.querySelector('input[type=search]').placeholder = appState.filterType === 1 + ? 'Search for offset or function name...' + : 'Search for instruction...'; + + // Update page number and max page + this.querySelector('fieldset#pageDisplay > legend').textContent = `Page ${appState.page + 1} of ${Math.max(1, appState.pageCount())}`; + + // Disable prev/next buttons on first/last page + setBooleanAttribute(this.querySelector('button#pagePrev'), 'disabled', appState.page === 0); + setBooleanAttribute(this.querySelector('button#pageNext'), 'disabled', appState.page === appState.maxPage()); + + // Update page select dropdown + const pageSelect = this.querySelector('select#pageSelect'); + setBooleanAttribute(pageSelect, 'disabled', appState.resultsCount() === 0); + pageSelect.innerHTML = ''; + + if (appState.resultsCount() === 0) { + const opt = document.createElement('option'); + opt.textContent = '- no results -'; + pageSelect.appendChild(opt); + } else { + for (const row of appState.pageHeadings()) { + const opt = document.createElement('option'); + opt.value = row[0]; + if (appState.page === row[0]) { + opt.setAttribute('selected', ''); + } + + const [start, end] = [row[1], row[2]]; + + opt.textContent = `${appState.sortCol}: ${start} to ${end}`; + pageSelect.appendChild(opt); + } + } + + // Update row count + this.querySelector('#rowcount').textContent = `${appState.resultsCount()}`; + } +} + +// Main application. +class ListingTable extends window.HTMLElement { + constructor() { + super(); + + // Register to receive updates + appState.addListener(() => this.somethingChanged()); + } + + setDiffRow(address, shouldExpand) { + const tbody = this.querySelector('tbody'); + const funcrow = tbody.querySelector(`func-row[data-address="${address}"]`); + if (funcrow === null) { + return; + } + + const existing = tbody.querySelector(`diff-row[data-address="${address}"]`); + if (existing !== null) { + if (!shouldExpand) { + tbody.removeChild(existing); + } + + return; + } + + const diffrow = document.createElement('diff-row'); + diffrow.address = address; + + // Decide what goes inside the diff row. + const obj = getDataByAddr(address); + + if ('stub' in obj) { + const msg = document.createElement('no-diff'); + const p = document.createElement('div'); + p.innerText = 'Stub. No diff.'; + msg.appendChild(p); + diffrow.appendChild(msg); + } else if (obj.diff.length === 0) { + const msg = document.createElement('no-diff'); + const p = document.createElement('div'); + p.innerText = 'Identical function - no diff'; + msg.appendChild(p); + diffrow.appendChild(msg); + } else { + const dd = new DiffDisplay(); + dd.option = '1'; + dd.address = address; + diffrow.appendChild(dd); + } + + // Insert the diff row after the parent func row. + tbody.insertBefore(diffrow, funcrow.nextSibling); + } + + connectedCallback() { + const thead = this.querySelector('thead'); + const headers = thead.querySelectorAll('th:not([data-no-sort])'); // TODO + headers.forEach(th => { + const col = th.getAttribute('data-col'); + if (col) { + const span = th.querySelector('span'); + if (span) { + span.addEventListener('click', evt => { appState.sortCol = col; }); + } + } + }); + + this.somethingChanged(); + } + + somethingChanged() { + // Toggle recomp/diffs column + setBooleanAttribute(this.querySelector('table'), 'show-recomp', appState.showRecomp); + this.querySelectorAll('func-row[data-address]').forEach(row => { + setBooleanAttribute(row, 'show-recomp', appState.showRecomp); + }); + + const thead = this.querySelector('thead'); + const headers = thead.querySelectorAll('th'); + + // Update sort indicator + headers.forEach(th => { + const col = th.getAttribute('data-col'); + const indicator = th.querySelector('sort-indicator'); + if (indicator === null) { + return; + } + + if (appState.sortCol === col) { + indicator.setAttribute('data-sort', appState.sortDesc ? 'desc' : 'asc'); + } else { + indicator.removeAttribute('data-sort'); + } + }); + + // Add the rows + const tbody = this.querySelector('tbody'); + tbody.innerHTML = ''; // ? + + for (const obj of appState.pageSlice()) { + const row = document.createElement('func-row'); + row.setAttribute('data-address', obj.address); // ? + row.addEventListener('name-click', evt => { + appState.toggleExpanded(obj.address); + this.setDiffRow(obj.address, appState.isExpanded(obj.address)); + }); + setBooleanAttribute(row, 'show-recomp', appState.showRecomp); + setBooleanAttribute(row, 'expanded', appState.isExpanded(row)); + + const items = [ + ['address', obj.address], + ['recomp', obj.recomp], + ['name', obj.name], + ['diffs', countDiffs(obj)], + ['matching', getMatchPercentText(obj)] + ]; + + items.forEach(([slotName, content]) => { + const div = document.createElement('span'); + div.setAttribute('slot', slotName); + div.innerText = content; + row.appendChild(div); + }); + + tbody.appendChild(row); + + if (appState.isExpanded(obj.address)) { + this.setDiffRow(obj.address, true); + } + } + } +} + +window.onload = () => { + window.customElements.define('listing-table', ListingTable); + window.customElements.define('listing-options', ListingOptions); + window.customElements.define('diff-display', DiffDisplay); + window.customElements.define('diff-display-options', DiffDisplayOptions); + window.customElements.define('sort-indicator', SortIndicator); + window.customElements.define('func-row', FuncRow); + window.customElements.define('diff-row', DiffRow); + window.customElements.define('no-diff', NoDiffMessage); + window.customElements.define('can-copy', CanCopy); +}; diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py new file mode 100644 index 00000000..bcdb0899 --- /dev/null +++ b/tools/reccmp/reccmp.py @@ -0,0 +1,344 @@ +#!/usr/bin/env python3 + +import argparse +import base64 +import json +import logging +import os +from datetime import datetime + +from isledecomp import ( + Bin, + get_file_in_script_dir, + print_combined_diff, + diff_json, + percent_string, +) +from isledecomp.compare import Compare as IsleCompare +from isledecomp.types import SymbolType +from pystache import Renderer +import colorama + +colorama.just_fix_windows_console() + + +def gen_json(json_file: str, orig_file: str, data): + """Create a JSON file that contains the comparison summary""" + + # If the structure of the JSON file ever changes, we would run into a problem + # reading an older format file in the CI action. Mark which version we are + # generating so we could potentially address this down the road. + json_format_version = 1 + + # Remove the diff field + reduced_data = [ + {key: value for (key, value) in obj.items() if key != "diff"} for obj in data + ] + + with open(json_file, "w", encoding="utf-8") as f: + json.dump( + { + "file": os.path.basename(orig_file).lower(), + "format": json_format_version, + "timestamp": datetime.now().timestamp(), + "data": reduced_data, + }, + f, + ) + + +def gen_html(html_file, data): + js_path = get_file_in_script_dir("reccmp.js") + with open(js_path, "r", encoding="utf-8") as f: + reccmp_js = f.read() + + output_data = Renderer().render_path( + get_file_in_script_dir("template.html"), {"data": data, "reccmp_js": reccmp_js} + ) + + with open(html_file, "w", encoding="utf-8") as htmlfile: + htmlfile.write(output_data) + + +def gen_svg(svg_file, name_svg, icon, svg_implemented_funcs, total_funcs, raw_accuracy): + icon_data = None + if icon: + with open(icon, "rb") as iconfile: + icon_data = base64.b64encode(iconfile.read()).decode("utf-8") + + total_statistic = raw_accuracy / total_funcs + full_percentbar_width = 127.18422 + output_data = Renderer().render_path( + get_file_in_script_dir("template.svg"), + { + "name": name_svg, + "icon": icon_data, + "implemented": f"{(svg_implemented_funcs / total_funcs * 100):.2f}% ({svg_implemented_funcs}/{total_funcs})", + "accuracy": f"{(raw_accuracy / svg_implemented_funcs * 100):.2f}%", + "progbar": total_statistic * full_percentbar_width, + "percent": f"{(total_statistic * 100):.2f}%", + }, + ) + with open(svg_file, "w", encoding="utf-8") as svgfile: + svgfile.write(output_data) + + +def print_match_verbose(match, show_both_addrs: bool = False, is_plain: bool = False): + percenttext = percent_string( + match.effective_ratio, match.is_effective_match, is_plain + ) + + if show_both_addrs: + addrs = f"0x{match.orig_addr:x} / 0x{match.recomp_addr:x}" + else: + addrs = hex(match.orig_addr) + + if match.is_stub: + print(f"{addrs}: {match.name} is a stub. No diff.") + return + + if match.effective_ratio == 1.0: + ok_text = ( + "OK!" + if is_plain + else (colorama.Fore.GREEN + "✨ OK! ✨" + colorama.Style.RESET_ALL) + ) + if match.ratio == 1.0: + print(f"{addrs}: {match.name} 100% match.\n\n{ok_text}\n\n") + else: + print( + f"{addrs}: {match.name} Effective 100% match. (Differs in register allocation only)\n\n{ok_text} (still differs in register allocation)\n\n" + ) + else: + print_combined_diff(match.udiff, is_plain, show_both_addrs) + + print( + f"\n{match.name} is only {percenttext} similar to the original, diff above" + ) + + +def print_match_oneline(match, show_both_addrs: bool = False, is_plain: bool = False): + percenttext = percent_string( + match.effective_ratio, match.is_effective_match, is_plain + ) + + if show_both_addrs: + addrs = f"0x{match.orig_addr:x} / 0x{match.recomp_addr:x}" + else: + addrs = hex(match.orig_addr) + + if match.is_stub: + print(f" {match.name} ({addrs}) is a stub.") + else: + print(f" {match.name} ({addrs}) is {percenttext} similar to the original") + + +def parse_args() -> argparse.Namespace: + def virtual_address(value) -> int: + """Helper method for argparse, verbose parameter""" + return int(value, 16) + + parser = argparse.ArgumentParser( + allow_abbrev=False, + description="Recompilation Compare: compare an original EXE with a recompiled EXE + PDB.", + ) + parser.add_argument( + "original", metavar="original-binary", help="The original binary" + ) + parser.add_argument( + "recompiled", metavar="recompiled-binary", help="The recompiled binary" + ) + parser.add_argument( + "pdb", metavar="recompiled-pdb", help="The PDB of the recompiled binary" + ) + parser.add_argument( + "decomp_dir", metavar="decomp-dir", help="The decompiled source tree" + ) + parser.add_argument( + "--total", + "-T", + metavar="", + help="Total number of expected functions (improves total accuracy statistic)", + ) + parser.add_argument( + "--verbose", + "-v", + metavar="", + type=virtual_address, + help="Print assembly diff for specific function (original file's offset)", + ) + parser.add_argument( + "--json", + metavar="", + help="Generate JSON file with match summary", + ) + parser.add_argument( + "--diff", + metavar="", + help="Diff against summary in JSON file", + ) + parser.add_argument( + "--html", + "-H", + metavar="", + help="Generate searchable HTML summary of status and diffs", + ) + parser.add_argument( + "--no-color", "-n", action="store_true", help="Do not color the output" + ) + parser.add_argument( + "--svg", "-S", metavar="", help="Generate SVG graphic of progress" + ) + parser.add_argument("--svg-icon", metavar="icon", help="Icon to use in SVG (PNG)") + parser.add_argument( + "--print-rec-addr", + action="store_true", + help="Print addresses of recompiled functions too", + ) + parser.add_argument( + "--silent", + action="store_true", + help="Don't display text summary of matches", + ) + + parser.set_defaults(loglevel=logging.INFO) + parser.add_argument( + "--debug", + action="store_const", + const=logging.DEBUG, + dest="loglevel", + help="Print script debug information", + ) + + args = parser.parse_args() + + if not os.path.isfile(args.original): + parser.error(f"Original binary {args.original} does not exist") + + if not os.path.isfile(args.recompiled): + parser.error(f"Recompiled binary {args.recompiled} does not exist") + + if not os.path.isfile(args.pdb): + parser.error(f"Symbols PDB {args.pdb} does not exist") + + if not os.path.isdir(args.decomp_dir): + parser.error(f"Source directory {args.decomp_dir} does not exist") + + return args + + +def main(): + args = parse_args() + logging.basicConfig(level=args.loglevel, format="[%(levelname)s] %(message)s") + + with Bin(args.original, find_str=True) as origfile, Bin( + args.recompiled + ) as recompfile: + if args.verbose is not None: + # Mute logger events from compare engine + logging.getLogger("isledecomp.compare.db").setLevel(logging.CRITICAL) + logging.getLogger("isledecomp.compare.lines").setLevel(logging.CRITICAL) + + isle_compare = IsleCompare(origfile, recompfile, args.pdb, args.decomp_dir) + + if args.loglevel == logging.DEBUG: + isle_compare.debug = True + + print() + + ### Compare one or none. + + if args.verbose is not None: + match = isle_compare.compare_address(args.verbose) + if match is None: + print(f"Failed to find a match at address 0x{args.verbose:x}") + return + + print_match_verbose( + match, show_both_addrs=args.print_rec_addr, is_plain=args.no_color + ) + return + + ### Compare everything. + + function_count = 0 + total_accuracy = 0 + total_effective_accuracy = 0 + htmlinsert = [] + + for match in isle_compare.compare_all(): + if not args.silent and args.diff is None: + print_match_oneline( + match, show_both_addrs=args.print_rec_addr, is_plain=args.no_color + ) + + if match.match_type == SymbolType.FUNCTION and not match.is_stub: + function_count += 1 + total_accuracy += match.ratio + total_effective_accuracy += match.effective_ratio + + # If html, record the diffs to an HTML file + html_obj = { + "address": f"0x{match.orig_addr:x}", + "recomp": f"0x{match.recomp_addr:x}", + "name": match.name, + "matching": match.effective_ratio, + } + + if match.is_effective_match: + html_obj["effective"] = True + + if match.udiff is not None: + html_obj["diff"] = match.udiff + + if match.is_stub: + html_obj["stub"] = True + + htmlinsert.append(html_obj) + + # Compare with saved diff report. + if args.diff is not None: + with open(args.diff, "r", encoding="utf-8") as f: + saved_data = json.load(f) + + diff_json( + saved_data, + htmlinsert, + args.original, + show_both_addrs=args.print_rec_addr, + is_plain=args.no_color, + ) + + ## Generate files and show summary. + + if args.json is not None: + gen_json(args.json, args.original, htmlinsert) + + if args.html is not None: + gen_html(args.html, json.dumps(htmlinsert)) + + implemented_funcs = function_count + + if args.total: + function_count = int(args.total) + + if function_count > 0: + effective_accuracy = total_effective_accuracy / function_count * 100 + actual_accuracy = total_accuracy / function_count * 100 + print( + f"\nTotal effective accuracy {effective_accuracy:.2f}% across {function_count} functions ({actual_accuracy:.2f}% actual accuracy)" + ) + + if args.svg is not None: + gen_svg( + args.svg, + os.path.basename(args.original), + args.svg_icon, + implemented_funcs, + function_count, + total_effective_accuracy, + ) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/reccmp/template.html b/tools/reccmp/template.html new file mode 100644 index 00000000..3ac15b45 --- /dev/null +++ b/tools/reccmp/template.html @@ -0,0 +1,365 @@ + + + + Decompilation Status + + + + + + +
+

Decompilation Status

+ + +
+
+ Options: + + + + + + +
+
+ Search filters on: + + + + + + +
+
+
+

Results:

+
+ Page + + + +
+
+
+ + + + + + + + + + + + + +
+
+ Address + +
+
+
+ Recomp + +
+
+
+ Name + +
+
+
+ + Matching +
+
+
+
+ + + + + + diff --git a/tools/reccmp/template.svg b/tools/reccmp/template.svg new file mode 100644 index 00000000..fad7ba10 --- /dev/null +++ b/tools/reccmp/template.svg @@ -0,0 +1,119 @@ + + + + + + + + {{name}}{{percent}}{{percent}}Implemented: {{implemented}}Accuracy: {{accuracy}} diff --git a/tools/requirements.txt b/tools/requirements.txt new file mode 100644 index 00000000..3f5e4e84 --- /dev/null +++ b/tools/requirements.txt @@ -0,0 +1,11 @@ +tools/isledecomp +capstone +clang==16.* +colorama>=0.4.6 +isledecomp +pystache +pyyaml +git+https://github.com/wbenny/pydemangler.git +# requirement of capstone due to python dropping distutils. +# see: https://github.com/capstone-engine/capstone/issues/2223 +setuptools ; python_version >= "3.12" \ No newline at end of file diff --git a/tools/roadmap/roadmap.py b/tools/roadmap/roadmap.py new file mode 100644 index 00000000..a0df3cbc --- /dev/null +++ b/tools/roadmap/roadmap.py @@ -0,0 +1,492 @@ +"""For all addresses matched by code annotations or recomp pdb, +report how "far off" the recomp symbol is from its proper place +in the original binary.""" + +import os +import argparse +import logging +import statistics +import bisect +from typing import Iterator, List, Optional, Tuple +from collections import namedtuple +from isledecomp import Bin as IsleBin +from isledecomp.bin import InvalidVirtualAddressError +from isledecomp.cvdump import Cvdump +from isledecomp.compare import Compare as IsleCompare +from isledecomp.types import SymbolType + +# Ignore all compare-db messages. +logging.getLogger("isledecomp.compare").addHandler(logging.NullHandler()) + + +def or_blank(value) -> str: + """Helper for dealing with potential None values in text output.""" + return "" if value is None else str(value) + + +class ModuleMap: + """Load a subset of sections from the pdb to allow you to look up the + module number based on the recomp address.""" + + def __init__(self, pdb, binfile) -> None: + cvdump = Cvdump(pdb).section_contributions().modules().run() + self.module_lookup = {m.id: (m.lib, m.obj) for m in cvdump.modules} + self.library_lookup = {m.obj: m.lib for m in cvdump.modules} + self.section_contrib = [ + ( + binfile.get_abs_addr(sizeref.section, sizeref.offset), + sizeref.size, + sizeref.module, + ) + for sizeref in cvdump.sizerefs + if binfile.is_valid_section(sizeref.section) + ] + + # For bisect performance enhancement + self.contrib_starts = [start for (start, _, __) in self.section_contrib] + + def get_lib_for_module(self, module: str) -> Optional[str]: + return self.library_lookup.get(module) + + def get_all_cmake_modules(self) -> List[str]: + return [ + obj + for (_, (__, obj)) in self.module_lookup.items() + if obj.startswith("CMakeFiles") + ] + + def get_module(self, addr: int) -> Optional[str]: + i = bisect.bisect_left(self.contrib_starts, addr) + # If the addr matches the section contribution start, we are in the + # right spot. Otherwise, we need to subtract one here. + # We don't want the insertion point given by bisect, but the + # section contribution that contains the address. + + (potential_start, _, __) = self.section_contrib[i] + if potential_start != addr: + i -= 1 + + # Safety catch: clamp to range of indices from section_contrib. + i = max(0, min(i, len(self.section_contrib) - 1)) + + (start, size, module_id) = self.section_contrib[i] + if start <= addr < start + size: + if (module := self.module_lookup.get(module_id)) is not None: + return module + + return None + + +def print_sections(sections): + print(" name | start | v.size | raw size") + print("---------|----------|----------|----------") + for sect in sections: + name = sect.name + print( + f"{name:>8} | {sect.virtual_address:8x} | {sect.virtual_size:8x} | {sect.size_of_raw_data:8x}" + ) + print() + + +ALLOWED_TYPE_ABBREVIATIONS = ["fun", "dat", "poi", "str", "vta", "flo"] + + +def match_type_abbreviation(mtype: Optional[SymbolType]) -> str: + """Return abbreviation of the given SymbolType name""" + if mtype is None: + return "" + + return mtype.name.lower()[:3] + + +def get_cmakefiles_prefix(module: str) -> str: + """For the given .obj, get the "CMakeFiles/something.dir/" prefix. + For lack of a better option, this is the library for this module.""" + if module.startswith("CMakeFiles"): + return "/".join(module.split("/", 2)[:2]) + "/" + + return module + + +def truncate_module_name(prefix: str, module: str) -> str: + """Remove the CMakeFiles prefix and the .obj suffix for the given module. + Input: CMakeFiles/lego1.dir/, CMakeFiles/lego1.dir/LEGO1/define.cpp.obj + Output: LEGO1/define.cpp""" + + if module.startswith(prefix): + module = module[len(prefix) :] + + if module.endswith(".obj"): + module = module[:-4] + + return module + + +def avg_remove_outliers(entries: List[int]) -> int: + """Compute the average from this list of entries (addresses) + after removing outlier values.""" + + if len(entries) == 1: + return entries[0] + + avg = statistics.mean(entries) + sd = statistics.pstdev(entries) + + return int(statistics.mean([e for e in entries if abs(e - avg) <= 2 * sd])) + + +RoadmapRow = namedtuple( + "RoadmapRow", + [ + "orig_sect_ofs", + "recomp_sect_ofs", + "orig_addr", + "recomp_addr", + "displacement", + "sym_type", + "size", + "name", + "module", + ], +) + + +class DeltaCollector: + """Reads each row of the results and aggregates information about the + placement of each module.""" + + def __init__(self, match_type: str = "fun") -> None: + # The displacement for each symbol from each module + self.disp_map = {} + + # Each address for each module + self.addresses = {} + + # The earliest address for each module + self.earliest = {} + + # String abbreviation for which symbol type we are checking + self.match_type = "fun" + + match_type = str(match_type).strip().lower()[:3] + if match_type in ALLOWED_TYPE_ABBREVIATIONS: + self.match_type = match_type + + def read_row(self, row: RoadmapRow): + if row.module is None: + return + + if row.sym_type != self.match_type: + return + + if row.orig_addr is not None: + if row.module not in self.addresses: + self.addresses[row.module] = [] + + self.addresses[row.module].append(row.orig_addr) + + if row.orig_addr < self.earliest.get(row.module, 0xFFFFFFFFF): + self.earliest[row.module] = row.orig_addr + + if row.displacement is not None: + if row.module not in self.disp_map: + self.disp_map[row.module] = [] + + self.disp_map[row.module].append(row.displacement) + + def iter_sorted(self) -> Iterator[Tuple[int, int]]: + """Compute the average address for each module, then generate them + in ascending order.""" + avg_address = { + mod: avg_remove_outliers(values) for mod, values in self.addresses.items() + } + for mod, avg in sorted(avg_address.items(), key=lambda x: x[1]): + yield (avg, mod) + + +def suggest_order(results: List[RoadmapRow], module_map: ModuleMap, match_type: str): + """Suggest the order of modules for CMakeLists.txt""" + + dc = DeltaCollector(match_type) + for row in results: + dc.read_row(row) + + # First, show the order of .obj files for the "CMake Modules" + # Meaning: the modules where the .obj file begins with "CMakeFiles". + # These are the libraries where we directly control the order. + # The library name (from cvdump) doesn't make it obvious that these are + # our libraries so we derive the name based on the CMakeFiles prefix. + leftover_modules = set(module_map.get_all_cmake_modules()) + + # A little convoluted, but we want to take the first two tokens + # of the string with '/' as the delimiter. + # i.e. CMakeFiles/isle.dir/ + # The idea is to print exactly what appears in CMakeLists.txt. + cmake_prefixes = sorted(set(get_cmakefiles_prefix(mod) for mod in leftover_modules)) + + # Save this off because we'll use it again later. + computed_order = list(dc.iter_sorted()) + + for prefix in cmake_prefixes: + print(prefix) + + last_earliest = 0 + # Show modules ordered by the computed average of addresses + for _, module in computed_order: + if not module.startswith(prefix): + continue + + leftover_modules.remove(module) + + avg_displacement = None + displacements = dc.disp_map.get(module) + if displacements is not None and len(displacements) > 0: + avg_displacement = int(statistics.mean(displacements)) + + # Call attention to any modules where ordering by earliest + # address is different from the computed order we display. + earliest = dc.earliest.get(module) + ooo_mark = "*" if earliest < last_earliest else " " + last_earliest = earliest + + code_file = truncate_module_name(prefix, module) + print(f"0x{earliest:08x}{ooo_mark} {avg_displacement:10} {code_file}") + + # These modules are included in the final binary (in some form) but + # don't contribute any symbols of the type we are checking. + # n.b. There could still be other modules that are part of + # CMakeLists.txt but are not included in the pdb for whatever reason. + # In other words: don't take the list we provide as the final word on + # what should or should not be included. + # This is merely a suggestion of the order. + for module in leftover_modules: + if not module.startswith(prefix): + continue + + # aligned with previous print + code_file = truncate_module_name(prefix, module) + print(f" no suggestion {code_file}") + + print() + + # Now display the order of all libaries in the final file. + library_order = {} + + for start, module in computed_order: + lib = module_map.get_lib_for_module(module) + if lib is None: + lib = get_cmakefiles_prefix(module) + + if start < library_order.get(lib, 0xFFFFFFFFF): + library_order[lib] = start + + print("Library order (average address shown):") + for lib, start in sorted(library_order.items(), key=lambda x: x[1]): + # Strip off any OS path for brevity + if not lib.startswith("CMakeFiles"): + lib = os.path.basename(lib) + + print(f"{lib:40} {start:08x}") + + +def print_text_report(results: List[RoadmapRow]): + """Print the result with original and recomp addresses.""" + for row in results: + print( + " ".join( + [ + f"{or_blank(row.orig_sect_ofs):14}", + f"{or_blank(row.recomp_sect_ofs):14}", + f"{or_blank(row.displacement):>8}", + f"{row.sym_type:3}", + f"{or_blank(row.size):6}", + or_blank(row.name), + ] + ) + ) + + +def print_diff_report(results: List[RoadmapRow]): + """Print only entries where we have the recomp address. + This is intended for generating a file to diff against. + The recomp addresses are always changing so we hide those.""" + for row in results: + if row.orig_addr is None or row.recomp_addr is None: + continue + + print( + " ".join( + [ + f"{or_blank(row.orig_sect_ofs):14}", + f"{or_blank(row.displacement):>8}", + f"{row.sym_type:3}", + f"{or_blank(row.size):6}", + or_blank(row.name), + ] + ) + ) + + +def export_to_csv(csv_file: str, results: List[RoadmapRow]): + with open(csv_file, "w+", encoding="utf-8") as f: + f.write( + "orig_sect_ofs,recomp_sect_ofs,orig_addr,recomp_addr,displacement,row_type,size,name,module\n" + ) + for row in results: + f.write(",".join(map(or_blank, row))) + f.write("\n") + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Show all addresses from original and recomp." + ) + parser.add_argument( + "original", metavar="original-binary", help="The original binary" + ) + parser.add_argument( + "recompiled", metavar="recompiled-binary", help="The recompiled binary" + ) + parser.add_argument( + "pdb", metavar="recompiled-pdb", help="The PDB of the recompiled binary" + ) + parser.add_argument( + "decomp_dir", metavar="decomp-dir", help="The decompiled source tree" + ) + parser.add_argument("--csv", metavar="", help="If set, export to CSV") + parser.add_argument( + "--verbose", "-v", action="store_true", help="Show recomp addresses in output" + ) + parser.add_argument( + "--order", + const="fun", + nargs="?", + type=str, + help="Show suggested order of modules (using the specified symbol type)", + ) + + (args, _) = parser.parse_known_args() + + if not os.path.isfile(args.original): + parser.error(f"Original binary {args.original} does not exist") + + if not os.path.isfile(args.recompiled): + parser.error(f"Recompiled binary {args.recompiled} does not exist") + + if not os.path.isfile(args.pdb): + parser.error(f"Symbols PDB {args.pdb} does not exist") + + if not os.path.isdir(args.decomp_dir): + parser.error(f"Source directory {args.decomp_dir} does not exist") + + return args + + +def main(): + args = parse_args() + + with IsleBin(args.original, find_str=True) as orig_bin, IsleBin( + args.recompiled + ) as recomp_bin: + engine = IsleCompare(orig_bin, recomp_bin, args.pdb, args.decomp_dir) + + module_map = ModuleMap(args.pdb, recomp_bin) + + def is_same_section(orig: int, recomp: int) -> bool: + """Compare the section name instead of the index. + LEGO1.dll adds extra sections for some reason. (Smacker library?)""" + + try: + orig_name = orig_bin.sections[orig - 1].name + recomp_name = recomp_bin.sections[recomp - 1].name + return orig_name == recomp_name + except IndexError: + return False + + def to_roadmap_row(match): + orig_sect = None + orig_ofs = None + orig_sect_ofs = None + recomp_sect = None + recomp_ofs = None + recomp_sect_ofs = None + orig_addr = None + recomp_addr = None + displacement = None + module_name = None + + if match.recomp_addr is not None: + if (module_ref := module_map.get_module(match.recomp_addr)) is not None: + (_, module_name) = module_ref + + row_type = match_type_abbreviation(match.compare_type) + name = ( + repr(match.name) + if match.compare_type == SymbolType.STRING + else match.name + ) + + if match.orig_addr is not None: + orig_addr = match.orig_addr + (orig_sect, orig_ofs) = orig_bin.get_relative_addr(match.orig_addr) + orig_sect_ofs = f"{orig_sect:04}:{orig_ofs:08x}" + + if match.recomp_addr is not None: + recomp_addr = match.recomp_addr + (recomp_sect, recomp_ofs) = recomp_bin.get_relative_addr( + match.recomp_addr + ) + recomp_sect_ofs = f"{recomp_sect:04}:{recomp_ofs:08x}" + + if ( + orig_sect is not None + and recomp_sect is not None + and is_same_section(orig_sect, recomp_sect) + ): + displacement = recomp_ofs - orig_ofs + + return RoadmapRow( + orig_sect_ofs, + recomp_sect_ofs, + orig_addr, + recomp_addr, + displacement, + row_type, + match.size, + name, + module_name, + ) + + def roadmap_row_generator(matches): + for match in matches: + try: + yield to_roadmap_row(match) + except InvalidVirtualAddressError: + # This is here to work around the fact that we have RVA + # values (i.e. not real virtual addrs) in our compare db. + pass + + results = list(roadmap_row_generator(engine.get_all())) + + if args.order is not None: + suggest_order(results, module_map, args.order) + return + + if args.csv is None: + if args.verbose: + print("ORIG sections:") + print_sections(orig_bin.sections) + + print("RECOMP sections:") + print_sections(recomp_bin.sections) + + print_text_report(results) + else: + print_diff_report(results) + + if args.csv is not None: + export_to_csv(args.csv, results) + + +if __name__ == "__main__": + main() diff --git a/tools/verexp/verexp.py b/tools/verexp/verexp.py new file mode 100644 index 00000000..e112c07a --- /dev/null +++ b/tools/verexp/verexp.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import argparse +import difflib +import subprocess +import os + +from isledecomp.lib import lib_path_join +from isledecomp.utils import print_diff + + +def main(): + parser = argparse.ArgumentParser( + allow_abbrev=False, + description="Verify Exports: Compare the exports of two DLLs.", + ) + parser.add_argument( + "original", metavar="original-binary", help="The original binary" + ) + parser.add_argument( + "recompiled", metavar="recompiled-binary", help="The recompiled binary" + ) + parser.add_argument( + "--no-color", "-n", action="store_true", help="Do not color the output" + ) + + args = parser.parse_args() + + if not os.path.isfile(args.original): + parser.error(f"Original binary file {args.original} does not exist") + + if not os.path.isfile(args.recompiled): + parser.error(f"Recompiled binary {args.recompiled} does not exist") + + def get_exports(file): + call = [lib_path_join("DUMPBIN.EXE"), "/EXPORTS"] + + if os.name != "nt": + call.insert(0, "wine") + file = ( + subprocess.check_output(["winepath", "-w", file]) + .decode("utf-8") + .strip() + ) + + call.append(file) + + raw = subprocess.check_output(call).decode("utf-8").split("\r\n") + exports = [] + + start = False + + for line in raw: + if not start: + if line == " ordinal hint name": + start = True + else: + if line: + exports.append(line[27 : line.rindex(" (")]) + elif exports: + break + + return exports + + og_exp = get_exports(args.original) + re_exp = get_exports(args.recompiled) + + udiff = difflib.unified_diff(og_exp, re_exp) + has_diff = print_diff(udiff, args.no_color) + + return 1 if has_diff else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tools/vtable/vtable.py b/tools/vtable/vtable.py new file mode 100644 index 00000000..aa294659 --- /dev/null +++ b/tools/vtable/vtable.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 + +import os +import argparse +import logging +from typing import List +import colorama +from isledecomp.bin import Bin as IsleBin +from isledecomp.compare import Compare as IsleCompare +from isledecomp.utils import print_combined_diff + +# Ignore all compare-db messages. +logging.getLogger("isledecomp.compare").addHandler(logging.NullHandler()) + +colorama.just_fix_windows_console() + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(description="Comparing vtables.") + parser.add_argument( + "original", metavar="original-binary", help="The original binary" + ) + parser.add_argument( + "recompiled", metavar="recompiled-binary", help="The recompiled binary" + ) + parser.add_argument( + "pdb", metavar="recompiled-pdb", help="The PDB of the recompiled binary" + ) + parser.add_argument( + "decomp_dir", metavar="decomp-dir", help="The decompiled source tree" + ) + parser.add_argument( + "--verbose", "-v", action="store_true", help="Show more detailed information" + ) + parser.add_argument( + "--no-color", "-n", action="store_true", help="Do not color the output" + ) + + (args, _) = parser.parse_known_args() + + if not os.path.isfile(args.original): + parser.error(f"Original binary {args.original} does not exist") + + if not os.path.isfile(args.recompiled): + parser.error(f"Recompiled binary {args.recompiled} does not exist") + + if not os.path.isfile(args.pdb): + parser.error(f"Symbols PDB {args.pdb} does not exist") + + if not os.path.isdir(args.decomp_dir): + parser.error(f"Source directory {args.decomp_dir} does not exist") + + return args + + +def show_vtable_diff(udiff: List, _: bool = False, plain: bool = False): + print_combined_diff(udiff, plain) + + +def print_summary(vtable_count: int, problem_count: int): + if problem_count == 0: + print(f"Vtables found: {vtable_count}.\n100% match.") + return + + print(f"Vtables found: {vtable_count}.\nVtables not matching: {problem_count}.") + + +def main(): + args = parse_args() + vtable_count = 0 + problem_count = 0 + + with IsleBin(args.original) as orig_bin, IsleBin(args.recompiled) as recomp_bin: + engine = IsleCompare(orig_bin, recomp_bin, args.pdb, args.decomp_dir) + + for tbl_match in engine.compare_vtables(): + vtable_count += 1 + if tbl_match.ratio < 1: + problem_count += 1 + + udiff = list(tbl_match.udiff) + + print( + tbl_match.name, + f": orig 0x{tbl_match.orig_addr:x}, recomp 0x{tbl_match.recomp_addr:x}", + ) + show_vtable_diff(udiff, args.verbose, args.no_color) + print() + + print_summary(vtable_count, problem_count) + + # Now compare adjuster thunk functions, if there are any. + # These matches are generated by the compare engine. + # They should always match 100%. If not, there is a problem + # with the inheritance or an overriden function. + for fun_match in engine.get_functions(): + if "`vtordisp" not in fun_match.name: + continue + + diff = engine.compare_address(fun_match.orig_addr) + if diff.ratio < 1.0: + problem_count += 1 + print( + f"Problem with adjuster thunk {fun_match.name} (0x{fun_match.orig_addr:x} / 0x{fun_match.recomp_addr:x})" + ) + + return 1 if problem_count > 0 else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/util/compat.h b/util/compat.h new file mode 100644 index 00000000..ea2a6507 --- /dev/null +++ b/util/compat.h @@ -0,0 +1,25 @@ +#ifndef COMPAT_H +#define COMPAT_H + +// Various macros to enable compiling with other/newer compilers. + +#if defined(__MINGW32__) || (defined(_MSC_VER) && _MSC_VER >= 1100) +#define COMPAT_MODE +#endif + +// Disable "identifier was truncated to '255' characters" warning. +// Impossible to avoid this if using STL map or set. +// This removes most (but not all) occurrences of the warning. +#pragma warning(disable : 4786) + +#define MSVC420_VERSION 1020 + +// We use `override` so newer compilers can tell us our vtables are valid, +// however this keyword was added in C++11, so we define it as empty for +// compatibility with older compilers. +#if __cplusplus < 201103L +#define override +#define static_assert(expr, msg) +#endif + +#endif // COMPAT_H diff --git a/util/decomp.h b/util/decomp.h new file mode 100644 index 00000000..81cb1d13 --- /dev/null +++ b/util/decomp.h @@ -0,0 +1,24 @@ +#ifndef DECOMP_H +#define DECOMP_H + +#if defined(ENABLE_DECOMP_ASSERTS) +#define DECOMP_STATIC_ASSERT(V) \ + namespace \ + { \ + typedef int foo[(V) ? 1 : -1]; \ + } +#define DECOMP_SIZE_ASSERT(T, S) DECOMP_STATIC_ASSERT(sizeof(T) == S) +#else +#define DECOMP_STATIC_ASSERT(V) +#define DECOMP_SIZE_ASSERT(T, S) +#endif + +#ifndef sizeOfArray +#define sizeOfArray(arr) (sizeof(arr) / sizeof(arr[0])) +#endif + +typedef unsigned char undefined; +typedef unsigned short undefined2; +typedef unsigned int undefined4; + +#endif // DECOMP_H