1 /* switch.cc
2    A switch which can be triggered by user to accomplish something
3 
4    Copyright (C) 2000  Mathias Broxvall
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 #include "switch.h"
22 
23 #include "game.h"
24 #include "guile.h"
25 #include "map.h"
26 #include "player.h"
27 #include "sound.h"
28 
CSwitch(Game & g,Real x,Real y,SCM on,SCM off)29 CSwitch::CSwitch(Game &g, Real x, Real y, SCM on, SCM off)
30     : Animated(g, Role_OtherAnimated, 1) {
31   position[0] = x;
32   position[1] = y;
33   position[2] = game.map->getHeight(x, y);
34   primaryColor = Color(0.8, 0.8, 0.8, 1.0);
35   secondaryColor = Color(0., 0., 0., 1.);
36   is_touched = false;
37   this->on = on;
38   this->off = off;
39   if (on) scm_gc_protect_object(on);
40   if (off) scm_gc_protect_object(off);
41 }
~CSwitch()42 CSwitch::~CSwitch() { CSwitch::releaseCallbacks(); }
releaseCallbacks()43 void CSwitch::releaseCallbacks() {
44   if (on) scm_gc_unprotect_object(on);
45   if (off) scm_gc_unprotect_object(off);
46   on = NULL;
47   off = NULL;
48 }
49 
generateBuffers(const GLuint * idxbufs,const GLuint * databufs,const GLuint * vaolist,bool mustUpdate) const50 void CSwitch::generateBuffers(const GLuint *idxbufs, const GLuint *databufs,
51                               const GLuint *vaolist, bool mustUpdate) const {
52   const int nfacets = 16;
53   GLfloat lever_length = 0.3f;
54   GLfloat lever_end = 0.03f;
55   GLfloat body_wid = 0.15f;
56   GLfloat body_rad = 0.15f;
57 
58   GLfloat data[4 * nfacets + 7][8];
59   ushort idxs[4 * nfacets + 6][3];
60 
61   Color side_color = is_on ? primaryColor : secondaryColor;
62 
63   GLfloat flat[3] = {0.f, 0.f, 0.f};
64   char *pos = (char *)data;
65   // Top curve
66   for (int i = 0; i < nfacets; i++) {
67     GLfloat angle = i * M_PI / (nfacets - 1);
68     GLfloat norm[3] = {std::cos(angle), 0., std::sin(angle)};
69     pos +=
70         packObjectVertex(pos, position[0] + body_wid, position[1] + body_rad * std::cos(angle),
71                          position[2] + body_rad * std::sin(angle), 0., 0., primaryColor, norm);
72     pos +=
73         packObjectVertex(pos, position[0] - body_wid, position[1] + body_rad * std::cos(angle),
74                          position[2] + body_rad * std::sin(angle), 0., 0., primaryColor, norm);
75   }
76   // Side panels
77   for (int i = 0; i < nfacets; i++) {
78     GLfloat angle = i * M_PI / (nfacets - 1);
79     pos +=
80         packObjectVertex(pos, position[0] + body_wid, position[1] + body_rad * std::cos(angle),
81                          position[2] + body_rad * std::sin(angle), 0., 0., side_color, flat);
82   }
83   for (int i = 0; i < nfacets; i++) {
84     GLfloat angle = i * M_PI / (nfacets - 1);
85     pos +=
86         packObjectVertex(pos, position[0] - body_wid, position[1] + body_rad * std::cos(angle),
87                          position[2] + body_rad * std::sin(angle), 0., 0., side_color, flat);
88   }
89   pos += packObjectVertex(pos, position[0] + body_wid, position[1], position[2], 0., 0.,
90                           side_color, flat);
91   pos += packObjectVertex(pos, position[0] - body_wid, position[1], position[2], 0., 0.,
92                           side_color, flat);
93 
94   for (int i = 0; i < nfacets; i++) {
95     int j = (i + 1) % nfacets;
96     idxs[2 * i][0] = 2 * i;
97     idxs[2 * i][1] = 2 * i + 1;
98     idxs[2 * i][2] = 2 * j + 1;
99     idxs[2 * i + 1][0] = 2 * j;
100     idxs[2 * i + 1][1] = 2 * i;
101     idxs[2 * i + 1][2] = 2 * j + 1;
102   }
103 
104   for (int i = 0; i < nfacets; i++) {
105     idxs[2 * nfacets + i][0] = 2 * nfacets + i;
106     idxs[2 * nfacets + i][1] = 2 * nfacets + (i + 1) % nfacets;
107     idxs[2 * nfacets + i][2] = 4 * nfacets;
108   }
109 
110   for (int i = 0; i < nfacets; i++) {
111     idxs[3 * nfacets + i][0] = 3 * nfacets + (i + 1) % nfacets;
112     idxs[3 * nfacets + i][1] = 3 * nfacets + i;
113     idxs[3 * nfacets + i][2] = 4 * nfacets + 1;
114   }
115 
116   // Draw Lever
117   int sgn = is_on ? 1 : -1;
118   pos +=
119       packObjectVertex(pos, position[0], position[1], position[2], 0., 0., primaryColor, flat);
120   pos += packObjectVertex(
121       pos, position[0] + lever_end * 1.4f, position[1] + sgn * (lever_length - lever_end),
122       position[2] + (lever_length + lever_end), 0., 0., primaryColor, flat);
123   pos += packObjectVertex(
124       pos, position[0] - lever_end * 1.4f, position[1] + sgn * (lever_length - lever_end),
125       position[2] + (lever_length + lever_end), 0., 0., primaryColor, flat);
126   pos += packObjectVertex(
127       pos, position[0] - lever_end * 1.4f, position[1] + sgn * (lever_length + lever_end),
128       position[2] + (lever_length - lever_end), 0., 0., primaryColor, flat);
129   pos += packObjectVertex(
130       pos, position[0] + lever_end * 1.4f, position[1] + sgn * (lever_length + lever_end),
131       position[2] + (lever_length - lever_end), 0., 0., primaryColor, flat);
132   int vstart = 4 * nfacets + 2;
133   int istart = 4 * nfacets;
134   ushort local[6][3] = {{0, 1, 2}, {0, 2, 3}, {0, 3, 4}, {0, 4, 1}, {1, 3, 2}, {1, 4, 3}};
135   for (int i = 0; i < 6; i++) {
136     idxs[istart + i][0] = local[i][0] + vstart;
137     idxs[istart + i][1] = local[i][1] + vstart;
138     idxs[istart + i][2] = local[i][2] + vstart;
139   }
140 
141   glBindVertexArray(vaolist[0]);
142   glBindBuffer(GL_ARRAY_BUFFER, databufs[0]);
143   glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
144   glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxbufs[0]);
145   glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(idxs), idxs, GL_STATIC_DRAW);
146   configureObjectAttributes();
147 }
148 
drawBuffers1(const GLuint * vaolist) const149 void CSwitch::drawBuffers1(const GLuint *vaolist) const {
150   glDisable(GL_BLEND);
151   glEnable(GL_CULL_FACE);
152 
153   const int nfacets = 16;
154   setActiveProgramAndUniforms(Shader_Object);
155   setObjectUniforms(specularColor, 0.12, Lighting_Regular);
156   glBindTexture(GL_TEXTURE_2D, textureBlank);
157 
158   glBindVertexArray(vaolist[0]);
159   glDrawElements(GL_TRIANGLES, (4 * nfacets + 6) * 3, GL_UNSIGNED_SHORT, (void *)0);
160 }
161 
drawBuffers2(const GLuint *) const162 void CSwitch::drawBuffers2(const GLuint * /*vaolist*/) const {}
163 
tick(Real t)164 void CSwitch::tick(Real t) {
165   Animated::tick(t);
166 
167   Coord3d v = position - game.player1->position;
168   Player *player = game.player1;
169 
170   double dist = length(v);
171   if (dist < player->radius + 0.3) {
172     if (!is_touched) {
173       if (is_on) {
174         is_on = false;
175         game.queueCall(off);
176         drawChanged = true;
177       } else {
178         is_on = true;
179         game.queueCall(on);
180         drawChanged = true;
181       }
182       playEffect(SFX_SWITCH);
183     }
184     is_touched = true;
185   } else
186     is_touched = false;
187 }
188