Descent3/legacy/editor/HView.cpp
JeodC a4ab78192c Join license header with historical commentrs
Join the license header with historical comments using a separator so IDEs can correctly parse the initial header.

Also use .gitattributes to ensure all files are LF.
2024-05-08 14:41:19 -04:00

492 lines
13 KiB
C++

/*
* Descent 3
* Copyright (C) 2024 Parallax Software
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
--- HISTORICAL COMMENTS FOLLOW ---
* $Logfile: /DescentIII/Main/editor/HView.cpp $
* $Revision: 1.1.1.1 $
* $Date: 2003-08-26 03:57:38 $
* $Author: kevinb $
*
* Code to implement view menu functions
*
* $Log: not supported by cvs2svn $
*
* 24 4/30/99 11:18p Matt
* Limit viewer to terrain bounds when moving the viewer to an external
* room.
*
* 23 4/29/99 11:51p Matt
* Improved viewer move functions.
*
* 22 4/17/99 2:42p Matt
* Set Viewer_moved when a new viewer is selected.
*
* 21 2/28/99 8:11p Matt
* Fixed problems when at max viewers
*
* 20 1/15/99 7:52p Chris
* Updated ObjSetPos() to include a f_update_attach_children flag
*
* 19 5/12/98 2:49p Matt
* Link the room viewer to the terrain, since there's not always a room to
* put him in.
*
* 18 3/12/98 7:30p Chris
* Added ObjSetOrient
*
* 17 2/09/98 10:55a Matt
* When searching for rooms to put the viewer in, don't consider external
* rooms.
*
* 16 2/05/98 3:11p Matt
* Don't move the viewer to an external room.
*
* 15 2/05/98 2:57p Matt
* Changed code to use ObjSetPos()
*
* 14 2/04/98 6:23p Matt
* Changed object room number to indicate a terrain cell via a flag. Got
* rid of the object flag which used to indicate terrain.
*
* 13 1/29/98 5:50p Matt
* Changed old camera object type to be viewer object (for editor), and
* now camera objects will just be for game cameras.
*
* 12 1/21/98 1:08p Matt
* Made SetViewMode() not take new_viewer parm, since it's not needed
* after my revamp of the editor view system.
*
* 11 1/21/98 12:33p Matt
* Revamped viewer system
*
* 10 1/19/98 10:04a Matt
* Removed unused function
*
* 9 11/14/97 1:01p Matt
* When can't find camera, don't just make one in the center of room 0.
* Instead, find the first room that's used.
*
* 8 9/17/97 11:51a Samir
* BIG SEGMENT RIPOUT
*
* 7 8/25/97 2:50p Chris
* Improve AABB/object movement code.
*
* 6 8/04/97 7:39p Matt
* Pass new room number to ObjSetPos()
*
* 5 8/04/97 12:43p Matt
* Added SetViewerFromRoomFace()
*
* 4 7/22/97 7:08p Matt
* Cleaned up D3EditState, moving some vars in and some out, and renaming
* and changing a few others
*
* 4 4/01/97 11:00p Matt
* Changed editor to keep a viewer object (type camera) seperate from the
* player object. This camera, and not the player, is now moved by
* slewing, the C key, etc. When going into the game, the viewer position
* & orientation are copied to the player. When going back to the editor,
* the player position is copied to the viewer, and the player object is
* reset to its start location.
*
* 3 3/31/97 5:58p Matt
* Revamped mine update flags
*
* 2 3/17/97 2:26p Matt
* Added function to set player view from curseg/curside
*
* 1 3/17/97 1:47p Matt
*
* $NoKeywords: $
*/
#include "mainfrm.h"
#include "HView.h"
#include "d3edit.h"
#include "terrain.h"
#include "erooms.h"
#include "editor.h"
#define FACE_VIEW_DIST 5.0
//Set the viewer in the specified room facing the specified face
//If room_center is true, put viewer at the center of the room facing the face
//If room_center is false, put the viewer directly in front of the selected face
//If the room is external, put the viewer a distance away from the room,
//facing either the center (if room_center is true) or the specified face
void SetViewerFromRoomFace(room *roomp,int facenum,bool room_center)
{
vector vp,newpos;
matrix orient;
int roomnum;
bool outside_mine = 0;
ComputeCenterPointOnFace(&vp,roomp,facenum);
roomnum = ROOMNUM(roomp);
if (room_center) {
//Get position
ComputeRoomCenter(&newpos,roomp);
if (roomp->flags & RF_EXTERNAL) {
vector t;
float rad = ComputeRoomBoundingSphere(&t,roomp);
newpos.z -= rad * 1.5;
if(newpos.x < 1.0)
newpos.x = 1.0;
if(newpos.x > TERRAIN_WIDTH * TERRAIN_SIZE - 1.0)
newpos.x = TERRAIN_WIDTH * TERRAIN_SIZE - 1.0;
if(newpos.z < 1.0)
newpos.z = 1.0;
if(newpos.z > TERRAIN_DEPTH * TERRAIN_SIZE - 1.0)
newpos.z = TERRAIN_WIDTH * TERRAIN_SIZE - 1.0;
orient = Identity_matrix;
roomnum = GetTerrainRoomFromPos(&newpos);
}
else {
//Get orientation
vp -= newpos; //vector from center of room to face
vm_VectorToMatrix(&orient,&vp,NULL,NULL);
}
}
else {
face *fp = &roomp->faces[facenum];
newpos = vp + fp->normal * FACE_VIEW_DIST;
vector t = -fp->normal;
vm_VectorToMatrix(&orient,&t,NULL,NULL);
if (roomp->flags & RF_EXTERNAL) {
if(newpos.x < 1.0)
newpos.x = 1.0;
if(newpos.x > TERRAIN_WIDTH * TERRAIN_SIZE - 1.0)
newpos.x = TERRAIN_WIDTH * TERRAIN_SIZE - 1.0;
if(newpos.z < 1.0)
newpos.z = 1.0;
if(newpos.z > TERRAIN_DEPTH * TERRAIN_SIZE - 1.0)
newpos.z = TERRAIN_WIDTH * TERRAIN_SIZE - 1.0;
roomnum = GetTerrainRoomFromPos(&newpos);
}
else {
int new_roomnum = FindPointRoom(&newpos);
if (new_roomnum == -1)
outside_mine = 1;
else
roomnum = new_roomnum;
}
}
//Reset viewer
if (Editor_view_mode == VM_ROOM) {
Viewer_object->pos = newpos;
Viewer_object->orient = orient;
}
else
MoveViewer(&newpos,roomnum,&orient);
if (outside_mine)
Viewer_object->flags |= OF_OUTSIDE_MINE;
Viewer_moved = 1;
}
//max viewers for each type
#define MAX_VIEWERS 20
//The viewer in room mode has this ID
#define ROOM_VIEWER_ID MAX_VIEWERS
//Finds a specific viewer object it one exists
//Parameters: id - which viewer id
//Returns: object number of a viewer object, or -1 if none
int FindViewerObject(int id)
{
object *objp;
int objnum=-1;
//trace through all objects looking for viewer
for (objnum=0,objp=Objects;objnum<=Highest_object_index;objnum++,objp++)
if ((objp->type == OBJ_VIEWER) && (objp->id == id))
break;
if (objnum <= Highest_object_index) //found one
return objnum;
else
return -1;
}
//Finds a viewer object if one exists.
//Starts looking at the specified id and searches through all possible ids
//Parameters: id - which viewer id
// view_mode - if -1, find any viewer, else find one that matches view mode
//Returns: object number of a viewer object, or -1 if none
int FindNextViewerObject(int id,int view_mode)
{
int i;
int objnum;
int terrain_flag;
if (id == -1)
id = 0;
ASSERT((id >= 0) && (id <= MAX_VIEWERS));
//Get flags
terrain_flag = (view_mode == VM_TERRAIN);
//Try all viewer id's, starting at the one passed in
for (i=0;i<MAX_VIEWERS;i++) {
int check_id = ((id + i) % MAX_VIEWERS);
objnum = FindViewerObject(check_id);
if ((objnum != -1) && ((view_mode == -1) || ((OBJECT_OUTSIDE(&Objects[objnum]) != 0) == terrain_flag)))
break;
}
if (i == MAX_VIEWERS) //didn't find one
return -1;
return objnum;
}
//Creates a viewer object of the specified type
//Parameters: view_mode - mine,terrain,or room. See constants in 3dedit.h
// pos - initial position of this object
// roomnum - initial room/terrain cell of this object
//Returns: object number of the object created, or -1 if at max number of viewers of that type
int CreateViewerObject(int view_mode,vector *pos,int roomnum)
{
int id;
object *objp;
int objnum=-1;
if (view_mode == VM_ROOM) {
id = ROOM_VIEWER_ID;
for (objnum=0,objp=Objects;objnum<=Highest_object_index;objnum++,objp++)
if ((objp->type == OBJ_VIEWER) && (objp->id == id))
return -1; //this one already used
}
else {
//for each id, loop through all objects to see if it's used
for (id=0;id<MAX_VIEWERS;id++) {
for (objnum=0,objp=Objects;objnum<=Highest_object_index;objnum++,objp++)
if ((objp->type == OBJ_VIEWER) && (objp->id == id))
break; //this one already used
if (objnum > Highest_object_index) //didn't find objec twith this id
break;
}
if (id == MAX_VIEWERS) //no unused viewer id's
return -1;
}
//Create the new object
objnum = ObjCreate(OBJ_VIEWER,id,roomnum,pos,NULL);
if (objnum == -1) {
Int3();
return -1;
}
return objnum;
}
//Returns the number (not the id) of the current viewer, in the range 0..MAX_VIEWERS
int GetViewerNum()
{
ASSERT(Editor_view_mode != VM_ROOM);
return Viewer_object->id;
}
//Set the specified object to be the viewer
void SetViewer(int objnum)
{
Viewer_object = &Objects[objnum];
if (Editor_view_mode != VM_ROOM)
Editor_viewer_id = Viewer_object->id;
if ((Editor_view_mode == VM_MINE) && OBJECT_OUTSIDE(Viewer_object))
SetViewMode(VM_TERRAIN);
if ((Editor_view_mode == VM_TERRAIN) && !(OBJECT_OUTSIDE(Viewer_object)))
SetViewMode(VM_MINE);
State_changed = Viewer_moved = 1;
}
//Creates a new viewer object. Copies position & orientation from the current viewer
void CreateNewViewer()
{
int objnum;
objnum = CreateViewerObject(Editor_view_mode,&Viewer_object->pos,Viewer_object->roomnum);
if (objnum == -1) {
OutrageMessageBox("Cannot create new viewer: you already have the maximum number of viewers.");
return;
}
ObjSetOrient(&Objects[objnum], &Viewer_object->orient);
SetViewer(objnum);
EditorStatus("Viewer %d created.",GetViewerNum());
World_changed = 1;
}
//Select next viewer
void SelectNextViewer()
{
int objnum;
if (Editor_view_mode == VM_ROOM) {
EditorStatus("There is only one viewer in Room View");
return;
}
ASSERT(Viewer_object != NULL);
objnum = FindNextViewerObject(Viewer_object->id + 1,-1);
ASSERT(objnum != -1);
if (objnum == OBJNUM(Viewer_object)) {
EditorStatus("No other viewers.");
return;
}
SetViewer(objnum);
EditorStatus("Viewer %d selected.",GetViewerNum());
}
//Deletes the current viewer object
void DeleteViewer()
{
int objnum,old_num;
if (Viewer_object->id == ROOM_VIEWER_ID) {
OutrageMessageBox("You cannot delete the Room viewer.");
return;
}
objnum = FindNextViewerObject(Viewer_object->id + 1,-1);
ASSERT(objnum != -1);
if (objnum == OBJNUM(Viewer_object)) { //couldn't find another viewer
OutrageMessageBox("You cannot delete your only viewer.");
return;
}
old_num = GetViewerNum();
//Kill the old viewer
ObjDelete(OBJNUM(Viewer_object));
//Set the new viewer
SetViewer(objnum);
EditorStatus("Viewer %d deleted. Viewer %d selected.",old_num,GetViewerNum());
World_changed = 1;
}
//Sets the viewer object for the editor, creating if not already in mine
//Keeps seperate viewer objects for mine & terrain views
void SetEditorViewer()
{
int objnum,roomnum;
//First, see if a camera object already exists in the level
if (Editor_view_mode == VM_ROOM)
objnum = FindViewerObject(ROOM_VIEWER_ID);
else
objnum = FindNextViewerObject(Editor_viewer_id,Editor_view_mode);
//If no viewer object, create one
if (objnum == -1) {
vector pos;
//get position for viewer
if (Editor_view_mode == VM_TERRAIN) { //if terrain, put viewer at center of world
pos.x = TERRAIN_SIZE * TERRAIN_WIDTH/2;
pos.y = Terrain_seg[0].y+30;
pos.z = TERRAIN_SIZE*TERRAIN_DEPTH/2;
roomnum = MAKE_ROOMNUM(0); //any value ok, so long as it has terrain flag
}
else if (Editor_view_mode == VM_MINE) { //if mine, put in center of any room
for (roomnum=0;roomnum<=Highest_room_index;roomnum++)
if (Rooms[roomnum].used && !(Rooms[roomnum].flags & RF_EXTERNAL)) {
ComputeRoomCenter(&pos,&Rooms[roomnum]);
break;
}
ASSERT(roomnum <= Highest_room_index);
}
else if (Editor_view_mode == VM_ROOM) { //if room, put at 0,0,0
vm_MakeZero(&pos);
roomnum = MAKE_ROOMNUM(0);
}
else
Int3(); //unknown view mode
objnum = CreateViewerObject(Editor_view_mode,&pos,roomnum);
//If no free viewer slots, grab any viewer and move it
if (objnum == -1) {
ASSERT(Viewer_object != NULL);
if (Viewer_object->type == OBJ_VIEWER)
objnum = OBJNUM(Viewer_object);
else {
objnum = FindNextViewerObject(Editor_viewer_id,-1);
ASSERT(objnum != -1);
}
ObjSetPos(&Objects[objnum],&pos,roomnum,NULL,true);
}
}
ASSERT(objnum != -1);
SetViewer(objnum);
}
//Moves the room viewer to the origin, if there is a room viewer
void ResetRoomViewer()
{
int objnum = FindViewerObject(ROOM_VIEWER_ID);
if (objnum != -1) {
vm_MakeZero(&Objects[objnum].pos);
ObjSetOrient(&Objects[objnum], &Identity_matrix);
}
}