Add freecam

This commit is contained in:
James Lambert 2022-09-27 19:33:56 -06:00
parent 964a8f3fd1
commit f767fdf8ab
11 changed files with 92 additions and 34 deletions

View file

@ -17,7 +17,7 @@ $(SKELATOOL64):
skelatool64/setup_dependencies.sh
make -C skelatool64
OPTIMIZER := -O0
OPTIMIZER := -O2
LCDEFS := -DDEBUG -g -Isrc/ -I/usr/include/n64/nustd -Werror -Wall
N64LIB := -lultra_rom -lnustd
@ -218,7 +218,7 @@ TEST_CHAMBER_OBJECTS = $(TEST_CHAMBERS:%.blend=build/%_geo.o)
build/%.fbx: %.blend
@mkdir -p $(@D)
$(BLENDER_2_9) $< --background --python tools/export_fbx.py -- $@
$(BLENDER_3_0) $< --background --python tools/export_fbx.py -- $@
build/assets/test_chambers/%.h build/assets/test_chambers/%_geo.c: build/assets/test_chambers/%.fbx build/assets/materials/static.h $(SKELATOOL64) $(TEXTURE_IMAGES)
$(SKELATOOL64) --level --fixed-point-scale 256 --model-scale 0.01 --name $(<:build/assets/test_chambers/%.fbx=%) -m assets/materials/static.skm.yaml -o $(<:%.fbx=%.h) $<

View file

