2 * Copyright (C) 2003 Robert Kooima
4 * NEVERBALL is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
16 #include <SDL_rwops.h>
27 #include "base_image.h"
28 #include "base_config.h"
31 #include "solid_draw.h"
32 #include "solid_all.h"
34 /*---------------------------------------------------------------------------*/
36 /* EXCLUDED material flags for each rendering pass. */
38 static const int pass_ex[] = {
39 M_REFLECTIVE | M_TRANSPARENT | M_DECAL,
40 M_REFLECTIVE | M_TRANSPARENT,
42 M_REFLECTIVE | M_DECAL,
46 /* INCLUDED material flags for each rendering pass. */
48 static const int pass_in[] = {
51 M_DECAL | M_TRANSPARENT,
56 /*---------------------------------------------------------------------------*/
58 static void sol_transform(const struct s_vary *vary,
59 const struct v_body *bp)
67 /* Compute the body transform. */
69 sol_body_p(p, vary, bp->pi, bp->t);
70 sol_body_e(e, vary, bp, 0);
72 q_as_axisangle(e, v, &a);
74 glTranslatef(p[0], p[1], p[2]);
75 glRotatef(V_DEG(a), v[0], v[1], v[2]);
77 /* Compute the shadow texture transform */
79 if (vary->uc && vary->uv->r > 0.0)
81 glActiveTexture_(GL_TEXTURE1);
82 glMatrixMode(GL_TEXTURE);
84 float k = 0.25f / vary->uv->r;
86 v_sub(d, vary->uv->p, p);
89 glTranslatef(0.5f - k * d[0],
90 0.5f - k * d[2], 0.0f);
93 glMatrixMode(GL_MODELVIEW);
94 glActiveTexture_(GL_TEXTURE0);
98 /*---------------------------------------------------------------------------*/
100 static void sol_load_bill(struct s_draw *draw)
102 static const GLfloat data[] = {
103 0.0f, 0.0f, -1.0f, -1.0f,
104 1.0f, 0.0f, 1.0f, -1.0f,
105 0.0f, 1.0f, -1.0f, 1.0f,
106 1.0f, 1.0f, 1.0f, 1.0f,
108 0.0f, 0.0f, -0.5f, 0.0f,
109 1.0f, 0.0f, 0.5f, 0.0f,
110 0.0f, 1.0f, -0.5f, 1.0f,
111 1.0f, 1.0f, 0.5f, 1.0f,
113 0.0f, 0.0f, -0.5f, -0.5f,
114 1.0f, 0.0f, 0.5f, -0.5f,
115 0.0f, 1.0f, -0.5f, 0.5f,
116 1.0f, 1.0f, 0.5f, 0.5f,
119 /* Initialize a vertex buffer object for billboard drawing. */
121 glGenBuffers_(1, &draw->bill);
122 glBindBuffer_(GL_ARRAY_BUFFER, draw->bill);
123 glBufferData_(GL_ARRAY_BUFFER, sizeof (data), data, GL_STATIC_DRAW);
124 glBindBuffer_(GL_ARRAY_BUFFER, 0);
127 static void sol_free_bill(struct s_draw *draw)
129 if (glIsBuffer_(draw->bill))
130 glDeleteBuffers_(1, &draw->bill);
133 static void sol_draw_bill(GLfloat w, GLfloat h, GLboolean edge)
137 glScalef(0.5f * w, 0.5f * h, 1.0f);
140 glTranslatef(0.0f, 0.5f, 0.0f);
142 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
147 /*---------------------------------------------------------------------------*/
149 /* NOTE: The state management here presumes that billboard rendering is */
150 /* NESTED within a wider SOL rendering process. That is: sol_draw_enable */
151 /* has been called and sol_draw_disable will be called in the future. */
152 /* Thus the "default" VBO state retained by billboard rendering is the */
153 /* state appropriate for normal SOL rendering. */
155 static void sol_bill_enable(const struct s_draw *draw)
157 const size_t s = sizeof (GLfloat);
159 glDisableClientState(GL_NORMAL_ARRAY);
160 glClientActiveTexture(GL_TEXTURE1);
161 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
162 glClientActiveTexture(GL_TEXTURE0);
164 glBindBuffer_(GL_ARRAY_BUFFER, draw->bill);
166 glTexCoordPointer(2, GL_FLOAT, s * 4, (GLvoid *) ( 0));
167 glVertexPointer (2, GL_FLOAT, s * 4, (GLvoid *) (s * 2));
170 static void sol_bill_disable(void)
173 glEnableClientState(GL_NORMAL_ARRAY);
174 glClientActiveTexture(GL_TEXTURE1);
175 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
176 glClientActiveTexture(GL_TEXTURE0);
180 /*---------------------------------------------------------------------------*/
182 #define tobyte(f) ((GLubyte) (f * 255.0f))
184 #define color_cmp(a, b) (tobyte((a)[0]) == tobyte((b)[0]) && \
185 tobyte((a)[1]) == tobyte((b)[1]) && \
186 tobyte((a)[2]) == tobyte((b)[2]) && \
187 tobyte((a)[3]) == tobyte((b)[3]))
189 static struct b_mtrl default_base_mtrl =
191 { 0.8f, 0.8f, 0.8f, 1.0f },
192 { 0.2f, 0.2f, 0.2f, 1.0f },
193 { 0.0f, 0.0f, 0.0f, 1.0f },
194 { 0.0f, 0.0f, 0.0f, 1.0f },
195 { 0.0f }, 0.0f, 0, ""
198 static struct d_mtrl default_draw_mtrl =
200 &default_base_mtrl, 0
203 const struct d_mtrl *sol_apply_mtrl(const struct d_mtrl *mp_draw,
204 const struct d_mtrl *mq_draw)
206 const struct b_mtrl *mp_base = mp_draw->base;
207 const struct b_mtrl *mq_base = mq_draw->base;
209 /* Bind the texture. */
211 if (mp_draw->o != mq_draw->o)
212 glBindTexture(GL_TEXTURE_2D, mp_draw->o);
214 /* Set material properties. */
216 if (!color_cmp(mp_base->a, mq_base->a))
217 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mp_base->a);
218 if (!color_cmp(mp_base->d, mq_base->d))
219 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp_base->d);
220 if (!color_cmp(mp_base->s, mq_base->s))
221 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mp_base->s);
222 if (!color_cmp(mp_base->e, mq_base->e))
223 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mp_base->e);
224 if (tobyte(mp_base->h[0]) != tobyte(mq_base->h[0]))
225 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mp_base->h);
229 if ((mp_base->fl & M_SHADOWED) && !(mq_base->fl & M_SHADOWED))
234 if (!(mp_base->fl & M_SHADOWED) && (mq_base->fl & M_SHADOWED))
239 /* Environment mapping. */
241 if ((mp_base->fl & M_ENVIRONMENT) && !(mq_base->fl & M_ENVIRONMENT))
243 glEnable(GL_TEXTURE_GEN_S);
244 glEnable(GL_TEXTURE_GEN_T);
246 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
247 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
250 if ((mq_base->fl & M_ENVIRONMENT) && !(mp_base->fl & M_ENVIRONMENT))
252 glDisable(GL_TEXTURE_GEN_S);
253 glDisable(GL_TEXTURE_GEN_T);
256 /* Additive blending. */
258 if ((mp_base->fl & M_ADDITIVE) && !(mq_base->fl & M_ADDITIVE))
259 glBlendFunc(GL_ONE, GL_ONE);
261 if ((mq_base->fl & M_ADDITIVE) && !(mp_base->fl & M_ADDITIVE))
262 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
264 /* Visibility-from-behind. */
266 if ((mp_base->fl & M_TWO_SIDED) && !(mq_base->fl & M_TWO_SIDED))
268 glDisable(GL_CULL_FACE);
269 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
272 if ((mq_base->fl & M_TWO_SIDED) && !(mp_base->fl & M_TWO_SIDED))
274 glEnable(GL_CULL_FACE);
275 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 0);
280 if ((mp_base->fl & M_DECAL) && !(mq_base->fl & M_DECAL))
282 glEnable(GL_POLYGON_OFFSET_FILL);
283 glPolygonOffset(-1.0f, -2.0f);
286 if ((mq_base->fl & M_DECAL) && !(mp_base->fl & M_DECAL))
287 glDisable(GL_POLYGON_OFFSET_FILL);
292 static GLuint sol_find_texture(const char *name)
299 /* Prefer a lossless copy of the texture over a lossy compression. */
301 strncpy(png, name, PATHMAX); strcat(png, ".png");
302 strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
304 /* Check for a PNG. */
306 if ((o = make_image_from_file(png)))
309 /* Check for a JPG. */
311 if ((o = make_image_from_file(jpg)))
317 static void sol_load_mtrl(struct d_mtrl *mp,
318 const struct b_mtrl *mq,
323 if ((mp->o = sol_find_texture(_(mq->f))))
325 /* Set the texture to clamp or repeat based on material type. */
327 if (mq->fl & M_CLAMP_S)
328 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
330 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
332 if (mq->fl & M_CLAMP_T)
333 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
335 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
337 /* If at least one material is reflective, mark it in the SOL. */
339 if (mq->fl & M_REFLECTIVE)
340 draw->reflective = 1;
344 static void sol_free_mtrl(struct d_mtrl *mp)
346 if (glIsTexture(mp->o))
347 glDeleteTextures(1, &mp->o);
350 static int sol_test_mtrl(const struct d_mtrl *mp, int p)
352 /* Test whether the material flags exclude f0 and include f1. */
354 return ((mp->base->fl & pass_in[p]) == pass_in[p] &&
355 (mp->base->fl & pass_ex[p]) == 0);
358 /*---------------------------------------------------------------------------*/
360 static int sol_count_geom(const struct s_base *base, int g0, int gc, int mi)
364 /* The arguments g0 and gc specify a range of the index array. These */
365 /* indices refer to geoms. Determine how many of these geoms use the */
368 for (gi = 0; gi < gc; gi++)
369 if (base->gv[base->iv[g0 + gi]].mi == mi)
375 static int sol_count_body(const struct b_body *bp,
376 const struct s_base *base, int mi)
380 /* Count all lump geoms with the given material. */
382 for (li = 0; li < bp->lc; li++)
383 c += sol_count_geom(base, base->lv[bp->l0 + li].g0,
384 base->lv[bp->l0 + li].gc, mi);
386 /* Count all body geoms with the given material. */
388 c += sol_count_geom(base, bp->g0, bp->gc, mi);
393 static int sol_count_mesh(const struct d_body *bp, int p)
397 /* Count the body meshes matching the given material flags. */
399 for (mi = 0; mi < bp->mc; ++mi)
400 if (sol_test_mtrl(bp->mv[mi].mp, p))
406 /*---------------------------------------------------------------------------*/
408 static void sol_mesh_vert(struct d_vert *vp,
409 const struct s_base *base, int oi)
411 /* Gather all vertex attributes for the given offs. */
413 const struct b_texc *tq = base->tv + base->ov[oi].ti;
414 const struct b_side *sq = base->sv + base->ov[oi].si;
415 const struct b_vert *vq = base->vv + base->ov[oi].vi;
432 static void sol_mesh_geom(struct d_vert *vv, int *vn,
433 struct d_geom *gv, int *gn,
434 const struct s_base *base, int *iv, int g0, int gc, int mi)
438 /* Insert all geoms with material mi into the vertex and element data. */
440 for (gi = 0; gi < gc; gi++)
442 const struct b_geom *gq = base->gv + base->iv[g0 + gi];
446 /* Insert a d_vert into the VBO data for each referenced b_off. */
448 if (iv[gq->oi] == -1)
451 sol_mesh_vert(vv + (*vn)++, base, gq->oi);
453 if (iv[gq->oj] == -1)
456 sol_mesh_vert(vv + (*vn)++, base, gq->oj);
458 if (iv[gq->ok] == -1)
461 sol_mesh_vert(vv + (*vn)++, base, gq->ok);
464 /* Populate the EBO data using remapped b_off indices. */
466 gv[*gn].i = iv[gq->oi];
467 gv[*gn].j = iv[gq->oj];
468 gv[*gn].k = iv[gq->ok];
475 static void sol_load_mesh(struct d_mesh *mp,
476 const struct b_body *bp,
477 const struct s_draw *draw, int mi)
479 const size_t vs = sizeof (struct d_vert);
480 const size_t gs = sizeof (struct d_geom);
482 struct d_vert *vv = 0;
483 struct d_geom *gv = 0;
486 int oc = draw->base->oc;
490 const int gc = sol_count_body(bp, draw->base, mi);
492 /* Get temporary storage for vertex and element array creation. */
494 if ((vv = (struct d_vert *) calloc(oc, vs)) &&
495 (gv = (struct d_geom *) calloc(gc, gs)) &&
496 (iv = (int *) calloc(oc, sizeof (int))))
500 /* Initialize the index remapping. */
502 for (i = 0; i < oc; ++i) iv[i] = -1;
504 /* Include all matching lump geoms in the arrays. */
506 for (li = 0; li < bp->lc; li++)
507 sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv,
508 draw->base->lv[bp->l0 + li].g0,
509 draw->base->lv[bp->l0 + li].gc, mi);
511 /* Include all matching body geoms in the arrays. */
513 sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv, bp->g0, bp->gc, mi);
515 /* Initialize buffer objects for all data. */
517 glGenBuffers_(1, &mp->vbo);
518 glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
519 glBufferData_(GL_ARRAY_BUFFER, vn * vs, vv, GL_STATIC_DRAW);
520 glBindBuffer_(GL_ARRAY_BUFFER, 0);
522 glGenBuffers_(1, &mp->ebo);
523 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
524 glBufferData_(GL_ELEMENT_ARRAY_BUFFER, gn * gs, gv, GL_STATIC_DRAW);
525 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
527 mp->mp = draw->mv + mi;
536 static void sol_free_mesh(struct d_mesh *mp)
538 if (glIsBuffer_(mp->ebo))
539 glDeleteBuffers_(1, &mp->ebo);
540 if (glIsBuffer_(mp->vbo))
541 glDeleteBuffers_(1, &mp->vbo);
544 static const struct d_mtrl *sol_draw_mesh(const struct d_mesh *mp,
545 const struct d_mtrl *mq, int p)
547 /* If this mesh has material matching the given flags... */
549 if (sol_test_mtrl(mp->mp, p))
551 const size_t s = sizeof (struct d_vert);
552 const GLenum T = GL_FLOAT;
554 /* Apply the material state. */
556 mq = sol_apply_mtrl(mp->mp, mq);
558 /* Bind the mesh data. */
560 glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
561 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
563 glVertexPointer (3, T, s, (GLvoid *) offsetof (struct d_vert, p));
564 glNormalPointer ( T, s, (GLvoid *) offsetof (struct d_vert, n));
566 glClientActiveTexture(GL_TEXTURE1);
567 glTexCoordPointer(2, T, s, (GLvoid *) offsetof (struct d_vert, u));
568 glClientActiveTexture(GL_TEXTURE0);
569 glTexCoordPointer(2, T, s, (GLvoid *) offsetof (struct d_vert, t));
573 glDrawElements(GL_TRIANGLES, mp->ebc, GL_UNSIGNED_SHORT, 0);
579 /*---------------------------------------------------------------------------*/
581 static void sol_load_body(struct d_body *bp,
582 const struct b_body *bq,
583 const struct s_draw *draw)
590 /* Determine how many materials this body uses. */
592 for (mi = 0; mi < draw->mc; ++mi)
593 if (sol_count_body(bq, draw->base, mi))
596 /* Allocate and initialize a mesh for each material. */
598 if ((bp->mv = (struct d_mesh *) calloc(bp->mc, sizeof (struct d_mesh))))
602 for (mi = 0; mi < draw->mc; ++mi)
603 if (sol_count_body(bq, draw->base, mi))
604 sol_load_mesh(bp->mv + mj++, bq, draw, mi);
607 /* Cache a mesh count for each pass. */
609 bp->pass[0] = sol_count_mesh(bp, 0);
610 bp->pass[1] = sol_count_mesh(bp, 1);
611 bp->pass[2] = sol_count_mesh(bp, 2);
612 bp->pass[3] = sol_count_mesh(bp, 3);
613 bp->pass[4] = sol_count_mesh(bp, 4);
616 static void sol_free_body(struct d_body *bp)
620 for (mi = 0; mi < bp->mc; ++mi)
621 sol_free_mesh(bp->mv + mi);
626 static const struct d_mtrl *sol_draw_body(const struct d_body *bp,
627 const struct d_mtrl *mq, int p)
631 for (i = 0; i < bp->mc; ++i)
632 mq = sol_draw_mesh(bp->mv + i, mq, p);
637 /*---------------------------------------------------------------------------*/
639 int sol_load_draw(struct s_draw *draw, const struct s_vary *vary, int s)
643 memset(draw, 0, sizeof (struct s_draw));
646 draw->base = vary->base;
648 /* Initialize all materials for this file. */
652 if ((draw->mv = calloc(draw->base->mc, sizeof (*draw->mv))))
654 draw->mc = draw->base->mc;
656 for (i = 0; i < draw->mc; i++)
657 sol_load_mtrl(draw->mv + i, draw->base->mv + i, draw);
661 /* Initialize all bodies for this file. */
665 if ((draw->bv = calloc(draw->base->bc, sizeof (*draw->bv))))
667 draw->bc = draw->base->bc;
669 for (i = 0; i < draw->bc; i++)
670 sol_load_body(draw->bv + i, draw->base->bv + i, draw);
679 void sol_free_draw(struct s_draw *draw)
685 for (i = 0; i < draw->bc; i++)
686 sol_free_body(draw->bv + i);
687 for (i = 0; i < draw->mc; i++)
688 sol_free_mtrl(draw->mv + i);
691 /*---------------------------------------------------------------------------*/
693 static const struct d_mtrl *sol_draw_all(const struct s_draw *draw,
694 const struct d_mtrl *mq, int p)
698 /* Draw all meshes of all bodies matching the given material flags. */
700 for (bi = 0; bi < draw->bc; ++bi)
702 if (draw->bv[bi].pass[p])
706 sol_transform(draw->vary, draw->vary->bv + bi);
707 mq = sol_draw_body(draw->bv + bi, mq, p);
715 const struct d_mtrl *sol_draw_enable(void)
717 glEnableClientState(GL_VERTEX_ARRAY);
718 glEnableClientState(GL_NORMAL_ARRAY);
720 glClientActiveTexture(GL_TEXTURE1);
721 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
722 glClientActiveTexture(GL_TEXTURE0);
723 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
725 return &default_draw_mtrl;
728 void sol_draw_disable(const struct d_mtrl *mq)
730 sol_apply_mtrl(&default_draw_mtrl, mq);
732 glClientActiveTexture(GL_TEXTURE1);
733 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
734 glClientActiveTexture(GL_TEXTURE0);
735 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
737 glDisableClientState(GL_NORMAL_ARRAY);
738 glDisableClientState(GL_VERTEX_ARRAY);
741 /*---------------------------------------------------------------------------*/
743 const struct d_mtrl *sol_draw(const struct s_draw *draw,
744 const struct d_mtrl *mq, int mask, int test)
746 /* Render all opaque geometry, decals last. */
748 mq = sol_draw_all(draw, mq, 0);
749 mq = sol_draw_all(draw, mq, 1);
751 /* Render all transparent geometry, decals first. */
753 if (!test) glDisable(GL_DEPTH_TEST);
754 if (!mask) glDepthMask(GL_FALSE);
756 mq = sol_draw_all(draw, mq, 2);
757 mq = sol_draw_all(draw, mq, 3);
759 if (!mask) glDepthMask(GL_TRUE);
760 if (!test) glEnable(GL_DEPTH_TEST);
762 /* Revert the buffer object state. */
764 glBindBuffer_(GL_ARRAY_BUFFER, 0);
765 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
770 const struct d_mtrl *sol_refl(const struct s_draw *draw,
771 const struct d_mtrl *mq)
773 /* Render all reflective geometry. */
775 mq = sol_draw_all(draw, mq, 4);
777 /* Revert the buffer object state. */
779 glBindBuffer_(GL_ARRAY_BUFFER, 0);
780 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
785 const struct d_mtrl *sol_back(const struct s_draw *draw,
786 const struct d_mtrl *mq,
787 float n, float f, float t)
789 glDisable(GL_LIGHTING);
790 glDepthMask(GL_FALSE);
792 sol_bill_enable(draw);
796 /* Consider each billboard. */
798 for (ri = 0; ri < draw->base->rc; ri++)
800 const struct b_bill *rp = draw->base->rv + ri;
802 /* Render only billboards at distances between n and f. */
804 if (n <= rp->d && rp->d < f)
806 float T = (rp->t > 0.0f) ? (fmodf(t, rp->t) - rp->t / 2) : 0;
808 float w = rp->w[0] + rp->w[1] * T + rp->w[2] * T * T;
809 float h = rp->h[0] + rp->h[1] * T + rp->h[2] * T * T;
811 /* Render only billboards facing the viewer. */
815 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * T * T;
816 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * T * T;
817 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * T * T;
821 if (ry) glRotatef(ry, 0.0f, 1.0f, 0.0f);
822 if (rx) glRotatef(rx, 1.0f, 0.0f, 0.0f);
824 glTranslatef(0.0f, 0.0f, -rp->d);
828 glRotatef(-rx - 90.0f, 1.0f, 0.0f, 0.0f);
829 glRotatef(-ry, 0.0f, 0.0f, 1.0f);
832 glRotatef(-rx, 1.0f, 0.0f, 0.0f);
834 if (rz) glRotatef(rz, 0.0f, 0.0f, 1.0f);
836 glScalef(w, h, 1.0f);
838 mq = sol_apply_mtrl(draw->mv + rp->mi, mq);
841 glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
843 glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
852 glDepthMask(GL_TRUE);
853 glEnable(GL_LIGHTING);
858 const struct d_mtrl *sol_bill(const struct s_draw *draw,
859 const struct d_mtrl *mq, const float *M, float t)
861 sol_bill_enable(draw);
865 for (ri = 0; ri < draw->base->rc; ++ri)
867 const struct b_bill *rp = draw->base->rv + ri;
872 float w = rp->w [0] + rp->w [1] * T + rp->w [2] * S;
873 float h = rp->h [0] + rp->h [1] * T + rp->h [2] * S;
874 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * S;
875 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * S;
876 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * S;
878 mq = sol_apply_mtrl(draw->mv + rp->mi, mq);
882 glTranslatef(rp->p[0], rp->p[1], rp->p[2]);
884 if (M && ((rp->fl & B_NOFACE) == 0)) glMultMatrixf(M);
886 if (fabsf(rx) > 0.0f) glRotatef(rx, 1.0f, 0.0f, 0.0f);
887 if (fabsf(ry) > 0.0f) glRotatef(ry, 0.0f, 1.0f, 0.0f);
888 if (fabsf(rz) > 0.0f) glRotatef(rz, 0.0f, 0.0f, 1.0f);
890 sol_draw_bill(w, h, GL_FALSE);
900 void sol_fade(const struct s_draw *draw, float k)
904 glMatrixMode(GL_PROJECTION);
907 glMatrixMode(GL_MODELVIEW);
911 glEnable(GL_COLOR_MATERIAL);
912 glDisable(GL_LIGHTING);
913 glDisable(GL_DEPTH_TEST);
914 glDisable(GL_TEXTURE_2D);
916 glColor4f(0.0f, 0.0f, 0.0f, k);
918 sol_bill_enable(draw);
919 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
922 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
924 glEnable(GL_TEXTURE_2D);
925 glEnable(GL_DEPTH_TEST);
926 glEnable(GL_LIGHTING);
927 glDisable(GL_COLOR_MATERIAL);
929 glMatrixMode(GL_PROJECTION);
931 glMatrixMode(GL_MODELVIEW);
936 /*---------------------------------------------------------------------------*/
938 int sol_load_full(struct s_full *full, const char *filename, int s)
940 if (sol_load_base(&full->base, filename))
942 sol_load_vary(&full->vary, &full->base);
943 sol_load_draw(&full->draw, &full->vary, s);
951 void sol_free_full(struct s_full *full)
953 sol_free_draw(&full->draw);
954 sol_free_vary(&full->vary);
955 sol_free_base(&full->base);
958 /*---------------------------------------------------------------------------*/