Skip to content

Commit

Permalink
chore(release): release v1.1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
lmichaelis committed Mar 12, 2023
1 parent 87235e1 commit 6fabc6b
Show file tree
Hide file tree
Showing 69 changed files with 1,929 additions and 1,723 deletions.
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ SpacesBeforeTrailingComments: 1
TabWidth: 4
UseTab: ForIndentation
AccessModifierOffset: -4
IndentPPDirectives: BeforeHash
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@
[submodule "vendor/mio"]
path = vendor/mio
url = https://github.com/mandreyel/mio.git
[submodule "vendor/lexy"]
path = vendor/lexy
url = https://github.com/foonathan/lexy.git
[submodule "vendor/libsquish"]
path = vendor/libsquish
url = https://github.com/lmichaelis/phoenix-libsquish.git
Expand Down
29 changes: 21 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
cmake_minimum_required(VERSION 3.10)
include(CheckIncludeFiles)
project(phoenix VERSION 1.0.1)
project(phoenix VERSION 1.1.1)

set(CMAKE_CXX_STANDARD 17)
set(PHOENIX_LOG_LEVEL 3 CACHE STRING "The logging level to use for phoenix. Set to 4, 3, 2, or 1 for DEBUG, INFO, WARN or ERROR respectively")

option(PHOENIX_BUILD_EXAMPLES "Build example code" OFF)
option(PHOENIX_BUILD_TESTS "Build tests" ON)
option(PHOENIX_BUILD_SHARED "Build phoenix as a shared library" OFF)
option(PHOENIX_DISABLE_SANITIZERS "Build without sanitizers in debug mode" OFF)
option(PHOENIX_INSTALL "Configure phoenix for cmake install" ON)

Expand Down Expand Up @@ -57,12 +58,14 @@ set(PHOENIX_SOURCES
source/buffer.cc
source/font.cc
source/material.cc
source/math.cc
source/mesh.cc
source/messages.cc
source/model.cc
source/model_hierarchy.cc
source/model_mesh.cc
source/model_script.cc
source/model_script_dsl.cc
source/morph_mesh.cc
source/phoenix.cc
source/proto_mesh.cc
Expand Down Expand Up @@ -112,32 +115,42 @@ set(PHOENIX_TESTS
tests/test_world.cc)

# add the phoenix library definition
add_library(phoenix ${PHOENIX_SOURCES} ${PHOENIX_EXTENSIONS} ${PHOENIX_HEADERS})
if (BUILD_SHARED_LIBS AND PHOENIX_BUILD_SHARED)
add_library(phoenix SHARED)
set_target_properties(phoenix PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN 1)
else ()
add_library(phoenix STATIC)
set(PHOENIX_DEFINES ${PHOENIX_DEFINES} PHOENIX_STATIC=1)
set_target_properties(phoenix PROPERTIES COMPILE_FLAGS "-DPHOENIX_STATIC=1")
endif ()

target_sources(phoenix PRIVATE ${PHOENIX_SOURCES} ${PHOENIX_EXTENSIONS} ${PHOENIX_HEADERS})
target_include_directories(phoenix PUBLIC include)

# Apps using phoenix will also need to link to glm, fmt and squish to avoid missing symbols
target_link_libraries(phoenix
PUBLIC glm::glm_static squish
PRIVATE mio lexy)
PRIVATE mio)

target_compile_definitions(phoenix PUBLIC ${PHOENIX_DEFINES})
target_compile_definitions(phoenix PUBLIC ${PHOENIX_DEFINES} PRIVATE PHOENIX_EXPORTS=1)
target_compile_options(phoenix PRIVATE ${PHOENIX_CXX_FLAGS})

if (NOT MSVC)
target_link_options(phoenix PUBLIC ${PHOENIX_CXX_FLAGS})
endif ()

set_target_properties(phoenix PROPERTIES
DEBUG_POSTFIX "${PHOENIX_DEBUG_POSTFIX}")
DEBUG_POSTFIX "${PHOENIX_DEBUG_POSTFIX}"
VERSION ${PROJECT_VERSION})

