1 /*
2  * score_record.cxx
3  * Daniel Nelson - 12/8/1
4  *
5  * Copyright (C) 2000  Daniel Nelson
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * Daniel Nelson - aluminumangel.org
22  * 174 W. 18th Ave.
23  * Columbus, OH  43210
24  */
25 
26 #include <GL/glut.h>
27 #include <cmath>
28 
29 #include "sstream.h"
30 #include "glext.h"
31 
32 using namespace std;
33 
34 #include "Game.h"
35 #include "Displayer.h"
36 #include "MetaState.h"
37 #include "String.h"
38 #include "Score.h"
39 
40 GLuint Displayer::score_to_beat_texture;
41 GLuint Displayer::record_textures[DC_SCORE_REC_NUMBER_DRAW];
42 GLubyte **Displayer::record_texture_data;
43 GLubyte *Displayer::player_rank_texture_data;
44 
copyRecordSubTexture(GLubyte * texture,GLubyte * subtexture,int subtex_width,int s_location,int copy_width)45 void Displayer::copyRecordSubTexture ( GLubyte *texture, GLubyte *subtexture,
46  int subtex_width, int s_location, int copy_width )
47 {
48   for (int t = DC_LETTER_TEX_LENGTH; t--; )
49     for (int s = copy_width; s--; ) {
50       int ds = s_location + s;
51 
52       texture[(t * DC_SCORE_REC_TEX_LENGTH_S + ds) * 4 + 0]
53        = subtexture[(t * subtex_width + s) * 4 + 0];
54       texture[(t * DC_SCORE_REC_TEX_LENGTH_S + ds) * 4 + 1]
55        = subtexture[(t * subtex_width + s) * 4 + 1];
56       texture[(t * DC_SCORE_REC_TEX_LENGTH_S + ds) * 4 + 2]
57        = subtexture[(t * subtex_width + s) * 4 + 2];
58       texture[(t * DC_SCORE_REC_TEX_LENGTH_S + ds) * 4 + 3]
59        = subtexture[(t * subtex_width + s) * 4 + 3];
60     }
61 }
62 
rerankScoreRecord()63 void Displayer::rerankScoreRecord (   )
64 {
65   GLubyte *subtexture
66    = new GLubyte[DC_LETTER_TEX_LENGTH * DC_SCORE_REC_RANK_STRING_TEX_WIDTH * 4];
67 
68   for (int n = Score::player_rank; n--; ) {
69     ostringstream rank_string;
70     rank_string << (GC_SCORE_REC_LENGTH - n) << ends;
71 
72     for (int i = DC_LETTER_TEX_LENGTH * DC_SCORE_REC_RANK_STRING_TEX_WIDTH * 4;
73      i--; )
74       subtexture[i] = 0;
75 
76     String::fillStringTexture(rank_string.str().data(), subtexture,
77      DC_SCORE_REC_RANK_STRING_TEX_WIDTH, true);
78     copyRecordSubTexture(record_texture_data[n], subtexture,
79      DC_SCORE_REC_RANK_STRING_TEX_WIDTH, DC_SCORE_REC_RANK_TEX_MARGIN,
80      DC_SCORE_REC_RANK_STRING_TEX_WIDTH);
81   }
82 
83   if (subtexture != null) {
84     delete [] subtexture;
85     subtexture = null;
86   }
87 }
88 
generateScoreRankTexture(int rank,int score,const char * name,GLubyte * texture)89 void Displayer::generateScoreRankTexture ( int rank, int score,
90  const char *name, GLubyte *texture )
91 {
92   ostringstream score_string;
93   score_string << score << ends;
94 
95   ostringstream rank_string;
96   rank_string << (GC_SCORE_REC_LENGTH - rank) << ends;
97 
98   int score_width
99    = String::stringWidth(score_string.str().data(), DC_SCORE_REC_TEX_LENGTH_S -
100    2 * DC_SCORE_REC_RANK_TEX_MARGIN);
101 
102   int max_name_width = (DC_SCORE_REC_TEX_LENGTH_S
103    - 2 * DC_SCORE_REC_RANK_TEX_MARGIN - DC_SCORE_REC_RANK_MIN_SPACE
104    - DC_SCORE_REC_RANK_STRING_TEX_WIDTH) - score_width;
105   int name_width = String::stringWidth(name, max_name_width);
106 
107   int subtex_width = name_width > score_width ? name_width : score_width;
108   if (DC_SCORE_REC_RANK_STRING_TEX_WIDTH > subtex_width)
109     subtex_width = DC_SCORE_REC_RANK_STRING_TEX_WIDTH;
110   GLubyte *subtexture
111    = new GLubyte[DC_LETTER_TEX_LENGTH * subtex_width * 4];
112 
113   for (int i = DC_LETTER_TEX_LENGTH * subtex_width * 4; i--; )
114     subtexture[i] = 0;
115   String::fillStringTexture(rank_string.str().data(), subtexture,
116    DC_SCORE_REC_RANK_STRING_TEX_WIDTH, true, subtex_width);
117   copyRecordSubTexture(texture, subtexture, subtex_width ,
118    DC_SCORE_REC_RANK_TEX_MARGIN, DC_SCORE_REC_RANK_STRING_TEX_WIDTH);
119 
120   for (int i = DC_LETTER_TEX_LENGTH * subtex_width * 4; i--; )
121     subtexture[i] = 0;
122   String::fillStringTexture(name, subtexture, name_width, true, subtex_width);
123   copyRecordSubTexture(texture, subtexture, subtex_width,
124    DC_SCORE_REC_RANK_STRING_TEX_WIDTH + DC_SCORE_REC_RANK_TEX_MARGIN,
125    name_width);
126 
127   for (int i = DC_LETTER_TEX_LENGTH * subtex_width * 4; i--; )
128     subtexture[i] = 0;
129   String::fillStringTexture(score_string.str().data(), subtexture, score_width, true,
130    subtex_width);
131   copyRecordSubTexture(texture, subtexture, subtex_width,
132    (DC_SCORE_REC_TEX_LENGTH_S - DC_SCORE_REC_RANK_TEX_MARGIN)
133    - score_width, score_width);
134 
135   if (subtexture != null) {
136     delete [] subtexture;
137     subtexture = null;
138   }
139 }
140 
generateScoreRecord()141 void Displayer::generateScoreRecord (   )
142 {
143   if (!(MetaState::mode & CM_SOLO)) return;
144 
145   // generate score to beat message
146 
147   glGenTextures(1, &score_to_beat_texture);
148 
149   glBindTexture(GL_TEXTURE_2D, score_to_beat_texture);
150 
151   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
152   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
153   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
154   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
155 
156   GLubyte texture[DC_SCORE_TO_BEAT_TEX_LENGTH_T]
157    [DC_SCORE_TO_BEAT_TEX_LENGTH_S][3];
158   for (int t = DC_SCORE_TO_BEAT_TEX_LENGTH_T; t--; )
159     for (int s = DC_SCORE_TO_BEAT_TEX_LENGTH_S; s--; )
160       texture[t][s][0] = texture[t][s][1] = texture[t][s][2] = 0;
161 
162   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, DC_SCORE_TO_BEAT_TEX_LENGTH_S,
163    DC_SCORE_TO_BEAT_TEX_LENGTH_T, GL_FALSE, GL_RGB, GL_UNSIGNED_BYTE,
164    texture);
165 
166   int width = String::stringWidth(DC_SCORE_TO_BEAT_MESSAGE,
167    DC_SCORE_TO_BEAT_TEX_LENGTH_S);
168   GLubyte *subtexture = new GLubyte[DC_LETTER_TEX_LENGTH * width * 4];
169   String::fillStringTexture(DC_SCORE_TO_BEAT_MESSAGE, subtexture, width);
170   glTexSubImage2D(GL_TEXTURE_2D, 0, (DC_SCORE_TO_BEAT_TEX_LENGTH_S - width)
171    / 2, (30 * DC_SCORE_TO_BEAT_TEX_LENGTH_T / 100 - DC_LETTER_TEX_LENGTH) / 2,
172    width, DC_LETTER_TEX_LENGTH, GL_RGBA, GL_UNSIGNED_BYTE, subtexture);
173   if (subtexture != null) {
174     delete [] subtexture;
175     subtexture = null;
176   }
177 
178   width = String::stringWidth(Score::record[GC_SCORE_REC_LENGTH - 1].name,
179    DC_SCORE_TO_BEAT_TEX_LENGTH_S);
180   subtexture = new GLubyte[DC_LETTER_TEX_LENGTH * width * 4];
181   String::fillStringTexture(Score::record[GC_SCORE_REC_LENGTH - 1].name,
182    subtexture, width);
183   glTexSubImage2D(GL_TEXTURE_2D, 0, (DC_SCORE_TO_BEAT_TEX_LENGTH_S - width)
184    / 2, (117 * DC_SCORE_TO_BEAT_TEX_LENGTH_T / 100 - DC_LETTER_TEX_LENGTH) / 2,
185    width, DC_LETTER_TEX_LENGTH, GL_RGBA, GL_UNSIGNED_BYTE, subtexture);
186   if (subtexture != null) {
187     delete [] subtexture;
188     subtexture = null;
189   }
190 
191   ostringstream score;
192   score << Score::record[GC_SCORE_REC_LENGTH - 1].score << ends;
193 
194   width = String::stringWidth(score.str().data(), DC_SCORE_TO_BEAT_TEX_LENGTH_S);
195   subtexture = new GLubyte[DC_LETTER_TEX_LENGTH * width * 4];
196   String::fillStringTexture(score.str().data(), subtexture, width);
197   glTexSubImage2D(GL_TEXTURE_2D, 0, (DC_SCORE_TO_BEAT_TEX_LENGTH_S - width)
198    / 2, (170 * DC_SCORE_TO_BEAT_TEX_LENGTH_T / 100 - DC_LETTER_TEX_LENGTH) / 2,
199    width, DC_LETTER_TEX_LENGTH, GL_RGBA, GL_UNSIGNED_BYTE, subtexture);
200   if (subtexture != null) {
201     delete [] subtexture;
202     subtexture = null;
203   }
204 
205   // generate rank textures
206 
207   record_texture_data = new GLubyte *[GC_SCORE_REC_LENGTH - 1];
208 
209   for (int n = GC_SCORE_REC_LENGTH - 1; n--; ) {
210     record_texture_data[n]
211      = new GLubyte[DC_LETTER_TEX_LENGTH * DC_SCORE_REC_TEX_LENGTH_S * 4];
212     for (int i = DC_LETTER_TEX_LENGTH * DC_SCORE_REC_TEX_LENGTH_S * 4;
213      i--; )
214       record_texture_data[n][i] = 0;
215 
216     generateScoreRankTexture(n + 1, Score::record[n + 1].score,
217      Score::record[n + 1].name, record_texture_data[n]);
218   }
219 
220   // ready space for the player's rank texture
221 
222   player_rank_texture_data
223    = new GLubyte[DC_LETTER_TEX_LENGTH * DC_SCORE_REC_TEX_LENGTH_S * 4];
224   for (int i = DC_LETTER_TEX_LENGTH * DC_SCORE_REC_TEX_LENGTH_S * 4; i--; )
225     player_rank_texture_data[i] = 0;
226 }
227