@ -6,7 +6,7 @@ A demake of portal for the Nintendo 64
First, you will need to setup [modern sdk](https://crashoveride95.github.io/n64hbrew/modernsdk/startoff.html)
Next, you will need to download blender 2.9 or higher. Then set the environment variable `BLENDER_2_9` to be the absolute path where the blender executable is located on your system.
Next, you will need to download blender 3.0 or higher. Then set the environment variable `BLENDER_3_0` to be the absolute path where the blender executable is located on your system.
<br />
@ -63,12 +63,12 @@ docker build . -t portal64
Then build
```sh
# Set the environment variable
BLENDER_2_9=/blender/blender
BLENDER_3_0=/blender/blender
# Build using docker
docker run \
-v /home/james/Blender/blender-2.93.1-linux-x64:/blender \
-e BLENDER_2_9 -v /home/james/portal/portal64/vpk:/usr/src/app/vpk \
-e BLENDER_3_0 -v /home/james/portal/portal64/vpk:/usr/src/app/vpk \
-t -v /home/james/portal/portal64/docker-output:/usr/src/app/build portal64
```

View file

@ -10,6 +10,7 @@
#define KEYFRAME_REMOVE_TOLERNACE 8
struct SKBoneKeyframeChain {
SKBoneKeyframeChain();
SKBoneKeyframe keyframe;
unsigned short tick;
bool isNeeded;
@ -18,6 +19,15 @@ struct SKBoneKeyframeChain {
struct SKBoneKeyframeChain* prev;
};
SKBoneKeyframeChain::SKBoneKeyframeChain():
tick(0),
isNeeded(false),
removalScore(0),
next(nullptr),
prev(nullptr) {
}
bool chainIsLess(SKBoneKeyframeChain* a, SKBoneKeyframeChain* b) {
return a->removalScore > b->removalScore;
}
@ -136,7 +146,7 @@ bool keyframeSortFn(const SKBoneKeyframeChain& a, const SKBoneKeyframeChain& b)
return (a.keyframe.usedAttributes & 0x7) < (b.keyframe.usedAttributes & 0x7);
}
void populateKeyframes(const aiAnimation& input, BoneHierarchy& bones, float fixedPointScale, float modelScale, const aiQuaternion& rotation, float timeScalar, std::vector<SKBoneKeyframeChain>& output) {
void populateKeyframes(const aiAnimation& input, BoneHierarchy& bones, float fixedPointScale, float modelScale, const aiQuaternion& rotation, std::vector<SKBoneKeyframeChain>& output) {
for (unsigned i = 0; i < input.mNumChannels; ++i) {
aiNodeAnim* node = input.mChannels[i];
@ -150,7 +160,7 @@ void populateKeyframes(const aiAnimation& input, BoneHierarchy& bones, float fix
aiVectorKey* vectorKey = &node->mPositionKeys[keyIndex];
SKBoneKeyframeChain keyframe;
keyframe.tick = (unsigned short)(vectorKey->mTime * timeScalar + 0.5f);
keyframe.tick = (unsigned short)(vectorKey->mTime);
keyframe.next = nullptr;
keyframe.prev = nullptr;
keyframe.keyframe.usedAttributes = SKBoneAttrMaskPosition;
@ -173,7 +183,7 @@ void populateKeyframes(const aiAnimation& input, BoneHierarchy& bones, float fix
aiQuatKey* quatKey = &node->mRotationKeys[keyIndex];
SKBoneKeyframeChain keyframe;
keyframe.tick = (unsigned short)(quatKey->mTime * timeScalar + 0.5f);
keyframe.tick = (unsigned short)(quatKey->mTime);
keyframe.next = nullptr;
keyframe.prev = nullptr;
keyframe.keyframe.usedAttributes = SKBoneAttrMaskRotation;
@ -190,7 +200,7 @@ void populateKeyframes(const aiAnimation& input, BoneHierarchy& bones, float fix
aiVectorKey* vectorKey = &node->mScalingKeys[keyIndex];
SKBoneKeyframeChain keyframe;
keyframe.tick = (unsigned short)(vectorKey->mTime * timeScalar + 0.5f);
keyframe.tick = (unsigned short)(vectorKey->mTime);
keyframe.next = nullptr;
keyframe.prev = nullptr;
keyframe.keyframe.usedAttributes = SKBoneAttrMaskScale;
@ -375,10 +385,8 @@ void buildInitialState(std::map<unsigned short, SKBoneKeyframeChain*>& firstKeyF
}
bool translateAnimationToSK(const aiAnimation& input, struct SKAnimation& output, BoneHierarchy& bones, float fixedPointScale, float modelScale, const aiQuaternion& rotation, unsigned short targetTicksPerSecond) {
float timeScalar = (float)targetTicksPerSecond / (float)1000.0f;
std::vector<SKBoneKeyframeChain> keyframes;
populateKeyframes(input, bones, fixedPointScale, modelScale, rotation, timeScalar, keyframes);
populateKeyframes(input, bones, fixedPointScale, modelScale, rotation, keyframes);
if (keyframes.size() == 0) {
return false;
@ -397,8 +405,8 @@ bool translateAnimationToSK(const aiAnimation& input, struct SKAnimation& output
buildInitialState(firstKeyFrame, currentChunk);
output.ticksPerSecond = targetTicksPerSecond;
output.maxTicks = (unsigned short)(input.mDuration * timeScalar);
output.ticksPerSecond = (unsigned short)input.mTicksPerSecond;
output.maxTicks = (unsigned short)(input.mDuration);
while (currentIndex < keyframes.size()) {
unsigned short tick = keyframes[currentIndex].tick;

View file

@ -154,7 +154,7 @@ static void gameProc(void* arg) {
dynamicSceneInit();
contactSolverInit(&gContactSolver);
portalSurfaceCleanupQueueInit();
levelLoad(2);
levelLoad(0);
cutsceneRunnerReset();
controllersInit();
initAudio();

View file

@ -221,30 +221,30 @@ float playerCleanupStickInput(s8 input) {
return ((float)input + (input > 0 ? -DEADZONE_SIZE : DEADZONE_SIZE)) * (1.0f / (MAX_JOYSTICK_RANGE - DEADZONE_SIZE));
}
void playerGetMoveBasis(struct Transform* transform, struct Vector3* forward, struct Vector3* right) {
quatMultVector(&transform->rotation, &gForward, forward);
quatMultVector(&transform->rotation, &gRight, right);
if (forward->y > 0.7f) {
quatMultVector(&transform->rotation, &gUp, forward);
vector3Negate(forward, forward);
} else if (forward->y < -0.7f) {
quatMultVector(&transform->rotation, &gUp, forward);
}
forward->y = 0.0f;
right->y = 0.0f;
vector3Normalize(forward, forward);
vector3Normalize(right, right);
}
void playerUpdate(struct Player* player, struct Transform* cameraTransform) {
struct Vector3 forward;
struct Vector3 right;
int doorwayMask = worldCheckDoorwaySides(&gCurrentLevel->world, &player->lookTransform.position, player->body.currentRoom);
struct Transform* transform = &player->lookTransform;
quatMultVector(&transform->rotation, &gForward, &forward);
quatMultVector(&transform->rotation, &gRight, &right);
if (forward.y > 0.7f) {
quatMultVector(&transform->rotation, &gUp, &forward);
vector3Negate(&forward, &forward);
} else if (forward.y < -0.7f) {
quatMultVector(&transform->rotation, &gUp, &forward);
}
forward.y = 0.0f;
right.y = 0.0f;
vector3Normalize(&gForward, &gForward);
vector3Normalize(&gRight, &gRight);
playerGetMoveBasis(&player->lookTransform, &forward, &right);
if ((player->flags & PlayerFlagsGrounded) && controllerGetButtonDown(0, A_BUTTON)) {
player->body.velocity.y = JUMP_IMPULSE;

View file

@ -31,4 +31,6 @@ void playerUpdate(struct Player* player, struct Transform* cameraTransform);
void playerRender(struct Player* player, struct RenderState* renderState);
void playerGetMoveBasis(struct Transform* transform, struct Vector3* forward, struct Vector3* right);
#endif

View file

@ -115,6 +115,8 @@ void sceneInit(struct Scene* scene) {
for (int i = 0; i < scene->boxDropperCount; ++i) {
boxDropperInit(&scene->boxDroppers[i], &gCurrentLevel->boxDroppers[i]);
}
scene->freeCameraOffset = gZeroVec;
}
void sceneRenderWithProperties(void* data, struct RenderProps* properties, struct RenderState* renderState) {
@ -277,6 +279,8 @@ struct Transform gRelativeElevatorTransform = {
{1.0f, 1.0f, 1.0f},
};
#define FREE_CAM_VELOCITY 2.0f
void sceneUpdate(struct Scene* scene) {
OSTime frameStart = osGetTime();
scene->lastFrameTime = frameStart - scene->lastFrameStart;
@ -361,6 +365,49 @@ void sceneUpdate(struct Scene* scene) {
scene->cpuTime = osGetTime() - frameStart;
scene->lastFrameStart = frameStart;
OSContPad* freecam = controllersGetControllerData(1);
struct Vector3 lookDir;
struct Vector3 rightDir;
playerGetMoveBasis(&scene->camera.transform, &lookDir, &rightDir);
if (freecam->stick_y) {
if (controllerGetButton(1, Z_TRIG)) {
vector3AddScaled(
&scene->freeCameraOffset,
&lookDir,
-freecam->stick_y * (FREE_CAM_VELOCITY * FIXED_DELTA_TIME / 80.0f),
&scene->freeCameraOffset
);
} else {
scene->freeCameraOffset.y += freecam->stick_y * (FREE_CAM_VELOCITY * FIXED_DELTA_TIME / 80.0f);
}
}
if (freecam->stick_x) {
vector3AddScaled(
&scene->freeCameraOffset,
&rightDir,
freecam->stick_x * (FREE_CAM_VELOCITY * FIXED_DELTA_TIME / 80.0f),
&scene->freeCameraOffset
);
}
if (controllerGetButtonDown(1, START_BUTTON)) {
scene->freeCameraOffset = gZeroVec;
}
vector3Add(&scene->camera.transform.position, &scene->freeCameraOffset, &scene->camera.transform.position);
if (controllerGetButtonDown(1, L_TRIG)) {
struct Transform identityTransform;
transformInitIdentity(&identityTransform);
identityTransform.position.y = 1.0f;
levelQueueLoad(NEXT_LEVEL, &identityTransform, &gZeroVec);
}
}
int sceneOpenPortal(struct Scene* scene, struct Transform* at, int portalIndex, int quadIndex, int roomIndex) {

View file

@ -29,6 +29,7 @@ struct Scene {
struct Pedestal* pedestals;
struct Signage* signage;
struct BoxDropper* boxDroppers;
struct Vector3 freeCameraOffset;
OSTime cpuTime;
OSTime lastFrameStart;
OSTime lastFrameTime;