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 /* Scale the shadow texture to the radius of the ball. */
99 /* Move the shadow texture under the ball. */
101 glTranslatef(-vary->uv->p[0],
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 static struct b_mtrl default_base_mtrl =
203 { 0.8f, 0.8f, 0.8f, 1.0f },
204 { 0.2f, 0.2f, 0.2f, 1.0f },
205 { 0.0f, 0.0f, 0.0f, 1.0f },
206 { 0.0f, 0.0f, 0.0f, 1.0f },
207 { 0.0f }, 0.0f, 0, ""
212 static struct d_mtrl default_draw_mtrl =
223 void sol_apply_mtrl(const struct d_mtrl *mp_draw, struct s_rend *rend)
225 const struct b_mtrl *mp_base = mp_draw->base;
226 const struct d_mtrl *mq_draw = rend->mp;
227 const struct b_mtrl *mq_base = mq_draw->base;
229 /* Bind the texture. */
231 if (mp_draw->o != mq_draw->o)
232 glBindTexture(GL_TEXTURE_2D, mp_draw->o);
234 /* Set material properties. */
236 if (mp_draw->d != mq_draw->d)
237 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp_base->d);
238 if (mp_draw->a != mq_draw->a)
239 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mp_base->a);
240 if (mp_draw->s != mq_draw->s)
241 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mp_base->s);
242 if (mp_draw->e != mq_draw->e)
243 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mp_base->e);
244 if (mp_draw->h != mq_draw->h)
245 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mp_base->h);
249 if ((mp_base->fl & M_SHADOWED) ^ (mq_base->fl & M_SHADOWED))
251 if (mp_base->fl & M_SHADOWED)
257 /* Environment mapping. */
259 #ifndef CONF_OPENGLES
260 if ((mp_base->fl & M_ENVIRONMENT) ^ (mq_base->fl & M_ENVIRONMENT))
262 if (mp_base->fl & M_ENVIRONMENT)
264 glEnable(GL_TEXTURE_GEN_S);
265 glEnable(GL_TEXTURE_GEN_T);
267 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
268 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
272 glDisable(GL_TEXTURE_GEN_S);
273 glDisable(GL_TEXTURE_GEN_T);
278 /* Additive blending. */
280 if ((mp_base->fl & M_ADDITIVE) ^ (mq_base->fl & M_ADDITIVE))
282 if (mp_base->fl & M_ADDITIVE)
283 glBlendFunc(GL_ONE, GL_ONE);
285 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
288 /* Visibility-from-behind. */
290 if ((mp_base->fl & M_TWO_SIDED) ^ (mq_base->fl & M_TWO_SIDED))
292 if (mp_base->fl & M_TWO_SIDED)
294 glDisable(GL_CULL_FACE);
295 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1);
299 glEnable(GL_CULL_FACE);
300 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 0);
306 if ((mp_base->fl & M_DECAL) ^ (mq_base->fl & M_DECAL))
308 if (mp_base->fl & M_DECAL)
310 glEnable(GL_POLYGON_OFFSET_FILL);
311 glPolygonOffset(-1.0f, -2.0f);
314 glDisable(GL_POLYGON_OFFSET_FILL);
320 static GLuint sol_find_texture(const char *name)
327 /* Prefer a lossless copy of the texture over a lossy compression. */
329 strncpy(png, name, PATHMAX); strcat(png, ".png");
330 strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
332 /* Check for a PNG. */
334 if ((o = make_image_from_file(png)))
337 /* Check for a JPG. */
339 if ((o = make_image_from_file(jpg)))
345 void sol_load_mtrl(struct d_mtrl *mp, const struct b_mtrl *mq)
349 if ((mp->o = sol_find_texture(_(mq->f))))
351 /* Set the texture to clamp or repeat based on material type. */
353 if (mq->fl & M_CLAMP_S)
354 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
358 if (mq->fl & M_CLAMP_T)
359 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
361 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
364 /* Cache the 32-bit material values for quick comparison. */
366 mp->d = (tobyte(mq->d[0]))
367 | (tobyte(mq->d[1]) << 8)
368 | (tobyte(mq->d[2]) << 16)
369 | (tobyte(mq->d[3]) << 24);
370 mp->a = (tobyte(mq->a[0]))
371 | (tobyte(mq->a[1]) << 8)
372 | (tobyte(mq->a[2]) << 16)
373 | (tobyte(mq->a[3]) << 24);
374 mp->s = (tobyte(mq->s[0]))
375 | (tobyte(mq->s[1]) << 8)
376 | (tobyte(mq->s[2]) << 16)
377 | (tobyte(mq->s[3]) << 24);
378 mp->e = (tobyte(mq->e[0]))
379 | (tobyte(mq->e[1]) << 8)
380 | (tobyte(mq->e[2]) << 16)
381 | (tobyte(mq->e[3]) << 24);
382 mp->h = (tobyte(mq->h[0]));
385 void sol_free_mtrl(struct d_mtrl *mp)
387 if (glIsTexture(mp->o))
388 glDeleteTextures(1, &mp->o);
391 static int sol_test_mtrl(const struct d_mtrl *mp, int p)
393 /* Test whether the material flags exclude f0 and include f1. */
395 return ((mp->base->fl & pass_in[p]) == pass_in[p] &&
396 (mp->base->fl & pass_ex[p]) == 0);
399 /*---------------------------------------------------------------------------*/
401 static int sol_count_geom(const struct s_base *base, int g0, int gc, int mi)
405 /* The arguments g0 and gc specify a range of the index array. These */
406 /* indices refer to geoms. Determine how many of these geoms use the */
409 for (gi = 0; gi < gc; gi++)
410 if (base->gv[base->iv[g0 + gi]].mi == mi)
416 static int sol_count_body(const struct b_body *bp,
417 const struct s_base *base, int mi)
421 /* Count all lump geoms with the given material. */
423 for (li = 0; li < bp->lc; li++)
424 c += sol_count_geom(base, base->lv[bp->l0 + li].g0,
425 base->lv[bp->l0 + li].gc, mi);
427 /* Count all body geoms with the given material. */
429 c += sol_count_geom(base, bp->g0, bp->gc, mi);
434 static int sol_count_mesh(const struct d_body *bp, int p)
438 /* Count the body meshes matching the given material flags. */
440 for (mi = 0; mi < bp->mc; ++mi)
441 if (sol_test_mtrl(bp->mv[mi].mp, p))
447 /*---------------------------------------------------------------------------*/
449 static void sol_mesh_vert(struct d_vert *vp,
450 const struct s_base *base, int oi)
452 /* Gather all vertex attributes for the given offs. */
454 const struct b_texc *tq = base->tv + base->ov[oi].ti;
455 const struct b_side *sq = base->sv + base->ov[oi].si;
456 const struct b_vert *vq = base->vv + base->ov[oi].vi;
470 static void sol_mesh_geom(struct d_vert *vv, int *vn,
471 struct d_geom *gv, int *gn,
472 const struct s_base *base, int *iv, int g0, int gc, int mi)
476 /* Insert all geoms with material mi into the vertex and element data. */
478 for (gi = 0; gi < gc; gi++)
480 const struct b_geom *gq = base->gv + base->iv[g0 + gi];
484 /* Insert a d_vert into the VBO data for each referenced b_off. */
486 if (iv[gq->oi] == -1)
489 sol_mesh_vert(vv + (*vn)++, base, gq->oi);
491 if (iv[gq->oj] == -1)
494 sol_mesh_vert(vv + (*vn)++, base, gq->oj);
496 if (iv[gq->ok] == -1)
499 sol_mesh_vert(vv + (*vn)++, base, gq->ok);
502 /* Populate the EBO data using remapped b_off indices. */
504 gv[*gn].i = iv[gq->oi];
505 gv[*gn].j = iv[gq->oj];
506 gv[*gn].k = iv[gq->ok];
513 static void sol_load_mesh(struct d_mesh *mp,
514 const struct b_body *bp,
515 const struct s_draw *draw, int mi)
517 const size_t vs = sizeof (struct d_vert);
518 const size_t gs = sizeof (struct d_geom);
520 struct d_vert *vv = 0;
521 struct d_geom *gv = 0;
524 int oc = draw->base->oc;
528 const int gc = sol_count_body(bp, draw->base, mi);
530 /* Get temporary storage for vertex and element array creation. */
532 if ((vv = (struct d_vert *) calloc(oc, vs)) &&
533 (gv = (struct d_geom *) calloc(gc, gs)) &&
534 (iv = (int *) calloc(oc, sizeof (int))))
538 /* Initialize the index remapping. */
540 for (i = 0; i < oc; ++i) iv[i] = -1;
542 /* Include all matching lump geoms in the arrays. */
544 for (li = 0; li < bp->lc; li++)
545 sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv,
546 draw->base->lv[bp->l0 + li].g0,
547 draw->base->lv[bp->l0 + li].gc, mi);
549 /* Include all matching body geoms in the arrays. */
551 sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv, bp->g0, bp->gc, mi);
553 /* Initialize buffer objects for all data. */
555 glGenBuffers_(1, &mp->vbo);
556 glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
557 glBufferData_(GL_ARRAY_BUFFER, vn * vs, vv, GL_STATIC_DRAW);
558 glBindBuffer_(GL_ARRAY_BUFFER, 0);
560 glGenBuffers_(1, &mp->ebo);
561 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
562 glBufferData_(GL_ELEMENT_ARRAY_BUFFER, gn * gs, gv, GL_STATIC_DRAW);
563 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
565 mp->mp = draw->mv + mi;
574 static void sol_free_mesh(struct d_mesh *mp)
576 if (glIsBuffer_(mp->ebo))
577 glDeleteBuffers_(1, &mp->ebo);
578 if (glIsBuffer_(mp->vbo))
579 glDeleteBuffers_(1, &mp->vbo);
582 void sol_draw_mesh(const struct d_mesh *mp, struct s_rend *rend, int p)
584 /* If this mesh has material matching the given flags... */
586 if (sol_test_mtrl(mp->mp, p))
588 const size_t s = sizeof (struct d_vert);
589 const GLenum T = GL_FLOAT;
591 /* Apply the material state. */
593 sol_apply_mtrl(mp->mp, rend);
595 /* Bind the mesh data. */
597 glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
598 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
600 glVertexPointer (3, T, s, (GLvoid *) offsetof (struct d_vert, p));
601 glNormalPointer ( T, s, (GLvoid *) offsetof (struct d_vert, n));
603 glClientActiveTexture_(GL_TEXTURE1);
604 glTexCoordPointer(3, T, s, (GLvoid *) offsetof (struct d_vert, p));
605 glClientActiveTexture_(GL_TEXTURE0);
606 glTexCoordPointer(2, T, s, (GLvoid *) offsetof (struct d_vert, t));
610 glDrawElements(GL_TRIANGLES, mp->ebc, GL_UNSIGNED_SHORT, 0);
614 /*---------------------------------------------------------------------------*/
616 static void sol_load_body(struct d_body *bp,
617 const struct b_body *bq,
618 const struct s_draw *draw)
625 /* Determine how many materials this body uses. */
627 for (mi = 0; mi < draw->mc; ++mi)
628 if (sol_count_body(bq, draw->base, mi))
631 /* Allocate and initialize a mesh for each material. */
633 if ((bp->mv = (struct d_mesh *) calloc(bp->mc, sizeof (struct d_mesh))))
637 for (mi = 0; mi < draw->mc; ++mi)
638 if (sol_count_body(bq, draw->base, mi))
639 sol_load_mesh(bp->mv + mj++, bq, draw, mi);
642 /* Cache a mesh count for each pass. */
644 bp->pass[0] = sol_count_mesh(bp, 0);
645 bp->pass[1] = sol_count_mesh(bp, 1);
646 bp->pass[2] = sol_count_mesh(bp, 2);
647 bp->pass[3] = sol_count_mesh(bp, 3);
648 bp->pass[4] = sol_count_mesh(bp, 4);
651 static void sol_free_body(struct d_body *bp)
655 for (mi = 0; mi < bp->mc; ++mi)
656 sol_free_mesh(bp->mv + mi);
661 static void sol_draw_body(const struct d_body *bp, struct s_rend *rend, int p)
665 for (i = 0; i < bp->mc; ++i)
666 sol_draw_mesh(bp->mv + i, rend, p);
669 /*---------------------------------------------------------------------------*/
671 int sol_load_draw(struct s_draw *draw, const struct s_vary *vary, int s)
675 memset(draw, 0, sizeof (struct s_draw));
678 draw->base = vary->base;
680 /* Initialize all materials for this file. */
684 if ((draw->mv = calloc(draw->base->mc, sizeof (*draw->mv))))
686 draw->mc = draw->base->mc;
688 for (i = 0; i < draw->mc; i++)
690 sol_load_mtrl(draw->mv + i, draw->base->mv + i);
692 /* If at least one material is reflective, mark it. */
694 if (draw->base->mv[i].fl & M_REFLECTIVE)
695 draw->reflective = 1;
700 /* Initialize all bodies for this file. */
704 if ((draw->bv = calloc(draw->base->bc, sizeof (*draw->bv))))
706 draw->bc = draw->base->bc;
708 for (i = 0; i < draw->bc; i++)
709 sol_load_body(draw->bv + i, draw->base->bv + i, draw);
718 void sol_free_draw(struct s_draw *draw)
724 for (i = 0; i < draw->bc; i++)
725 sol_free_body(draw->bv + i);
726 for (i = 0; i < draw->mc; i++)
727 sol_free_mtrl(draw->mv + i);
730 /*---------------------------------------------------------------------------*/
732 static void sol_draw_all(const struct s_draw *draw, struct s_rend *rend, int p)
736 /* Draw all meshes of all bodies matching the given material flags. */
738 for (bi = 0; bi < draw->bc; ++bi)
740 if (draw->bv[bi].pass[p])
744 sol_transform(draw->vary, draw->vary->bv + bi);
745 sol_draw_body(draw->bv + bi, rend, p);
751 void sol_draw_enable(struct s_rend *rend)
753 glEnableClientState(GL_VERTEX_ARRAY);
754 glEnableClientState(GL_NORMAL_ARRAY);
756 glClientActiveTexture_(GL_TEXTURE1);
757 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
758 glClientActiveTexture_(GL_TEXTURE0);
759 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
761 rend->mp = &default_draw_mtrl;
764 void sol_draw_disable(struct s_rend *rend)
766 sol_apply_mtrl(&default_draw_mtrl, rend);
768 glClientActiveTexture_(GL_TEXTURE1);
769 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
770 glClientActiveTexture_(GL_TEXTURE0);
771 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
773 glDisableClientState(GL_NORMAL_ARRAY);
774 glDisableClientState(GL_VERTEX_ARRAY);
777 /*---------------------------------------------------------------------------*/
779 void sol_draw(const struct s_draw *draw, struct s_rend *rend, int mask, int test)
781 /* Render all opaque geometry, decals last. */
783 sol_draw_all(draw, rend, 0);
784 sol_draw_all(draw, rend, 1);
786 /* Render all transparent geometry, decals first. */
788 if (!test) glDisable(GL_DEPTH_TEST);
789 if (!mask) glDepthMask(GL_FALSE);
791 sol_draw_all(draw, rend, 2);
792 sol_draw_all(draw, rend, 3);
794 if (!mask) glDepthMask(GL_TRUE);
795 if (!test) glEnable(GL_DEPTH_TEST);
797 /* Revert the buffer object state. */
799 glBindBuffer_(GL_ARRAY_BUFFER, 0);
800 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
803 void sol_refl(const struct s_draw *draw, struct s_rend *rend)
805 /* Render all reflective geometry. */
807 sol_draw_all(draw, rend, 4);
809 /* Revert the buffer object state. */
811 glBindBuffer_(GL_ARRAY_BUFFER, 0);
812 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
815 void sol_back(const struct s_draw *draw,
817 float n, float f, float t)
819 if (!draw || !draw->base)
822 glDisable(GL_LIGHTING);
823 glDepthMask(GL_FALSE);
825 sol_bill_enable(draw);
829 /* Consider each billboard. */
831 for (ri = 0; ri < draw->base->rc; ri++)
833 const struct b_bill *rp = draw->base->rv + ri;
835 /* Render only billboards at distances between n and f. */
837 if (n <= rp->d && rp->d < f)
839 float T = (rp->t > 0.0f) ? (fmodf(t, rp->t) - rp->t / 2) : 0;
841 float w = rp->w[0] + rp->w[1] * T + rp->w[2] * T * T;
842 float h = rp->h[0] + rp->h[1] * T + rp->h[2] * T * T;
844 /* Render only billboards facing the viewer. */
848 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * T * T;
849 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * T * T;
850 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * T * T;
854 if (ry) glRotatef(ry, 0.0f, 1.0f, 0.0f);
855 if (rx) glRotatef(rx, 1.0f, 0.0f, 0.0f);
857 glTranslatef(0.0f, 0.0f, -rp->d);
861 glRotatef(-rx - 90.0f, 1.0f, 0.0f, 0.0f);
862 glRotatef(-ry, 0.0f, 0.0f, 1.0f);
865 glRotatef(-rx, 1.0f, 0.0f, 0.0f);
867 if (rz) glRotatef(rz, 0.0f, 0.0f, 1.0f);
869 glScalef(w, h, 1.0f);
871 sol_apply_mtrl(draw->mv + rp->mi, rend);
874 glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
876 glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
885 glDepthMask(GL_TRUE);
886 glEnable(GL_LIGHTING);
889 void sol_bill(const struct s_draw *draw,
890 struct s_rend *rend, const float *M, float t)
892 sol_bill_enable(draw);
896 for (ri = 0; ri < draw->base->rc; ++ri)
898 const struct b_bill *rp = draw->base->rv + ri;
903 float w = rp->w [0] + rp->w [1] * T + rp->w [2] * S;
904 float h = rp->h [0] + rp->h [1] * T + rp->h [2] * S;
905 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * S;
906 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * S;
907 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * S;
909 sol_apply_mtrl(draw->mv + rp->mi, rend);
913 glTranslatef(rp->p[0], rp->p[1], rp->p[2]);
915 if (M && ((rp->fl & B_NOFACE) == 0)) glMultMatrixf(M);
917 if (fabsf(rx) > 0.0f) glRotatef(rx, 1.0f, 0.0f, 0.0f);
918 if (fabsf(ry) > 0.0f) glRotatef(ry, 0.0f, 1.0f, 0.0f);
919 if (fabsf(rz) > 0.0f) glRotatef(rz, 0.0f, 0.0f, 1.0f);
921 sol_draw_bill(w, h, GL_FALSE);
929 void sol_fade(const struct s_draw *draw, float k)
933 glMatrixMode(GL_PROJECTION);
936 glMatrixMode(GL_MODELVIEW);
940 glEnable(GL_COLOR_MATERIAL);
941 glDisable(GL_LIGHTING);
942 glDisable(GL_DEPTH_TEST);
943 glDisable(GL_TEXTURE_2D);
945 glColor4f(0.0f, 0.0f, 0.0f, k);
947 sol_bill_enable(draw);
948 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
951 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
953 glEnable(GL_TEXTURE_2D);
954 glEnable(GL_DEPTH_TEST);
955 glEnable(GL_LIGHTING);
956 glDisable(GL_COLOR_MATERIAL);
958 glMatrixMode(GL_PROJECTION);
960 glMatrixMode(GL_MODELVIEW);
965 /*---------------------------------------------------------------------------*/
967 int sol_load_full(struct s_full *full, const char *filename, int s)
969 if (sol_load_base(&full->base, filename))
971 sol_load_vary(&full->vary, &full->base);
972 sol_load_draw(&full->draw, &full->vary, s);
980 void sol_free_full(struct s_full *full)
982 sol_free_draw(&full->draw);
983 sol_free_vary(&full->vary);
984 sol_free_base(&full->base);
987 /*---------------------------------------------------------------------------*/