if (PHOENIX_INSTALL)
install(TARGETS phoenix ARCHIVE LIBRARY RUNTIME)

install(DIRECTORY "include/phoenix" TYPE INCLUDE)
install(DIRECTORY "${glm_SOURCE_DIR}/glm" TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp" PATTERN "*.inl" PATTERN "*.h")

if (NOT BUILD_SHARED_LIBS)
if (NOT PHOENIX_BUILD_SHARED)
# For static linking we'll need to provide the dependency static libraries
install(DIRECTORY "${glm_SOURCE_DIR}/glm" TYPE INCLUDE FILES_MATCHING PATTERN "*.hpp" PATTERN "*.inl" PATTERN "*.h")

foreach (lib glm::glm_static squish)
install(FILES "$<TARGET_LINKER_FILE:${lib}>" TYPE LIB)
endforeach ()
Expand Down
27 changes: 27 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,33 @@ found in [readme.md](readme.md#versioning).

---

## v1.1.1

This update again brings many bugfixes and smaller improvements in addition to updates to the documentation.
_phoenix_ can now also be built as a shared library which should be considered an experimental feature. This update
also finally replaces the old [lexy](https://github.com/foonathan/lexy) parser for model scripts with a self-rolled
implementation.

### Bugfixes
* [03cb97bd] Fixed a stack corruption issue in the VM which could be triggered if the `movvf` or `movf` was called
with a member but no current instance was present
* [c6cb69de] Fixed broken VM execution flag `allow_null_instance_access` for instructions `addmovi`, `submovi`,
`mulmovi` and `divmovi`.
* [cae1c118, f0d6751f] Fixed a VM/script bug which could occur when using higher-order functions.
* [2cd3da6f] Added checks for division by zero errors in the VM.
* [3693450b] Prevent null-pointer de-reference in `vm::initialize_instance` if the instance's parent symbol can
not be found.
* [1bf25106] VDF entries with a size larger than the VDF file itself are now no longer loaded.
* [5d78aa49, 4e7b8630] Fix an issues with ignoring whitespace in binary archives.
* [c7d4115f] Catch numeric conversion errors in archives and re-throw them as `parser_error`s.

### Misc

* [4e9ae25e] Move the const-ness check for script symbols into the VM.
* [c7c6b94a] (experimental) Allow for building phoenix as a shared library.
* [15cd5893] Save the checksums for animations, model meshes and skeletons.
* [16679249] Switch to a custom model script parser, dropping the dependency on [lexy](https://github.com/foonathan/lexy)

## v1.1.0

Oh boy, this is a big one! There are a lot of additions, some changes and also some deprecations here. Also, the
Expand Down
16 changes: 16 additions & 0 deletions docs/assets/javascript/mathjax.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
window.MathJax = {
tex: {
inlineMath: [["\\(", "\\)"]],
displayMath: [["\\[", "\\]"]],
processEscapes: true,
processEnvironments: true
},
options: {
ignoreHtmlClass: ".*|",
processHtmlClass: "arithmatex"
}
};

document$.subscribe(() => {
MathJax.typesetPromise()
})
189 changes: 185 additions & 4 deletions docs/engine/formats/animation.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ chunks. Also refer to the [Datatype Reference](../datatypes.md) for general info
float fps;
float fpsSource;

float samplePositionRangeMin;
float samplePositionScalar;
float samplePositionMin;
float samplePositionScale;
zTBBox3D bounds;
string next;
Expand Down Expand Up @@ -85,7 +85,188 @@ chunks. Also refer to the [Datatype Reference](../datatypes.md) for general info
struct zCModelAni_Samples {
uint checksum;
uint nodeIndices[/* zCModelAni_Header.numNodes */];
ushort rotation[3];
ushort position[3];

struct zTMdl_AniSample {
ushort rotation[3];
ushort position[3];
} samples[/* zCModelAni_Header.numNodes * zCModelAni_Header.numFrames */];
};
```

The `zCModelAni.checksum` field is used to match compatible the animation to a specific model. It is the same for
assets belonging to the same model. Linked assets are `zCModelAni.checksum`, `zCModelMeshLib.checksum` and
`zCModelHierarchy.checksum`.

It is important to understand that the animation samples do not contain the actual values for the rotation and
position. To save on memory and disk space consumption, the values are packed into shorts which are converted
back to floats on demand. See [Sample Positions](#sample-positions) and [Sample Rotations](#sample-rotations) for
more information.

---

### Sample Positions

The positions are represented as multiples of `zCModelAni_Header.samplePositionScale`. The formula for packing a
given `zVEC3` position into the stored format can be summarized like this:

$$
\begin{bmatrix}
x_{p} \\
y_{p} \\
z_{p}
\end{bmatrix}
=
\Bigg(-v_{min} +
\begin{bmatrix}
x \\
y \\
z
\end{bmatrix}
\Bigg) \cdot \frac{65535}{v_{max} - v_{min}}
$$

where $v_{min}$ is the smallest value across all components of all sample positions of the animation and $v_{max}$
is the maximum value. The output vector $\begin{smallmatrix}x_{p} \\ y_{p} \\ z_{p} \end{smallmatrix}$ then contains a
scaled representation of the input vector $\begin{smallmatrix}x \\ y \\ z\end{smallmatrix}$ as three 16-bit unsigned
integers. This operation is performed by `zCModelAni::AddTrafoMatrix` and `zTMdl_AniSample::PackTrans`.

Alongside these packed positions, both $v_{min}$ and the constant $s = (\frac{65535}{v_{max} - v_{min}})^{-1}$ are saved
as `zCModelAni_Header.samplePositionMin` and `zCModelAni_Header.samplePositionScale` respectively. Thus, to convert
the stored position back to its floating point representation, the following calculation may be applied:

$$
\begin{bmatrix}
x \\
y \\
z
\end{bmatrix}
=
\begin{bmatrix}
x_{p} \\
y_{p} \\
z_{p}
\end{bmatrix}
\cdot s + v_{min}
$$

where $x_{p}$ , $y_{p}$ and $z_{p}$ are `zTMdl_AniSample.position[0]`, `zTMdl_AniSample.position[1]` and
`zTMdl_AniSample.position[2]` respectively. This operation is performed by `zTMdl_AniSample::UnpackTrans` .

### Sample Rotations

The rotations are represented as a packed quaternion which is calculated in the following way:

$$
\begin{bmatrix}
x_{p} \\
y_{p} \\
z_{p}
\end{bmatrix}
=
\begin{cases}
\begin{bmatrix}
x \\
y \\
z
\end{bmatrix}
\div s + h & \quad \text{if } w \geq 0 \\
-\Bigg(
\begin{bmatrix}
x \\
y \\
z
\end{bmatrix}
\div s + h\Bigg) - 2 & \quad \text{if } w < 0 \\
\end{cases}
$$

where

$$
s = \frac{1}{2^{16} - 1} * 2.1 = \frac{1}{65535} * 2.1
$$

and

$$
h = 2^{15} - 1 = 32767
$$

This operation packs a quaternion of the form $r = \begin{smallmatrix}x \\ y \\ z \\ w\end{smallmatrix}$ into a set of
three 16-bit unsigned integers $x_{p}$ , $y_{p}$ and $z_{p}$ which are stored into the sample. **The input quaternion
$r$ is required to be a unit vector**. This operation was performed by `zCModelAni::AddTrafoMatrix` and
`zTMdl_AniSample::PackQuat`.

They can be unpacked using some quaternion wizardry as described below.

$$
\begin{bmatrix}
x \\
y \\
z \\
w
\end{bmatrix}
=
\begin{cases}
\begin{bmatrix}
x_{t} \\
y_{t} \\
z_{t} \\
\sqrt{1 - l}
\end{bmatrix} & \quad \text{if } l \leq 1 \\
\begin{bmatrix}
x_{t} \\
y_{t} \\
z_{t} \\
0
\end{bmatrix}
\cdot \frac{1}{\sqrt{l}} & \quad \text{if } l > 1
\end{cases}
$$

where

$$
\begin{bmatrix}
x_{t} \\
y_{t} \\
z_{t} \\
\end{bmatrix}
=
\Bigg(\begin{bmatrix}
x_{p} \\
y_{p} \\
z_{p} \\
\end{bmatrix} - h\Bigg) \cdot s
$$

and

$$
l = (x_{t})^2 + (y_{t})^2 + (z_{t})^2
$$

The values $x_{p}$ , $y_{p}$ and $z_{p}$ for this computation are stored in `zTMdl_AniSample.rotation[0]`,
`zTMdl_AniSample.rotation[1]` and `zTMdl_AniSample.rotation[2]` respectively. This is possible since the quaternion
$r$ used to calculate the packed rotation is guaranteed to be a unit-quaternion, thus, if we have three components
(like we do), it is possible to calculate the third component. This operation is performed by
`zTMdl_AniSample::UnpackQuat`.

---

### (todo) How animated models are loaded

Animated models are loaded by using their associated model script file. While parsing the model script, the parser
will encounter a `meshAndTree` directive (in MSB files a chunk of type `0xf300`) which points to a model hierarchy.

This model hierarchy is then loaded and acts as the ground truth of the model. If a hierarchy can't be loaded for any
reason, the engine tries to load a model mesh instead.

The model script parser continues and eventually hits the `aniEnum` section. While loading it, it will come across
`ani` sections. Those sections contain a model and animation name which are then loaded as animations and model meshes
respectively.

Linking these parts together is a checksum calculates from the list of hierarchy nodes. It is just the CRC32 checksum
of all node names appended after each other in the order they are saved in. I.e. a model hierarchy with two nodes
`"BIP01"` and `"BIP01 LEVER STICK"` (in that order) will have a checksum of `ea809bf7` (which
is `crc32("BIP01BIP01 LEVER STICK")`.
29 changes: 29 additions & 0 deletions docs/library/formats/animation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@


Animations (also called _Model Animations_) form part of the animations system of the _ZenGin_ they contain only
animation samples, i.e. the position and orientation of each bone of the skeleton they're applied to. While there is
space for additional data within animation files, it is mostly empty.

## Overview

*phoenix'* implementation of animations lives in `include/phoenix/animation.hh` and `source/animation.cc`. The most
important part of an animation are its samples. They are stored in `animation::samples` after it has been parsed.
Animation files themselves don't contain information about when to run animation or any other effects which should be
applied during it. Those parts of the animation system are defined in [Model Script](formats/model-script.md) files
which should be loaded before animations. The `animation::events` field will always be empty for that reason.


### Loading a Font

Like most data structures in *phoenix*, animations can be loaded using the `#!cpp phoenix::animation::parse()` function.
It takes a `phoenix::buffer` as a parameter and loads the animation from it.

```cpp title="Example"
#include <phoenix/animation.hh>

int main(int, const char** argv) {
auto anim_buffer = phoenix::buffer::mmap("A.man");
[[maybe_unused]] auto anim = phoenix::animation::parse(anim_buffer);
return 0;
}
```
2 changes: 1 addition & 1 deletion docs/library/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The following is a list of file types and formats used by ZenGin.

| Format | Extension | Description | _phoenix_ Class Name |
|-----------------------------------------------------------|:------------------------------:|----------------------------------------------------------------------------------------------------------------------------|----------------------|
| [Model Animation](formats/model-animation.md) | `.MAN` | Contains animations for a model | `animation` |
| [Model Animation](formats/animation.md) | `.MAN` | Contains animations for a model | `animation` |
| [Model Hierarchy](formats/model-hierarchy.md) | `.MDH` | Contains skeletal information for a model | `model_hierarchy` |
| [Model Mesh](formats/model-mesh.md) | `.MDM` | Contains the mesh of a model | `model_mesh` |
| [Model](formats/model.md) | `.MDL` | Contains a mesh and a hierarchy which make up a model | `model` |
Expand Down
Loading

0 comments on commit 6fabc6b

Please sign in to comment.