2012-01-23 23:45:33 +00:00
|
|
|
#include "camera.h"
|
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
2012-01-24 13:16:20 +00:00
|
|
|
#include "render.h"
|
2012-01-29 11:34:49 +00:00
|
|
|
#include "scenery.h"
|
2012-01-29 17:39:56 +00:00
|
|
|
#include "tools.h"
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
void cameraSave(PackStream* stream, CameraDefinition* camera)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-04-22 17:12:39 +00:00
|
|
|
v3Save(stream, &camera->location);
|
2012-06-17 09:40:40 +00:00
|
|
|
packWriteDouble(stream, &camera->yaw);
|
|
|
|
packWriteDouble(stream, &camera->pitch);
|
|
|
|
packWriteDouble(stream, &camera->roll);
|
2012-01-23 23:45:33 +00:00
|
|
|
}
|
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
void cameraLoad(PackStream* stream, CameraDefinition* camera)
|
2012-01-23 23:45:33 +00:00
|
|
|
{
|
2012-04-22 17:12:39 +00:00
|
|
|
v3Load(stream, &camera->location);
|
2012-06-17 09:40:40 +00:00
|
|
|
packReadDouble(stream, &camera->yaw);
|
|
|
|
packReadDouble(stream, &camera->pitch);
|
|
|
|
packReadDouble(stream, &camera->roll);
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
cameraValidateDefinition(camera, 0);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
CameraDefinition cameraCreateDefinition()
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
CameraDefinition definition;
|
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
definition.location.x = 0.0;
|
2012-01-23 23:45:33 +00:00
|
|
|
definition.location.y = 0.0;
|
|
|
|
definition.location.z = 0.0;
|
2012-01-29 11:34:49 +00:00
|
|
|
definition.yaw = 0.0;
|
|
|
|
definition.pitch = 0.0;
|
|
|
|
definition.roll = 0.0;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-31 11:20:52 +00:00
|
|
|
definition.width = 1.0;
|
|
|
|
definition.height = 1.0;
|
|
|
|
definition.yfov = 1.57;
|
|
|
|
definition.xratio = 1.0;
|
|
|
|
definition.znear = 1.0;
|
|
|
|
definition.zfar = 1000.0;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
cameraValidateDefinition(&definition, 0);
|
2012-01-23 23:45:33 +00:00
|
|
|
|
|
|
|
return definition;
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cameraDeleteDefinition(CameraDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2013-01-22 20:50:37 +00:00
|
|
|
UNUSED(definition);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void cameraCopyDefinition(CameraDefinition* source, CameraDefinition* destination)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
*destination = *source;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
cameraValidateDefinition(destination, 0);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
void cameraValidateDefinition(CameraDefinition* definition, int check_above)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2013-01-20 15:07:45 +00:00
|
|
|
Renderer* renderer;
|
2012-06-17 09:40:40 +00:00
|
|
|
double water_height, terrain_height, diff;
|
2012-01-29 11:34:49 +00:00
|
|
|
Vector3 move;
|
|
|
|
Matrix4 rotation;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
if (check_above)
|
|
|
|
{
|
2012-12-09 17:49:28 +00:00
|
|
|
renderer = sceneryCreateStandardRenderer();
|
2013-01-20 15:07:45 +00:00
|
|
|
terrain_height = renderer->terrain->getHeight(renderer, definition->location.x, definition->location.z, 1) + 0.5;
|
2013-02-27 16:38:27 +00:00
|
|
|
water_height = renderer->water->getHeightInfo(renderer).max_height + 0.5;
|
2013-01-20 15:07:45 +00:00
|
|
|
rendererDelete(renderer);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
if (definition->location.y < water_height || definition->location.y < terrain_height)
|
|
|
|
{
|
|
|
|
if (water_height > terrain_height)
|
|
|
|
{
|
|
|
|
diff = water_height - definition->location.y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
diff = terrain_height - definition->location.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
move.x = move.z = 0.0;
|
|
|
|
move.y = diff;
|
|
|
|
definition->location = v3Add(definition->location, move);
|
|
|
|
}
|
|
|
|
}
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2013-01-16 15:56:17 +00:00
|
|
|
if (definition->location.y > 100.0)
|
|
|
|
{
|
|
|
|
definition->location.y = 100.0;
|
|
|
|
}
|
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
definition->forward.x = 1.0;
|
|
|
|
definition->forward.y = 0.0;
|
|
|
|
definition->forward.z = 0.0;
|
|
|
|
definition->right.x = 0.0;
|
|
|
|
definition->right.y = 0.0;
|
|
|
|
definition->right.z = 1.0;
|
2012-01-23 23:45:33 +00:00
|
|
|
definition->up.x = 0.0;
|
|
|
|
definition->up.y = 1.0;
|
|
|
|
definition->up.z = 0.0;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
rotation = m4NewRotateEuler(definition->yaw, definition->pitch, definition->roll);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
definition->forward = m4MultPoint(rotation, definition->forward);
|
|
|
|
definition->right = m4MultPoint(rotation, definition->right);
|
|
|
|
definition->up = m4MultPoint(rotation, definition->up);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
definition->target = v3Add(definition->location, definition->forward);
|
|
|
|
|
2012-01-31 11:20:52 +00:00
|
|
|
definition->project = m4Mult(m4NewPerspective(definition->yfov, definition->xratio, definition->znear, definition->zfar), m4NewLookAt(definition->location, definition->target, definition->up));
|
2012-01-23 23:45:33 +00:00
|
|
|
definition->unproject = m4Inverse(definition->project);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void cameraSetLocation(CameraDefinition* camera, double x, double y, double z)
|
2012-01-23 23:45:33 +00:00
|
|
|
{
|
|
|
|
camera->location.x = x;
|
|
|
|
camera->location.y = y;
|
|
|
|
camera->location.z = z;
|
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
cameraValidateDefinition(camera, 0);
|
2012-01-23 23:45:33 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void cameraSetTarget(CameraDefinition* camera, double x, double y, double z)
|
2012-01-23 23:45:33 +00:00
|
|
|
{
|
2012-01-29 11:34:49 +00:00
|
|
|
Vector3 forward, target;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
target.x = x;
|
|
|
|
target.y = y;
|
|
|
|
target.z = z;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
forward = v3Sub(target, camera->location);
|
|
|
|
if (v3Norm(forward) < 0.0000001)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
forward = v3Normalize(forward);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
if (fabs(forward.x) < 0.0000001 && fabs(forward.z) < 0.0000001)
|
|
|
|
{
|
|
|
|
/* Forward vector is vertical */
|
|
|
|
if (forward.y > 0.0)
|
|
|
|
{
|
|
|
|
camera->pitch = M_PI_2;
|
|
|
|
}
|
|
|
|
else if (forward.y > 0.0)
|
|
|
|
{
|
|
|
|
camera->pitch = -M_PI_2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-04-20 11:28:56 +00:00
|
|
|
/* Guess angles */
|
|
|
|
v3ToEuler(forward, &camera->yaw, &camera->pitch);
|
2012-01-29 11:34:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cameraValidateDefinition(camera, 0);
|
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void cameraSetRoll(CameraDefinition* camera, double angle)
|
2012-01-29 11:34:49 +00:00
|
|
|
{
|
|
|
|
camera->roll = angle;
|
|
|
|
|
|
|
|
cameraValidateDefinition(camera, 0);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void cameraStrafeForward(CameraDefinition* camera, double value)
|
2012-01-27 16:01:34 +00:00
|
|
|
{
|
2012-01-29 11:34:49 +00:00
|
|
|
camera->location = v3Add(camera->location, v3Scale(camera->forward, value));
|
2012-01-27 16:01:34 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
cameraValidateDefinition(camera, 0);
|
2012-01-27 16:01:34 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void cameraStrafeRight(CameraDefinition* camera, double value)
|
2012-01-27 16:01:34 +00:00
|
|
|
{
|
2012-01-29 11:34:49 +00:00
|
|
|
camera->location = v3Add(camera->location, v3Scale(camera->right, value));
|
2012-01-27 16:01:34 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
cameraValidateDefinition(camera, 0);
|
2012-01-27 16:01:34 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void cameraStrafeUp(CameraDefinition* camera, double value)
|
2012-01-27 16:01:34 +00:00
|
|
|
{
|
2012-01-29 11:34:49 +00:00
|
|
|
camera->location = v3Add(camera->location, v3Scale(camera->up, value));
|
2012-01-27 16:01:34 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
cameraValidateDefinition(camera, 0);
|
2012-01-27 16:01:34 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void cameraRotateYaw(CameraDefinition* camera, double value)
|
2012-01-27 17:21:57 +00:00
|
|
|
{
|
2012-01-29 11:34:49 +00:00
|
|
|
camera->yaw += value;
|
2012-01-27 17:21:57 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
cameraValidateDefinition(camera, 0);
|
|
|
|
}
|
2012-01-27 17:21:57 +00:00
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void cameraRotatePitch(CameraDefinition* camera, double value)
|
2012-01-29 11:34:49 +00:00
|
|
|
{
|
|
|
|
camera->pitch += value;
|
|
|
|
|
|
|
|
cameraValidateDefinition(camera, 0);
|
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
void cameraRotateRoll(CameraDefinition* camera, double value)
|
2012-01-29 11:34:49 +00:00
|
|
|
{
|
|
|
|
camera->roll += value;
|
2012-01-27 17:21:57 +00:00
|
|
|
|
2012-01-29 11:34:49 +00:00
|
|
|
cameraValidateDefinition(camera, 0);
|
2012-01-27 17:21:57 +00:00
|
|
|
}
|
|
|
|
|
2012-01-31 11:20:52 +00:00
|
|
|
void cameraSetRenderSize(CameraDefinition* camera, int width, int height)
|
|
|
|
{
|
2012-06-17 09:40:40 +00:00
|
|
|
camera->width = (double)width;
|
|
|
|
camera->height = (double)height;
|
2012-01-31 11:20:52 +00:00
|
|
|
camera->xratio = camera->width / camera->height;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-01-31 11:20:52 +00:00
|
|
|
cameraValidateDefinition(camera, 0);
|
|
|
|
}
|
|
|
|
|
2012-01-29 21:45:58 +00:00
|
|
|
Vector3 cameraProject(CameraDefinition* camera, Renderer* renderer, Vector3 point)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-29 14:23:10 +00:00
|
|
|
point = m4Transform(camera->project, point);
|
2012-06-09 20:26:34 +00:00
|
|
|
if (point.z < 1.0)
|
|
|
|
{
|
|
|
|
point.x = -point.x;
|
|
|
|
point.y = -point.y;
|
|
|
|
}
|
2012-01-31 11:20:52 +00:00
|
|
|
point.x = (point.x + 1.0) * 0.5 * camera->width;
|
|
|
|
point.y = (-point.y + 1.0) * 0.5 * camera->height;
|
2011-12-10 13:25:22 +00:00
|
|
|
return point;
|
|
|
|
}
|
|
|
|
|
2012-01-29 21:45:58 +00:00
|
|
|
Vector3 cameraUnproject(CameraDefinition* camera, Renderer* renderer, Vector3 point)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-31 11:20:52 +00:00
|
|
|
point.x = (point.x / (0.5 * camera->width) - 1.0);
|
|
|
|
point.y = -(point.y / (0.5 * camera->height) - 1.0);
|
2012-01-29 14:23:10 +00:00
|
|
|
return m4Transform(camera->unproject, point);
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Render a quad that will fill the view in front of the camera.
|
|
|
|
* This quad can be used for post-processing.
|
2012-01-23 23:45:33 +00:00
|
|
|
*
|
2011-12-10 13:25:22 +00:00
|
|
|
* @param col Color of the polygon.
|
|
|
|
* @param callback Post-processing callback.
|
|
|
|
*/
|
2012-01-29 21:45:58 +00:00
|
|
|
/*void cameraPushOverlay(CameraDefinition* camera, Color col, f_RenderFragmentCallback callback)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-29 21:45:58 +00:00
|
|
|
Vertex v1, v2, v3, v4;
|
2011-12-10 13:25:22 +00:00
|
|
|
Vector3 v;
|
2012-01-23 23:45:33 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
v.x = 0.0;
|
|
|
|
v.y = 0.0;
|
|
|
|
v.z = 10.0;
|
2012-01-23 23:45:33 +00:00
|
|
|
v1.location = cameraUnproject(camera, v);
|
2011-12-10 13:25:22 +00:00
|
|
|
v1.color = col;
|
|
|
|
v1.callback = callback;
|
|
|
|
|
|
|
|
v.x = 0.0;
|
2012-06-17 09:40:40 +00:00
|
|
|
v.y = (double)render_height;
|
2011-12-10 13:25:22 +00:00
|
|
|
v.z = 10.0;
|
2012-01-23 23:45:33 +00:00
|
|
|
v2.location = cameraUnproject(camera, v);
|
2011-12-10 13:25:22 +00:00
|
|
|
v2.color = col;
|
|
|
|
v2.callback = callback;
|
2012-01-23 23:45:33 +00:00
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
v.x = (double)render_width;
|
|
|
|
v.y = (double)render_height;
|
2011-12-10 13:25:22 +00:00
|
|
|
v.z = 10.0;
|
2012-01-23 23:45:33 +00:00
|
|
|
v3.location = cameraUnproject(camera, v);
|
2011-12-10 13:25:22 +00:00
|
|
|
v3.color = col;
|
|
|
|
v3.callback = callback;
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
v.x = (double)render_width;
|
2011-12-10 13:25:22 +00:00
|
|
|
v.y = 0.0;
|
|
|
|
v.z = 10.0;
|
2012-01-23 23:45:33 +00:00
|
|
|
v4.location = cameraUnproject(camera, v);
|
2011-12-10 13:25:22 +00:00
|
|
|
v4.color = col;
|
|
|
|
v4.callback = callback;
|
2012-01-23 23:45:33 +00:00
|
|
|
|
2012-01-29 21:45:58 +00:00
|
|
|
renderPushQuad(&v1, &v2, &v3, &v4);
|
|
|
|
}*/
|
2012-05-09 16:26:07 +00:00
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
static inline void _updateBox(Vector3* point, double* xmin, double* xmax, double* ymin, double* ymax, double* zmax)
|
2012-05-09 16:26:07 +00:00
|
|
|
{
|
2012-11-10 17:05:01 +00:00
|
|
|
*xmin = (*xmin < point->x) ? *xmin : point->x;
|
|
|
|
*ymin = (*ymin < point->y) ? *ymin : point->y;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-11-10 17:05:01 +00:00
|
|
|
*xmax = (*xmax > point->x) ? *xmax : point->x;
|
|
|
|
*ymax = (*ymax > point->y) ? *ymax : point->y;
|
|
|
|
*zmax = (*zmax > point->z) ? *zmax : point->z;
|
2012-05-09 16:26:07 +00:00
|
|
|
}
|
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
int cameraIsBoxInView(CameraDefinition* camera, Vector3 center, double xsize, double ysize, double zsize)
|
2012-05-09 16:26:07 +00:00
|
|
|
{
|
|
|
|
Vector3 projected;
|
2012-06-17 09:40:40 +00:00
|
|
|
double xmin, xmax, ymin, ymax, zmax;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-09 16:26:07 +00:00
|
|
|
center.x -= xsize / 2.0;
|
|
|
|
center.y -= ysize / 2.0;
|
|
|
|
center.z -= zsize / 2.0;
|
|
|
|
projected = cameraProject(camera, NULL, center);
|
|
|
|
xmin = xmax = projected.x;
|
|
|
|
ymin = ymax = projected.y;
|
|
|
|
zmax = projected.z;
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-09 16:26:07 +00:00
|
|
|
center.x += xsize;
|
|
|
|
projected = cameraProject(camera, NULL, center);
|
|
|
|
_updateBox(&projected, &xmin, &xmax, &ymin, &ymax, &zmax);
|
|
|
|
|
2012-06-09 20:26:34 +00:00
|
|
|
center.z += zsize;
|
2012-05-09 16:26:07 +00:00
|
|
|
projected = cameraProject(camera, NULL, center);
|
|
|
|
_updateBox(&projected, &xmin, &xmax, &ymin, &ymax, &zmax);
|
|
|
|
|
2012-06-09 20:26:34 +00:00
|
|
|
center.x -= xsize;
|
2012-05-09 16:26:07 +00:00
|
|
|
projected = cameraProject(camera, NULL, center);
|
|
|
|
_updateBox(&projected, &xmin, &xmax, &ymin, &ymax, &zmax);
|
|
|
|
|
2012-06-09 20:26:34 +00:00
|
|
|
center.y += ysize;
|
2012-05-09 16:26:07 +00:00
|
|
|
projected = cameraProject(camera, NULL, center);
|
|
|
|
_updateBox(&projected, &xmin, &xmax, &ymin, &ymax, &zmax);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-06-09 20:26:34 +00:00
|
|
|
center.x += xsize;
|
2012-05-09 16:26:07 +00:00
|
|
|
projected = cameraProject(camera, NULL, center);
|
|
|
|
_updateBox(&projected, &xmin, &xmax, &ymin, &ymax, &zmax);
|
|
|
|
|
2012-06-09 20:26:34 +00:00
|
|
|
center.z -= zsize;
|
2012-05-09 16:26:07 +00:00
|
|
|
projected = cameraProject(camera, NULL, center);
|
|
|
|
_updateBox(&projected, &xmin, &xmax, &ymin, &ymax, &zmax);
|
|
|
|
|
2012-06-09 20:26:34 +00:00
|
|
|
center.x -= xsize;
|
2012-05-09 16:26:07 +00:00
|
|
|
projected = cameraProject(camera, NULL, center);
|
|
|
|
_updateBox(&projected, &xmin, &xmax, &ymin, &ymax, &zmax);
|
2012-12-09 17:49:28 +00:00
|
|
|
|
2012-05-09 16:26:07 +00:00
|
|
|
return xmin <= camera->width && xmax >= 0.0 && ymin <= camera->height && ymax >= 0.0 && zmax >= camera->znear;
|
|
|
|
}
|