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