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