Index: meson.build ================================================================== --- meson.build +++ meson.build @@ -1,14 +1,16 @@ -project('Cube', ['c', 'objcpp'], +project('Cube', ['c', 'objc', 'objcpp'], meson_version: '>=1.5.0') -add_global_arguments( - [ - '-fobjc-arc', - '-fobjc-arc-exceptions' - ], - language: 'objcpp') +foreach lang : ['objc', 'objcpp'] + add_global_arguments( + [ + '-fobjc-arc', + '-fobjc-arc-exceptions' + ], + language: lang) +endforeach objfw_dep = dependency('objfw') sdl_dep = dependency('SDL2') sdlimage_dep = dependency('SDL2_image') sdlmixer_dep = dependency('SDL2_mixer') ADDED src/Ident.h Index: src/Ident.h ================================================================== --- /dev/null +++ src/Ident.h @@ -0,0 +1,18 @@ +#import + +OF_ASSUME_NONNULL_BEGIN + +enum IdentType { ID_VAR, ID_COMMAND, ID_ALIAS }; + +@interface Ident : OFObject +@property (nonatomic) enum IdentType type; +@property (copy, nonatomic) OFString *name; +@property (nonatomic) int min, max; // ID_VAR +@property (nonatomic) int *storage; // ID_VAR +@property (nonatomic) void (*fun)(); // ID_VAR, ID_COMMAND +@property (nonatomic) int narg; // ID_VAR, ID_COMMAND +@property (copy, nonatomic) OFString *action; // ID_ALIAS +@property (nonatomic) bool persist; +@end + +OF_ASSUME_NONNULL_END ADDED src/Ident.m Index: src/Ident.m ================================================================== --- /dev/null +++ src/Ident.m @@ -0,0 +1,4 @@ +#import "Ident.h" + +@implementation Ident +@end ADDED src/KeyMapping.h Index: src/KeyMapping.h ================================================================== --- /dev/null +++ src/KeyMapping.h @@ -0,0 +1,13 @@ +#import + +OF_ASSUME_NONNULL_BEGIN + +@interface KeyMapping : OFObject +@property (readonly) int code; +@property (readonly, nonatomic) OFString *name; +@property (copy, nonatomic) OFString *action; + +- (instancetype)initWithCode:(int)code name:(OFString *)name; +@end + +OF_ASSUME_NONNULL_END ADDED src/KeyMapping.m Index: src/KeyMapping.m ================================================================== --- /dev/null +++ src/KeyMapping.m @@ -0,0 +1,13 @@ +#import "KeyMapping.h" + +@implementation KeyMapping +- (instancetype)initWithCode:(int)code name:(OFString *)name +{ + self = [super init]; + + _code = code; + _name = [name copy]; + + return self; +} +@end ADDED src/MD2.h Index: src/MD2.h ================================================================== --- /dev/null +++ src/MD2.h @@ -0,0 +1,29 @@ +#import + +OF_ASSUME_NONNULL_BEGIN + +@class MapModelInfo; + +@interface MD2 : OFObject +@property (nonatomic) MapModelInfo *mmi; +@property (copy, nonatomic) OFString *loadname; +@property (nonatomic) int mdlnum; +@property (nonatomic) bool loaded; + +- (bool)loadWithIRI:(OFIRI *)IRI; +- (void)renderWithLight:(OFVector3D &)light + frame:(int)frame + range:(int)range + x:(float)x + y:(float)y + z:(float)z + yaw:(float)yaw + pitch:(float)pitch + scale:(float)scale + speed:(float)speed + snap:(int)snap + basetime:(int)basetime; +- (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)snap; +@end + +OF_ASSUME_NONNULL_END ADDED src/MD2.mm Index: src/MD2.mm ================================================================== --- /dev/null +++ src/MD2.mm @@ -0,0 +1,207 @@ +#import "MD2.h" + +#include "cube.h" + +struct md2_header { + int magic; + int version; + int skinWidth, skinHeight; + int frameSize; + int numSkins, numVertices, numTexcoords; + int numTriangles, numGlCommands, numFrames; + int offsetSkins, offsetTexcoords, offsetTriangles; + int offsetFrames, offsetGlCommands, offsetEnd; +}; + +struct md2_vertex { + uchar vertex[3], lightNormalIndex; +}; + +struct md2_frame { + float scale[3]; + float translate[3]; + char name[16]; + md2_vertex vertices[1]; +}; + +@implementation MD2 { + int _numGlCommands; + int *_glCommands; + int _numTriangles; + int _frameSize; + int _numFrames; + int _numVerts; + char *_frames; + OFVector3D **_mverts; + int _displaylist; + int _displaylistverts; +} + +- (void)dealloc +{ + if (_glCommands) + delete[] _glCommands; + if (_frames) + delete[] _frames; +} + +- (bool)loadWithIRI:(OFIRI *)IRI +{ + @autoreleasepool { + OFSeekableStream *stream; + @try { + stream = (OFSeekableStream *)[[OFIRIHandler + handlerForIRI:IRI] openItemAtIRI:IRI mode:@"r"]; + } @catch (id e) { + return false; + } + + if (![stream isKindOfClass:[OFSeekableStream class]]) + return false; + + md2_header header; + [stream readIntoBuffer:&header exactLength:sizeof(md2_header)]; + endianswap( + &header, sizeof(int), sizeof(md2_header) / sizeof(int)); + + if (header.magic != 844121161 || header.version != 8) + return false; + + _frames = new char[header.frameSize * header.numFrames]; + if (_frames == NULL) + return false; + + [stream seekToOffset:header.offsetFrames whence:OFSeekSet]; + [stream readIntoBuffer:_frames + exactLength:header.frameSize * header.numFrames]; + + for (int i = 0; i < header.numFrames; ++i) + endianswap( + _frames + i * header.frameSize, sizeof(float), 6); + + _glCommands = new int[header.numGlCommands]; + if (_glCommands == NULL) + return false; + + [stream seekToOffset:header.offsetGlCommands whence:OFSeekSet]; + [stream readIntoBuffer:_glCommands + exactLength:header.numGlCommands * sizeof(int)]; + endianswap(_glCommands, sizeof(int), header.numGlCommands); + + _numFrames = header.numFrames; + _numGlCommands = header.numGlCommands; + _frameSize = header.frameSize; + _numTriangles = header.numTriangles; + _numVerts = header.numVertices; + + [stream close]; + + _mverts = new OFVector3D *[_numFrames]; + loopj(_numFrames) _mverts[j] = NULL; + + return true; + } +} + +float +snap(int sn, float f) +{ + return sn ? (float)(((int)(f + sn * 0.5f)) & (~(sn - 1))) : f; +} + +- (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)sn +{ + _mverts[frame] = new OFVector3D[_numVerts]; + md2_frame *cf = (md2_frame *)((char *)_frames + _frameSize * frame); + float sc = 16.0f / scale; + loop(vi, _numVerts) + { + uchar *cv = (uchar *)&cf->vertices[vi].vertex; + OFVector3D *v = &(_mverts[frame])[vi]; + v->x = (snap(sn, cv[0] * cf->scale[0]) + cf->translate[0]) / sc; + v->y = + -(snap(sn, cv[1] * cf->scale[1]) + cf->translate[1]) / sc; + v->z = (snap(sn, cv[2] * cf->scale[2]) + cf->translate[2]) / sc; + } +} + +- (void)renderWithLight:(OFVector3D &)light + frame:(int)frame + range:(int)range + x:(float)x + y:(float)y + z:(float)z + yaw:(float)yaw + pitch:(float)pitch + scale:(float)sc + speed:(float)speed + snap:(int)sn + basetime:(int)basetime +{ + loopi(range) if (!_mverts[frame + i])[self scaleWithFrame:frame + i + scale:sc + snap:sn]; + + glPushMatrix(); + glTranslatef(x, y, z); + glRotatef(yaw + 180, 0, -1, 0); + glRotatef(pitch, 0, 0, 1); + + glColor3fv((float *)&light); + + if (_displaylist && frame == 0 && range == 1) { + glCallList(_displaylist); + xtraverts += _displaylistverts; + } else { + if (frame == 0 && range == 1) { + static int displaylistn = 10; + glNewList(_displaylist = displaylistn++, GL_COMPILE); + _displaylistverts = xtraverts; + } + + int time = lastmillis - basetime; + int fr1 = (int)(time / speed); + float frac1 = (time - fr1 * speed) / speed; + float frac2 = 1 - frac1; + fr1 = fr1 % range + frame; + int fr2 = fr1 + 1; + if (fr2 >= frame + range) + fr2 = frame; + OFVector3D *verts1 = _mverts[fr1]; + OFVector3D *verts2 = _mverts[fr2]; + + for (int *command = _glCommands; (*command) != 0;) { + int numVertex = *command++; + if (numVertex > 0) { + glBegin(GL_TRIANGLE_STRIP); + } else { + glBegin(GL_TRIANGLE_FAN); + numVertex = -numVertex; + } + + loopi(numVertex) + { + float tu = *((float *)command++); + float tv = *((float *)command++); + glTexCoord2f(tu, tv); + int vn = *command++; + OFVector3D &v1 = verts1[vn]; + OFVector3D &v2 = verts2[vn]; +#define ip(c) v1.c *frac2 + v2.c *frac1 + glVertex3f(ip(x), ip(z), ip(y)); + } + + xtraverts += numVertex; + + glEnd(); + } + + if (_displaylist) { + glEndList(); + _displaylistverts = xtraverts - _displaylistverts; + } + } + + glPopMatrix(); +} +@end ADDED src/MapModelInfo.h Index: src/MapModelInfo.h ================================================================== --- /dev/null +++ src/MapModelInfo.h @@ -0,0 +1,16 @@ +#import + +OF_ASSUME_NONNULL_BEGIN + +@interface MapModelInfo : OFObject +@property (nonatomic) int rad, h, zoff, snap; +@property (copy, nonatomic) OFString *name; + +- (instancetype)initWithRad:(int)rad + h:(int)h + zoff:(int)zoff + snap:(int)snap + name:(OFString *)name; +@end + +OF_ASSUME_NONNULL_END ADDED src/MapModelInfo.m Index: src/MapModelInfo.m ================================================================== --- /dev/null +++ src/MapModelInfo.m @@ -0,0 +1,20 @@ +#import "MapModelInfo.h" + +@implementation MapModelInfo +- (instancetype)initWithRad:(int)rad + h:(int)h + zoff:(int)zoff + snap:(int)snap + name:(OFString *)name +{ + self = [super init]; + + _rad = rad; + _h = h; + _zoff = zoff; + _snap = snap; + _name = [name copy]; + + return self; +} +@end Index: src/command.mm ================================================================== --- src/command.mm +++ src/command.mm @@ -3,25 +3,11 @@ #include "cube.h" #include -enum { ID_VAR, ID_COMMAND, ID_ALIAS }; - -@interface Ident : OFObject -@property (nonatomic) int type; // one of ID_* above -@property (copy, nonatomic) OFString *name; -@property (nonatomic) int min, max; // ID_VAR -@property (nonatomic) int *storage; // ID_VAR -@property (nonatomic) void (*fun)(); // ID_VAR, ID_COMMAND -@property (nonatomic) int narg; // ID_VAR, ID_COMMAND -@property (copy, nonatomic) OFString *action; // ID_ALIAS -@property (nonatomic) bool persist; -@end - -@implementation Ident -@end +#import "Ident.h" void itoa(char *s, int i) { sprintf_s(s)("%d", i); Index: src/console.mm ================================================================== --- src/console.mm +++ src/console.mm @@ -3,10 +3,12 @@ #include "cube.h" #include #include +#import "KeyMapping.h" + struct cline { char *cref; int outtime; }; vector conlines; @@ -91,30 +93,10 @@ }; }; // keymap is defined externally in keymap.cfg -@interface KeyMapping : OFObject -@property (readonly) int code; -@property (readonly, nonatomic) OFString *name; -@property (copy, nonatomic) OFString *action; - -- (instancetype)initWithCode:(int)code name:(OFString *)name; -@end - -@implementation KeyMapping -- (instancetype)initWithCode:(int)code name:(OFString *)name -{ - self = [super init]; - - _code = code; - _name = [name copy]; - - return self; -} -@end - static OFMutableArray *keyMappings = nil; void keymap(OFString *code, OFString *key, OFString *action) { Index: src/cube.h ================================================================== --- src/cube.h +++ src/cube.h @@ -113,21 +113,10 @@ struct block { int x, y, xs, ys; }; -@interface MapModelInfo : OFObject -@property (nonatomic) int rad, h, zoff, snap; -@property (copy, nonatomic) OFString *name; - -- (instancetype)initWithRad:(int)rad - h:(int)h - zoff:(int)zoff - snap:(int)snap - name:(OFString *)name; -@end - enum { GUN_FIST = 0, GUN_SG, GUN_CG, GUN_RL, Index: src/entities.mm ================================================================== --- src/entities.mm +++ src/entities.mm @@ -1,8 +1,10 @@ // entities.cpp: map entity related functions (pickup etc.) #include "cube.h" + +#import "MapModelInfo.h" vector ents; static OFString *entmdlnames[] = { @"shells", Index: src/meson.build ================================================================== --- src/meson.build +++ src/meson.build @@ -1,8 +1,12 @@ executable('client', [ 'Cube.mm', + 'Ident.m', + 'KeyMapping.m', + 'MD2.mm', + 'MapModelInfo.m', 'client.mm', 'clientextras.mm', 'clientgame.mm', 'clients2c.mm', 'command.mm', Index: src/physics.mm ================================================================== --- src/physics.mm +++ src/physics.mm @@ -3,10 +3,12 @@ // and simply tweaked until they "felt right", and have no basis in reality. // Collision detection is simplistic but very robust (uses discrete steps at // fixed fps). #include "cube.h" + +#import "MapModelInfo.h" bool plcollide(dynent *d, dynent *o, float &headspace, float &hi, float &lo) // collide with player or monster { Index: src/protos.h ================================================================== --- src/protos.h +++ src/protos.h @@ -208,10 +208,11 @@ // rendermd2 extern void rendermodel(OFString *mdl, int frame, int range, int tex, float rad, float x, float y, float z, float yaw, float pitch, bool teammate, float scale, float speed, int snap = 0, int basetime = 0); +@class MapModelInfo; extern MapModelInfo *getmminfo(int i); // server extern void initserver(bool dedicated, int uprate, const char *sdesc, const char *ip, const char *master, OFString *passwd, int maxcl); Index: src/rendermd2.mm ================================================================== --- src/rendermd2.mm +++ src/rendermd2.mm @@ -1,247 +1,16 @@ // rendermd2.cpp: loader code adapted from a nehe tutorial #include "cube.h" -struct md2_header { - int magic; - int version; - int skinWidth, skinHeight; - int frameSize; - int numSkins, numVertices, numTexcoords; - int numTriangles, numGlCommands, numFrames; - int offsetSkins, offsetTexcoords, offsetTriangles; - int offsetFrames, offsetGlCommands, offsetEnd; -}; - -struct md2_vertex { - uchar vertex[3], lightNormalIndex; -}; - -struct md2_frame { - float scale[3]; - float translate[3]; - char name[16]; - md2_vertex vertices[1]; -}; - -@interface MD2 : OFObject { - int _numGlCommands; - int *_glCommands; - int _numTriangles; - int _frameSize; - int _numFrames; - int _numVerts; - char *_frames; - OFVector3D **_mverts; - int _displaylist; - int _displaylistverts; -} - -@property (nonatomic) MapModelInfo *mmi; -@property (copy, nonatomic) OFString *loadname; -@property (nonatomic) int mdlnum; -@property (nonatomic) bool loaded; - -- (bool)loadWithIRI:(OFIRI *)IRI; -- (void)renderWithLight:(OFVector3D &)light - frame:(int)frame - range:(int)range - x:(float)x - y:(float)y - z:(float)z - yaw:(float)yaw - pitch:(float)pitch - scale:(float)scale - speed:(float)speed - snap:(int)snap - basetime:(int)basetime; -- (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)snap; -@end +#import "MD2.h" +#import "MapModelInfo.h" static OFMutableDictionary *mdllookup = nil; static OFMutableArray *mapmodels = nil; -@implementation MD2 -+ (void)initialize -{ - if (self != [MD2 class]) - return; - - mdllookup = [[OFMutableDictionary alloc] init]; - mapmodels = [[OFMutableArray alloc] init]; -} - -- (void)dealloc -{ - if (_glCommands) - delete[] _glCommands; - if (_frames) - delete[] _frames; -} - -- (bool)loadWithIRI:(OFIRI *)IRI -{ - @autoreleasepool { - OFSeekableStream *stream; - @try { - stream = (OFSeekableStream *)[[OFIRIHandler - handlerForIRI:IRI] openItemAtIRI:IRI mode:@"r"]; - } @catch (id e) { - return false; - } - - if (![stream isKindOfClass:[OFSeekableStream class]]) - return false; - - md2_header header; - [stream readIntoBuffer:&header exactLength:sizeof(md2_header)]; - endianswap( - &header, sizeof(int), sizeof(md2_header) / sizeof(int)); - - if (header.magic != 844121161 || header.version != 8) - return false; - - _frames = new char[header.frameSize * header.numFrames]; - if (_frames == NULL) - return false; - - [stream seekToOffset:header.offsetFrames whence:OFSeekSet]; - [stream readIntoBuffer:_frames - exactLength:header.frameSize * header.numFrames]; - - for (int i = 0; i < header.numFrames; ++i) - endianswap( - _frames + i * header.frameSize, sizeof(float), 6); - - _glCommands = new int[header.numGlCommands]; - if (_glCommands == NULL) - return false; - - [stream seekToOffset:header.offsetGlCommands whence:OFSeekSet]; - [stream readIntoBuffer:_glCommands - exactLength:header.numGlCommands * sizeof(int)]; - endianswap(_glCommands, sizeof(int), header.numGlCommands); - - _numFrames = header.numFrames; - _numGlCommands = header.numGlCommands; - _frameSize = header.frameSize; - _numTriangles = header.numTriangles; - _numVerts = header.numVertices; - - [stream close]; - - _mverts = new OFVector3D *[_numFrames]; - loopj(_numFrames) _mverts[j] = NULL; - - return true; - } -} - -float -snap(int sn, float f) -{ - return sn ? (float)(((int)(f + sn * 0.5f)) & (~(sn - 1))) : f; -} - -- (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)sn -{ - _mverts[frame] = new OFVector3D[_numVerts]; - md2_frame *cf = (md2_frame *)((char *)_frames + _frameSize * frame); - float sc = 16.0f / scale; - loop(vi, _numVerts) - { - uchar *cv = (uchar *)&cf->vertices[vi].vertex; - OFVector3D *v = &(_mverts[frame])[vi]; - v->x = (snap(sn, cv[0] * cf->scale[0]) + cf->translate[0]) / sc; - v->y = - -(snap(sn, cv[1] * cf->scale[1]) + cf->translate[1]) / sc; - v->z = (snap(sn, cv[2] * cf->scale[2]) + cf->translate[2]) / sc; - } -} - -- (void)renderWithLight:(OFVector3D &)light - frame:(int)frame - range:(int)range - x:(float)x - y:(float)y - z:(float)z - yaw:(float)yaw - pitch:(float)pitch - scale:(float)sc - speed:(float)speed - snap:(int)sn - basetime:(int)basetime -{ - loopi(range) if (!_mverts[frame + i])[self scaleWithFrame:frame + i - scale:sc - snap:sn]; - - glPushMatrix(); - glTranslatef(x, y, z); - glRotatef(yaw + 180, 0, -1, 0); - glRotatef(pitch, 0, 0, 1); - - glColor3fv((float *)&light); - - if (_displaylist && frame == 0 && range == 1) { - glCallList(_displaylist); - xtraverts += _displaylistverts; - } else { - if (frame == 0 && range == 1) { - static int displaylistn = 10; - glNewList(_displaylist = displaylistn++, GL_COMPILE); - _displaylistverts = xtraverts; - } - - int time = lastmillis - basetime; - int fr1 = (int)(time / speed); - float frac1 = (time - fr1 * speed) / speed; - float frac2 = 1 - frac1; - fr1 = fr1 % range + frame; - int fr2 = fr1 + 1; - if (fr2 >= frame + range) - fr2 = frame; - OFVector3D *verts1 = _mverts[fr1]; - OFVector3D *verts2 = _mverts[fr2]; - - for (int *command = _glCommands; (*command) != 0;) { - int numVertex = *command++; - if (numVertex > 0) { - glBegin(GL_TRIANGLE_STRIP); - } else { - glBegin(GL_TRIANGLE_FAN); - numVertex = -numVertex; - } - - loopi(numVertex) - { - float tu = *((float *)command++); - float tv = *((float *)command++); - glTexCoord2f(tu, tv); - int vn = *command++; - OFVector3D &v1 = verts1[vn]; - OFVector3D &v2 = verts2[vn]; -#define ip(c) v1.c *frac2 + v2.c *frac1 - glVertex3f(ip(x), ip(z), ip(y)); - } - - xtraverts += numVertex; - - glEnd(); - } - - if (_displaylist) { - glEndList(); - _displaylistverts = xtraverts - _displaylistverts; - } - } - - glPopMatrix(); -} - -const int FIRSTMDL = 20; +static const int FIRSTMDL = 20; void delayedload(MD2 *m) { if (!m.loaded) { @@ -263,45 +32,52 @@ m.loaded = true; } } } -int modelnum = 0; - MD2 * loadmodel(OFString *name) { @autoreleasepool { + static int modelnum = 0; + MD2 *m = mdllookup[name]; if (m != nil) return m; + m = [[MD2 alloc] init]; m.mdlnum = modelnum++; - MapModelInfo *mmi = [[MapModelInfo alloc] initWithRad:2 - h:2 - zoff:0 - snap:0 - name:@""]; - m.mmi = mmi; + m.mmi = [[MapModelInfo alloc] initWithRad:2 + h:2 + zoff:0 + snap:0 + name:@""]; m.loadname = name; + + if (mdllookup == nil) + mdllookup = [[OFMutableDictionary alloc] init]; + mdllookup[name] = m; + return m; } } void mapmodel( OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name) { MD2 *m = loadmodel(name); - MapModelInfo *mmi = - [[MapModelInfo alloc] initWithRad:(int)rad.longLongValue - h:(int)h.longLongValue - zoff:(int)zoff.longLongValue - snap:(int)snap.longLongValue - name:m.loadname]; - m.mmi = mmi; + m.mmi = [[MapModelInfo alloc] initWithRad:(int)rad.longLongValue + h:(int)h.longLongValue + zoff:(int)zoff.longLongValue + snap:(int)snap.longLongValue + name:m.loadname]; + + if (mapmodels == nil) + mapmodels = [[OFMutableArray alloc] init]; + [mapmodels addObject:m]; } COMMAND(mapmodel, ARG_5STR) void @@ -363,25 +139,5 @@ scale:scale speed:speed snap:snap basetime:basetime]; } -@end - -@implementation MapModelInfo -- (instancetype)initWithRad:(int)rad - h:(int)h - zoff:(int)zoff - snap:(int)snap - name:(OFString *)name -{ - self = [super init]; - - _rad = rad; - _h = h; - _zoff = zoff; - _snap = snap; - _name = [name copy]; - - return self; -} -@end