#include "glext.h"
#include "vec3.h"
+#include "geom.h"
#include "image.h"
#include "base_image.h"
#include "base_config.h"
/*---------------------------------------------------------------------------*/
-static int sol_enum_mtrl(const struct s_base *base,
- const struct b_body *bp, int mi)
+/* EXCLUDED material flags for each rendering pass. */
+
+static const int pass_ex[] = {
+ M_REFLECTIVE | M_TRANSPARENT | M_DECAL,
+ M_REFLECTIVE | M_TRANSPARENT,
+ M_REFLECTIVE,
+ M_REFLECTIVE | M_DECAL,
+ 0,
+};
+
+/* INCLUDED material flags for each rendering pass. */
+
+static const int pass_in[] = {
+ 0,
+ M_DECAL,
+ M_DECAL | M_TRANSPARENT,
+ M_TRANSPARENT,
+ M_REFLECTIVE,
+};
+
+/*---------------------------------------------------------------------------*/
+
+static void sol_transform(const struct s_vary *vary,
+ const struct v_body *bp, int ui)
{
- int li, gi, c = 0;
+ float a;
+ float e[4];
+ float p[3];
+ float v[3];
- /* Count all lump geoms with this material. */
+ /* Apply the body position and rotation to the model-view matrix. */
- for (li = 0; li < bp->lc; li++)
+ sol_body_p(p, vary, bp->pi, bp->t);
+ sol_body_e(e, vary, bp, 0);
+
+ q_as_axisangle(e, v, &a);
+
+ glTranslatef(p[0], p[1], p[2]);
+ glRotatef(V_DEG(a), v[0], v[1], v[2]);
+
+ /* Apply the shadow transform to the texture matrix. */
+
+ if (ui >= 0 && ui < vary->uc && vary->uv[ui].r > 0.0f)
{
- int g0 = base->lv[bp->l0 + li].g0;
- int gc = base->lv[bp->l0 + li].gc;
+ struct v_ball *up = vary->uv + ui;
+
+ if (tex_env_stage(TEX_STAGE_SHADOW))
+ {
+ glMatrixMode(GL_TEXTURE);
+ {
+ float k = 0.25f / up->r;
+
+ glLoadIdentity();
+
+ /* Center the shadow texture on the ball. */
+
+ glTranslatef(0.5f, 0.5f, 0.0f);
+
+ /* Transform ball XZ position to ST texture coordinate. */
+
+ glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
- for (gi = 0; gi < gc; gi++)
- if (base->gv[base->iv[g0 + gi]].mi == mi)
- c++;
+ /* Scale the shadow texture to the radius of the ball. */
+
+ glScalef(k, k, k);
+
+ /* Move the shadow texture under the ball. */
+
+ glTranslatef(-up->p[0], -up->p[1], -up->p[2]);
+
+ /* Apply the body position and rotation. */
+
+ glTranslatef(p[0], p[1], p[2]);
+ glRotatef(V_DEG(a), v[0], v[1], v[2]);
+
+ /* Vertically center clipper texture on ball position. */
+
+ if (tex_env_stage(TEX_STAGE_CLIP))
+ {
+ glLoadIdentity();
+ glTranslatef(p[0] - up->p[0],
+ p[1] - up->p[1] + 0.5f,
+ p[2] - up->p[2]);
+ glRotatef(V_DEG(a), v[0], v[1], v[2]);
+
+ }
+ }
+ glMatrixMode(GL_MODELVIEW);
+
+ tex_env_stage(TEX_STAGE_TEXTURE);
+ }
}
+}
- /* Count all body geoms with this material. */
+/*---------------------------------------------------------------------------*/
- for (gi = 0; gi < bp->gc; gi++)
- if (base->gv[base->iv[bp->g0 + gi]].mi == mi)
- c++;
+static void sol_load_bill(struct s_draw *draw)
+{
+ static const GLfloat data[] = {
+ 0.0f, 0.0f, -1.0f, -1.0f,
+ 1.0f, 0.0f, 1.0f, -1.0f,
+ 0.0f, 1.0f, -1.0f, 1.0f,
+ 1.0f, 1.0f, 1.0f, 1.0f,
+
+ 0.0f, 0.0f, -0.5f, 0.0f,
+ 1.0f, 0.0f, 0.5f, 0.0f,
+ 0.0f, 1.0f, -0.5f, 1.0f,
+ 1.0f, 1.0f, 0.5f, 1.0f,
+
+ 0.0f, 0.0f, -0.5f, -0.5f,
+ 1.0f, 0.0f, 0.5f, -0.5f,
+ 0.0f, 1.0f, -0.5f, 0.5f,
+ 1.0f, 1.0f, 0.5f, 0.5f,
+ };
+
+ /* Initialize a vertex buffer object for billboard drawing. */
+
+ glGenBuffers_(1, &draw->bill);
+ glBindBuffer_(GL_ARRAY_BUFFER, draw->bill);
+ glBufferData_(GL_ARRAY_BUFFER, sizeof (data), data, GL_STATIC_DRAW);
+ glBindBuffer_(GL_ARRAY_BUFFER, 0);
+}
- return c;
+static void sol_free_bill(struct s_draw *draw)
+{
+ if (glIsBuffer_(draw->bill))
+ glDeleteBuffers_(1, &draw->bill);
}
-static int sol_enum_body(const struct s_base *base,
- const struct b_body *bp, int fl)
+static void sol_draw_bill(GLfloat w, GLfloat h, GLboolean edge)
{
- int mi, c = 0;
+ glPushMatrix();
+ {
+ glScalef(0.5f * w, 0.5f * h, 1.0f);
- /* Count all geoms with this flag. */
+ if (edge)
+ glTranslatef(0.0f, 0.5f, 0.0f);
- for (mi = 0; mi < base->mc; mi++)
- if (base->mv[mi].fl & fl)
- c = c + sol_enum_mtrl(base, bp, mi);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ }
+ glPopMatrix();
+}
- return c;
+/*---------------------------------------------------------------------------*/
+
+/* NOTE: The state management here presumes that billboard rendering is */
+/* NESTED within a wider SOL rendering process. That is: sol_draw_enable */
+/* has been called and sol_draw_disable will be called in the future. */
+/* Thus the "default" VBO state retained by billboard rendering is the */
+/* state appropriate for normal SOL rendering. */
+
+static void sol_bill_enable(const struct s_draw *draw)
+{
+ const size_t s = sizeof (GLfloat);
+
+ glBindBuffer_(GL_ARRAY_BUFFER, draw->bill);
+
+ glTexCoordPointer(2, GL_FLOAT, s * 4, (GLvoid *) ( 0));
+ glVertexPointer (2, GL_FLOAT, s * 4, (GLvoid *) (s * 2));
+}
+
+static void sol_bill_disable(void)
+{
}
/*---------------------------------------------------------------------------*/
#define tobyte(f) ((GLubyte) (f * 255.0f))
-#define color_cmp(a, b) (tobyte((a)[0]) == tobyte((b)[0]) && \
- tobyte((a)[1]) == tobyte((b)[1]) && \
- tobyte((a)[2]) == tobyte((b)[2]) && \
- tobyte((a)[3]) == tobyte((b)[3]))
-
static struct b_mtrl default_base_mtrl =
{
{ 0.8f, 0.8f, 0.8f, 1.0f },
{ 0.2f, 0.2f, 0.2f, 1.0f },
{ 0.0f, 0.0f, 0.0f, 1.0f },
{ 0.0f, 0.0f, 0.0f, 1.0f },
- { 0.0f }, 0.0f, M_OPAQUE, ""
+ { 0.0f }, 0.0f, 0, ""
};
+/* Nasty. */
+
static struct d_mtrl default_draw_mtrl =
{
- &default_base_mtrl, 0
+ &default_base_mtrl,
+ 0xffcccccc,
+ 0xff333333,
+ 0xff000000,
+ 0xff000000,
+ 0x00000000,
+ 0
};
-static const struct d_mtrl *sol_draw_mtrl(const struct s_draw *draw,
- const struct d_mtrl *mp_draw,
- const struct d_mtrl *mq_draw)
+void sol_apply_mtrl(const struct d_mtrl *mp_draw, struct s_rend *rend)
{
const struct b_mtrl *mp_base = mp_draw->base;
+ const struct d_mtrl *mq_draw = rend->mp;
const struct b_mtrl *mq_base = mq_draw->base;
- /* Change material properties only as needed. */
+ /* Bind the texture. */
- if (!color_cmp(mp_base->a, mq_base->a))
- glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mp_base->a);
- if (!color_cmp(mp_base->d, mq_base->d))
+ if (mp_draw->o != mq_draw->o)
+ glBindTexture(GL_TEXTURE_2D, mp_draw->o);
+
+ /* Set material properties. */
+
+ if (mp_draw->d != mq_draw->d)
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp_base->d);
- if (!color_cmp(mp_base->s, mq_base->s))
+ if (mp_draw->a != mq_draw->a)
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mp_base->a);
+ if (mp_draw->s != mq_draw->s)
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mp_base->s);
- if (!color_cmp(mp_base->e, mq_base->e))
+ if (mp_draw->e != mq_draw->e)
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mp_base->e);
- if (tobyte(mp_base->h[0]) != tobyte(mq_base->h[0]))
+ if (mp_draw->h != mq_draw->h)
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mp_base->h);
- /* Bind the texture. */
+ /* Ball shadow. */
- if (mp_draw->o != mq_draw->o)
- glBindTexture(GL_TEXTURE_2D, mp_draw->o);
+ if ((mp_base->fl & M_SHADOWED) ^ (mq_base->fl & M_SHADOWED))
+ {
+ if (mp_base->fl & M_SHADOWED)
+ shad_draw_set();
+ else
+ shad_draw_clr();
+ }
- /* Enable environment mapping. */
+ /* Environment mapping. */
- if ((mp_base->fl & M_ENVIRONMENT) && !(mq_base->fl & M_ENVIRONMENT))
+#if !ENABLE_OPENGLES
+ if ((mp_base->fl & M_ENVIRONMENT) ^ (mq_base->fl & M_ENVIRONMENT))
{
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
+ if (mp_base->fl & M_ENVIRONMENT)
+ {
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+ }
+ else
+ {
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ }
}
+#endif
- /* Disable environment mapping. */
+ /* Additive blending. */
- if ((mq_base->fl & M_ENVIRONMENT) && !(mp_base->fl & M_ENVIRONMENT))
+ if ((mp_base->fl & M_ADDITIVE) ^ (mq_base->fl & M_ADDITIVE))
{
- glDisable(GL_TEXTURE_GEN_S);
- glDisable(GL_TEXTURE_GEN_T);
+ if (mp_base->fl & M_ADDITIVE)
+ glBlendFunc(GL_ONE, GL_ONE);
+ else
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
- /* Enable additive blending. */
-
- if ((mp_base->fl & M_ADDITIVE) && !(mq_base->fl & M_ADDITIVE))
- glBlendFunc(GL_ONE, GL_ONE);
-
- /* Enable standard blending. */
-
- if ((mq_base->fl & M_ADDITIVE) && !(mp_base->fl & M_ADDITIVE))
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- /* Enable visibility-from-behind. */
+ /* Visibility-from-behind. */
- if ((mp_base->fl & M_TWO_SIDED) && !(mq_base->fl & M_TWO_SIDED))
+ if ((mp_base->fl & M_TWO_SIDED) ^ (mq_base->fl & M_TWO_SIDED))
{
- glDisable(GL_CULL_FACE);
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
+ if (mp_base->fl & M_TWO_SIDED)
+ {
+ glDisable(GL_CULL_FACE);
+ glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1);
+ }
+ else
+ {
+ glEnable(GL_CULL_FACE);
+ glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 0);
+ }
}
- /* Disable visibility-from-behind. */
+ /* Decal offset. */
- if ((mq_base->fl & M_TWO_SIDED) && !(mp_base->fl & M_TWO_SIDED))
+ if ((mp_base->fl & M_DECAL) ^ (mq_base->fl & M_DECAL))
{
- glEnable(GL_CULL_FACE);
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
+ if (mp_base->fl & M_DECAL)
+ {
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(-1.0f, -2.0f);
+ }
+ else
+ glDisable(GL_POLYGON_OFFSET_FILL);
}
- /* Enable decal offset. */
+ rend->mp = mp_draw;
+}
- if ((mp_base->fl & M_DECAL) && !(mq_base->fl & M_DECAL))
- {
- glEnable(GL_POLYGON_OFFSET_FILL);
- glPolygonOffset(-1.0f, -2.0f);
- }
+static GLuint sol_find_texture(const char *name)
+{
+ char png[MAXSTR];
+ char jpg[MAXSTR];
- /* Disable decal offset. */
+ GLuint o;
- if ((mq_base->fl & M_DECAL) && !(mp_base->fl & M_DECAL))
- glDisable(GL_POLYGON_OFFSET_FILL);
+ /* Prefer a lossless copy of the texture over a lossy compression. */
- return mp_draw;
-}
+ strncpy(png, name, PATHMAX); strcat(png, ".png");
+ strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
-static const struct d_mtrl *sol_back_bill(const struct s_draw *draw,
- const struct b_bill *rp,
- const struct d_mtrl *mp,
- float t)
-{
- float T = (rp->t > 0.0f) ? (fmodf(t, rp->t) - rp->t / 2) : 0.0f;
+ /* Check for a PNG. */
- float w = rp->w[0] + rp->w[1] * T + rp->w[2] * T * T;
- float h = rp->h[0] + rp->h[1] * T + rp->h[2] * T * T;
+ if ((o = make_image_from_file(png)))
+ return o;
- if (w > 0 && h > 0)
- {
- float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * T * T;
- float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * T * T;
- float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * T * T;
+ /* Check for a JPG. */
- glPushMatrix();
- {
- float y0 = (rp->fl & B_EDGE) ? 0 : -h / 2;
- float y1 = (rp->fl & B_EDGE) ? h : +h / 2;
+ if ((o = make_image_from_file(jpg)))
+ return o;
- glRotatef(ry, 0.0f, 1.0f, 0.0f);
- glRotatef(rx, 1.0f, 0.0f, 0.0f);
- glTranslatef(0.0f, 0.0f, -rp->d);
+ return 0;
+}
- if (rp->fl & B_FLAT)
- {
- glRotatef(-rx - 90.0f, 1.0f, 0.0f, 0.0f);
- glRotatef(-ry, 0.0f, 0.0f, 1.0f);
- }
- if (rp->fl & B_EDGE)
- glRotatef(-rx, 1.0f, 0.0f, 0.0f);
+void sol_load_mtrl(struct d_mtrl *mp, const struct b_mtrl *mq)
+{
+ mp->base = mq;
- glRotatef(rz, 0.0f, 0.0f, 1.0f);
+ if ((mp->o = sol_find_texture(_(mq->f))))
+ {
+ /* Set the texture to clamp or repeat based on material type. */
- mp = sol_draw_mtrl(draw, draw->mv + rp->mi, mp);
+ if (mq->fl & M_CLAMP_S)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glBegin(GL_QUADS);
- {
- glTexCoord2f(0.0f, 0.0f); glVertex2f(-w / 2, y0);
- glTexCoord2f(1.0f, 0.0f); glVertex2f(+w / 2, y0);
- glTexCoord2f(1.0f, 1.0f); glVertex2f(+w / 2, y1);
- glTexCoord2f(0.0f, 1.0f); glVertex2f(-w / 2, y1);
- }
- glEnd();
- }
- glPopMatrix();
+ if (mq->fl & M_CLAMP_T)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ else
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
- return mp;
+ /* Cache the 32-bit material values for quick comparison. */
+
+ mp->d = (tobyte(mq->d[0]))
+ | (tobyte(mq->d[1]) << 8)
+ | (tobyte(mq->d[2]) << 16)
+ | (tobyte(mq->d[3]) << 24);
+ mp->a = (tobyte(mq->a[0]))
+ | (tobyte(mq->a[1]) << 8)
+ | (tobyte(mq->a[2]) << 16)
+ | (tobyte(mq->a[3]) << 24);
+ mp->s = (tobyte(mq->s[0]))
+ | (tobyte(mq->s[1]) << 8)
+ | (tobyte(mq->s[2]) << 16)
+ | (tobyte(mq->s[3]) << 24);
+ mp->e = (tobyte(mq->e[0]))
+ | (tobyte(mq->e[1]) << 8)
+ | (tobyte(mq->e[2]) << 16)
+ | (tobyte(mq->e[3]) << 24);
+ mp->h = (tobyte(mq->h[0]));
}
-/*---------------------------------------------------------------------------*/
+void sol_free_mtrl(struct d_mtrl *mp)
+{
+ if (glIsTexture(mp->o))
+ glDeleteTextures(1, &mp->o);
+}
-void sol_back(const struct s_draw *draw, float n, float f, float t)
+static int sol_test_mtrl(const struct d_mtrl *mp, int p)
{
- const struct d_mtrl *mp = &default_draw_mtrl;
+ /* Test whether the material flags exclude f0 and include f1. */
- int ri;
+ return ((mp->base->fl & pass_in[p]) == pass_in[p] &&
+ (mp->base->fl & pass_ex[p]) == 0);
+}
- /* Render all billboards in the given range. */
+/*---------------------------------------------------------------------------*/
- if (draw && draw->base)
- {
- glDisable(GL_LIGHTING);
- glDepthMask(GL_FALSE);
- {
- for (ri = 0; ri < draw->base->rc; ri++)
- if (n <= draw->base->rv[ri].d && draw->base->rv[ri].d < f)
- mp = sol_back_bill(draw, draw->base->rv + ri, mp, t);
+static int sol_count_geom(const struct s_base *base, int g0, int gc, int mi)
+{
+ int gi, c = 0;
- mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
- }
- glDepthMask(GL_TRUE);
- glEnable(GL_LIGHTING);
- }
-}
+ /* The arguments g0 and gc specify a range of the index array. These */
+ /* indices refer to geoms. Determine how many of these geoms use the */
+ /* given material */
-/*---------------------------------------------------------------------------*/
-/*
- * The following code renders a body in a ludicrously inefficient
- * manner. It iterates the materials and scans the data structure for
- * geometry using each. This has the effect of absolutely minimizing
- * material changes, texture bindings, and Begin/End pairs, but
- * maximizing trips through the data.
- *
- * However, this is only done once for each level. The results are
- * stored in display lists. Thus, it is well worth it.
- */
+ for (gi = 0; gi < gc; gi++)
+ if (base->gv[base->iv[g0 + gi]].mi == mi)
+ c++;
+
+ return c;
+}
-static void sol_draw_geom(const struct s_base *base,
- const struct b_geom *gp, int mi)
+static int sol_count_body(const struct b_body *bp,
+ const struct s_base *base, int mi)
{
- if (gp->mi == mi)
- {
- const float *ui = base->tv[gp->ti].u;
- const float *uj = base->tv[gp->tj].u;
- const float *uk = base->tv[gp->tk].u;
+ int li, c = 0;
- const float *ni = base->sv[gp->si].n;
- const float *nj = base->sv[gp->sj].n;
- const float *nk = base->sv[gp->sk].n;
+ /* Count all lump geoms with the given material. */
- const float *vi = base->vv[gp->vi].p;
- const float *vj = base->vv[gp->vj].p;
- const float *vk = base->vv[gp->vk].p;
+ for (li = 0; li < bp->lc; li++)
+ c += sol_count_geom(base, base->lv[bp->l0 + li].g0,
+ base->lv[bp->l0 + li].gc, mi);
- glTexCoord2fv(ui);
- glNormal3fv(ni);
- glVertex3fv(vi);
+ /* Count all body geoms with the given material. */
- glTexCoord2fv(uj);
- glNormal3fv(nj);
- glVertex3fv(vj);
+ c += sol_count_geom(base, bp->g0, bp->gc, mi);
- glTexCoord2fv(uk);
- glNormal3fv(nk);
- glVertex3fv(vk);
- }
+ return c;
}
-static void sol_draw_lump(const struct s_base *base,
- const struct b_lump *lp, int mi)
+static int sol_count_mesh(const struct d_body *bp, int p)
{
- int i;
+ int mi, c = 0;
- for (i = 0; i < lp->gc; i++)
- sol_draw_geom(base, base->gv + base->iv[lp->g0 + i], mi);
+ /* Count the body meshes matching the given material flags. */
+
+ for (mi = 0; mi < bp->mc; ++mi)
+ if (sol_test_mtrl(bp->mv[mi].mp, p))
+ c++;
+
+ return c;
}
-static const struct d_mtrl *sol_draw_body(const struct s_draw *draw,
- const struct b_body *bp,
- const struct d_mtrl *mp,
- int fl, int decal)
+/*---------------------------------------------------------------------------*/
+
+static void sol_mesh_vert(struct d_vert *vp,
+ const struct s_base *base, int oi)
{
- const struct s_base *base = draw->base;
+ /* Gather all vertex attributes for the given offs. */
- int mi, li, gi;
+ const struct b_texc *tq = base->tv + base->ov[oi].ti;
+ const struct b_side *sq = base->sv + base->ov[oi].si;
+ const struct b_vert *vq = base->vv + base->ov[oi].vi;
- /* Iterate all materials of the correct opacity. */
+ vp->p[0] = vq->p[0];
+ vp->p[1] = vq->p[1];
+ vp->p[2] = vq->p[2];
- for (mi = 0; mi < draw->mc; mi++)
+ vp->n[0] = sq->n[0];
+ vp->n[1] = sq->n[1];
+ vp->n[2] = sq->n[2];
+
+ vp->t[0] = tq->u[0];
+ vp->t[1] = tq->u[1];
+}
+
+static void sol_mesh_geom(struct d_vert *vv, int *vn,
+ struct d_geom *gv, int *gn,
+ const struct s_base *base, int *iv, int g0, int gc, int mi)
+{
+ int gi;
+
+ /* Insert all geoms with material mi into the vertex and element data. */
+
+ for (gi = 0; gi < gc; gi++)
{
- struct d_mtrl *mq = draw->mv + mi;
+ const struct b_geom *gq = base->gv + base->iv[g0 + gi];
- if ((mq->base->fl & fl) && (mq->base->fl & M_DECAL) == decal)
+ if (gq->mi == mi)
{
- if (sol_enum_mtrl(draw->base, bp, mi))
+ /* Insert a d_vert into the VBO data for each referenced b_off. */
+
+ if (iv[gq->oi] == -1)
+ {
+ iv[gq->oi] = *vn;
+ sol_mesh_vert(vv + (*vn)++, base, gq->oi);
+ }
+ if (iv[gq->oj] == -1)
+ {
+ iv[gq->oj] = *vn;
+ sol_mesh_vert(vv + (*vn)++, base, gq->oj);
+ }
+ if (iv[gq->ok] == -1)
{
- /* Set the material state. */
+ iv[gq->ok] = *vn;
+ sol_mesh_vert(vv + (*vn)++, base, gq->ok);
+ }
- mp = sol_draw_mtrl(draw, mq, mp);
+ /* Populate the EBO data using remapped b_off indices. */
- /* Render all geometry of that material. */
+ gv[*gn].i = iv[gq->oi];
+ gv[*gn].j = iv[gq->oj];
+ gv[*gn].k = iv[gq->ok];
- glBegin(GL_TRIANGLES);
- {
- for (li = 0; li < bp->lc; li++)
- sol_draw_lump(draw->base,
- base->lv + bp->l0 + li,
- mi);
- for (gi = 0; gi < bp->gc; gi++)
- sol_draw_geom(draw->base,
- base->gv + base->iv[bp->g0 + gi],
- mi);
- }
- glEnd();
- }
+ (*gn)++;
}
}
-
- return mp;
}
-static void sol_draw_list(const struct s_vary *vary,
- const struct v_body *bp, GLuint list)
+static void sol_load_mesh(struct d_mesh *mp,
+ const struct b_body *bp,
+ const struct s_draw *draw, int mi)
{
- float p[3], e[4], u[3], a;
+ const size_t vs = sizeof (struct d_vert);
+ const size_t gs = sizeof (struct d_geom);
- sol_body_p(p, vary, bp->pi, bp->t);
- sol_body_e(e, vary, bp, 0);
+ struct d_vert *vv = 0;
+ struct d_geom *gv = 0;
+ int *iv = 0;
- q_as_axisangle(e, u, &a);
- a = V_DEG(a);
+ int oc = draw->base->oc;
+ int vn = 0;
+ int gn = 0;
- glPushMatrix();
+ const int gc = sol_count_body(bp, draw->base, mi);
+
+ /* Get temporary storage for vertex and element array creation. */
+
+ if ((vv = (struct d_vert *) calloc(oc, vs)) &&
+ (gv = (struct d_geom *) calloc(gc, gs)) &&
+ (iv = (int *) calloc(oc, sizeof (int))))
{
- /* Translate and rotate a moving body. */
+ int li, i;
- glTranslatef(p[0], p[1], p[2]);
- glRotatef(a, u[0], u[1], u[2]);
+ /* Initialize the index remapping. */
- /* Draw the body. */
+ for (i = 0; i < oc; ++i) iv[i] = -1;
- glCallList(list);
- }
- glPopMatrix();
-}
+ /* Include all matching lump geoms in the arrays. */
-void sol_draw(const struct s_draw *draw, int depthmask, int depthtest)
-{
- int bi;
+ for (li = 0; li < bp->lc; li++)
+ sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv,
+ draw->base->lv[bp->l0 + li].g0,
+ draw->base->lv[bp->l0 + li].gc, mi);
- /* Render all opaque geometry into the color and depth buffers. */
+ /* Include all matching body geoms in the arrays. */
- for (bi = 0; bi < draw->bc; bi++)
- if (draw->bv[bi].ol)
- sol_draw_list(draw->vary, draw->vary->bv + bi, draw->bv[bi].ol);
+ sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv, bp->g0, bp->gc, mi);
- /* Render all translucent geometry into only the color buffer. */
+ /* Initialize buffer objects for all data. */
- if (depthtest == 0) glDisable(GL_DEPTH_TEST);
- if (depthmask == 0) glDepthMask(GL_FALSE);
- {
- for (bi = 0; bi < draw->bc; bi++)
- if (draw->bv[bi].tl)
- sol_draw_list(draw->vary, draw->vary->bv + bi, draw->bv[bi].tl);
+ glGenBuffers_(1, &mp->vbo);
+ glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
+ glBufferData_(GL_ARRAY_BUFFER, vn * vs, vv, GL_STATIC_DRAW);
+ glBindBuffer_(GL_ARRAY_BUFFER, 0);
+
+ glGenBuffers_(1, &mp->ebo);
+ glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
+ glBufferData_(GL_ELEMENT_ARRAY_BUFFER, gn * gs, gv, GL_STATIC_DRAW);
+ glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
+
+ mp->mp = draw->mv + mi;
+ mp->ebc = gn * 3;
}
- if (depthmask == 0) glDepthMask(GL_TRUE);
- if (depthtest == 0) glEnable(GL_DEPTH_TEST);
+
+ free(iv);
+ free(gv);
+ free(vv);
}
-void sol_bill(const struct s_draw *draw, const float *M, float t)
+static void sol_free_mesh(struct d_mesh *mp)
{
- const struct d_mtrl *mp = &default_draw_mtrl;
+ if (glIsBuffer_(mp->ebo))
+ glDeleteBuffers_(1, &mp->ebo);
+ if (glIsBuffer_(mp->vbo))
+ glDeleteBuffers_(1, &mp->vbo);
+}
- int ri;
+void sol_draw_mesh(const struct d_mesh *mp, struct s_rend *rend, int p)
+{
+ /* If this mesh has material matching the given flags... */
- for (ri = 0; ri < draw->base->rc; ++ri)
+ if (sol_test_mtrl(mp->mp, p))
{
- const struct b_bill *rp = draw->base->rv + ri;
+ const size_t s = sizeof (struct d_vert);
+ const GLenum T = GL_FLOAT;
- float T = rp->t * t;
- float S = fsinf(T);
+ /* Apply the material state. */
- float w = rp->w [0] + rp->w [1] * T + rp->w [2] * S;
- float h = rp->h [0] + rp->h [1] * T + rp->h [2] * S;
- float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * S;
- float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * S;
- float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * S;
+ sol_apply_mtrl(mp->mp, rend);
- mp = sol_draw_mtrl(draw, draw->mv + rp->mi, mp);
+ /* Bind the mesh data. */
- glPushMatrix();
- {
- glTranslatef(rp->p[0], rp->p[1], rp->p[2]);
+ glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
+ glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
+
+ glVertexPointer (3, T, s, (GLvoid *) offsetof (struct d_vert, p));
+ glNormalPointer ( T, s, (GLvoid *) offsetof (struct d_vert, n));
- if (M && ((rp->fl & B_NOFACE) == 0)) glMultMatrixf(M);
+ if (tex_env_stage(TEX_STAGE_SHADOW))
+ {
+ glTexCoordPointer(3, T, s, (GLvoid *) offsetof (struct d_vert, p));
- if (fabsf(rx) > 0.0f) glRotatef(rx, 1.0f, 0.0f, 0.0f);
- if (fabsf(ry) > 0.0f) glRotatef(ry, 0.0f, 1.0f, 0.0f);
- if (fabsf(rz) > 0.0f) glRotatef(rz, 0.0f, 0.0f, 1.0f);
+ if (tex_env_stage(TEX_STAGE_CLIP))
+ glTexCoordPointer(3, T, s, (GLvoid *) offsetof (struct d_vert, p));
- glBegin(GL_QUADS);
- {
- glTexCoord2f(0.0f, 0.0f); glVertex2f(-w / 2, -h / 2);
- glTexCoord2f(1.0f, 0.0f); glVertex2f(+w / 2, -h / 2);
- glTexCoord2f(1.0f, 1.0f); glVertex2f(+w / 2, +h / 2);
- glTexCoord2f(0.0f, 1.0f); glVertex2f(-w / 2, +h / 2);
- }
- glEnd();
+ tex_env_stage(TEX_STAGE_TEXTURE);
}
- glPopMatrix();
- }
+ glTexCoordPointer(2, T, s, (GLvoid *) offsetof (struct d_vert, t));
+
+ /* Draw the mesh. */
- mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
+ glDrawElements(GL_TRIANGLES, mp->ebc, GL_UNSIGNED_SHORT, 0);
+ }
}
-void sol_refl(const struct s_draw *draw)
+/*---------------------------------------------------------------------------*/
+
+static void sol_load_body(struct d_body *bp,
+ const struct b_body *bq,
+ const struct s_draw *draw)
{
- int bi;
+ int mi;
- /* Render all reflective geometry into the color and depth buffers. */
+ bp->base = bq;
+ bp->mc = 0;
- for (bi = 0; bi < draw->bc; bi++)
- if (draw->bv[bi].rl)
- sol_draw_list(draw->vary, draw->vary->bv + bi, draw->bv[bi].rl);
-}
+ /* Determine how many materials this body uses. */
-/*---------------------------------------------------------------------------*/
+ for (mi = 0; mi < draw->mc; ++mi)
+ if (sol_count_body(bq, draw->base, mi))
+ bp->mc++;
-static void sol_shad_geom(const struct s_base *base,
- const struct b_geom *gp, int mi)
-{
- if (gp->mi == mi)
+ /* Allocate and initialize a mesh for each material. */
+
+ if ((bp->mv = (struct d_mesh *) calloc(bp->mc, sizeof (struct d_mesh))))
{
- const float *vi = base->vv[gp->vi].p;
- const float *vj = base->vv[gp->vj].p;
- const float *vk = base->vv[gp->vk].p;
+ int mj = 0;
- glVertex3fv(vi);
- glVertex3fv(vj);
- glVertex3fv(vk);
+ for (mi = 0; mi < draw->mc; ++mi)
+ if (sol_count_body(bq, draw->base, mi))
+ sol_load_mesh(bp->mv + mj++, bq, draw, mi);
}
-}
-static void sol_shad_lump(const struct s_base *base,
- const struct b_lump *lp, int mi)
-{
- int i;
+ /* Cache a mesh count for each pass. */
- for (i = 0; i < lp->gc; i++)
- sol_shad_geom(base, base->gv + base->iv[lp->g0 + i], mi);
+ bp->pass[0] = sol_count_mesh(bp, 0);
+ bp->pass[1] = sol_count_mesh(bp, 1);
+ bp->pass[2] = sol_count_mesh(bp, 2);
+ bp->pass[3] = sol_count_mesh(bp, 3);
+ bp->pass[4] = sol_count_mesh(bp, 4);
}
-static void sol_shad_body(const struct s_base *base,
- const struct b_body *bp,
- int fl, int decal)
+static void sol_free_body(struct d_body *bp)
{
- int mi, li, gi;
+ int mi;
- if (decal)
- {
- glEnable(GL_POLYGON_OFFSET_FILL);
- glPolygonOffset(-1.0f, -2.0f);
- }
+ for (mi = 0; mi < bp->mc; ++mi)
+ sol_free_mesh(bp->mv + mi);
- glBegin(GL_TRIANGLES);
- {
- for (mi = 0; mi < base->mc; mi++)
- {
- struct b_mtrl *mp = base->mv + mi;
+ free(bp->mv);
+}
- if ((mp->fl & fl) && (mp->fl & M_DECAL) == decal)
- {
- for (li = 0; li < bp->lc; li++)
- sol_shad_lump(base, base->lv + bp->l0 + li, mi);
- for (gi = 0; gi < bp->gc; gi++)
- sol_shad_geom(base, base->gv + base->iv[bp->g0 + gi], mi);
- }
- }
- }
- glEnd();
+static void sol_draw_body(const struct d_body *bp, struct s_rend *rend, int p)
+{
+ int i;
- if (decal)
- glDisable(GL_POLYGON_OFFSET_FILL);
+ for (i = 0; i < bp->mc; ++i)
+ sol_draw_mesh(bp->mv + i, rend, p);
}
-static void sol_shad_list(const struct s_vary *vary,
- const struct v_ball *up,
- const struct v_body *bp, GLuint list)
-{
- float p[3], e[4], u[3], a;
- float d[3];
+/*---------------------------------------------------------------------------*/
- float X[] = { 1.0f, 0.0f, 0.0f, 0.0f };
- float Z[] = { 0.0f, 0.0f, 1.0f, 0.0f };
+int sol_load_draw(struct s_draw *draw, const struct s_vary *vary, int s)
+{
+ int i;
- sol_body_p(p, vary, bp->pi, bp->t);
- sol_body_e(e, vary, bp, 0);
+ memset(draw, 0, sizeof (struct s_draw));
- v_sub(d, up->p, p);
+ draw->vary = vary;
+ draw->base = vary->base;
- if (e[0] != 1.0f)
- {
- q_as_axisangle(e, u, &a);
- a = V_DEG(a);
+ /* Initialize all materials for this file. */
- q_conj(e, e);
- q_rot(X, e, X);
- q_rot(Z, e, Z);
- }
- else
+ if (draw->base->mc)
{
- u[0] = 0.0f;
- u[1] = 0.0f;
- u[2] = 0.0f;
+ if ((draw->mv = calloc(draw->base->mc, sizeof (*draw->mv))))
+ {
+ draw->mc = draw->base->mc;
- a = 0.0f;
- }
+ for (i = 0; i < draw->mc; i++)
+ {
+ sol_load_mtrl(draw->mv + i, draw->base->mv + i);
- glTexGenfv(GL_S, GL_OBJECT_PLANE, X);
- glTexGenfv(GL_T, GL_OBJECT_PLANE, Z);
+ /* If at least one material is reflective, mark it. */
- /* Translate the shadow on a moving body. */
+ if (draw->base->mv[i].fl & M_REFLECTIVE)
+ draw->reflective = 1;
+ }
+ }
+ }
- glMatrixMode(GL_TEXTURE);
- {
- float k = 0.25f / up->r;
+ /* Initialize shadow state. */
- glPushMatrix();
- glTranslatef(0.5f - k * d[0],
- 0.5f - k * d[2], 0.0f);
- glScalef(k, k, 0.0f);
- }
- glMatrixMode(GL_MODELVIEW);
+ draw->shadow_ui = -1;
- /* Draw the body. */
+ /* Initialize all bodies for this file. */
- glPushMatrix();
+ if (draw->base->bc)
{
- glTranslatef(p[0], p[1], p[2]);
- glRotatef(a, u[0], u[1], u[2]);
+ if ((draw->bv = calloc(draw->base->bc, sizeof (*draw->bv))))
+ {
+ draw->bc = draw->base->bc;
- glCallList(list);
+ for (i = 0; i < draw->bc; i++)
+ sol_load_body(draw->bv + i, draw->base->bv + i, draw);
+ }
}
- glPopMatrix();
- /* Pop the shadow translation. */
+ sol_load_bill(draw);
- glMatrixMode(GL_TEXTURE);
- {
- glPopMatrix();
- }
- glMatrixMode(GL_MODELVIEW);
+ return 1;
}
-void sol_shad(const struct s_draw *draw, int ui)
+void sol_free_draw(struct s_draw *draw)
{
- int bi;
+ int i;
- /* Render all shadowed geometry. */
+ sol_free_bill(draw);
- glDepthMask(GL_FALSE);
- {
- for (bi = 0; bi < draw->bc; bi++)
- if (draw->bv[bi].sl)
- sol_shad_list(draw->vary,
- draw->vary->uv + ui,
- draw->vary->bv + bi, draw->bv[bi].sl);
- }
- glDepthMask(GL_TRUE);
+ for (i = 0; i < draw->bc; i++)
+ sol_free_body(draw->bv + i);
+ for (i = 0; i < draw->mc; i++)
+ sol_free_mtrl(draw->mv + i);
}
/*---------------------------------------------------------------------------*/
-static void sol_load_objects(struct s_draw *draw, int s)
+static void sol_draw_all(const struct s_draw *draw, struct s_rend *rend, int p)
{
- int i;
-
- /* Here we sort geometry into display lists by material type. */
-
- for (i = 0; i < draw->bc; i++)
- {
- struct d_body *bp = draw->bv + i;
+ int bi;
- int on = sol_enum_body(draw->base, bp->base, M_OPAQUE);
- int tn = sol_enum_body(draw->base, bp->base, M_TRANSPARENT);
- int rn = sol_enum_body(draw->base, bp->base, M_REFLECTIVE);
- int dn = sol_enum_body(draw->base, bp->base, M_DECAL);
- int sn = sol_enum_body(draw->base, bp->base, M_SHADOWED);
+ /* Draw all meshes of all bodies matching the given material flags. */
- /* Draw all opaque geometry, decals last. */
+ for (bi = 0; bi < draw->bc; ++bi)
- if (on)
+ if (draw->bv[bi].pass[p])
{
- bp->ol = glGenLists(1);
-
- glNewList(bp->ol, GL_COMPILE);
+ glPushMatrix();
{
- const struct d_mtrl *mp = &default_draw_mtrl;
-
- mp = sol_draw_body(draw, bp->base, mp, M_OPAQUE, 0);
- mp = sol_draw_body(draw, bp->base, mp, M_OPAQUE, M_DECAL);
- mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
+ sol_transform(draw->vary, draw->vary->bv + bi, draw->shadow_ui);
+ sol_draw_body(draw->bv + bi, rend, p);
}
- glEndList();
+ glPopMatrix();
}
- else bp->ol = 0;
-
- /* Draw all translucent geometry, decals first. */
-
- if (tn)
- {
- bp->tl = glGenLists(1);
+}
- glNewList(bp->tl, GL_COMPILE);
- {
- const struct d_mtrl *mp = &default_draw_mtrl;
+void sol_draw_enable(struct s_rend *rend)
+{
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
- mp = sol_draw_body(draw, bp->base, mp, M_TRANSPARENT, M_DECAL);
- mp = sol_draw_body(draw, bp->base, mp, M_TRANSPARENT, 0);
- mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
- }
- glEndList();
- }
- else bp->tl = 0;
+ if (gli.max_texture_units > 2)
+ tex_env_active(&tex_env_shadow_clip);
+ else if (gli.max_texture_units > 1)
+ tex_env_active(&tex_env_shadow);
+ else
+ tex_env_active(&tex_env_default);
- /* Draw all reflective geometry. */
+ if (tex_env_stage(TEX_STAGE_SHADOW))
+ {
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- if (rn)
- {
- bp->rl = glGenLists(1);
+ if (tex_env_stage(TEX_STAGE_CLIP))
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glNewList(bp->rl, GL_COMPILE);
- {
- const struct d_mtrl *mp = &default_draw_mtrl;
+ tex_env_stage(TEX_STAGE_TEXTURE);
+ }
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- mp = sol_draw_body(draw, bp->base, mp, M_REFLECTIVE, 0);
- mp = sol_draw_mtrl(draw, &default_draw_mtrl, mp);
- }
- glEndList();
+ rend->mp = &default_draw_mtrl;
+}
- draw->reflective = 1;
- }
- else bp->rl = 0;
+void sol_draw_disable(struct s_rend *rend)
+{
+ sol_apply_mtrl(&default_draw_mtrl, rend);
- /* Draw all shadowed geometry. */
+ if (tex_env_stage(TEX_STAGE_SHADOW))
+ {
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- if (s && (on || rn || sn))
- {
- bp->sl = glGenLists(1);
+ if (tex_env_stage(TEX_STAGE_CLIP))
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glNewList(bp->sl, GL_COMPILE);
- {
- if (on) sol_shad_body(draw->base, bp->base, M_OPAQUE, 0);
- if (rn) sol_shad_body(draw->base, bp->base, M_REFLECTIVE, 0);
- if (dn) sol_shad_body(draw->base, bp->base, M_OPAQUE, M_DECAL);
- if (sn)
- {
- /* Transparent shadowed geometry hack. */
+ tex_env_stage(TEX_STAGE_TEXTURE);
+ }
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- if (dn)
- sol_shad_body(draw->base, bp->base, M_SHADOWED, M_DECAL);
+ tex_env_active(&tex_env_default);
- sol_shad_body(draw->base, bp->base, M_SHADOWED, 0);
- }
- }
- glEndList();
- }
- else bp->sl = 0;
- }
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_VERTEX_ARRAY);
}
-static GLuint sol_find_texture(const char *name)
+/*---------------------------------------------------------------------------*/
+
+void sol_draw(const struct s_draw *draw, struct s_rend *rend, int mask, int test)
{
- char png[MAXSTR];
- char jpg[MAXSTR];
+ /* Render all opaque geometry, decals last. */
- GLuint o;
+ sol_draw_all(draw, rend, 0);
+ sol_draw_all(draw, rend, 1);
- /* Prefer a lossless copy of the texture over a lossy compression. */
+ /* Render all transparent geometry, decals first. */
- strncpy(png, name, PATHMAX); strcat(png, ".png");
- strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
+ if (!test) glDisable(GL_DEPTH_TEST);
+ if (!mask) glDepthMask(GL_FALSE);
+ {
+ sol_draw_all(draw, rend, 2);
+ sol_draw_all(draw, rend, 3);
+ }
+ if (!mask) glDepthMask(GL_TRUE);
+ if (!test) glEnable(GL_DEPTH_TEST);
- /* Check for a PNG. */
+ /* Revert the buffer object state. */
- if ((o = make_image_from_file(png)))
- return o;
+ glBindBuffer_(GL_ARRAY_BUFFER, 0);
+ glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
- /* Check for a JPG. */
+void sol_refl(const struct s_draw *draw, struct s_rend *rend)
+{
+ /* Render all reflective geometry. */
- if ((o = make_image_from_file(jpg)))
- return o;
+ sol_draw_all(draw, rend, 4);
- return 0;
+ /* Revert the buffer object state. */
+
+ glBindBuffer_(GL_ARRAY_BUFFER, 0);
+ glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
}
-static void sol_load_textures(struct s_draw *draw)
+void sol_back(const struct s_draw *draw,
+ struct s_rend *rend,
+ float n, float f, float t)
{
- int i;
+ if (!draw || !draw->base)
+ return;
- /* Load the image referenced by each material. */
+ glDisable(GL_LIGHTING);
+ glDepthMask(GL_FALSE);
- for (i = 0; i < draw->mc; i++)
+ sol_bill_enable(draw);
{
- struct d_mtrl *mp = draw->mv + i;
+ int ri;
+
+ /* Consider each billboard. */
- if ((mp->o = sol_find_texture(_(mp->base->f))))
+ for (ri = 0; ri < draw->base->rc; ri++)
{
- /* Set the texture to clamp or repeat based on material type. */
+ const struct b_bill *rp = draw->base->rv + ri;
- if (mp->base->fl & M_CLAMPED)
- {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
- }
- else
+ /* Render only billboards at distances between n and f. */
+
+ if (n <= rp->d && rp->d < f)
{
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- }
- }
- }
-}
+ float T = (rp->t > 0.0f) ? (fmodf(t, rp->t) - rp->t / 2) : 0;
-/*---------------------------------------------------------------------------*/
+ float w = rp->w[0] + rp->w[1] * T + rp->w[2] * T * T;
+ float h = rp->h[0] + rp->h[1] * T + rp->h[2] * T * T;
-int sol_load_draw(struct s_draw *draw, const struct s_vary *vary, int s)
-{
- int i;
+ /* Render only billboards facing the viewer. */
- memset(draw, 0, sizeof (*draw));
+ if (w > 0 && h > 0)
+ {
+ float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * T * T;
+ float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * T * T;
+ float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * T * T;
- draw->vary = vary;
- draw->base = draw->vary->base;
+ glPushMatrix();
+ {
+ if (ry) glRotatef(ry, 0.0f, 1.0f, 0.0f);
+ if (rx) glRotatef(rx, 1.0f, 0.0f, 0.0f);
- if (draw->base->mc)
- {
- draw->mv = calloc(draw->base->mc, sizeof (*draw->mv));
- draw->mc = draw->base->mc;
+ glTranslatef(0.0f, 0.0f, -rp->d);
- for (i = 0; i < draw->base->mc; i++)
- {
- struct d_mtrl *mp = draw->mv + i;
- struct b_mtrl *mq = draw->base->mv + i;
+ if (rp->fl & B_FLAT)
+ {
+ glRotatef(-rx - 90.0f, 1.0f, 0.0f, 0.0f);
+ glRotatef(-ry, 0.0f, 0.0f, 1.0f);
+ }
+ if (rp->fl & B_EDGE)
+ glRotatef(-rx, 1.0f, 0.0f, 0.0f);
+
+ if (rz) glRotatef(rz, 0.0f, 0.0f, 1.0f);
- mp->base = mq;
+ glScalef(w, h, 1.0f);
+
+ sol_apply_mtrl(draw->mv + rp->mi, rend);
+
+ if (rp->fl & B_EDGE)
+ glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
+ else
+ glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
+ }
+ glPopMatrix();
+ }
+ }
}
}
+ sol_bill_disable();
- if (draw->base->bc)
+ glDepthMask(GL_TRUE);
+ glEnable(GL_LIGHTING);
+}
+
+void sol_bill(const struct s_draw *draw,
+ struct s_rend *rend, const float *M, float t)
+{
+ sol_bill_enable(draw);
{
- draw->bv = calloc(draw->base->bc, sizeof (*draw->bv));
- draw->bc = draw->base->bc;
+ int ri;
- for (i = 0; i < draw->base->bc; i++)
+ for (ri = 0; ri < draw->base->rc; ++ri)
{
- struct d_body *bp = draw->bv + i;
- struct b_body *bq = draw->base->bv + i;
+ const struct b_bill *rp = draw->base->rv + ri;
- bp->base = bq;
- }
- }
+ float T = rp->t * t;
+ float S = fsinf(T);
- sol_load_textures(draw);
- sol_load_objects (draw, s);
+ float w = rp->w [0] + rp->w [1] * T + rp->w [2] * S;
+ float h = rp->h [0] + rp->h [1] * T + rp->h [2] * S;
+ float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * S;
+ float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * S;
+ float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * S;
- return 1;
-}
+ sol_apply_mtrl(draw->mv + rp->mi, rend);
-void sol_free_draw(struct s_draw *draw)
-{
- int i;
+ glPushMatrix();
+ {
+ glTranslatef(rp->p[0], rp->p[1], rp->p[2]);
- for (i = 0; i < draw->mc; i++)
- {
- if (glIsTexture(draw->mv[i].o))
- glDeleteTextures(1, &draw->mv[i].o);
+ if (M && ((rp->fl & B_NOFACE) == 0)) glMultMatrixf(M);
+
+ if (fabsf(rx) > 0.0f) glRotatef(rx, 1.0f, 0.0f, 0.0f);
+ if (fabsf(ry) > 0.0f) glRotatef(ry, 0.0f, 1.0f, 0.0f);
+ if (fabsf(rz) > 0.0f) glRotatef(rz, 0.0f, 0.0f, 1.0f);
+
+ sol_draw_bill(w, h, GL_FALSE);
+ }
+ glPopMatrix();
+ }
}
+ sol_bill_disable();
+}
- for (i = 0; i < draw->bc; i++)
+void sol_fade(const struct s_draw *draw, float k)
+{
+ if (k > 0.0f)
{
- if (glIsList(draw->bv[i].ol))
- glDeleteLists(draw->bv[i].ol, 1);
- if (glIsList(draw->bv[i].tl))
- glDeleteLists(draw->bv[i].tl, 1);
- if (glIsList(draw->bv[i].rl))
- glDeleteLists(draw->bv[i].rl, 1);
- if (glIsList(draw->bv[i].sl))
- glDeleteLists(draw->bv[i].sl, 1);
- }
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ {
+ glEnable(GL_COLOR_MATERIAL);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_TEXTURE_2D);
+
+ glColor4f(0.0f, 0.0f, 0.0f, k);
- free(draw->mv);
- free(draw->bv);
+ sol_bill_enable(draw);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ sol_bill_disable();
- memset(draw, 0, sizeof (*draw));
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ }
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
}
/*---------------------------------------------------------------------------*/