Index: src/cube.h ================================================================== --- src/cube.h +++ src/cube.h @@ -103,14 +103,21 @@ (y) >= ssize - MINBORD) struct block { int x, y, xs, ys; }; -struct mapmodelinfo { - int rad, h, zoff, snap; - const char *name; -}; + +@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, Index: src/entities.mm ================================================================== --- src/entities.mm +++ src/entities.mm @@ -34,21 +34,21 @@ triggertime = 0; loopv(ents) { entity &e = ents[i]; if (e.type == MAPMODEL) { - mapmodelinfo *mmi = getmminfo(e.attr2); - if (!mmi) + MapModelInfo *mmi = getmminfo(e.attr2); + if (mmi == nil) continue; @autoreleasepool { - rendermodel(@(mmi->name), 0, 1, e.attr4, - (float)mmi->rad, e.x, - (float)S(e.x, e.y)->floor + mmi->zoff + + rendermodel(mmi.name, 0, 1, e.attr4, + (float)mmi.rad, e.x, + (float)S(e.x, e.y)->floor + mmi.zoff + e.attr3, e.y, (float)((e.attr1 + 7) - (e.attr1 + 7) % 15), - 0, false, 1.0f, 10.0f, mmi->snap); + 0, false, 1.0f, 10.0f, mmi.snap); } } else { if (OUTBORD(e.x, e.y)) continue; if (e.type != CARROT) { Index: src/physics.mm ================================================================== --- src/physics.mm +++ src/physics.mm @@ -57,25 +57,25 @@ loopv(ents) { entity &e = ents[i]; if (e.type != MAPMODEL) continue; - mapmodelinfo *mmi = getmminfo(e.attr2); - if (!mmi || !mmi->h) + MapModelInfo *mmi = getmminfo(e.attr2); + if (mmi == nil || !mmi.h) continue; - const float r = mmi->rad + d->radius; + const float r = mmi.rad + d->radius; if (fabs(e.x - d->o.x) < r && fabs(e.y - d->o.y) < r) { float mmz = - (float)(S(e.x, e.y)->floor + mmi->zoff + e.attr3); + (float)(S(e.x, e.y)->floor + mmi.zoff + e.attr3); if (d->o.z - d->eyeheight < mmz) { if (mmz < hi) hi = mmz; - } else if (mmz + mmi->h > lo) - lo = mmz + mmi->h; - }; - }; -}; + } else if (mmz + mmi.h > lo) + lo = mmz + mmi.h; + } + } +} // all collision happens here // spawn is a dirty side effect used in spawning // drop & rise are supplied by the physics below to indicate gravity/push for // current mini-timestep Index: src/protos.h ================================================================== --- src/protos.h +++ src/protos.h @@ -210,11 +210,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); -extern mapmodelinfo *getmminfo(int i); +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); extern void cleanupserver(); Index: src/rendermd2.mm ================================================================== --- src/rendermd2.mm +++ src/rendermd2.mm @@ -22,48 +22,66 @@ float translate[3]; char name[16]; md2_vertex vertices[1]; }; -struct md2 { - int numGlCommands; - int *glCommands; - int numTriangles; - int frameSize; - int numFrames; - int numVerts; - char *frames; - OFVector3D **mverts; - int displaylist; - int displaylistverts; - - mapmodelinfo mmi; - char *loadname; - int mdlnum; - bool loaded; - - bool load(char *filename); - void render(OFVector3D &light, int numFrame, int range, float x, - float y, float z, float yaw, float pitch, float scale, float speed, - int snap, int basetime); - void scale(int frame, float scale, int sn); - - md2() - : numGlCommands(0), frameSize(0), numFrames(0), displaylist(0), - loaded(false) {}; - - ~md2() - { - if (glCommands) - delete[] glCommands; - if (frames) - delete[] frames; - } -}; - -bool -md2::load(char *filename) +@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)loadWithPath:(char *)filename; +- (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 + +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)loadWithPath:(char *)filename { FILE *file; md2_header header; if ((file = fopen(filename, "rb")) == NULL) @@ -73,109 +91,118 @@ 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) + _frames = new char[header.frameSize * header.numFrames]; + if (_frames == NULL) return false; fseek(file, header.offsetFrames, SEEK_SET); - fread(frames, header.frameSize * header.numFrames, 1, file); - - for (int i = 0; i < header.numFrames; ++i) { - endianswap(frames + i * header.frameSize, sizeof(float), 6); - } - - glCommands = new int[header.numGlCommands]; - if (glCommands == NULL) + fread(_frames, header.frameSize * header.numFrames, 1, file); + + 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; fseek(file, header.offsetGlCommands, SEEK_SET); - fread(glCommands, header.numGlCommands * sizeof(int), 1, file); - - endianswap(glCommands, sizeof(int), header.numGlCommands); - - numFrames = header.numFrames; - numGlCommands = header.numGlCommands; - frameSize = header.frameSize; - numTriangles = header.numTriangles; - numVerts = header.numVertices; + fread(_glCommands, header.numGlCommands * sizeof(int), 1, file); + + endianswap(_glCommands, sizeof(int), header.numGlCommands); + + _numFrames = header.numFrames; + _numGlCommands = header.numGlCommands; + _frameSize = header.frameSize; + _numTriangles = header.numTriangles; + _numVerts = header.numVertices; fclose(file); - mverts = new OFVector3D *[numFrames]; - loopj(numFrames) mverts[j] = NULL; + _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 -md2::scale(int frame, float scale, int sn) +- (void)scaleWithFrame:(int)frame scale:(float)scale snap:(int)sn { - mverts[frame] = new OFVector3D[numVerts]; - md2_frame *cf = (md2_frame *)((char *)frames + frameSize * frame); + _mverts[frame] = new OFVector3D[_numVerts]; + md2_frame *cf = (md2_frame *)((char *)_frames + _frameSize * frame); float sc = 16.0f / scale; - loop(vi, numVerts) + loop(vi, _numVerts) { uchar *cv = (uchar *)&cf->vertices[vi].vertex; - OFVector3D *v = &(mverts[frame])[vi]; + 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 -md2::render(OFVector3D &light, int frame, int range, float x, float y, float z, - float yaw, float pitch, float sc, float speed, int snap, int basetime) -{ - loopi(range) if (!mverts[frame + i]) scale(frame + i, sc, snap); + } +} + +- (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; + 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; - }; + 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]; + OFVector3D *verts1 = _mverts[fr1]; + OFVector3D *verts2 = _mverts[fr2]; - for (int *command = glCommands; (*command) != 0;) { + 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++); @@ -183,105 +210,113 @@ 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) { + if (_displaylist) { glEndList(); - displaylistverts = xtraverts - displaylistverts; - }; - }; + _displaylistverts = xtraverts - _displaylistverts; + } + } glPopMatrix(); } -hashtable *mdllookup = NULL; -vector mapmodels; const int FIRSTMDL = 20; void -delayedload(md2 *m) -{ - if (!m->loaded) { - sprintf_sd(name1)("packages/models/%s/tris.md2", m->loadname); - if (!m->load(path(name1))) - fatal("loadmodel: ", name1); - sprintf_sd(name2)("packages/models/%s/skin.jpg", m->loadname); - int xs, ys; - installtex(FIRSTMDL + m->mdlnum, path(name2), xs, ys); - m->loaded = true; +delayedload(MD2 *m) +{ + if (!m.loaded) { + @autoreleasepool { + sprintf_sd(name1)("packages/models/%s/tris.md2", + m.loadname.UTF8String); + if (![m loadWithPath:path(name1)]) + fatal("loadmodel: ", name1); + sprintf_sd(name2)("packages/models/%s/skin.jpg", + m.loadname.UTF8String); + int xs, ys; + installtex(FIRSTMDL + m.mdlnum, path(name2), xs, ys); + m.loaded = true; + } } } int modelnum = 0; -md2 * +MD2 * loadmodel(OFString *name) { @autoreleasepool { - if (!mdllookup) - mdllookup = new hashtable; - md2 **mm = mdllookup->access(name.UTF8String); - if (mm) - return *mm; - md2 *m = new md2(); - m->mdlnum = modelnum++; - mapmodelinfo mmi = {2, 2, 0, 0, ""}; - m->mmi = mmi; - m->loadname = newstring(name.UTF8String); - mdllookup->access(m->loadname, &m); + 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.loadname = name; + mdllookup[name] = m; return m; } } void mapmodel( OFString *rad, OFString *h, OFString *zoff, OFString *snap, OFString *name) { - md2 *m = loadmodel(name); - mapmodelinfo mmi = {(int)rad.longLongValue, (int)h.longLongValue, - (int)zoff.longLongValue, (int)snap.longLongValue, m->loadname}; - m->mmi = mmi; - mapmodels.add(m); + 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; + [mapmodels addObject:m]; } COMMAND(mapmodel, ARG_5STR) void mapmodelreset() { - mapmodels.setsize(0); + [mapmodels removeAllObjects]; } COMMAND(mapmodelreset, ARG_NONE) -mapmodelinfo * +MapModelInfo * getmminfo(int i) { - return i < mapmodels.length() ? &mapmodels[i]->mmi : NULL; + return i < mapmodels.count ? mapmodels[i].mmi : nil; } 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, int basetime) { - md2 *m = loadmodel(mdl); + MD2 *m = loadmodel(mdl); if (isoccluded(player1->o.x, player1->o.y, x - rad, z - rad, rad * 2)) return; delayedload(m); int xs, ys; glBindTexture(GL_TEXTURE_2D, - tex ? lookuptexture(tex, xs, ys) : FIRSTMDL + m->mdlnum); + tex ? lookuptexture(tex, xs, ys) : FIRSTMDL + m.mdlnum); int ix = (int)x; int iy = (int)z; OFVector3D light = OFMakeVector3D(1, 1, 1); @@ -290,16 +325,46 @@ float ll = 256.0f; // 0.96f; float of = 0.0f; // 0.1f; light.x = s->r / ll + of; light.y = s->g / ll + of; light.z = s->b / ll + of; - }; + } if (teammate) { light.x *= 0.6f; light.y *= 0.7f; light.z *= 1.2f; - }; + } + + [m renderWithLight:light + frame:frame + range:range + x:x + y:y + z:z + yaw:yaw + pitch:pitch + 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]; - m->render(light, frame, range, x, y, z, yaw, pitch, scale, speed, snap, - basetime); -}; + return self; +} +@end