boinc/api/gutil_text.cpp

367 lines
8.7 KiB
C++

// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2008 University of California
//
// BOINC is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version.
//
// BOINC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
// The part of BOINC's graphics utilities that uses GLUT char-drawing
#if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_)
#include "boinc_win.h"
#else
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <setjmp.h>
#ifdef _WIN32
#ifdef __cplusplus
extern "C" {
#include "jpeglib.h"
}
#else
#include "jpeglib.h"
#endif
#endif
#ifndef _WIN32
extern "C"{
#include <jpeglib.h>
}
#endif
#include "boinc_gl.h"
#include "boinc_glut.h"
#include "filesys.h"
#include "str_util.h"
#include "str_replace.h"
#include "gutil.h"
#define STROKE_SCALE 120
// GLUT stroke characters are about 120 units high
GLfloat text_width(const char* text) {
GLfloat sum = 0;
for (const char* p = text; *p; p++) {
sum += glutStrokeWidth(GLUT_STROKE_ROMAN, *p);
}
return sum/STROKE_SCALE;
}
static void draw_text_line_aux(const char *text) {
for (const char* p = text; *p; p++) {
glutStrokeCharacter(GLUT_STROKE_ROMAN, *p);
}
}
static void draw_text_start(GLfloat* pos, GLfloat char_height, GLfloat line_width) {
glLineWidth(line_width);
glPushMatrix();
glTranslatef(pos[0], pos[1], pos[2]);
glRasterPos3d(pos[0],pos[1],pos[2]);
float w = char_height/STROKE_SCALE;
glScalef(w, w, w);
}
static void draw_text_end() {
glPopMatrix();
}
// draw a line of text in the XY plane at the given starting position,
// character height, and line width.
void draw_text_simple(const char* text, float line_width, float char_height)
{
glLineWidth(line_width);
float w = char_height/STROKE_SCALE;
glScalef(w, w, w);
draw_text_line_aux(text);
}
void draw_text_line(
GLfloat* _pos, GLfloat char_height, GLfloat line_width, const char *text,
int justify
) {
GLfloat pos[3];
GLfloat w;
memcpy(pos, _pos, sizeof(pos));
switch(justify) {
case TEXT_LEFT:
break;
case TEXT_CENTER:
w = text_width(text);
pos[0] -= w/2;
break;
case TEXT_RIGHT:
w = text_width(text);
pos[0] -= w;
break;
}
draw_text_start(pos, char_height, line_width);
draw_text_line_aux(text);
draw_text_end();
}
// draw rotated text
void draw_rotated_text(
GLfloat* pos, GLfloat height, GLfloat width, GLfloat /*spacing*/, const char *text,
GLfloat rotation, GLfloat* rotation_vector)
{
draw_text_start(pos, height, width);
glRotatef(rotation,rotation_vector[0],rotation_vector[1],rotation_vector[2]);
draw_text_line_aux(text);
draw_text_end();
}
// draw multiple lines of text
//
void draw_text(
GLfloat* _pos, GLfloat char_height, GLfloat line_width,
GLfloat line_spacing, const char* text
) {
char* q, *p;
char buf[4096];
GLfloat pos[3];
memcpy(pos, _pos, sizeof(pos));
strlcpy(buf, text, 4096);
p = buf;
while (*p) {
q = strchr(p, '\n');
if (q) *q = 0;
draw_text_start(pos, char_height, line_width);
draw_text_line_aux(p);
draw_text_end();
pos[1] -= line_spacing;
if (!q) break;
p = q+1;
}
}
void draw_text_new_3d(
GLfloat* _pos, GLfloat /*char_height*/, GLfloat /*line_width*/,
GLfloat line_spacing, const char* text
) {
char* q, *p;
char buf[4096];
GLfloat pos[3];
memcpy(pos, _pos, sizeof(pos));
strlcpy(buf, text, 4096);
p = buf;
glPushMatrix();
glTranslatef(pos[0], pos[1], pos[2]);
while (*p) {
q = strchr(p, '\n');
if (q) *q = 0;
glRasterPos3d(pos[0],pos[1],pos[2]);
print_text(p);
pos[1] -= line_spacing;
if (!q) break;
p = q+1;
}
glPopMatrix();
}
void draw_text_new(
GLfloat* _pos, GLfloat /*char_height*/, GLfloat /*line_width*/,
GLfloat line_spacing, const char* text
) {
char *q, *p;
char buf[4096];
GLfloat pos[3];
memcpy(pos,_pos,sizeof(pos));
strlcpy(buf, text, 4096);
p=buf;
int viewport[4];
get_viewport(viewport);
while(*p) {
q = strchr(p, '\n');
if (q) *q = 0;
glRasterPos3d(pos[0],pos[1],pos[2]);
print_text(p);
pos[1] -= line_spacing;
if (!q) break;
p = q+1;
}
}
void draw_text_right(
GLfloat* _pos, GLfloat char_height, GLfloat line_width,
GLfloat line_spacing, const char* text
) {
char *q, *p;
char buf[4096];
GLfloat pos[3];
memcpy(pos,_pos,sizeof(pos));
float orig = pos[0];
strlcpy(buf, text, 4096);
p=buf;
float w;
while (*p) {
q = strchr(p, '\n');
if (q) *q = 0;
w = text_width(p)/66.5f;
pos[0] -= w;
draw_text_start(pos, char_height, line_width);
draw_text_line_aux(p);
draw_text_end();
pos[1] -= line_spacing;
pos[0]=orig;
if (!q) break;
p = q+1;
}
}
MOVING_TEXT_PANEL::MOVING_TEXT_PANEL() :
theta(0), dtheta(0), color(0), char_height(0), line_width(0), line_spacing(0), margin(0)
{
int i;
for (i=0;i<3;i++) {
base_pos[i]=size[i]=0;
}
for (i=0;i<PANEL_MAX_LINES;i++) {
memset(&(text[i][0]),0,256);
}
}
void MOVING_TEXT_PANEL::init(
float* p, float* s, COLOR& c, double d, double ch, double lw, double ls, double m
) {
memcpy(pos, p, sizeof(pos));
memcpy(base_pos, p, sizeof(base_pos));
memcpy(size, s, sizeof(size));
color = c;
theta = 0;
dtheta = d;
char_height = ch;
line_width = lw;
line_spacing = ls;
margin = m;
memset(text, 0, sizeof(text));
}
// draw a rectangle of the given color in the XY plane
// and draw the given test in it
//
void MOVING_TEXT_PANEL::draw() {
COLOR side_color = color;
GLfloat pos0[3], pos1[3], pos2[3], pos3[3];
memcpy(pos0, pos, sizeof(pos0));
memcpy(pos1, pos, sizeof(pos0));
pos1[0] += size[0];
memcpy(pos2, pos1, sizeof(pos0));
pos2[1] += size[1];
memcpy(pos3, pos2, sizeof(pos0));
pos3[0] -= size[0];
mode_unshaded();
glColor4fv(&color.r);
glBegin(GL_QUADS);
glVertex3fv(pos0);
glVertex3fv(pos1);
glVertex3fv(pos2);
glVertex3fv(pos3);
// draw flanges
//
side_color.r /= 2;
side_color.g /= 2;
side_color.b /= 2;
glColor4fv(&side_color.r);
GLfloat posa0[3], posa1[3], posa2[3], posa3[3];
memcpy(posa0, pos0, sizeof(pos0));
memcpy(posa1, pos1, sizeof(pos0));
memcpy(posa2, pos2, sizeof(pos0));
memcpy(posa3, pos3, sizeof(pos0));
posa0[2] -= .2;
posa1[2] -= .2;
posa2[2] -= .2;
posa3[2] -= .2;
glVertex3fv(pos0);
glVertex3fv(pos1);
glVertex3fv(posa1);
glVertex3fv(posa0);
glVertex3fv(pos1);
glVertex3fv(pos2);
glVertex3fv(posa2);
glVertex3fv(posa1);
glVertex3fv(pos2);
glVertex3fv(pos3);
glVertex3fv(posa3);
glVertex3fv(posa2);
glVertex3fv(pos3);
glVertex3fv(pos0);
glVertex3fv(posa0);
glVertex3fv(posa3);
glEnd();
pos3[0] += margin;
pos3[1] -= (margin+char_height);
pos3[2] += 0.01;
glColor3f(1, 1, 1);
for (int i=0; i<PANEL_MAX_LINES; i++) {
if (strlen(text[i])) {
draw_text(pos3, char_height, line_width, line_spacing, text[i]);
}
pos3[1] -= line_spacing;
}
}
void MOVING_TEXT_PANEL::set_text(int lineno, const char* str) {
char buf[8192];
strcpy(buf, str);
char* p = buf;
char* q = strchr(p, '\n');
while (p) {
if (q) *q = 0;
strlcpy(text[lineno++], p, 256);
if (!q) break;
p = q+1;
q = strchr(p, '\n');
}
}
void MOVING_TEXT_PANEL::move(double dt) {
pos[0] = base_pos[0] + sin(theta);
pos[1] = base_pos[1];
pos[2] = base_pos[2] + cos(theta);
theta += dtheta*dt;
}
void MOVING_TEXT_PANEL::get_pos(int lineno, float* p) {
memcpy(p, pos, sizeof(pos));
p[0] += margin;
p[1] += (size[1] - margin - lineno*line_spacing);
}
static int compare_tp(const void* p1, const void* p2) {
const MOVING_TEXT_PANEL* tp1=(const MOVING_TEXT_PANEL*)p1, *tp2 = (const MOVING_TEXT_PANEL*)p2;
if (tp1->pos[2] > tp2->pos[2]) return 1;
if (tp2->pos[2] > tp1->pos[2]) return -1;
return 0;
}
void MOVING_TEXT_PANEL::sort(MOVING_TEXT_PANEL* tp, int n) {
qsort(tp, n, sizeof(MOVING_TEXT_PANEL), compare_tp);
}