mirror of
https://github.com/AntonioND/nitro-engine.git
synced 2025-06-18 16:45:33 -04:00
445 lines
10 KiB
C
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;
|
|
}
|