nitro-engine/source/NECamera.c
2024-07-29 00:09:41 +01:00

445 lines
10 KiB
C

// SPDX-License-Identifier: MIT
//
// Copyright (c) 2008-2024 Antonio Niño Díaz
//
// This file is part of Nitro Engine
#include "NEMain.h"
/// @file NECamera.c
static NE_Camera **NE_UserCamera;
static int NE_MAX_CAMERAS;
static bool ne_camera_system_inited = false;
// Internal use only
ARM_CODE static void __NE_CameraUpdateMatrix(NE_Camera * cam)
{
// From libnds, modified a bit
int32_t side[3], forward[3], up[3];
for (int i = 0; i < 3; i++)
forward[i] = cam->from[i] - cam->to[i];
normalizef32(forward);
crossf32(cam->up, forward, side);
normalizef32(side);
// Recompute local up
crossf32(forward, side, up);
cam->matrix.m[0] = side[0];
cam->matrix.m[1] = up[0];
cam->matrix.m[2] = forward[0];
cam->matrix.m[3] = 0;
cam->matrix.m[4] = side[1];
cam->matrix.m[5] = up[1];
cam->matrix.m[6] = forward[1];
cam->matrix.m[7] = 0;
cam->matrix.m[8] = side[2];
cam->matrix.m[9] = up[2];
cam->matrix.m[10] = forward[2];
cam->matrix.m[11] = 0;
cam->matrix.m[12] = -dotf32(cam->from, side);
cam->matrix.m[13] = -dotf32(cam->from, up);
cam->matrix.m[14] = -dotf32(cam->from, forward);
cam->matrix.m[15] = inttof32(1);
}
NE_Camera *NE_CameraCreate(void)
{
if (!ne_camera_system_inited)
{
NE_DebugPrint("System not initialized");
return NULL;
}
for (int i = 0; i < NE_MAX_CAMERAS; i++)
{
if (NE_UserCamera[i] != NULL)
continue;
NE_Camera *cam = calloc(1, sizeof(NE_Camera));
if (cam == NULL)
{
NE_DebugPrint("Not enough memory");
return NULL;
}
cam->to[2] = inttof32(1);
cam->up[1] = inttof32(1);
cam->matrix_is_updated = false;
NE_UserCamera[i] = cam;
return cam;
}
NE_DebugPrint("No free slots");
return NULL;
}
void NE_CameraSetI(NE_Camera *cam, int xfrom, int yfrom, int zfrom,
int xto, int yto, int zto, int xup, int yup, int zup)
{
NE_AssertPointer(cam, "NULL pointer");
cam->from[0] = xfrom;
cam->from[1] = yfrom;
cam->from[2] = zfrom;
cam->to[0] = xto;
cam->to[1] = yto;
cam->to[2] = zto;
cam->up[0] = xup;
cam->up[1] = yup;
cam->up[2] = zup;
cam->matrix_is_updated = false;
}
void NE_CameraUse(NE_Camera *cam)
{
NE_AssertPointer(cam, "NULL pointer");
if (!cam->matrix_is_updated)
{
__NE_CameraUpdateMatrix(cam);
cam->matrix_is_updated = true;
}
glLoadMatrix4x4(&cam->matrix);
}
ARM_CODE void NE_CameraMoveFreeI(NE_Camera *cam, int front, int right, int up)
{
NE_AssertPointer(cam, "NULL pointer");
cam->matrix_is_updated = false;
int32_t vec_front[3], vec_right[3], vec_up[3];
int32_t result[3] = { 0, 0, 0 };
// Temporary vector used to normalize other vectors
int temp[3];
for (int i = 0; i < 3; i++)
vec_front[i] = cam->to[i] - cam->from[i];
if (front != 0)
{
for (int i = 0; i < 3; i++)
temp[i] = vec_front[i];
normalizef32((int32_t *) &temp);
for (int i = 0; i < 3; i++)
result[i] += mulf32(temp[i], front);
}
if (right != 0 || up != 0)
{
// The right vector is needed to get the up vector
crossf32(vec_front, cam->up, vec_right);
if (right != 0)
{
for (int i = 0; i < 3; i++)
temp[i] = vec_right[i];
normalizef32((int32_t *) &temp);
for (int i = 0; i < 3; i++)
result[i] += mulf32(temp[i], right);
}
if (up != 0)
{
crossf32(vec_right, vec_front, vec_up);
// Last vector, not needed to use "temp"
normalizef32((int32_t *) &vec_up);
for (int i = 0; i < 3; i++)
result[i] += mulf32(vec_up[i], up);
}
}
for (int i = 0; i < 3; i++)
{
cam->from[i] += result[i];
cam->to[i] += result[i];
}
}
void NE_CameraMoveI(NE_Camera *cam, int x, int y, int z)
{
NE_AssertPointer(cam, "NULL pointer");
cam->matrix_is_updated = false;
cam->from[0] += x;
cam->from[1] += y;
cam->from[2] += z;
cam->to[0] += x;
cam->to[1] += y;
cam->to[2] += z;
}
ARM_CODE void NE_CameraRotate(NE_Camera *cam, int rx, int ry, int rz)
{
NE_AssertPointer(cam, "NULL pointer");
int cam_vector[3], result_vector[3];
for (int i = 0; i < 3; i++)
cam_vector[i] = cam->to[i] - cam->from[i];
int sine, cosine;
if (rx != 0)
{
cam->matrix_is_updated = false;
sine = sinLerp(rx << 6);
cosine = cosLerp(rx << 6);
result_vector[1] = mulf32(cam_vector[1], cosine)
- mulf32(cam_vector[2], sine);
result_vector[2] = mulf32(cam_vector[1], sine)
+ mulf32(cam_vector[2], cosine);
cam->to[1] = cam->from[1] + result_vector[1];
cam->to[2] = cam->from[2] + result_vector[2];
}
if (ry != 0)
{
cam->matrix_is_updated = false;
sine = sinLerp(ry << 6);
cosine = cosLerp(ry << 6);
result_vector[0] = mulf32(cam_vector[0], cosine)
- mulf32(cam_vector[2], sine);
result_vector[2] = mulf32(cam_vector[0], sine)
+ mulf32(cam_vector[2], cosine);
cam->to[0] = cam->from[0] + result_vector[0];
cam->to[2] = cam->from[2] + result_vector[2];
}
if (rz != 0)
{
cam->matrix_is_updated = false;
sine = sinLerp(rz << 6);
cosine = cosLerp(rz << 6);
result_vector[0] = mulf32(cam_vector[0], cosine)
- mulf32(cam_vector[1], sine);
result_vector[1] = mulf32(cam_vector[0], sine)
+ mulf32(cam_vector[1], cosine);
cam->to[0] = cam->from[0] + result_vector[0];
cam->to[1] = cam->from[1] + result_vector[1];
}
}
// Internal use only
ARM_CODE static void __NE_RotateVectorAxis(int32_t *vector, int angle,
int x, int y, int z)
{
// Vector must be an array of 3 ints with your vector in f32 format!
int sin = sinLerp(angle << 6);
int cos = cosLerp(angle << 6);
int one_minus_cos = inttof32(1) - cos;
int x_by_one_minus_cos = mulf32(one_minus_cos, x);
int y_by_one_minus_cos = mulf32(one_minus_cos, y);
int z_by_one_minus_cos = mulf32(one_minus_cos, z);
int x_by_sin = mulf32(sin, x);
int y_by_sin = mulf32(sin, y);
int z_by_sin = mulf32(sin, z);
int matrix[9];
matrix[0] = mulf32(x, x_by_one_minus_cos) + cos;
matrix[1] = mulf32(y, x_by_one_minus_cos) - z_by_sin;
matrix[2] = mulf32(z, x_by_one_minus_cos) + y_by_sin;
matrix[3] = mulf32(x, y_by_one_minus_cos) + z_by_sin;
matrix[4] = mulf32(y, y_by_one_minus_cos) + cos;
matrix[5] = mulf32(z, y_by_one_minus_cos) - x_by_sin;
matrix[6] = mulf32(x, z_by_one_minus_cos) - y_by_sin;
matrix[7] = mulf32(y, z_by_one_minus_cos) + x_by_sin;
matrix[8] = mulf32(z, z_by_one_minus_cos) + cos;
int result_vector[3];
result_vector[0] = mulf32(vector[0], matrix[0])
+ mulf32(vector[1], matrix[3])
+ mulf32(vector[2], matrix[6]);
result_vector[1] = mulf32(vector[0], matrix[1])
+ mulf32(vector[1], matrix[4])
+ mulf32(vector[2], matrix[7]);
result_vector[2] = mulf32(vector[0], matrix[2])
+ mulf32(vector[1], matrix[5])
+ mulf32(vector[2], matrix[8]);
for (int i = 0; i < 3; i++)
vector[i] = result_vector[i];
}
void NE_CameraRotateAxisI(NE_Camera *cam, int angle, int x, int y, int z)
{
NE_AssertPointer(cam, "NULL pointer");
if (angle == 0)
return;
cam->matrix_is_updated = false;
int32_t cam_vector[3];
for (int i = 0; i < 3; i++)
cam_vector[i] = cam->to[i] - cam->from[i];
__NE_RotateVectorAxis(cam_vector, angle, x, y, z);
for (int i = 0; i < 3; i++)
cam->to[i] = cam->from[i] + cam_vector[i];
}
ARM_CODE void NE_CameraRotateFree(NE_Camera *cam, int rx, int ry, int rz)
{
NE_AssertPointer(cam, "NULL pointer");
if ((rx | ry | rz) == 0)
return;
cam->matrix_is_updated = false;
int32_t vec_front[3], vec_right[3], vec_up[3];
for (int i = 0; i < 3; i++)
vec_front[i] = cam->to[i] - cam->from[i];
if (ry || rx) {
crossf32(vec_front, cam->up, vec_right);
if (ry)
{
crossf32(vec_right, vec_front, vec_up);
normalizef32(vec_up);
NE_CameraRotateAxisI(cam, ry, vec_up[0], vec_up[1], vec_up[2]);
}
if (rx)
{
normalizef32(vec_right);
NE_CameraRotateAxisI(cam, rx,
vec_right[0], vec_right[1], vec_right[2]);
}
}
if (rz)
{
normalizef32(vec_front);
__NE_RotateVectorAxis(cam->up, rz,
vec_front[0], vec_front[1], vec_front[2]);
}
}
void NE_CameraDelete(NE_Camera *cam)
{
NE_AssertPointer(cam, "NULL pointer");
for (int i = 0; i < NE_MAX_CAMERAS; i++)
{
if (NE_UserCamera[i] != cam)
continue;
NE_UserCamera[i] = NULL;
free(cam);
return;
}
NE_DebugPrint("Object not found");
}
int NE_CameraSystemReset(int max_cameras)
{
if (ne_camera_system_inited)
NE_CameraSystemEnd();
if (max_cameras < 1)
NE_MAX_CAMERAS = NE_DEFAULT_CAMERAS;
else
NE_MAX_CAMERAS = max_cameras;
NE_UserCamera = calloc(NE_MAX_CAMERAS, sizeof(NE_UserCamera));
if (NE_UserCamera == NULL)
{
NE_DebugPrint("Not enough memory");
return -1;
}
ne_camera_system_inited = true;
return 0;
}
void NE_CameraSystemEnd(void)
{
if (!ne_camera_system_inited)
return;
for (int i = 0; i < NE_MAX_CAMERAS; i++)
{
if (NE_UserCamera[i])
NE_CameraDelete(NE_UserCamera[i]);
}
free(NE_UserCamera);
ne_camera_system_inited = false;
}
void NE_ViewPush(void)
{
MATRIX_PUSH = 0;
}
void NE_ViewPop(void)
{
MATRIX_POP = 1;
}
void NE_ViewMoveI(int x, int y, int z)
{
MATRIX_TRANSLATE = x;
MATRIX_TRANSLATE = y;
MATRIX_TRANSLATE = z;
}
void NE_ViewRotate(int rx, int ry, int rz)
{
if (rx != 0)
glRotateXi(rx << 6);
if (ry != 0)
glRotateYi(ry << 6);
if (rz != 0)
glRotateZi(rz << 6);
}
void NE_ViewScaleI(int x, int y, int z)
{
MATRIX_SCALE = x;
MATRIX_SCALE = y;
MATRIX_SCALE = z;
}