FreeWRL/FreeX3D  3.0.0
statusbarHud.c
1 /*
2 
3 */
4 
5 /****************************************************************************
6  This file is part of the FreeWRL/FreeX3D Distribution.
7 
8  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
9 
10  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
11  it under the terms of the GNU Lesser Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
22 ****************************************************************************/
23 
24 
25 #include <config.h>
26 #include <system.h>
27 #include <internal.h>
28 
29 #include <libFreeWRL.h>
30 #include <scenegraph/Viewer.h>
31 #include <opengl/OpenGL_Utils.h>
32 #include <opengl/Textures.h>
33 #include <opengl/LoadTextures.h>
34 #include "scenegraph/RenderFuncs.h"
35 #include "common.h"
36 
37 /* the following are bitmap icons for the toolbar,
38 generated by writing out C structs from thresholded png icons. Setting 2
39 parameters in this statusbarHud.c causes it to read in your 32x32xRGBA .pngs.
40 and write out C struct versions:
41 buttonType = 0; // 0 = rgba .png 1= .c bitmap (see above)
42 savePng2dotc = 1; // if you read png and want to save to a bitmap .c struct, put 1
43 */
44 #if defined(STATUSBAR_HUD) || defined(STATUSBAR_STD)
45 //#define KIOSK 1
46 //#define TOUCH 1
47 
48 static GLfloat colorButtonHighlight[4] = {.5f,.5f,.5f,.5f};
49 static GLfloat colorButtonCTRL[4] = {.6f,.6f,.6f,.5f};
50 
51 static GLfloat colorClear[4] = {0.24f,0.27f,0.34f,1.0f}; //steely grey
52 #define LIME {.8f,1.0f,0.0f,1.0f}
53 
54 
55 #define HIGHLIGHT LIME
56 static GLfloat colorButtonIcon[4] = HIGHLIGHT;
57 static GLfloat colorStatusbarText[4] = HIGHLIGHT;
58 static GLfloat colorMessageText[4] = HIGHLIGHT; //over VRML window, which is often black
59 
60 static int ui_color_changed = -1;
61 
62 void update_ui_colors(){
63  int ic;
64  ic = fwl_get_ui_color_changed();
65  if( ic != ui_color_changed){
66  fwl_get_ui_color("panel",colorClear);
67  fwl_get_ui_color("menuIcon",colorButtonIcon);
68  fwl_get_ui_color("statusText",colorStatusbarText);
69  fwl_get_ui_color("messageText",colorMessageText);
70  ui_color_changed = ic;
71  }
72 }
73 static GLbyte vShaderStr[] =
74  "attribute vec4 a_position; \n"
75  "attribute vec2 a_texCoord; \n"
76  "varying vec2 v_texCoord; \n"
77  "void main() \n"
78  "{ \n"
79  " gl_Position = a_position; \n"
80  " v_texCoord = a_texCoord; \n"
81  "} \n";
82 
83 // using Luminance-alpha images, you need to set a color in order for it to show up different than white
84 static GLbyte fShaderStr[] =
85 #ifdef GL_ES_VERSION_2_0
86  "precision mediump float; \n"
87 #endif //GL_ES_VERSION_2_0
88  "varying vec2 v_texCoord; \n"
89  "uniform sampler2D Texture0; \n"
90  "uniform vec4 Color4f; \n"
91  "void main() \n"
92  "{ \n"
93  " gl_FragColor = Color4f * texture2D( Texture0, v_texCoord ); \n"
94  "} \n";
95 // " gl_FragColor = vec4(1.0,1.0,1.0,1.0); \n"
96 
97 GLuint esLoadShader ( GLenum type, const char *shaderSrc )
98 {
99  GLuint shader;
100  GLint compiled;
101  // Create the shader object
102  shader = glCreateShader ( type );
103 
104  if ( shader == 0 )
105  return 0;
106 
107  // Load the shader source
108  glShaderSource ( shader, 1, &shaderSrc, NULL );
109 
110  // Compile the shader
111  glCompileShader ( shader );
112 
113  // Check the compile status
114  glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );
115 
116  if ( !compiled )
117  {
118  GLint infoLen = 0;
119 
120  glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
121 
122  if ( infoLen > 1 )
123  {
124  char* infoLog = MALLOC(void *, sizeof(char) * infoLen );
125 
126  glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
127  printf ( "Error compiling shader:\n%s\n", infoLog );
128 
129  FREE( infoLog );
130  }
131 
132  glDeleteShader ( shader );
133  return 0;
134  }
135 
136  return shader;
137 
138 }
139 
140 GLuint esLoadProgram ( const char *vertShaderSrc, const char *fragShaderSrc )
141 {
142  GLuint vertexShader;
143  GLuint fragmentShader;
144  GLuint programObject;
145  GLint linked;
146 
147  // Load the vertex/fragment shaders
148  vertexShader = esLoadShader ( GL_VERTEX_SHADER, vertShaderSrc );
149  if ( vertexShader == 0 )
150  return 0;
151 
152  fragmentShader = esLoadShader ( GL_FRAGMENT_SHADER, fragShaderSrc );
153  if ( fragmentShader == 0 )
154  {
155  glDeleteShader( vertexShader );
156  return 0;
157  }
158 
159  // Create the program object
160  programObject = glCreateProgram ( );
161 
162  if ( programObject == 0 )
163  return 0;
164 
165  glAttachShader ( programObject, vertexShader );
166  glAttachShader ( programObject, fragmentShader );
167 
168  // Link the program
169  glLinkProgram ( programObject );
170 
171  // Check the link status
172  glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
173 
174  if ( !linked )
175  {
176  GLint infoLen = 0;
177 
178  glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );
179 
180  if ( infoLen > 1 )
181  {
182  char* infoLog = MALLOC(void *, sizeof(char) * infoLen );
183 
184  glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
185  printf ( "Error linking program:\n%s\n", infoLog );
186 
187  FREE( infoLog );
188  }
189 
190  glDeleteProgram ( programObject );
191  return 0;
192  }
193 
194  // Free up no longer needed shader resources
195  glDeleteShader ( vertexShader );
196  glDeleteShader ( fragmentShader );
197 
198  return programObject;
199 }
200 
201 
202 //#include "hudIcons_hexbit.h" //2010 bit per pixel
203 #include "hudIcons_octalpha.h" //2012 byte per pixel (nicer)
204 
205 /* <<< bitmap menu button icons */
206 
207 /*fw fixed size bitmap fonts >>>
208 first 1: char # 0-127 (ie '!'=33, 'a'=97)
209 next 6: FW_GL_BITMAP(width,height,xbo,ybo,xadv,yadv,
210 last 7+: FW_GL_BITMAP(,,,,,,const GLubyte *bitmap);
211 Non-ASCII chars:
212 [ ] dec 28 oct 034
213 [*] dec 29 oct 035
214 <* dec 30 oct 036
215 *> dec 31 oct 037
216 */
217 
218 
219 GLubyte fwLetters8x15[][22] = {
220 {28,8,15,0,0,8,0,0x0,0x0,0x0,0xfe,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0xfe,0x0,0x0,0x0},
221 {29,8,15,0,0,8,0,0x0,0x0,0x0,0xfe,0x82,0x92,0xba,0xca,0x8a,0x86,0x86,0xfe,0x4,0x2,0x2},
222 {30,8,15,0,0,8,0,0x0,0x0,0x0,0x4,0xc,0x1c,0x3c,0x7c,0xfc,0x7c,0x3c,0x1c,0xc,0x4,0x0},
223 {31,8,15,0,0,8,0,0x0,0x0,0x0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x0},
224 {32,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
225 {33,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x20,0x20,0x0,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0},
226 {35,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x24,0x24,0x24,0xfe,0x24,0x24,0x24,0xfe,0x24,0x0,0x0},
227 {36,8,15,0,0,8,0,0x0,0x0,0x0,0x10,0x38,0x54,0x94,0x14,0x18,0x10,0x70,0x90,0x94,0x78,0x10},
228 {37,8,15,0,0,8,0,0x0,0x0,0x0,0x80,0x44,0x4a,0x2a,0x34,0x10,0x10,0x48,0xa8,0xa4,0x44,0x0},
229 {38,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x74,0x88,0x94,0xa0,0x40,0x40,0xa0,0x90,0x50,0x20,0x0},
230 {39,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x40,0x20,0x20,0x30,0x30,0x0,0x0},
231 {40,8,15,0,0,8,0,0x0,0x0,0x0,0x8,0x10,0x20,0x20,0x40,0x40,0x40,0x40,0x20,0x20,0x10,0x8},
232 {41,8,15,0,0,8,0,0x0,0x0,0x40,0x20,0x10,0x10,0x8,0x8,0x8,0x8,0x8,0x10,0x10,0x20,0x40},
233 {42,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x54,0x38,0x38,0x54,0x10,0x0,0x0,0x0},
234 {43,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x10,0x10,0x10,0xfe,0x10,0x10,0x10,0x10,0x0,0x0,0x0},
235 {44,8,15,0,0,8,0,0x0,0x0,0x20,0x10,0x18,0x18,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
236 {45,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0,0x0,0x0,0x0,0x0,0x0},
237 {46,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x30,0x30,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
238 {47,8,15,0,0,8,0,0x0,0x0,0x40,0x40,0x20,0x20,0x10,0x10,0x8,0x8,0x4,0x4,0x2,0x2,0x0},
239 {48,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x84,0xc4,0xa4,0x9c,0x84,0x84,0x84,0x78,0x0},
240 {49,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x30,0x10,0x0},
241 {50,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0xfe,0x80,0x40,0x20,0x10,0x8,0x6,0x82,0x82,0x7c,0x0},
242 {51,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x4,0x4,0x4,0x18,0x4,0x4,0x84,0x78,0x0},
243 {52,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x8,0x8,0x8,0x8,0xfc,0x88,0x48,0x28,0x18,0x8,0x0},
244 {53,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x4,0x4,0x84,0xf8,0x80,0x80,0x80,0xfc,0x0},
245 {54,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x7c,0x84,0x82,0xc2,0xa4,0x98,0x80,0x84,0x44,0x38,0x0},
246 {55,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x20,0x20,0x10,0x10,0x10,0x10,0x8,0x4,0x4,0xfc,0x0},
247 {56,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x84,0x84,0x78,0x0},
248 {57,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x4,0x34,0x4c,0x84,0x84,0x84,0x44,0x38,0x0},
249 {58,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x30,0x30,0x0,0x0,0x0,0x30,0x30,0x0,0x0,0x0,0x0},
250 {59,8,15,0,0,8,0,0x0,0x40,0x20,0x10,0x30,0x30,0x0,0x0,0x30,0x30,0x0,0x0,0x0,0x0,0x0},
251 {60,8,15,0,0,8,0,0x0,0x0,0x0,0x4,0x8,0x10,0x20,0x40,0x80,0x40,0x20,0x10,0x8,0x4,0x0},
252 {61,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xf8,0x0,0x0,0xf8,0x0,0x0,0x0,0x0},
253 {62,8,15,0,0,8,0,0x0,0x0,0x80,0x40,0x20,0x10,0x8,0x4,0x4,0x8,0x10,0x20,0x40,0x80,0x0},
254 {63,8,15,0,0,8,0,0x0,0x0,0x0,0x10,0x10,0x0,0x0,0x10,0x18,0x4,0x2,0x82,0x44,0x38,0x0},
255 {64,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x38,0x44,0x80,0x98,0xa4,0xa4,0x9c,0x84,0x48,0x30,0x0},
256 {65,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x84,0x84,0xfc,0x84,0x48,0x48,0x48,0x30,0x30,0x0,0x0},
257 {66,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0xf8,0x84,0x84,0x84,0x84,0xf8,0x84,0x84,0x84,0xf8,0x0},
258 {67,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x80,0x80,0x80,0x80,0x80,0x80,0x84,0x78,0x0},
259 {68,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0xf0,0x88,0x84,0x84,0x84,0x84,0x84,0x88,0xf0,0x0,0x0},
260 {69,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0xfc,0x80,0x80,0x80,0x80,0xf0,0x80,0x80,0xfc,0x0,0x0},
261 {70,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x80,0x80,0x80,0x80,0x80,0xf0,0x80,0x80,0x80,0xfe,0x0},
262 {71,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x7a,0x86,0x82,0x82,0x82,0x8c,0x80,0x80,0x44,0x38,0x0},
263 {72,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x84,0x84,0x84,0x84,0xfc,0x84,0x84,0x84,0x84,0x84,0x0},
264 {73,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x38,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x0},
265 {74,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x70,0x88,0x88,0x8,0x8,0x8,0x8,0x8,0x8,0x18,0x0},
266 {75,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x86,0x88,0x90,0xa0,0xc0,0xa0,0x90,0x88,0x84,0x80,0x0},
267 {76,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0xfc,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x0},
268 {77,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x82,0x82,0x92,0x92,0xaa,0xaa,0xc6,0xc6,0x82,0x82,0x0},
269 {78,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x84,0x8c,0x8c,0x94,0x94,0xa4,0xa4,0xc4,0xc4,0x84,0x0},
270 {79,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x84,0x78,0x0},
271 {80,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x80,0x80,0x80,0x80,0xb8,0xc4,0x84,0x84,0x84,0xf8,0x0},
272 {81,8,15,0,0,8,0,0x0,0x4,0x18,0x20,0x7c,0xa2,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x7c,0x0},
273 {82,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x82,0x84,0x8c,0x88,0xfc,0x82,0x82,0x82,0x82,0xfc,0x0},
274 {83,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x4,0x4,0x18,0x60,0x80,0x80,0x84,0x7c,0x0},
275 {84,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0xfe,0x0},
276 {85,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x7c,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x0},
277 {86,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x10,0x10,0x28,0x44,0x44,0x44,0x44,0x82,0x82,0x82,0x0},
278 {87,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x44,0x44,0xaa,0xaa,0x92,0x92,0x92,0x82,0x82,0x0,0x0},
279 {88,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x84,0x84,0x48,0x48,0x30,0x30,0x4c,0x44,0x84,0x84,0x0},
280 {89,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x10,0x10,0x10,0x10,0x10,0x28,0x28,0x44,0x82,0x82,0x0},
281 {90,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0xfe,0x80,0x40,0x40,0x20,0x10,0x8,0x4,0x4,0xfe,0x0},
282 {91,8,15,0,0,8,0,0x0,0x0,0x0,0xe0,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xe0,0x0},
283 {92,8,15,0,0,8,0,0x0,0x0,0x4,0x4,0x8,0x8,0x10,0x10,0x20,0x20,0x40,0x40,0x80,0x80,0x0},
284 {93,8,15,0,0,8,0,0x0,0x0,0x0,0x38,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x38,0x0},
285 {94,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x44,0x28,0x10,0x0},
286 {95,8,15,0,0,8,0,0x0,0xfe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0},
287 {96,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x20,0x40,0xc0,0xc0,0x0},
288 {97,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x74,0x88,0x98,0x68,0x8,0x88,0x70,0x0,0x0,0x0,0x0},
289 {98,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0xb8,0xc4,0x84,0xc4,0xc4,0xb8,0x80,0x80,0x80,0x0,0x0},
290 {99,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x80,0x80,0x80,0x84,0x78,0x0,0x0,0x0,0x0},
291 {100,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x74,0x8c,0x8c,0x84,0x8c,0x74,0x4,0x4,0x4,0x0,0x0},
292 {101,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x80,0xbc,0xc4,0x84,0x78,0x0,0x0,0x0,0x0},
293 {102,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x20,0x20,0x20,0x20,0x78,0x20,0x20,0x24,0x3c,0x0,0x0},
294 {103,8,15,0,0,8,0,0x18,0x64,0x4,0x4,0x34,0x4c,0x84,0x84,0x84,0x8c,0x74,0x0,0x0,0x0,0x0},
295 {104,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x84,0x84,0x84,0x84,0x84,0xc4,0xb8,0x80,0x80,0x80,0x0},
296 {105,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x10,0x10,0x10,0x10,0x10,0x10,0x30,0x0,0x10,0x0,0x0},
297 {106,8,15,0,0,8,0,0x40,0xa0,0x90,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x30,0x0,0x10,0x0},
298 {107,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x84,0x98,0xb0,0xc0,0xa0,0x90,0x88,0x80,0x80,0x0,0x0},
299 {108,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x18,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x30,0x0,0x0},
300 {109,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x54,0x54,0x54,0x54,0x54,0x54,0xa8,0x0,0x0,0x0,0x0},
301 {110,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x84,0x84,0x84,0x84,0x84,0xc8,0xb8,0x0,0x0,0x0,0x0},
302 {111,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x78,0x84,0x84,0x84,0x84,0x84,0x78,0x0,0x0,0x0,0x0},
303 {112,8,15,0,0,8,0,0x80,0x80,0x80,0x80,0xb8,0xa4,0xc4,0x84,0x84,0xc4,0xa4,0x18,0x0,0x0,0x0},
304 {113,8,15,0,0,8,0,0x2,0x4,0x4,0x4,0x74,0x8c,0x8c,0x84,0x84,0x8c,0x74,0x0,0x0,0x0,0x0},
305 {114,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x80,0x80,0x80,0x80,0xc0,0xa4,0xb8,0x0,0x0,0x0,0x0},
306 {115,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0xf8,0x84,0x4,0x38,0x40,0x84,0x78,0x0,0x0,0x0,0x0},
307 {116,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x30,0x28,0x20,0x20,0x20,0x20,0x78,0x20,0x20,0x0,0x0},
308 {117,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x74,0x4c,0x84,0x84,0x84,0x84,0x84,0x0,0x0,0x0,0x0},
309 {118,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x30,0x30,0x48,0x48,0x84,0x84,0x84,0x0,0x0,0x0,0x0},
310 {119,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x24,0x5a,0x92,0x92,0x82,0x82,0x82,0x0,0x0,0x0,0x0},
311 {120,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x84,0x84,0x48,0x30,0x48,0x84,0x84,0x0,0x0,0x0,0x0},
312 {121,8,15,0,0,8,0,0x38,0x44,0x84,0x4,0x74,0x8c,0x84,0x84,0x84,0x84,0x0,0x0,0x0,0x0,0x0},
313 {122,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0xfc,0x80,0x40,0x20,0x10,0x8,0xfc,0x0,0x0,0x0,0x0},
314 {123,8,15,0,0,8,0,0x0,0x0,0x30,0x40,0x40,0x40,0x40,0x40,0xc0,0x40,0x40,0x40,0x40,0x30,0x0},
315 {124,8,15,0,0,8,0,0x0,0x0,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x0},
316 {125,8,15,0,0,8,0,0x0,0x0,0x0,0x60,0x10,0x10,0x10,0x10,0x18,0x10,0x10,0x10,0x10,0x60,0x0},
317 {126,8,15,0,0,8,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x98,0xb4,0x64,0x0,0x0,0x0,0x0,0x0},
318 {255,0,0,0,0,0,0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}
319 };
320 //the buttons need to be larger for fingers on touch devices
321 #if defined(QNX) || defined(KIOSK)
322 #define BUTSIZE 48
323 #else
324 #define BUTSIZE 32
325 #endif
326 #define MAXBUT 32
327 /* <<< bitmap fonts */
328 typedef struct {
329  int cwidth;
330  int cheight;
331  int have[256];
332  GLfloat tex[2][2][256]; //texture coordinates lower left, upper right
333  GLfloat owh[2][2][256]; //offset, width, height
334  GLubyte *lumalpha;
335  GLuint textureID;
336 } pfont_t;
337 
338 typedef struct buttonSet buttonSet;
339 typedef struct {
340  int width;
341  int height;
342  GLfloat tex0[2][2];
343  GLfloat owh[2][2];
344  //GLfloat vert[12];
345  GLfloat tex[8];
346  GLubyte *lumalpha;
347  char *name;
348  const char *help;
349  int action; //ACTION_
350  int butStatus;
351  bool isToggle;
352  bool isRadio;
353  int *radioset;
354  buttonSet *buttonset;
355 } pmenuItem_t;
356 
357 typedef struct buttonSet {
358  int n;
359  int index;
360  pmenuItem_t ** items;
361 } buttonSet;
362 //Mar 2015 separate menubar from list of menuitems
363 // menuitmes - icons and actions which are prepared and can be placed on a menubar
364 // menubar - (new) container holding a runtime-changable arrangement of menuitems
365 // - benefit: FLY2 > dragchords > {yawz,xy,yawpitch,roll} can share one menubar button,
366 // with 2 click modes: a) change FLY2 chord (a toggle mode, new) and b) switch to FLY2 from another (normal)
367 
368 typedef struct {
369  pmenuItem_t *item; //holds icon specifics, and meaning: Action
370  GLfloat vert[12]; //bar designed coordinates
371  int action; //over-ride of the menuitem action if needed
372  int butrect[4];
373 } barItem;
374 
375 typedef struct {
376  pmenuItem_t *items;
377  int nitems;
378  barItem *bitems; //new
379  int nbitems; //new
380  //int nactive; //now refers to bitems
381  GLubyte *lumalpha;
382  GLuint textureID;
383  GLfloat *vert;
384  //GLfloat *tex;
385  GLushort *ind;
386  int blankItem;
387  bool top; // true: menu appears at top of screen, else bottom
388  int yoffset; // computed position of menu y
389  int **radiosets;
390  int *toggles;
391 } pmenu_t;
392 
393 
394 
395 typedef struct {int x; int y;} XY;
396 typedef struct {
397  GLfloat x;
398  GLfloat y;
399 } FXY;
400 #include <list.h>
401 static ivec4 defaultViewport = {0,0,400,400};
402 typedef struct pstatusbar{
403  int loopcount;// = 0;
404  int hadString;// = 0;
405  int initDone;
406  int showButtons;// =0;
407  int showStatus;
408  int wantButtons;
409  int wantStatusbar;
410  int statusbar_pinned;
411  int menubar_pinned;
412  int show_status;
413  int show_menu;
414  int yoff_status;
415  //textureTableIndexStruct_s butts[mbuts][2];
416  int butsLoaded;// = 0;
417  int isOver;// = -1;
418  int iconSize;// = 32;
419  int buttonType;// = 1; /* 0 = rgba .png 1= .c bitmap (see above) */
420  int savePng2dotc;// = 0; /* if you read png and want to save to a bitmap .c struct, put 1 */
421  int showConText;// = 0;
422  int showOptions;// =0;
423  int showHelp;//=0;
424  s_list_t *conlist;
425  int concount;
426  int fontInitialized;// = 0;
427  //GLuint fwFontOffset[3];
428  //XY fwFontSize[3];
429  //int sb_hasString;// = FALSE;
430  struct Uni_String *myline;
431  //char buffer[200];
432  char messagebar[200];
433  int bmfontsize;// = 2; /* 0,1 or 2 */
434  int optionsLoaded;// = 0;
435  char * optionsVal[30];
436  int osystem;// = 3; //mac 1btn = 0, mac nbutton = 1, linux game descent = 2, windows =3
437  XY bmWH;// = {10,15}; /* simple bitmap font from redbook above, width and height in pixels */
438  int bmScale; //1 or 2 for the hud pixel fonts, changes between ..ForOptions and ..Regular
439  int bmScaleForOptions; //special scale for the options check boxes (touch needs bigger)
440  int bmScaleRegular; //scale non-clickable/non-touchable text ! ?
441  int statusBarSize; //in pixels, should be bmScale x 16
442  int statusBarRows;
443  int posType; //1 == glRasterPos (opengl < 1.4), 0= glWindowPos (opengl 1.4+)
444  pfont_t pfont;
445  // Load the shaders and get a linked program object
446  GLuint programObject; // = esLoadProgram ( vShaderStr, fShaderStr );
447  GLuint positionLoc;
448  GLuint texCoordLoc;
449  GLuint textureLoc;
450  GLuint color4fLoc;
451  pmenu_t pmenu;
452  int buttonSize; //size of menu buttons, in pixels - default 32
453  int buttonRows;
454  GLfloat textColor[4];
455  //int screenWidth;
456  //int screenHeight;
457  ivec4 vport;
458  int clipPlane;
459  int side_top, side_bottom;
460 }* ppstatusbar;
461 void *statusbar_constructor(){
462  void *v = MALLOCV(sizeof(struct pstatusbar));
463  memset(v,0,sizeof(struct pstatusbar));
464  return v;
465 }
466 void statusbar_init(struct tstatusbar *t){
467  //public
468  //private
469  t->prv = statusbar_constructor();
470  {
471  int i;
472  ppstatusbar p = (ppstatusbar)t->prv;
473  p->loopcount = 0;
474  p->hadString = 0;
475  p->wantStatusbar = 1;
476  p->wantButtons = p->wantStatusbar;
477  p->showButtons = p->wantButtons;
478  p->showStatus = p->wantStatusbar;
479  //p->statusbar_pinned = 1;
480  //p->menubar_pinned = 0;
481  p->butsLoaded = 0;
482  p->isOver = -1;
483  p->iconSize = 32;
484  p->buttonType = 1; /* 0 = rgba .png 1= .c bitmap (see above) (put 0 to read .png, write C) */
485  p->savePng2dotc = 0; /* if you read png and want to save to a bitmap .c struct, put 1 */
486  p->showConText = 0;
487  p->showOptions =0;
488  p->showHelp = 0;
489  p->fontInitialized = 0;
490  //p->sb_hasString = FALSE;
491  p->initDone = FALSE;
492  p->optionsLoaded = 0;
493  p->osystem = 3; //mac 1btn = 0, mac nbutton = 1, linux game descent = 2, windows =3
494  p->bmWH.x = 8;
495  p->bmWH.y = 15; //{10,15}; /* simple bitmap font from redbook above, width and height in pixels */
496 #ifdef TOUCH
497  p->bmScaleForOptions = 2;
498 #else
499  p->bmScaleForOptions = 1;
500 #endif
501  p->bmScaleRegular = 1;
502 #ifdef KIOSK
503  p->bmScaleRegular = 2;
504  p->bmScaleForOptions = 2;
505 #endif
506  p->bmScale = p->bmScaleRegular; //functions can change this on the fly
507  p->statusBarSize = p->bmScaleRegular * 16;
508  p->statusBarRows = 1;
509  p->posType = 0; //assume ogl 1.4+, and correct if not
510  p->pfont.cheight = 0;
511  p->pfont.cwidth = 0;
512  p->pfont.lumalpha = NULL;
513  p->pmenu.items = MALLOC(pmenuItem_t *, MAXBUT * sizeof(pmenuItem_t));
514  for(i=0;i<MAXBUT;i++) p->pmenu.items[i].butStatus = 0;
515  p->pmenu.bitems = (barItem *)malloc(MAXBUT * sizeof(barItem));
516  bzero(p->pmenu.bitems,MAXBUT * sizeof(barItem));
517 
518  //p->showOptions = p->butStatus[10] = 1; //for debugging hud text
519  p->buttonSize = BUTSIZE;
520  p->buttonRows = 1;
521  p->textColor[3] = 1.0f;
522  //p->screenWidth = 400;
523  //p->screenHeight = 200,
524  p->vport = defaultViewport;
525  p->clipPlane = p->statusBarSize;
526  }
527 }
528 
529 //ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
530 
531 void initProgramObject(){
532  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
533 
534  // Load the shaders and get a linked program object
535  p->programObject = esLoadProgram ( (const char*) vShaderStr, (const char *)fShaderStr );
536  // Get the attribute locations
537  p->positionLoc = glGetAttribLocation ( p->programObject, "a_position" );
538  p->texCoordLoc = glGetAttribLocation ( p->programObject, "a_texCoord" );
539  // Get the sampler location
540  p->textureLoc = glGetUniformLocation ( p->programObject, "Texture0" );
541  p->color4fLoc = glGetUniformLocation ( p->programObject, "Color4f" );
542 }
543 static int lenOptions = 26;
544 void statusbar_clear(struct tstatusbar *t){
545  //public
546  //private
547  {
548  ppstatusbar p = (ppstatusbar)t->prv;
549  int i;
550  glDeleteTextures(1, &(p->pfont.textureID));
551  glDeleteTextures(1, &(p->pmenu.textureID));
552  if(p->conlist)
553  ml_delete_all(p->conlist);
554  if(p->optionsVal)
555  for(i=0;i<lenOptions;i++)
556  {
557  if(p->optionsVal[i])
558  FREE_IF_NZ(p->optionsVal[i]);
559  }
560  if(p->pmenu.items)
561  for(i=0;i<p->pmenu.nitems;i++)
562  FREE_IF_NZ(p->pmenu.items[i].lumalpha);
563  FREE_IF_NZ(p->pmenu.lumalpha);
564  FREE_IF_NZ(p->pmenu.items);
565  FREE_IF_NZ(p->pmenu.vert);
566  FREE_IF_NZ(p->pmenu.ind);
567  FREE_IF_NZ(p->pfont.lumalpha);
568  }
569 }
570 void fwMakeRasterFonts()
571 {
572  int i,j,k,m,w,h,bytewidth,bit;
573  //int bit1;
574  int ichar,isize, irow, icol, irowheight,icolwidth, iwidth, iheight;
575  float width, height;
576  GLubyte *cdata, *row;
577  GLubyte white[2];
578  //GLuint fwFontOffset8x15;
579  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
580 
581  //FW_GL_PIXELSTOREI(GL_UNPACK_ALIGNMENT, 1);
582  //fwFontOffset8x15 = glGenLists (128);
583  p->pfont.cheight = 15;
584  p->pfont.cwidth = 8;
585  // we'll make a squarish image, 16 characters wide, 16 char high
586  // 2 bytes per pixel: luminance and alpha
587  //height = p->pfont.cheight * 16;
588  //width = p->pfont.cwidth * 16;
589  iheight = 16 * 16;
590  iwidth = 16 * 16;
591  height = (float)iheight;
592  width = (float)iwidth;
593  irowheight = 15;
594  icolwidth = 8;
595  isize = iheight * iwidth * 2; //(p->pfont.cheight *16) * (p->pfont.cwidth * 16) * 2;
596 
597  p->pfont.lumalpha = MALLOC(GLubyte *, isize);
598  //memset(p->pfont.lumalpha,0,isize);
599  memset(p->pfont.lumalpha,0,isize);
600  white[0] = white[1] = (GLubyte)255;
601  for(m=0;m<256;m++)
602  {
603  p->pfont.have[m] = 0;
604  }
605  for(m=0;m<128;m++)
606  {
607  ichar = fwLetters8x15[m][0];
608  if(ichar == 255)break;
609  p->pfont.have[ichar] = 1; //loaded
610  cdata = &fwLetters8x15[m][7];
611  w = fwLetters8x15[m][1];
612  h = fwLetters8x15[m][2];
613  //16 rows of 16 chars
614  irow = ichar / 16;
615  icol = ichar % 16;
616  p->pfont.tex[0][0][ichar] = (GLfloat)(icol * icolwidth);
617  p->pfont.tex[1][0][ichar] = (GLfloat)(irow * irowheight);
618  p->pfont.tex[0][1][ichar] = p->pfont.tex[0][0][ichar] + p->pfont.cwidth;
619  p->pfont.tex[1][1][ichar] = p->pfont.tex[1][0][ichar] + p->pfont.cheight;
620  p->pfont.owh[0][0][ichar] = p->pfont.owh[1][0][ichar] = 0.0f;
621  p->pfont.owh[0][1][ichar] = (GLfloat)p->pfont.cwidth; //8;
622  p->pfont.owh[1][1][ichar] = (GLfloat)p->pfont.cheight; //.15;
623  //normalize texture coords from image coords to 0-1 range
624  for(j=0;j<2;j++) {
625  p->pfont.tex[0][j][ichar] /= width;
626  p->pfont.tex[1][j][ichar] /= height;
627  }
628  bytewidth = ((w-1)/8 +1);
629  for(j=0;j<h;j++)
630  {
631  row = &cdata[j*bytewidth];
632  for(i=0;i<w;i++)
633  {
634  k = i/8;
635  //bit = row[k] & (1<<(w-i-1))? 1 : 0;
636  bit = row[k] & (1<<((bytewidth*8)-i-1))? 1 : 0;
637  if(bit)
638  {
639  //memcpy(&p->pfont.lumalpha[(((irow*15)+j)*8*16 + icol*8 + i)*2],white,2);
640  int ip;
641  ip = (irow*irowheight +j)*iwidth;
642  ip += icol*icolwidth + i;
643  memcpy(&p->pfont.lumalpha[ip*2],white,2);
644  //memcpy(&p->pfont.lumalpha[(((irow*irowheight)+j)*icolwidth*16 + icol*icolwidth + i)*2],white,2);
645  }
646  }
647  }
648  }
649  if(false){
650  //int k;
651  FILE * fp;
652  fp = fopen("hud_junk_0.txt","w+");
653  fprintf(fp,"char data\n");
654  for(m=0;m<128;m++)
655  {
656  ichar = fwLetters8x15[m][0];
657  if(ichar == 255)break;
658  fprintf(fp,"%c %d ",(char)ichar,ichar);
659  fprintf(fp,"tex %6.2f %6.2f %6.2f %6.2f",p->pfont.tex[0][0][ichar],p->pfont.tex[1][0][ichar],p->pfont.tex[0][1][ichar],p->pfont.tex[1][1][ichar]);
660  fprintf(fp,"ohw %6.2f %6.2f %6.2f %6.2f",p->pfont.owh[0][0][ichar],p->pfont.owh[1][0][ichar],p->pfont.owh[0][1][ichar],p->pfont.owh[1][1][ichar]);
661  fprintf(fp,"\n");
662  }
663  fclose(fp);
664  }
665 
666  glGenTextures(1, &(p->pfont.textureID));
667  //p->pfont.textureID = LoadTexture ( "basemap.tga" );
668  glBindTexture(GL_TEXTURE_2D, p->pfont.textureID);
669 
670  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR); //GL_NEAREST); //GL_LINEAR);
671  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR); //GL_NEAREST); //GL_LINEAR);
672 
673  glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, iwidth, iheight, 0, GL_LUMINANCE_ALPHA , GL_UNSIGNED_BYTE, p->pfont.lumalpha);
674  //glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 16*16, irowheight*16, 0, GL_LUMINANCE_ALPHA , GL_UNSIGNED_BYTE, p->pfont.lumalpha);
675  //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA , GL_UNSIGNED_BYTE, cursor);
676 
677 }
678 
679 void initFont(void)
680 {
681  /*initialize raster bitmap font above */
682  // FW_GL_SHADEMODEL (GL_FLAT);
683  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
684 
685  fwMakeRasterFonts();
686  p->fontInitialized = 1;
687 }
688 //int bmfontsize = 2; /* 0,1 or 2 */
689 //static int ibufvert, ibuftex, ibufidx;
690 void printString(char *s){}
691 FXY screen2normalizedScreen( GLfloat x, GLfloat y);
692 FXY screen2normalizedScreenScale( GLfloat x, GLfloat y);
693 // OLD_IPHONE_AQUA #ifdef AQUA
694 // OLD_IPHONE_AQUA #include <malloc/malloc.h>
695 // OLD_IPHONE_AQUA #else
696 
697 #include <malloc.h>
698 
699 // OLD_IPHONE_AQUA #endif
700 
701 void printString3(GLfloat sx, GLfloat sy, char *s, int len)
702 {
703  int i, j;
704  int ichar;
705  FXY charScreenSize;
706  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
707  GLfloat x,y,z;
708  GLfloat *vert;
709  GLfloat *tex;
710  GLushort* ind;
711  int sizeoftex, sizeofvert, sizeofind;
712 
713  // construct triangle list
714  if(!s) return;
715  //len = (int) strlen(s);
716  if(len == 0) return;
717  sizeofvert = len * sizeof(GLfloat) * 4 * 3;
718  sizeoftex = len * sizeof(GLfloat) * 4 * 2;
719  sizeofind = len * sizeof(GLshort) * 2 * 3;
720  vert = (GLfloat*)alloca(sizeofvert); //2 new vertex, 3D
721  tex = (GLfloat*)alloca(sizeoftex); //4 new texture coords, 2D
722  ind = (GLushort*)alloca(sizeofind); //2 triangles, 3 points each
723  x=y=z = 0.0f;
724  x = sx;
725  y = sy;
726  i = 0;
727  // 1 2 coords and tex coords pattern
728  // 0 3
729  for(j=0;j<len;j++)
730  {
731  ichar = (int)s[i];
732  if (ichar == '\t') ichar = ' '; //trouble with tabs, quick hack
733  if(p->pfont.have[ichar])
734  {
735  charScreenSize = screen2normalizedScreenScale(p->pfont.owh[0][1][ichar]*p->bmScale,p->pfont.owh[1][1][ichar]*p->bmScale);
736  vert[i*4*3 +0] = x;
737  vert[i*4*3 +1] = y;
738  vert[i*4*3 +2] = z;
739  vert[i*4*3 +3] = x;
740  vert[i*4*3 +4] = y + charScreenSize.y;
741  vert[i*4*3 +5] = z;
742  vert[i*4*3 +6] = x + charScreenSize.x;
743  vert[i*4*3 +7] = y + charScreenSize.y;
744  vert[i*4*3 +8] = z;
745  vert[i*4*3 +9] = x + charScreenSize.x;
746  vert[i*4*3+10] = y;
747  vert[i*4*3+11] = z;
748  x = x + charScreenSize.x;
749  tex[i*4*2 +0] = p->pfont.tex[0][0][ichar];
750  tex[i*4*2 +1] = p->pfont.tex[1][0][ichar];
751  tex[i*4*2 +2] = p->pfont.tex[0][0][ichar];
752  tex[i*4*2 +3] = p->pfont.tex[1][1][ichar];
753  tex[i*4*2 +4] = p->pfont.tex[0][1][ichar];
754  tex[i*4*2 +5] = p->pfont.tex[1][1][ichar];
755  tex[i*4*2 +6] = p->pfont.tex[0][1][ichar];
756  tex[i*4*2 +7] = p->pfont.tex[1][0][ichar];
757  ind[i*3*2 +0] = i*4 + 0;
758  ind[i*3*2 +1] = i*4 + 1;
759  ind[i*3*2 +2] = i*4 + 2;
760  ind[i*3*2 +3] = i*4 + 2;
761  ind[i*3*2 +4] = i*4 + 3;
762  ind[i*3*2 +5] = i*4 + 0;
763  i++;
764  }
765  }
766  //bindTexture and DrawElements calls are the same for GL and GLES2
767 
768  glActiveTexture ( GL_TEXTURE0 );
769  glBindTexture ( GL_TEXTURE_2D, p->pfont.textureID );
770  // Load the vertex position
771  glVertexAttribPointer ( p->positionLoc, 3, GL_FLOAT,
772  GL_FALSE, 0, vert );
773  // Load the texture coordinate
774  glVertexAttribPointer ( p->texCoordLoc, 2, GL_FLOAT,
775  GL_FALSE, 0, tex ); //fails - p->texCoordLoc is 429xxxxx - garbage
776 
777  glEnableVertexAttribArray ( p->positionLoc );
778  glEnableVertexAttribArray ( p->texCoordLoc );
779  // Set the base map sampler to texture unit to 0
780  glUniform1i ( p->textureLoc, 0 );
781  glDrawElements ( GL_TRIANGLES, i*3*2, GL_UNSIGNED_SHORT, ind );
782  //FREE(vert);
783  //FREE(tex);
784  //FREE(ind);
785 
786 
787 }
788 void printString2(GLfloat sx, GLfloat sy, char *s){
789  printString3(sx,sy,s,strlen(s));
790 }
791 void render_init(void);
792 
794 //void kill_status (void) {
795 // /* hopefully, by this time, rendering has been stopped */
796 // ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
797 //
798 // p->sb_hasString = FALSE;
799 // p->buffer[0] = '\0';
800 //}
801 //
802 //
804 //void update_status(char* msg) {
805 // ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
806 //
807 // if (msg==NULL){
808 // p->sb_hasString = FALSE;
809 // p->buffer[0] = '\0';
810 // }else {
811 // p->sb_hasString = TRUE;
812 // strcpy (p->buffer,msg);
813 // }
814 //}
815 //char *get_status(){
816 // ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
817 // return p->buffer;
818 //}
819 
820 /* start cheapskate widgets >>>> */
821 //static int lenOptions = 16;
822 char * optionsText[] = {
823 "",
824 " mono",
825 " side-by-side",
826 " up-down",
827 " anaglyph",
828 " shutter",
829 "Eyebase - object space",
830 "\36 \37",
831 "Your Eyebase = fiducials",
832 "\36 \37",
833 "Anaglyph",
834 " RGB",
835 " left",
836 " right",
837 " neither",
838 " pin statusbar",
839 " pin menubar",
840 "colorScheme:",
841 "",
842 "target FPS \36 \37",
843 " emulate multitouch (mousewheel)",
844 "pickray eye:",
845 " left right either",
846 "screen orientation \36 \37",
847 "shading style:",
848 " flat gouraud phong wire",
849 NULL,
850 };
851 //0123456789012345678901234567890
852 
853 //int optionsLoaded = 0;
854 //char * optionsVal[15];
855 void setOptionsVal()
856 {
857 }
858 char *colorschemenames [] = {
859 "original",
860 "midnight",
861 "angry",
862 "favicon",
863 "aqua",
864 "neon:lime",
865 "neon:yellow",
866 "neon:cyan",
867 "neon:pink",
868 NULL,
869 };
870 void fwl_setPickraySide(int ipreferredSide, int either);
871 void fwl_getPickraySide(int *ipreferredSide, int *either);
872 int fwl_getOrientation();
873 int fwl_getOrientation2();
874 void fwl_setOrientation2(int degrees);
875 int fwl_getShadingStyle();
876 void initOptionsVal()
877 {
878  int i,j,k, iside, ieither, shadingStyle;
880  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
881  viewer = Viewer();
882 
883  for(i=0;i<lenOptions;i++)
884  {
885  if(!p->optionsVal[i])
886  p->optionsVal[i] = MALLOC(char*, 30);
887  for(j=0;j<30;j++) p->optionsVal[i][j] = ' ';
888  p->optionsVal[i][29] = '\0';
889  }
890  p->optionsVal[1][0] = 034; //[]
891  p->optionsVal[2][0] = 034; //[]
892  p->optionsVal[3][0] = 034; //[]
893  p->optionsVal[4][0] = 034; //[]
894  p->optionsVal[5][0] = 034; //[]
895 
896  if(!(viewer->sidebyside || viewer->updown || viewer->anaglyph || viewer->shutterGlasses))
897  p->optionsVal[1][0] = 035; //[*] '*';
898  if(viewer->sidebyside)
899  p->optionsVal[2][0] = 035; //[*] '*';
900  if(viewer->updown)
901  p->optionsVal[3][0] = 035; //[*] '*';
902  if(viewer->anaglyph)
903  p->optionsVal[4][0] = 035; //[*] '*';
904  if(viewer->shutterGlasses)
905  p->optionsVal[5][0] = 035; //[*] '*';
906  sprintf(p->optionsVal[7]," %4.3f",viewer->eyedist); //.eyebase); //.060f);
907  sprintf(p->optionsVal[9]," %4.3f",viewer->screendist); //.6f);
908  //sprintf(p->optionsVal[7]," %4.3f",viewer->stereoParameter); //.toein.4f);
909  for(i=0;i<3;i++){
910  for(j=0;j<3;j++){
911  k = getAnaglyphPrimarySide(j,i);
912  p->optionsVal[12+i][j+1] = (k ? 035 : ' ');
913  }
914  }
915  fwl_get_sbh_pin(&p->statusbar_pinned,&p->menubar_pinned);
916  p->optionsVal[15][0] = p->statusbar_pinned ? 035 : 034;
917  p->optionsVal[16][0] = p->menubar_pinned ? 035 : 034;
918  sprintf(p->optionsVal[18]," %s ",fwl_get_ui_colorschemename());
919  sprintf(p->optionsVal[19]," %4d",fwl_get_target_fps());
920  p->optionsVal[20][0] = 034; //[]
921  if(fwl_get_emulate_multitouch())
922  p->optionsVal[20][0] = 035; //[*] '*';
923  fwl_getPickraySide(&iside,&ieither);
924  p->optionsVal[22][1] = p->optionsVal[22][7] = p->optionsVal[22][14] = 034;
925  if(iside==0) p->optionsVal[22][1] = 035;
926  else p->optionsVal[22][7] = 035;
927  if(ieither) p->optionsVal[22][14] = 035;
928  sprintf(p->optionsVal[23]," %4d",fwl_getOrientation2());
929  shadingStyle = fwl_getShadingStyle();
930  p->optionsVal[25][1] = p->optionsVal[25][7] = p->optionsVal[25][16] = p->optionsVal[25][23] =034;
931  switch(shadingStyle){
932  case 0: p->optionsVal[25][1] = 035; break;
933  case 1: p->optionsVal[25][7] = 035; break;
934  case 2: p->optionsVal[25][16] = 035; break;
935  case 3: p->optionsVal[25][23] = 035; break;
936  default:
937  break;
938  }
939 
940  p->optionsLoaded = 1;
941 }
942 void updateOptionsVal()
943 {
944  /* on each loop we refresh the hud Options state from the viewer state,
945  in case others - via keyboard or gui - are also updating the viewer state*/
946  initOptionsVal();
947 }
948 /* the optionsCase char is used in a switch case later to involk the appropriate function */
949 char * optionsCase[] = {
950 "",
951 "00000000",
952 "22222222222222",
953 "44444444",
954 "33333333",
955 "11111111",
956 " ",
957 "55 66",
958 " ",
959 "DDEEEEEFF",
960 " ",
961 " ",
962 " rst ",
963 " uvw ",
964 " xyz ",
965 "77777777",
966 "88888888",
967 " ",
968 "99999999",
969 " KK LL",
970 "GGGGGGGGGGG",
971 " ",
972 "MM NN OO",
973 " PP QQ",
974 " ",
975 "RR SS TT UU",
976 NULL,
977 };
978 
979 XY mouse2screen(int x, int y)
980 {
981  XY xy;
982  xy.x = x;
983  //xy.y = ((ppstatusbar)(gglobal()->statusbar.prv))->screenHeight -y;
984  xy.y = y;
985  return xy;
986 }
987 XY screen2text(int x, int y)
988 {
989  XY rc;
990  int topOffset;
991  ppstatusbar p;
992  ttglobal tg = gglobal();
993  p = (ppstatusbar)tg->statusbar.prv;
994 
995  topOffset = p->side_top;
996  if(p->pmenu.top) topOffset += p->buttonSize;
997  rc.x = x/(p->bmWH.x*p->bmScale) -1; //10;
998  rc.y = (int)((p->vport.H -y - topOffset)/(p->bmWH.y*p->bmScale)); //15.0 );
999  rc.y -= 1;
1000  return rc;
1001 }
1002 XY text2screen( int col, int row)
1003 {
1004  XY xy;
1005  int topOffset;
1006  ppstatusbar p;
1007  ttglobal tg = gglobal();
1008  p = (ppstatusbar)tg->statusbar.prv;
1009  topOffset = p->side_top;
1010  if(p->pmenu.top) topOffset += p->buttonSize;
1011  xy.x = (col+1)*p->bmWH.x*p->bmScale; //10;
1012  xy.y = p->vport.H - topOffset - (row+2)*p->bmWH.y*p->bmScale; //15;
1013  return xy;
1014 }
1015 FXY screen2normalizedScreenScale( GLfloat x, GLfloat y)
1016 {
1017  FXY xy;
1018  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
1019 
1020  //convert to -1 to 1 range
1021  xy.x = ((GLfloat)x/(GLfloat)p->vport.W * 2.0f);
1022  xy.y = ((GLfloat)y/(GLfloat)p->vport.H * 2.0f);
1023  return xy;
1024 }
1025 FXY screen2normalizedScreen( GLfloat x, GLfloat y)
1026 {
1027  FXY xy;
1028  //convert to -1 to 1 range
1029  xy = screen2normalizedScreenScale(x,y);
1030  xy.x -= 1.0;
1031  xy.y -= 1.0;
1032  return xy;
1033 }
1034 void printOptions()
1035 {
1036  int j;
1037  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
1038 
1039  //printTextCursor();
1040  if(!p->optionsLoaded) initOptionsVal();
1041  updateOptionsVal(); //ideally we would be stateless in the hud, let Viewer hold state, that way other gui/shortcuts can be used
1042 
1043  p->bmScale = p->bmScaleForOptions;
1044  for(j=0;j<lenOptions;j++)
1045  {
1046  FXY xy;
1047  XY xy0 = text2screen(0,j);
1048  xy = screen2normalizedScreen( (GLfloat)xy0.x, (GLfloat)xy0.y);
1049  printString2(xy.x,xy.y,p->optionsVal[j]); /* " 0.050 " */
1050  printString2(xy.x,xy.y,optionsText[j]); /* "< >" */
1051  }
1052  p->bmScale = p->bmScaleRegular;
1053 
1054 }
1055 int handleOptionPress(int mouseX, int mouseY)
1056 {
1057  /* general idea: we don't update the hud/option state here - just the Viewer state - then
1058  refresh the hud/options state from the Viewer on each statusbar draw iteration
1059  */
1060  int opt;
1061  XY xys;
1062  XY xyt;
1063  X3D_Viewer *viewer;
1064  ppstatusbar p;
1065  ttglobal tg = gglobal();
1066  p = (ppstatusbar)tg->statusbar.prv;
1067 
1068  viewer = Viewer();
1069 
1070  p->bmScale = p->bmScaleForOptions;
1071  xys = mouse2screen(mouseX,mouseY);
1072  p->side_top = 0;
1073  if (Viewer()->updown) p->side_top = p->vport.H / 2;
1074  xyt = screen2text(xys.x,xys.y);
1075  opt = ' ';
1076  if( 0 <= xyt.y && xyt.y < lenOptions )
1077  {
1078  int len = (int) strlen(optionsCase[xyt.y]);
1079  if( xyt.x < len )
1080  {
1081  /* we are on an options line */
1082  opt = optionsCase[xyt.y][xyt.x];
1083  }
1084  }
1085  if(opt == ' ') return 0;
1086  p->bmScale = p->bmScaleRegular;
1087 
1088  /* we're clicking a sensitive area. */
1089  switch(opt)
1090  {
1091  case '?': {
1092  /* EAI */
1093  /* Note, this is actually useless (I suspect) because the EAI would already have started / (or ignored) */
1094  printf("toggle EAI");
1095  /* fwl_setp_eai(1 - fwl_getp_eai()); */
1096  break;}
1097  case '0':
1098  case '1':
1099  case '2':
1100  case '3':
1101  case '4':
1102  toggleOrSetStereo(opt-'0');
1103  break;
1104  case '7':
1105  fwl_get_sbh_pin(&p->statusbar_pinned,&p->menubar_pinned);
1106  p->statusbar_pinned = 1 - p->statusbar_pinned;
1107  fwl_set_sbh_pin(p->statusbar_pinned,p->menubar_pinned);
1108  break;
1109  case '8':
1110  fwl_get_sbh_pin(&p->statusbar_pinned,&p->menubar_pinned);
1111  p->menubar_pinned = 1 - p->menubar_pinned;
1112  fwl_set_sbh_pin(p->statusbar_pinned,p->menubar_pinned);
1113  break;
1114  case '9':
1115  fwl_next_ui_colorscheme();
1116  break;
1117  case 'r':
1118  case 's':
1119  case 't':
1120  setAnaglyphPrimarySide(opt-'r',0); //L,R,N
1121  break;
1122  case 'u':
1123  case 'v':
1124  case 'w':
1125  setAnaglyphPrimarySide(opt-'u',1); //L,R,N
1126  break;
1127  case 'x':
1128  case 'y':
1129  case 'z':
1130  setAnaglyphPrimarySide(opt-'x',2); //L,R,N
1131  //setAnaglyphSideColor(opt,1);
1132  break;
1133  case '5': {
1134  /* eyebase */
1135  printf("reduce eyebase");
1136  viewer->eyedist *= .9;
1137  updateEyehalf();
1138  break;}
1139  case '6': {
1140  /* eyebase */
1141  printf("increase eyebase");
1142  viewer->eyedist *= 1.1;
1143  updateEyehalf();
1144  break;}
1145  case 'D': {
1146  /* screendist */
1147  printf("reduce screendist");
1148  viewer->screendist -= .02; //*= .9;
1149  updateEyehalf();
1150  break;}
1151  case 'G': {
1152  fwl_set_emulate_multitouch(1 - fwl_get_emulate_multitouch());
1153  break;
1154  }
1155  case 'E': {
1156  /* screendist */
1157  printf("set screendist");
1158  break;}
1159  case 'F': {
1160  /* screendist */
1161  printf("increase screendist");
1162  viewer->screendist += .02; //*= 1.1;
1163  if(viewer->sidebyside)
1164  viewer->screendist = min(viewer->screendist,.375);
1165  updateEyehalf();
1166  break;}
1167  case 'H': {
1168  /* toein */
1169  printf("reduce toe-in");
1170  viewer->stereoParameter *= .9;
1171  updateEyehalf();
1172  break;}
1173  case 'I': {
1174  /* toein */
1175  printf("set toe-in");
1176  break;}
1177  case 'J': {
1178  /* toein */
1179  printf("increase toe-in");
1180  viewer->stereoParameter *= 1.1;
1181  if(viewer->sidebyside)
1182  viewer->stereoParameter = min(viewer->stereoParameter,.01); //toe-in is dangerous in sidebyside because it can force you to go wall-eyed
1183  updateEyehalf();
1184  break;}
1185  case 'K':
1186  case 'L':
1187  {
1188  //for target frames_per_second choices, we'd like a nice pow2 series like 7, 15, 30, 60, 120, 240 FPS
1189  int i15, tfps;
1190  tfps = fwl_get_target_fps();
1191  i15 = (int)((double)tfps / 15.0 + .5);
1192  if(opt == 'K') i15 /= 2;
1193  if(opt == 'L') i15 = max(1,i15*2);
1194  if(i15 < 1) tfps = 7;
1195  else tfps = min(3840,(int)15*i15);
1196  fwl_set_target_fps(tfps);
1197  }
1198  case 'M':
1199  case 'N':
1200  case 'O':
1201  {
1202  int iside, ieither;
1203  fwl_getPickraySide(&iside,&ieither);
1204  if(opt == 'O'){
1205  ieither = 1 - ieither;
1206  }else{
1207  iside = 1 - iside;
1208  }
1209  fwl_setPickraySide(iside,ieither);
1210  }
1211  break;
1212  case 'P':
1213  fwl_setOrientation2((fwl_getOrientation2()+90) % 360);
1214  break;
1215  case 'Q':
1216  fwl_setOrientation2( (fwl_getOrientation2() + 360 -90) % 360);
1217  break;
1218  case 'R':
1219  case 'S':
1220  case 'T':
1221  case 'U':
1222  {
1223  int shadingStyle;
1224  shadingStyle = opt - 'R';
1225  fwl_setShadingStyle(shadingStyle);
1226  }
1227  break;
1228  default:
1229  break;
1230  }
1231  return 1;
1232 }
1233 /* <<< end cheapskate widgets */
1234 
1235 
1236 
1237 //int osystem = 3; //mac 1btn = 0, mac nbutton = 1, linux game descent = 2, windows =3
1238 #if defined(QNX) //|| defined(_MSC_VER)
1239 int lenhelp = 21;
1240 char * keyboardShortcutHelp[] = {
1241 "WALK Mode",
1242 " movement: drag left/right for turns;",
1243 " drag up/down for forward/backward",
1244 "FLY Mode",
1245 " use the buttons for these motions:",
1246 " bird: drag left/right for left/right turns",
1247 " drag up/down for foreward/backward",
1248 " tilt up/down",
1249 " translation up/down and left/right",
1250 " rotation about the viewpoint/camera axis",
1251 "EXAMINE Mode",
1252 " rotation: drag left/right or up/down",
1253 "Level to bound viewpoint",
1254 "Flashlight/headlight",
1255 "Collision (and for WALK also gravity)",
1256 "Previous, Next viewpoint",
1257 "(this Help)",
1258 "Console messages from the program",
1259 "Options",
1260 "Reload last scene",
1261 "Enter URL of .x3d or .wrl scene"
1262 #elif defined(KIOSK) //|| defined(_MSC_VER)
1263 int lenhelp = 19;
1264 char * keyboardShortcutHelp[] = {
1265 "WALK Mode",
1266 " movement: drag left/right for turns;",
1267 " drag up/down for forward/backward",
1268 "FLY Mode",
1269 " use the buttons for these motions:",
1270 " bird: drag left/right for left/right turns",
1271 " drag up/down for foreward/backward",
1272 " tilt up/down",
1273 " translation up/down and left/right",
1274 " rotation about the viewpoint/camera axis",
1275 "EXAMINE Mode",
1276 " rotation: drag left/right or up/down",
1277 "Level to bound viewpoint",
1278 "Flashlight/headlight",
1279 "Collision (and for WALK also gravity)",
1280 "Previous, Next viewpoint",
1281 "(this Help)",
1282 "Console messages from the program",
1283 "Options"
1284 NULL,
1285 };
1286 #elif defined(_MSC_VER_NOT)
1287 int lenhelp = 16;
1288 char * keyboardShortcutHelp[] = {
1289 "WALK Mode",
1290 " movement: drag left/right for turns;",
1291 " drag up/down for forward/backward",
1292 "Keyboard FLY Mode",
1293 " use the keyboard for these motions:",
1294 " 8 k rotation down/up",
1295 " u o rotation left/right",
1296 " 7 9 rotation about the Z axis",
1297 " a z translation forwards/backwards",
1298 " j l translation left/right",
1299 " p ; translation up/down",
1300 " or use arrow keys. to change keychord: press SHIFT->",
1301 "EXAMINE Mode",
1302 " rotation: drag left/right or up/down",
1303 "EXPLORE Mode - use CTRL-click to recenter",
1304 "hit spacebar to get console prompt :, then type help"
1305 NULL,
1306 };
1307 #elif defined(OLD_HELP)
1308 int lenhelp = 20;
1309 char * keyboardShortcutHelp[] = {
1310 "EXAMINE Mode",
1311 " LMB rotation: MX rotation around Y axis; MY rotation around X axis",
1312 " RMB zooms", // On Apple computers with one button mice, press and hold the "control" key, and use your mouse.
1313 "WALK Mode",
1314 " LMB movement: MX left/right turns; MY walk forward/backward",
1315 " RMB height", //se Button 3 moves you up/down (changes your height above the ground). On Apple computers with one button mice, press and hold the "control" key, and use your mouse.
1316 "EXPLORE Mode",
1317 " - use CTRL-click to recenter",
1318 "Keyboard navigation",
1319 " - use arrow keys. to change keychord: press SHIFT> or SHIFT<",
1320 "other",
1321 " e Switch to Examine navigation mode",
1322 " w Switch to Walk navigation mode",
1323 " v Go to next viewpoint in the scene",
1324 " b Go to previous viewpoint in the scene",
1325 " / Print current viewport local pose",
1326 " h Toggle headlight",
1327 " c Toggle collision detection",
1328 " x Snapshot",
1329 " q Quit browser",
1330 NULL,
1331 };
1332 #else
1333 int lenhelp = 15;
1334 char * keyboardShortcutHelp[] = {
1335 " ",
1336 " ",
1337 "Keyboard Viewpoint change:",
1338 " PgDn,PgUp,Home,End = Next,Prev,First,Last",
1339 "Keyboard commands:",
1340 " / Print current viewpoint pose",
1341 " x Snapshot",
1342 " q Quit browser",
1343 "Keyboard navigation:",
1344 " use arrow keys.",
1345 " to change keychord: press SHIFT> or SHIFT<",
1346 "Touch cursor control:",
1347 " use both PEDAL % and HOVER ^ buttons to move cursor",
1348 " use PEDAL % button to drag cursor around",
1349 NULL,
1350 };
1351 #endif
1352 
1353 const char *libFreeWRL_get_version();
1354 void printKeyboardHelp(ppstatusbar p)
1355 {
1356  int j;
1357  XY xy;
1358  FXY fxy, fxy2, fxy3;
1359  GLfloat side_bottom_f;
1360 
1361  if(0){
1362  //print version info
1363  static const char *versionInfo = "libfreeWRL version ";
1364  xy = text2screen(0,0);
1365  fxy = screen2normalizedScreen((GLfloat)xy.x,(GLfloat)xy.y);
1366  printString2(fxy.x,fxy.y,(char *)versionInfo);
1367  xy = text2screen((int)strlen(versionInfo),0);
1368  fxy = screen2normalizedScreen((GLfloat)xy.x,(GLfloat)xy.y);
1369  printString2(fxy.x,fxy.y,(char*)libFreeWRL_get_version());
1370  }
1371 
1372  //font size:
1373  fxy2 = screen2normalizedScreenScale((GLfloat)p->bmWH.x, (GLfloat)p->bmWH.y);
1374  fxy2.y *= p->bmScale;
1375  side_bottom_f = -1.0f;
1376  fxy3 = screen2normalizedScreenScale((GLfloat)0, (GLfloat)p->buttonRows * p->buttonSize);
1377  side_bottom_f += fxy3.y;
1378  //draw bottom up, to explain buttons
1379  j = 0;
1380  while(keyboardShortcutHelp[j] != NULL)
1381  {
1382  //if (Viewer()->updown){
1383  // if(iside == 0) side_bottom_f = 0.0f;
1384  printString2(-1.0f, side_bottom_f + (lenhelp-j)*fxy2.y, keyboardShortcutHelp[j]);
1385  j++;
1386  if(p->show_status && j > lenhelp) break; //they can see button help on the statusbar on mouse-over button
1387  }
1388 }
1389 
1390 void hudSetConsoleMessage(char *buffer)
1391 {
1392  s_list_t* last;
1393  /*calling program passes ownership of buffer here, where we free when scrolling off */
1394  //char *ln;
1395  //int linelen;
1396  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
1397 
1398  //printf("+%s\n", buffer);
1399  if(!p->conlist)
1400  {
1401  //char * line;
1402  //line = MALLOC(char *, 2);
1403  //line[0] = '\0';
1404  //p->conlist = ml_new(line);
1405  //p->concount = 1;
1406  p->concount = 0;
1407  }
1408  last = ml_new(buffer);
1409  if (!p->conlist)
1410  p->conlist = last;
1411  else
1412  ml_append(p->conlist,last);
1413  p->concount++;
1414  if( p->concount > 50 ) // > MAXMESSAGES number of scrolling lines
1415  {
1416  //printf("-%s\n", (char*)p->conlist->elem);
1417  free((char*)p->conlist->elem); //free a previous buffer now scrolled up off the screen
1418  p->conlist = ml_delete_self(p->conlist, p->conlist); /*delete from top*/
1419  p->concount--;
1420  }
1421 }
1422 
1423 void printConsoleText()
1424 {
1425  /* ConsoleMessage() comes out as a multi-line history rendered over the scene */
1426  int jstart;
1427  int j = 0;
1428  XY xybottom;
1429  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
1430 
1431  jstart = j;
1432  {
1433  s_list_t *__l;
1434  s_list_t *next;
1435  s_list_t *_list = p->conlist;
1436  /* lets keep the scrolling text from touching the bottom of the screen */
1437  xybottom = screen2text(0,p->side_bottom);
1438  jstart = max(0,p->concount-(xybottom.y - 3)); /* keep it 3 lines off the bottom */
1439  for(__l=_list;__l!=NULL;)
1440  {
1441  next = ml_next(__l); /* we need to get next from __l before action deletes element */
1442  if(j >= jstart) /* no need to print off-screen text */
1443  {
1444  FXY fxy;
1445  XY xy = text2screen(0,j-jstart);
1446  fxy = screen2normalizedScreen((GLfloat)xy.x,(GLfloat)xy.y);
1447  printString2(fxy.x,fxy.y,__l->elem);
1448  }
1449  j++;
1450  __l = next;
1451  }
1452  }
1453 }
1454 
1455 enum {
1456 ACTION_WALK,
1457 ACTION_FLY2,
1458 ACTION_TILT,
1459 ACTION_TPLANE,
1460 ACTION_RPLANE,
1461 ACTION_FLY,
1462 ACTION_EXAMINE,
1463 ACTION_EXPLORE,
1464 ACTION_SPHERICAL,
1465 ACTION_TURNTABLE,
1466 ACTION_LOOKAT,
1467 ACTION_YAWZ,
1468 ACTION_YAWPITCH,
1469 ACTION_ROLL,
1470 ACTION_XY,
1471 ACTION_DIST,
1472 ACTION_SHIFT,
1473 ACTION_HOVER,
1474 ACTION_PEDAL,
1475 ACTION_LEVEL,
1476 ACTION_HEADLIGHT,
1477 ACTION_COLLISION,
1478 ACTION_PREV,
1479 ACTION_NEXT,
1480 ACTION_HELP,
1481 ACTION_MESSAGES,
1482 ACTION_OPTIONS,
1483 ACTION_RELOAD,
1484 ACTION_URL,
1485 ACTION_FILE,
1486 ACTION_BLANK
1487 } button_actions;
1488 
1489 struct button_help {
1490 int action;
1491 char *help;
1492 } button_helps [] = {
1493 {ACTION_WALK, "WALK"},
1494 {ACTION_FLY2, "FLY2"},
1495 {ACTION_TILT, "TILT"},
1496 {ACTION_TPLANE, "TRANSLATE"},
1497 {ACTION_RPLANE, "ROLL"},
1498 {ACTION_FLY, "FLY {yaw-z,xy,yaw-pitch,roll}"},
1499 {ACTION_EXAMINE, "EXAMINE"},
1500 {ACTION_EXPLORE, "EXPLORE {examine,recenter}"},
1501 {ACTION_SPHERICAL, "SPHERICAL {pan,zoom}"},
1502 {ACTION_TURNTABLE, "TURNTABLE"},
1503 {ACTION_LOOKAT, "LOOKAT"},
1504 {ACTION_YAWZ, "FLY yaw-z"},
1505 {ACTION_YAWPITCH, "FLY yaw-pitch"},
1506 {ACTION_ROLL, "FLY roll"},
1507 {ACTION_XY, "FLY xy"},
1508 {ACTION_DIST, "DIST (for examine,explore,turntable)"},
1509 {ACTION_SHIFT, "SHIFT Key (turns off sensors)"},
1510 {ACTION_HOVER, "HOVER up-drag isOver mode"},
1511 {ACTION_PEDAL, "PEDAL drags in-scene cursor"},
1512 {ACTION_LEVEL, "LEVEL to bound VP (ViewPoint)"},
1513 {ACTION_HEADLIGHT, "HEADLIGHT"},
1514 {ACTION_COLLISION, "COLLISION (and gravity)"},
1515 {ACTION_PREV, "Prev VP"},
1516 {ACTION_NEXT, "Next VP"},
1517 {ACTION_HELP, "Help"},
1518 {ACTION_MESSAGES, "Console"},
1519 {ACTION_OPTIONS, "Options"},
1520 {ACTION_RELOAD, "Reload"},
1521 {ACTION_URL, "URL"},
1522 {ACTION_FILE, "FILE"},
1523 {ACTION_BLANK, NULL},
1524 };
1525 const char *help_for_action(int action){
1526  int i;
1527  struct button_help *bh;
1528  i = 0;
1529  do{
1530  bh = &button_helps[i];
1531  if(bh->action == action) break;
1532  i++;
1533  }while(bh->action != ACTION_BLANK);
1534  return bh->help;
1535 }
1536 
1537 void convertPng2hexAlpha()
1538 {
1539  /* How to make new button icons:
1540  1. design a button gray or white over alpha in something like blender
1541  2. render to 32x32 .png with alpha channel
1542  3. p->buttonType = 0 in function that calls convertPng2hexAlpha
1543  4. change mbuts to 1 if doing just one button
1544  5. put the name of button for butFnames[] = {"mybutname.png"};
1545  6. put your mybutname.png in the folder where freewrl runs from (see diagnostic GetCurrentDirectory below)
1546  7. build and run freewrl once - should get hudicons_octalpha_h output file
1547  8. copy and paste from hudicons_octalpha_h to freewrl's hudicons_octalpha.h at the bottom (leave existing buttons)
1548  9. // p->buttonType = 0 - comment back out in function below
1549  10. tinker with code in statusbarhud.c in several places to get the button to show and do things
1550  */
1551  int w,h,ii,size;
1552  static int mbuts = 1; //2; //8; // 17;
1553  static char * butFnames[] = {"hover.png"}; //{"pedal.png"}; //{"shift.png","sensor.png"}; //{"YAWZ.png"}; // {"lookat.png","explore.png","spherical.png","turntable.png","XY.png","ROLL.png","YAWPITCH.png","YAWZ.png"}; //{"tilt.png"}; //{"tplane.png","rplane.png","walk.png","fly.png","examine.png","level.png","headlight.png","collision.png","prev.png","next.png","help.png","messages.png","options.png","reload.png","url.png","file.png","blank.png"};//"flyEx.png",
1555 
1556  FILE* out = fopen("hudIcons_octalpha_h","w+");
1557  //{
1558  // //where to put .png, windows desktop
1559  // char dirname[1024];
1560  // GetCurrentDirectory(1000,dirname); //not supported in winRT
1561  // printf("current directory:%s\n",dirname);
1562  //}
1563  /* png icon files (can have transparency) problem: you need to put them in the current working directory*/
1564  for(ii=0;ii<mbuts;ii++)
1565  {
1566  int j,k,l,g,rgbmax[3];
1567  texture_load_from_file(&butts, butFnames[ii]);
1568  /* compute grayed out (non active) versions */
1569  w = butts.x;
1570  h = butts.y;
1571  size = w * h * 4;
1572  //step 1 find maximum RGB
1573  for(j=0;j<3;j++) rgbmax[j] = 0;
1574  for(j=0;j<butts.x;j++)
1575  {
1576  for(k=0;k<butts.y;k++)
1577  {
1578  for(l=0;l<3;l++)
1579  {
1580  g = butts.texdata[j*w*4 + k*4 + l];
1581  rgbmax[l] = g > rgbmax[l] ? g : rgbmax[l];
1582  }
1583  }
1584  }
1585  //step 2 scale to max color (for maximum white 255,255,255 in solid areas)
1586  for(j=0;j<butts.x;j++)
1587  {
1588  for(k=0;k<butts.y;k++)
1589  {
1590  g = 0;
1591  //scale color to maximum color (so solid will be 255,255,255 white
1592  for(l=0;l<3;l++)
1593  {
1594  int h;
1595  h = butts.texdata[j*w*4 + k*4 + l];
1596  h = (int)((float)h/(float)rgbmax[l]*255.0f);
1597  g += h;
1598  }
1599  //convert to gray so I can take any channel later
1600  g = g / 3; //convert colorful RGB to gray RGB
1601  g = g > 255? 255 : g;
1602  for(l=0;l<3;l++)
1603  butts.texdata[j*w*4 + k*4 + l] = g;
1604  }
1605  }
1606  /* write rgba out as binary bitmap in .c struct format for inclusion above */
1607  {
1608  //unsigned char row, a, bit;
1609  char butname[30];
1610  strcpy(butname,butFnames[ii]);
1611  for(j=0;j<(int)strlen(butname);j++)
1612  if(butname[j] == '.') {butname[j] = '\0'; break;}
1613  fprintf(out,"GLubyte %s[] = {\n",butname);
1614  //2012 1 byte per pixel method (nicer)
1615  {
1616  //this method writes only the alpha channel, and does it in octal strings
1617  //(to reconstruct luminance later, copy alpha to lum)
1618  //this makes a nice compact header file.
1619  char str[5];
1620  unsigned char *data;
1621  int i,m,n,lastlen;
1622  bool lastoct;
1623 
1624  fprintf(out,"\"");
1625  n = 0;
1626  lastoct = false;
1627  lastlen = 0;
1628  data = &butts.texdata[0]; //start on the alpha [3]
1629  for(i=0;i<size;i+=4) //do every 4th (skip RGB, just alpha)
1630  {
1631  int datai;
1632  // value = Red * Alpha (if I don't do this, the reconstructed lumalpha icons will look fat/ swollen/ smudged
1633  datai = (int)(((float) data[i] * (float)data[i+3])/255.0f);
1634  //this octal string writing method matches how Gimp write images to C
1635  //weird part: if an octal /xxx has less than 3 digits, and the next
1636  //thing is a '0' to '9' then you need to break the string with
1637  //an extra "" to interupt the octal string representation
1638  if( datai == '"' || datai == '\\') {sprintf(str,"\\%c",datai); lastoct = false;}
1639  else if( datai >= '0' && datai <= '9' && lastoct && lastlen < 4) {sprintf(str,"\"\"%c",datai); lastoct = false;}
1640  else if( datai > 32 && datai < 127 ) {sprintf(str,"%c",datai); lastoct = false;}
1641  else {sprintf(str,"\\%o",datai); lastoct = true;}
1642  fprintf(out,"%s",str);
1643  m = (int) strlen(str);
1644  n += m;
1645  lastlen = m;
1646  if(n > 71)
1647  {
1648  fprintf(out,"\"\n\"");
1649  n = 0;
1650  }
1651  }
1652  fprintf(out,"\"\n");
1653 
1654  }
1655  fprintf(out,"};\n");
1656  }
1657  } //i=1,mbut
1658  fclose(out);
1659  exit(0); //close the program,
1660  //rename hudIcons_octalpha_h to hudIcons_octalpha.h and rebuild
1661  //then rerun with p->buttonType = 1
1662 }
1663 
1664 void initButtons()
1665 {
1666  /* first time renderButtons() is called, this is called to
1667  load the button icons and set up coords in pixels*/
1668  int i, buttonAtlasSizeCol, buttonAtlasSizeRow, buttonAtlasSquared;
1669  ttglobal tg = gglobal();
1670  ppstatusbar p = (ppstatusbar)tg->statusbar.prv;
1671  p->clipPlane = p->statusBarSize; //16;
1672 
1673  //p->buttonType = 0; //uncomment this line to convert png buttons to hudIcons_octalpha_h header format
1674  if(p->buttonType == 0){
1675  convertPng2hexAlpha();
1676  exit(0);
1677  }
1678  if(p->buttonType == 1)
1679  {
1680 
1681  //buttonlist, actionlist and NACTION are/mustbe synchronized, will become part of pmenitem tuple together
1682  // - include all buttons and actions here (filter out ones you don't want in mainbar)
1683  static GLubyte * buttonlist [] = {
1684  walk, fly, examine,
1685  yawz, xy, yawpitch, roll,
1686  explore, spherical, turntable, lookat, distance,
1687  shift, hover, pedal, level, headlight,
1688  collision, prev, next, help, messages,
1689  options, reload, url, file, blank
1690  };
1691  static int actionlist [] = {
1692  ACTION_WALK, ACTION_FLY, ACTION_EXAMINE,
1693  ACTION_YAWZ, ACTION_XY, ACTION_YAWPITCH, ACTION_ROLL,
1694  ACTION_EXPLORE, ACTION_SPHERICAL, ACTION_TURNTABLE, ACTION_LOOKAT, ACTION_DIST,
1695  ACTION_SHIFT, ACTION_HOVER, ACTION_PEDAL, ACTION_LEVEL, ACTION_HEADLIGHT,
1696  ACTION_COLLISION, ACTION_PREV,ACTION_NEXT, ACTION_HELP, ACTION_MESSAGES,
1697  ACTION_OPTIONS,ACTION_RELOAD, ACTION_URL, ACTION_FILE, ACTION_BLANK,
1698  };
1699  static int NACTION = 27; //must match buttonlist and actionlist count, and be <= MAXBUT defined above
1700  //radiosets are to indicate what things are deselected (if any) when another thing is selected
1701  static int radiosets [][9] = {
1702  {8,ACTION_FLY,ACTION_WALK,ACTION_EXAMINE,ACTION_EXPLORE,ACTION_SPHERICAL,ACTION_TURNTABLE,ACTION_LOOKAT,ACTION_DIST},
1703  {3,ACTION_MESSAGES,ACTION_OPTIONS,ACTION_HELP},
1704  //{4,ACTION_YAWZ, ACTION_XY, ACTION_YAWPITCH, ACTION_ROLL},
1705  {0},
1706  };
1707  //not sure we need to toggle in the View, the Model holds the state, and
1708  //controller checks once per frame
1709  static int toggles [] = {
1710  ACTION_COLLISION,ACTION_HEADLIGHT,ACTION_SHIFT,ACTION_HOVER,ACTION_PEDAL,
1711  ACTION_HELP,ACTION_MESSAGES,ACTION_OPTIONS,0
1712  };
1713  static int togglesets [][8] = {{ACTION_FLY,4,ACTION_YAWZ, ACTION_XY, ACTION_YAWPITCH, ACTION_ROLL},{0}};
1714 
1715  static int mainbar_linux [] = {
1716  ACTION_WALK, ACTION_FLY, ACTION_EXAMINE,
1717  ACTION_EXPLORE, ACTION_SPHERICAL, ACTION_TURNTABLE, ACTION_LOOKAT, ACTION_DIST,
1718  ACTION_SHIFT, ACTION_HOVER, ACTION_PEDAL, ACTION_LEVEL, ACTION_HEADLIGHT, ACTION_COLLISION, ACTION_PREV,
1719  ACTION_NEXT, ACTION_HELP, ACTION_MESSAGES, ACTION_OPTIONS,
1720  //ACTION_RELOAD, ACTION_URL,
1721  //ACTION_FILE,
1722  -1,
1723  };
1724  static int *mainbar = NULL;
1725 
1726  p->pmenu.nitems = NACTION; //number of action items, even if not shown on menubar
1727  mainbar = mainbar_linux;
1728 
1729  //count number of menubar items, assuming last item is -1 sentinal value
1730  i=0;
1731  do{
1732  i++;
1733  p->pmenu.nbitems = i;
1734  }while(mainbar[i]>-1);
1735  //p->pmenu.nbitems = 18;
1736 #if defined(QNX) || defined(KIOSK)
1737  p->pmenu.top = true;
1738 #else
1739  p->pmenu.top = false;
1740 #endif
1741 
1742 
1743  //convert to lumalpha
1744  //p->pmenu.items = (pmenuItem_t *)malloc(16 * sizeof(pmenuItem_t)); done in module init
1745  //may 1, 2012: QNX GLES2 needs power-of-2 image dimensions, but doesn't need to be square
1746  //bad: 32x5 by 32x5 (25 icons) good: 32x8 by 32x4 (8x4 = 32 icons)
1747  buttonAtlasSizeCol = 8; // 8x4 grid of buttons
1748  buttonAtlasSizeRow = 4;
1749  buttonAtlasSquared = buttonAtlasSizeCol*buttonAtlasSizeRow;
1750  p->pmenu.lumalpha = MALLOC(GLubyte*, 32*32*2 *buttonAtlasSquared); //4x4 grid of icons each 32x32x2
1751  memset(p->pmenu.lumalpha,0,32*32*2 *buttonAtlasSquared);
1752  p->pmenu.vert= MALLOC(GLfloat*, 3*4*buttonAtlasSquared*sizeof(GLfloat));
1753 // p->pmenu.tex = MALLOC(GLfloat*, 2*4*buttonAtlasSquared*sizeof(GLfloat));
1754  p->pmenu.ind = MALLOC(GLushort*, 3*2*buttonAtlasSquared*sizeof(GLushort));
1755  p->pmenu.yoffset = 0;
1756  if(p->pmenu.top) p->pmenu.yoffset = p->vport.H - p->buttonSize; //32.0f;
1757  for(i=0;i<p->pmenu.nitems;i++)
1758  {
1759  int j,k,irow,icol;
1760  int kt;
1761 
1762  p->pmenu.items[i].action = actionlist[i];
1763  p->pmenu.items[i].help = help_for_action(actionlist[i]);
1764  p->pmenu.items[i].isToggle = false;
1765  p->pmenu.items[i].buttonset = NULL;
1766  j=0;
1767  while(toggles[j] > 0)
1768  {
1769  if(p->pmenu.items[i].action == toggles[j])
1770  {
1771  p->pmenu.items[i].isToggle = true;
1772  break;
1773  }
1774  j++;
1775  }
1776  p->pmenu.items[i].radioset = NULL;
1777  p->pmenu.items[i].isRadio = false;
1778  j=0;
1779  while(radiosets[j][0] > 0)
1780  {
1781  for(k=1;k<=radiosets[j][0];k++)
1782  if(p->pmenu.items[i].action == radiosets[j][k])
1783  {
1784  p->pmenu.items[i].isRadio = true;
1785  p->pmenu.items[i].radioset = &radiosets[j][0];
1786  break;
1787  }
1788  j++;
1789  }
1790 
1791 
1792  p->pmenu.items[i].height = 32;
1793  p->pmenu.items[i].width = 32;
1794  p->pmenu.items[i].lumalpha = MALLOC(GLubyte*, 32 * 32 * 2);
1795  for(j=0;j<32;j++) //pixel row within image
1796  {
1797  for(k=0;k<32;k++) //pixel column within image
1798  {
1799  int ibyte, ibit, color;
1800  if(false){
1801  //binary image
1802  ibyte = (j*32 + k)/8;
1803  ibit = (j*32 + k)%8;
1804  color = buttonlist[i][ibyte] & (1<<(7-ibit))? 255 : 0;
1805  }else if(true){
1806  //255 alpha channel image
1807  ibyte = j*32 + k;
1808  color = buttonlist[i][ibyte];
1809  }
1810  p->pmenu.items[i].lumalpha[(j*32 +k)*2 +0] = color;
1811  p->pmenu.items[i].lumalpha[(j*32 +k)*2 +1] = color;
1812  }
1813  }
1814  //copy to main lumapha
1815  irow = i / buttonAtlasSizeCol; //button row within 5x5 buttons image
1816  icol = i % buttonAtlasSizeCol; //button colum "
1817  for(j=0;j<32;j++) //pixel row within item image
1818  {
1819  for(k=0;k<32;k++) //pixel column within item image
1820  {
1821  p->pmenu.lumalpha[(irow*32 +j)*32*2*buttonAtlasSizeCol + (icol*32 +k)*2 + 0] = p->pmenu.items[i].lumalpha[(j*32 +k)*2 +0];
1822  p->pmenu.lumalpha[(irow*32 +j)*32*2*buttonAtlasSizeCol + (icol*32 +k)*2 + 1] = p->pmenu.items[i].lumalpha[(j*32 +k)*2 +1];
1823  }
1824  }
1825  //assign texture coordinates
1826  p->pmenu.items[i].tex0[0][0] = (GLfloat)(icol*32 + 0)/(GLfloat)(32*buttonAtlasSizeCol);
1827  p->pmenu.items[i].tex0[1][0] = (GLfloat)(irow*32 + 0)/(GLfloat)(32*buttonAtlasSizeRow);
1828  p->pmenu.items[i].tex0[0][1] = (GLfloat)(icol*32 +32)/(GLfloat)(32*buttonAtlasSizeCol);
1829  p->pmenu.items[i].tex0[1][1] = (GLfloat)(irow*32 +32)/(GLfloat)(32*buttonAtlasSizeRow);
1830  //Q. how will I flexibly do the highlight?
1831  //I think I would loop through the buttons to do the highlighting, but then the buttons themselves
1832  //can be done with a single mesh.
1833  kt = 0;
1834  // 1 3 vertex order
1835  // 0 2
1836  for(j=0;j<2;j++) //row
1837  {
1838  for(k=0;k<2;k++) //column
1839  {
1840  //texture coords
1841  //p->pmenu.items[i].tex[kt +0] = p->pmenu.tex[mt+kt + 0] = p->pmenu.items[i].tex0[0][j];
1842  //p->pmenu.items[i].tex[kt +1] = p->pmenu.tex[mt+kt + 1] = p->pmenu.items[i].tex0[1][k];
1843  p->pmenu.items[i].tex[kt +0] = p->pmenu.items[i].tex0[0][j];
1844  p->pmenu.items[i].tex[kt +1] = p->pmenu.items[i].tex0[1][k];
1845  kt+=2;
1846  }
1847  }
1848  }
1849  glGenTextures(1, &(p->pmenu.textureID));
1850  glBindTexture(GL_TEXTURE_2D, p->pmenu.textureID);
1851  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
1852  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
1853 
1854  glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, 32*buttonAtlasSizeCol, 32*buttonAtlasSizeRow, 0, GL_LUMINANCE_ALPHA , GL_UNSIGNED_BYTE, p->pmenu.lumalpha);
1855 
1856  {
1857  //fill out any sub-button togglebutton toggleset actions
1858  int *togset, kset;
1859  kset = 0;
1860  togset = togglesets[kset];
1861  while(togset[0]){
1862  int k, ipact, nact, iact;
1863  ipact = togset[0];
1864  nact = togset[1];
1865  for(k=0;k<p->pmenu.nitems;k++){
1866  if(ipact == p->pmenu.items[k].action){
1867  int m;
1868  p->pmenu.items[k].buttonset = malloc(sizeof(buttonSet));
1869  p->pmenu.items[k].buttonset->n = nact;
1870  p->pmenu.items[k].buttonset->index = 0; //first one by default
1871  p->pmenu.items[k].buttonset->items = malloc(nact * sizeof(void*));
1872  for(m=0;m<nact;m++){
1873  int n;
1874  p->pmenu.items[k].buttonset->items[m] = NULL;
1875  iact = togset[m+2];
1876  for(n=0;n<p->pmenu.nitems;n++){
1877  if(iact == p->pmenu.items[n].action){
1878  p->pmenu.items[k].buttonset->items[m] = &p->pmenu.items[n];
1879  }
1880  }
1881  }
1882  }
1883  }
1884  nact = togset[1];
1885  kset++;
1886  togset = togglesets[kset];
1887  }
1888  }
1889 
1890 
1891  for(i=0;i<p->pmenu.nbitems;i++)
1892  {
1893  int j, k, mi, mv, kv;
1894  GLfloat dx;
1895  FXY xyxy[2];
1896  int bz = p->buttonSize;
1897 
1898  //pixel coord boxes, for mouse picking of buttons
1899  p->pmenu.bitems[i].butrect[0] = 5+(i*bz); /* lower left x */
1900  p->pmenu.bitems[i].butrect[1] = 0; /* lower left y */
1901  p->pmenu.bitems[i].butrect[2] = 5+(i*bz)+bz;/* upper right x */
1902  p->pmenu.bitems[i].butrect[3] = bz; /* upper right y */
1903 
1904  mv = i*3*4;
1905  mi = i*3*2;
1906  kv = 0;
1907  // 1 3 vertex order
1908  // 0 2
1909  /* normalized coords moved to draw function for resize
1910  xyxy[0] = screen2normalizedScreen( 0.0f, p->pmenu.yoffset); //0.0f);
1911  //xyxy[1] = screen2normalizedScreen( 32.0f, 32.0f + p->pmenu.yoffset);
1912  xyxy[1] = screen2normalizedScreen( p->buttonSize, p->buttonSize + p->pmenu.yoffset);
1913  */
1914  xyxy[0].x = 0.0f;
1915  xyxy[0].y = 0.0f; //we'll need to compute yoffset in draw
1916  xyxy[1].x = (GLfloat)p->buttonSize;
1917  xyxy[1].y = (GLfloat)p->buttonSize;
1918  dx = xyxy[1].x - xyxy[0].x;
1919  for(j=0;j<2;j++) //row
1920  {
1921  for(k=0;k<2;k++) //column
1922  {
1923  //vertex coords
1924  p->pmenu.bitems[i].vert[kv +0] = p->pmenu.vert[mv+kv +0] = xyxy[j].x + (GLfloat)(i*dx);
1925  p->pmenu.bitems[i].vert[kv +1] = p->pmenu.vert[mv+kv +1] = xyxy[k].y;
1926  p->pmenu.bitems[i].vert[kv +2] = p->pmenu.vert[mv+kv +2] = 0.0f;
1927  //p->pmenu.bitems[i].vert[kv +0] = xyxy[j].x + (GLfloat)(i*dx);
1928  //p->pmenu.bitems[i].vert[kv +1] = xyxy[k].y;
1929  //p->pmenu.bitems[i].vert[kv +2] = 0.0f;
1930  kv+=3;
1931  }
1932  }
1933 
1934  // triangle indices
1935  // 1-3
1936  // |/|
1937  // 0-2
1938  p->pmenu.ind[mi +0] = (GLushort)(i*4) +0;
1939  p->pmenu.ind[mi +1] = (GLushort)(i*4) +1;
1940  p->pmenu.ind[mi +2] = (GLushort)(i*4) +3;
1941  p->pmenu.ind[mi +3] = (GLushort)(i*4) +0;
1942  p->pmenu.ind[mi +4] = (GLushort)(i*4) +3;
1943  p->pmenu.ind[mi +5] = (GLushort)(i*4) +2;
1944 
1945  //assign icon+action to menubar button location
1946  for(j=0;j<p->pmenu.nitems;j++){
1947  if(mainbar[i] == p->pmenu.items[j].action){
1948  p->pmenu.bitems[i].item = &p->pmenu.items[j];
1949  break;
1950  }
1951  }
1952  }
1953  }
1954  p->butsLoaded = 1;
1955 }
1956 /* the following setMenuButton_ were defined for some other front end and called from various locations
1957  - re-using here
1958  - mar 2015: this still refers-to/indexes-into the longer items[] list, not the shorter mainbuttonbar []
1959 */
1960 int getMenuItemByAction(int iaction)
1961 {
1962  int i;
1963  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
1964  for(i=0;i<p->pmenu.nitems;i++)
1965  if(p->pmenu.items[i].action == iaction)
1966  return i;
1967  return -1;
1968 }
1969 
1970 void setRadioPalsOff(int *ipals, int iaction)
1971 {
1972  int i,j;
1973  ppstatusbar p;
1974  ttglobal tg = gglobal();
1975  p = (ppstatusbar)tg->statusbar.prv;
1976  j=0;
1977  for(j=1;j<=ipals[0];j++)
1978  {
1979  if(ipals[j] != iaction)
1980  {
1981  i = getMenuItemByAction(ipals[j]);
1982  if(i > -1)
1983  p->pmenu.items[i].butStatus = 0;
1984  }
1985  }
1986  return;
1987 }
1988 
1989 void setMenuButton_collision(int val){
1990  int i;
1991  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
1992  i = getMenuItemByAction(ACTION_COLLISION);
1993  if(i > -1)
1994  p->pmenu.items[i].butStatus = val;
1995 }
1996 void setMenuButton_consoleText(int val){
1997  int i;
1998  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
1999  i = getMenuItemByAction(ACTION_MESSAGES);
2000  if(i > -1)
2001  p->pmenu.items[i].butStatus = val;
2002 }
2003 void setMenuButton_texSize(int size){
2004  /* this isn't called in my configuration so I don't know what the range is */
2005  printf("text size=%d\n",size);
2006  //int bmfontsize = 2; /* 0,1 or 2 - our current size range*/
2007 }
2008 void setMenuButton_headlight(int val){
2009  int i;
2010  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
2011  i = getMenuItemByAction(ACTION_HEADLIGHT);
2012  if(i > -1)
2013  p->pmenu.items[i].butStatus = val;
2014 }
2015 void setMenuButton_shift(int val){
2016  int i;
2017  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
2018  i = getMenuItemByAction(ACTION_SHIFT);
2019  if(i > -1)
2020  p->pmenu.items[i].butStatus = val;
2021 }
2022 void setMenuButton_hover(int val){
2023  int i;
2024  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
2025  i = getMenuItemByAction(ACTION_HOVER);
2026  if(i > -1)
2027  p->pmenu.items[i].butStatus = val;
2028 }
2029 void setMenuButton_pedal(int val){
2030  int i;
2031  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
2032  i = getMenuItemByAction(ACTION_PEDAL);
2033  if(i > -1)
2034  p->pmenu.items[i].butStatus = val;
2035 }
2036 void setMenuButton_ctrl(int ctrl){
2037  //not used yet - ctrl affects 3-state buttons like Explore (goes into pick mode when pressed 2x),
2038  //and examine, spherical (ctrl + LMB == RMB)
2039  // could be used to highlight double-pressed button so user knows to toggle off
2040 }
2041 
2042 static int chord2action [] = {ACTION_YAWZ,ACTION_YAWPITCH,ACTION_ROLL,ACTION_XY};
2043 
2044 void setMenuButton_navModes(int type, int dragchord)
2045 {
2046  int i, newval, iaction;
2047  ppstatusbar p = (ppstatusbar)gglobal()->statusbar.prv;
2048 
2049  switch(type)
2050  {
2051  case VIEWER_NONE:
2052  iaction = ACTION_EXAMINE;
2053  newval = 0;
2054  break;
2055  case VIEWER_EXAMINE:
2056  iaction = ACTION_EXAMINE;
2057  newval = 1;
2058  break;
2059  case VIEWER_WALK:
2060  iaction = ACTION_WALK;
2061  newval = 1;
2062  break;
2063  case VIEWER_TURNTABLE:
2064  iaction = ACTION_TURNTABLE;
2065  newval = 1;
2066  break;
2067  case VIEWER_LOOKAT:
2068  iaction = ACTION_LOOKAT;
2069  newval = 1;
2070  break;
2071  case VIEWER_EXPLORE:
2072  iaction = ACTION_EXPLORE;
2073  newval = 1;
2074  break;
2075  case VIEWER_SPHERICAL:
2076  iaction = ACTION_SPHERICAL;
2077  newval = 1;
2078  break;
2079  case VIEWER_DIST:
2080  iaction = ACTION_DIST;
2081  newval = 1;
2082  break;
2083  case VIEWER_FLY:
2084 #if defined(QNX) || defined(KIOSK)//|| defined(_MSC_VER)
2085  iaction = ACTION_FLY2;
2086 #else
2087  iaction = ACTION_FLY;
2088 #endif
2089  newval = 1;
2090  break;
2091  default:
2092  iaction = -1;
2093  }
2094  if(iaction > -1){
2095  i = getMenuItemByAction(iaction);
2096  if(i>-1){
2097  if(p->pmenu.items[i].buttonset){
2098  //its a fancy toggle button that rolls through different icons; need to update the sub-icon
2099  if(iaction == p->pmenu.items[i].action){
2100  int j;
2101  //pressing a button already pressed if its a togglebutton, means incrementing the toggle
2102  switch(iaction){
2103  case ACTION_FLY:
2104  if(p->pmenu.items[i].buttonset){
2105  for(j=0;j<p->pmenu.items[i].buttonset->n;j++){
2106  if(p->pmenu.items[i].buttonset->items[j]->action == chord2action[dragchord]){
2107  p->pmenu.items[i].buttonset->index = j;
2108  }
2109  }
2110  }
2111  break;
2112  default:
2113  break;
2114  }
2115  }
2116  }
2117  if(p->pmenu.items[i].isRadio)
2118  setRadioPalsOff(p->pmenu.items[i].radioset,iaction);
2119  p->pmenu.items[i].butStatus = newval;
2120  }
2121  }
2122 return;
2123 }
2124 int viewer_getDragChord();
2125 void viewer_setDragChord(int chord);
2126 
2127 /* handle all the displaying and event loop stuff. */
2128 void updateButtonStatus()
2129 {
2130  //checks collision, headlight and navmode in the model
2131  //in MVC -model,view,controller- terminology, this is the controller,
2132  // and it checks the model (libfreewrl ie fwl functions), and updates the view (statusbar hud)
2133  //-these can be set by either the UI (this statusbar), keyboard hits, or from
2134  // events inside vrml.
2135  // Here we take our UI current state from the scene state.
2136  // For FRONTEND_HANDLES_DISPLAY_THREAD configurations, the frontend should do
2137  // the equivalent of the following once per frame (poll state and set UI)
2138  int headlight, collision, navmode, dragchord, ctrl, shift, hover, pedal, consoletext;
2139  //poll model state:
2140  headlight = fwl_get_headlight();
2141  collision = fwl_getCollision();
2142  navmode = fwl_getNavMode();
2143  dragchord = viewer_getDragChord();
2144  shift = fwl_getShift();
2145  hover = fwl_getHover();
2146  pedal = fwl_getPedal();
2147  ctrl = fwl_getCtrl();
2148  consoletext = getShowConsoleText();
2149  //lookatMode = fwl_getLookatMode();
2150  //update UI(view):
2151  setMenuButton_shift(shift);
2152  setMenuButton_hover(hover);
2153  setMenuButton_pedal(pedal);
2154  setMenuButton_ctrl(ctrl);
2155  setMenuButton_navModes(navmode,dragchord);
2156  setMenuButton_headlight(headlight);
2157  setMenuButton_collision(collision);
2158  setMenuButton_consoleText(consoletext);
2159  //setMenuButton_lookat(lookatMode);
2160 }
2161 
2162 void updateConsoleStatus()
2163 {
2164  //polls ConsoleMessage.c for accumulated messages and updates statusbarHud.c via hudSetConsoleMessage
2165  int nlines, i;
2166  char *buffer;
2167  nlines = fwg_get_unread_message_count(); //poll model
2168  for (i = 0; i<nlines; i++)
2169  {
2170  buffer = fwg_get_last_message(); // poll model
2171  hudSetConsoleMessage(buffer); //update UI(view)
2172  //free(buffer);
2173  }
2174 }
2175 
2176 
2177 int handleButtonOver(int mouseX, int mouseY)
2178 {
2179  /* called from mainloop > fwl_handle_aqua to
2180  a) detect a button over and
2181  b) highlight underneath the button*/
2182  int i, x, y, ihalf;
2183  ppstatusbar p;
2184  ttglobal tg = gglobal();
2185  p = (ppstatusbar)tg->statusbar.prv;
2186 
2187  x = mouseX;
2188  //if (p->pmenu.top)
2189  // y = mouseY;
2190  //else
2191  // y = p->screenHeight - mouseY - p->pmenu.yoffset;
2192  if (p->pmenu.top)
2193  y = p->vport.H - mouseY;
2194  else
2195  y = mouseY - p->pmenu.yoffset;
2196 
2197  p->isOver = -1;
2198 
2199  ihalf = (p->pmenu.nbitems + 1)/p->buttonRows;
2200  for(i=0;i<p->pmenu.nbitems;i++)
2201  {
2202  int j,xx,yy,butrect[4];
2203  for(j=0;j<4;j++) butrect[j] = p->pmenu.bitems[i].butrect[j];
2204  xx = x;
2205  yy = y;
2206  if(i >= ihalf){
2207  xx = x + ihalf * p->buttonSize;
2208  yy = y - p->buttonSize;
2209  }
2210  if(xx > butrect[0] && xx < butrect[2]
2211  && yy > butrect[1] && yy < butrect[3] )
2212  {
2213  /* printf("%d",i); */ /* is over */
2214  p->isOver = i;
2215  break;
2216  }
2217  }
2218  return p->isOver; // == -1 ? 0 : 1;
2219 }
2220 char *frontend_pick_URL(void);
2221 char *frontend_pick_file(void);
2222 void toggleMenu(int val)
2223 {
2224  ppstatusbar p;
2225  ttglobal tg = gglobal();
2226  p = (ppstatusbar)tg->statusbar.prv;
2227  if(p->wantButtons)
2228  p->showButtons = val > 0 ? 1 : 0;
2229  else
2230  p->showButtons = 0;
2231 }
2232 
2233 int action2chord(int iaction){
2234  int ichord = CHORD_YAWZ;
2235  switch(iaction){
2236  case ACTION_YAWZ: ichord = CHORD_YAWZ; break;
2237  case ACTION_XY: ichord = CHORD_XY; break;
2238  case ACTION_YAWPITCH: ichord = CHORD_YAWPITCH; break;
2239  case ACTION_ROLL: ichord = CHORD_ROLL; break;
2240  default: ichord = 0; break;
2241  }
2242  return ichord;
2243 }
2244 
2245 int handleButtonRelease(int mouseX, int mouseY)
2246 {
2247  /* called from mainloop > to
2248  a) detect a button hit and
2249  b) toggle the button icon and
2250  c) set the related option
2251  */
2252  int i,x,y,ihit,iaction,ihalf;
2253  //int j, oldval;
2254  ppstatusbar p;
2255  ttglobal tg = gglobal();
2256  p = (ppstatusbar)tg->statusbar.prv;
2257 
2258  x = mouseX;
2259  //if(p->pmenu.top)
2260  // y = mouseY;
2261  //else
2262  // y = p->screenHeight - mouseY - p->pmenu.yoffset;
2263  if(p->pmenu.top)
2264  y = p->vport.H - mouseY;
2265  else
2266  y = mouseY - p->pmenu.yoffset;
2267  ihalf = (p->pmenu.nbitems + 1)/p->buttonRows;
2268  ihit = -1;
2269  for(i=0;i<p->pmenu.nbitems;i++)
2270  {
2271  int j,xx,yy,butrect[4];
2272  for(j=0;j<4;j++) butrect[j] = p->pmenu.bitems[i].butrect[j];
2273  xx = x;
2274  yy = y;
2275  if(i >= ihalf){
2276  xx = x + ihalf * p->buttonSize;
2277  yy = y - p->buttonSize;
2278  }
2279  if(xx > butrect[0] && xx < butrect[2]
2280  && yy > butrect[1] && yy < butrect[3] )
2281  {
2282  ihit = i;
2283  iaction = p->pmenu.bitems[i].item->action;
2284  if(p->pmenu.bitems[i].item->butStatus && p->pmenu.bitems[i].item->buttonset ){
2285  //fancy toggle button, need to increment to next button in buttonset whenever the button is pressed when already active
2286  p->pmenu.bitems[i].item->buttonset->index++;
2287  p->pmenu.bitems[i].item->buttonset->index = (p->pmenu.bitems[i].item->buttonset->index % 4);
2288  }
2289  if(p->pmenu.bitems[i].item->isRadio)
2290  {
2291  setRadioPalsOff(p->pmenu.bitems[i].item->radioset,iaction);
2292  if(p->pmenu.bitems[i].item->isToggle )
2293  p->pmenu.bitems[i].item->butStatus = 1 - p->pmenu.bitems[i].item->butStatus;
2294  else
2295  p->pmenu.bitems[i].item->butStatus = 1;
2296  }
2297  else if(p->pmenu.bitems[i].item->isToggle)
2298  p->pmenu.bitems[i].item->butStatus = 1 - p->pmenu.bitems[i].item->butStatus;
2299  switch(iaction)
2300  {
2301  case ACTION_WALK:
2302  fwl_set_viewer_type (VIEWER_WALK); break;
2303  case ACTION_FLY2:
2304  fwl_set_viewer_type (VIEWER_FLY2); break;
2305  case ACTION_TILT:
2306  fwl_set_viewer_type (VIEWER_TILT); break;
2307  case ACTION_TPLANE:
2308  fwl_set_viewer_type (VIEWER_TPLANE); break;
2309  case ACTION_RPLANE:
2310  fwl_set_viewer_type (VIEWER_RPLANE); break;
2311  case ACTION_FLY:
2312  fwl_set_viewer_type(VIEWER_FLY);
2313  if(p->pmenu.bitems[i].item->buttonset){
2314  int iact, idx, ichord;
2315  idx = p->pmenu.bitems[i].item->buttonset->index;
2316  iact = p->pmenu.bitems[i].item->buttonset->items[idx]->action;
2317  ichord = action2chord(iact);
2318  viewer_setDragChord(ichord);
2319  }
2320  break;
2321  case ACTION_EXPLORE:
2322  fwl_set_viewer_type(VIEWER_EXPLORE); break;
2323  case ACTION_LOOKAT:
2324  fwl_set_viewer_type(VIEWER_LOOKAT); break;
2325  case ACTION_EXAMINE:
2326  fwl_set_viewer_type (VIEWER_EXAMINE); break;
2327  case ACTION_SPHERICAL:
2328  fwl_set_viewer_type(VIEWER_SPHERICAL); break;
2329  case ACTION_TURNTABLE:
2330  fwl_set_viewer_type(VIEWER_TURNTABLE); break;
2331  case ACTION_DIST:
2332  fwl_set_viewer_type(VIEWER_DIST); break;
2333  case ACTION_SHIFT: fwl_setShift(p->pmenu.bitems[i].item->butStatus); break;
2334  case ACTION_HOVER: fwl_setHover(p->pmenu.bitems[i].item->butStatus);
2335  break;
2336  case ACTION_PEDAL: fwl_setPedal(p->pmenu.bitems[i].item->butStatus); break;
2337  case ACTION_LEVEL: viewer_level_to_bound(); break;
2338  case ACTION_HEADLIGHT: fwl_toggle_headlight(); break;
2339  case ACTION_COLLISION: toggle_collision(); break;
2340  case ACTION_PREV: fwl_Prev_ViewPoint(); break;
2341  case ACTION_NEXT: fwl_Next_ViewPoint(); break;
2342  case ACTION_HELP:
2343  //p->showHelp = p->pmenu.items[i].butStatus;
2344  if(!p->pmenu.bitems[i].item->butStatus)
2345  //just turned off, clear statusbar help string
2346  update_status(NULL);
2347  showConsoleText(0);
2348  break;
2349  case ACTION_MESSAGES:
2350  //p->showConText = p->pmenu.items[i].butStatus;
2351  update_status(NULL);
2352  showConsoleText(p->pmenu.bitems[i].item->butStatus);
2353  break;
2354  case ACTION_OPTIONS:
2355  //p->showOptions = p->pmenu.items[i].butStatus;
2356  update_status(NULL);
2357  showConsoleText(0);
2358  break;
2359  //case ACTION_RELOAD: fwl_reload(); break;
2360  case ACTION_URL:
2361  //load URL
2362 #ifndef KIOSK
2363  //fwl_setPromptForURL(1);
2364  #if defined(_MSC_VER) || defined(QNX)
2365  {
2366  char *fname = frontend_pick_URL();
2367  if(fname)
2368  {
2369  fwl_replaceWorldNeeded(fname);
2370  FREE(fname);
2371  }
2372  }
2373  #endif
2374 #endif
2375 
2376  break;
2377  case ACTION_FILE:
2378  //load file
2379 #ifndef KIOSK
2380  //fwl_setPromptForFile(1);
2381 
2382  #if defined(_MSC_VER) || defined(QNX)
2383  {
2384  char *fname = frontend_pick_file();
2385  if(fname)
2386  {
2387  fwl_replaceWorldNeeded(fname);
2388  FREE(fname);
2389  }
2390  }
2391  #endif
2392 
2393 #endif
2394  break;
2395  default:
2396  break;
2397  }
2398  } //end if rect
2399  } //end for
2400  return ihit == -1 ? 0 : 1;
2401 }
2402 void updateButtonVertices()
2403 {
2404  int i,j,k,kv,mv,ihalf;
2405  float xx,yy;
2406  //int zz;
2407  FXY xy;
2408  ppstatusbar p;
2409  ttglobal tg = gglobal();
2410  p = (ppstatusbar)tg->statusbar.prv;
2411 
2412  //p->pmenu.yoffset = (float) yoff_button; //0.0f;
2413  if(p->pmenu.top) p->pmenu.yoffset = (p->vport.H - p->buttonSize - p->pmenu.yoffset); //32.0f;
2414 
2415  ihalf = (p->pmenu.nbitems + 1)/p->buttonRows;
2416  for(i=0;i<p->pmenu.nbitems;i++)
2417  {
2418  int button_xoff, button_yoff;
2419  kv = 0;
2420  button_yoff = button_xoff = 0;
2421  if(i >= ihalf){
2422  //for phones / narrow / portrait stack 2 rows of buttons
2423  button_yoff = p->buttonSize;
2424  button_xoff = -(ihalf * p->buttonSize);
2425  }
2426  for(j=0;j<2;j++)
2427  for(k=0;k<2;k++)
2428  {
2429  xx = p->pmenu.bitems[i].vert[kv +0];
2430  yy = p->pmenu.bitems[i].vert[kv +1];
2431  xy = screen2normalizedScreen(xx + button_xoff,yy + p->pmenu.yoffset + button_yoff + p->side_bottom);
2432  mv = i*3*4;
2433  p->pmenu.vert[mv+kv +0] = xy.x;
2434  p->pmenu.vert[mv+kv +1] = xy.y;
2435  kv += 3;
2436  }
2437  }
2438 }
2439 
2440 void renderButtons()
2441 {
2442  /* called from drawStatusBar() to render the user buttons like walk/fly, headlight, collision etc. */
2443  int i,ctrl,itrim;
2444  ppstatusbar p;
2445  ttglobal tg = gglobal();
2446  p = (ppstatusbar)tg->statusbar.prv;
2447 
2448 
2449  if(!p->butsLoaded)
2450  initButtons();
2451  updateButtonVertices();
2452  //updateButtonStatus();
2453  itrim = 0;
2454  #ifdef ANGLEPROJECT
2455  itrim = 1; //if width of window it floods entire window instead of just menubar
2456  #endif
2457  glScissor(p->vport.X,p->vport.Y + p->pmenu.yoffset+p->side_bottom,p->vport.W -itrim ,p->buttonSize*p->buttonRows); //tg->Mainloop.clipPlane*2);
2458 
2459  glEnable(GL_SCISSOR_TEST);
2460  //glClearColor(.922f,.91f,.844f,1.0f); //windowing gray
2461  glClearColor(colorClear[0],colorClear[1],colorClear[2],colorClear[3]);
2462  //glClearColor(.754f,.82f,.93f,1.0f); //193.0f/256.0f,210.0f/256.0f,238.0f/256.0f,1.0f); //windowing blue
2463  glClear(GL_COLOR_BUFFER_BIT);
2464  glDisable(GL_SCISSOR_TEST);
2465  doglClearColor(); //set back for other cases
2466  // Bind the base map
2467  glActiveTexture ( GL_TEXTURE0 );
2468 
2469  glBindTexture ( GL_TEXTURE_2D, p->pmenu.textureID );
2470 
2471  ctrl = fwl_getCtrl();
2472  for(i=0;i<p->pmenu.nbitems;i++)
2473  {
2474  int do_ctrl;
2475  bool highlightIt = p->pmenu.bitems[i].item->butStatus;
2476  do_ctrl = ctrl && i < 8;
2477 
2478  if(highlightIt) //i==p->isOver || p->pmenu.items[i].butStatus)
2479  {
2480  /*draw a background highlight rectangle*/
2481 
2482  if(do_ctrl)
2483  glUniform4f(p->color4fLoc,colorButtonCTRL[0],colorButtonCTRL[1],colorButtonCTRL[2],colorButtonCTRL[3]);
2484  else
2485  glUniform4f(p->color4fLoc,colorButtonHighlight[0],colorButtonHighlight[1],colorButtonHighlight[2],colorButtonHighlight[3]);
2486  glVertexAttribPointer ( p->positionLoc, 3, GL_FLOAT,
2487  GL_FALSE, 0, &(p->pmenu.vert[i*3*4]) );
2488  // Load the texture coordinate
2489  glVertexAttribPointer ( p->texCoordLoc, 2, GL_FLOAT,
2490  GL_FALSE, 0, p->pmenu.items[p->pmenu.nitems-1].tex ); //nitems -1 should be the blank texture
2491  glEnableVertexAttribArray ( p->positionLoc );
2492  glEnableVertexAttribArray ( p->texCoordLoc );
2493  glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, p->pmenu.ind ); //first 6 should be 0 1 3 0 3 2
2494  }
2495  // render triangles
2496 
2497  glVertexAttribPointer ( p->positionLoc, 3, GL_FLOAT,
2498  GL_FALSE, 0, &(p->pmenu.vert[i*3*4]) );
2499 
2500 
2501  // Load the texture coordinate
2502  if(p->pmenu.bitems[i].item->buttonset){
2503  //fancy togglebutton buttonset
2504  glVertexAttribPointer ( p->texCoordLoc, 2, GL_FLOAT,
2505  GL_FALSE, 0, p->pmenu.bitems[i].item->buttonset->items[p->pmenu.bitems[i].item->buttonset->index]->tex ); //nitems -1 should be the blank texture
2506  }else{
2507  glVertexAttribPointer ( p->texCoordLoc, 2, GL_FLOAT,
2508  GL_FALSE, 0, p->pmenu.bitems[i].item->tex ); //nitems -1 should be the blank texture
2509  }
2510  //glUniform4f(p->color4fLoc,0.37f,0.37f,0.9f,1.0f); //BLUE ICON SHAPE COLOR
2511  glUniform4f(p->color4fLoc,colorButtonIcon[0],colorButtonIcon[1],colorButtonIcon[2],colorButtonIcon[3]);
2512  glEnableVertexAttribArray ( p->positionLoc );
2513  glEnableVertexAttribArray ( p->texCoordLoc );
2514  glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, p->pmenu.ind ); //first 6 should be 0 1 3 0 3 2
2515 
2516  /* old one-shot
2517  // Load the vertex position
2518  glVertexAttribPointer ( p->positionLoc, 3, GL_FLOAT,
2519  GL_FALSE, 0, p->pmenu.vert );
2520  // Load the texture coordinate
2521  glVertexAttribPointer ( p->texCoordLoc, 2, GL_FLOAT,
2522  GL_FALSE, 0, p->pmenu.tex ); //fails - p->texCoordLoc is 429xxxxx - garbage
2523  glUniform4f(p->color4fLoc,0.37f,0.37f,0.9f,1.0f); //BLUE ICON SHAPE COLOR
2524  glEnableVertexAttribArray ( p->positionLoc );
2525  glEnableVertexAttribArray ( p->texCoordLoc );
2526 
2527  // Set the base map sampler to texture unit to 0
2528  glUniform1i ( p->textureLoc, 0 );
2529  glDrawElements ( GL_TRIANGLES, p->pmenu.nbitems*3*2, GL_UNSIGNED_SHORT, p->pmenu.ind ); //render the main menu bar
2530  */
2531  }
2532  //clean up
2533  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
2534  FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
2535  p->hadString = 1;
2536 }
2537 void updateViewportSize();
2538 void fwl_getWindowSize(int *width, int *height);
2539 void statusbarHud_DrawCursor(GLint textureID,int x,int y){
2540 GLfloat cursorVert[] = {
2541  -.05f, -.05f, 0.0f,
2542  -.05f, .05f, 0.0f,
2543  .05f, .05f, 0.0f,
2544  -.05f, -.05f, 0.0f,
2545  .05f, .05f, 0.0f,
2546  .05f, -.05f, 0.0f};
2547 GLfloat cursorTex[] = {
2548  0.0f, 0.0f,
2549  0.0f, 1.0f,
2550  1.0f, 1.0f,
2551  0.0f, 0.0f,
2552  1.0f, 1.0f,
2553  1.0f, 0.0f};
2554  GLushort ind[] = {0,1,2,3,4,5};
2555  //GLint pos, tex;
2556  FXY fxy;
2557  XY xy;
2558  int i,j,screenWidth,screenHeight;
2559  GLfloat cursorVert2[18];
2560 
2561  ppstatusbar p;
2562  ttglobal tg = gglobal();
2563  p = (ppstatusbar)tg->statusbar.prv;
2564 
2565  FW_GL_DEPTHMASK(GL_FALSE);
2566  glDisable(GL_DEPTH_TEST);
2567  if(p->programObject == 0) initProgramObject();
2568  glUseProgram ( p->programObject );
2569 
2570  //updateViewportSize();
2571  fwl_getWindowSize(&screenWidth,&screenHeight);
2572  xy = mouse2screen(x,y);
2573  //FW_GL_VIEWPORT(p->vport.X, p->vport.Y, p->vport.W, p->vport.H); //screenWidth, p->screenHeight);
2574  FW_GL_VIEWPORT(0,0,screenWidth,screenHeight);
2575  //fxy = screen2normalizedScreenScale((GLfloat)xy.x,(GLfloat)xy.y);
2576  fxy.x = ((GLfloat)xy.x/(GLfloat)screenWidth * 2.0f);
2577  fxy.y = ((GLfloat)xy.y/(GLfloat)screenHeight * 2.0f);
2578 
2579  fxy.y -= 1.0;
2580  fxy.x -= 1.0;
2581  //fxy.y *= .5;
2582  //fxy.x *= .5;
2583  for(i=0;i<6;i++){
2584  for(j=0;j<3;j++)
2585  cursorVert2[i*3 + j] = cursorVert[i*3 +j];
2586  cursorVert2[i*3 +0] += fxy.x;
2587  cursorVert2[i*3 +1] += fxy.y;
2588  }
2589  // Load the vertex position
2590  //p->positionLoc = glGetAttribLocation ( p->programObject, "a_position" );
2591  //p->texCoordLoc = glGetAttribLocation ( p->programObject, "a_texCoord" );
2592  // Get the sampler location
2593  //p->textureLoc = glGetUniformLocation ( p->programObject, "Texture0" );
2594  //p->color4fLoc = glGetUniformLocation ( p->programObject, "Color4f" );
2595 
2596  glVertexAttribPointer (p->positionLoc, 3, GL_FLOAT,
2597  GL_FALSE, 0, cursorVert2 );
2598  // Load the texture coordinate
2599  glVertexAttribPointer ( p->texCoordLoc, 2, GL_FLOAT,
2600  GL_FALSE, 0, cursorTex ); //fails - p->texCoordLoc is 429xxxxx - garbage
2601  glUniform4f(p->color4fLoc,0.7f,0.7f,0.9f,1.0f);
2602  glEnableVertexAttribArray (p->positionLoc );
2603  glEnableVertexAttribArray ( p->texCoordLoc);
2604 
2606  glActiveTexture ( GL_TEXTURE0 );
2607  glBindTexture ( GL_TEXTURE_2D, textureID );
2608 
2609  // Set the base map sampler to texture unit to 0
2610  glUniform1i ( p->textureLoc, 0 );
2611  glDrawElements ( GL_TRIANGLES, 3*2, GL_UNSIGNED_SHORT, ind ); //just render the active ones
2612 
2613  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
2614  FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
2615 
2616 
2617  glEnable(GL_DEPTH_TEST);
2618  FW_GL_DEPTHMASK(GL_TRUE);
2619  restoreGlobalShader();
2620 
2621 }
2622 void updateViewCursorStyle(int cstyle);
2623 void fwl_set_frontend_using_cursor(int on);
2624 bool showAction(ppstatusbar p, int action)
2625 {
2626  int item = getMenuItemByAction(action);
2627  if( item > -1)
2628  {
2629  return p->pmenu.items[item].butStatus;
2630  }
2631  return false;
2632 }
2633 int overMenubar(ppstatusbar p, int mouseY){
2634  int y, isOver = 0;
2635  if(p->showButtons){
2636  //if(p->pmenu.top)
2637  // y = mouseY;
2638  //else
2639  // y = p->screenHeight - mouseY - p->pmenu.yoffset;
2640  if(p->pmenu.top)
2641  y = p->vport.H - mouseY;
2642  else
2643  y = mouseY - p->pmenu.yoffset;
2644  if( y >= 0 && y <= p->buttonSize * p->buttonRows) isOver = 1;
2645  }
2646  return isOver;
2647 }
2648 int overStatusbar(ppstatusbar p, int mouseY){
2649  int isOver = 0;
2650  //p->screenHeight - mouseY < p->clipPlane
2651  //if(p->screenHeight - mouseY < p->statusBarSize) isOver = 1;
2652  if(mouseY < p->statusBarSize * p->statusBarRows) isOver = 1;
2653  //if(p->show_status){
2654  //y = p->screenHeight - mouseY;
2655  //if(y >= p->side_bottom && y <= p->side_bottom + p->statusBarSize) isOver = 1;
2656  //}
2657  return isOver;
2658 }
2659 //void fwl_getWindowSize(int *width, int *height);
2660 //void fwl_getWindowSize1(int windex, int *width, int *height);
2661 
2662 //void updateWindowSize(){
2663 // //call this one when rendering the statusbarHud.
2664 // //the libfreewrl rendering loop should have setScreenDim to the appropriate values
2665 // int width, height;
2666 // ppstatusbar p;
2667 // ttglobal tg = gglobal();
2668 // p = (ppstatusbar)tg->statusbar.prv;
2669 // fwl_getWindowSize(&width,&height);
2670 // p->screenWidth = width;
2671 // p->screenHeight = height;
2672 //}
2673 //void updateWindowSize1(int windex){
2674 // //call this one when recieving window events
2675 // //windex: index of targetwindow
2676 // int width, height;
2677 // ppstatusbar p;
2678 // ttglobal tg = gglobal();
2679 // p = (ppstatusbar)tg->statusbar.prv;
2680 // fwl_getWindowSize1(windex,&width,&height);
2681 // p->screenWidth = width;
2682 // p->screenHeight = height;
2683 //}
2684 void updateViewportSize(){
2685  Stack *vportstack;
2686  ppstatusbar p;
2687  ttglobal tg = gglobal();
2688  p = (ppstatusbar)tg->statusbar.prv;
2689 
2690  vportstack = (Stack*)tg->Mainloop._vportstack;
2691  p->vport = stack_top(ivec4,vportstack); //should be same as stack bottom, only one on stack here
2692 }
2693 void updateSBHRows(){
2694  ppstatusbar p;
2695  ttglobal tg = gglobal();
2696  p = (ppstatusbar)tg->statusbar.prv;
2697  //I think there's a 5 pixel lead gap, 2x=10
2698  if(p->vport.W < ((p->buttonSize * p->pmenu.nbitems) + 10)){
2699  p->buttonRows = 2;
2700  p->statusBarRows = 1; //not sure I need 2
2701  }else{
2702  p->buttonRows = 1;
2703  p->statusBarRows = 1;
2704  }
2705 }
2706 int handleStatusbarHud1(int mev, int butnum, int mouseX, int mouseY, int windex)
2707 {
2708  int mouseYY;
2709  ppstatusbar p;
2710  ttglobal tg = gglobal();
2711  p = (ppstatusbar)tg->statusbar.prv;
2712 
2713  //printf("in handleStatusbarHud1 mev %d butnum %d x %d y %d wx %d\n",mev,butnum,mouseX,mouseY,windex);
2714  //updateWindowSize1(windex);
2715  mouseYY = mouseY; // - p->pmenu.yoffset;
2716  //if butnum == 0 for press or release, it means we are in a so-called up-drag
2717  if ((mev == ButtonPress) || (mev == ButtonRelease) )
2718  {
2719  /* record which button is down */
2720  /* >>> statusbar hud */
2721  int ihit = 0;
2722  //if (p->showButtons)
2723  if(overMenubar(p,mouseY))
2724  {
2725  if (mev == ButtonRelease){
2726  ihit = handleButtonRelease(mouseX,mouseYY);
2727  if(!ihit){
2728  //if its over the menubar on mouseup, but no button hit...
2729  //.. then we toggle menu and or statusbar
2730  p->menubar_pinned = 1 - p->menubar_pinned;
2731  fwl_get_sbh_pin(&p->statusbar_pinned, &p->menubar_pinned);
2732  p->menubar_pinned = 1 - p->menubar_pinned;
2733  fwl_set_sbh_pin(p->statusbar_pinned, p->menubar_pinned);
2734  if(!p->menubar_pinned)
2735  toggleMenu(0); //toggle self off
2736  else
2737  if(!p->statusbar_pinned && !p->showStatus)
2738  p->showStatus = 1; //turn menubar back on if not pinned, not showing, and menubar is pinned
2739  }
2740  }
2741  if (mev == ButtonPress){
2742  if (showAction(p, ACTION_HELP)) {
2743  int ib_over;
2744  ib_over = handleButtonOver(mouseX, mouseYY);
2745  if (ib_over > -1)
2746  update_status((char *)p->pmenu.bitems[ib_over].item->help);
2747  else
2748  update_status(NULL);
2749  }
2750  ihit = 1; //ButtonPress or release, swallow click so scene doesn't get it
2751  }
2752  }else if(overStatusbar(p,mouseY)){
2753  //someone may be touching the statusbar (or statusbar zone) to bring up the menubar and/or statusbar
2754  if(mev == ButtonRelease){
2755  if(p->wantButtons && !p->showButtons) toggleMenu(1); //toggle menubar on
2756  if(p->wantStatusbar && !p->statusbar_pinned ) p->showStatus = 1 - p->showStatus; //toggle self
2757  }
2758  ihit = 1; //ButtonPress or release on statusbar: swallow click so scene doesn't get it
2759  }
2760  //if(p->showOptions)
2761  if (!ihit && showAction(p, ACTION_OPTIONS))
2762  {
2763  if (mev == ButtonPress)
2764  ihit = handleOptionPress(mouseX,mouseYY);
2765  //return 1;
2766  }
2767  if (ihit) return 1;
2768  }
2769  if (mev == MotionNotify)
2770  {
2771  if (p->pmenu.top){
2772 #if defined(KIOSK)
2773  toggleMenu(1);
2774 #elif defined(_MSC_VER)
2775  //if input device is a mouse, mouse over statusbar to bring down menu
2776  //else call toggleMenu from main program on some window event
2777  static int lastover;
2778  if (p->vport.H - mouseYY < 16)
2779  {
2780  if (!lastover)
2781  toggleMenu(1 - p->showButtons);
2782  //p->showButtons = 1 - p->showButtons;
2783  lastover = 1;
2784  }
2785  else{
2786  lastover = 0;
2787  }
2788 #endif
2789  if (p->showButtons == 1){
2790  int ihit;
2791  //updateViewCursorStyle(ACURSE);
2792  //setArrowCursor();
2793  ihit = handleButtonOver(mouseX,mouseYY);
2794  if (ihit) return 1;
2795  //return 1; /* don't process for navigation */
2796  }
2797  }
2798  else{
2799  /* buttons at bottom, unpinned menu brought up by mouse-over statusbar
2800  and kept up by mouse over menubar
2801  */
2802  //if (p->screenHeight - mouseY < p->clipPlane) //clipline)
2803  if(overMenubar(p,mouseY) || overStatusbar(p,mouseY))
2804  {
2805  p->showButtons = p->wantButtons;
2806  //if( p->screenHeight - mouseYY > 0 ){
2807  if(overMenubar(p,mouseY)){
2808  //setArrowCursor();
2809  if(showAction(p, ACTION_HELP)){
2810  int ib_over;
2811  ib_over = handleButtonOver(mouseX,mouseYY);
2812  if(ib_over > -1)
2813  update_status((char *)p->pmenu.bitems[ib_over].item->help);
2814  else
2815  update_status(NULL);
2816  }
2817  }
2818  //setArrowCursor();
2819  //updateViewCursorStyle(ACURSE);
2820  return 1; /* don't process for navigation */
2821  }
2822  else
2823  {
2824  p->showButtons = p->menubar_pinned;
2825  }
2826  }
2827  //if(p->showOptions)
2828  if (showAction(p, ACTION_OPTIONS))
2829  {
2830  /* let HUD options menu swallow button clicks */
2831  return 1;
2832  }
2833  /* <<< statusbar hud */
2834  }
2835  return 0;
2836 }
2837 // call a few functions from the display event handlers, such as resize
2838 //void statusbar_set_window_size(int width, int height)
2839 //{
2840 // //Nov 2015: this function is obsolete: frontend event handler just calls fwl_setScreenDim(wi,hi)
2841 // // and statusbarHud polls the model on mouse and render for the current wi,hi
2842 // // ie updateWindowSize() updateWindowSize1(windex)
2843 // ttglobal tg = gglobal();
2844 // ppstatusbar p = (ppstatusbar)tg->statusbar.prv;
2845 // p->vport.H = height;
2846 // p->vport.W = width;
2847 // fwl_setScreenDim(width, height);
2848 // //if(1) fwl_setScreenDim2(5,10,width-10,height-20); //test vport, screenDim2
2849 //}
2850 int getCursorStyle();
2851 int statusbar_handle_mouse1(int mev, int butnum, int mouseX, int yup, int windex)
2852 {
2853  int vpx, vpy, iret, ihandled;
2854  ttglobal tg = gglobal();
2855  ppstatusbar p = (ppstatusbar)tg->statusbar.prv;
2856  updateViewportSize();
2857  updateSBHRows();
2858  //updateWindowSize1(windex);
2859  //yup = p->screenHeight - mouseY;
2860  vpy = yup - p->vport.Y;
2861  vpx = mouseX - p->vport.X;
2862  ihandled = handleStatusbarHud1(mev, butnum, vpx, vpy, windex);
2863  iret = 0;
2864  if (!ihandled){
2865  fwl_set_frontend_using_cursor(FALSE);
2866  }else{
2867  fwl_set_frontend_using_cursor(TRUE);
2868  iret = 1;
2869  }
2870  return iret;
2871 }
2872 int statusbar_handle_mouse(int mev, int butnum, int mouseX, int mouseY)
2873 {
2874  return statusbar_handle_mouse1(mev,butnum,mouseX,mouseY,0);
2875 }
2876 
2877 char *getMessageBar(); //in common.c
2878 char *fwl_getKeyChord();
2879 void fwl_setClipPlane(int height);
2880 int fwl_get_sbh_wantMenubar();
2881 int fwl_get_sbh_wantStatusbar();
2882 void drawStatusBarSide()
2883 {
2884 }
2885 void update_pinned(){
2886  ppstatusbar p;
2887  ttglobal tg = gglobal();
2888  p = (ppstatusbar)tg->statusbar.prv;
2889  fwl_get_sbh_pin(&p->statusbar_pinned,&p->menubar_pinned);
2890  p->wantButtons = fwl_get_sbh_wantMenubar();
2891  p->wantStatusbar = fwl_get_sbh_wantStatusbar();
2892 }
2893 void update_density(){
2894  float density_factor;
2895  int ifactor;
2896  ppstatusbar p;
2897  ttglobal tg = gglobal();
2898  p = (ppstatusbar)tg->statusbar.prv;
2899  density_factor = fwl_getDensityFactor();
2900  ifactor = (int)(density_factor + .5f);
2901  ifactor = max(1,ifactor);
2902  p->bmScaleRegular = ifactor;
2903  p->bmScale = ifactor;
2904  p->bmScaleForOptions = ifactor;
2905  //Q. what do I need to recompute?
2906  p->statusBarSize = p->bmScaleRegular * 16;
2907  p->buttonSize = (int)(density_factor * 32);
2908 }
2909 int statusbar_getClipPlane(){
2910  int vrml_clipplane;
2911  int statusbar_height, menubar_height;
2912  ppstatusbar p;
2913  ttglobal tg = gglobal();
2914  p = (ppstatusbar)tg->statusbar.prv;
2915  //vrml_clipplane is for contenttype_statusbar to know its vrml area of the screen, which it clears,
2916  // and centers its sub-contents in
2917  //unpinned menu and status are not used for calculating what's left for vrml, because
2918  // being unpinned they are always changing and it can get irritating watching the vrml content continuously resizing
2919  // every time you bring up the menu or statusbar.
2920  statusbar_height = (p->statusbar_pinned && p->wantStatusbar)? p->statusBarSize * p->statusBarRows : 0;
2921  menubar_height = (p->menubar_pinned && p->wantButtons) ? p->buttonSize * p->buttonRows : 0;
2922  vrml_clipplane = statusbar_height + menubar_height;
2923  return vrml_clipplane;
2924 
2925 }
2926 char *getDistBar();
2927 void drawStatusBar()
2928 {
2929  /* drawStatusBar() is called just before swapbuffers in mainloop so anything that you want to render 2D
2930  (non-scene things like browser status messages FPS,
2931  browser control option buttons (menu bar) and checkboxes, console error messages)
2932  you can put in here.
2933  Ideally things like buttons and status could be hidden/optional/configurable, since some
2934  applications don't want to give option control to the user - for example a museum kiosk application -
2935  and some applications have gui widgets for it.
2936 
2937  The interface that statusbarHud implements
2938  let S be statusbar, M be menubar, C be console and H be options+help
2939 S drawStatusBar() - call before swapbuffers in mainloop
2940 
2941  The interface statusbarHud requires other modules to implement to serve it:
2942  //already implemented
2943 MH int currentX[0],currentY[0] - mouse coords
2944 CH int screenHeight - in pixels
2945 H Viewer.(various stereo params)
2946  //new requirements for statusbarHud:
2947 H void setStereo(int type); //implement in viewer.c
2948 H void toggleOrSetStereo(int type); // "
2949 H void setAnaglyphSideColor(char color, int iside); //"
2950 H void updateEyehalf(); //"
2951 M viewer_level_to_bound(); //"
2952 M void toggle_collision() //"
2953  */
2954  char *pp;
2955  int i,nsides, menu_over_status;
2956  GLfloat side_bottom_f;
2957  ppstatusbar p;
2958  ttglobal tg = gglobal();
2959  p = (ppstatusbar)tg->statusbar.prv;
2960 
2961  update_ui_colors();
2962  update_pinned();
2963  update_density();
2964 // if(!p->wantStatusbar) return;
2965  //init-once things are done everytime for convenience
2966  //fwl_setClipPlane(p->statusBarSize);
2967  if(!p->fontInitialized) initFont();
2968  if(p->programObject == 0) initProgramObject();
2969  //MVC statusbarHud is in View and Controller just called us and told us
2970  //..to poll the Model to update and draw ourself
2971  updateViewportSize();
2972  updateSBHRows();
2973  //updateWindowSize();
2974  updateButtonStatus(); //poll Model for some button state
2975  updateConsoleStatus(); //poll Model for console text
2976 
2977  glDepthMask(GL_FALSE);
2978  glDisable(GL_DEPTH_TEST);
2979  p->posType = 1; // use RasterPos2i instead of WindowPos2i
2980  glUseProgram ( p->programObject );
2981  glViewport(p->vport.X, p->vport.Y, p->vport.W, p->vport.H); //screenWidth, p->screenHeight);
2982 
2983  p->show_menu = p->wantButtons && (p->menubar_pinned || p->showButtons);
2984  menu_over_status = !p->menubar_pinned && p->showButtons;
2985  p->show_status = p->wantStatusbar && ((p->showStatus || p->statusbar_pinned) && !menu_over_status);
2986  p->show_status = p->show_status || showAction(p, ACTION_HELP); //if ? help button on, then show statusbar to get button hints
2987 
2988 
2989 
2990  p->yoff_status = 0;
2991  //p->pmenu.yoffset = (p->menubar_pinned || !p->statusbar_pinned) ? p->statusBarSize : 0;
2992  p->pmenu.yoffset = p->show_status ? p->statusBarSize * p->statusBarRows : 0;
2993 
2994  //p->clipPlane is for statusbarHud to glClear an area the background color of the status and/or menubar
2995  p->clipPlane = (p->show_menu ? p->buttonSize * p->buttonRows : 0) + p->show_status ? p->statusBarSize * p->statusBarRows : 0; //(p->show_status ? p->statusBarSize : 0);
2996  //vrml_clipplane is for libfreewrl to know its vrml area of the screen, which it clears, and centers the scene in
2997  //unpinned menu and status are not used for calculating what's left for vrml, because
2998  // being unpinned they are always changing and it can get irritating watching the vrml content continuously resizing
2999  // every time you bring up the menu or statusbar.
3000  //vrml_clipplane = (p->statusbar_pinned && p->wantStatusbar ? p->statusBarSize : 0) + (p->menubar_pinned && p->wantButtons ? p->buttonSize : 0);
3001  //fwl_setClipPlane(vrml_clipplane); //p->clipPlane);
3002 
3003  nsides = 1;
3004  if (Viewer()->updown) nsides = 2; //one stereo mode updown draws the menubar and/or statusbar twice, once for each stereo side
3005  for (i = 0; i < nsides; i++)
3006  {
3007  p->side_top = 0;
3008  p->side_bottom = 0;
3009  side_bottom_f = -1.0f;
3010  if (Viewer()->updown){
3011  //the upper viewport is the left stereo side is i==0
3012  p->side_top = i*(p->vport.H / 2);
3013  p->side_bottom = (1 -i) *(p->vport.H /2);
3014  if(i == 0) side_bottom_f = 0.0f;
3015  }
3016 
3017  if (p->show_menu) //p->showButtons)
3018  {
3019  renderButtons();
3020 #ifndef KIOSK
3021  glDepthMask(GL_TRUE);
3022  if (p->posType == 1) {
3023  glEnable(GL_DEPTH_TEST);
3024  }
3025  //continue;
3026 #endif
3027  }
3028  if(p->show_status)
3029  {
3030  int sblen, sslen,itrim;
3031  FXY xy;
3032  /* OK time to update the status bar */
3033  /* unconditionally clear the statusbar area */
3034  itrim = 0;
3035  #ifdef ANGLEPROJECT
3036  itrim = 1; //if width of window it floods entire window instead of just menubar
3037  #endif
3038 
3039  glScissor(p->vport.X, p->vport.Y + p->side_bottom, p->vport.W -itrim, p->statusBarSize * p->statusBarRows); //p->clipPlane);
3040  glEnable(GL_SCISSOR_TEST);
3041  //glClearColor(.922f, .91f, .844f, 1.0f); //windowing gray
3042  glClearColor(colorClear[0],colorClear[1],colorClear[2],colorClear[3]);
3043  glClear(GL_COLOR_BUFFER_BIT);
3044  glDisable(GL_SCISSOR_TEST);
3045 
3046  // you must call drawStatusBar() from render() just before swapbuffers
3047  glDepthMask(FALSE);
3048  glDisable(GL_DEPTH_TEST);
3049 
3050  //glUniform4f(p->color4fLoc, .2f, .2f, .2f, 1.0f);
3051  glUniform4f(p->color4fLoc,colorStatusbarText[0],colorStatusbarText[1],colorStatusbarText[2],colorStatusbarText[3]);
3052  xy = screen2normalizedScreenScale((GLfloat)p->bmWH.x, (GLfloat)p->bmWH.y);
3053  xy.x *= p->bmScale; //apply density_factor scale
3054  xy.y *= p->bmScale;
3055  sblen = (int)(2.0f/xy.x);
3056  sblen -= 4; //FPS chars - (9+7); //get number of chars left after touch status and vp status
3057  sslen = 0;
3058  {
3059  pp = get_status(); // p->buffer;
3060  /* print status bar text - things like PLANESENSOR */
3061  //printString2(-1.0f + xy.x*5.0f, side_bottom_f, pp);
3062  sslen = strlen(pp);
3063  printString2(-1.0f, side_bottom_f, pp);
3064  p->hadString = 1;
3065  }
3066  {
3067  int len, istart,istart1,ilen,lenk,lenkk;
3068  char *strfps, *strdist, *strstatus, *strAkeys;
3069 
3070  //squeeze status and optionally keychord into remaining space
3071  strAkeys = fwl_getKeyChord(); //keychord like YAWZ or YAWPITCH
3072  lenkk = lenk = strlen(strAkeys); //9 maximum
3073 
3074  strstatus = getMenuStatus(); //viewpoint name, other status
3075  len = strlen(strstatus);
3076  ilen = len;
3077 
3078  istart1 = sslen +1; //minimum start location
3079  if(max(istart1,35) + len + 9 < sblen) {
3080  lenkk = 9; //lots of room for keychord and status
3081  istart = max(istart1,35);
3082  }else if(istart1 + len + 9 < sblen){
3083  lenkk = 9;
3084  istart = istart1;
3085  }else if(istart1 + len + lenkk < sblen){
3086  istart = istart1;
3087  lenkk= lenkk;
3088  }else if(p->buttonRows == 2){
3089  istart = istart1;
3090  lenkk = 0; //mobile portrait, don't need keychord
3091  ilen = sblen - istart;
3092  }else{
3093  istart = istart1;
3094  lenkk = lenkk;
3095  ilen = sblen - istart - lenkk;
3096  }
3097  //istart2 = min(35,sblen - len);
3098  //istart = max(istart1, istart2);
3099  //ilen = max(0,min(len,sblen-istart));
3100  printString3(-1.0f + xy.x*istart, side_bottom_f, strstatus,ilen);
3101 
3102  if(lenkk){
3103  //on mobile, you tend not to use keychords - just touch, and in portrait, with statusBarRows == 1 its too crowded
3104  printString3(1.0f - xy.x*(lenk + 4), side_bottom_f, strAkeys,lenk); //max 9 wide
3105  }
3106  //always draw FPS
3107  strfps = getFpsBar(); //FPS
3108  printString2(1.0f - xy.x*(4), side_bottom_f, strfps); //4 wide
3109  strdist = getDistBar(); //Viewer.Dist
3110  printString2(1.0f - xy.x*(22), side_bottom_f, strdist); //6 wide
3111  }
3112 
3113  }
3114 
3115  //glUniform4f(p->color4fLoc, 1.0f, 1.0f, 1.0f, 1.0f);
3116  glUniform4f(p->color4fLoc,colorMessageText[0],colorMessageText[1],colorMessageText[2],colorMessageText[3]);
3117  //glDisable(GL_SCISSOR_TEST); //ideally this would scissor everything but statusbar+menu so we don't overwrite bars
3118  if (showAction(p, ACTION_HELP))
3119  printKeyboardHelp(p);
3120  if (showAction(p, ACTION_MESSAGES))
3121  printConsoleText();
3122  if (showAction(p, ACTION_OPTIONS))
3123  printOptions();
3124  }
3125  //rely on Model to reset clearcolor on each frame. glClearColor(0.0f,0.0f,0.0f,1.0f);
3126  glDepthMask(TRUE);
3127  glEnable(GL_DEPTH_TEST);
3128 }
3129 
3130 #else //ifdef STATUSBAR_HUD
3131 //stubs
3132 int statusbar_getClipPlane(){
3133  return 0;
3134 }
3135 int statusbar_handle_mouse1(int mev, int butnum, int mouseX, int yup, int windex){
3136  return 0; //not handled
3137 }
3138 #endif
3139 
Definition: Viewer.h:196
Definition: list.h:37
Definition: Vector.h:36
Definition: display.c:65
Definition: CursorDraw.c:211