/*---------------------------------------------------------------------------*/
-#ifdef WIN32
-#pragma comment(lib, "SDL_ttf.lib")
-#pragma comment(lib, "SDL_image.lib")
-#pragma comment(lib, "SDL_mixer.lib")
-#pragma comment(lib, "SDL.lib")
-#pragma comment(lib, "SDLmain.lib")
-#pragma comment(lib, "opengl32.lib")
-#endif
-
-/*---------------------------------------------------------------------------*/
-
-#include <SDL.h>
-#include <SDL_image.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vec3.h"
#include "solid.h"
+#include "base_image.h"
#include "base_config.h"
#define MAXSTR 256
/*---------------------------------------------------------------------------*/
+static int debug_output = 0;
+
+/*---------------------------------------------------------------------------*/
+
/* Ohhhh... arbitrary! */
-#define MAXM 256
-#define MAXV 32767
-#define MAXE 32767
-#define MAXS 32767
-#define MAXT 32767
-#define MAXG 32767
-#define MAXL 1024
-#define MAXN 1024
-#define MAXP 512
-#define MAXB 512
-#define MAXH 1024
-#define MAXZ 16
-#define MAXJ 32
-#define MAXX 256
-#define MAXR 1024
-#define MAXU 16
-#define MAXW 32
-#define MAXD 128
-#define MAXA 8192
-#define MAXI 32767
+#define MAXM 1024
+#define MAXV 65534
+#define MAXE 65534
+#define MAXS 65534
+#define MAXT 65534
+#define MAXG 65534
+#define MAXL 2048
+#define MAXN 2048
+#define MAXP 1024
+#define MAXB 1024
+#define MAXH 2048
+#define MAXZ 1024
+#define MAXJ 1024
+#define MAXX 1024
+#define MAXR 2048
+#define MAXU 1024
+#define MAXW 1024
+#define MAXD 1024
+#define MAXA 16384
+#define MAXI 65534
static int overflow(const char *s)
{
static int incz(struct s_file *fp)
{
- return (fp->zc < MAXZ) ? fp->zc++ : overflow("geol");
+ return (fp->zc < MAXZ) ? fp->zc++ : overflow("goal");
}
static int incj(struct s_file *fp)
return (fp->wc < MAXW) ? fp->wc++ : overflow("view");
}
+static int incd(struct s_file *fp)
+{
+ return (fp->dc < MAXD) ? fp->dc++ : overflow("dict");
+}
+
static int inci(struct s_file *fp)
{
return (fp->ic < MAXI) ? fp->ic++ : overflow("indx");
fp->rc = 0;
fp->uc = 0;
fp->wc = 0;
+ fp->dc = 0;
fp->ac = 0;
fp->ic = 0;
fp->rv = (struct s_bill *) calloc(MAXR, sizeof (struct s_bill));
fp->uv = (struct s_ball *) calloc(MAXU, sizeof (struct s_ball));
fp->wv = (struct s_view *) calloc(MAXW, sizeof (struct s_view));
+ fp->dv = (struct s_dict *) calloc(MAXD, sizeof (struct s_dict));
fp->av = (char *) calloc(MAXA, sizeof (char));
fp->iv = (int *) calloc(MAXI, sizeof (int));
}
* The following code caches image sizes. Textures are referenced by
* name, but their sizes are necessary when computing texture
* coordinates. This code allows each file to be accessed only once
- * regardless of the number of surfaces refering to it.
+ * regardless of the number of surfaces referring to it.
*/
struct _imagedata
static int size_load(const char *file, int *w, int *h)
{
- SDL_Surface *S;
+ void *p;
- if ((S = IMG_Load(file)))
+ if ((p = image_load(file, w, h, NULL)))
{
- *w = S->w;
- *h = S->h;
-
- SDL_FreeSurface(S);
-
+ free(p);
return 1;
}
return 0;
static void size_image(const char *name, int *w, int *h)
{
char jpg[MAXSTR];
- char tga[MAXSTR];
char png[MAXSTR];
int i;
*h = 0;
strcpy(jpg, name); strcat(jpg, ".jpg");
- strcpy(tga, name); strcat(tga, ".tga");
strcpy(png, name); strcat(png, ".png");
if (size_load(config_data(png), w, h) ||
- size_load(config_data(tga), w, h) ||
size_load(config_data(jpg), w, h))
{
mp->e[0] = mp->e[1] = mp->e[2] = mp->e[3] = 1.0f;
mp->h[0] = 0.0f;
mp->fl = 0;
+ mp->angle = 45.0f;
if ((fin = fopen(config_data(name), "r")))
{
"%f %f %f %f "
"%f %f %f %f "
"%f %f %f %f "
- "%f %d ",
+ "%f %d %f",
mp->d, mp->d + 1, mp->d + 2, mp->d + 3,
mp->a, mp->a + 1, mp->a + 2, mp->a + 3,
mp->s, mp->s + 1, mp->s + 2, mp->s + 3,
mp->e, mp->e + 1, mp->e + 2, mp->e + 3,
- mp->h, &mp->fl);
+ mp->h, &mp->fl, &mp->angle);
fclose(fin);
}
static void move_body(struct s_file *fp,
struct s_body *bp)
{
- int i;
+ int i, *b;
+
+ /* Move the lumps. */
for (i = 0; i < bp->lc; i++)
move_lump(fp, fp->lv + bp->l0 + i, fp->pv[bp->pi].p);
+
+ /* Create an array to mark any verts referenced by moved geoms. */
+
+ if (bp->gc > 0 && (b = (int *) calloc(fp->vc, sizeof (int))))
+ {
+ /* Mark the verts. */
+
+ for (i = 0; i < bp->gc; i++)
+ {
+ b[fp->gv[fp->iv[bp->g0 + i]].vi] = 1;
+ b[fp->gv[fp->iv[bp->g0 + i]].vj] = 1;
+ b[fp->gv[fp->iv[bp->g0 + i]].vk] = 1;
+ }
+
+ /* Apply the motion to the marked vertices. */
+
+ for (i = 0; i < fp->vc; ++i)
+ if (b[i])
+ move_vert(fp->vv + i, fp->pv[bp->pi].p);
+
+ free(b);
+ }
}
static void move_file(struct s_file *fp)
/* Scan a key-value pair. */
- if (buf[0] == '"')
+ if (buf[0] == '\"')
{
strcpy(key, strtok(buf, "\""));
(void) strtok(NULL, "\"");
pp->t = 1.f;
pp->pi = pi;
pp->f = 1;
+ pp->s = 1;
for (i = 0; i < c; i++)
{
if (strcmp(k[i], "speed") == 0)
sscanf(v[i], "%f", &pp->t);
+ if (strcmp(k[i], "smooth") == 0)
+ pp->s = atoi(v[i]);
+
if (strcmp(k[i], "origin") == 0)
{
int x = 0, y = 0, z = 0;
}
}
+static void make_dict(struct s_file *fp,
+ const char *k,
+ const char *v)
+{
+ int space_left, space_needed, di = incd(fp);
+
+ struct s_dict *dp = fp->dv + di;
+
+ space_left = MAXA - fp->ac;
+ space_needed = strlen(k) + 1 + strlen(v) + 1;
+
+ if (space_needed > space_left)
+ {
+ fp->dc--;
+ return;
+ }
+
+ dp->ai = fp->ac;
+ dp->aj = dp->ai + strlen(k) + 1;
+ fp->ac = dp->aj + strlen(v) + 1;
+
+ strncpy(fp->av + dp->ai, k, space_left);
+ strncpy(fp->av + dp->aj, v, space_left - strlen(k) - 1);
+}
+
+static int read_dict_entries = 0;
+
static void make_body(struct s_file *fp,
char k[][MAXSTR],
char v[][MAXSTR], int c, int l0)
else if (strcmp(k[i], "origin") == 0)
sscanf(v[i], "%d %d %d", &x, &y, &z);
- else if (strcmp(k[i], "classname") != 0)
- {
- /* Considers other strings as metadata */
- strcat(fp->av, k[i]);
- strcat(fp->av, "=");
- strcat(fp->av, v[i]);
- strcat(fp->av, "\n");
- fp->ac += (int) (strlen(v[i]) + (strlen(k[i])) + 2);
- }
+ else if (read_dict_entries && strcmp(k[i], "classname") != 0)
+ make_dict(fp, k[i], v[i]);
}
bp->l0 = l0;
for (i = v0; i < fp->vc; i++)
v_add(fp->vv[i].p, fp->vv[i].p, p);
+
+ read_dict_entries = 0;
}
static void make_item(struct s_file *fp,
zp->p[1] = 0.f;
zp->p[2] = 0.f;
zp->r = 0.75;
- zp->s = 0;
- zp->c = 0;
for (i = 0; i < c; i++)
{
if (strcmp(k[i], "radius") == 0)
sscanf(v[i], "%f", &zp->r);
- if (strcmp(k[i], "skip") == 0)
- sscanf(v[i], "%d", &zp->s);
- if (strcmp(k[i], "special") == 0)
- sscanf(v[i], "%d", &zp->c);
if (strcmp(k[i], "origin") == 0)
{
sscanf(v[i], "%f", &xp->t0);
if (strcmp(k[i], "state") == 0)
- xp->f = atoi(v[i]);
+ {
+ xp->f = atoi(v[i]);
+ xp->f0 = atoi(v[i]);
+ }
if (strcmp(k[i], "invisible") == 0)
xp->i = atoi(v[i]);
if (!strcmp(v[i], "info_player_deathmatch")) make_goal(fp, k, v, c);
if (!strcmp(v[i], "target_teleporter")) make_jump(fp, k, v, c);
if (!strcmp(v[i], "target_position")) make_targ(fp, k, v, c);
- if (!strcmp(v[i], "worldspawn")) make_body(fp, k, v, c, l0);
+ if (!strcmp(v[i], "worldspawn"))
+ {
+ read_dict_entries = 1;
+ make_body(fp, k, v, c, l0);
+ }
if (!strcmp(v[i], "func_train")) make_body(fp, k, v, c, l0);
if (!strcmp(v[i], "misc_model")) make_body(fp, k, v, c, l0);
}
/*
* Find all verts that lie on the given side of the lump. Sort these
* verts to have a counter-clockwise winding about the plane normal.
- * Create geoms to tessalate the resulting convex polygon.
+ * Create geoms to tessellate the resulting convex polygon.
*/
static void clip_geom(struct s_file *fp,
struct s_lump *lp, int si)
}
/*
- * Iterate the sides of the lump, attemping to generate a new vert for
+ * Iterate the sides of the lump, attempting to generate a new vert for
* each trio of planes, a new edge for each pair of planes, and a new
* set of geom for each visible plane.
*/
/*
* For each body element type, determine if element 'p' is equivalent
* to element 'q'. This is more than a simple memory compare. It
- * effectively snaps mtrls and verts togather, and may reverse the
+ * effectively snaps mtrls and verts together, and may reverse the
* winding of an edge or a geom. This is done in order to maximize
* the number of elements that can be eliminated.
*/
static void uniq_file(struct s_file *fp)
{
- uniq_mtrl(fp);
- uniq_vert(fp);
- uniq_edge(fp);
- uniq_side(fp);
- uniq_texc(fp);
- uniq_geom(fp);
+ /* Debug mode skips optimization, producing oversized output files. */
+
+ if (debug_output == 0)
+ {
+ uniq_mtrl(fp);
+ uniq_vert(fp);
+ uniq_edge(fp);
+ uniq_side(fp);
+ uniq_texc(fp);
+ uniq_geom(fp);
+ }
+}
+
+/*---------------------------------------------------------------------------*/
+
+struct s_trip
+{
+ int vi;
+ int mi;
+ int si;
+ int gi;
+};
+
+static int comp_trip(const void *p, const void *q)
+{
+ const struct s_trip *tp = (const struct s_trip *) p;
+ const struct s_trip *tq = (const struct s_trip *) q;
+
+ if (tp->vi < tq->vi) return -1;
+ if (tp->vi > tq->vi) return +1;
+ if (tp->mi < tq->mi) return -1;
+ if (tp->mi > tq->mi) return +1;
+
+ return 0;
}
+static void smth_file(struct s_file *fp)
+{
+ struct s_trip temp, *T;
+
+ if (debug_output == 0)
+ {
+ if ((T = (struct s_trip *) malloc(fp->gc * 3 * sizeof (struct s_trip))))
+ {
+ int gi, i, j, k, l, c = 0;
+
+ /* Create a list of all non-faceted vertex triplets. */
+
+ for (gi = 0; gi < fp->gc; ++gi)
+ {
+ struct s_geom *gp = fp->gv + gi;
+
+ T[c].vi = gp->vi;
+ T[c].mi = gp->mi;
+ T[c].si = gp->si;
+ T[c].gi = gi;
+ c++;
+
+ T[c].vi = gp->vj;
+ T[c].mi = gp->mi;
+ T[c].si = gp->sj;
+ T[c].gi = gi;
+ c++;
+
+ T[c].vi = gp->vk;
+ T[c].mi = gp->mi;
+ T[c].si = gp->sk;
+ T[c].gi = gi;
+ c++;
+ }
+
+ /* Sort all triplets by vertex index and material. */
+
+ qsort(T, c, sizeof (struct s_trip), comp_trip);
+
+ /* For each set of triplets sharing vertex index and material... */
+
+ for (i = 0; i < c; i = l)
+ {
+ int acc = 0;
+
+ float N[3], angle = fp->mv[T[i].mi].angle;
+ const float *Ni = fp->sv[T[i].si].n;
+
+ /* Sort the set by side similarity to the first. */
+
+ for (j = i + 1; j < c && (T[j].vi == T[i].vi &&
+ T[j].mi == T[i].mi); ++j)
+ {
+ for (k = j + 1; k < c && (T[k].vi == T[i].vi &&
+ T[k].mi == T[i].mi); ++k)
+ {
+ const float *Nj = fp->sv[T[j].si].n;
+ const float *Nk = fp->sv[T[k].si].n;
+
+ if (T[j].si != T[k].si && v_dot(Nk, Ni) > v_dot(Nj, Ni))
+ {
+ temp = T[k];
+ T[k] = T[j];
+ T[j] = temp;
+ }
+ }
+ }
+
+ /* Accumulate all similar side normals. */
+
+ N[0] = Ni[0];
+ N[1] = Ni[1];
+ N[2] = Ni[2];
+
+ for (l = i + 1; l < c && (T[l].vi == T[i].vi &&
+ T[l].mi == T[i].mi); ++l)
+ if (T[l].si != T[i].si)
+ {
+ const float *Nl = fp->sv[T[l].si].n;
+
+ if (V_DEG(facosf(v_dot(Ni, Nl))) > angle)
+ break;
+
+ N[0] += Nl[0];
+ N[1] += Nl[1];
+ N[2] += Nl[2];
+
+ acc++;
+ }
+
+ /* If at least two normals have been accumulated... */
+
+ if (acc)
+ {
+ /* Store the accumulated normal as a new side. */
+
+ int ss = incs(fp);
+
+ v_nrm(fp->sv[ss].n, N);
+ fp->sv[ss].d = 0.0f;
+
+ /* Assign the new normal to the merged triplets. */
+
+ for (j = i; j < l; ++j)
+ T[j].si = ss;
+ }
+ }
+
+ /* Assign the remapped normals to the original geoms. */
+
+ for (i = 0; i < c; ++i)
+ {
+ struct s_geom *gp = fp->gv + T[i].gi;
+
+ if (gp->vi == T[i].vi) gp->si = T[i].si;
+ if (gp->vj == T[i].vi) gp->sj = T[i].si;
+ if (gp->vk == T[i].vi) gp->sk = T[i].si;
+ }
+
+ free(T);
+ }
+
+ uniq_side(fp);
+ }
+}
+
+
/*---------------------------------------------------------------------------*/
static void sort_file(struct s_file *fp)
/* Flag each lump with its position WRT the side. */
for (li = 0; li < lc; li++)
- switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
+ if (debug_output)
+ {
+ fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
+ }
+ else
{
- case +1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10; break;
- case 0: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20; break;
- case -1: fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40; break;
+ switch (test_lump_side(fp, fp->lv + l0 + li, fp->sv + sj))
+ {
+ case +1:
+ fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x10;
+ break;
+
+ case 0:
+ fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x20;
+ break;
+
+ case -1:
+ fp->lv[l0+li].fl = (fp->lv[l0+li].fl & 1) | 0x40;
+ break;
+ }
}
/* Sort all lumps in the range by their flag values. */
" geom lump path node body\n"
"%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n"
" item goal view jump swch"
- " bill ball char indx\n"
- "%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
+ " bill ball char dict indx\n"
+ "%6d%6d%6d%6d%6d%6d%6d%6d%6d%6d\n",
#if 0
name, n, m, c,
#endif
p->mc, p->vc, p->ec, p->sc, p->tc,
p->gc, p->lc, p->pc, p->nc, p->bc,
p->hc, p->zc, p->wc, p->jc, p->xc,
- p->rc, p->uc, p->ac, p->ic);
+ p->rc, p->uc, p->ac, p->dc, p->ic);
}
-/* Skip the ugly SDL main substitution since we only need sdl_image. */
-#ifdef main
-# undef main
-#endif
-
int main(int argc, char *argv[])
{
char src[MAXSTR];
if (argc > 2)
{
+ if (argc > 3 && strcmp(argv[3], "--debug") == 0)
+ debug_output = 1;
+
if (config_data_path(argv[2], NULL))
{
strncpy(src, argv[1], MAXSTR);
clip_file(&f);
move_file(&f);
uniq_file(&f);
+ smth_file(&f);
sort_file(&f);
node_file(&f);
dump_file(&f, dst);
}
else fprintf(stderr, "Failure to establish data directory\n");
}
- else fprintf(stderr, "Usage: %s <map> [data]\n", argv[0]);
+ else fprintf(stderr, "Usage: %s <map> <data> [--debug]\n", argv[0]);
return 0;
}