my WIP on porting QuakeEd to GNUstep/QuakeForge

This commit is contained in:
Bill Currie 2003-03-18 19:48:24 +00:00
parent 3423ed59d5
commit 48a5ad0d36
58 changed files with 27068 additions and 0 deletions

View file

@ -0,0 +1,55 @@
#import <AppKit/AppKit.h>
#import "SetBrush.h"
#import "EditWindow.h"
extern id brush_i;
extern BOOL brushdraw; // YES when drawing cutbrushes and ents
@interface Brush : SetBrush
{
id cutbrushes_i;
id cutentities_i;
boolean updatemask[MAXBRUSHVERTEX];
BOOL dontdraw; // for modal instance loops
BOOL deleted; // when not visible at all
}
- init;
- initFromSetBrush: br;
- deselect;
- (BOOL)isSelected;
- (BOOL)XYmouseDown: (NSPoint *)pt; // return YES if brush handled
- (BOOL)ZmouseDown: (NSPoint *)pt; // return YES if brush handled
- _keyDown:(NSEvent *)theEvent;
- (NSPoint)centerPoint; // for camera flyby mode
- InstanceSize;
- XYDrawSelf;
- ZDrawSelf;
- CameraDrawSelf;
- flipHorizontal: sender;
- flipVertical: sender;
- rotate90: sender;
- makeTall: sender;
- makeShort: sender;
- makeWide: sender;
- makeNarrow: sender;
- placeEntity: sender;
- cut: sender;
- copy: sender;
- addBrush;
@end

View file

@ -0,0 +1,61 @@
#import <AppKit/AppKit.h>
#import "mathlib.h"
#import "SetBrush.h"
extern id cameraview_i;
extern byte renderlist[1024*1024*4];
void CameraMoveto(vec3_t p);
void CameraLineto(vec3_t p);
extern BOOL timedrawing;
@interface CameraView : NSView
{
float xa, ya, za;
float move;
float *zbuffer;
unsigned *imagebuffer;
BOOL angleChange; // JR 6.8.95
vec3_t origin;
vec3_t matrix[3];
NSPoint dragspot;
drawmode_t drawmode;
// UI links
id mode_radio_i;
}
- setXYOrigin: (NSPoint *)pt;
- setZOrigin: (float)pt;
- setOrigin: (vec3_t)org angle: (float)angle;
- getOrigin: (vec3_t)org;
- (float)yawAngle;
- matrixFromAngles;
- _keyDown: (NSEvent *)theEvent;
- drawMode: sender;
- setDrawMode: (drawmode_t)mode;
- homeView: sender;
- XYDrawSelf; // for drawing viewpoint in XY view
- ZDrawSelf; // for drawing viewpoint in XY view
- (BOOL)XYmouseDown: (NSPoint *)pt flags:(int)flags; // return YES if brush handled
- (BOOL)ZmouseDown: (NSPoint *)pt flags:(int)flags; // return YES if brush handled
- upFloor:sender;
- downFloor: sender;
@end

View file

