mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
a4ab78192c
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.
492 lines
13 KiB
C++
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);
|
|
}
|
|
}
|