quakeforge/tools/Forge/Bundles/MapEdit/CameraView.m
Bill Currie 931900fbd3 Pass .m files through indent.
The result isn't perfect, but it cleans up the whitespace and makes the
code more consistent with the rest of the project.
2010-09-26 13:50:17 +09:00

955 lines
17 KiB
Objective-C

#include "QF/sys.h"
#include "CameraView.h"
#include "Map.h"
#include "QuakeEd.h"
#include "XYView.h"
#include "ZView.h"
id cameraview_i;
extern NSBezierPath *path;
BOOL timedrawing = 0;
@implementation CameraView
/*
==================
initWithFrame:
==================
*/
- initWithFrame:(NSRect)frameRect
{
int size;
[super initWithFrame: frameRect];
cameraview_i = self;
xa = ya = za = 0;
[self matrixFromAngles];
origin[0] = 64;
origin[1] = 64;
origin[2] = 48;
move = 16;
size = _bounds.size.width * _bounds.size.height;
zbuffer = malloc (size * 4);
imagebuffer = malloc (size * 4);
return self;
}
-setXYOrigin:(NSPoint *)pt
{
origin[0] = pt->x;
origin[1] = pt->y;
return self;
}
-setZOrigin:(float)pt
{
origin[2] = pt;
return self;
}
-setOrigin:(vec3_t)org angle:(float)angle
{
VectorCopy (org, origin);
ya = angle;
[self matrixFromAngles];
return self;
}
-getOrigin:(vec3_t)org
{
VectorCopy (origin, org);
return self;
}
-(float)yawAngle
{
return ya;
}
-upFloor:sender
{
sb_floor_dir = 1;
sb_floor_dist = 99999;
[map_i makeAllPerform: @selector (feetToFloor)];
if (sb_floor_dist == 99999) {
Sys_Printf ("already on top floor");
return self;
}
Sys_Printf ("up floor");
origin[2] += sb_floor_dist;
[quakeed_i updateCamera];
return self;
}
-downFloor:sender
{
sb_floor_dir = -1;
sb_floor_dist = -99999;
[map_i makeAllPerform: @selector (feetToFloor)];
if (sb_floor_dist == -99999) {
Sys_Printf ("already on bottom floor");
return self;
}
Sys_Printf ("down floor");
origin[2] += sb_floor_dist;
[quakeed_i updateCamera];
return self;
}
/*
===============================================================================
UI TARGETS
===============================================================================
*/
/*
============
homeView
============
*/
-homeView:sender
{
xa = za = 0;
[self matrixFromAngles];
[quakeed_i updateAll];
Sys_Printf ("homed view angle");
return self;
}
-drawMode:sender
{
drawmode =[sender selectedColumn];
[quakeed_i updateCamera];
return self;
}
-setDrawMode:(drawmode_t)mode
{
drawmode = mode;
[mode_radio_i selectCellAtRow: 0 column: mode];
[quakeed_i updateCamera];
return self;
}
/*
===============================================================================
TRANSFORMATION METHODS
===============================================================================
*/
-matrixFromAngles
{
if (xa > M_PI * 0.4)
xa = M_PI * 0.4;
if (xa < -M_PI * 0.4)
xa = -M_PI * 0.4;
// vpn
matrix[2][0] = cos (xa) * cos (ya);
matrix[2][1] = cos (xa) * sin (ya);
matrix[2][2] = sin (xa);
// vup
matrix[1][0] = cos (xa + M_PI / 2) * cos (ya);
matrix[1][1] = cos (xa + M_PI / 2) * sin (ya);
matrix[1][2] = sin (xa + M_PI / 2);
// vright
CrossProduct (matrix[2], matrix[1], matrix[0]);
return self;
}
-inverseTransform:(vec_t *)invec to:(vec_t *)outvec
{
vec3_t inverse[3];
vec3_t temp;
int i, j;
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
inverse[i][j] = matrix[j][i];
temp[0] = DotProduct (invec, inverse[0]);
temp[1] = DotProduct (invec, inverse[1]);
temp[2] = DotProduct (invec, inverse[2]);
VectorAdd (temp, origin, outvec);
return self;
}
/*
===============================================================================
DRAWING METHODS
===============================================================================
*/
typedef struct {
vec3_t trans;
int clipflags;
vec3_t screen; // valid only if clipflags == 0
} campt_t;
#define CLIP_RIGHT 1
#define CLIP_LEFT 2
#define CLIP_TOP 4
#define CLIP_BOTTOM 8
#define CLIP_FRONT 16
int cam_cur;
campt_t campts[2];
vec3_t r_matrix[3];
vec3_t r_origin;
float mid_x, mid_y;
float topscale = (240.0 / 3) / 160;
float bottomscale = (240.0 * 2 / 3) / 160;
extern plane_t rfrustum[5];
void
MakeCampt (vec3_t in, campt_t * pt)
{
vec3_t temp;
float scale;
// transform the points
VectorSubtract (in, r_origin, temp);
pt->trans[0] = DotProduct (temp, r_matrix[0]);
pt->trans[1] = DotProduct (temp, r_matrix[1]);
pt->trans[2] = DotProduct (temp, r_matrix[2]);
// check clip flags
if (pt->trans[2] < 1)
pt->clipflags = CLIP_FRONT;
else
pt->clipflags = 0;
if (pt->trans[0] > pt->trans[2])
pt->clipflags |= CLIP_RIGHT;
else if (-pt->trans[0] > pt->trans[2])
pt->clipflags |= CLIP_LEFT;
if (pt->trans[1] > pt->trans[2] * topscale)
pt->clipflags |= CLIP_TOP;
else if (-pt->trans[1] > pt->trans[2] * bottomscale)
pt->clipflags |= CLIP_BOTTOM;
if (pt->clipflags)
return;
// project
scale = mid_x / pt->trans[2];
pt->screen[0] = mid_x + pt->trans[0] * scale;
pt->screen[1] = mid_y + pt->trans[1] * scale;
}
void
CameraMoveto (vec3_t p)
{
campt_t *pt;
if ([path elementCount] > 2048)
lineflush ();
pt = &campts[cam_cur];
cam_cur ^= 1;
MakeCampt (p, pt);
if (!pt->clipflags) {
// onscreen, so move there immediately
NSPoint point = { pt->screen[0], pt->screen[1] };
[path moveToPoint: point];
}
}
void
ClipLine (vec3_t p1, vec3_t p2, int planenum)
{
float d, d2, frac;
vec3_t new;
plane_t *pl;
float scale;
NSPoint point;
if (planenum == 5) {
// draw it!
scale = mid_x / p1[2];
point.x = mid_x + p1[0] * scale;
point.y = mid_y + p1[1] * scale;
[path moveToPoint: point];
scale = mid_x / p2[2];
point.x = mid_x + p2[0] * scale;
point.y = mid_y + p2[1] * scale;
[path lineToPoint: point];
return;
}
pl = &rfrustum[planenum];
d = DotProduct (p1, pl->normal) - pl->dist;
d2 = DotProduct (p2, pl->normal) - pl->dist;
if (d <= ON_EPSILON && d2 <= ON_EPSILON) { // off screen
return;
}
if (d >= 0 && d2 >= 0) { // on front
ClipLine (p1, p2, planenum + 1);
return;
}
frac = d / (d - d2);
new[0] = p1[0] + frac * (p2[0] - p1[0]);
new[1] = p1[1] + frac * (p2[1] - p1[1]);
new[2] = p1[2] + frac * (p2[2] - p1[2]);
if (d > 0)
ClipLine (p1, new, planenum + 1);
else
ClipLine (new, p2, planenum + 1);
}
int c_off, c_on, c_clip;
void
CameraLineto (vec3_t p)
{
campt_t *p1, *p2;
int bits;
p2 = &campts[cam_cur];
cam_cur ^= 1;
p1 = &campts[cam_cur];
MakeCampt (p, p2);
if (p1->clipflags & p2->clipflags) {
c_off++;
return; // entirely off screen
}
bits = p1->clipflags | p2->clipflags;
if (!bits) {
NSPoint point1 = { p1->screen[0], p1->screen[1] };
NSPoint point2 = { p2->screen[0], p2->screen[1] };
c_on++;
[path moveToPoint: point1];
[path lineToPoint: point2];
return; // entirely on screen
}
// needs to be clipped
c_clip++;
ClipLine (p1->trans, p2->trans, 0);
}
/*
=============
drawSolid
=============
*/
-drawSolid
{
unsigned char *planes[5];
//
// draw it
//
VectorCopy (origin, r_origin);
VectorCopy (matrix[0], r_matrix[0]);
VectorCopy (matrix[1], r_matrix[1]);
VectorCopy (matrix[2], r_matrix[2]);
r_width = _bounds.size.width;
r_height = _bounds.size.height;
r_picbuffer = imagebuffer;
r_zbuffer = zbuffer;
r_drawflat = (drawmode == dr_flat);
REN_BeginCamera ();
REN_ClearBuffers ();
//
// render the setbrushes
//
[map_i makeAllPerform: @selector (CameraRenderSelf)];
//
// display the output
//
[[self window] setBackingType: NSBackingStoreRetained];
planes[0] = (unsigned char *) imagebuffer;
NSDrawBitmap (_bounds, r_width, r_height, 8, 3, 32, r_width * 4, NO, NO, @"RGB", // FIXME
// what
// should
// this
// be?
(const unsigned char **const) planes);
// XXX NSPing ();
[[self window] setBackingType: NSBackingStoreBuffered];
return self;
}
/*
===================
drawWire
===================
*/
-drawWire:(NSRect)rect
{
// copy current info to globals for the C callbacks
mid_x = _bounds.size.width / 2;
mid_y = 2 * _bounds.size.height / 3;
VectorCopy (origin, r_origin);
VectorCopy (matrix[0], r_matrix[0]);
VectorCopy (matrix[1], r_matrix[1]);
VectorCopy (matrix[2], r_matrix[2]);
r_width = _bounds.size.width;
r_height = _bounds.size.height;
r_picbuffer = imagebuffer;
r_zbuffer = zbuffer;
REN_BeginCamera ();
// erase window
NSEraseRect (rect);
// draw all entities
linestart (0, 0, 0);
[map_i makeUnselectedPerform: @selector (CameraDrawSelf)];
lineflush ();
return self;
}
/*
===================
drawSelf
===================
*/
-drawSelf:(NSRect)rects :(int)rectCount
{
float drawtime = 0;
if (timedrawing)
drawtime = Sys_DoubleTime ();
if (drawmode == dr_texture || drawmode == dr_flat)
[self drawSolid];
else
[self drawWire: rects];
if (timedrawing) {
// XXX NSPing ();
drawtime = Sys_DoubleTime () - drawtime;
printf ("CameraView drawtime: %5.3f\n", drawtime);
}
return self;
}
/*
=============
XYDrawSelf
=============
*/
-XYDrawSelf
{
PSsetrgbcolor (0, 0, 1.0);
PSsetlinewidth (0.15);
PSmoveto (origin[0] - 16, origin[1]);
PSrlineto (16, 8);
PSrlineto (16, -8);
PSrlineto (-16, -8);
PSrlineto (-16, 8);
PSrlineto (32, 0);
PSmoveto (origin[0], origin[1]);
PSrlineto (64 * cos (ya + M_PI / 4), 64 * sin (ya + M_PI / 4));
PSmoveto (origin[0], origin[1]);
PSrlineto (64 * cos (ya - M_PI / 4), 64 * sin (ya - M_PI / 4));
PSstroke ();
return self;
}
/*
=============
ZDrawSelf
=============
*/
-ZDrawSelf
{
PSsetrgbcolor (0, 0, 1.0);
PSsetlinewidth (0.15);
PSmoveto (-16, origin[2]);
PSrlineto (16, 8);
PSrlineto (16, -8);
PSrlineto (-16, -8);
PSrlineto (-16, 8);
PSrlineto (32, 0);
PSmoveto (-15, origin[2] - 47);
PSrlineto (29, 0);
PSrlineto (0, 54);
PSrlineto (-29, 0);
PSrlineto (0, -54);
PSstroke ();
return self;
}
/*
===============================================================================
XYZ mouse view methods
===============================================================================
*/
/*
================
modalMoveLoop
================
*/
-modalMoveLoop:(NSPoint *)basept :(vec3_t)movemod :converter
{
vec3_t originbase;
NSEvent *event = 0; // XXX
NSPoint newpt;
// NSPoint brushpt;
vec3_t delta;
// id ent;
int i;
// vec3_t temp;
Sys_Printf ("moving camera position");
VectorCopy (origin, originbase);
//
// modal event loop using instance drawing
//
goto drawentry;
while ([event type] != NSLeftMouseUp &&[event type] != NSRightMouseUp) {
//
// calculate new point
//
newpt =[event locationInWindow];
newpt =[converter convertPoint: newpt fromView: NULL];
delta[0] = newpt.x - basept->x;
delta[1] = newpt.y - basept->y;
delta[2] = delta[1]; // height change
for (i = 0; i < 3; i++)
origin[i] = originbase[i] + movemod[i] * delta[i];
#if 0 // FIXME
//
// if command is down, look towards brush or entity
//
if (event->flags & NS_SHIFTMASK) {
ent =[quakemap_i selectedEntity];
if (ent) {
[ent origin: temp];
brushpt.x = temp[0];
brushpt.y = temp[1];
} else
brushpt =[brush_i centerPoint];
ya = atan2 (brushpt.y - newpt.y, brushpt.x - newpt.x);
[self matrixFromAngles];
}
#endif
drawentry:
//
// instance draw new frame
//
[quakeed_i newinstance];
[self display];
event = [NSApp nextEventMatchingMask: NSLeftMouseUpMask
| NSLeftMouseDraggedMask | NSRightMouseUpMask
| NSRightMouseDraggedMask | NSApplicationDefinedMask
untilDate: [NSDate distantFuture]
inMode: NSEventTrackingRunLoopMode dequeue: YES];
if ([event type] == NSKeyDown) {
[self _keyDown: event];
[self display];
goto drawentry;
}
}
return self;
}
//============================================================================
/*
===============
XYmouseDown
===============
*/
-(BOOL) XYmouseDown:(NSPoint *)pt flags:(int)flags
// return YES if brush handled
{
vec3_t movemod;
if (fabs (pt->x - origin[0]) > 16 || fabs (pt->y - origin[1]) > 16)
return NO;
#if 0
if (flags & NSAlternateKeyMask) { // up / down drag
movemod[0] = 0;
movemod[1] = 0;
movemod[2] = 1;
} else
#endif
{
movemod[0] = 1;
movemod[1] = 1;
movemod[2] = 0;
}
[self modalMoveLoop: pt : movemod : xyview_i];
return YES;
}
/*
===============
ZmouseDown
===============
*/
-(BOOL) ZmouseDown:(NSPoint *)pt flags:(int)flags
// return YES if brush handled
{
vec3_t movemod;
if (fabs (pt->y - origin[2]) > 16 || pt->x < -8 || pt->x > 8)
return NO;
movemod[0] = 0;
movemod[1] = 0;
movemod[2] = 1;
[self modalMoveLoop: pt : movemod : zview_i];
return YES;
}
//=============================================================================
/*
===================
viewDrag:
===================
*/
-viewDrag:(NSPoint *)pt
{
float dx, dy;
NSEvent *event = 0; // XXX
NSPoint newpt;
//
// modal event loop using instance drawing
//
goto drawentry;
while ([event type] != NSRightMouseUp) {
//
// calculate new point
//
newpt =[event locationInWindow];
newpt =[self convertPoint: newpt fromView: NULL];
dx = newpt.x - pt->x;
dy = newpt.y - pt->y;
*pt = newpt;
ya -= dx / _bounds.size.width * M_PI / 2 * 4;
xa += dy / _bounds.size.width * M_PI / 2 * 4;
[self matrixFromAngles];
drawentry:
[quakeed_i newinstance];
[self display];
event = [NSApp nextEventMatchingMask: NSRightMouseUpMask
| NSRightMouseDraggedMask
untilDate: [NSDate distantFuture]
inMode: NSEventTrackingRunLoopMode dequeue: YES];
if ([event type] == NSKeyDown) {
[self _keyDown:event];
[self display];
goto drawentry;
}
}
return self;
}
//=============================================================================
/*
===================
mouseDown
===================
*/
-(void) mouseDown:(NSEvent *)theEvent
{
NSPoint pt;
int i;
vec3_t p1, p2;
float forward, right, up;
int flags;
pt =[theEvent locationInWindow];
pt =[self convertPoint: pt fromView: NULL];
VectorCopy (origin, p1);
forward = 160;
right = pt.x - 160;
up = pt.y - 240 * 2 / 3;
for (i = 0; i < 3; i++)
p2[i] =
forward * matrix[2][i] + up * matrix[1][i] + right * matrix[0][i];
for (i = 0; i < 3; i++)
p2[i] = p1[i] + 100 * p2[i];
flags =
[theEvent modifierFlags] & (NSShiftKeyMask | NSControlKeyMask |
NSAlternateKeyMask | NSCommandKeyMask);
//
// bare click to select a texture
//
if (flags == 0) {
[map_i getTextureRay: p1 : p2];
return;
}
//
// shift click to select / deselect a brush from the world
//
if (flags == NSShiftKeyMask) {
[map_i selectRay: p1 : p2 : NO];
return;
}
//
// cmd-shift click to set a target/targetname entity connection
//
if (flags == (NSShiftKeyMask | NSCommandKeyMask)) {
[map_i entityConnect: p1 : p2];
return;
}
//
// alt click = set entire brush texture
//
if (flags == NSAlternateKeyMask) {
if (drawmode != dr_texture) {
Sys_Printf ("No texture setting except in texture mode!\n");
NopSound ();
return;
}
[map_i setTextureRay: p1 : p2 : YES];
[quakeed_i updateAll];
return;
}
//
// ctrl-alt click = set single face texture
//
if (flags == (NSControlKeyMask | NSAlternateKeyMask)) {
if (drawmode != dr_texture) {
Sys_Printf ("No texture setting except in texture mode!\n");
NopSound ();
return;
}
[map_i setTextureRay: p1 : p2 : NO];
[quakeed_i updateAll];
return;
}
Sys_Printf ("bad flags for click");
NopSound ();
return;
}
/*
===================
rightMouseDown
===================
*/
-(void) rightMouseDown:(NSEvent *)theEvent
{
NSPoint pt;
int flags;
pt =[theEvent locationInWindow];
[self convertPoint: pt fromView: NULL];
flags =
[theEvent modifierFlags] & (NSShiftKeyMask | NSControlKeyMask |
NSAlternateKeyMask | NSCommandKeyMask);
//
// click = drag camera
//
if (flags == 0) {
Sys_Printf ("looking");
[self viewDrag: &pt];
Sys_Printf ("%s", "");
return;
}
Sys_Printf ("bad flags for click");
NopSound ();
return;
}
/*
===============
keyDown
===============
*/
#define KEY_RIGHTARROW 0xae
#define KEY_LEFTARROW 0xac
#define KEY_UPARROW 0xad
#define KEY_DOWNARROW 0xaf
-_keyDown:(NSEvent *)theEvent
{
int ch;
ch = tolower ([[theEvent characters] characterAtIndex: 0]);
switch (ch) {
case 13:
return self;
case 'a':
case 'A':
xa += M_PI / 8;
[self matrixFromAngles];
[quakeed_i updateCamera];
return self;
case 'z':
case 'Z':
xa -= M_PI / 8;
[self matrixFromAngles];
[quakeed_i updateCamera];
return self;
case KEY_RIGHTARROW:
ya -= M_PI * move / (64 * 2);
[self matrixFromAngles];
[quakeed_i updateCamera];
break;
case KEY_LEFTARROW:
ya += M_PI * move / (64 * 2);
[self matrixFromAngles];
[quakeed_i updateCamera];
break;
case KEY_UPARROW:
origin[0] += move * cos (ya);
origin[1] += move * sin (ya);
[quakeed_i updateCamera];
break;
case KEY_DOWNARROW:
origin[0] -= move * cos (ya);
origin[1] -= move * sin (ya);
[quakeed_i updateCamera];
break;
case '.':
origin[0] += move * cos (ya - M_PI_2);
origin[1] += move * sin (ya - M_PI_2);
[quakeed_i updateCamera];
break;
case ',':
origin[0] -= move * cos (ya - M_PI_2);
origin[1] -= move * sin (ya - M_PI_2);
[quakeed_i updateCamera];
break;
case 'd':
case 'D':
origin[2] += move;
[quakeed_i updateCamera];
break;
case 'c':
case 'C':
origin[2] -= move;
[quakeed_i updateCamera];
break;
}
return self;
}
@end