@ -0,0 +1,971 @@
#import "qedefs.h"
id cameraview_i;
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)
{
qprintf ("already on top floor");
return self;
}
qprintf ("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)
{
qprintf ("already on bottom floor");
return self;
}
qprintf ("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];
qprintf ("homed view angle");
return self;
}
- drawMode: sender
{
drawmode = [sender selectedColumn];
[quakeed_i updateCamera];
return self;
}
- setDrawMode: (drawmode_t)mode
{
drawmode = mode;
//XXX[mode_radio_i selectCellAt:0: 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; // only valid 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 frustum[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 (upath->numberOfPoints > 2048)
lineflush ();
pt = &campts[cam_cur];
cam_cur ^= 1;
MakeCampt (p,pt);
if (!pt->clipflags)
{ // onscreen, so move there immediately
UPmoveto (upath, pt->screen[0], pt->screen[1]);
}
}
void ClipLine (vec3_t p1, vec3_t p2, int planenum)
{
float d, d2, frac;
vec3_t new;
plane_t *pl;
float scale;
if (planenum == 5)
{ // draw it!
scale = mid_x/p1[2];
new[0] = mid_x + p1[0]*scale;
new[1] = mid_y + p1[1]*scale;
UPmoveto (upath, new[0], new[1]);
scale = mid_x/p2[2];
new[0] = mid_x + p2[0]*scale;
new[1] = mid_y + p2[1]*scale;
UPlineto (upath, new[0], new[1]);
return;
}
pl = &frustum[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 )
{
c_on++;
UPmoveto (upath, p1->screen[0], p1->screen[1]);
UPlineto (upath, p2->screen[0], p2->screen[1]);
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
{
static float drawtime; // static to shut up compiler warning
if (timedrawing)
drawtime = I_FloatTime ();
if (drawmode == dr_texture || drawmode == dr_flat)
[self drawSolid];
else
[self drawWire: rects];
if (timedrawing)
{
//XXX NSPing ();
drawtime = I_FloatTime() - 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;
qprintf ("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];
/*XXX
event = [NSApp nextEventMatchingMask: NSLeftMouseUpMask
| NSLeftMouseDraggedMask | NSRightMouseUpMask
| NSRightMouseDraggedMask | NSApplicationDefinedMask];
*/
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];
/*XXX
event = [NSApp getNextEvent:
NSKeyDownMask | NSRightMouseUpMask | NSRightMouseDraggedMask];
*/
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)
{
qprintf ("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)
{
qprintf ("No texture setting except in texture mode!\n");
NopSound ();
return;
}
[map_i setTextureRay: p1 : p2 : NO];
[quakeed_i updateAll];
return;
}
qprintf ("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)
{
qprintf ("looking");
[self viewDrag: &pt];
qprintf ("");
return;
}
qprintf ("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

View file

@ -0,0 +1,24 @@
extern id clipper_i;
@interface Clipper : Object
{
int num;
vec3_t pos[3];
plane_t plane;
}
- (BOOL)hide;
- XYClick: (NSPoint)pt;
- (BOOL)XYDrag: (NSPoint *)pt;
- ZClick: (NSPoint)pt;
- carve;
- flipNormal;
- (BOOL)getFace: (face_t *)pl;
- cameraDrawSelf;
- XYDrawSelf;
- ZDrawSelf;
@end

View file

@ -0,0 +1,230 @@
#include "qedefs.h"
#import <AppKit/NSGraphics.h>
#import <AppKit/DPSOperators.h>
id clipper_i;
@implementation Clipper
- init
{
[super init];
clipper_i = self;
return self;
}
- (BOOL)hide
{
int oldnum;
oldnum = num;
num = 0;
return (oldnum > 0);
}
- flipNormal
{
vec3_t temp;
if (num == 2)
{
VectorCopy (pos[0], temp);
VectorCopy (pos[1], pos[0]);
VectorCopy (temp, pos[1]);
}
else if (num == 3)
{
VectorCopy (pos[0], temp);
VectorCopy (pos[2], pos[0]);
VectorCopy (temp, pos[2]);
}
else
{
qprintf ("no clipplane");
NSBeep ();
}
return self;
}
- (BOOL)getFace: (face_t *)f
{
vec3_t v1, v2, norm;
int i;
VectorCopy (vec3_origin, plane.normal);
plane.dist = 0;
if (num < 2)
return NO;
if (num == 2)
{
VectorCopy (pos[0], pos[2]);
pos[2][2] += 16;
}
for (i=0 ; i<3 ; i++)
VectorCopy (pos[i], f->planepts[i]);
VectorSubtract (pos[2], pos[0], v1);
VectorSubtract (pos[1], pos[0], v2);
CrossProduct (v1, v2, norm);
VectorNormalize (norm);
if ( !norm[0] && !norm[1] && !norm[2] )
return NO;
[texturepalette_i getTextureDef: &f->texture];
return YES;
}
/*
================
XYClick
================
*/
- XYClick: (NSPoint)pt
{
int i;
vec3_t new;
new[0] = [xyview_i snapToGrid: pt.x];
new[1] = [xyview_i snapToGrid: pt.y];
new[2] = [map_i currentMinZ];
// see if a point is allready there
for (i=0 ; i<num ; i++)
{
if (new[0] == pos[i][0] && new[1] == pos[i][1])
{
if (pos[i][2] == [map_i currentMinZ])
pos[i][2] = [map_i currentMaxZ];
else
pos[i][2] = [map_i currentMinZ];
[quakeed_i updateAll];
return self;
}
}
if (num == 3)
num = 0;
VectorCopy (new, pos[num]);
num++;
[quakeed_i updateAll];
return self;
}
/*
================
XYDrag
================
*/
- (BOOL)XYDrag: (NSPoint *)pt
{
int i;
for (i=0 ; i<3 ; i++)
{
if (fabs(pt->x - pos[i][0] > 10) || fabs(pt->y - pos[i][1] > 10) )
continue;
// drag this point
}
return NO;
}
- ZClick: (NSPoint)pt
{
return self;
}
//=============================================================================
- carve
{
[map_i makeSelectedPerform: @selector(carveByClipper)];
num = 0;
return self;
}
- cameraDrawSelf
{
vec3_t mid;
int i;
linecolor (1,0.5,0);
for (i=0 ; i<num ; i++)
{
VectorCopy (pos[i], mid);
mid[0] -= 8;
mid[1] -= 8;
CameraMoveto (mid);
mid[0] += 16;
mid[1] += 16;
CameraLineto (mid);
VectorCopy (pos[i], mid);
mid[0] -= 8;
mid[1] += 8;
CameraMoveto (mid);
mid[0] += 16;
mid[1] -= 16;
CameraLineto (mid);
}
return self;
}
- XYDrawSelf
{
int i;
char text[8];
PSsetrgbcolor (1,0.5,0);
//XXX PSselectfont("Helvetica-Medium",10/[xyview_i currentScale]);
PSrotate(0);
for (i=0 ; i<num ; i++)
{
PSmoveto (pos[i][0]-4, pos[i][1]-4);
sprintf (text, "%i", i);
PSshow (text);
PSstroke ();
PSarc ( pos[i][0], pos[i][1], 10, 0, 360);
PSstroke ();
}
return self;
}
- ZDrawSelf
{
int i;
char text[8];
PSsetrgbcolor (1,0.5,0);
//XXX PSselectfont("Helvetica-Medium",10/[zview_i currentScale]);
PSrotate(0);
for (i=0 ; i<num ; i++)
{
PSmoveto (-28+i*8 - 4, pos[i][2]-4);
sprintf (text, "%i", i);
PSshow (text);
PSstroke ();
PSarc ( -28+i*8, pos[i][2], 10, 0, 360);
PSstroke ();
}
return self;
}
@end

View file

@ -0,0 +1,47 @@
#import <AppKit/AppKit.h>
typedef struct
{
char *key;
char *value;
} dict_t;
@interface Dict:Storage
{
}
- initFromFile:(FILE *)fp;
- (id) parseMultipleFrom:(char *)value;
- (int) getValueUnits:(char *)key;
- delString:(char *)string fromValue:(char *)key;
- addString:(char *)string toValue:(char *)key;
- (char *)convertListToString:(id)list;
- (char *)getStringFor:(char *)name;
- removeKeyword:(char *)key;
- (unsigned int)getValueFor:(char *)name;
- changeStringFor:(char *)key to:(char *)value;
- (dict_t *) findKeyword:(char *)key;
- writeBlockTo:(FILE *)fp;
- writeFile:(char *)path;
// INTERNAL
- init;
- (id) parseBraceBlock:(FILE *)fp;
- setupMultiple:(char *)value;
- (char *)getNextParameter;
@end
int GetNextChar(FILE *fp);
void CopyUntilWhitespc(FILE *fp,char *buffer);
void CopyUntilQuote(FILE *fp,char *buffer);
int FindBrace(FILE *fp);
int FindQuote(FILE *fp);
int FindWhitespc(FILE *fp);
int FindNonwhitespc(FILE *fp);
char *FindWhitespcInBuffer(char *buffer);
char *FindNonwhitespcInBuffer(char *buffer);

View file

@ -0,0 +1,583 @@
#import "qedefs.h"
@implementation Dict
- init
{
[super initCount:0
elementSize:sizeof(dict_t)
description:NULL];
return self;
}
- print
{
int i;
dict_t *d;
for (i=0 ; i<numElements ; i++)
{
d = [self elementAt: i];
printf ("%s : %s\n",d->key, d->value);
}
return self;
}
/*
===========
copyFromZone
JDC
===========
*/
- copyFromZone:(NSZone *)zone
{
id new;
int i;
dict_t *d;
char *old;
new = [super copyFromZone: zone];
for (i=0 ; i<numElements ; i++)
{
d = [self elementAt: i];
old = d->key;
d->key = malloc(strlen(old)+1);
strcpy (d->key, old);
old = d->value;
d->value = malloc(strlen(old)+1);
strcpy (d->value, old);
}
return new;
}
- initFromFile:(FILE *)fp
{
[self init];
return [self parseBraceBlock:fp];
}
//===============================================
//
// Dictionary pair functions
//
//===============================================
//
// Write a { } block out to a FILE*
//
- writeBlockTo:(FILE *)fp
{
int max;
int i;
dict_t *d;
fprintf(fp,"{\n");
max = [super count];
for (i = 0;i < max;i++)
{
d = [super elementAt:i];
fprintf(fp,"\t{\"%s\"\t\"%s\"}\n",d->key,d->value);
}
fprintf(fp,"}\n");
return self;
}
//
// Write a single { } block out
//
- writeFile:(char *)path
{
FILE *fp;
fp = fopen(path,"w+t");
if (fp != NULL)
{
printf("Writing dictionary file %s.\n",path);
fprintf(fp,"// QE_Project file %s\n",path);
[self writeBlockTo:fp];
fclose(fp);
}
else
{
printf("Error writing %s!\n",path);
return NULL;
}
return self;
}
//===============================================
//
// Utility methods
//
//===============================================
//
// Find a keyword in storage
// Returns * to dict_t, otherwise NULL
//
- (dict_t *) findKeyword:(char *)key
{
int max;
int i;
dict_t *d;
max = [super count];
for (i = 0;i < max;i++)
{
d = [super elementAt:i];
if (!strcmp(d->key,key))
return d;
}
return NULL;
}
//
// Change a keyword's string
//
- changeStringFor:(char *)key to:(char *)value
{
dict_t *d;
dict_t newd;
d = [self findKeyword:key];
if (d != NULL)
{
free(d->value);
d->value = malloc(strlen(value)+1);
strcpy(d->value,value);
}
else
{
newd.key = malloc(strlen(key)+1);
strcpy(newd.key,key);
newd.value = malloc(strlen(value)+1);
strcpy(newd.value,value);
[self addElement:&newd];
}
return self;
}
//
// Search for keyword, return the string *
//
- (char *)getStringFor:(char *)name
{
dict_t *d;
d = [self findKeyword:name];
if (d != NULL)
return d->value;
return "";
}
//
// Search for keyword, return the value
//
- (unsigned int)getValueFor:(char *)name
{
dict_t *d;
d = [self findKeyword:name];
if (d != NULL)
return atol(d->value);
return 0;
}
//
// Return # of units in keyword's value
//
- (int) getValueUnits:(char *)key
{
id temp;
int count;
temp = [self parseMultipleFrom:key];
count = [temp count];
[temp free];
return count;
}
//
// Convert List to string
//
- (char *)convertListToString:(id)list
{
int i;
int max;
char tempstr[4096];
char *s;
char *newstr;
max = [list count];
tempstr[0] = 0;
for (i = 0;i < max;i++)
{
s = [list elementAt:i];
strcat(tempstr,s);
strcat(tempstr," ");
}
newstr = malloc(strlen(tempstr)+1);
strcpy(newstr,tempstr);
return newstr;
}
//
// JDC: I wrote this to simplify removing vectors
//
- removeKeyword:(char *)key
{
dict_t *d;
d = [self findKeyword:key];
if (d == NULL)
return self;
[self removeElementAt:d - (dict_t*)dataPtr];
return self;
}
//
// Delete string from keyword's value
//
- delString:(char *)string fromValue:(char *)key
{
id temp;
int count;
int i;
char *s;
dict_t *d;
d = [self findKeyword:key];
if (d == NULL)
return NULL;
temp = [self parseMultipleFrom:key];
count = [temp count];
for (i = 0;i < count;i++)
{
s = [temp elementAt:i];
if (!strcmp(s,string))
{
[temp removeElementAt:i];
free(d->value);
d->value = [self convertListToString:temp];
[temp free];
break;
}
}
return self;
}
//
// Add string to keyword's value
//
- addString:(char *)string toValue:(char *)key
{
char *newstr;
char spacing[] = "\t";
dict_t *d;
d = [self findKeyword:key];
if (d == NULL)
return NULL;
newstr = malloc(strlen(string) + strlen(d->value) + strlen(spacing) + 1);
strcpy(newstr,d->value);
strcat(newstr,spacing);
strcat(newstr,string);
free(d->value);
d->value = newstr;
return self;
}
//===============================================
//
// Use these for multiple parameters in a keyword value
//
//===============================================
char *searchStr;
char item[4096];
- setupMultiple:(char *)value
{
searchStr = value;
return self;
}
- (char *)getNextParameter
{
char *s;
if (!searchStr)
return NULL;
strcpy(item,searchStr);
s = FindWhitespcInBuffer(item);
if (!*s)
searchStr = NULL;
else
{
*s = 0;
searchStr = FindNonwhitespcInBuffer(s+1);
}
return item;
}
//
// Parses a keyvalue string & returns a Storage full of those items
//
- (id) parseMultipleFrom:(char *)key
{
#define ITEMSIZE 128
id stuff;
char string[ITEMSIZE];
char *s;
s = [self getStringFor:key];
if (s == NULL)
return NULL;
stuff = [[Storage alloc]
initCount:0
elementSize:ITEMSIZE
description:NULL];
[self setupMultiple:s];
while((s = [self getNextParameter]))
{
bzero(string,ITEMSIZE);
strcpy(string,s);
[stuff addElement:string];
}
return stuff;
}
//===============================================
//
// Dictionary pair parsing
//
//===============================================
//
// parse all keyword/value pairs within { } 's
//
- (id) parseBraceBlock:(FILE *)fp
{
int c;
dict_t pair;
char string[1024];
c = FindBrace(fp);
if (c == -1)
return NULL;
while((c = FindBrace(fp)) != '}')
{
if (c == -1)
return NULL;
// c = FindNonwhitespc(fp);
// if (c == -1)
// return NULL;
// CopyUntilWhitespc(fp,string);
// JDC: fixed to allow quoted keys
c = FindNonwhitespc(fp);
if (c == -1)
return NULL;
c = fgetc(fp);
if ( c == '\"')
CopyUntilQuote(fp,string);
else
{
ungetc (c,fp);
CopyUntilWhitespc(fp,string);
}
pair.key = malloc(strlen(string)+1);
strcpy(pair.key,string);
c = FindQuote(fp);
CopyUntilQuote(fp,string);
pair.value = malloc(strlen(string)+1);
strcpy(pair.value,string);
[super addElement:&pair];
c = FindBrace(fp);
}
return self;
}
@end
//===============================================
//
// C routines for string parsing
//
//===============================================
int GetNextChar(FILE *fp)
{
int c;
int c2;
c = getc(fp);
if (c == EOF)
return -1;
if (c == '/') // parse comments
{
c2 = getc(fp);
if (c2 == '/')
{
while((c2 = getc(fp)) != '\n');
c = getc(fp);
}
else
ungetc(c2,fp);
}
return c;
}
void CopyUntilWhitespc(FILE *fp,char *buffer)
{
int count = 800;
int c;
while(count--)
{
c = GetNextChar(fp);
if (c == EOF)
return;
if (c <= ' ')
{
*buffer = 0;
return;
}
*buffer++ = c;
}
}
void CopyUntilQuote(FILE *fp,char *buffer)
{
int count = 800;
int c;
while(count--)
{
c = GetNextChar(fp);
if (c == EOF)
return;
if (c == '\"')
{
*buffer = 0;
return;
}
*buffer++ = c;
}
}
int FindBrace(FILE *fp)
{
int count = 800;
int c;
while(count--)
{
c = GetNextChar(fp);
if (c == EOF)
return -1;
if (c == '{' ||
c == '}')
return c;
}
return -1;
}
int FindQuote(FILE *fp)
{
int count = 800;
int c;
while(count--)
{
c = GetNextChar(fp);
if (c == EOF)
return -1;
if (c == '\"')
return c;
}
return -1;
}
int FindWhitespc(FILE *fp)
{
int count = 800;
int c;
while(count--)
{
c = GetNextChar(fp);
if (c == EOF)
return -1;
if (c <= ' ')
{
ungetc(c,fp);
return c;
}
}
return -1;
}
int FindNonwhitespc(FILE *fp)
{
int count = 800;
int c;
while(count--)
{
c = GetNextChar(fp);
if (c == EOF)
return -1;
if (c > ' ')
{
ungetc(c,fp);
return c;
}
}
return -1;
}
char *FindWhitespcInBuffer(char *buffer)
{
int count = 1000;
char *b = buffer;
while(count--)
if (*b <= ' ')
return b;
else
b++;
return NULL;
}
char *FindNonwhitespcInBuffer(char *buffer)
{
int count = 1000;
char *b = buffer;
while(count--)
if (*b > ' ')
return b;
else
b++;
return NULL;
}

View file

@ -0,0 +1,12 @@
#import <AppKit/AppKit.h>
@interface DictList:List
{
}
- initListFromFile:(FILE *)fp;
- writeListFile:(char *)filename;
- (id) findDictKeyword:(char *)key;
@end

View file

@ -0,0 +1,69 @@
#import "qedefs.h"
@implementation DictList
//
// Read in variable # of objects from FILE *
//
- initListFromFile:(FILE *)fp
{
id d;
[super init];
do
{
d = [(Dict *)[Dict alloc] initFromFile:fp];
if (d != NULL)
[self addObject:d];
} while(d != NULL);
[d free];
return self;
}
//
// Write out list file
//
- writeListFile:(char *)filename
{
FILE *fp;
int i;
id obj;
fp = fopen(filename,"w+t");
if (fp == NULL)
return NULL;
fprintf(fp,"// Object List written by QuakeEd\n");
for (i = 0;i < maxElements;i++)
{
obj = [self objectAt:i];
[obj writeBlockTo:fp];
}
fclose(fp);
return self;
}
//
// Find the keyword in all the Dict objects
//
- (id) findDictKeyword:(char *)key
{
int i;
dict_t *d;
id dict;
for (i = 0;i < maxElements;i++)
{
dict = [self objectAt:i];
d = [(Dict *)dict findKeyword:key];
if (d != NULL)
return dict;
}
return NULL;
}
@end

View file

@ -0,0 +1,40 @@
#define MAX_KEY 64
#define MAX_VALUE 128
typedef struct epair_s
{
struct epair_s *next;
char key[MAX_KEY];
char value[MAX_VALUE];
} epair_t;
// an Entity is a list of brush objects, with additional key / value info
@interface Entity : NSObject <NSCopying, NSMutableCopying>
{
epair_t *epairs;
BOOL modifiable;
}
- initClass: (char *)classname;
- initFromTokens;
- free;
- (BOOL)modifiable;
- setModifiable: (BOOL)m;
- (char *)targetname;
- writeToFILE: (FILE *)f region:(BOOL)reg;
- (char *)valueForQKey: (char *)k;
- getVector: (vec3_t)v forKey: (char *)k;
- setKey:(char *)k toValue:(char *)v;
- (int)numPairs;
- (epair_t *)epairs;
- removeKeyPair: (char *)key;
@end

View file

@ -0,0 +1,485 @@
#include "qedefs.h"
@implementation Entity
vec3_t bad_mins = {-8, -8, -8};
vec3_t bad_maxs = {8, 8, 8};
- createFixedBrush: (vec3_t)org
{
vec3_t emins, emaxs;
float *v, *v2, *color;
id new;
texturedef_t td;
// get class
new = [entity_classes_i classForName: [self valueForQKey: "classname"]];
if (new)
{
v = [new mins];
v2 = [new maxs];
}
else
{
v = bad_mins;
v2 = bad_maxs;
}
color = [new drawColor];
modifiable = NO;
memset(&td,0,sizeof(td));
strcpy (td.texture,"entity");
VectorAdd (org, v, emins);
VectorAdd (org, v2, emaxs);
new = [[SetBrush alloc] initOwner: self mins:emins maxs:emaxs
texture: &td];
[new setEntityColor: color];
[self addObject: new];
return self;
}
- copyWithZone:(NSZone *)zone
{
id new, nb;
epair_t *e;
int i;
new = [[Entity alloc] init];
[new setModifiable: modifiable];
for (e=epairs ; e ; e=e->next)
{ // don't copy target and targetname fields
if (strncmp(e->key,"target",6))
[new setKey: e->key toValue: e->value];
}
for (i=0 ; i<numElements ; i++)
{
nb = [[self objectAt: i] copy];
[nb setParent: new];
[new addObject: nb];
}
return new;
}
- initClass: (char *)classname
{
id new;
esize_t esize;
char value[80];
vec3_t min, max;
float *v;
[super init];
modifiable = YES;
[self setKey: "classname" toValue:classname];
// get class
new = [entity_classes_i classForName: [self valueForQKey: "classname"]];
if (!new)
esize = esize_model;
else
esize = [new esize];
// create a brush if needed
if (esize == esize_fixed)
{
v = [new mins];
[[map_i selectedBrush] getMins: min maxs: max];
VectorSubtract (min, v, min);
sprintf (value, "%i %i %i",(int)min[0], (int)min[1], (int)min[2]);
[self setKey:"origin" toValue: value];
[self createFixedBrush: min];
}
else
modifiable = YES;
return self;
}
- free
{
epair_t *e, *n;
for (e=epairs ; e ; e=n)
{
n = e->next;
free (e);
}
return [super free];
}
- (BOOL)modifiable
{
return modifiable;
}
- setModifiable: (BOOL)m
{
modifiable = m;
return self;
}
- removeObject: o
{
o = [super removeObject: o];
if (numElements)
return o;
// the entity is empty, so remove the entire thing
if ( self == [map_i objectAt: 0])
return o; // never remove the world
[map_i removeObject: self];
[self free];
return o;
}
- (char *)valueForQKey: (char *)k
{
epair_t *e;
static char ret[64];
for (e=epairs ; e ; e=e->next)
if (!strcmp(k,e->key))
{
strcpy (ret, e->value);
return ret;
}
return "";
}
- getVector: (vec3_t)v forKey: (char *)k
{
char *c;
c = [self valueForQKey: k];
v[0] = v[1] = v[2] = 0;
sscanf (c, "%f %f %f", &v[0], &v[1], &v[2]);
return self;
}
- print
{
epair_t *e;
for (e=epairs ; e ; e=e->next)
printf ("%20s : %20s\n",e->key, e->value);
return self;
}
- setKey:(char *)k toValue:(char *)v
{
epair_t *e;
if (strlen(k) > MAX_KEY)
Error ("setKey: %s > MAX_KEY", k);
if (strlen(v) > MAX_VALUE)
Error ("setKey: %s > MAX_VALUE", v);
while (*k && *k <= ' ')
k++;
if (!*k)
return self; // don't set NULL values
for (e=epairs ; e ; e=e->next)
if (!strcmp(k,e->key))
{
memset (e->value, 0, sizeof(e->value));
strcpy (e->value, v);
return self;
}
e = malloc (sizeof(epair_t));
memset (e, 0, sizeof(epair_t));
strcpy (e->key, k);
strcpy (e->value, v);
e->next = epairs;
epairs = e;
return self;
}
- (int)numPairs
{
int i;
epair_t *e;
i=0;
for (e=epairs ; e ; e=e->next)
i++;
return i;
}
- (epair_t *)epairs
{
return epairs;
}
- removeKeyPair: (char *)key
{
epair_t *e, *e2;
if (!epairs)
return self;
e = epairs;
if (!strcmp(e->key, key))
{
epairs = e->next;
free (e);
return self;
}
for (; e ; e=e->next)
{
if (e->next && !strcmp(e->next->key, key))
{
e2 = e->next;
e->next = e2->next;
free (e2);
return self;
}
}
printf ("WARNING: removeKeyPair: %s not found\n", key);
return self;
}
/*
=============
targetname
If the entity does not have a "targetname" key, a unique one is generated
=============
*/
- (char *)targetname
{
char *t;
int i, count;
id ent;
int tval, maxt;
char name[20];
t = [self valueForQKey: "targetname"];
if (t && t[0])
return t;
// make a unique name of the form t<number>
count = [map_i count];
maxt = 0;
for (i=1 ; i<count ; i++)
{
ent = [map_i objectAt: i];
t = [ent valueForQKey: "targetname"];
if (!t || t[0] != 't')
continue;
tval = atoi (t+1);
if (tval > maxt)
maxt = tval;
}
sprintf (name,"t%i",maxt+1);
[self setKey: "targetname" toValue: name];
return [self valueForQKey: "targetname"]; // so it's not on the stack
}
/*
==============================================================================
FILE METHODS
==============================================================================
*/
int nument;
- initFromTokens
{
char key[MAXTOKEN];
id eclass, brush;
char *spawn;
vec3_t emins, emaxs;
vec3_t org;
texturedef_t td;
esize_t esize;
int i, c;
float *color;
[self init];
if (!GetToken (true))
{
[self free];
return nil;
}
if (strcmp (token, "{") )
Error ("initFromFileP: { not found");
do
{
if (!GetToken (true))
break;
if (!strcmp (token, "}") )
break;
if (!strcmp (token, "{") )
{ // read a brush
brush = [[SetBrush alloc] initFromTokens: self];
[self addObject: brush];
}
else
{ // read a key / value pair
strcpy (key, token);
GetToken (false);
[self setKey: key toValue:token];
}
} while (1);
nument++;
// get class
spawn = [self valueForQKey: "classname"];
eclass = [entity_classes_i classForName: spawn];
esize = [eclass esize];
[self getVector: org forKey: "origin"];
if ([self count] && esize != esize_model)
{
printf ("WARNING:Entity with brushes and wrong model type\n");
[self empty];
}
if (![self count] && esize == esize_model)
{
printf ("WARNING:Entity with no brushes and esize_model\n");
[texturepalette_i getTextureDef: &td];
for (i=0 ; i<3 ; i++)
{
emins[i] = org[i] - 8;
emaxs[i] = org[i] + 8;
}
brush = [[SetBrush alloc] initOwner: self mins:emins maxs:emaxs
texture: &td];
[self addObject: brush];
}
// create a brush if needed
if (esize == esize_fixed)
[self createFixedBrush: org];
else
modifiable = YES;
// set all the brush colors
color = [eclass drawColor];
c = [self count];
for (i=0 ; i<c ; i++)
{
brush = [self objectAt: i];
[brush setEntityColor: color];
}
return self;
}
- writeToFILE: (FILE *)f region:(BOOL)reg;
{
epair_t *e;
int i;
id new;
char value[80];
vec3_t mins, maxs, org;
float *v;
BOOL temporg;
char oldang[80];
temporg = NO;
if (reg)
{
if ( !strcmp ([self valueForQKey: "classname"], "info_player_start") )
{ // move the playerstart temporarily to the camera position
temporg = YES;
strcpy (oldang, [self valueForQKey: "angle"]);
sprintf (value, "%i", (int)([cameraview_i yawAngle]*180/M_PI));
[self setKey: "angle" toValue: value];
}
else if ( self != [map_i objectAt: 0]
&& [[self objectAt: 0] regioned] )
return self; // skip the entire entity definition
}
fprintf (f,"{\n");
// set an origin epair
if (!modifiable)
{
[[self objectAt: 0] getMins: mins maxs: maxs];
if (temporg)
{
[cameraview_i getOrigin: mins];
mins[0] -= 16;
mins[1] -= 16;
mins[2] -= 48;
}
new = [entity_classes_i classForName:
[self valueForQKey: "classname"]];
if (new)
v = [new mins];
else
v = vec3_origin;
VectorSubtract (mins, v, org);
sprintf (value, "%i %i %i",(int)org[0], (int)org[1], (int)org[2]);
[self setKey:"origin" toValue: value];
}
for (e=epairs ; e ; e=e->next)
fprintf (f,"\"%s\"\t\"%s\"\n", e->key, e->value);
// fixed size entities don't save out brushes
if ( modifiable )
{
for (i=0 ; i<numElements ; i++)
[[self objectAt: i] writeToFILE: f region: reg];
}
fprintf (f,"}\n");
if (temporg)
[self setKey: "angle" toValue: oldang];
return self;
}
/*
==============================================================================
INTERACTION
==============================================================================
*/
@end

View file

@ -0,0 +1,42 @@
#import <AppKit/AppKit.h>
#import "mathlib.h"
typedef enum {esize_model, esize_fixed} esize_t;
#define MAX_FLAGS 8
@interface EntityClass : Object
{
char *name;
esize_t esize;
vec3_t mins, maxs;
vec3_t color;
char *comments;
char flagnames[MAX_FLAGS][32];
}
- initFromText: (char *)text;
- (char *)classname;
- (esize_t)esize;
- (float *)mins; // only for esize_fixed
- (float *)maxs; // only for esize_fixed
- (float *)drawColor;
- (char *)comments;
- (char *)flagName: (unsigned)flagnum;
@end
extern id entity_classes_i;
@interface EntityClassList : NSMutableArray
{
id nullclass;
char *source_path;
}
- initForSourceDirectory: (char *)path;
- (id)classForName: (char *)name;
- (void)scanDirectory;
@end

View file

@ -0,0 +1,265 @@
#import "qedefs.h"
@implementation EntityClass
// the classname, color triple, and bounding box are parsed out of comments
// A ? size means take the exact brush size.
//
// /*QUAKED <classname> (0 0 0) ?
// /*QUAKED <classname> (0 0 0) (-8 -8 -8) (8 8 8)
//
// Flag names can follow the size description:
//
// /*QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY
char *debugname;
- initFromText: (char *)text
{
char *t;
int len;
int r, i;
char parms[256], *p;
[super init];
text += strlen("/*QUAKED ");
// grab the name
text = COM_Parse (text);
name = malloc (strlen(com_token)+1);
strcpy (name, com_token);
debugname = name;
// grab the color
r = sscanf (text," (%f %f %f)", &color[0], &color[1], &color[2]);
if (r != 3)
return NULL;
while (*text != ')')
{
if (!*text)
return NULL;
text++;
}
text++;
// get the size
text = COM_Parse (text);
if (com_token[0] == '(')
{ // parse the size as two vectors
esize = esize_fixed;
r = sscanf (text,"%f %f %f) (%f %f %f)", &mins[0], &mins[1], &mins[2], &maxs[0], &maxs[1], &maxs[2]);
if (r != 6)
return NULL;
for (i=0 ; i<2 ; i++)
{
while (*text != ')')
{
if (!*text)
return NULL;
text++;
}
text++;
}
}
else
{ // use the brushes
esize = esize_model;
}
// get the flags
// copy to the first /n
p = parms;
while (*text && *text != '\n')
*p++ = *text++;
*p = 0;
text++;
// any remaining words are parm flags
p = parms;
for (i=0 ; i<8 ; i++)
{
p = COM_Parse (p);
if (!p)
break;
strcpy (flagnames[i], com_token);
}
// find the length until close comment
for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++)
;
// copy the comment block out
len = t-text;
comments = malloc (len+1);
memcpy (comments, text, len);
comments[len] = 0;
return self;
}
- (esize_t)esize
{
return esize;
}
- (char *)classname
{
return name;
}
- (float *)mins
{
return mins;
}
- (float *)maxs
{
return maxs;
}
- (float *)drawColor
{
return color;
}
- (char *)comments
{
return comments;
}
- (char *)flagName: (unsigned)flagnum
{
if (flagnum >= MAX_FLAGS)
Error ("EntityClass flagName: bad number");
return flagnames[flagnum];
}
@end
//===========================================================================
@implementation EntityClassList
/*
=================
insertEC:
=================
*/
- (void)insertEC: ec
{
char *name;
int i;
name = [ec classname];
for (i=0 ; i<[self count] ; i++)
{
if (strcasecmp (name, [[self objectAtIndex: i] classname]) < 0)
{
[self insertObject: ec atIndex:i];
return;
}
}
[self addObject: ec];
}
/*
=================
scanFile
=================
*/
- (void)scanFile: (char *)filename
{
int size;
char *data;
id cl;
int i;
char path[1024];
sprintf (path,"%s/%s", source_path, filename);
size = LoadFile (path, (void *)&data);
for (i=0 ; i<size ; i++)
if (!strncmp(data+i, "/*QUAKED",8))
{
cl = [[EntityClass alloc] initFromText: data+i];
if (cl)
[self insertEC: cl];
else
printf ("Error parsing: %s in %s\n",debugname, filename);
}
free (data);
}
/*
=================
scanDirectory
=================
*/
- (void)scanDirectory
{
int count, i;
struct direct **namelist, *ent;
[self removeAllObjects];
count = scandir(source_path, &namelist, NULL, NULL);
for (i=0 ; i<count ; i++)
{
int len;
ent = namelist[i];
len = strlen (ent->d_name);
if (len <= 3)
continue;
if (!strcmp (ent->d_name+len-3,".qc"))
[self scanFile: ent->d_name];
}
}
id entity_classes_i;
- initForSourceDirectory: (char *)path
{
[super init];
source_path = path;
[self scanDirectory];
entity_classes_i = self;
nullclass = [[EntityClass alloc] initFromText:
"/*QUAKED UNKNOWN_CLASS (0 0.5 0) ?"];
return self;
}
- (id)classForName: (char *)name
{
int i;
id o;
for (i=0 ; i<[self count] ; i++)
{
o = [self objectAtIndex: i];
if (!strcmp (name,[o classname]) )
return o;
}
return nullclass;
}
@end

View file

@ -0,0 +1,27 @@
include $(GNUSTEP_MAKEFILES)/common.make
BUNDLE_NAME= MapEdit
BUNDLE_EXTENSION= .forgeb
#
# We don't install this bundle, it goes inside the app.
#
BUNDLE_INSTALL_DIR= none
MapEdit_STANDARD_INSTALL= no
MapEdit_RESOURCE_FILES= \
MapEdit.gorm
MapEdit_OBJC_FILES= \
CameraView.m Clipper.m EntityClass.m KeypairView.m PopScrollView.m ZView.m misc.m render.m
MapEdit_HEADERS= \
EntityClass.h
MapEdit_PRINCIPAL_CLASS= \
MapEdit
-include GNUmakefile.preamble
include $(GNUSTEP_MAKEFILES)/bundle.make
-include GNUmakefile.postamble

View file

@ -0,0 +1,39 @@
# Additional flags to pass to the preprocessor
ADDITIONAL_CPPFLAGS +=
# Additional flags to pass to the Objective-C compiler
ADDITIONAL_OBJCFLAGS += -DUSING_NIBS -Wall -Werror
# Additional flags to pass to the C compiler
ADDITIONAL_CFLAGS += -Wall -Werror
# Additional include directories the compiler should search
ADDITIONAL_INCLUDE_DIRS += -I ../..
# Additional LDFLAGS to pass to the linker
ADDITIONAL_LDFLAGS +=
# Additional library directories the linker should search
ADDITIONAL_LIB_DIRS +=
# Additional libraries
# GNUstepWeb
ADDITIONAL_GSW_LIBS +=
# GUI apps
ADDITIONAL_GUI_LIBS +=
# Libraries
ADDITIONAL_LIBRARY_LIBS +=
# ObjC stuff
ADDITIONAL_OBJC_LIBS +=
# Tools
ADDITIONAL_TOOL_LIBS +=
# WebObjects
ADDITIONAL_WO_LIBS +=
#
# Flags dealing with installing and uninstalling
#
# Additional directories to be created during installation
ADDITIONAL_INSTALL_DIRS +=

View file

@ -0,0 +1,71 @@
#import <AppKit/AppKit.h>
#define MINIWINICON "DoomEdIcon"
typedef enum
{
i_project,
i_textures,
i_things,
i_prefs,
i_settings,
i_output,
i_help,
i_end
} insp_e;
extern id inspcontrol_i;
@interface InspectorControl:Object
{
id inspectorView_i; // inspector view
id inspectorSubview_i; // inspector view's current subview (gets replaced)
id contentList; // List of contentviews (corresponds to
// insp_e enum order)
id windowList; // List of Windows (corresponds to
// insp_e enum order)
id obj_textures_i; // TexturePalette object (for delegating)
id obj_genkeypair_i; // GenKeyPair object
id popUpButton_i; // PopUpList title button
id popUpMatrix_i; // PopUpList matrix
id itemList; // List of popUp buttons
insp_e currentInspectorType; // keep track of current inspector
//
// Add id's here for new inspectors
// **NOTE: Make sure PopUpList has correct TAG value that
// corresponds to the enums above!
// Windows
id win_project_i; // project
id win_textures_i; // textures
id win_things_i; // things
id win_prefs_i; // preferences
id win_settings_i; // project settings
id win_output_i; // bsp output
id win_help_i; // documentation
// PopUpList objs
id itemProject_i; // project
id itemTextures_i; // textures
id itemThings_i; // things
id itemPrefs_i; // preferences
id itemSettings_i; // project settings
id itemOutput_i; // bsp output
id itemHelp_i; // docs
}
- awakeFromNib;
- changeInspector:sender;
- changeInspectorTo:(insp_e)which;
- (insp_e)getCurrentInspector;
@end
@protocol InspectorControl
- windowResized;
@end

View file

@ -0,0 +1,128 @@
#import "qedefs.h"
// Add .h-files here for new inspectors
#import "Things.h"
#import "TexturePalette.h"
#import "Preferences.h"
id inspcontrol_i;
@implementation InspectorControl
- awakeFromNib
{
inspcontrol_i = self;
currentInspectorType = -1;
contentList = [[List alloc] init];
windowList = [[List alloc] init];
itemList = [[List alloc] init];
// ADD NEW INSPECTORS HERE...
[windowList addObject:win_project_i];
[contentList addObject:[win_project_i contentView]];
[itemProject_i setKeyEquivalent:'1'];
[itemList addObject:itemProject_i];
[windowList addObject:win_textures_i];
[contentList addObject:[win_textures_i contentView]];
[itemTextures_i setKeyEquivalent:'2'];
[itemList addObject:itemTextures_i];
[windowList addObject:win_things_i];
[contentList addObject:[win_things_i contentView]];
[itemThings_i setKeyEquivalent:'3'];
[itemList addObject:itemThings_i];
[windowList addObject:win_prefs_i];
[contentList addObject:[win_prefs_i contentView]];
[itemPrefs_i setKeyEquivalent:'4'];
[itemList addObject:itemPrefs_i];
[windowList addObject:win_settings_i];
[contentList addObject:[win_settings_i contentView]];
[itemSettings_i setKeyEquivalent:'5'];
[itemList addObject:itemSettings_i];
[windowList addObject:win_output_i];
[contentList addObject:[win_output_i contentView]];
[itemOutput_i setKeyEquivalent:'6'];
[itemList addObject:itemOutput_i];
[windowList addObject:win_help_i];
[contentList addObject:[win_help_i contentView]];
[itemHelp_i setKeyEquivalent:'7'];
[itemList addObject:itemHelp_i];
// Setup inspector window with project subview first
[inspectorView_i setAutoresizeSubviews:YES];
inspectorSubview_i = [contentList objectAt:i_project];
[inspectorView_i addSubview:inspectorSubview_i];
currentInspectorType = -1;
[self changeInspectorTo:i_project];
return self;
}
//
// Sent by the PopUpList in the Inspector
// Each cell in the PopUpList must have the correct tag
//
- changeInspector:sender
{
id cell;
cell = [sender selectedCell];
[self changeInspectorTo:[cell tag]];
return self;
}
//
// Change to specific Inspector
//
- changeInspectorTo:(insp_e)which
{
id newView;
NSRect r;
id cell;
NSRect f;
if (which == currentInspectorType)
return self;
currentInspectorType = which;
newView = [contentList objectAt:which];
cell = [itemList objectAt:which]; // set PopUpButton title
[popUpButton_i setTitle:[cell title]];
[inspectorView_i replaceSubview:inspectorSubview_i with:newView];
[inspectorView_i getFrame:&r];
inspectorSubview_i = newView;
[inspectorSubview_i setAutosizing:NS_WIDTHSIZABLE | NS_HEIGHTSIZABLE];
[inspectorSubview_i sizeTo:r.size.width - 4 :r.size.height - 4];
[inspectorSubview_i lockFocus];
[inspectorSubview_i getBounds:&f];
PSsetgray(NS_LTGRAY);
NSRectFill(&f);
[inspectorSubview_i unlockFocus];
[inspectorView_i display];
return self;
}
- (insp_e)getCurrentInspector
{
return currentInspectorType;
}
@end

View file

@ -0,0 +1,16 @@
extern id keypairview_i;
@interface KeypairView:NSView
{
}
- calcViewSize;
#define SPACING 4
#define FONTSIZE 12
#define EXTRASPC 2
#define LINEHEIGHT 16
@end

View file

@ -0,0 +1,93 @@
#import "qedefs.h"
id keypairview_i;
@implementation KeypairView
/*
==================
initWithFrame:
==================
*/
- initWithFrame:(NSRect)frameRect
{
[super initWithFrame:frameRect];
keypairview_i = self;
return self;
}
- calcViewSize
{
NSRect b;
NSPoint pt;
int count;
id ent;
ent = [map_i currentEntity];
count = [ent numPairs];
//XXX[_super_view setFlipped: YES];
b = [_super_view bounds];
b.size.height = LINEHEIGHT*count + SPACING;
[self setBounds: b];
pt.x = pt.y = 0;
[self scrollPoint: pt];
return self;
}
- drawSelf:(const NSRect *)rects :(int)rectCount
{
epair_t *pair;
int y;
//XXX PSsetgray(NSGrayComponent(NS_COLORLTGRAY));
PSrectfill(0,0,_bounds.size.width,_bounds.size.height);
//XXX PSselectfont("Helvetica-Bold",FONTSIZE);
PSrotate(0);
PSsetgray(0);
pair = [[map_i currentEntity] epairs];
y = _bounds.size.height - LINEHEIGHT;
for ( ; pair ; pair=pair->next)
{
PSmoveto(SPACING, y);
PSshow(pair->key);
PSmoveto(100, y);
PSshow(pair->value);
y -= LINEHEIGHT;
}
PSstroke();
return self;
}
- (void)mouseDown:(NSEvent *)theEvent
{
NSPoint loc;
int i;
epair_t *p;
loc = [theEvent locationInWindow];
loc = [self convertPoint:loc fromView:NULL];
i = (_bounds.size.height - loc.y - 4) / LINEHEIGHT;
p = [[map_i currentEntity] epairs];
while ( i )
{
p=p->next;
if (!p)
return;
i--;
}
if (p)
[things_i setSelectedKey: p];
return;
}
@end

View file

@ -0,0 +1,68 @@
// Map is a list of Entity objects
extern id map_i;
@interface Map : NSMutableArray
{
id currentEntity;
id oldselection; // temp when loading a new map
float minz, maxz;
}
- newMap;
- writeStats;
- readMapFile: (char *)fname;
- writeMapFile: (char *)fname useRegion: (BOOL)reg;
- entityConnect: (vec3_t)p1 : (vec3_t)p2;
- selectRay: (vec3_t)p1 : (vec3_t)p2 : (BOOL)ef;
- grabRay: (vec3_t)p1 : (vec3_t)p2;
- setTextureRay: (vec3_t)p1 : (vec3_t)p2 : (BOOL)allsides;
- getTextureRay: (vec3_t)p1 : (vec3_t)p2;
- currentEntity;
- setCurrentEntity: ent;
- (float)currentMinZ;
- setCurrentMinZ: (float)m;
- (float)currentMaxZ;
- setCurrentMaxZ: (float)m;
- (int)numSelected;
- selectedBrush; // returns the first selected brush
//
// operations on current selection
//
- makeSelectedPerform: (SEL)sel;
- makeUnselectedPerform: (SEL)sel;
- makeAllPerform: (SEL)sel;
- makeGlobalPerform: (SEL)sel; // in and out of region
- cloneSelection: sender;
- makeEntity: sender;
- subtractSelection: sender;
- selectCompletelyInside: sender;
- selectPartiallyInside: sender;
- tallBrush: sender;
- shortBrush: sender;
- rotate_x: sender;
- rotate_y: sender;
- rotate_z: sender;
- flip_x: sender;
- flip_y: sender;
- flip_z: sender;
- selectCompleteEntity: sender;
@end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
#import <AppKit/AppKit.h>
@interface PopScrollView : NSScrollView
{
id button1, button2;
}
- initWithFrame:(NSRect)frameRect button1: b1 button2: b2;
- tile;
@end

View file

@ -0,0 +1,87 @@
#import "qedefs.h"
@implementation PopScrollView
/*
====================
initWithFrame: button:
Initizes a scroll view with a button at it's lower right corner
====================
*/
- initWithFrame:(NSRect)frameRect button1:b1 button2:b2
{
[super initWithFrame: frameRect];
[self addSubview: b1];
[self addSubview: b2];
button1 = b1;
button2 = b2;
[self setHasHorizontalScroller: YES];
[self setHasVerticalScroller: YES];
[self setBorderType: NSBezelBorder];
return self;
}
/*
================
tile
Adjust the size for the pop up scale menu
=================
*/
- tile
{
NSRect scrollerframe;
NSRect buttonframe, buttonframe2;
NSRect newframe;
[super tile];
buttonframe = [button1 frame];
buttonframe2 = [button2 frame];
scrollerframe = [_horizScroller frame];
newframe.origin.y = scrollerframe.origin.y;
newframe.origin.x = scrollerframe.size.width - buttonframe.size.width;
newframe.size.width = buttonframe.size.width;
newframe.size.height = scrollerframe.size.height;
scrollerframe.size.width -= newframe.size.width;
[button1 setFrame: newframe];
newframe.size.width = buttonframe2.size.width;
newframe.origin.x -= newframe.size.width;
[button2 setFrame: newframe];
scrollerframe.size.width -= newframe.size.width;
[_horizScroller setFrame: scrollerframe];
return self;
}
/*
- superviewSizeChanged:(const NSSize *)oldSize
{
[super superviewSizeChanged: oldSize];
[[self docView] newSuperBounds];
return self;
}
*/
-(BOOL) acceptsFirstResponder
{
return YES;
}
@end

View file

@ -0,0 +1,78 @@
extern id preferences_i;
extern float lightaxis[3];
// these are personal preferences saved in NeXT defaults, not project
// parameters saved in the quake.qe_project file
@interface Preferences:Object
{
id bspSound_i; // actual sound object
// internal state
char projectpath[1024];
char bspSound[1024];
BOOL brushOffset;
BOOL showBSP;
float xlight;
float ylight;
float zlight; // 0.0 - 1.0
int startwad; // 0 - 2
// UI targets
id startproject_i; // TextField
id bspSoundField_i; // TextField of bspSound
id brushOffset_i; // Brush Offset checkbox
id showBSP_i; // Show BSP Output checkbox
id startwad_i; // which wad to load at startup
id xlight_i; // X-side lighting
id ylight_i; // Y-side lighting
id zlight_i; // Z-side lighting
}
- readDefaults;
//
// validate and set methods called by UI or defaults
//
- setProjectPath:(char *)path;
- setBspSoundPath:(char *)path; // set the path of the soundfile externally
- setShowBSP:(int)state; // set the state of ShowBSP
- setBrushOffset:(int)state; // set the state of BrushOffset
- setStartWad:(int)value; // set start wad (0-2)
- setXlight:(float)value; // set Xlight value for CameraView
- setYlight:(float)value; // set Ylight value for CameraView
- setZlight:(float)value; // set Zlight value for CameraView
//
// UI targets
//
- setBspSound:sender; // use OpenPanel to select sound
- setCurrentProject:sender; // make current roject the default
- UIChanged: sender; // target for all checks and fields
//
// methods used by other objects to retreive defaults
//
- playBspSound;
- (char *)getProjectPath;
- (int)getBrushOffset; // get the state
- (int)getShowBSP; // get the state
- (float)getXlight; // get Xlight value
- (float)getYlight; // get Ylight value
- (float)getZlight; // get Zlight value
- (int)getStartWad;
@end

View file

@ -0,0 +1,330 @@
#import "qedefs.h"
id preferences_i;
#define DEFOWNER "QuakeEd2"
float lightaxis[3] = {1, 0.6, 0.75};
@implementation Preferences
- init
{
[super init];
preferences_i = self;
return self;
}
int _atoi (char *c)
{
if (!c)
return 0;
return atoi(c);
}
int _atof (char *c)
{
if (!c)
return 0;
return atof(c);
}
void WriteNumericDefault (char *name, float value)
{
char str[128];
sprintf (str,"%f", value);
NSWriteDefault (DEFOWNER, name, str);
}
void WriteStringDefault (char *name, char *value)
{
NSWriteDefault (DEFOWNER, name, value);
}
//
// Read in at start of program
//
- readDefaults
{
char *string;
float value;
string = (char *)NSGetDefaultValue(DEFOWNER,"ProjectPath");
[self setProjectPath: string];
string = (char *)NSGetDefaultValue(DEFOWNER,"BspSoundPath");
[self setBspSoundPath:string];
value = _atoi((char *)NSGetDefaultValue(DEFOWNER,"ShowBSPOutput"));
[self setShowBSP:value];
value = _atoi((char *)NSGetDefaultValue(DEFOWNER,"OffsetBrushCopy"));
[self setBrushOffset:value];
value = _atoi((char *)NSGetDefaultValue(DEFOWNER,"StartWad"));
[self setStartWad:value];
value = _atof((char *)NSGetDefaultValue(DEFOWNER,"Xlight"));
[self setXlight:value];
value = _atof((char *)NSGetDefaultValue(DEFOWNER,"Ylight"));
[self setYlight:value];
value = _atof((char *)NSGetDefaultValue(DEFOWNER,"Zlight"));
[self setZlight:value];
return self;
}
- setProjectPath:(char *)path
{
if (!path)
path = "";
strcpy (projectpath, path);
[startproject_i setStringValue: path];
WriteStringDefault ("ProjectPath", path);
return self;
}
- setCurrentProject:sender
{
[startproject_i setStringValue: [project_i currentProjectFile]];
[self UIChanged: self];
return self;
}
- (char *)getProjectPath
{
return projectpath;
}
//
//===============================================
// BSP sound stuff
//===============================================
//
// Set the BSP sound using an OpenPanel
//
- setBspSound:sender
{
id panel;
char *types[]={"snd",NULL};
int rtn;
char **filename;
char path[1024], file[64];
panel = [OpenPanel new];
ExtractFilePath (bspSound, path);
ExtractFileBase (bspSound, file);
rtn = [panel
runModalForDirectory:path
file: file
types: types];
if (rtn)
{
filename = (char **)[panel filenames];
strcpy(bspSound,[panel directory]);
strcat(bspSound,"/");
strcat(bspSound,filename[0]);
[self setBspSoundPath:bspSound];
[self playBspSound];
}
return self;
}
//
// Play the BSP sound
//
- playBspSound
{
[bspSound_i play];
return self;
}
//
// Set the bspSound path
//
- setBspSoundPath:(char *)path
{
if (!path)
path = "";
strcpy(bspSound,path);
if (bspSound_i)
[bspSound_i free];
bspSound_i = [[Sound alloc] initFromSoundfile:bspSound];
if (!bspSound_i)
{
strcpy (bspSound, "/NextLibrary/Sounds/Funk.snd");
bspSound_i = [[Sound alloc] initFromSoundfile:bspSound];
}
[bspSoundField_i setStringValue:bspSound];
WriteStringDefault ("BspSoundPath", bspSound);
return self;
}
//===============================================
// Show BSP Output management
//===============================================
//
// Set the state
//
- setShowBSP:(int)state
{
showBSP = state;
[showBSP_i setIntValue:state];
WriteNumericDefault ("ShowBSPOutput", showBSP);
return self;
}
//
// Get the state
//
- (int)getShowBSP
{
return showBSP;
}
//===============================================
// "Offset Brush ..." management
//===============================================
//
// Set the state
//
- setBrushOffset:(int)state
{
brushOffset = state;
[brushOffset_i setIntValue:state];
WriteNumericDefault ("OffsetBrushCopy", state);
return self;
}
//
// Get the state
//
- (int)getBrushOffset
{
return brushOffset;
}
//===============================================
// StartWad
//===============================================
- setStartWad:(int)value // set start wad (0-2)
{
startwad = value;
if (startwad<0 || startwad>2)
startwad = 0;
[startwad_i selectCellAt:startwad : 0];
WriteNumericDefault ("StartWad", value);
return self;
}
- (int)getStartWad
{
return startwad;
}
//===============================================
// X,Y,Z light values
//===============================================
//
// Set the state
//
- setXlight:(float)value
{
xlight = value;
if (xlight < 0.25 || xlight > 1)
xlight = 0.6;
lightaxis[1] = xlight;
[xlight_i setFloatValue:xlight];
WriteNumericDefault ("Xlight", xlight);
return self;
}
- setYlight:(float)value
{
ylight = value;
if (ylight < 0.25 || ylight > 1)
ylight = 0.75;
lightaxis[2] = ylight;
[ylight_i setFloatValue:ylight];
WriteNumericDefault ("Ylight", ylight);
return self;
}
- setZlight:(float)value
{
zlight = value;
if (zlight < 0.25 || zlight > 1)
zlight = 1;
lightaxis[0] = zlight;
[zlight_i setFloatValue:zlight];
WriteNumericDefault ("Zlight", zlight);
return self;
}
//
// Get the state
//
- (float)getXlight
{
return [xlight_i floatValue];
}
- (float)getYlight
{
return [ylight_i floatValue];
}
- (float)getZlight
{
return [zlight_i floatValue];
}
/*
============
UIChanged
Grab all the current UI state
============
*/
-UIChanged: sender
{
qprintf ("defaults updated");
[self setProjectPath: (char *)[startproject_i stringValue]];
[self setBspSoundPath: (char *)[bspSoundField_i stringValue]];
[self setShowBSP: [showBSP_i intValue]];
[self setBrushOffset: [brushOffset_i intValue]];
[self setStartWad: [startwad_i selectedRow]];
[self setXlight: [xlight_i floatValue]];
[self setYlight: [ylight_i floatValue]];
[self setZlight: [zlight_i floatValue]];
[map_i makeGlobalPerform: @selector(flushTextures)];
[quakeed_i updateAll];
return self;
}
@end

View file

@ -0,0 +1,108 @@
#import <AppKit/AppKit.h>
#include <sys/stat.h>
#define BASEPATHKEY "basepath"
#define MAPNAMESKEY "maps"
#define DESCKEY "desc"
#define WADSKEY "wads"
#define BSPFULLVIS "bspfullvis"
#define BSPFASTVIS "bspfastvis"
#define BSPNOVIS "bspnovis"
#define BSPRELIGHT "bsprelight"
#define BSPLEAKTEST "bspleaktest"
#define BSPENTITIES "bspentities"
#define SUBDIR_ENT "progs" // subdir names in heirarchy
#define SUBDIR_MAPS "maps"
#define SUBDIR_GFX "gfx"
extern id project_i;
@interface Project:Object
{
id projectInfo; // dictionary storage of project info
id basepathinfo_i; // outlet to base path info textfield
id mapbrowse_i; // outlet to QuakeEd Maps browser
id currentmap_i; // outlet to current map textfield
id mapList; // list of map names (Storage)
id descList; // list of map descriptions (Storage)
id wadList; // list of wad names (Storage)
id pis_panel_i; // outlet to Project Info Settings (PIS) panel
id pis_basepath_i; // outlet to PIS->base path
id pis_wads_i; // outlet to PIS->wad browser
id pis_fullvis_i; // outlet to PIS->full vis command
id pis_fastvis_i; // outlet to PIS->fast vis command
id pis_novis_i; // outlet to PIS->no vis command
id pis_relight_i; // outlet to PIS->relight command
id pis_leaktest_i; // outlet to PIS->leak test command
id BSPoutput_i; // outlet to Text
char path_projectinfo[128]; // path of QE_Project file
char path_basepath[128]; // base path of heirarchy
char path_progdir[128]; // derived from basepath
char path_mapdirectory[128]; // derived from basepath
char path_finalmapdir[128]; // derived from basepath
char path_wad8[128]; // path of texture WAD for cmd-8 key
char path_wad9[128]; // path of texture WAD for cmd-9 key
char path_wad0[128]; // path of texture WAD for cmd-0 key
char string_fullvis[1024]; // cmd-line parm
char string_fastvis[1024]; // cmd-line parm
char string_novis[1024]; // cmd-line parm
char string_relight[1024]; // cmd-line parm
char string_leaktest[1024]; // cmd-line parm
char string_entities[1024]; // cmd-line parm
int showDescriptions; // 1 = show map descs in browser
time_t lastModified; // last time project file was modified
}
- initProject;
- initVars;
- (char *)currentProjectFile;
- setTextureWad: (char *)wf;
- addToOutput:(char *)string;
- clearBspOutput:sender;
- initProjSettings;
- changeChar:(char)f to:(char)t in:(id)obj;
- (int)searchForString:(char *)str in:(id)obj;
- parseProjectFile; // read defaultsdatabase for project path
- openProjectFile:(char *)path; // called by openProject and newProject
- openProject;
- clickedOnMap:sender; // called if clicked on map in browser
- clickedOnWad:sender; // called if clicked on wad in browser
// methods to querie the project file
- (char *)getMapDirectory;
- (char *)getFinalMapDirectory;
- (char *)getProgDirectory;
- (char *)getWAD8;
- (char *)getWAD9;
- (char *)getWAD0;
- (char *)getFullVisCmd;
- (char *)getFastVisCmd;
- (char *)getNoVisCmd;
- (char *)getRelightCmd;
- (char *)getLeaktestCmd;
- (char *)getEntitiesCmd;
@end
void changeString(char cf,char ct,char *string);

View file

@ -0,0 +1,526 @@
//======================================
//
// QuakeEd Project Management
//
//======================================
#import "qedefs.h"
id project_i;
@implementation Project
- init
{
project_i = self;
return self;
}
//===========================================================
//
// Project code
//
//===========================================================
- initVars
{
char *s;
s = [preferences_i getProjectPath];
StripFilename(s);
strcpy(path_basepath,s);
strcpy(path_progdir,s);
strcat(path_progdir,"/"SUBDIR_ENT);
strcpy(path_mapdirectory,s);
strcat(path_mapdirectory,"/"SUBDIR_MAPS); // source dir
strcpy(path_finalmapdir,s);
strcat(path_finalmapdir,"/"SUBDIR_MAPS); // dest dir
[basepathinfo_i setStringValue:s]; // in Project Inspector
#if 0
if ((s = [projectInfo getStringFor:BASEPATHKEY]))
{
strcpy(path_basepath,s);
strcpy(path_progdir,s);
strcat(path_progdir,"/"SUBDIR_ENT);
strcpy(path_mapdirectory,s);
strcat(path_mapdirectory,"/"SUBDIR_MAPS); // source dir
strcpy(path_finalmapdir,s);
strcat(path_finalmapdir,"/"SUBDIR_MAPS); // dest dir
[basepathinfo_i setStringValue:s]; // in Project Inspector
}
#endif
if ((s = [projectInfo getStringFor:BSPFULLVIS]))
{
strcpy(string_fullvis,s);
changeString('@','\"',string_fullvis);
}
if ((s = [projectInfo getStringFor:BSPFASTVIS]))
{
strcpy(string_fastvis,s);
changeString('@','\"',string_fastvis);
}
if ((s = [projectInfo getStringFor:BSPNOVIS]))
{
strcpy(string_novis,s);
changeString('@','\"',string_novis);
}
if ((s = [projectInfo getStringFor:BSPRELIGHT]))
{
strcpy(string_relight,s);
changeString('@','\"',string_relight);
}
if ((s = [projectInfo getStringFor:BSPLEAKTEST]))
{
strcpy(string_leaktest,s);
changeString('@','\"',string_leaktest);
}
if ((s = [projectInfo getStringFor:BSPENTITIES]))
{
strcpy(string_entities,s);
changeString('@','\"', string_entities);
}
// Build list of wads
wadList = [projectInfo parseMultipleFrom:WADSKEY];
// Build list of maps & descriptions
mapList = [projectInfo parseMultipleFrom:MAPNAMESKEY];
descList = [projectInfo parseMultipleFrom:DESCKEY];
[self changeChar:'_' to:' ' in:descList];
[self initProjSettings];
return self;
}
//
// Init Project Settings fields
//
- initProjSettings
{
[pis_basepath_i setStringValue:path_basepath];
[pis_fullvis_i setStringValue:string_fullvis];
[pis_fastvis_i setStringValue:string_fastvis];
[pis_novis_i setStringValue:string_novis];
[pis_relight_i setStringValue:string_relight];
[pis_leaktest_i setStringValue:string_leaktest];
return self;
}
//
// Add text to the BSP Output window
//
- addToOutput:(char *)string
{
int end;
end = [BSPoutput_i textLength];
[BSPoutput_i setSel:end :end];
[BSPoutput_i replaceSel:string];
end = [BSPoutput_i textLength];
[BSPoutput_i setSel:end :end];
[BSPoutput_i scrollSelToVisible];
return self;
}
- clearBspOutput:sender
{
[BSPoutput_i selectAll:self];
[BSPoutput_i replaceSel:"\0"];
return self;
}
- print
{
[BSPoutput_i printPSCode:self];
return self;
}
- initProject
{
[self parseProjectFile];
if (projectInfo == NULL)
return self;
[self initVars];
[mapbrowse_i reuseColumns:YES];
[mapbrowse_i loadColumnZero];
[pis_wads_i reuseColumns:YES];
[pis_wads_i loadColumnZero];
[things_i initEntities];
return self;
}
//
// Change a character to another in a Storage list of strings
//
- changeChar:(char)f to:(char)t in:(id)obj
{
int i;
int max;
char *string;
max = [obj count];
for (i = 0;i < max;i++)
{
string = [obj elementAt:i];
changeString(f,t,string);
}
return self;
}
//
// Fill the QuakeEd Maps or wads browser
// (Delegate method - delegated in Interface Builder)
//
- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
id cell, list;
int max;
char *name;
int i;
if (sender == mapbrowse_i)
list = mapList;
else if (sender == pis_wads_i)
list = wadList;
else
{
list = nil;
Error ("Project: unknown browser to fill");
}
max = [list count];
for (i = 0 ; i<max ; i++)
{
name = [list elementAt:i];
[matrix addRow];
cell = [matrix cellAt:i :0];
[cell setStringValue:name];
[cell setLeaf:YES];
[cell setLoaded:YES];
}
return i;
}
//
// Clicked on a map name or description!
//
- clickedOnMap:sender
{
id matrix;
int row;
char fname[1024];
id panel;
matrix = [sender matrixInColumn:0];
row = [matrix selectedRow];
sprintf(fname,"%s/%s.map",path_mapdirectory,
(char *)[mapList elementAt:row]);
panel = NSGetAlertPanel("Loading...",
"Loading map. Please wait.",NULL,NULL,NULL);
[panel orderFront:NULL];
[quakeed_i doOpen:fname];
[panel performClose:NULL];
NSFreeAlertPanel(panel);
return self;
}
- setTextureWad: (char *)wf
{
int i, c;
char *name;
qprintf ("loading %s", wf);
// set the row in the settings inspector wad browser
c = [wadList count];
for (i=0 ; i<c ; i++)
{
name = (char *)[wadList elementAt:i];
if (!strcmp(name, wf))
{
[[pis_wads_i matrixInColumn:0] selectCellAt: i : 0];
break;
}
}
// update the texture inspector
[texturepalette_i initPaletteFromWadfile:wf ];
[[map_i objectAt: 0] setKey:"wad" toValue: wf];
// [inspcontrol_i changeInspectorTo:i_textures];
[quakeed_i updateAll];
return self;
}
//
// Clicked on a wad name
//
- clickedOnWad:sender
{
id matrix;
int row;
char *name;
matrix = [sender matrixInColumn:0];
row = [matrix selectedRow];
name = (char *)[wadList elementAt:row];
[self setTextureWad: name];
return self;
}
//
// Read in the <name>.QE_Project file
//
- parseProjectFile
{
char *path;
int rtn;
path = [preferences_i getProjectPath];
if (!path || !path[0] || access(path,0))
{
rtn = NSRunAlertPanel("Project Error!",
"A default project has not been found.\n"
, "Open Project", NULL, NULL);
if ([self openProject] == nil)
while (1) // can't run without a project
[NSApp terminate: self];
return self;
}
[self openProjectFile:path];
return self;
}
//
// Loads and parses a project file
//
- openProjectFile:(char *)path
{
FILE *fp;
struct stat s;
strcpy(path_projectinfo,path);
projectInfo = NULL;
fp = fopen(path,"r+t");
if (fp == NULL)
return self;
stat(path,&s);
lastModified = s.st_mtime;
projectInfo = [(Dict *)[Dict alloc] initFromFile:fp];
fclose(fp);
return self;
}
- (char *)currentProjectFile
{
return path_projectinfo;
}
//
// Open a project file
//
- openProject
{
char path[128];
id openpanel;
int rtn;
char *projtypes[2] = {"qpr",NULL};
char **filenames;
char *dir;
openpanel = [OpenPanel new];
[openpanel allowMultipleFiles:NO];
[openpanel chooseDirectories:NO];
rtn = [openpanel runModalForTypes:projtypes];
if (rtn == NS_OKTAG)
{
(const char *const *)filenames = [openpanel filenames];
dir = (char *)[openpanel directory];
sprintf(path,"%s/%s",dir,filenames[0]);
strcpy(path_projectinfo,path);
[self openProjectFile:path];
return self;
}
return nil;
}
//
// Search for a string in a List of strings
//
- (int)searchForString:(char *)str in:(id)obj
{
int i;
int max;
char *s;
max = [obj count];
for (i = 0;i < max; i++)
{
s = (char *)[obj elementAt:i];
if (!strcmp(s,str))
return 1;
}
return 0;
}
- (char *)getMapDirectory
{
return path_mapdirectory;
}
- (char *)getFinalMapDirectory
{
return path_finalmapdir;
}
- (char *)getProgDirectory
{
return path_progdir;
}
//
// Return the WAD name for cmd-8
//
- (char *)getWAD8
{
if (!path_wad8[0])
return NULL;
return path_wad8;
}
//
// Return the WAD name for cmd-9
//
- (char *)getWAD9
{
if (!path_wad9[0])
return NULL;
return path_wad9;
}
//
// Return the WAD name for cmd-0
//
- (char *)getWAD0
{
if (!path_wad0[0])
return NULL;
return path_wad0;
}
//
// Return the FULLVIS cmd string
//
- (char *)getFullVisCmd
{
if (!string_fullvis[0])
return NULL;
return string_fullvis;
}
//
// Return the FASTVIS cmd string
//
- (char *)getFastVisCmd
{
if (!string_fastvis[0])
return NULL;
return string_fastvis;
}
//
// Return the NOVIS cmd string
//
- (char *)getNoVisCmd
{
if (!string_novis[0])
return NULL;
return string_novis;
}
//
// Return the RELIGHT cmd string
//
- (char *)getRelightCmd
{
if (!string_relight[0])
return NULL;
return string_relight;
}
//
// Return the LEAKTEST cmd string
//
- (char *)getLeaktestCmd
{
if (!string_leaktest[0])
return NULL;
return string_leaktest;
}
- (char *)getEntitiesCmd
{
if (!string_entities[0])
return NULL;
return string_entities;
}
@end
//====================================================
// C Functions
//====================================================
//
// Change a character to a different char in a string
//
void changeString(char cf,char ct,char *string)
{
int j;
for (j = 0;j < strlen(string);j++)
if (string[j] == cf)
string[j] = ct;
}

View file

@ -0,0 +1,98 @@
extern id quakeed_i;
extern BOOL filter_light, filter_path, filter_entities;
extern BOOL filter_clip_brushes, filter_water_brushes, filter_world;
extern UserPath *upath;
extern id g_cmd_out_i;
double I_FloatTime (void);
void NopSound (void);
void qprintf (char *fmt, ...); // prints text to cmd_out_i
@interface QuakeEd : NSWindow
{
BOOL dirty;
char filename[1024]; // full path with .map extension
// UI objects
id brushcount_i;
id entitycount_i;
id regionbutton_i;
id show_coordinates_i;
id show_names_i;
id filter_light_i;
id filter_path_i;
id filter_entities_i;
id filter_clip_i;
id filter_water_i;
id filter_world_i;
id cmd_in_i; // text fields
id cmd_out_i;
id xy_drawmode_i; // passed over to xyview after init
}
- setDefaultFilename;
- (char *)currentFilename;
- updateAll; // when a model has been changed
- updateCamera; // when the camera has moved
- updateXY;
- updateZ;
- updateAll:sender;
- newinstance; // force next flushwindow to clear all instance drawing
- redrawInstance; // erase and redraw all instance now
- appDidInit:sender;
- appWillTerminate:sender;
- openProject:sender;
- textCommand: sender;
- applyRegion: sender;
- (BOOL)dirty;
- clear: sender;
- centerCamera: sender;
- centerZChecker: sender;
- changeXYLookUp: sender;
- setBrushRegion: sender;
- setXYRegion: sender;
- open: sender;
- save: sender;
- saveAs: sender;
- doOpen: (char *)fname;
- saveBSP:(char *)cmdline dialog:(BOOL)wt;
- BSP_Full: sender;
- BSP_FastVis: sender;
- BSP_NoVis: sender;
- BSP_relight: sender;
- BSP_stop: sender;
- BSP_entities: sender;
//
// UI querie for other objects
//
- (BOOL)showCoordinates;
- (BOOL)showNames;
@end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,15 @@
/* Generated by the NeXT Project Builder
NOTE: Do NOT change this file -- Project Builder maintains it.
*/
#import <appkit/appkit.h>
void main(int argc, char *argv[]) {
[Application new];
if ([NSApp loadNibSection:"QuakeEd.nib" owner:NSApp withNames:NO])
[NSApp run];
[NSApp free];
exit(0);
}

View file

@ -0,0 +1,158 @@
#define MAX_FACES 16
typedef float vec5_t[5];
typedef struct
{
int numpoints;
vec5_t points[8]; // variable sized
} winding_t;
#define MAX_POINTS_ON_WINDING 64
typedef struct
{
vec3_t normal;
float dist;
} plane_t;
typedef struct
{
// implicit rep
vec3_t planepts[3];
texturedef_t texture;
// cached rep
plane_t plane;
qtexture_t *qtexture;
float light; // 0 - 1.0
winding_t *w;
} face_t;
#define ON_EPSILON 0.1
#define FP_EPSILON 0.01
#define VECTOR_EPSILON 0.0001
#define SIDE_FRONT 0
#define SIDE_BACK 1
#define SIDE_ON 2
winding_t *ClipWinding (winding_t *in, plane_t *split);
winding_t *CopyWinding (winding_t *w);
winding_t *NewWinding (int points);
@interface SetBrush : Object
{
BOOL regioned; // not active
BOOL selected;
BOOL invalid; // not a proper polyhedron
id parent; // the entity this brush is in
vec3_t bmins, bmaxs;
vec3_t entitycolor;
int numfaces;
face_t faces[MAX_FACES];
}
- initOwner: own mins:(float *)mins maxs:(float *)maxs texture:(texturedef_t *)tex;
- initFromTokens: own;
- setMins:(float *)mins maxs:(float *)maxs;
- parent;
- setParent: (id)p;
- setEntityColor: (vec3_t)color;
- calcWindings;
- writeToFILE: (FILE *)f region: (BOOL)reg;
- (BOOL)selected;
- (BOOL)regioned;
- setSelected: (BOOL)s;
- setRegioned: (BOOL)s;
- getMins: (vec3_t)mins maxs: (vec3_t)maxs;
- (BOOL)containsPoint: (vec3_t)pt;
- freeWindings;
- removeIfInvalid;
extern vec3_t region_min, region_max;
- newRegion;
- (texturedef_t *)texturedef;
- (texturedef_t *)texturedefForFace: (int)f;
- setTexturedef: (texturedef_t *)tex;
- setTexturedef: (texturedef_t *)tex forFace:(int)f;
- XYDrawSelf;
- ZDrawSelf;
- CameraDrawSelf;
- XYRenderSelf;
- CameraRenderSelf;
- hitByRay: (vec3_t)p1 : (vec3_t) p2 : (float *)time : (int *)face;
//
// single brush actions
//
extern int numcontrolpoints;
extern float *controlpoints[MAX_FACES*3];
- getZdragface: (vec3_t)dragpoint;
- getXYdragface: (vec3_t)dragpoint;
- getXYShearPoints: (vec3_t)dragpoint;
- addFace: (face_t *)f;
//
// multiple brush actions
//
- carveByClipper;
extern vec3_t sb_translate;
- translate;
extern id carve_in, carve_out;
- select;
- deselect;
- remove;
- flushTextures;
extern vec3_t sb_mins, sb_maxs;
- addToBBox;
extern vec3_t sel_x, sel_y, sel_z;
extern vec3_t sel_org;
- transform;
- flipNormals;
- carve;
- setCarveVars;
extern id sb_newowner;
- moveToEntity;
- takeCurrentTexture;
extern vec3_t select_min, select_max;
- selectPartial;
- selectComplete;
- regionPartial;
- regionComplete;
extern float sb_floor_dir, sb_floor_dist;
- feetToFloor;
- (int) getNumBrushFaces;
- (face_t *)getBrushFace: (int)which;
@end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,113 @@
typedef union
{
byte chan[4];
unsigned p;
} pixel32_t;
typedef struct
{
char texture[16];
float rotate;
float shift[2];
float scale[2];
} texturedef_t;
typedef struct
{
char name[16];
int width;
int height;
NSBitmapImageRep *rep;
void *data;
pixel32_t flatcolor;
} qtexture_t;
#define MAX_TEXTURES 1024
extern int tex_count;
extern qtexture_t qtextures[MAX_TEXTURES];
void TEX_InitFromWad (char *path);
qtexture_t *TEX_ForName (char *name);
typedef struct
{
id image; // NSImage
NSRect r;
char *name;
int index;
int display; // flag (on/off)
} texpal_t;
#define TEX_INDENT 10
#define TEX_SPACING 16
extern id texturepalette_i;
@interface TexturePalette:Object
{
char currentwad[1024];
id textureList_i;
id textureView_i;
id searchField_i;
id sizeField_i;
id field_Xshift_i;
id field_Yshift_i;
id field_Xscale_i;
id field_Yscale_i;
id field_Rotate_i;
int viewWidth;
int viewHeight;
int selectedTexture;
}
- (char*)currentWad;
- initPaletteFromWadfile:(char *)wf;
- computeTextureViewSize;
- alphabetize;
- getList;
- (int)getSelectedTexture;
- setSelectedTexture:(int)which;
- (int)getSelectedTexIndex;
// Called externally
- (char *)getSelTextureName;
- setTextureByName:(char *)name;
// New methods to replace the 2 above ones
- setTextureDef:(texturedef_t *)td;
- getTextureDef:(texturedef_t *)td;
// Action methods
- searchForTexture:sender;
- clearTexinfo: sender;
- incXShift:sender;
- decXShift:sender;
- incYShift:sender;
- decYShift:sender;
- incRotate: sender;
- decRotate: sender;
- incXScale:sender;
- decXScale:sender;
- incYScale:sender;
- decYScale:sender;
- texturedefChanged: sender;
- onlyShowMapTextures:sender;
- (int) searchForTextureInPalette:(char *)texture;
- setDisplayFlag:(int)index to:(int)value;
@end

View file

@ -0,0 +1,818 @@
#import "qedefs.h"
id texturepalette_i;
#define TYP_MIPTEX 67
int tex_count;
qtexture_t qtextures[MAX_TEXTURES];
typedef struct
{
char name[16];
unsigned width, height;
unsigned offsets[4]; // four mip maps stored
} miptex_t;
unsigned tex_palette[256];
unsigned badtex_d[] =
{
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
0,0,0,0,0,0,0,0,
0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff
};
qtexture_t badtex = {"notexture",16,16,NULL, badtex_d, {0,0,255,255}};
/*
==============
TEX_InitPalette
==============
*/
void TEX_InitPalette (byte *pal)
{
int r,g,b,v;
int i;
for (i=0 ; i<256 ; i++)
{
r = pal[0];
g = pal[1];
b = pal[2];
pal += 3;
v = (r<<24) + (g<<16) + (b<<8) + 255;
v = BigLong (v);
tex_palette[i] = v;
}
}
/*
=================
TEX_ImageFromMiptex
=================
*/
void TEX_ImageFromMiptex (miptex_t *qtex)
{
NSBitmapImageRep *bm;
byte *source;
unsigned *dest;
int width, height, i, count;
qtexture_t *q;
int tr, tg, tb;
width = LittleLong(qtex->width);
height = LittleLong(qtex->height);
bm = [[NSBitmapImageRep alloc]
initData: NULL
pixelsWide: width
pixelsHigh: height
bitsPerSample: 8
samplesPerPixel:3
hasAlpha: NO
isPlanar: NO
colorSpace: NS_RGBColorSpace
bytesPerRow: width*4
bitsPerPixel: 32];
dest = (unsigned *)[bm data];
count = width*height;
source = (byte *)qtex + LittleLong(qtex->offsets[0]);
q = &qtextures[tex_count];
tex_count++;
q->width = width;
q->height = height;
q->rep = bm;
q->data = dest;
tr = tg = tb = 0;
for (i=0 ; i<count ; i++)
{
dest[i] = tex_palette[source[i]];
tr += ((pixel32_t *)&dest[i])->chan[0];
tg += ((pixel32_t *)&dest[i])->chan[1];
tb += ((pixel32_t *)&dest[i])->chan[2];
}
q->flatcolor.chan[0] = tr / count;
q->flatcolor.chan[1] = tg / count;
q->flatcolor.chan[2] = tb / count;
q->flatcolor.chan[3] = 0xff;
}
//=============================================================================
typedef struct
{
char identification[4]; // should be WAD2 or 2DAW
int numlumps;
int infotableofs;
} wadinfo_t;
typedef struct
{
int filepos;
int disksize;
int size; // uncompressed
char type;
char compression;
char pad1, pad2;
char name[16]; // must be null terminated
} lumpinfo_t;
/*
=================
TEX_InitFromWad
=================
*/
void TEX_InitFromWad (char *path)
{
int i;
char local[1024];
char newpath[1024];
byte *wadfile;
wadinfo_t *wadinfo;
lumpinfo_t *lumpinfo;
int numlumps;
float start, stop;
start = I_FloatTime ();
strcpy(newpath, [preferences_i getProjectPath]);
strcat(newpath,"/");
strcat(newpath, path);
// free any textures
for (i=0 ; i<tex_count ; i++)
[qtextures[i].rep free];
tex_count = 0;
// try and use the cached wadfile
sprintf (local, "/qcache%s", newpath);
Sys_UpdateFile (local, newpath);
LoadFile (local, (void **)&wadfile);
wadinfo = (wadinfo_t *)wadfile;
if (strncmp (wadfile, "WAD2", 4))
{
unlink (local);
Error ("TEX_InitFromWad: %s isn't a wadfile", newpath);
}
numlumps = LittleLong (wadinfo->numlumps);
lumpinfo = (lumpinfo_t *)(wadfile + LittleLong (wadinfo->infotableofs));
if (strcmp (lumpinfo->name, "PALETTE"))
{
unlink (local);
Error ("TEX_InitFromWad: %s doesn't have palette as 0",path);
}
TEX_InitPalette (wadfile + LittleLong(lumpinfo->filepos));
lumpinfo++;
for (i=1 ; i<numlumps ; i++, lumpinfo++)
{
if (lumpinfo->type != TYP_MIPTEX)
Error ("TEX_InitFromWad: %s is not a miptex!",lumpinfo->name);
CleanupName (lumpinfo->name,qtextures[tex_count].name);
TEX_ImageFromMiptex ( (miptex_t *)(wadfile +
LittleLong(lumpinfo->filepos) ));
}
free (wadfile);
stop = I_FloatTime ();
qprintf ("loaded %s (%5.1f)", local, stop - start);
}
/*
=================
TEX_NumForName
=================
*/
qtexture_t *TEX_ForName (char *name)
{
char newname[16];
int i;
qtexture_t *q;
CleanupName (name, newname);
for (i=0,q = qtextures ; i< tex_count ; i++, q++)
{
if (!strcmp(name, q->name))
return q;
}
return &badtex;
}
//===========================================================================
@implementation TexturePalette
- init
{
[super init];
texturepalette_i = self;
selectedTexture = -1;
return self;
}
- display
{
[[textureView_i superview] display];
return self;
}
- (char *)currentWad
{
return currentwad;
}
- initPaletteFromWadfile:(char *)wf
{
int i;
texpal_t t;
qtexture_t *q;
strcpy (currentwad, wf);
[map_i makeGlobalPerform: @selector(flushTextures)];
selectedTexture = -1;
// Init textures WAD
TEX_InitFromWad(wf);
// Create STORAGE
if (textureList_i)
[textureList_i empty];
else
textureList_i = [[Storage alloc]
initCount:0
elementSize:sizeof(texpal_t)
description:NULL];
// Init STORAGE
for (i = 0,q=qtextures;i < tex_count; i++,q++)
{
t.image = q->rep;
t.r.size.width = [t.image pixelsWide];
if (t.r.size.width < 64)
t.r.size.width = 64;
t.r.size.height = [t.image pixelsHigh] + TEX_SPACING;
t.name = q->name;
t.index = i;
t.display = 1;
[textureList_i addElement:&t];
}
// Calculate size of TextureView
[self alphabetize];
[self computeTextureViewSize];
[textureView_i setParent:self];
[self setSelectedTexture:0];
return self;
}
// Return texture STORAGE list
- getList
{
return textureList_i;
}
// Alphabetize texture list - reverse order!
- alphabetize
{
int i;
int max;
texpal_t *t1p;
texpal_t *t2p;
texpal_t t1;
texpal_t t2;
int found;
max = [textureList_i count];
found = 1;
while(found)
{
found = 0;
for (i = 0;i < max-1;i++)
{
t1p = [textureList_i elementAt:i];
t2p = [textureList_i elementAt:i+1];
if (strcmp(t1p->name,t2p->name) < 0)
{
t1 = *t1p;
t2 = *t2p;
[textureList_i replaceElementAt:i with:&t2];
[textureList_i replaceElementAt:i+1 with:&t1];
found = 1;
}
}
}
return self;
}
- computeTextureViewSize
{
int i;
int max;
int x;
texpal_t *t;
int y;
id view;
NSRect b;
int maxwidth;
int maxheight;
NSPoint pt;
max = [textureList_i count];
y = 0;
maxheight = 0;
x = TEX_INDENT;
view = [textureView_i superview];
[view getBounds:&b];
maxwidth = b.size.width;
for (i = 0;i < max; i++)
{
t = [textureList_i elementAt:i];
if (x + t->r.size.width + TEX_INDENT > maxwidth)
{
x = TEX_INDENT;
y += maxheight;
maxheight = 0;
}
if (t->r.size.height > maxheight)
maxheight = t->r.size.height;
t->r.origin.x = x;
t->r.origin.y = y;
x += t->r.size.width + TEX_INDENT;
if (i == max - 1)
y += t->r.size.height;
}
viewWidth = maxwidth;
viewHeight = y + TEX_SPACING;
[textureView_i sizeTo:viewWidth :viewHeight];
pt.x = pt.y = 0;
[textureView_i scrollPoint:&pt];
return self;
}
- windowResized
{
[self computeTextureViewSize];
return self;
}
- texturedefChanged: sender
{
if ([map_i numSelected])
{
if ( [[map_i currentEntity] modifiable] )
{
[map_i makeSelectedPerform: @selector(takeCurrentTexture)];
[quakeed_i updateAll];
}
else
qprintf ("can't modify spawned entities");
}
[quakeed_i makeFirstResponder: quakeed_i];
return self;
}
- clearTexinfo: sender
{
[field_Xshift_i setFloatValue:0];
[field_Yshift_i setFloatValue:0];
[field_Xscale_i setFloatValue:1];
[field_Yscale_i setFloatValue:1];
[field_Rotate_i setFloatValue:0];
[self texturedefChanged: self];
return self;
}
//
// Set the selected texture
//
- setSelectedTexture:(int)which
{
texpal_t *t;
NSRect r;
char string[16];
// wipe the fields
[self clearTexinfo: self];
if (which != selectedTexture)
{
[textureView_i deselect];
selectedTexture = which;
t = [textureList_i elementAt:which];
r = t->r;
r.size.width += TEX_INDENT*2;
r.size.height += TEX_INDENT*2;
r.origin.x -= TEX_INDENT;
r.origin.y -= TEX_INDENT;
[textureView_i scrollRectToVisible:&r];
[textureView_i display];
sprintf(string,"%d x %d",(int)t->r.size.width,
(int)t->r.size.height - TEX_SPACING);
[sizeField_i setStringValue:string];
}
[self texturedefChanged:self];
return self;
}
//
// Return the selected texture index
//
- (int)getSelectedTexture
{
return selectedTexture;
}
//
// Return the original tex_ index of the selected texture
// so the texture info can be indexed from tex_images, etc.
//
- (int)getSelectedTexIndex
{
texpal_t *t;
if (selectedTexture == -1)
return -1;
t = [textureList_i elementAt:selectedTexture];
return t->index;
}
//
// Return the name of the selected texture
//
- (char *)getSelTextureName
{
texpal_t *t;
if (selectedTexture == -1)
return NULL;
t = [textureList_i elementAt:selectedTexture];
return t->name;
}
//
// Set selected texture by texture name
//
- setTextureByName:(char *)name
{
texpal_t *t;
int i;
int max;
max = [textureList_i count];
CleanupName(name,name);
for (i = 0;i < max;i++)
{
t = [textureList_i elementAt:i];
if (!strcmp(t->name,name))
{
[self setSelectedTexture: i];
return self;
}
}
return self;
}
//===================================================
//
// Action methods
//
//===================================================
//
// Search for texture named in searchField
//
- searchForTexture:sender
{
int i;
int max;
int len;
char name[32];
texpal_t *t;
if (selectedTexture == -1)
return self;
max = [textureList_i count];
strcpy(name,(const char *)[sender stringValue]);
[sender setStringValue:strupr(name)];
len = strlen(name);
for (i = selectedTexture-1;i >= 0; i--)
{
t = [textureList_i elementAt:i];
if (!strncmp(t->name,name,len))
{
[self setTextureByName:t->name];
[sender selectText:sender];
[self texturedefChanged:self];
return self;
}
}
for (i = max-1;i >= selectedTexture; i--)
{
t = [textureList_i elementAt:i];
if (!strncmp(t->name,name,len))
{
[self setTextureByName:t->name];
[sender selectText:sender];
[self texturedefChanged:self];
return self;
}
}
[self texturedefChanged:self];
return self;
}
//
// Set texture def from outside TexturePalette
//
- setTextureDef:(texturedef_t *)td
{
[self setTextureByName:td->texture];
[field_Xshift_i setFloatValue:td->shift[0]];
[field_Yshift_i setFloatValue:td->shift[1]];
[field_Xscale_i setFloatValue:td->scale[0]];
[field_Yscale_i setFloatValue:td->scale[1]];
[field_Rotate_i setFloatValue:td->rotate];
[self texturedefChanged:self];
return self;
}
//
// Return the current texture def to passed *
//
- getTextureDef:(texturedef_t *)td
{
if (selectedTexture == -1)
{
memset (td, 0, sizeof(*td));
strcpy (td->texture, "notexture");
return self;
}
strncpy(td->texture,[self getSelTextureName],16);
td->shift[0] = [field_Xshift_i floatValue];
td->shift[1] = [field_Yshift_i floatValue];
td->scale[0] = [field_Xscale_i floatValue];
td->scale[1] = [field_Yscale_i floatValue];
td->rotate = [field_Rotate_i floatValue];
return self;
}
//============================================================================
//
// Change value in a field
//
- changeField:(id)field by:(int)amount
{
int val;
val = [field intValue];
val += amount;
[field setIntValue:val];
[self texturedefChanged:self];
return self;
}
//
// Inc/Dec the XShift field
//
- incXShift:sender
{
[self changeField:field_Xshift_i by:8];
return self;
}
- decXShift:sender
{
[self changeField:field_Xshift_i by:-8];
return self;
}
//
// Inc/Dec the YShift field
//
- incYShift:sender
{
[self changeField:field_Yshift_i by:8];
return self;
}
- decYShift:sender
{
[self changeField:field_Yshift_i by:-8];
return self;
}
//
// Inc/Dec the Rotate field
//
- incRotate:sender
{
[self changeField:field_Rotate_i by:90];
return self;
}
- decRotate:sender
{
[self changeField:field_Rotate_i by:-90];
return self;
}
//
// Inc/Dec the Xscale field
//
- incXScale:sender
{
[field_Xscale_i setIntValue: 1];
[self texturedefChanged:self];
return self;
}
- decXScale:sender
{
[field_Xscale_i setIntValue: -1];
[self texturedefChanged:self];
return self;
}
//
// Inc/Dec the Yscale field
//
- incYScale:sender
{
[field_Yscale_i setIntValue: 1];
[self texturedefChanged:self];
return self;
}
- decYScale:sender
{
[field_Yscale_i setIntValue: -1];
[self texturedefChanged:self];
return self;
}
//============================================================================
//
// Search for texture in entire palette
// Return index of texturedef, or -1 if unsuccessful
//
- (int) searchForTextureInPalette:(char *)texture
{
int i;
int max;
char name[32];
texpal_t *t;
if (selectedTexture == -1)
return -1;
max = [textureList_i count];
strcpy(name,texture);
for (i = 0; i < max; i++)
{
t = [textureList_i elementAt:i];
if (!strcmp(t->name,name))
return i;
}
return -1;
};
//
// Scan thru map & only display textures that are in map
//
- onlyShowMapTextures:sender
{
int max;
int i;
int j;
id brushes;
SetBrush *b;
int numfaces;
face_t *f;
int index;
// Turn 'em off
if ([sender intValue])
{
max = [textureList_i count];
for (i = 0;i < max; i++)
[self setDisplayFlag:i to:0];
brushes = [map_i objectAt:0];
max = [brushes count];
for (i = 0;i < max; i++)
{
b = (SetBrush *)[brushes objectAt:i];
numfaces = [b getNumBrushFaces];
for (j = 0; j < numfaces; j++)
{
f = [b getBrushFace:j];
index = [self searchForTextureInPalette:f->texture.texture];
if (index >= 0)
[self setDisplayFlag:index to:1];
}
}
}
// Turn 'em on
else
{
max = [textureList_i count];
for (i = 0;i < max; i++)
[self setDisplayFlag:i to:1];
}
[textureView_i display];
return self;
}
- setDisplayFlag:(int)index to:(int)value
{
texpal_t *tp;
tp = [textureList_i elementAt:index];
tp->display = value;
return self;
};
@end

View file

@ -0,0 +1,12 @@
@interface TextureView:NSView
{
id parent_i;
int deselectIndex;
}
- setParent:(id)from;
- deselect;
@end

View file

@ -0,0 +1,152 @@
#import "qedefs.h"
/*
NOTE: I am specifically not using cached image reps, because the data is also needed for texturing the views, and a cached rep would waste tons of space.
*/
@implementation TextureView
- init
{
deselectIndex = -1;
return self;
}
- setParent:(id)from
{
parent_i = from;
return self;
}
- (BOOL)acceptsFirstMouse
{
return YES;
}
- drawSelf:(const NSRect *)rects :(int)rectCount
{
int i;
int max;
id list_i;
texpal_t *t;
int x;
int y;
NSPoint p;
NSRect r;
int selected;
selected = [parent_i getSelectedTexture];
list_i = [parent_i getList];
PSselectfont("Helvetica-Medium",FONTSIZE);
PSrotate(0);
PSsetgray(NS_LTGRAY);
PSrectfill(rects->origin.x, rects->origin.y,
rects->size.width, rects->size.height);
if (!list_i) // WADfile didn't init
return self;
if (deselectIndex != -1)
{
t = [list_i elementAt:deselectIndex];
r = t->r;
r.origin.x -= TEX_INDENT;
r.origin.y -= TEX_INDENT;
r.size.width += TEX_INDENT*2;
r.size.height += TEX_INDENT*2;
PSsetgray(NSGrayComponent(NS_COLORLTGRAY));
PSrectfill(r.origin.x, r.origin.y,
r.size.width, r.size.height);
p = t->r.origin;
p.y += TEX_SPACING;
[t->image drawAt:&p];
PSsetgray(0);
x = t->r.origin.x;
y = t->r.origin.y + 7;
PSmoveto(x,y);
PSshow(t->name);
PSstroke();
deselectIndex = -1;
}
max = [list_i count];
PSsetgray(0);
for (i = 0;i < max; i++)
{
t = [list_i elementAt:i];
r = t->r;
r.origin.x -= TEX_INDENT/2;
r.size.width += TEX_INDENT;
r.origin.y += 4;
if (NSIntersectsRect(&rects[0],&r) == YES &&
t->display)
{
if (selected == i)
{
PSsetgray(1);
PSrectfill(r.origin.x,r.origin.y,
r.size.width,r.size.height);
PSsetrgbcolor(1,0,0);
PSrectstroke(r.origin.x, r.origin.y,
r.size.width, r.size.height);
PSsetgray(0);
}
p = t->r.origin;
p.y += TEX_SPACING;
[t->image drawAt:&p];
x = t->r.origin.x;
y = t->r.origin.y + 7;
PSmoveto(x,y);
PSshow(t->name);
}
}
PSstroke();
return self;
}
- deselect
{
deselectIndex = [parent_i getSelectedTexture];
return self;
}
- mouseDown:(NSEvent *)theEvent
{
NSPoint loc;
int i;
int max;
int oldwindowmask;
texpal_t *t;
id list;
NSRect r;
oldwindowmask = [window addToEventMask:NS_LMOUSEDRAGGEDMASK];
loc = theEvent->location;
[self convertPoint:&loc fromView:NULL];
list = [parent_i getList];
max = [list count];
for (i = 0;i < max; i++)
{
t = [list elementAt:i];
r = t->r;
if (NSPointInRect(&loc,&r) == YES)
{
[self deselect];
[parent_i setSelectedTexture:i];
break;
}
}
[window setEventMask:oldwindowmask];
return self;
}
@end

View file

@ -0,0 +1,42 @@
#import <AppKit/AppKit.h>
extern id things_i;
#define ENTITYNAMEKEY "spawn"
@interface Things:Object
{
id entity_browser_i; // browser
id entity_comment_i; // scrolling text window
id prog_path_i;
int lastSelected; // last row selected in browser
id keyInput_i;
id valueInput_i;
id flags_i;
}
- initEntities;
- newCurrentEntity;
- setSelectedKey:(epair_t *)ep;
- clearInputs;
- (char *)spawnName;
// UI targets
- reloadEntityClasses: sender;
- selectEntity: sender;
- doubleClickEntity: sender;
// Action methods
- addPair:sender;
- delPair:sender;
- setAngle:sender;
- setFlags:sender;
@end

View file

@ -0,0 +1,317 @@
#import "qedefs.h"
id things_i;
@implementation Things
- init
{
[super init];
things_i = self;
lastSelected = 0;
return self;
}
//
// Load the TEXT object with the entity comment
//
- loadEntityComment:(id)obj
{
[entity_comment_i selectAll:self];
[entity_comment_i replaceSel:[obj comments]];
return self;
}
- initEntities
{
char *path;
path = [project_i getProgDirectory];
[prog_path_i setStringValue: path];
[[EntityClassList alloc] initForSourceDirectory: path];
[self loadEntityComment:[entity_classes_i objectAt:lastSelected]];
[entity_browser_i loadColumnZero];
[[entity_browser_i matrixInColumn:0] selectCellAt:lastSelected :0];
[entity_browser_i setDoubleAction: @selector(doubleClickEntity:)];
return self;
}
- selectEntity: sender
{
id matr;
matr = [sender matrixInColumn: 0];
lastSelected = [matr selectedRow];
[self loadEntityComment:[entity_classes_i objectAt:lastSelected]];
[quakeed_i makeFirstResponder: quakeed_i];
return self;
}
- doubleClickEntity: sender
{
[map_i makeEntity: sender];
[quakeed_i makeFirstResponder: quakeed_i];
return self;
}
- (char *)spawnName
{
return [[entity_classes_i objectAt:lastSelected] classname];
}
//
// Flush entity classes & reload them!
//
- reloadEntityClasses: sender
{
EntityClass *ent;
char *path;
path = (char *)[prog_path_i stringValue];
if (!path || !path[0])
{
path = [project_i getProgDirectory];
[prog_path_i setStringValue: path];
}
// Free all entity info in memory...
[entity_classes_i freeObjects];
[entity_classes_i free];
// Now, RELOAD!
[[EntityClassList alloc] initForSourceDirectory: path];
lastSelected = 0;
ent = [entity_classes_i objectAt:lastSelected];
[self loadEntityComment:[entity_classes_i objectAt:lastSelected]];
[entity_browser_i loadColumnZero];
[[entity_browser_i matrixInColumn:0] selectCellAt:lastSelected :0];
[self newCurrentEntity]; // in case flags changed
return self;
}
- selectClass: (char *)class
{
id classent;
classent = [entity_classes_i classForName:class];
if (!classent)
return self;
lastSelected = [entity_classes_i indexOf: classent];
if (lastSelected < 0)
lastSelected = 0;
[self loadEntityComment:classent];
[[entity_browser_i matrixInColumn:0] selectCellAt:lastSelected :0];
[[entity_browser_i matrixInColumn:0] scrollCellToVisible:lastSelected :0];
return self;
}
- newCurrentEntity
{
id ent, classent, cell;
char *classname;
int r, c;
char *flagname;
int flags;
ent = [map_i currentEntity];
classname = [ent valueForQKey: "classname"];
if (ent != [map_i objectAt: 0])
[self selectClass: classname]; // don't reset for world
classent = [entity_classes_i classForName:classname];
flagname = [ent valueForQKey: "spawnflags"];
if (!flagname)
flags = 0;
else
flags = atoi(flagname);
[flags_i setAutodisplay: NO];
for (r=0 ; r<4 ; r++)
for (c=0 ; c<3 ; c++)
{
cell = [flags_i cellAt: r : c];
if (c < 2)
{
flagname = [classent flagName: c*4 + r];
[cell setTitle: flagname];
}
[cell setIntValue: (flags & (1<< ((c*4)+r)) ) > 0];
}
[flags_i setAutodisplay: YES];
[flags_i display];
// [keyInput_i setStringValue: ""];
// [valueInput_i setStringValue: ""];
[keypairview_i calcViewSize];
[keypairview_i display];
[quakeed_i makeFirstResponder: quakeed_i];
return self;
}
//
// Clicked in the Keypair view - set as selected
//
- setSelectedKey:(epair_t *)ep;
{
[keyInput_i setStringValue:ep->key];
[valueInput_i setStringValue:ep->value];
[valueInput_i selectText:self];
return self;
}
- clearInputs
{
// [keyInput_i setStringValue: ""];
// [valueInput_i setStringValue: ""];
[quakeed_i makeFirstResponder: quakeed_i];
return self;
}
//
// Action methods
//
-addPair:sender
{
char *key, *value;
key = (char *)[keyInput_i stringValue];
value = (char *)[valueInput_i stringValue];
[ [map_i currentEntity] setKey: key toValue: value ];
[keypairview_i calcViewSize];
[keypairview_i display];
[self clearInputs];
[quakeed_i updateXY];
return self;
}
-delPair:sender
{
[quakeed_i makeFirstResponder: quakeed_i];
[ [map_i currentEntity] removeKeyPair: (char *)[keyInput_i stringValue] ];
[keypairview_i calcViewSize];
[keypairview_i display];
[self clearInputs];
[quakeed_i updateXY];
return self;
}
//
// Set the key/value fields to "angle <button value>"
//
- setAngle:sender
{
const char *title;
char value[10];
title = [[sender selectedCell] title];
if (!strcmp(title,"Up"))
strcpy (value, "-1");
else if (!strcmp(title,"Dn"))
strcpy (value, "-2");
else
strcpy (value, title);
[keyInput_i setStringValue:"angle"];
[valueInput_i setStringValue:value];
[self addPair:NULL];
[self clearInputs];
[quakeed_i updateXY];
return self;
}
- setFlags:sender
{
int flags;
int r, c, i;
id cell;
char str[20];
[self clearInputs];
flags = 0;
for (r=0 ; r<4 ; r++)
for (c=0 ; c<3 ; c++)
{
cell = [flags_i cellAt: r : c];
i = ([cell intValue] > 0);
flags |= (i<< ((c*4)+r));
}
if (!flags)
[[map_i currentEntity] removeKeyPair: "spawnflags"];
else
{
sprintf (str, "%i", flags);
[[map_i currentEntity] setKey: "spawnflags" toValue: str];
}
[keypairview_i calcViewSize];
[keypairview_i display];
return self;
}
//
// Fill the Entity browser
// (Delegate method - delegated in Interface Builder)
//
- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
id cell;
int max;
int i;
id object;
max = [entity_classes_i count];
i = 0;
while(max--)
{
object = [entity_classes_i objectAt:i];
[matrix addRow];
cell = [matrix cellAt:i++ :0];
[cell setStringValue:[object classname]];
[cell setLeaf:YES];
[cell setLoaded:YES];
}
return i;
}
@end

View file

@ -0,0 +1,72 @@
/*
* UserPath.h by Bruce Blumberg, NeXT Computer, Inc.
*
* You may freely copy,distribute and re-use the code in this example. NeXT
* disclaims any warranty of any kind, expressed or implied, as to its fitness
* for any particular purpose
*
* This file and its associated .m file define a data structure and set of
* functions aimed at facilitating the use of user paths. Here is a simple
* example:
*
* UserPath *arect;
* arect = newUserPath(); // creates an empty user path
* beginUserPath(arect,YES); // initialize user path and cache
* UPmoveto(arect,0.0,0.0); // add moveto to userpath; update bounding box
* UPrlineto(arect,0.0,100.0); // add rlineto to path; update bounding box
* UPrlineto(arect,100.0,0.0); // add rlineto to path; update bounding box
* UPrlineto(arect,0.0,-100.0); // add rlineto to path; update bounding box
* closePath(arect); // close path
* endUserPath(arect,dps_stroke); // close user path and specify operator
* sendUserPath(arect);
*
* As you will note, the set of routines manage the allocation and growth of
* the operator and operand arrays, as well as the calculation of the bounding
* box. A user path created via these functions may be optionally cached down
* at the window server, or repeatedly sent down. The user paths created by
* this set of functions are all allocated in a unique zone.
*
* Note: the associated file is a .m file because it pulls in some .h files
* which reference objective C methods.
*/
#import <objc/objc.h>
#import <AppKit/NSGraphicsContext.h>
typedef struct _UP {
float *points;
int numberOfPoints;
char *ops;
NSPoint cp;
int numberOfOps;
int max;
float bbox[4];
int opForUserPath;
BOOL ping;
} UserPath;
/* UserPath functions */
NSZone *userPathZone();
UserPath *newUserPath();
void freeUserPath(UserPath *up);
void debugUserPath(UserPath *up, BOOL shouldPing);
void growUserPath(UserPath *up);
void beginUserPath(UserPath *up, BOOL cache);
void endUserPath(UserPath *up, int op);
int sendUserPath(UserPath *up);
void UPmoveto(UserPath *up, float x, float y);
void UPrmoveto(UserPath *up, float x, float y);
void UPlineto(UserPath *up, float x, float y);
void UPrlineto(UserPath *up, float x, float y);
void UPcurveto(UserPath *up, float x1, float y1, float x2, float y2, float x3,
float y3);
void UPrcurveto(UserPath *up, float dx1, float dy1, float dx2, float dy2,
float dx3, float dy3);
void UParc(UserPath *up, float x, float y, float r, float ang1, float ang2);
void UParcn(UserPath *up, float x, float y, float r, float ang1, float ang2);
void UParct(UserPath *up, float x1, float y1, float x2, float y2, float r);
void closePath(UserPath *up);
void addPts(UserPath *up, float x, float y);
void addOp(UserPath *up, int op);
void add(UserPath *up, int op, float x, float y);
void checkBBox(UserPath *up, float x, float y);

View file

@ -0,0 +1,209 @@
/*
* UserPath.m by Bruce Blumberg, NeXT Computer, Inc.
*
* You may freely copy,distribute and re-use the code in this example. NeXT
* disclaims any warranty of any kind, expressed or implied, as to its fitness
* for any particular purpose
*
*/
#import "UserPath.h"
#import <mach/mach_init.h>
#import <appkit/graphics.h>
#import <appkit/errors.h>
#import <math.h>
#import <libc.h>
static NSZone *upZone = NULL;
NSZone *userPathZone()
/* Creates a unique zone for use by all user paths */
{
if (!upZone) {
upZone = NSCreateZone(vm_page_size, vm_page_size, 1);
}
return upZone;
}
UserPath *newUserPath()
/* Creates a new User Path in the zone returned by userPathZone */
{
UserPath *up;
up = (UserPath *)NSZoneMalloc(userPathZone(), sizeof(UserPath));
up->max = 8192; // JDC
up->points = (float *)NSZoneMalloc(userPathZone(),
sizeof(float) * up->max);
up->ops = (char *)NSZoneMalloc(userPathZone(),
(2 + (up->max / 2)) * sizeof(char));
up->ping = NO;
return up;
}
void freeUserPath(UserPath *up)
/* Frees User Path and its associated buffers */
{
free(up->points);
free(up->ops);
free(up);
return;
}
void growUserPath(UserPath *up)
/*
* grows the associated buffers as necessary. buffer size doubles on each
* call. You never need to call grow directly as it is called as needed by the
* methods and functions which add elements into the buffer
*/
{
/* double the size of the internal buffers */
printf ("growUserPath\n");
up->max *= 2;
up->points = (float *)NSZoneRealloc(userPathZone(), up->points,
sizeof(float) * up->max);
up->ops = (char *)NSZoneRealloc(userPathZone(), up->ops,
(2 + (up->max / 2)) * sizeof(char));
return;
}
void beginUserPath(UserPath *up, BOOL cache)
/*
* Call this to start generating a user path. The cache argument specifies if
* you want the user path cached at the server (i.e. dps_ucache). In either
* case, the UserPath object will automatically calculate the bounding box for
* the path and add the dps_setbbox operator.
*/
{
up->numberOfPoints = up->numberOfOps = 0;
up->cp.x = up->cp.y = 0;
up->bbox[0] = up->bbox[1] = 1.0e6;
up->bbox[2] = up->bbox[3] = -1.0e6;
if (cache) {
up->ops[up->numberOfOps++] = dps_ucache;
}
up->ops[up->numberOfOps++] = dps_setbbox;
up->opForUserPath = 0;
return;
}
void endUserPath(UserPath *up, int op)
/*
* Call this to stop filling the path. Note this does not send the userpath to
* the server -- use sendUserPath. The op argument should be one of the
* following:
* dps_uappend, dps_ufill ,dps_ueofill, dps_ustroke, dps_ustrokepath,
* dps_inufill, dps_inueofill, dps_inustroke, dps_def, dps_put.
* These are defined in <dpsclient/dpsNext.h.
*/
{
up->opForUserPath = op;
return;
}
void UPdebug(UserPath *up, BOOL shouldPing)
/*
* Sets ping to YES so that after each time a user path is sent down to the
* window server, an NSPing() is sent after. The purpose is to catch PostScript
* errors that may be generated by the user path. sendUserPath brackets the
* download and the NSPing() in an NS_DURING... NS_HANDLER construct. Normally
* ping is NO.
*/
{
up->ping = shouldPing;
return;
}
int sendUserPath(UserPath *up)
/*
* Call this to send the path down to the server. If ping==YES (set via
* debug:), the function will send an NSPing() after the Path. In any event,
* code is bracketed by a NS_DURING ... NS_HANDLER construct which will try to
* catch postscript errors. If ping==NO (the default) it is unlikely to catch
* errors, with ping==YES it will. Whether you can recover or not is another
* matter. sendUserPath returns 0 on success and -1 on failure. If no previous
* endUserPath: has been sent, will return -2 and will not send the path to the
* server.
*/
{
NSHandler exception;
exception.code = 0;
if (up->opForUserPath != 0) {
NS_DURING
DPSDoUserPath(up->points, up->numberOfPoints, dps_float, up->ops,
up->numberOfOps, up->bbox, up->opForUserPath);
if (up->ping) {
NSPing();
}
NS_HANDLER
exception = NSLocalHandler;
NS_ENDHANDLER
if (exception.code) {
NSReportError(&exception);
if (exception.code == dps_err_ps) {
return -1;
}
} else {
return 0;
}
}
return -1;
}
void UPmoveto(UserPath *up, float x, float y)
/* adds <x y moveto> to user path and updates bounding box */
{
up->ops[up->numberOfOps++] = dps_moveto;
up->points[up->numberOfPoints++] = x;
up->points[up->numberOfPoints++] = y;
if (x < up->bbox[0]) {
up->bbox[0] = x;
}
if (y < up->bbox[1]) {
up->bbox[1] = y;
}
if (x > up->bbox[2]) {
up->bbox[2] = x;
}
if (y > up->bbox[3]) {
up->bbox[3] = y;
}
return;
}
void UPlineto(UserPath *up, float x, float y)
/* adds <x y lineto> to user path and updates bounding box */
{
up->ops[up->numberOfOps++] = dps_lineto;
up->points[up->numberOfPoints++] = x;
up->points[up->numberOfPoints++] = y;
if (x < up->bbox[0]) {
up->bbox[0] = x;
}
if (y < up->bbox[1]) {
up->bbox[1] = y;
}
if (x > up->bbox[2]) {
up->bbox[2] = x;
}
if (y > up->bbox[3]) {
up->bbox[3] = y;
}
return;
}

View file

@ -0,0 +1,66 @@
#import <AppKit/AppKit.h>
#import "mathlib.h"
#import "SetBrush.h"
extern id xyview_i;
#define MINSCALE 0.125
#define MAXSCALE 2.0
extern vec3_t xy_viewnormal; // v_forward for xy view
extern float xy_viewdist; // clip behind this plane
extern NSRect xy_draw_rect;
void linestart (float r, float g, float b);
void lineflush (void);
void linecolor (float r, float g, float b);
void XYmoveto (vec3_t pt);
void XYlineto (vec3_t pt);
typedef enum {dr_wire, dr_flat, dr_texture} drawmode_t;
@interface XYView : NSView
{
NSRect realbounds, newrect, combinedrect;
NSPoint midpoint;
int gridsize;
float scale;
// for textured view
int xywidth, xyheight;
float *xyzbuffer;
unsigned *xypicbuffer;
drawmode_t drawmode;
// UI links
id mode_radio_i;
}
- (float)currentScale;
- setModeRadio: m;
- drawMode: sender;
- setDrawMode: (drawmode_t)mode;
- newSuperBounds;
- newRealBounds: (NSRect *)nb;
- addToScrollRange: (float)x :(float)y;
- setOrigin: (NSPoint *)pt scale: (float)sc;
- centerOn: (vec3_t)org;
- drawMode: sender;
- superviewChanged;
- (int)gridsize;
- (float)snapToGrid: (float)f;
@end

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,11 @@
#import <AppKit/AppKit.h>
@interface ZScrollView : NSScrollView
{
id button1;
}
- initFrame:(NSRect)frameRect button1: b1;
- tile;
@end

View file

@ -0,0 +1,71 @@
#import "qedefs.h"
@implementation ZScrollView
/*
====================
initWithFrame: button:
Initizes a scroll view with a button at it's lower right corner
====================
*/
- initWithFrame:(const NSRect *)frameRect button1:b1
{
[super initWithFrame: frameRect];
[self addSubview: b1];
button1 = b1;
[self setHorizScrollerRequired: YES];
[self setVertScrollerRequired: YES];
[self setBorderType: NS_BEZEL];
return self;
}
/*
================
tile
Adjust the size for the pop up scale menu
=================
*/
- tile
{
NSRect scrollerframe;
[super tile];
[_horizScroller getFrame: &scrollerframe];
[button1 setFrame: &scrollerframe];
scrollerframe.size.width = 0;
[_horizScroller setFrame: &scrollerframe];
return self;
}
-(BOOL) acceptsFirstResponder
{
return YES;
}
- superviewSizeChanged:(const NSSize *)oldSize
{
[super superviewSizeChanged: oldSize];
[[self docView] newSuperBounds];
return self;
}
@end

View file

@ -0,0 +1,42 @@
#import <AppKit/AppKit.h>
#import "mathlib.h"
extern id zview_i;
// zplane controls the objects displayed in the xyview
extern float zplane;
extern float zplanedir;
@interface ZView : NSView
{
float minheight, maxheight;
float oldminheight, oldmaxheight;
float topbound, bottombound; // for floor clipping
float scale;
vec3_t origin;
}
- clearBounds;
- getBounds: (float *)top :(float *)bottom;
- getPoint: (NSPoint *)pt;
- setPoint: (NSPoint *)pt;
- addToHeightRange: (float)height;
- newRealBounds;
- newSuperBounds;
- XYDrawSelf;
- (BOOL)XYmouseDown: (NSPoint *)pt;
- setXYOrigin: (NSPoint *)pt;
- setOrigin: (NSPoint *)pt scale: (float)sc;
@end

View file

@ -0,0 +1,869 @@
#import "qedefs.h"
id zview_i;
id zscrollview_i, zscalemenu_i, zscalebutton_i;
float zplane;
float zplanedir;
@implementation ZView
/*
==================
initWithFrame:
==================
*/
- (id)initWithFrame:(NSRect)frameRect
{
NSPoint pt;
origin[0] = 0.333;
origin[1] = 0.333;
[super initWithFrame:frameRect];
[self allocateGState];
[self clearBounds];
zview_i = self;
scale = 1;
//
// initialize the pop up menus
//
zscalebutton_i = [[NSPopUpButton alloc] init];
[zscalebutton_i setTarget: self];
[zscalebutton_i setAction: @selector(scaleMenuTarget:)];
[zscalebutton_i addItemWithTitle: @"12.5%"];
[zscalebutton_i addItemWithTitle: @"25%"];
[zscalebutton_i addItemWithTitle: @"50%"];
[zscalebutton_i addItemWithTitle: @"75%"];
[zscalebutton_i addItemWithTitle: @"100%"];
[zscalebutton_i addItemWithTitle: @"200%"];
[zscalebutton_i addItemWithTitle: @"300%"];
[zscalebutton_i selectItemAtIndex: 4];
// initialize the scroll view
zscrollview_i = [[ZScrollView alloc]
initFrame: frameRect
button1: zscalebutton_i
];
[zscrollview_i setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
[zscrollview_i setDocumentView: self];
RELEASE (zscrollview_i);
// [_super_view setDrawOrigin: 0 : 0];
minheight = 0;
maxheight = 64;
pt.x = -_bounds.size.width;
pt.y = -128;
[self newRealBounds];
[self setOrigin: &pt scale: 1];
return zscrollview_i;
}
- setXYOrigin: (NSPoint *)pt
{
origin[0] = pt->x + 0.333;
origin[1] = pt->y + 0.333;
return self;
}
- (float)currentScale
{
return scale;
}
/*
===================
setOrigin:scale:
===================
*/
- setOrigin: (NSPoint *)pt scale: (float)sc
{
NSRect sframe;
NSRect newbounds;
//
// calculate the area visible in the cliprect
//
scale = sc;
sframe = [_super_view frame];
newbounds = [_super_view frame];
newbounds.origin = *pt;
newbounds.size.width /= scale;
newbounds.size.height /= scale;
//
// union with the realbounds
//
if (newbounds.origin.y > oldminheight)
{
newbounds.size.height += newbounds.origin.y - oldminheight;
newbounds.origin.y = oldminheight;
}
if (newbounds.origin.y+newbounds.size.height < oldmaxheight)
{
newbounds.size.height += oldmaxheight
- (newbounds.origin.y + newbounds.size.height);
}
//
// redisplay everything
//
//XXX[quakeed_i disableDisplay];
//
// size this view
//
[self setBoundsSize: newbounds.size];
//XXX[self setDrawOrigin: -newbounds.size.width/2 : newbounds.origin.y];
//XXX[self moveTo: -newbounds.size.width/2 : newbounds.origin.y];
//
// scroll and scale the clip view
//
//XXX[_super_view setDrawSize
//XXX : sframe.size.width/scale
//XXX : sframe.size.height/scale];
//XXX[_super_view setDrawOrigin: pt->x : pt->y];
//XXX[quakeed_i reenableDisplay];
[zscrollview_i display];
return self;
}
/*
====================
scaleMenuTarget:
Called when the scaler popup on the window is used
====================
*/
- scaleMenuTarget: sender
{
char const *item;
NSRect visrect, sframe;
float nscale;
item = [[sender titleOfSelectedItem] cString];
sscanf (item,"%f",&nscale);
nscale /= 100;
if (nscale == scale)
return NULL;
// keep the center of the view constant
visrect = [_super_view bounds];
sframe = [_super_view frame];
visrect.origin.x += visrect.size.width/2;
visrect.origin.y += visrect.size.height/2;
visrect.origin.x -= sframe.size.width/2/nscale;
visrect.origin.y -= sframe.size.height/2/nscale;
[self setOrigin: &visrect.origin scale: nscale];
return self;
}
- clearBounds
{
topbound = 999999;
bottombound = -999999;
return self;
}
- getBounds: (float *)top :(float *)bottom;
{
*top = topbound;
*bottom = bottombound;
return self;
}
/*
==================
addToHeightRange:
==================
*/
- addToHeightRange: (float)height
{
if (height < minheight)
minheight = height;
if (height > maxheight)
maxheight = height;
return self;
}
/*
==================
newSuperBounds
When _super_view is resized
==================
*/
- newSuperBounds
{
oldminheight++;
[self newRealBounds];
return self;
}
/*
===================
newRealBounds
Should only change the scroll bars, not cause any redraws.
If realbounds has shrunk, nothing will change.
===================
*/
- newRealBounds
{
NSRect sbounds;
float vistop, visbottom;
if (minheight == oldminheight && maxheight == oldmaxheight)
return self;
oldminheight = minheight;
oldmaxheight = maxheight;
minheight -= 16;
maxheight += 16;
//
// calculate the area visible in the cliprect
//
sbounds = [_super_view bounds];
visbottom = sbounds.origin.y;
vistop = visbottom + sbounds.size.height;
if (vistop > maxheight)
maxheight = vistop;
if (visbottom < minheight)
minheight = visbottom;
if (minheight == _bounds.origin.y && maxheight-minheight == _bounds.size.height)
return self;
sbounds.origin.y = minheight;
sbounds.size.height = maxheight - minheight;
//
// size this view
//
//XXX[quakeed_i disableDisplay];
//XXX[self suspendNotifyAncestorWhenFrameChanged:YES];
[self setBoundsSize: sbounds.size];
//XXX[self setDrawOrigin: -sbounds.size.width/2 : sbounds.origin.y];
//XXX[self moveTo: -sbounds.size.width/2 : sbounds.origin.y];
//XXX[self suspendNotifyAncestorWhenFrameChanged:NO];
//XXX[[_super_view _super_view] reflectScroll: _super_view];
//XXX[quakeed_i reenableDisplay];
//XXX[[[[self _super_view] _super_view] vertScroller] display];
return self;
}
/*
============
drawGrid
Draws tile markings every 64 units, and grid markings at the grid scale if
the grid lines are >= 4 pixels apart
Rect is in global world (unscaled) coordinates
============
*/
- drawGrid: (const NSRect *)rect
{
int y, stopy;
float top,bottom;
int left, right;
int gridsize;
char text[10];
BOOL showcoords;
showcoords = [quakeed_i showCoordinates];
PSsetlinewidth (0);
gridsize = [xyview_i gridsize];
left = _bounds.origin.x;
right = 24;
bottom = rect->origin.y-1;
top = rect->origin.y+rect->size.height+2;
//
// grid
//
// can't just divide by grid size because of negetive coordinate
// truncating direction
//
if (gridsize>= 4/scale)
{
y = floor(bottom/gridsize);
stopy = floor(top/gridsize);
y *= gridsize;
stopy *= gridsize;
if (y<bottom)
y+= gridsize;
beginUserPath (upath,NO);
for ( ; y<=stopy ; y+= gridsize)
if (y&31)
{
UPmoveto (upath, left, y);
UPlineto (upath, right, y);
}
endUserPath (upath, dps_ustroke);
PSsetrgbcolor (0.8,0.8,1.0); // thin grid color
sendUserPath (upath);
}
//
// half tiles
//
y = floor(bottom/32);
stopy = floor(top/32);
if ( ! (((int)y + 4096) & 1) )
y++;
y *= 32;
stopy *= 32;
if (stopy >= top)
stopy -= 32;
beginUserPath (upath,NO);
for ( ; y<=stopy ; y+= 64)
{
UPmoveto (upath, left, y);
UPlineto (upath, right, y);
}
endUserPath (upath, dps_ustroke);
PSsetgray (12.0/16.0);
sendUserPath (upath);
//
// tiles
//
y = floor(bottom/64);
stopy = floor(top/64);
y *= 64;
stopy *= 64;
if (y<bottom)
y+= 64;
if (stopy >= top)
stopy -= 64;
beginUserPath (upath,NO);
PSsetgray (0); // for text
PSselectfont("Helvetica-Medium",10/scale);
PSrotate(0);
for ( ; y<=stopy ; y+= 64)
{
if (showcoords)
{
sprintf (text, "%i",y);
PSmoveto(left,y);
PSshow(text);
}
UPmoveto (upath, left+24, y);
UPlineto (upath, right, y);
}
// divider
UPmoveto (upath, 0, _bounds.origin.y);
UPlineto (upath, 0, _bounds.origin.y + _bounds.size.height);
endUserPath (upath, dps_ustroke);
PSsetgray (10.0/16.0);
sendUserPath (upath);
//
// origin
//
PSsetlinewidth (5);
PSsetgray (4.0/16.0);
PSmoveto (right,0);
PSlineto (left,0);
PSstroke ();
PSsetlinewidth (0.15);
return self;
}
- drawZplane
{
PSsetrgbcolor (0.2, 0.2, 0);
PSarc (0, zplane, 4, 0, M_PI*2);
PSfill ();
return self;
}
/*
===============================================================================
drawSelf
===============================================================================
*/
- drawSelf:(const NSRect *)rects :(int)rectCount
{
NSRect visRect;
minheight = 999999;
maxheight = -999999;
// allways draw the entire bar
[self getVisibleRect:&visRect];
rects = &visRect;
// erase window
NSEraseRect (&rects[0]);
// draw grid
[self drawGrid: &rects[0]];
// draw zplane
// [self drawZplane];
// draw all entities
[map_i makeUnselectedPerform: @selector(ZDrawSelf)];
// possibly resize the view
[self newRealBounds];
return self;
}
/*
==============
XYDrawSelf
==============
*/
- XYDrawSelf
{
PSsetrgbcolor (0,0.5,1.0);
PSsetlinewidth (0.15);
PSmoveto (origin[0]-16, origin[1]-16);
PSrlineto (32,32);
PSmoveto (origin[0]-16, origin[1]+16);
PSrlineto (32,-32);
PSstroke ();
return self;
}
/*
==============
getPoint: (NSPoint *)pt
==============
*/
- getPoint: (NSPoint *)pt
{
pt->x = origin[0] + 0.333; // offset a bit to avoid edge cases
pt->y = origin[1] + 0.333;
return self;
}
- setPoint: (NSPoint *)pt
{
origin[0] = pt->x;
origin[1] = pt->y;
return self;
}
/*
==============================================================================
MOUSE CLICKING
==============================================================================
*/
/*
================
dragLoop:
================
*/
static NSPoint oldreletive;
- dragFrom: (NSEvent *)startevent
useGrid: (BOOL)ug
callback: (void (*) (float dy)) callback
{
NSEvent *event;
NSPoint startpt, newpt;
NSPoint reletive, delta;
int gridsize;
gridsize = [xyview_i gridsize];
startpt = startevent->location;
[self convertPoint:&startpt fromView:NULL];
oldreletive.x = oldreletive.y = 0;
while (1)
{
event = [NSApp getNextEvent:
NSLeftMouseUpMask | NSLeftMouseDraggedMask
| NSRightMouseUpMask | NSRightMouseDraggedMask];
if (event->type == NSLeftMouseUp || event->type == NSRightMouseUp)
break;
newpt = event->location;
[self convertPoint:&newpt fromView:NULL];
reletive.y = newpt.y - startpt.y;
if (ug)
{ // we want truncate towards 0 behavior here
reletive.y = gridsize * (int)(reletive.y / gridsize);
}
if (reletive.y == oldreletive.y)
continue;
delta.y = reletive.y - oldreletive.y;
oldreletive = reletive;
callback (delta.y);
}
return self;
}
//============================================================================
void ZDragCallback (float dy)
{
sb_translate[0] = 0;
sb_translate[1] = 0;
sb_translate[2] = dy;
[map_i makeSelectedPerform: @selector(translate)];
[quakeed_i redrawInstance];
}
- selectionDragFrom: (NSEvent*)theEvent
{
qprintf ("dragging selection");
[self dragFrom: theEvent
useGrid: YES
callback: ZDragCallback ];
[quakeed_i updateCamera];
qprintf ("");
return self;
}
//============================================================================
void ZScrollCallback (float dy)
{
NSRect basebounds;
NSPoint neworg;
float scale;
[ [zview_i _super_view] getBounds: &basebounds];
[zview_i convertRectFromSuperview: &basebounds];
neworg.y = basebounds.origin.y - dy;
scale = [zview_i currentScale];
oldreletive.y -= dy;
[zview_i setOrigin: &neworg scale: scale];
}
- scrollDragFrom: (NSEvent*)theEvent
{
qprintf ("scrolling view");
[self dragFrom: theEvent
useGrid: YES
callback: ZScrollCallback ];
qprintf ("");
return self;
}
//============================================================================
void ZControlCallback (float dy)
{
int i;
for (i=0 ; i<numcontrolpoints ; i++)
controlpoints[i][2] += dy;
[[map_i selectedBrush] calcWindings];
[quakeed_i redrawInstance];
}
- (BOOL)planeDragFrom: (NSEvent*)theEvent
{
NSPoint pt;
vec3_t dragpoint;
if ([map_i numSelected] != 1)
return NO;
pt= theEvent->location;
[self convertPoint:&pt fromView:NULL];
dragpoint[0] = origin[0];
dragpoint[1] = origin[1];
dragpoint[2] = pt.y;
[[map_i selectedBrush] getZdragface: dragpoint];
if (!numcontrolpoints)
return NO;
qprintf ("dragging brush plane");
pt= theEvent->location;
[self convertPoint:&pt fromView:NULL];
[self dragFrom: theEvent
useGrid: YES
callback: ZControlCallback ];
[[map_i selectedBrush] removeIfInvalid];
[quakeed_i updateCamera];
qprintf ("");
return YES;
}
//============================================================================
/*
===================
mouseDown
===================
*/
- (void)mouseDown:(NSEvent *)theEvent
{
NSPoint pt;
int flags;
vec3_t p1;
pt= theEvent->location;
[self convertPoint:&pt fromView:NULL];
p1[0] = origin[0];
p1[1] = origin[1];
p1[2] = pt.y;
flags = theEvent->flags & (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask);
//
// shift click to select / deselect a brush from the world
//
if (flags == NSShiftKeyMask)
{
[map_i selectRay: p1 : p1 : NO];
return;
}
//
// alt click = set entire brush texture
//
if (flags == NSAlternateKeyMask)
{
[map_i setTextureRay: p1 : p1 : YES];
return;
}
//
// control click = position view
//
if (flags == NSControlKeyMask)
{
[cameraview_i setZOrigin: pt.y];
[quakeed_i updateAll];
[cameraview_i ZmouseDown: &pt flags:theEvent->flags];
return;
}
//
// bare click to drag icons or new brush drag
//
if ( flags == 0 )
{
// check eye
if ( [cameraview_i ZmouseDown: &pt flags:theEvent->flags] )
return;
if ([map_i numSelected])
{
if ( pt.x > 0)
{
if ([self planeDragFrom: theEvent])
return;
}
[self selectionDragFrom: theEvent];
return;
}
}
qprintf ("bad flags for click");
NopSound ();
return;
}
/*
===================
rightMouseDown
===================
*/
- (void)rightMouseDown:(NSEvent *)theEvent
{
NSPoint pt;
int flags;
pt= theEvent->location;
[self convertPoint:&pt fromView:NULL];
flags = theEvent->flags & (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask);
//
// click = scroll view
//
if (flags == 0)
{
[self scrollDragFrom: theEvent];
}
qprintf ("bad flags for click");
NopSound ();
}
/*
===============================================================================
XY mouse view methods
===============================================================================
*/
/*
================
modalMoveLoop
================
*/
- modalMoveLoop: (NSPoint *)basept :(vec3_t)movemod : converter
{
vec3_t originbase;
NSEvent *event;
NSPoint newpt;
vec3_t delta;
int i;
VectorCopy (origin, originbase);
//
// modal event loop using instance drawing
//
goto drawentry;
while (event->type != NSLeftMouseUp)
{
//
// calculate new point
//
newpt = event->location;
[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];
drawentry:
//
// instance draw new frame
//
[quakeed_i newinstance];
[self display];
NSPing ();
event = [NSApp getNextEvent:
NSLeftMouseUpMask | NSLeftMouseDraggedMask];
}
//
// draw the brush back into the window buffer
//
// [xyview_i display];
return self;
}
/*
===============
XYmouseDown
===============
*/
- (BOOL)XYmouseDown: (NSPoint *)pt
{
vec3_t movemod;
if (fabs(pt->x - origin[0]) > 16
|| fabs(pt->y - origin[1]) > 16)
return NO;
movemod[0] = 1;
movemod[1] = 1;
movemod[2] = 0;
[self modalMoveLoop: pt : movemod : xyview_i];
return YES;
}
@end

View file

@ -0,0 +1,611 @@
// cmdlib.c
#include "cmdlib.h"
#define PATHSEPERATOR '/'
/*
================
I_FloatTime
================
*/
double I_FloatTime (void)
{
struct timeval tp;
struct timezone tzp;
static int secbase;
gettimeofday(&tp, &tzp);
if (!secbase)
{
secbase = tp.tv_sec;
return tp.tv_usec/1000000.0;
}
return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
}
char com_token[1024];
boolean com_eof;
/*
==============
COM_Parse
Parse a token out of a string
==============
*/
char *COM_Parse (char *data)
{
int c;
int len;
com_eof = false;
len = 0;
com_token[0] = 0;
if (!data)
return NULL;
// skip whitespace
skipwhite:
while ( (c = *data) <= ' ')
{
if (c == 0)
{
com_eof = true;
return NULL; // end of file;
}
data++;
}
// skip // comments
if (c=='/' && data[1] == '/')
{
while (*data && *data != '\n')
data++;
goto skipwhite;
}
// handle quoted strings specially
if (c == '\"')
{
data++;
do
{
c = *data++;
if (c=='\"')
{
com_token[len] = 0;
return data;
}
com_token[len] = c;
len++;
} while (1);
}
// parse single characters
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
{
com_token[len] = c;
len++;
com_token[len] = 0;
return data+1;
}
// parse a regular word
do
{
com_token[len] = c;
data++;
len++;
c = *data;
if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
break;
} while (c>32);
com_token[len] = 0;
return data;
}
/*
================
=
= filelength
=
================
*/
int filelength (int handle)
{
struct stat fileinfo;
if (fstat (handle,&fileinfo) == -1)
{
fprintf (stderr,"Error fstating");
exit (1);
}
return fileinfo.st_size;
}
int tell (int handle)
{
return lseek (handle, 0, L_INCR);
}
char *strupr (char *start)
{
char *in;
in = start;
while (*in)
{
*in = toupper(*in);
in++;
}
return start;
}
char *strlower (char *start)
{
char *in;
in = start;
while (*in)
{
*in = tolower(*in);
in++;
}
return start;
}
char *getcwd (char *path, int length)
{
return getwd(path);
}
/* globals for command line args */
extern int NXArgc;
extern char **NXArgv;
#define myargc NXArgc
#define myargv NXArgv
/*
=============================================================================
MISC FUNCTIONS
=============================================================================
*/
/*
=================
=
= CheckParm
=
= Checks for the given parameter in the program's command line arguments
=
= Returns the argument number (1 to argc-1) or 0 if not present
=
=================
*/
int CheckParm (char *check)
{
int i;
for (i = 1;i<myargc;i++)
{
if ( !stricmp(check, myargv[i]) )
return i;
}
return 0;
}
int SafeOpenWrite (char *filename)
{
int handle;
umask (0);
handle = open(filename,O_RDWR | O_CREAT | O_TRUNC
, 0666);
if (handle == -1)
Error ("Error opening %s: %s",filename,strerror(errno));
return handle;
}
int SafeOpenRead (char *filename)
{
int handle;
handle = open(filename,O_RDONLY);
if (handle == -1)
Error ("Error opening %s: %s",filename,strerror(errno));
return handle;
}
void SafeRead (int handle, void *buffer, long count)
{
int iocount;
iocount = read (handle,buffer,count);
if (iocount != count)
Error ("File read failure");
}
void SafeWrite (int handle, void *buffer, long count)
{
int iocount;
iocount = write (handle,buffer,count);
if (iocount != count)
Error ("File write failure");
}
void *SafeMalloc (long size)
{
void *ptr;
ptr = malloc (size);
if (!ptr)
Error ("Malloc failure for %lu bytes",size);
return ptr;
}
/*
==============
=
= LoadFile
=
= appends a 0 byte
==============
*/
long LoadFile (char *filename, void **bufferptr)
{
int handle;
long length;
void *buffer;
handle = SafeOpenRead (filename);
length = filelength (handle);
buffer = SafeMalloc (length+1);
((char *)buffer)[length] = 0;
SafeRead (handle, buffer, length);
close (handle);
*bufferptr = buffer;
return length;
}
/*
==============
=
= SaveFile
=
==============
*/
void SaveFile (char *filename, void *buffer, long count)
{
int handle;
handle = SafeOpenWrite (filename);
SafeWrite (handle, buffer, count);
close (handle);
}
void DefaultExtension (char *path, char *extension)
{
char *src;
//
// if path doesn't have a .EXT, append extension
// (extension should include the .)
//
src = path + strlen(path) - 1;
while (*src != PATHSEPERATOR && src != path)
{
if (*src == '.')
return; // it has an extension
src--;
}
strcat (path, extension);
}
void DefaultPath (char *path, char *basepath)
{
char temp[128];
if (path[0] == PATHSEPERATOR)
return; // absolute path location
strcpy (temp,path);
strcpy (path,basepath);
strcat (path,temp);
}
void StripFilename (char *path)
{
int length;
length = strlen(path)-1;
while (length > 0 && path[length] != PATHSEPERATOR)
length--;
path[length] = 0;
}
void StripExtension (char *path)
{
int length;
length = strlen(path)-1;
while (length > 0 && path[length] != '.')
length--;
if (length)
path[length] = 0;
}
/*
====================
=
= Extract file parts
=
====================
*/
void ExtractFilePath (char *path, char *dest)
{
char *src;
src = path + strlen(path) - 1;
//
// back up until a \ or the start
//
while (src != path && *(src-1) != PATHSEPERATOR)
src--;
memcpy (dest, path, src-path);
dest[src-path] = 0;
}
void ExtractFileBase (char *path, char *dest)
{
char *src;
src = path + strlen(path) - 1;
//
// back up until a \ or the start
//
while (src != path && *(src-1) != PATHSEPERATOR)
src--;
while (*src && *src != '.')
{
*dest++ = *src++;
}
*dest = 0;
}
void ExtractFileExtension (char *path, char *dest)
{
char *src;
src = path + strlen(path) - 1;
//
// back up until a . or the start
//
while (src != path && *(src-1) != '.')
src--;
if (src == path)
{
*dest = 0; // no extension
return;
}
strcpy (dest,src);
}
/*
==============
=
= ParseNum / ParseHex
=
==============
*/
long ParseHex (char *hex)
{
char *str;
long num;
num = 0;
str = hex;
while (*str)
{
num <<= 4;
if (*str >= '0' && *str <= '9')
num += *str-'0';
else if (*str >= 'a' && *str <= 'f')
num += 10 + *str-'a';
else if (*str >= 'A' && *str <= 'F')
num += 10 + *str-'A';
else
Error ("Bad hex number: %s",hex);
str++;
}
return num;
}
long ParseNum (char *str)
{
if (str[0] == '$')
return ParseHex (str+1);
if (str[0] == '0' && str[1] == 'x')
return ParseHex (str+2);
return atol (str);
}
int GetKey (void)
{
return getchar ();
}
/*
============================================================================
BYTE ORDER FUNCTIONS
============================================================================
*/
#ifdef __BIG_ENDIAN__
short LittleShort (short l)
{
byte b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
short BigShort (short l)
{
return l;
}
long LittleLong (long l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4;
}
long BigLong (long l)
{
return l;
}
float LittleFloat (float l)
{
union {byte b[4]; float f;} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
float BigFloat (float l)
{
return l;
}
#else
short BigShort (short l)
{
byte b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
short LittleShort (short l)
{
return l;
}
long BigLong (long l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4;
}
long LittleLong (long l)
{
return l;
}
float BigFloat (float l)
{
union {byte b[4]; float f;} in, out;
in.f = l;
out.b[0] = in.b[3];
out.b[1] = in.b[2];
out.b[2] = in.b[1];
out.b[3] = in.b[0];
return out.f;
}
float LittleFloat (float l)
{
return l;
}
#endif

View file

@ -0,0 +1,62 @@
// cmdlib.h
#ifndef __CMDLIB__
#define __CMDLIB__
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#define strcmpi strcasecmp
#define stricmp strcasecmp
char *strupr (char *in);
char *strlower (char *in);
int filelength (int handle);
int tell (int handle);
#ifndef __BYTEBOOL__
#define __BYTEBOOL__
typedef enum {false, true} boolean;
typedef unsigned char byte;
#endif
double I_FloatTime (void);
int GetKey (void);
void Error (char *error, ...);
int CheckParm (char *check);
int SafeOpenWrite (char *filename);
int SafeOpenRead (char *filename);
void SafeRead (int handle, void *buffer, long count);
void SafeWrite (int handle, void *buffer, long count);
void *SafeMalloc (long size);
long LoadFile (char *filename, void **bufferptr);
void SaveFile (char *filename, void *buffer, long count);
void DefaultExtension (char *path, char *extension);
void DefaultPath (char *path, char *basepath);
void StripFilename (char *path);
void StripExtension (char *path);
void ExtractFilePath (char *path, char *dest);
void ExtractFileBase (char *path, char *dest);
void ExtractFileExtension (char *path, char *dest);
long ParseNum (char *str);
short BigShort (short l);
short LittleShort (short l);
long BigLong (long l);
long LittleLong (long l);
float BigFloat (float l);
float LittleFloat (float l);
extern char com_token[1024];
extern boolean com_eof;
char *COM_Parse (char *data);
#endif

View file

@ -0,0 +1,175 @@
QuakeEd 2.0
by John Carmack and John Romero
Terms:
Brush
A convex polyhedron with a textruedef for each face.
Entity
A set of brushes and key/value attributes. The world is allways entity 0. Lights, doors, monsters, etc are all entities. Entities can either have a fixed, non-modifiable size (monsters, lights, etc), or can be represented by an arbitrary collection of brushes (doors, plats, bridges, etc).
An entity is created by selecting one or more brushes in the world, then selecting a class in the Entity Browser, then clicking Create Entity (or double click the class name). If the entity class has a fixed size, the selected brushes are removed and a fixed sized brush is put in their place. Otherwise, the selected brushes are removed from the world entity and made the contents of the newly created entity.
Current Entity
Selection
The current selection of brushes is drawn with a red outline.
The selection is not cleared when loading a new map, so selections can be brought over from other files.
Texturedef
A texture name with offset numbers and flip flags. Determines what will be drawn on a brush face. By default, all faces of a brush have the same texturedef, but you can explicityly change single faces if desired.
Using QuakeEd:
The NeXT "cmd" key is the alt key on the left side of the space bar. "alt" is the alt key on the right side.
Camera View
click
Sets the current texturedef to the value of the face clicked on.
Does not change any selection status.
f there are any brushes selected, they will all be changed to this texturedef.
If there are no brushes selected, the height of the next new brush created will be set based on the size of the brush clicked on.
shift-click
Toggles the selection status of the clicked on brush.
If the brush is part of a different entity than the current entity, all brushes in current are deselected before selecting the new brush. The current entity inpector is then changed to reflect the new entity.
alt-click
Sets the entire brush clicked on to the current texturedef. Does not change any selection status.
alt-ctrl-click
Sets the single face clicked on to the current texturedef without changing the other faces.
right-click drag
Change camera angle.
XYView
double click
Positions the Z checker at the click point.
click drag with no selection
The camera or Z checker will be dragged if directly clicked on, otherwise a new rectilinear brush will be dragged out from the click point. The initial height of the brush is determined by the last brush selected or camera-clicked on.
If the button is released when the new brush has no volume (a veneer), the brush is discarded.
click drag with a single brush selected
If the click is inside the selected brush, the brush will be dragged around without changing its shape.
If the click is outside the brush, dragging will move the planes that face the click point. Planes will only move directly along their normals, so a recrilinear brush will stay rectilinear.
Spawned entity brushes (monsters, etc) can not be resized at all.
click drag with multiple brushes selected
No group shape changes are allowed, so the click must be inside one of the brushes, and all brushes are moved together.
cmd-click drag with a single brush selected
Holds the plane that faces the click point, and shears the adjacent planes. To grab a single corner, click outside the brush in the overlap area between two planes. If you click inside the brush, the top plane will be held.
shift-click
Toggles the selection status of the clicked on brush as in the camera view.
Entities are allways checked before the world, so you can shift-click on entities even if there is a ceiling above them.
cmd-shift click
Connects two entities. The current entity has a target key generated, and the clicked on entity has a targetname key created.
alt-click
alt-ctrl-click
Sets textures as in the camera view.
ctrl-click
Moves the camera to the point clicked on. It can be dragged dynamically if desired.
right click
right ctrl-click
Points the camera towards the click point. It can be dragged if desired.
cmd-right click drag
Slides the XY view to expose more space.
alt-right click
Positions a clipper tool endpoint. The first click places it at the minimum Z of the selection. A second click at the same point moves it to the maximum Z of the selection.
Two clipper points will carve as a straight line in the XY view. Three points (one of which must be at the max point instead of the min) will carve a slope.
Escape removes the current clippers, and enter actually cuts the selection.
ZView
click drag
The camera icon can be dragged if it is clicked on, otherwise no action if there is not a selection.
If multiple brushes are selected, they will allways be dragged as a unit, no matter where the click is.
If a single brush is selected, the location of the click determines if the drag will move the entire brush or just the top or bottom plane.
A click anywhere on the left side of the Z view will drag the full brush. If the click is on the right side, it will drag just the plane closest to it, changing the size of the brush. Clicking inside a brush on the right side also drags the full brush.
shift-click
Toggles the selection status of the clicked on brush as in the camera view.
alt-click
Sets the entire brush texture as in the camera view. (alt-ctrl click is meaningless without a direction)
ctrl-click
Moves the camera to the height clicked on. It can be dragged dynamically if desired.
right click drag
Slides the Z view to expose more space.
Keyboard
F2 : set camera wire draw mode
F3 : set camera solid draw mode
F4 : set camera textured draw mode
F5 : set XY wire draw mode
F6 : set XY textured draw mode
F8 : Home camera pitch angle
F12 : geometrically subtract the selection from the rest of the world.
PageUp : moves the camera view to the next floor up.
PageDown : moves the camera view to the next floor down.
cursor arrows, a z d c , .
Step move the camera with quake controls.
Esc or End: deselect all selected brushes
Backspace : delete all selected brushes
/ : Flip the normal on the clipper tool
Enter : Carve selected brushes by the clipper tool
Space : clone all selected brushes. deselects the originals and selects the copies after offsetting by the grid size.
Keypad arrows: moves the current selection in gridsize incrmenets.
+ - : moves the current selection up or down by gridsize increments.
cmd-1 - cmd-7 : change inspectors
Text commands
Obscure commands are entered by typing the command into the command field (under the output field).
texname : prints the names of the textures on the selected brush. Used to track down problems with accidentally taking graphics out of a wadfile.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,93 @@
// mathlib.c -- math primitives
#include "mathlib.h"
#include <math.h>
vec3_t vec3_origin = {0,0,0};
double VectorLength(vec3_t v)
{
int i;
double length;
length = 0;
for (i=0 ; i< 3 ; i++)
length += v[i]*v[i];
length = sqrt (length); // FIXME
return length;
}
void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc)
{
vc[0] = va[0] + scale*vb[0];
vc[1] = va[1] + scale*vb[1];
vc[2] = va[2] + scale*vb[2];
}
boolean VectorCompare (vec3_t v1, vec3_t v2)
{
int i;
for (i=0 ; i<3 ; i++)
if (v1[i] != v2[i])
return false;
return true;
}
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
{
cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
}
vec_t _DotProduct (vec3_t v1, vec3_t v2)
{
return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
}
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
{
out[0] = va[0]-vb[0];
out[1] = va[1]-vb[1];
out[2] = va[2]-vb[2];
}
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
{
out[0] = va[0]+vb[0];
out[1] = va[1]+vb[1];
out[2] = va[2]+vb[2];
}
void _VectorCopy (vec3_t in, vec3_t out)
{
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
}
void VectorNormalize (vec3_t v)
{
int i;
float length;
length = 0;
for (i=0 ; i< 3 ; i++)
length += v[i]*v[i];
length = sqrt (length);
for (i=0 ; i< 3 ; i++)
v[i] /= length;
}
void VectorScale (vec3_t v, vec_t scale, vec3_t out)
{
out[0] = v[0] * scale;
out[1] = v[1] * scale;
out[2] = v[2] * scale;
}

View file

@ -0,0 +1,31 @@
#ifndef __MATHLIB__
#define __MATHLIB__
#include "cmdlib.h"
// mathlib.h
typedef float vec_t;
typedef vec_t vec3_t[3];
extern vec3_t vec3_origin;
boolean VectorCompare (vec3_t v1, vec3_t v2);
#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];}
#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];}
#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];}
vec_t _DotProduct (vec3_t v1, vec3_t v2);
void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out);
void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out);
void _VectorCopy (vec3_t in, vec3_t out);
void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);
void VectorNormalize (vec3_t v);
void VectorScale (vec3_t v, vec_t scale, vec3_t out);
double VectorLength(vec3_t v);
void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc);
#endif

View file

@ -0,0 +1,274 @@
#include "qedefs.h"
char token[MAXTOKEN];
boolean unget;
char *script_p;
int scriptline;
void StartTokenParsing (char *data)
{
scriptline = 1;
script_p = data;
unget = false;
}
boolean GetToken (boolean crossline)
{
char *token_p;
if (unget) // is a token allready waiting?
return true;
//
// skip space
//
skipspace:
while (*script_p <= 32)
{
if (!*script_p)
{
if (!crossline)
Error ("Line %i is incomplete",scriptline);
return false;
}
if (*script_p++ == '\n')
{
if (!crossline)
Error ("Line %i is incomplete",scriptline);
scriptline++;
}
}
if (script_p[0] == '/' && script_p[1] == '/') // comment field
{
if (!crossline)
Error ("Line %i is incomplete\n",scriptline);
while (*script_p++ != '\n')
if (!*script_p)
{
if (!crossline)
Error ("Line %i is incomplete",scriptline);
return false;
}
goto skipspace;
}
//
// copy token
//
token_p = token;
if (*script_p == '"')
{
script_p++;
while ( *script_p != '"' )
{
if (!*script_p)
Error ("EOF inside quoted token");
*token_p++ = *script_p++;
if (token_p == &token[MAXTOKEN])
Error ("Token too large on line %i",scriptline);
}
script_p++;
}
else while ( *script_p > 32 )
{
*token_p++ = *script_p++;
if (token_p == &token[MAXTOKEN])
Error ("Token too large on line %i",scriptline);
}
*token_p = 0;
return true;
}
void UngetToken ()
{
unget = true;
}
void qprintf (char *fmt, ...) // prints text to cmd_out_i
{
va_list argptr;
static char string[1024];
va_start (argptr, fmt);
vsprintf (string, fmt,argptr);
va_end (argptr);
[g_cmd_out_i setStringValue: [NSString stringWithCString: string]];
//NSPing ();
return;
}
/*
=================
Error
For abnormal program terminations
=================
*/
BOOL in_error;
void Error (char *error, ...)
{
va_list argptr;
static char string[1024];
if (in_error)
[NSApp terminate: NULL];
in_error = YES;
va_start (argptr,error);
vsprintf (string,error,argptr);
va_end (argptr);
strcat (string, "\nmap saved to "FN_CRASHSAVE);
[map_i writeMapFile: FN_CRASHSAVE useRegion: NO];
NSRunAlertPanel (@"Error", [NSString stringWithCString: string],NULL,NULL,NULL);
[NSApp terminate: NULL];
}
void CleanupName (char *in, char *out)
{
int i;
for (i=0 ; i< 16 ; i++ )
{
if (!in[i])
break;
out[i] = toupper(in[i]);
}
for ( ; i< 16 ; i++ )
out[i] = 0;
}
void PrintRect (NSRect *r)
{
printf ("(%4.0f, %4.0f) + (%4.0f, %4.0f) = (%4.0f,%4.0f)\n"
,r->origin.x,r->origin.y,
r->size.width, r->size.height, r->origin.x+r->size.width,
r->origin.y+r->size.height);
}
/*
============
FileTime
returns -1 if not present
============
*/
int FileTime (char *path)
{
struct stat buf;
if (stat (path,&buf) == -1)
return -1;
return buf.st_mtime;
}
/*
============
CreatePath
============
*/
void CreatePath (char *path)
{
char *ofs;
for (ofs = path+1 ; *ofs ; ofs++)
{
if (*ofs == '/')
{ // create the directory
*ofs = 0;
mkdir (path,0777);
*ofs = '/';
}
}
}
int I_FileOpenRead (char *path, int *handle)
{
int h;
struct stat fileinfo;
h = open (path, O_RDONLY, 0666);
*handle = h;
if (h == -1)
return -1;
if (fstat (h,&fileinfo) == -1)
Error ("Error fstating %s", path);
return fileinfo.st_size;
}
int I_FileOpenWrite (char *path)
{
int handle;
umask (0);
handle = open(path,O_RDWR | O_CREAT | O_TRUNC
, 0666);
if (handle == -1)
Error ("Error opening %s: %s", path,strerror(errno));
return handle;
}
/*
============
Sys_UpdateFile
Copies a more recent net file to the local drive
============
*/
void Sys_UpdateFile (char *path, char *netpath)
{
int ltime, ntime;
int in, out, size;
char *buf;
ltime = FileTime (path);
ntime = FileTime (netpath);
if (ntime <= ltime)
return; // up to date
// copy the file
printf ("UpdateFile: copying %s to %s...\n", netpath, path);
size = I_FileOpenRead (netpath, &in);
buf = malloc (size);
if (read (in, buf, size) != size)
Error ("UpdateFile: couldn't read all of %s", netpath);
close (in);
CreatePath (path);
out = I_FileOpenWrite (path);
write (out, buf, size);
close (out);
}

View file

@ -0,0 +1,57 @@
#import <AppKit/AppKit.h>
#import <ctype.h>
#import <sys/types.h>
#import <sys/dir.h>
#import <math.h>
#import <unistd.h>
#import <sys/fcntl.h>
#import "UserPath.h"
#import "cmdlib.h"
#import "mathlib.h"
#import "EntityClass.h"
#import "Project.h"
#import "QuakeEd.h"
#import "Map.h"
#import "TexturePalette.h"
#import "SetBrush.h"
#import "render.h"
#import "Entity.h"
#import "XYView.h"
#import "CameraView.h"
#import "ZView.h"
#import "ZScrollView.h"
#import "Preferences.h"
#import "InspectorControl.h"
#import "PopScrollView.h"
#import "KeypairView.h"
#import "Things.h"
#import "TextureView.h"
#import "Clipper.h"
void PrintRect (NSRect *r);
int FileTime (char *path);
void Sys_UpdateFile (char *path, char *netpath);
void CleanupName (char *in, char *out);
extern BOOL in_error;
void Error (char *error, ...);
#define MAXTOKEN 128
extern char token[MAXTOKEN];
extern int scriptline;
void StartTokenParsing (char *data);
boolean GetToken (boolean crossline); // returns false at eof
void UngetToken ();
#define FN_CMDOUT "/tmp/QuakeEdCmd.txt"
#define FN_TEMPSAVE "/qcache/temp.map"
#define FN_AUTOSAVE "/qcache/AutoSaveMap.map"
#define FN_CRASHSAVE "/qcache/ErrorSaveMap.map"
#define FN_DEVLOG "/qcache/devlog"

View file

@ -0,0 +1,13 @@
{
{"basepath" "/raid/quake/id1"}
{"maps" "jrbase1 jrbase2 jrbase4 jrwiz1 jrwiz2 jrdungn jrmed1 jrmed2 jrstart tim4 tim5 tim6 tim7 tim9 tboss amtest98 ammap2 amtest1 amdm3 amdem1 ammet2 amlev13 ammech3 schurch smotte sramp2 scath sally spit stemple"}
{"desc" "jrbase1 jrbase2 jrbase4 jrwiz1 jrwiz2 jrdungn jrmed1 jrmed2 jrstart tim4 tim5 tim6 tim7 tim9 tboss amtest98 ammap2 amtest1 amdm3 amdem1 ammet2 amlev13 ammech3 schurch smotte sramp2 scath sally spit stemple"}
{"wads" "gfx/medieval.wad gfx/base.wad gfx/wizard.wad gfx/metal.wad gfx/tim.wad gfx/items.wad gfx/start.wad"}
{"bspfullvis" "rsh satan @/LocalApps/qbsp $1 $2 ; /LocalApps/light -extra $2 ; /LocalApps/vis $2@"}
{"bspfastvis" "rsh satan @/LocalApps/qbsp $1 $2 ; /LocalApps/light $2 ; /LocalApps/vis -fast $2@"}
{"bspnovis" "rsh satan @/LocalApps/qbsp $1 $2 ; /LocalApps/light $2@"}
{"bsprelight" "rsh satan @/LocalApps/qbsp -onlyents $1 $2 ; /LocalApps/light -extra $2@"}
{"bspleaktest" "rsh satan @/LocalApps/qbsp -mark -notjunc $1 $2 ; /LocalApps/light $2@"}
{"bspentities" "rsh satan @/LocalApps/qbsp -onlyents $1 $2@"}
}

View file

@ -0,0 +1,33 @@
5/18/96
This is a dump of the current source code for QuakeEd, our map editing application.
This does not include everything necessary to build maps. There are graphics files, prog files, and other utilities needed. I plan on releasing a full development set of tools after the game ships. This is just intended to help out anyone working on their own map editor.
This is a NEXTSTEP application, so hardly anyone is going to be able to use the code as is. This is not an OPENSTEP application. It doesn't even use the foundation kit, so porting to gnustep or openstep-solaris/mach/nt would not be trivial.
There are lots of mixed case and >8 character filenames, so I'm using unix gnutar (compressed) format.
Because most people won't have access to a NEXTSTEP machine, I took pictures of some of the more important stuff from interface builder:
mainwindow.tiff : a screenshot of the primary window
inspectors.tiff : a screenshot of the important inspector views
help.txt : a dump of the (minimal) help inspector's contents.
I included some sample data to help you follow the code:
quake.qpr : our current project file
jrbase1.map : a sample map
triggers.qc : a sample qc source file that includes some /*QUAKED comments
There will not be any major changes to this code base. I am eagerly looking forward to writing a brand new editor for windows NT + open GL as soon as Quake ships.
This application was really not a very good fit for NEXTSTEP. The display postscript model fundamentally doesn't fit very well with what we need here -- if you run in an 8 bit color mode, the line drawing runs at an ok speed, but the texture view goes half the speed it should as it dithers from 24 bit color down to 8 bit. If you run in 24 bit color mode, you get less screen real estate and significantly slower line drawing as a 3 megabyte XY view is flushed. Sigh. If anyone does actually run this on NEXTSTEP be advised that you want a fast machine. I never had the time to properly optimize QuakeEd.
The texture view rendering code in here is crap. Anyone coding a new editor is strongly advised to just use an available optimized library, like open GL or direct 3D.
John Carmack
Id Software
johnc@idsoftware.com

View file

@ -0,0 +1,13 @@
extern int r_width, r_height;
extern unsigned *r_picbuffer;
extern float *r_zbuffer;
extern vec3_t r_origin, r_matrix[3];
extern BOOL r_drawflat;
void REN_ClearBuffers (void);
void REN_DrawCameraFace (face_t *idpol);
void REN_DrawXYFace (face_t *idpol);
void REN_BeginCamera (void);
void REN_BeginXY (void);

View file

@ -0,0 +1,748 @@
#import "qedefs.h"
//define NOLIGHT
vec3_t r_origin, r_matrix[3];
int t_width, t_height;
unsigned *t_data;
int t_widthmask, t_heightmask, t_widthshift;
float t_widthadd, t_heightadd;
int r_width, r_height;
float *r_zbuffer;
unsigned *r_picbuffer;
vec5_t rightside, leftside, rightstep,leftstep;
face_t *r_face;
BOOL r_drawflat;
pixel32_t r_flatcolor;
int sy[20];
/*
====================
REN_ClearBuffers
====================
*/
void REN_ClearBuffers (void)
{
int size;
size = r_width * r_height*4;
memset (r_zbuffer, 0, size);
memset (r_picbuffer, 0, size);
}
/*
====================
REN_SetTexture
====================
*/
void REN_SetTexture (face_t *face)
{
int i;
int t_heightshift;
qtexture_t *q;
if (!face->qtexture)
face->qtexture = TEX_ForName (face->texture.texture); // try to load
q = face->qtexture;
t_width = q->width;
t_height = q->height;
t_data = q->data;
r_flatcolor = q->flatcolor;
r_flatcolor.chan[0] *= r_face->light;
r_flatcolor.chan[1] *= r_face->light;
r_flatcolor.chan[2] *= r_face->light;
t_widthadd = t_width*1024;
t_heightadd = t_height*1024;
t_widthmask = t_width-1;
t_heightmask = t_height-1;
t_widthshift = 0;
i = t_width;
while (i >= 2)
{
t_widthshift++;
i>>=1;
}
t_heightshift = 0;
i = t_width;
while (i >= 2)
{
t_heightshift++;
i>>=1;
}
if ( (1<<t_widthshift) != t_width || (1<<t_heightshift) != t_height)
t_widthshift = t_heightshift = 0; // non power of two
}
/*
==================
REN_DrawSpan
==================
*/
void REN_DrawSpan (int y)
{
int x, count;
int ofs;
int tx, ty;
int x1, x2;
float ufrac, vfrac, zfrac, lightfrac, ustep, vstep, zstep;
pixel32_t *in, *out;
float scale;
if (y<0 || y >= r_height)
return;
x1 = (leftside[0]);
x2 = (rightside[0]);
count = x2 - x1;
if (count < 0)
return;
zfrac = leftside[2];
ufrac = leftside[3];
vfrac = leftside[4];
lightfrac = r_face->light;
if (!count)
scale = 1;
else
scale = 1.0/count;
zstep = (rightside[2] - zfrac)*scale;
ustep = (rightside[3] - ufrac)*scale;
vstep = (rightside[4] - vfrac)*scale;
if (x1 < 0)
{
ufrac -= x1*ustep;
vfrac -= x1*vstep;
zfrac -= x1*zstep;
x1 = 0;
}
if (x2 > r_width)
x2 = r_width;
ofs = y*r_width+x1;
// this should be specialized for 1.0 / 0.5 / 0.75 light levels
for (x=x1 ; x < x2 ; x++)
{
if (r_zbuffer[ofs] <= zfrac)
{
scale = 1/zfrac;
r_zbuffer[ofs] = zfrac;
if (t_widthshift)
{
tx = (int)((ufrac*scale)) & t_widthmask;
ty = (int)((vfrac*scale)) & t_heightmask;
in = (pixel32_t *)&t_data [(ty<<t_widthshift)+tx];
}
else
{
tx = (int)((ufrac*scale)+t_widthadd) % t_width;
ty = (int)((vfrac*scale)+t_heightadd) % t_height;
in = (pixel32_t *)&t_data [ty*t_width+tx];
}
out = (pixel32_t *)&r_picbuffer[ofs];
#ifdef NOLIGHT
*out = *in;
#else
out->chan[0] = in->chan[0]*lightfrac;
out->chan[1] = in->chan[1]*lightfrac;
out->chan[2] = in->chan[2]*lightfrac;
out->chan[3] = 0xff;
#endif
}
ufrac += ustep;
vfrac += vstep;
zfrac += zstep;
ofs++;
}
}
/*
==================
REN_DrawFlatSpan
==================
*/
void REN_DrawFlatSpan (int y)
{
int x, count;
int ofs;
int x1, x2;
float zfrac, zstep;
int *out;
if (y<0 || y >= r_height)
return;
x1 = (leftside[0]);
x2 = (rightside[0]);
count = x2 - x1;
if (count < 0)
return;
zfrac = leftside[2];
zstep = (rightside[2] - zfrac)/count;
if (x1 < 0)
{
zfrac -= x1*zstep;
x1 = 0;
}
if (x2 > r_width)
x2 = r_width;
ofs = y*r_width+x1;
// this should be specialized for 1.0 / 0.5 / 0.75 light levels
for (x=x1 ; x < x2 ; x++)
{
if (r_zbuffer[ofs] <= zfrac)
{
r_zbuffer[ofs] = zfrac;
out = (int *)&r_picbuffer[ofs];
*out = r_flatcolor.p;
}
zfrac += zstep;
ofs++;
}
}
/*
=====================
REN_RasterizeFace
=====================
*/
void REN_RasterizeFace (winding_t *w)
{
int y;
int i;
int top, bot;
int leftv, rightv;
int count;
int numvertex;
//
// find top vertex
//
numvertex = w->numpoints;
top = 0x7fffffff;
bot = 0x80000000;
leftv = 0;
for (i=0 ; i<numvertex ; i++)
{
w->points[i][3] *= w->points[i][2];
w->points[i][4] *= w->points[i][2];
sy[i] = (int)w->points[i][1];
if (sy[i] < top)
{
top = sy[i];
leftv = i;
}
if (sy[i] > bot)
bot = sy[i];
}
rightv = leftv;
if (top < 0 || bot > r_height || top > bot)
return; // shouldn't have to have this...
//
// render a trapezoid
//
y = top;
while (y < bot)
{
if (y >= sy[leftv])
{
do
{
for (i=0 ; i<5 ; i++)
leftside[i] = w->points[leftv][i];
leftv--;
if (leftv == -1)
leftv = numvertex-1;
} while (sy[leftv] <= y);
count = sy[leftv]-y;
for (i=0 ; i<5 ; i++)
leftstep[i] = (w->points[leftv][i] - leftside[i])/count;
}
if (y >= sy[rightv])
{
do
{
for (i=0 ; i<5 ; i++)
rightside[i] = w->points[rightv][i];
rightv++;
if (rightv == numvertex)
rightv = 0;
} while (sy[rightv] <= y);
count = sy[rightv]-y;
for (i=0 ; i<5 ; i++)
rightstep[i] = (w->points[rightv][i] - rightside[i])/count;
}
if (r_drawflat)
REN_DrawFlatSpan (y);
else
REN_DrawSpan (y);
for (i=0 ; i<5 ; i++)
{
leftside[i] += leftstep[i];
rightside[i] += rightstep[i];
}
y++;
}
}
//=============================================================================
/*
==================
REN_DrawSpanLinear
==================
*/
void REN_DrawSpanLinear (int y)
{
int x, count;
int ofs;
int tx, ty;
int x1, x2;
float ufrac, vfrac, zfrac, ustep, vstep, zstep;
pixel32_t *in, *out;
float scale;
if (y<0 || y >= r_height)
return;
x1 = (leftside[0]);
x2 = (rightside[0]);
count = x2 - x1;
if (count < 0)
return;
zfrac = leftside[2];
ufrac = leftside[3];
vfrac = leftside[4];
if (!count)
scale = 1;
else
scale = 1.0/count;
zstep = (rightside[2] - zfrac)*scale;
ustep = (rightside[3] - ufrac)*scale;
vstep = (rightside[4] - vfrac)*scale;
if (x1 < 0)
{
ufrac -= x1*ustep;
vfrac -= x1*vstep;
zfrac -= x1*zstep;
x1 = 0;
}
if (x2 > r_width)
x2 = r_width;
ofs = y*r_width+x1;
for (x=x1 ; x < x2 ; x++)
{
if (r_zbuffer[ofs] <= zfrac)
{
r_zbuffer[ofs] = zfrac;
if (t_widthshift)
{
tx = (int)ufrac & t_widthmask;
ty = (int)vfrac & t_heightmask;
in = (pixel32_t *)&t_data [(ty<<t_widthshift)+tx];
}
else
{
tx = (int)(ufrac+t_widthadd) % t_width;
ty = (int)(vfrac+t_heightadd) % t_height;
in = (pixel32_t *)&t_data [ty*t_width+tx];
}
out = (pixel32_t *)&r_picbuffer[ofs];
*out = *in;
}
ufrac += ustep;
vfrac += vstep;
zfrac += zstep;
ofs++;
}
}
/*
=====================
REN_RasterizeFaceLinear
=====================
*/
void REN_RasterizeFaceLinear (winding_t *w)
{
int y;
int i;
int top, bot;
int leftv, rightv;
int count;
int numvertex;
//
// find top vertex
//
numvertex = w->numpoints;
top = 0x7fffffff;
bot = 0x80000000;
leftv = 0;
for (i=0 ; i<numvertex ; i++)
{
sy[i] = (int)w->points[i][1];
if (sy[i] < top)
{
top = sy[i];
leftv = i;
}
if (sy[i] > bot)
bot = sy[i];
}
rightv = leftv;
if (top < 0 || bot > r_height || top > bot)
return; // shouldn't have to have this...
//
// render a trapezoid
//
y = top;
while (y < bot)
{
if (y >= sy[leftv])
{
do
{
for (i=0 ; i<5 ; i++)
leftside[i] = w->points[leftv][i];
leftv--;
if (leftv == -1)
leftv = numvertex-1;
} while (sy[leftv] <= y);
count = sy[leftv]-y;
for (i=0 ; i<5 ; i++)
leftstep[i] = (w->points[leftv][i] - leftside[i])/count;
}
if (y >= sy[rightv])
{
do
{
for (i=0 ; i<5 ; i++)
rightside[i] = w->points[rightv][i];
rightv++;
if (rightv == numvertex)
rightv = 0;
} while (sy[rightv] <= y);
count = sy[rightv]-y;
for (i=0 ; i<5 ; i++)
rightstep[i] = (w->points[rightv][i] - rightside[i])/count;
}
REN_DrawSpanLinear (y);
for (i=0 ; i<5 ; i++)
{
leftside[i] += leftstep[i];
rightside[i] += rightstep[i];
}
y++;
}
}
//============================================================================
/*
==================
REN_BeginCamera
===================
*/
float r_width_2, r_height_3;
plane_t frustum[5];
void REN_BeginCamera (void)
{
r_width_2 = (float)r_width / 2;
r_height_3 = (float)r_height / 3;
// clip to right side
frustum[0].normal[0] = -1;
frustum[0].normal[1] = 0;
frustum[0].normal[2] = 1;
frustum[0].dist = 0;
// clip to left side
frustum[1].normal[0] = 1;
frustum[1].normal[1] = 0;
frustum[1].normal[2] = 1;
frustum[1].dist = 0;
// clip to top side
frustum[2].normal[0] = 0;
frustum[2].normal[1] = -1;
frustum[2].normal[2] = r_height_3 / r_width_2;
frustum[2].dist = 0;
// clip to bottom side
frustum[3].normal[0] = 0;
frustum[3].normal[1] = 1;
frustum[3].normal[2] = 2*r_height_3 / r_width_2;
frustum[3].dist = 0;
// near Z
frustum[4].normal[0] = 0;
frustum[4].normal[1] = 0;
frustum[4].normal[2] = 1;
frustum[4].dist = 1;
}
void REN_BeginXY (void)
{
frustum[0].normal[0] = 1;
frustum[0].normal[1] = 0;
frustum[0].normal[2] = 0;
frustum[0].dist = 0;
frustum[1].normal[0] = -1;
frustum[1].normal[1] = 0;
frustum[1].normal[2] = 0;
frustum[1].dist = -r_width;
frustum[2].normal[0] = 0;
frustum[2].normal[1] = 1;
frustum[2].normal[2] = 0;
frustum[2].dist = 0;
frustum[3].normal[0] = 0;
frustum[3].normal[1] = -1;
frustum[3].normal[2] = 0;
frustum[3].dist = -r_height;
}
/*
=====================
REN_DrawCameraFace
=====================
*/
void REN_DrawCameraFace (face_t *idpol)
{
int i;
float scale;
int numvertex;
winding_t *w, *in;
vec3_t temp;
if (!idpol->w)
return; // overconstrained plane
r_face = idpol;
//
// back face cull
//
if (DotProduct (r_origin, idpol->plane.normal) <= idpol->plane.dist)
return;
//
// transform in 3D (FIXME: clip first, then transform)
//
in = idpol->w;
numvertex = in->numpoints;
w = NewWinding (numvertex);
w->numpoints = numvertex;
for (i=0 ; i<numvertex ; i++)
{
VectorSubtract (in->points[i], r_origin, temp);
w->points[i][0] = DotProduct(temp,r_matrix[0]);
w->points[i][1] = DotProduct(temp,r_matrix[1]);
w->points[i][2] = DotProduct(temp,r_matrix[2]);
w->points[i][3] = in->points[i][3];
w->points[i][4] = in->points[i][4];
}
//
// 3D clip
//
for (i=0 ; i<4 ; i++)
{
w = ClipWinding (w, &frustum[i]);
if (!w)
return;
}
//
// project to 2D
//
for (i=0 ; i<w->numpoints ; i++)
{
scale = r_width_2 / w->points[i][2];
w->points[i][0] = r_width_2 + scale*w->points[i][0];
w->points[i][1] = r_height_3 - scale*w->points[i][1];
w->points[i][2] = scale;
}
//
// draw it
//
REN_SetTexture (idpol);
REN_RasterizeFace (w);
free (w);
}
/*
=====================
REN_DrawXYFace
=====================
*/
void REN_DrawXYFace (face_t *idpol)
{
int i, j, numvertex;
winding_t *w, *in;
float *dest, *source;
float temp;
if (!idpol->w)
return; // overconstrained plane
w = idpol->w;
r_face = idpol;
//
// back (and side) face cull
//
if (DotProduct (idpol->plane.normal, xy_viewnormal) > -VECTOR_EPSILON)
return;
//
// transform
//
in = idpol->w;
numvertex = in->numpoints;
w = NewWinding (numvertex);
w->numpoints = numvertex;
for (i=0 ; i<numvertex ; i++)
{
// using Z as a scale for the 2D projection
w->points[i][0] = (in->points[i][0] - r_origin[0])*r_origin[2];
w->points[i][1] = r_height - (in->points[i][1] - r_origin[1])*r_origin[2];
w->points[i][2] = in->points[i][2] + 3000;
w->points[i][3] = in->points[i][3];
w->points[i][4] = in->points[i][4];
}
//
// clip
//
for (i=0 ; i<4 ; i++)
{
w = ClipWinding (w, &frustum[i]);
if (!w)
return;
}
//
// project to 2D
//
for (i=0 ; i<w->numpoints ; i++)
{
dest = w->points[i];
if (dest[0] < 0)
dest[0] = 0;
if (dest[0] > r_width)
dest[0] = r_width;
if (dest[1] < 0)
dest[1] = 0;
if (dest[1] > r_height)
dest[1] = r_height;
if (xy_viewnormal[2] > 0)
dest[2] = 4096-dest[2];
}
if (xy_viewnormal[2] > 0)
{ // flip order when upside down
for (i=0 ; i<w->numpoints/2 ; i++)
{
dest = w->points[i];
source = w->points[w->numpoints-1-i];
for (j=0 ; j<5 ; j++)
{
temp = dest[j];
dest[j] = source[j];
source[j] = temp;
}
}
}
REN_SetTexture (idpol);
//
// draw it
//
REN_RasterizeFaceLinear (w);
free (w);
}