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)
66 /* Apply the body position and rotation to the model-view matrix. */
68 sol_body_p(p, vary, bp->pi, bp->t);
69 sol_body_e(e, vary, bp, 0);
71 q_as_axisangle(e, v, &a);
73 glTranslatef(p[0], p[1], p[2]);
74 glRotatef(V_DEG(a), v[0], v[1], v[2]);
76 /* Apply the shadow transform to the texture matrix. */
78 if (vary->uc && vary->uv->r > 0.0)
80 glActiveTexture_(GL_TEXTURE1);
81 glMatrixMode(GL_TEXTURE);
83 float k = 0.25f / vary->uv->r;
87 /* Center the shadow texture on the ball. */
89 glTranslatef(0.5f, 0.5f, 0.0f);
91 /* Transform ball XZ position to ST texture coordinate. */
93 glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
95 /* Move the shadow texture under the ball. */
97 glTranslatef(-vary->uv->p[0],
101 /* Scale the shadow texture to the radius of the ball. */
105 /* Apply the body position and rotation. */
107 glTranslatef(p[0], p[1], p[2]);
108 glRotatef(V_DEG(a), v[0], v[1], v[2]);
110 glMatrixMode(GL_MODELVIEW);
111 glActiveTexture_(GL_TEXTURE0);
115 /*---------------------------------------------------------------------------*/
117 static void sol_load_bill(struct s_draw *draw)
119 static const GLfloat data[] = {
120 0.0f, 0.0f, -1.0f, -1.0f,
121 1.0f, 0.0f, 1.0f, -1.0f,
122 0.0f, 1.0f, -1.0f, 1.0f,
123 1.0f, 1.0f, 1.0f, 1.0f,
125 0.0f, 0.0f, -0.5f, 0.0f,
126 1.0f, 0.0f, 0.5f, 0.0f,
127 0.0f, 1.0f, -0.5f, 1.0f,
128 1.0f, 1.0f, 0.5f, 1.0f,
130 0.0f, 0.0f, -0.5f, -0.5f,
131 1.0f, 0.0f, 0.5f, -0.5f,
132 0.0f, 1.0f, -0.5f, 0.5f,
133 1.0f, 1.0f, 0.5f, 0.5f,
136 /* Initialize a vertex buffer object for billboard drawing. */
138 glGenBuffers_(1, &draw->bill);
139 glBindBuffer_(GL_ARRAY_BUFFER, draw->bill);
140 glBufferData_(GL_ARRAY_BUFFER, sizeof (data), data, GL_STATIC_DRAW);
141 glBindBuffer_(GL_ARRAY_BUFFER, 0);
144 static void sol_free_bill(struct s_draw *draw)
146 if (glIsBuffer_(draw->bill))
147 glDeleteBuffers_(1, &draw->bill);
150 static void sol_draw_bill(GLfloat w, GLfloat h, GLboolean edge)
154 glScalef(0.5f * w, 0.5f * h, 1.0f);
157 glTranslatef(0.0f, 0.5f, 0.0f);
159 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
164 /*---------------------------------------------------------------------------*/
166 /* NOTE: The state management here presumes that billboard rendering is */
167 /* NESTED within a wider SOL rendering process. That is: sol_draw_enable */
168 /* has been called and sol_draw_disable will be called in the future. */
169 /* Thus the "default" VBO state retained by billboard rendering is the */
170 /* state appropriate for normal SOL rendering. */
172 static void sol_bill_enable(const struct s_draw *draw)
174 const size_t s = sizeof (GLfloat);
176 glDisableClientState(GL_NORMAL_ARRAY);
177 glClientActiveTexture_(GL_TEXTURE1);
178 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
179 glClientActiveTexture_(GL_TEXTURE0);
181 glBindBuffer_(GL_ARRAY_BUFFER, draw->bill);
183 glTexCoordPointer(2, GL_FLOAT, s * 4, (GLvoid *) ( 0));
184 glVertexPointer (2, GL_FLOAT, s * 4, (GLvoid *) (s * 2));
187 static void sol_bill_disable(void)
190 glEnableClientState(GL_NORMAL_ARRAY);
191 glClientActiveTexture_(GL_TEXTURE1);
192 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
193 glClientActiveTexture_(GL_TEXTURE0);
197 /*---------------------------------------------------------------------------*/
199 #define tobyte(f) ((GLubyte) (f * 255.0f))
201 #define color_cmp(a, b) (tobyte((a)[0]) == tobyte((b)[0]) && \
202 tobyte((a)[1]) == tobyte((b)[1]) && \
203 tobyte((a)[2]) == tobyte((b)[2]) && \
204 tobyte((a)[3]) == tobyte((b)[3]))
206 static struct b_mtrl default_base_mtrl =
208 { 0.8f, 0.8f, 0.8f, 1.0f },
209 { 0.2f, 0.2f, 0.2f, 1.0f },
210 { 0.0f, 0.0f, 0.0f, 1.0f },
211 { 0.0f, 0.0f, 0.0f, 1.0f },
212 { 0.0f }, 0.0f, 0, ""
215 static struct d_mtrl default_draw_mtrl =
217 &default_base_mtrl, 0
220 const struct d_mtrl *sol_apply_mtrl(const struct d_mtrl *mp_draw,
221 const struct d_mtrl *mq_draw)
223 const struct b_mtrl *mp_base = mp_draw->base;
224 const struct b_mtrl *mq_base = mq_draw->base;
226 /* Bind the texture. */
228 if (mp_draw->o != mq_draw->o)
229 glBindTexture(GL_TEXTURE_2D, mp_draw->o);
231 /* Set material properties. */
233 if (!color_cmp(mp_base->a, mq_base->a))
234 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mp_base->a);
235 if (!color_cmp(mp_base->d, mq_base->d))
236 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp_base->d);
237 if (!color_cmp(mp_base->s, mq_base->s))
238 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mp_base->s);
239 if (!color_cmp(mp_base->e, mq_base->e))
240 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mp_base->e);
241 if (tobyte(mp_base->h[0]) != tobyte(mq_base->h[0]))
242 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mp_base->h);
246 if ((mp_base->fl & M_SHADOWED) && !(mq_base->fl & M_SHADOWED))
251 if (!(mp_base->fl & M_SHADOWED) && (mq_base->fl & M_SHADOWED))
256 /* Environment mapping. */
258 #ifndef CONF_OPENGLES
259 if ((mp_base->fl & M_ENVIRONMENT) && !(mq_base->fl & M_ENVIRONMENT))
261 glEnable(GL_TEXTURE_GEN_S);
262 glEnable(GL_TEXTURE_GEN_T);
264 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
265 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
268 if ((mq_base->fl & M_ENVIRONMENT) && !(mp_base->fl & M_ENVIRONMENT))
270 glDisable(GL_TEXTURE_GEN_S);
271 glDisable(GL_TEXTURE_GEN_T);
275 /* Additive blending. */
277 if ((mp_base->fl & M_ADDITIVE) && !(mq_base->fl & M_ADDITIVE))
278 glBlendFunc(GL_ONE, GL_ONE);
280 if ((mq_base->fl & M_ADDITIVE) && !(mp_base->fl & M_ADDITIVE))
281 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
283 /* Visibility-from-behind. */
285 if ((mp_base->fl & M_TWO_SIDED) && !(mq_base->fl & M_TWO_SIDED))
287 glDisable(GL_CULL_FACE);
288 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1);
291 if ((mq_base->fl & M_TWO_SIDED) && !(mp_base->fl & M_TWO_SIDED))
293 glEnable(GL_CULL_FACE);
294 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 0);
299 if ((mp_base->fl & M_DECAL) && !(mq_base->fl & M_DECAL))
301 glEnable(GL_POLYGON_OFFSET_FILL);
302 glPolygonOffset(-1.0f, -2.0f);
305 if ((mq_base->fl & M_DECAL) && !(mp_base->fl & M_DECAL))
306 glDisable(GL_POLYGON_OFFSET_FILL);
311 static GLuint sol_find_texture(const char *name)
318 /* Prefer a lossless copy of the texture over a lossy compression. */
320 strncpy(png, name, PATHMAX); strcat(png, ".png");
321 strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
323 /* Check for a PNG. */
325 if ((o = make_image_from_file(png)))
328 /* Check for a JPG. */
330 if ((o = make_image_from_file(jpg)))
336 static void sol_load_mtrl(struct d_mtrl *mp,
337 const struct b_mtrl *mq,
342 if ((mp->o = sol_find_texture(_(mq->f))))
344 /* Set the texture to clamp or repeat based on material type. */
346 if (mq->fl & M_CLAMP_S)
347 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
349 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
351 if (mq->fl & M_CLAMP_T)
352 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
354 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
356 /* If at least one material is reflective, mark it in the SOL. */
358 if (mq->fl & M_REFLECTIVE)
359 draw->reflective = 1;
363 static void sol_free_mtrl(struct d_mtrl *mp)
365 if (glIsTexture(mp->o))
366 glDeleteTextures(1, &mp->o);
369 static int sol_test_mtrl(const struct d_mtrl *mp, int p)
371 /* Test whether the material flags exclude f0 and include f1. */
373 return ((mp->base->fl & pass_in[p]) == pass_in[p] &&
374 (mp->base->fl & pass_ex[p]) == 0);
377 /*---------------------------------------------------------------------------*/
379 static int sol_count_geom(const struct s_base *base, int g0, int gc, int mi)
383 /* The arguments g0 and gc specify a range of the index array. These */
384 /* indices refer to geoms. Determine how many of these geoms use the */
387 for (gi = 0; gi < gc; gi++)
388 if (base->gv[base->iv[g0 + gi]].mi == mi)
394 static int sol_count_body(const struct b_body *bp,
395 const struct s_base *base, int mi)
399 /* Count all lump geoms with the given material. */
401 for (li = 0; li < bp->lc; li++)
402 c += sol_count_geom(base, base->lv[bp->l0 + li].g0,
403 base->lv[bp->l0 + li].gc, mi);
405 /* Count all body geoms with the given material. */
407 c += sol_count_geom(base, bp->g0, bp->gc, mi);
412 static int sol_count_mesh(const struct d_body *bp, int p)
416 /* Count the body meshes matching the given material flags. */
418 for (mi = 0; mi < bp->mc; ++mi)
419 if (sol_test_mtrl(bp->mv[mi].mp, p))
425 /*---------------------------------------------------------------------------*/
427 static void sol_mesh_vert(struct d_vert *vp,
428 const struct s_base *base, int oi)
430 /* Gather all vertex attributes for the given offs. */
432 const struct b_texc *tq = base->tv + base->ov[oi].ti;
433 const struct b_side *sq = base->sv + base->ov[oi].si;
434 const struct b_vert *vq = base->vv + base->ov[oi].vi;
448 static void sol_mesh_geom(struct d_vert *vv, int *vn,
449 struct d_geom *gv, int *gn,
450 const struct s_base *base, int *iv, int g0, int gc, int mi)
454 /* Insert all geoms with material mi into the vertex and element data. */
456 for (gi = 0; gi < gc; gi++)
458 const struct b_geom *gq = base->gv + base->iv[g0 + gi];
462 /* Insert a d_vert into the VBO data for each referenced b_off. */
464 if (iv[gq->oi] == -1)
467 sol_mesh_vert(vv + (*vn)++, base, gq->oi);
469 if (iv[gq->oj] == -1)
472 sol_mesh_vert(vv + (*vn)++, base, gq->oj);
474 if (iv[gq->ok] == -1)
477 sol_mesh_vert(vv + (*vn)++, base, gq->ok);
480 /* Populate the EBO data using remapped b_off indices. */
482 gv[*gn].i = iv[gq->oi];
483 gv[*gn].j = iv[gq->oj];
484 gv[*gn].k = iv[gq->ok];
491 static void sol_load_mesh(struct d_mesh *mp,
492 const struct b_body *bp,
493 const struct s_draw *draw, int mi)
495 const size_t vs = sizeof (struct d_vert);
496 const size_t gs = sizeof (struct d_geom);
498 struct d_vert *vv = 0;
499 struct d_geom *gv = 0;
502 int oc = draw->base->oc;
506 const int gc = sol_count_body(bp, draw->base, mi);
508 /* Get temporary storage for vertex and element array creation. */
510 if ((vv = (struct d_vert *) calloc(oc, vs)) &&
511 (gv = (struct d_geom *) calloc(gc, gs)) &&
512 (iv = (int *) calloc(oc, sizeof (int))))
516 /* Initialize the index remapping. */
518 for (i = 0; i < oc; ++i) iv[i] = -1;
520 /* Include all matching lump geoms in the arrays. */
522 for (li = 0; li < bp->lc; li++)
523 sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv,
524 draw->base->lv[bp->l0 + li].g0,
525 draw->base->lv[bp->l0 + li].gc, mi);
527 /* Include all matching body geoms in the arrays. */
529 sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv, bp->g0, bp->gc, mi);
531 /* Initialize buffer objects for all data. */
533 glGenBuffers_(1, &mp->vbo);
534 glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
535 glBufferData_(GL_ARRAY_BUFFER, vn * vs, vv, GL_STATIC_DRAW);
536 glBindBuffer_(GL_ARRAY_BUFFER, 0);
538 glGenBuffers_(1, &mp->ebo);
539 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
540 glBufferData_(GL_ELEMENT_ARRAY_BUFFER, gn * gs, gv, GL_STATIC_DRAW);
541 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
543 mp->mp = draw->mv + mi;
552 static void sol_free_mesh(struct d_mesh *mp)
554 if (glIsBuffer_(mp->ebo))
555 glDeleteBuffers_(1, &mp->ebo);
556 if (glIsBuffer_(mp->vbo))
557 glDeleteBuffers_(1, &mp->vbo);
560 static const struct d_mtrl *sol_draw_mesh(const struct d_mesh *mp,
561 const struct d_mtrl *mq, int p)
563 /* If this mesh has material matching the given flags... */
565 if (sol_test_mtrl(mp->mp, p))
567 const size_t s = sizeof (struct d_vert);
568 const GLenum T = GL_FLOAT;
570 /* Apply the material state. */
572 mq = sol_apply_mtrl(mp->mp, mq);
574 /* Bind the mesh data. */
576 glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
577 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
579 glVertexPointer (3, T, s, (GLvoid *) offsetof (struct d_vert, p));
580 glNormalPointer ( T, s, (GLvoid *) offsetof (struct d_vert, n));
582 glClientActiveTexture_(GL_TEXTURE1);
583 glTexCoordPointer(3, T, s, (GLvoid *) offsetof (struct d_vert, p));
584 glClientActiveTexture_(GL_TEXTURE0);
585 glTexCoordPointer(2, T, s, (GLvoid *) offsetof (struct d_vert, t));
589 glDrawElements(GL_TRIANGLES, mp->ebc, GL_UNSIGNED_SHORT, 0);
595 /*---------------------------------------------------------------------------*/
597 static void sol_load_body(struct d_body *bp,
598 const struct b_body *bq,
599 const struct s_draw *draw)
606 /* Determine how many materials this body uses. */
608 for (mi = 0; mi < draw->mc; ++mi)
609 if (sol_count_body(bq, draw->base, mi))
612 /* Allocate and initialize a mesh for each material. */
614 if ((bp->mv = (struct d_mesh *) calloc(bp->mc, sizeof (struct d_mesh))))
618 for (mi = 0; mi < draw->mc; ++mi)
619 if (sol_count_body(bq, draw->base, mi))
620 sol_load_mesh(bp->mv + mj++, bq, draw, mi);
623 /* Cache a mesh count for each pass. */
625 bp->pass[0] = sol_count_mesh(bp, 0);
626 bp->pass[1] = sol_count_mesh(bp, 1);
627 bp->pass[2] = sol_count_mesh(bp, 2);
628 bp->pass[3] = sol_count_mesh(bp, 3);
629 bp->pass[4] = sol_count_mesh(bp, 4);
632 static void sol_free_body(struct d_body *bp)
636 for (mi = 0; mi < bp->mc; ++mi)
637 sol_free_mesh(bp->mv + mi);
642 static const struct d_mtrl *sol_draw_body(const struct d_body *bp,
643 const struct d_mtrl *mq, int p)
647 for (i = 0; i < bp->mc; ++i)
648 mq = sol_draw_mesh(bp->mv + i, mq, p);
653 /*---------------------------------------------------------------------------*/
655 int sol_load_draw(struct s_draw *draw, const struct s_vary *vary, int s)
659 memset(draw, 0, sizeof (struct s_draw));
662 draw->base = vary->base;
664 /* Initialize all materials for this file. */
668 if ((draw->mv = calloc(draw->base->mc, sizeof (*draw->mv))))
670 draw->mc = draw->base->mc;
672 for (i = 0; i < draw->mc; i++)
673 sol_load_mtrl(draw->mv + i, draw->base->mv + i, draw);
677 /* Initialize all bodies for this file. */
681 if ((draw->bv = calloc(draw->base->bc, sizeof (*draw->bv))))
683 draw->bc = draw->base->bc;
685 for (i = 0; i < draw->bc; i++)
686 sol_load_body(draw->bv + i, draw->base->bv + i, draw);
695 void sol_free_draw(struct s_draw *draw)
701 for (i = 0; i < draw->bc; i++)
702 sol_free_body(draw->bv + i);
703 for (i = 0; i < draw->mc; i++)
704 sol_free_mtrl(draw->mv + i);
707 /*---------------------------------------------------------------------------*/
709 static const struct d_mtrl *sol_draw_all(const struct s_draw *draw,
710 const struct d_mtrl *mq, int p)
714 /* Draw all meshes of all bodies matching the given material flags. */
716 for (bi = 0; bi < draw->bc; ++bi)
718 if (draw->bv[bi].pass[p])
722 sol_transform(draw->vary, draw->vary->bv + bi);
723 mq = sol_draw_body(draw->bv + bi, mq, p);
731 const struct d_mtrl *sol_draw_enable(void)
733 glEnableClientState(GL_VERTEX_ARRAY);
734 glEnableClientState(GL_NORMAL_ARRAY);
736 glClientActiveTexture_(GL_TEXTURE1);
737 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
738 glClientActiveTexture_(GL_TEXTURE0);
739 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
741 return &default_draw_mtrl;
744 void sol_draw_disable(const struct d_mtrl *mq)
746 sol_apply_mtrl(&default_draw_mtrl, mq);
748 glClientActiveTexture_(GL_TEXTURE1);
749 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
750 glClientActiveTexture_(GL_TEXTURE0);
751 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
753 glDisableClientState(GL_NORMAL_ARRAY);
754 glDisableClientState(GL_VERTEX_ARRAY);
757 /*---------------------------------------------------------------------------*/
759 const struct d_mtrl *sol_draw(const struct s_draw *draw,
760 const struct d_mtrl *mq, int mask, int test)
762 /* Render all opaque geometry, decals last. */
764 mq = sol_draw_all(draw, mq, 0);
765 mq = sol_draw_all(draw, mq, 1);
767 /* Render all transparent geometry, decals first. */
769 if (!test) glDisable(GL_DEPTH_TEST);
770 if (!mask) glDepthMask(GL_FALSE);
772 mq = sol_draw_all(draw, mq, 2);
773 mq = sol_draw_all(draw, mq, 3);
775 if (!mask) glDepthMask(GL_TRUE);
776 if (!test) glEnable(GL_DEPTH_TEST);
778 /* Revert the buffer object state. */
780 glBindBuffer_(GL_ARRAY_BUFFER, 0);
781 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
786 const struct d_mtrl *sol_refl(const struct s_draw *draw,
787 const struct d_mtrl *mq)
789 /* Render all reflective geometry. */
791 mq = sol_draw_all(draw, mq, 4);
793 /* Revert the buffer object state. */
795 glBindBuffer_(GL_ARRAY_BUFFER, 0);
796 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
801 const struct d_mtrl *sol_back(const struct s_draw *draw,
802 const struct d_mtrl *mq,
803 float n, float f, float t)
805 glDisable(GL_LIGHTING);
806 glDepthMask(GL_FALSE);
808 sol_bill_enable(draw);
812 /* Consider each billboard. */
814 for (ri = 0; ri < draw->base->rc; ri++)
816 const struct b_bill *rp = draw->base->rv + ri;
818 /* Render only billboards at distances between n and f. */
820 if (n <= rp->d && rp->d < f)
822 float T = (rp->t > 0.0f) ? (fmodf(t, rp->t) - rp->t / 2) : 0;
824 float w = rp->w[0] + rp->w[1] * T + rp->w[2] * T * T;
825 float h = rp->h[0] + rp->h[1] * T + rp->h[2] * T * T;
827 /* Render only billboards facing the viewer. */
831 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * T * T;
832 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * T * T;
833 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * T * T;
837 if (ry) glRotatef(ry, 0.0f, 1.0f, 0.0f);
838 if (rx) glRotatef(rx, 1.0f, 0.0f, 0.0f);
840 glTranslatef(0.0f, 0.0f, -rp->d);
844 glRotatef(-rx - 90.0f, 1.0f, 0.0f, 0.0f);
845 glRotatef(-ry, 0.0f, 0.0f, 1.0f);
848 glRotatef(-rx, 1.0f, 0.0f, 0.0f);
850 if (rz) glRotatef(rz, 0.0f, 0.0f, 1.0f);
852 glScalef(w, h, 1.0f);
854 mq = sol_apply_mtrl(draw->mv + rp->mi, mq);
857 glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
859 glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
868 glDepthMask(GL_TRUE);
869 glEnable(GL_LIGHTING);
874 const struct d_mtrl *sol_bill(const struct s_draw *draw,
875 const struct d_mtrl *mq, const float *M, float t)
877 sol_bill_enable(draw);
881 for (ri = 0; ri < draw->base->rc; ++ri)
883 const struct b_bill *rp = draw->base->rv + ri;
888 float w = rp->w [0] + rp->w [1] * T + rp->w [2] * S;
889 float h = rp->h [0] + rp->h [1] * T + rp->h [2] * S;
890 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * S;
891 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * S;
892 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * S;
894 mq = sol_apply_mtrl(draw->mv + rp->mi, mq);
898 glTranslatef(rp->p[0], rp->p[1], rp->p[2]);
900 if (M && ((rp->fl & B_NOFACE) == 0)) glMultMatrixf(M);
902 if (fabsf(rx) > 0.0f) glRotatef(rx, 1.0f, 0.0f, 0.0f);
903 if (fabsf(ry) > 0.0f) glRotatef(ry, 0.0f, 1.0f, 0.0f);
904 if (fabsf(rz) > 0.0f) glRotatef(rz, 0.0f, 0.0f, 1.0f);
906 sol_draw_bill(w, h, GL_FALSE);
916 void sol_fade(const struct s_draw *draw, float k)
920 glMatrixMode(GL_PROJECTION);
923 glMatrixMode(GL_MODELVIEW);
927 glEnable(GL_COLOR_MATERIAL);
928 glDisable(GL_LIGHTING);
929 glDisable(GL_DEPTH_TEST);
930 glDisable(GL_TEXTURE_2D);
932 glColor4f(0.0f, 0.0f, 0.0f, k);
934 sol_bill_enable(draw);
935 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
938 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
940 glEnable(GL_TEXTURE_2D);
941 glEnable(GL_DEPTH_TEST);
942 glEnable(GL_LIGHTING);
943 glDisable(GL_COLOR_MATERIAL);
945 glMatrixMode(GL_PROJECTION);
947 glMatrixMode(GL_MODELVIEW);
952 /*---------------------------------------------------------------------------*/
954 int sol_load_full(struct s_full *full, const char *filename, int s)
956 if (sol_load_base(&full->base, filename))
958 sol_load_vary(&full->vary, &full->base);
959 sol_load_draw(&full->draw, &full->vary, s);
967 void sol_free_full(struct s_full *full)
969 sol_free_draw(&full->draw);
970 sol_free_vary(&full->vary);
971 sol_free_base(&full->base);
974 /*---------------------------------------------------------------------------*/