forked from 0ad/0ad
6d8b9e33ef
This was SVN commit r804.
504 lines
14 KiB
C++
Executable File
504 lines
14 KiB
C++
Executable File
#include "precompiled.h"
|
|
|
|
#include "Matrix3D.h"
|
|
#include "Renderer.h"
|
|
#include "Terrain.h"
|
|
#include "LightEnv.h"
|
|
#include "HFTracer.h"
|
|
#include "TextureManager.h"
|
|
#include "ObjectManager.h"
|
|
#include "Prometheus.h"
|
|
#include "Hotkey.h"
|
|
#include "ConfigDB.h"
|
|
|
|
#include "sdl.h"
|
|
#include "res/tex.h"
|
|
#include "detect.h"
|
|
#include "input.h"
|
|
#include "lib.h"
|
|
|
|
void InitScene ();
|
|
void InitResources ();
|
|
void RenderScene ();
|
|
|
|
extern bool keys[512]; // SDL also defines non-ascii keys; 512 should be enough
|
|
extern bool mouseButtons[5];
|
|
extern int mouse_x, mouse_y;
|
|
extern bool g_active;
|
|
|
|
|
|
CMatrix3D g_WorldMat;
|
|
CTerrain g_Terrain;
|
|
CCamera g_Camera;
|
|
CLightEnv g_LightEnv;
|
|
|
|
|
|
float g_CameraZoom = 10;
|
|
|
|
std::vector<CVector3D> cameraTargets;
|
|
CVector3D cameraBookmarks[10];
|
|
bool bookmarkInUse[10] = { false, false, false, false, false, false, false, false, false, false };
|
|
u8 currentBookmark = 255;
|
|
CVector3D cameraDelta;
|
|
CVector3D cameraPivot;
|
|
|
|
// These were 'const'; loaded from config now.
|
|
|
|
float ViewScrollSpeed = 60;
|
|
float ViewRotateSensitivity = 0.002f;
|
|
float ViewRotateAboutTargetSensitivity = 0.010f;
|
|
float ViewDragSensitivity = 0.5f;
|
|
float ViewZoomSensitivityWheel = 16.0f;
|
|
float ViewZoomSensitivity = 256.0f;
|
|
float ViewZoomSmoothness = 0.02f; // 0.0 = instantaneous zooming, 1.0 = so slow it never moves
|
|
float ViewSnapSmoothness = 0.02f; // Just the same.
|
|
|
|
float ViewFOV;
|
|
|
|
extern int g_xres, g_yres;
|
|
|
|
void terr_init()
|
|
{
|
|
SViewPort vp;
|
|
vp.m_X=0;
|
|
vp.m_Y=0;
|
|
vp.m_Width=g_xres;
|
|
vp.m_Height=g_yres;
|
|
g_Camera.SetViewPort(&vp);
|
|
|
|
CConfigValue* cfg;
|
|
|
|
#define getViewParameter( name, value ) STMT( \
|
|
cfg = g_ConfigDB.GetValue( CFG_SYSTEM, name );\
|
|
if( cfg ) cfg->GetFloat( value ); )
|
|
|
|
getViewParameter( "view.scroll.speed", ViewScrollSpeed );
|
|
getViewParameter( "view.rotate.speed", ViewRotateSensitivity );
|
|
getViewParameter( "view.rotate.abouttarget.speed", ViewRotateAboutTargetSensitivity );
|
|
getViewParameter( "view.drag.speed", ViewDragSensitivity );
|
|
getViewParameter( "view.zoom.speed", ViewZoomSensitivity );
|
|
getViewParameter( "view.zoom.wheel.speed", ViewZoomSensitivityWheel );
|
|
getViewParameter( "view.zoom.smoothness", ViewZoomSmoothness );
|
|
getViewParameter( "view.snap.smoothness", ViewSnapSmoothness );
|
|
|
|
if( ( ViewZoomSmoothness < 0.0f ) || ( ViewZoomSmoothness > 1.0f ) ) ViewZoomSmoothness = 0.02f;
|
|
if( ( ViewSnapSmoothness < 0.0f ) || ( ViewSnapSmoothness > 1.0f ) ) ViewSnapSmoothness = 0.02f;
|
|
|
|
#undef getViewParameter
|
|
|
|
InitResources ();
|
|
InitScene ();
|
|
}
|
|
|
|
|
|
static void move_camera(float DeltaTime)
|
|
{
|
|
float delta = powf( ViewSnapSmoothness, DeltaTime );
|
|
g_Camera.m_Orientation.Translate( cameraDelta * ( 1.0f - delta ) );
|
|
cameraDelta *= delta;
|
|
|
|
#define CAMERASTYLE 2 // 0 = old style, 1 = relatively new style, 2 = newest style
|
|
|
|
#if CAMERASTYLE == 2
|
|
|
|
// This could be rewritten much more reliably, so it doesn't e.g. accidentally tilt
|
|
// the camera, assuming we know exactly what limits the camera should have.
|
|
|
|
|
|
// Calculate mouse movement
|
|
static int mouse_last_x = 0;
|
|
static int mouse_last_y = 0;
|
|
int mouse_dx = mouse_x - mouse_last_x;
|
|
int mouse_dy = mouse_y - mouse_last_y;
|
|
mouse_last_x = mouse_x;
|
|
mouse_last_y = mouse_y;
|
|
|
|
// Miscellaneous vectors
|
|
CVector3D forwards = g_Camera.m_Orientation.GetIn();
|
|
CVector3D rightwards = g_Camera.m_Orientation.GetLeft() * -1.0f; // upwards.Cross(forwards);
|
|
CVector3D upwards( 0.0f, 1.0f, 0.0f );
|
|
// rightwards.Normalize();
|
|
|
|
CVector3D forwards_horizontal = forwards;
|
|
forwards_horizontal.Y = 0.0f;
|
|
forwards_horizontal.Normalize();
|
|
|
|
/*
|
|
if ((mouseButtons[SDL_BUTTON_MIDDLE] && (keys[SDLK_LCTRL] || keys[SDLK_RCTRL]))
|
|
|| (mouseButtons[SDL_BUTTON_LEFT] && mouseButtons[SDL_BUTTON_RIGHT]) )
|
|
*/
|
|
if( hotkeys[HOTKEY_CAMERA_ROTATE] )
|
|
{
|
|
// Ctrl + middle-drag or left-and-right-drag to rotate view
|
|
|
|
// Untranslate the camera, so it rotates around the correct point
|
|
CVector3D position = g_Camera.m_Orientation.GetTranslation();
|
|
g_Camera.m_Orientation.Translate(position*-1);
|
|
|
|
// Sideways rotation
|
|
g_Camera.m_Orientation.RotateY(ViewRotateSensitivity * (float)(mouse_dx));
|
|
|
|
// Up/down rotation
|
|
CQuaternion temp;
|
|
temp.FromAxisAngle(rightwards, ViewRotateSensitivity * (float)(mouse_dy));
|
|
g_Camera.m_Orientation.Rotate(temp);
|
|
|
|
// Retranslate back to the right position
|
|
g_Camera.m_Orientation.Translate(position);
|
|
|
|
}
|
|
else if( hotkeys[HOTKEY_CAMERA_ROTATE_ABOUT_TARGET] )
|
|
{
|
|
CVector3D origin = g_Camera.m_Orientation.GetTranslation();
|
|
CVector3D delta = origin - cameraPivot;
|
|
|
|
CQuaternion rotateH, rotateV; CMatrix3D rotateM;
|
|
|
|
// Side-to-side rotation
|
|
rotateH.FromAxisAngle( upwards, ViewRotateAboutTargetSensitivity * (float)mouse_dx );
|
|
|
|
// Up-down rotation
|
|
rotateV.FromAxisAngle( rightwards, ViewRotateAboutTargetSensitivity * (float)mouse_dy );
|
|
|
|
rotateH *= rotateV;
|
|
rotateH.ToMatrix( rotateM );
|
|
|
|
delta = rotateM.Rotate( delta );
|
|
|
|
// Lock the inclination to a rather arbitrary values (for the sake of graphical decency)
|
|
|
|
float scan = sqrt( delta.X * delta.X + delta.Z * delta.Z ) / delta.Y;
|
|
if( ( scan >= 0.5f ) )
|
|
{
|
|
// Move the camera to the origin (in preparation for rotation )
|
|
g_Camera.m_Orientation.Translate( origin * -1.0f );
|
|
|
|
g_Camera.m_Orientation.Rotate( rotateH );
|
|
|
|
// Move the camera back to where it belongs
|
|
g_Camera.m_Orientation.Translate( cameraPivot + delta );
|
|
}
|
|
|
|
}
|
|
else if( hotkeys[HOTKEY_CAMERA_PAN] )
|
|
{
|
|
// Middle-drag to pan
|
|
g_Camera.m_Orientation.Translate(rightwards * (ViewDragSensitivity * mouse_dx));
|
|
g_Camera.m_Orientation.Translate(forwards_horizontal * (-ViewDragSensitivity * mouse_dy));
|
|
}
|
|
|
|
// Mouse movement
|
|
|
|
if( !hotkeys[HOTKEY_CAMERA_ROTATE] && !hotkeys[HOTKEY_CAMERA_ROTATE_ABOUT_TARGET] )
|
|
{
|
|
if (mouse_x >= g_xres-2)
|
|
g_Camera.m_Orientation.Translate(rightwards * (ViewScrollSpeed * DeltaTime));
|
|
else if (mouse_x <= 3)
|
|
g_Camera.m_Orientation.Translate(-rightwards * (ViewScrollSpeed * DeltaTime));
|
|
|
|
if (mouse_y >= g_yres-2)
|
|
g_Camera.m_Orientation.Translate(-forwards_horizontal * (ViewScrollSpeed * DeltaTime));
|
|
else if (mouse_y <= 3)
|
|
g_Camera.m_Orientation.Translate(forwards_horizontal * (ViewScrollSpeed * DeltaTime));
|
|
}
|
|
|
|
|
|
// Keyboard movement (added to mouse movement, so you can go faster if you want)
|
|
|
|
if( hotkeys[HOTKEY_CAMERA_PAN_RIGHT] )
|
|
g_Camera.m_Orientation.Translate(rightwards * (ViewScrollSpeed * DeltaTime));
|
|
if( hotkeys[HOTKEY_CAMERA_PAN_LEFT] )
|
|
g_Camera.m_Orientation.Translate(-rightwards * (ViewScrollSpeed * DeltaTime));
|
|
|
|
if( hotkeys[HOTKEY_CAMERA_PAN_BACKWARD] )
|
|
g_Camera.m_Orientation.Translate(-forwards_horizontal * (ViewScrollSpeed * DeltaTime));
|
|
if( hotkeys[HOTKEY_CAMERA_PAN_FORWARD] )
|
|
g_Camera.m_Orientation.Translate(forwards_horizontal * (ViewScrollSpeed * DeltaTime));
|
|
|
|
// Smoothed zooming (move a certain percentage towards the desired zoom distance every frame)
|
|
|
|
static float zoom_delta = 0.0f;
|
|
|
|
if( hotkeys[HOTKEY_CAMERA_ZOOM_WHEEL_IN] )
|
|
zoom_delta += ViewZoomSensitivityWheel;
|
|
else if( hotkeys[HOTKEY_CAMERA_ZOOM_WHEEL_OUT] )
|
|
zoom_delta -= ViewZoomSensitivityWheel;
|
|
|
|
if( hotkeys[HOTKEY_CAMERA_ZOOM_IN] )
|
|
zoom_delta += ViewZoomSensitivity*DeltaTime;
|
|
else if( hotkeys[HOTKEY_CAMERA_ZOOM_OUT] )
|
|
zoom_delta -= ViewZoomSensitivity*DeltaTime;
|
|
|
|
if (zoom_delta)
|
|
{
|
|
float zoom_proportion = powf(ViewZoomSmoothness, DeltaTime);
|
|
g_Camera.m_Orientation.Translate(forwards * (zoom_delta * (1.0f-zoom_proportion)));
|
|
zoom_delta *= zoom_proportion;
|
|
}
|
|
|
|
|
|
#elif CAMERASTYLE == 1
|
|
|
|
// Remember previous mouse position, to calculate changes
|
|
static mouse_last_x = 0;
|
|
static mouse_last_y = 0;
|
|
|
|
// Miscellaneous vectors
|
|
CVector3D forwards = g_Camera.m_Orientation.GetIn();
|
|
CVector3D upwards (0.0f, 1.0f, 0.0f);
|
|
CVector3D rightwards = upwards.Cross(forwards);
|
|
|
|
// Click and drag to look around
|
|
if (mouseButtons[0])
|
|
{
|
|
// Untranslate the camera, so it rotates around the correct point
|
|
CVector3D position = g_Camera.m_Orientation.GetTranslation();
|
|
g_Camera.m_Orientation.Translate(position*-1);
|
|
|
|
// Sideways rotation
|
|
g_Camera.m_Orientation.RotateY(ViewRotateSpeed*(float)(mouse_x-mouse_last_x));
|
|
|
|
// Up/down rotation
|
|
CQuaternion temp;
|
|
temp.FromAxisAngle(rightwards, ViewRotateSpeed*(float)(mouse_y-mouse_last_y));
|
|
g_Camera.m_Orientation.Rotate(temp);
|
|
|
|
// Retranslate back to the right position
|
|
g_Camera.m_Orientation.Translate(position);
|
|
}
|
|
mouse_last_x = mouse_x;
|
|
mouse_last_y = mouse_y;
|
|
|
|
// Calculate the necessary vectors for movement
|
|
|
|
rightwards.Normalize();
|
|
CVector3D forwards_horizontal = upwards.Cross(rightwards);
|
|
forwards_horizontal.Normalize();
|
|
|
|
// Move when desirable
|
|
|
|
if (mouse_x >= g_xres-2)
|
|
g_Camera.m_Orientation.Translate(rightwards);
|
|
else if (mouse_x <= 3)
|
|
g_Camera.m_Orientation.Translate(-rightwards);
|
|
|
|
if (mouse_y >= g_yres-2)
|
|
g_Camera.m_Orientation.Translate(forwards_horizontal);
|
|
else if (mouse_y <= 3)
|
|
g_Camera.m_Orientation.Translate(-forwards_horizontal);
|
|
|
|
// Smoothed height-changing (move a certain percentage towards the desired height every frame)
|
|
|
|
static float height_delta = 0.0f;
|
|
|
|
if (mouseButtons[SDL_BUTTON_WHEELUP])
|
|
height_delta -= 4.0f;
|
|
else if (mouseButtons[SDL_BUTTON_WHEELDOWN])
|
|
height_delta += 4.0f;
|
|
|
|
const float height_speed = 0.2f;
|
|
g_Camera.m_Orientation.Translate(0.0f, height_delta*height_speed, 0.0f);
|
|
height_delta *= (1.0f - height_speed);
|
|
|
|
#else // CAMERASTYLE == 0
|
|
|
|
const float dx = ViewScrollSpeed * DeltaTime;
|
|
const CVector3D Right(dx,0, dx);
|
|
const CVector3D Up (dx,0,-dx);
|
|
|
|
if (mouse_x >= g_xres-2)
|
|
g_Camera.m_Orientation.Translate(Right);
|
|
if (mouse_x <= 3)
|
|
g_Camera.m_Orientation.Translate(Right*-1);
|
|
|
|
if (mouse_y >= g_yres-2)
|
|
g_Camera.m_Orientation.Translate(Up);
|
|
if (mouse_y <= 3)
|
|
g_Camera.m_Orientation.Translate(Up*-1);
|
|
|
|
/*
|
|
janwas: grr, plotted the zoom vector on paper twice, but it appears
|
|
to be completely wrong. sticking with the FOV hack for now.
|
|
if anyone sees what's wrong, or knows how to correctly implement zoom,
|
|
please put this code out of its misery :)
|
|
*/
|
|
// RC - added ScEd style zoom in and out (actually moving camera, rather than fudging fov)
|
|
|
|
float dir=0;
|
|
if (mouseButtons[SDL_BUTTON_WHEELUP]) dir=-1;
|
|
else if (mouseButtons[SDL_BUTTON_WHEELDOWN]) dir=1;
|
|
|
|
float factor=dir*dir;
|
|
if (factor) {
|
|
if (dir<0) factor=-factor;
|
|
CVector3D forward=g_Camera.m_Orientation.GetIn();
|
|
|
|
// check we're not going to zoom into the terrain, or too far out into space
|
|
float h=g_Camera.m_Orientation.GetTranslation().Y+forward.Y*factor*g_CameraZoom;
|
|
float minh=65536*HEIGHT_SCALE*1.05f;
|
|
|
|
if (h<minh || h>1500) {
|
|
// yup, we will; don't move anywhere (do clamped move instead, at some point)
|
|
} else {
|
|
// do a full move
|
|
g_CameraZoom-=(factor)*0.1f;
|
|
if (g_CameraZoom<0.01f) g_CameraZoom=0.01f;
|
|
g_Camera.m_Orientation.Translate(forward*(factor*g_CameraZoom));
|
|
}
|
|
}
|
|
#endif // CAMERASTYLE
|
|
|
|
g_Camera.UpdateFrustum ();
|
|
}
|
|
|
|
|
|
void terr_update(const float DeltaTime)
|
|
{
|
|
if(g_active)
|
|
move_camera(DeltaTime);
|
|
}
|
|
|
|
int terr_handler(const SDL_Event* ev)
|
|
{
|
|
// put any events that must be processed even if inactive here
|
|
|
|
if(!g_active)
|
|
return EV_PASS;
|
|
|
|
switch(ev->type)
|
|
{
|
|
|
|
case SDL_HOTKEYDOWN:
|
|
switch(ev->user.code)
|
|
{
|
|
case HOTKEY_WIREFRAME:
|
|
if (g_Renderer.GetTerrainRenderMode()==WIREFRAME) {
|
|
g_Renderer.SetTerrainRenderMode(SOLID);
|
|
} else {
|
|
g_Renderer.SetTerrainRenderMode(WIREFRAME);
|
|
}
|
|
return( EV_HANDLED );
|
|
|
|
case HOTKEY_CAMERA_RESET:
|
|
// quick hack to return camera home, for screenshots (after alt+tabbing)
|
|
g_Camera.SetProjection (1, 5000, DEGTORAD(20));
|
|
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
|
|
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
|
|
g_Camera.m_Orientation.Translate (100, 150, -100);
|
|
return( EV_HANDLED );
|
|
|
|
case HOTKEY_CAMERA_ROTATE_ABOUT_TARGET:
|
|
{
|
|
int x, z;
|
|
CHFTracer tracer( g_Terrain.GetHeightMap(), g_Terrain.GetVerticesPerSide(), CELL_SIZE, HEIGHT_SCALE );
|
|
CVector3D origin, dir;
|
|
origin = g_Camera.m_Orientation.GetTranslation();
|
|
dir = g_Camera.m_Orientation.GetIn();
|
|
g_Camera.BuildCameraRay( origin, dir );
|
|
|
|
if( !tracer.RayIntersect( origin, dir, x, z, cameraPivot ) )
|
|
cameraPivot = origin - dir * ( origin.Y / dir.Y );
|
|
}
|
|
return( EV_HANDLED );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return EV_PASS;
|
|
}
|
|
|
|
|
|
|
|
|
|
void InitScene ()
|
|
{
|
|
// setup default lighting environment
|
|
g_LightEnv.m_SunColor=RGBColor(1,1,1);
|
|
g_LightEnv.m_Rotation=DEGTORAD(270);
|
|
g_LightEnv.m_Elevation=DEGTORAD(45);
|
|
g_LightEnv.m_TerrainAmbientColor=RGBColor(0,0,0);
|
|
g_LightEnv.m_UnitsAmbientColor=RGBColor(0.4f,0.4f,0.4f);
|
|
g_Renderer.SetLightEnv(&g_LightEnv);
|
|
|
|
// load terrain
|
|
TexInfo ti;
|
|
int err = tex_load("terrain.raw", &ti);
|
|
if(err == 0)
|
|
{
|
|
int w = ti.w, h = ti.h;
|
|
printf("terrain.raw: %dx%d\n", w, h);
|
|
char* p = (char*)mem_get_ptr(ti.hm);
|
|
|
|
u16 *p16=new u16[w*h];
|
|
u16 *p16p=p16;
|
|
while (p16p < p16+(w*h))
|
|
*p16p++ = (*p++) << 8;
|
|
|
|
g_Terrain.Resize(w/PATCH_SIZE);
|
|
g_Terrain.SetHeightMap(p16);
|
|
|
|
delete[] p16;
|
|
|
|
tex_free(&ti);
|
|
}
|
|
|
|
// get default texture to apply to terrain
|
|
CTextureEntry* texture=0;
|
|
for (uint ii=0;ii<g_TexMan.m_TerrainTextures.size();ii++) {
|
|
if (g_TexMan.m_TerrainTextures[ii].m_Textures.size()) {
|
|
texture=g_TexMan.m_TerrainTextures[ii].m_Textures[0];
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
// cover entire terrain with default texture
|
|
u32 patchesPerSide=g_Terrain.GetPatchesPerSide();
|
|
for (uint pj=0; pj<patchesPerSide; pj++) {
|
|
for (uint pi=0; pi<patchesPerSide; pi++) {
|
|
|
|
CPatch* patch=g_Terrain.GetPatch(pi,pj);
|
|
|
|
for (int j=0;j<PATCH_SIZE;j++) {
|
|
for (int i=0;i<PATCH_SIZE;i++) {
|
|
patch->m_MiniPatches[j][i].Tex1=texture ? texture->GetHandle() :0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
g_Camera.SetProjection (1, 5000, DEGTORAD(20));
|
|
g_Camera.m_Orientation.SetXRotation(DEGTORAD(30));
|
|
g_Camera.m_Orientation.RotateY(DEGTORAD(-45));
|
|
|
|
g_Camera.m_Orientation.Translate (100, 150, -100);
|
|
|
|
}
|
|
|
|
void InitResources()
|
|
{
|
|
g_TexMan.LoadTerrainTextures();
|
|
g_ObjMan.LoadObjects();
|
|
|
|
const char* fns[CRenderer::NumAlphaMaps] = {
|
|
"art/textures/terrain/alphamaps/special/blendcircle.png",
|
|
"art/textures/terrain/alphamaps/special/blendlshape.png",
|
|
"art/textures/terrain/alphamaps/special/blendedge.png",
|
|
"art/textures/terrain/alphamaps/special/blendedgecorner.png",
|
|
"art/textures/terrain/alphamaps/special/blendedgetwocorners.png",
|
|
"art/textures/terrain/alphamaps/special/blendfourcorners.png",
|
|
"art/textures/terrain/alphamaps/special/blendtwooppositecorners.png",
|
|
"art/textures/terrain/alphamaps/special/blendlshapecorner.png",
|
|
"art/textures/terrain/alphamaps/special/blendtwocorners.png",
|
|
"art/textures/terrain/alphamaps/special/blendcorner.png",
|
|
"art/textures/terrain/alphamaps/special/blendtwoedges.png",
|
|
"art/textures/terrain/alphamaps/special/blendthreecorners.png",
|
|
"art/textures/terrain/alphamaps/special/blendushape.png",
|
|
"art/textures/terrain/alphamaps/special/blendbad.png"
|
|
};
|
|
|
|
g_Renderer.LoadAlphaMaps(fns);
|
|
}
|
|
|