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, int ui)
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 (ui >= 0 && ui < vary->uc && vary->uv[ui].r > 0.0f)
80 struct v_ball *up = vary->uv + ui;
82 if (tex_env_stage(TEX_STAGE_SHADOW))
84 glMatrixMode(GL_TEXTURE);
86 float k = 0.25f / up->r;
90 /* Center the shadow texture on the ball. */
92 glTranslatef(0.5f, 0.5f, 0.0f);
94 /* Transform ball XZ position to ST texture coordinate. */
96 glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
98 /* Scale the shadow texture to the radius of the ball. */
102 /* Move the shadow texture under the ball. */
104 glTranslatef(-up->p[0], -up->p[1], -up->p[2]);
106 /* Apply the body position and rotation. */
108 glTranslatef(p[0], p[1], p[2]);
109 glRotatef(V_DEG(a), v[0], v[1], v[2]);
111 /* Vertically center clipper texture on ball position. */
113 if (tex_env_stage(TEX_STAGE_CLIP))
116 glTranslatef(p[0] - up->p[0],
117 p[1] - up->p[1] + 0.5f,
119 glRotatef(V_DEG(a), v[0], v[1], v[2]);
123 glMatrixMode(GL_MODELVIEW);
125 tex_env_stage(TEX_STAGE_TEXTURE);
130 /*---------------------------------------------------------------------------*/
132 static void sol_load_bill(struct s_draw *draw)
134 static const GLfloat data[] = {
135 0.0f, 0.0f, -1.0f, -1.0f,
136 1.0f, 0.0f, 1.0f, -1.0f,
137 0.0f, 1.0f, -1.0f, 1.0f,
138 1.0f, 1.0f, 1.0f, 1.0f,
140 0.0f, 0.0f, -0.5f, 0.0f,
141 1.0f, 0.0f, 0.5f, 0.0f,
142 0.0f, 1.0f, -0.5f, 1.0f,
143 1.0f, 1.0f, 0.5f, 1.0f,
145 0.0f, 0.0f, -0.5f, -0.5f,
146 1.0f, 0.0f, 0.5f, -0.5f,
147 0.0f, 1.0f, -0.5f, 0.5f,
148 1.0f, 1.0f, 0.5f, 0.5f,
151 /* Initialize a vertex buffer object for billboard drawing. */
153 glGenBuffers_(1, &draw->bill);
154 glBindBuffer_(GL_ARRAY_BUFFER, draw->bill);
155 glBufferData_(GL_ARRAY_BUFFER, sizeof (data), data, GL_STATIC_DRAW);
156 glBindBuffer_(GL_ARRAY_BUFFER, 0);
159 static void sol_free_bill(struct s_draw *draw)
161 if (glIsBuffer_(draw->bill))
162 glDeleteBuffers_(1, &draw->bill);
165 static void sol_draw_bill(GLfloat w, GLfloat h, GLboolean edge)
169 glScalef(0.5f * w, 0.5f * h, 1.0f);
172 glTranslatef(0.0f, 0.5f, 0.0f);
174 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
179 /*---------------------------------------------------------------------------*/
181 /* NOTE: The state management here presumes that billboard rendering is */
182 /* NESTED within a wider SOL rendering process. That is: sol_draw_enable */
183 /* has been called and sol_draw_disable will be called in the future. */
184 /* Thus the "default" VBO state retained by billboard rendering is the */
185 /* state appropriate for normal SOL rendering. */
187 static void sol_bill_enable(const struct s_draw *draw)
189 const size_t s = sizeof (GLfloat);
191 glBindBuffer_(GL_ARRAY_BUFFER, draw->bill);
193 glTexCoordPointer(2, GL_FLOAT, s * 4, (GLvoid *) ( 0));
194 glVertexPointer (2, GL_FLOAT, s * 4, (GLvoid *) (s * 2));
197 static void sol_bill_disable(void)
201 /*---------------------------------------------------------------------------*/
203 #define tobyte(f) ((GLubyte) (f * 255.0f))
205 static struct b_mtrl default_base_mtrl =
207 { 0.8f, 0.8f, 0.8f, 1.0f },
208 { 0.2f, 0.2f, 0.2f, 1.0f },
209 { 0.0f, 0.0f, 0.0f, 1.0f },
210 { 0.0f, 0.0f, 0.0f, 1.0f },
211 { 0.0f }, 0.0f, 0, ""
216 static struct d_mtrl default_draw_mtrl =
227 void sol_apply_mtrl(const struct d_mtrl *mp_draw, struct s_rend *rend)
229 const struct b_mtrl *mp_base = mp_draw->base;
230 const struct d_mtrl *mq_draw = rend->mp;
231 const struct b_mtrl *mq_base = mq_draw->base;
233 /* Bind the texture. */
235 if (mp_draw->o != mq_draw->o)
236 glBindTexture(GL_TEXTURE_2D, mp_draw->o);
238 /* Set material properties. */
240 if (mp_draw->d != mq_draw->d)
241 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mp_base->d);
242 if (mp_draw->a != mq_draw->a)
243 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mp_base->a);
244 if (mp_draw->s != mq_draw->s)
245 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mp_base->s);
246 if (mp_draw->e != mq_draw->e)
247 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mp_base->e);
248 if (mp_draw->h != mq_draw->h)
249 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mp_base->h);
253 if ((mp_base->fl & M_SHADOWED) ^ (mq_base->fl & M_SHADOWED))
255 if (mp_base->fl & M_SHADOWED)
261 /* Environment mapping. */
264 if ((mp_base->fl & M_ENVIRONMENT) ^ (mq_base->fl & M_ENVIRONMENT))
266 if (mp_base->fl & M_ENVIRONMENT)
268 glEnable(GL_TEXTURE_GEN_S);
269 glEnable(GL_TEXTURE_GEN_T);
271 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
272 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
276 glDisable(GL_TEXTURE_GEN_S);
277 glDisable(GL_TEXTURE_GEN_T);
282 /* Additive blending. */
284 if ((mp_base->fl & M_ADDITIVE) ^ (mq_base->fl & M_ADDITIVE))
286 if (mp_base->fl & M_ADDITIVE)
287 glBlendFunc(GL_ONE, GL_ONE);
289 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
292 /* Visibility-from-behind. */
294 if ((mp_base->fl & M_TWO_SIDED) ^ (mq_base->fl & M_TWO_SIDED))
296 if (mp_base->fl & M_TWO_SIDED)
298 glDisable(GL_CULL_FACE);
299 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 1);
303 glEnable(GL_CULL_FACE);
304 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, 0);
310 if ((mp_base->fl & M_DECAL) ^ (mq_base->fl & M_DECAL))
312 if (mp_base->fl & M_DECAL)
314 glEnable(GL_POLYGON_OFFSET_FILL);
315 glPolygonOffset(-1.0f, -2.0f);
318 glDisable(GL_POLYGON_OFFSET_FILL);
324 static GLuint sol_find_texture(const char *name)
331 /* Prefer a lossless copy of the texture over a lossy compression. */
333 strncpy(png, name, PATHMAX); strcat(png, ".png");
334 strncpy(jpg, name, PATHMAX); strcat(jpg, ".jpg");
336 /* Check for a PNG. */
338 if ((o = make_image_from_file(png)))
341 /* Check for a JPG. */
343 if ((o = make_image_from_file(jpg)))
349 void sol_load_mtrl(struct d_mtrl *mp, const struct b_mtrl *mq)
353 if ((mp->o = sol_find_texture(_(mq->f))))
355 /* Set the texture to clamp or repeat based on material type. */
357 if (mq->fl & M_CLAMP_S)
358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
360 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
362 if (mq->fl & M_CLAMP_T)
363 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
365 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
368 /* Cache the 32-bit material values for quick comparison. */
370 mp->d = (tobyte(mq->d[0]))
371 | (tobyte(mq->d[1]) << 8)
372 | (tobyte(mq->d[2]) << 16)
373 | (tobyte(mq->d[3]) << 24);
374 mp->a = (tobyte(mq->a[0]))
375 | (tobyte(mq->a[1]) << 8)
376 | (tobyte(mq->a[2]) << 16)
377 | (tobyte(mq->a[3]) << 24);
378 mp->s = (tobyte(mq->s[0]))
379 | (tobyte(mq->s[1]) << 8)
380 | (tobyte(mq->s[2]) << 16)
381 | (tobyte(mq->s[3]) << 24);
382 mp->e = (tobyte(mq->e[0]))
383 | (tobyte(mq->e[1]) << 8)
384 | (tobyte(mq->e[2]) << 16)
385 | (tobyte(mq->e[3]) << 24);
386 mp->h = (tobyte(mq->h[0]));
389 void sol_free_mtrl(struct d_mtrl *mp)
391 if (glIsTexture(mp->o))
392 glDeleteTextures(1, &mp->o);
395 static int sol_test_mtrl(const struct d_mtrl *mp, int p)
397 /* Test whether the material flags exclude f0 and include f1. */
399 return ((mp->base->fl & pass_in[p]) == pass_in[p] &&
400 (mp->base->fl & pass_ex[p]) == 0);
403 /*---------------------------------------------------------------------------*/
405 static int sol_count_geom(const struct s_base *base, int g0, int gc, int mi)
409 /* The arguments g0 and gc specify a range of the index array. These */
410 /* indices refer to geoms. Determine how many of these geoms use the */
413 for (gi = 0; gi < gc; gi++)
414 if (base->gv[base->iv[g0 + gi]].mi == mi)
420 static int sol_count_body(const struct b_body *bp,
421 const struct s_base *base, int mi)
425 /* Count all lump geoms with the given material. */
427 for (li = 0; li < bp->lc; li++)
428 c += sol_count_geom(base, base->lv[bp->l0 + li].g0,
429 base->lv[bp->l0 + li].gc, mi);
431 /* Count all body geoms with the given material. */
433 c += sol_count_geom(base, bp->g0, bp->gc, mi);
438 static int sol_count_mesh(const struct d_body *bp, int p)
442 /* Count the body meshes matching the given material flags. */
444 for (mi = 0; mi < bp->mc; ++mi)
445 if (sol_test_mtrl(bp->mv[mi].mp, p))
451 /*---------------------------------------------------------------------------*/
453 static void sol_mesh_vert(struct d_vert *vp,
454 const struct s_base *base, int oi)
456 /* Gather all vertex attributes for the given offs. */
458 const struct b_texc *tq = base->tv + base->ov[oi].ti;
459 const struct b_side *sq = base->sv + base->ov[oi].si;
460 const struct b_vert *vq = base->vv + base->ov[oi].vi;
474 static void sol_mesh_geom(struct d_vert *vv, int *vn,
475 struct d_geom *gv, int *gn,
476 const struct s_base *base, int *iv, int g0, int gc, int mi)
480 /* Insert all geoms with material mi into the vertex and element data. */
482 for (gi = 0; gi < gc; gi++)
484 const struct b_geom *gq = base->gv + base->iv[g0 + gi];
488 /* Insert a d_vert into the VBO data for each referenced b_off. */
490 if (iv[gq->oi] == -1)
493 sol_mesh_vert(vv + (*vn)++, base, gq->oi);
495 if (iv[gq->oj] == -1)
498 sol_mesh_vert(vv + (*vn)++, base, gq->oj);
500 if (iv[gq->ok] == -1)
503 sol_mesh_vert(vv + (*vn)++, base, gq->ok);
506 /* Populate the EBO data using remapped b_off indices. */
508 gv[*gn].i = iv[gq->oi];
509 gv[*gn].j = iv[gq->oj];
510 gv[*gn].k = iv[gq->ok];
517 static void sol_load_mesh(struct d_mesh *mp,
518 const struct b_body *bp,
519 const struct s_draw *draw, int mi)
521 const size_t vs = sizeof (struct d_vert);
522 const size_t gs = sizeof (struct d_geom);
524 struct d_vert *vv = 0;
525 struct d_geom *gv = 0;
528 int oc = draw->base->oc;
532 const int gc = sol_count_body(bp, draw->base, mi);
534 /* Get temporary storage for vertex and element array creation. */
536 if ((vv = (struct d_vert *) calloc(oc, vs)) &&
537 (gv = (struct d_geom *) calloc(gc, gs)) &&
538 (iv = (int *) calloc(oc, sizeof (int))))
542 /* Initialize the index remapping. */
544 for (i = 0; i < oc; ++i) iv[i] = -1;
546 /* Include all matching lump geoms in the arrays. */
548 for (li = 0; li < bp->lc; li++)
549 sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv,
550 draw->base->lv[bp->l0 + li].g0,
551 draw->base->lv[bp->l0 + li].gc, mi);
553 /* Include all matching body geoms in the arrays. */
555 sol_mesh_geom(vv, &vn, gv, &gn, draw->base, iv, bp->g0, bp->gc, mi);
557 /* Initialize buffer objects for all data. */
559 glGenBuffers_(1, &mp->vbo);
560 glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
561 glBufferData_(GL_ARRAY_BUFFER, vn * vs, vv, GL_STATIC_DRAW);
562 glBindBuffer_(GL_ARRAY_BUFFER, 0);
564 glGenBuffers_(1, &mp->ebo);
565 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
566 glBufferData_(GL_ELEMENT_ARRAY_BUFFER, gn * gs, gv, GL_STATIC_DRAW);
567 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
569 mp->mp = draw->mv + mi;
578 static void sol_free_mesh(struct d_mesh *mp)
580 if (glIsBuffer_(mp->ebo))
581 glDeleteBuffers_(1, &mp->ebo);
582 if (glIsBuffer_(mp->vbo))
583 glDeleteBuffers_(1, &mp->vbo);
586 void sol_draw_mesh(const struct d_mesh *mp, struct s_rend *rend, int p)
588 /* If this mesh has material matching the given flags... */
590 if (sol_test_mtrl(mp->mp, p))
592 const size_t s = sizeof (struct d_vert);
593 const GLenum T = GL_FLOAT;
595 /* Apply the material state. */
597 sol_apply_mtrl(mp->mp, rend);
599 /* Bind the mesh data. */
601 glBindBuffer_(GL_ARRAY_BUFFER, mp->vbo);
602 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, mp->ebo);
604 glVertexPointer (3, T, s, (GLvoid *) offsetof (struct d_vert, p));
605 glNormalPointer ( T, s, (GLvoid *) offsetof (struct d_vert, n));
607 if (tex_env_stage(TEX_STAGE_SHADOW))
609 glTexCoordPointer(3, T, s, (GLvoid *) offsetof (struct d_vert, p));
611 if (tex_env_stage(TEX_STAGE_CLIP))
612 glTexCoordPointer(3, T, s, (GLvoid *) offsetof (struct d_vert, p));
614 tex_env_stage(TEX_STAGE_TEXTURE);
616 glTexCoordPointer(2, T, s, (GLvoid *) offsetof (struct d_vert, t));
620 glDrawElements(GL_TRIANGLES, mp->ebc, GL_UNSIGNED_SHORT, 0);
624 /*---------------------------------------------------------------------------*/
626 static void sol_load_body(struct d_body *bp,
627 const struct b_body *bq,
628 const struct s_draw *draw)
635 /* Determine how many materials this body uses. */
637 for (mi = 0; mi < draw->mc; ++mi)
638 if (sol_count_body(bq, draw->base, mi))
641 /* Allocate and initialize a mesh for each material. */
643 if ((bp->mv = (struct d_mesh *) calloc(bp->mc, sizeof (struct d_mesh))))
647 for (mi = 0; mi < draw->mc; ++mi)
648 if (sol_count_body(bq, draw->base, mi))
649 sol_load_mesh(bp->mv + mj++, bq, draw, mi);
652 /* Cache a mesh count for each pass. */
654 bp->pass[0] = sol_count_mesh(bp, 0);
655 bp->pass[1] = sol_count_mesh(bp, 1);
656 bp->pass[2] = sol_count_mesh(bp, 2);
657 bp->pass[3] = sol_count_mesh(bp, 3);
658 bp->pass[4] = sol_count_mesh(bp, 4);
661 static void sol_free_body(struct d_body *bp)
665 for (mi = 0; mi < bp->mc; ++mi)
666 sol_free_mesh(bp->mv + mi);
671 static void sol_draw_body(const struct d_body *bp, struct s_rend *rend, int p)
675 for (i = 0; i < bp->mc; ++i)
676 sol_draw_mesh(bp->mv + i, rend, p);
679 /*---------------------------------------------------------------------------*/
681 int sol_load_draw(struct s_draw *draw, const struct s_vary *vary, int s)
685 memset(draw, 0, sizeof (struct s_draw));
688 draw->base = vary->base;
690 /* Initialize all materials for this file. */
694 if ((draw->mv = calloc(draw->base->mc, sizeof (*draw->mv))))
696 draw->mc = draw->base->mc;
698 for (i = 0; i < draw->mc; i++)
700 sol_load_mtrl(draw->mv + i, draw->base->mv + i);
702 /* If at least one material is reflective, mark it. */
704 if (draw->base->mv[i].fl & M_REFLECTIVE)
705 draw->reflective = 1;
710 /* Initialize shadow state. */
712 draw->shadow_ui = -1;
714 /* Initialize all bodies for this file. */
718 if ((draw->bv = calloc(draw->base->bc, sizeof (*draw->bv))))
720 draw->bc = draw->base->bc;
722 for (i = 0; i < draw->bc; i++)
723 sol_load_body(draw->bv + i, draw->base->bv + i, draw);
732 void sol_free_draw(struct s_draw *draw)
738 for (i = 0; i < draw->bc; i++)
739 sol_free_body(draw->bv + i);
740 for (i = 0; i < draw->mc; i++)
741 sol_free_mtrl(draw->mv + i);
744 /*---------------------------------------------------------------------------*/
746 static void sol_draw_all(const struct s_draw *draw, struct s_rend *rend, int p)
750 /* Draw all meshes of all bodies matching the given material flags. */
752 for (bi = 0; bi < draw->bc; ++bi)
754 if (draw->bv[bi].pass[p])
758 sol_transform(draw->vary, draw->vary->bv + bi, draw->shadow_ui);
759 sol_draw_body(draw->bv + bi, rend, p);
765 void sol_draw_enable(struct s_rend *rend)
767 glEnableClientState(GL_VERTEX_ARRAY);
768 glEnableClientState(GL_NORMAL_ARRAY);
770 if (gli.max_texture_units > 2)
771 tex_env_active(&tex_env_shadow_clip);
772 else if (gli.max_texture_units > 1)
773 tex_env_active(&tex_env_shadow);
775 tex_env_active(&tex_env_default);
777 if (tex_env_stage(TEX_STAGE_SHADOW))
779 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
781 if (tex_env_stage(TEX_STAGE_CLIP))
782 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
784 tex_env_stage(TEX_STAGE_TEXTURE);
786 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
788 rend->mp = &default_draw_mtrl;
791 void sol_draw_disable(struct s_rend *rend)
793 sol_apply_mtrl(&default_draw_mtrl, rend);
795 if (tex_env_stage(TEX_STAGE_SHADOW))
797 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
799 if (tex_env_stage(TEX_STAGE_CLIP))
800 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
802 tex_env_stage(TEX_STAGE_TEXTURE);
804 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
806 tex_env_active(&tex_env_default);
808 glDisableClientState(GL_NORMAL_ARRAY);
809 glDisableClientState(GL_VERTEX_ARRAY);
812 /*---------------------------------------------------------------------------*/
814 void sol_draw(const struct s_draw *draw, struct s_rend *rend, int mask, int test)
816 /* Render all opaque geometry, decals last. */
818 sol_draw_all(draw, rend, 0);
819 sol_draw_all(draw, rend, 1);
821 /* Render all transparent geometry, decals first. */
823 if (!test) glDisable(GL_DEPTH_TEST);
824 if (!mask) glDepthMask(GL_FALSE);
826 sol_draw_all(draw, rend, 2);
827 sol_draw_all(draw, rend, 3);
829 if (!mask) glDepthMask(GL_TRUE);
830 if (!test) glEnable(GL_DEPTH_TEST);
832 /* Revert the buffer object state. */
834 glBindBuffer_(GL_ARRAY_BUFFER, 0);
835 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
838 void sol_refl(const struct s_draw *draw, struct s_rend *rend)
840 /* Render all reflective geometry. */
842 sol_draw_all(draw, rend, 4);
844 /* Revert the buffer object state. */
846 glBindBuffer_(GL_ARRAY_BUFFER, 0);
847 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
850 void sol_back(const struct s_draw *draw,
852 float n, float f, float t)
854 if (!draw || !draw->base)
857 glDisable(GL_LIGHTING);
858 glDepthMask(GL_FALSE);
860 sol_bill_enable(draw);
864 /* Consider each billboard. */
866 for (ri = 0; ri < draw->base->rc; ri++)
868 const struct b_bill *rp = draw->base->rv + ri;
870 /* Render only billboards at distances between n and f. */
872 if (n <= rp->d && rp->d < f)
874 float T = (rp->t > 0.0f) ? (fmodf(t, rp->t) - rp->t / 2) : 0;
876 float w = rp->w[0] + rp->w[1] * T + rp->w[2] * T * T;
877 float h = rp->h[0] + rp->h[1] * T + rp->h[2] * T * T;
879 /* Render only billboards facing the viewer. */
883 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * T * T;
884 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * T * T;
885 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * T * T;
889 if (ry) glRotatef(ry, 0.0f, 1.0f, 0.0f);
890 if (rx) glRotatef(rx, 1.0f, 0.0f, 0.0f);
892 glTranslatef(0.0f, 0.0f, -rp->d);
896 glRotatef(-rx - 90.0f, 1.0f, 0.0f, 0.0f);
897 glRotatef(-ry, 0.0f, 0.0f, 1.0f);
900 glRotatef(-rx, 1.0f, 0.0f, 0.0f);
902 if (rz) glRotatef(rz, 0.0f, 0.0f, 1.0f);
904 glScalef(w, h, 1.0f);
906 sol_apply_mtrl(draw->mv + rp->mi, rend);
909 glDrawArrays(GL_TRIANGLE_STRIP, 4, 4);
911 glDrawArrays(GL_TRIANGLE_STRIP, 8, 4);
920 glDepthMask(GL_TRUE);
921 glEnable(GL_LIGHTING);
924 void sol_bill(const struct s_draw *draw,
925 struct s_rend *rend, const float *M, float t)
927 sol_bill_enable(draw);
931 for (ri = 0; ri < draw->base->rc; ++ri)
933 const struct b_bill *rp = draw->base->rv + ri;
938 float w = rp->w [0] + rp->w [1] * T + rp->w [2] * S;
939 float h = rp->h [0] + rp->h [1] * T + rp->h [2] * S;
940 float rx = rp->rx[0] + rp->rx[1] * T + rp->rx[2] * S;
941 float ry = rp->ry[0] + rp->ry[1] * T + rp->ry[2] * S;
942 float rz = rp->rz[0] + rp->rz[1] * T + rp->rz[2] * S;
944 sol_apply_mtrl(draw->mv + rp->mi, rend);
948 glTranslatef(rp->p[0], rp->p[1], rp->p[2]);
950 if (M && ((rp->fl & B_NOFACE) == 0)) glMultMatrixf(M);
952 if (fabsf(rx) > 0.0f) glRotatef(rx, 1.0f, 0.0f, 0.0f);
953 if (fabsf(ry) > 0.0f) glRotatef(ry, 0.0f, 1.0f, 0.0f);
954 if (fabsf(rz) > 0.0f) glRotatef(rz, 0.0f, 0.0f, 1.0f);
956 sol_draw_bill(w, h, GL_FALSE);
964 void sol_fade(const struct s_draw *draw, float k)
968 glMatrixMode(GL_PROJECTION);
971 glMatrixMode(GL_MODELVIEW);
975 glEnable(GL_COLOR_MATERIAL);
976 glDisable(GL_LIGHTING);
977 glDisable(GL_DEPTH_TEST);
978 glDisable(GL_TEXTURE_2D);
980 glColor4f(0.0f, 0.0f, 0.0f, k);
982 sol_bill_enable(draw);
983 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
986 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
988 glEnable(GL_TEXTURE_2D);
989 glEnable(GL_DEPTH_TEST);
990 glEnable(GL_LIGHTING);
991 glDisable(GL_COLOR_MATERIAL);
993 glMatrixMode(GL_PROJECTION);
995 glMatrixMode(GL_MODELVIEW);
1000 /*---------------------------------------------------------------------------*/
1002 int sol_load_full(struct s_full *full, const char *filename, int s)
1004 if (sol_load_base(&full->base, filename))
1006 sol_load_vary(&full->vary, &full->base);
1007 sol_load_draw(&full->draw, &full->vary, s);
1015 void sol_free_full(struct s_full *full)
1017 sol_free_draw(&full->draw);
1018 sol_free_vary(&full->vary);
1019 sol_free_base(&full->base);
1022 /*---------------------------------------------------------------------------*/