mirror of https://github.com/BOINC/boinc.git
512 lines
12 KiB
C
Executable File
512 lines
12 KiB
C
Executable File
//#include <afx.h> // for ASSERT
|
|
// The contents of this file are subject to the BOINC Public License
|
|
// Version 1.0 (the "License"); you may not use this file except in
|
|
// compliance with the License. You may obtain a copy of the License at
|
|
// http://boinc.berkeley.edu/license_1.0.txt
|
|
//
|
|
// Software distributed under the License is distributed on an "AS IS"
|
|
// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing rights and limitations
|
|
// under the License.
|
|
//
|
|
// The Original Code is the Berkeley Open Infrastructure for Network Computing.
|
|
//
|
|
// The Initial Developer of the Original Code is the SETI@home project.
|
|
// Portions created by the SETI@home project are Copyright (C) 2002
|
|
// University of California at Berkeley. All Rights Reserved.
|
|
//
|
|
// Contributor(s):
|
|
//
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#ifdef _WIN32
|
|
#include <windows.h>
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#include <glut.h>
|
|
#endif
|
|
#ifdef __APPLE_CC__
|
|
#include <OpenGL/gl.h>
|
|
#include <GLUT/glut.h>
|
|
#endif
|
|
#ifdef unix
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#include <GL/glut.h>
|
|
#endif
|
|
|
|
#include "gutil.h"
|
|
GLfloat mat_diffuse[] = {0.7, 0.5, 1.0, 0.4};
|
|
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
|
|
GLfloat mat_shininess[] = {40.0};
|
|
|
|
void mode_shaded(GLfloat* color) {
|
|
glEnable(GL_DEPTH_TEST);
|
|
glEnable(GL_LIGHTING);
|
|
glEnable(GL_LIGHT0);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glShadeModel (GL_SMOOTH);
|
|
glDepthMask(GL_TRUE);
|
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, color);
|
|
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
|
|
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
|
|
}
|
|
|
|
void mode_texture() {
|
|
glMatrixMode( GL_MODELVIEW );
|
|
glLoadIdentity();
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_LIGHT0);
|
|
}
|
|
|
|
void mode_unshaded() {
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_LIGHT0);
|
|
glEnable(GL_BLEND);
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glShadeModel (GL_SMOOTH);
|
|
glDepthMask(GL_TRUE);
|
|
}
|
|
|
|
void mode_lines() {
|
|
glEnable(GL_BLEND);
|
|
glDisable(GL_LIGHTING);
|
|
glDisable(GL_LIGHT0);
|
|
//glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
//glDepthMask(GL_TRUE);
|
|
//glEnable(GL_LINE_SMOOTH);
|
|
//glHint(GL_LINE_SMOOTH, GL_NICEST);
|
|
//glDisable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
static double HuetoRGB(double m1, double m2, double h ) {
|
|
if( h < 0 ) h += 1.0;
|
|
if( h > 1 ) h -= 1.0;
|
|
if( 6.0*h < 1 ) return (m1+(m2-m1)*h*6.0);
|
|
if( 2.0*h < 1 ) return m2;
|
|
if( 3.0*h < 2.0 ) return (m1+(m2-m1)*((2.0/3.0)-h)*6.0);
|
|
return m1;
|
|
}
|
|
|
|
void HLStoRGB( double H, double L, double S, COLOR& c) {
|
|
double m1, m2;
|
|
|
|
if(S==0) {
|
|
c.r=c.g=c.b=L;
|
|
} else {
|
|
if(L <=0.5)
|
|
m2 = L*(1.0+S);
|
|
else
|
|
m2 = L+S-L*S;
|
|
m1 = 2.0*L-m2;
|
|
c.r = HuetoRGB(m1,m2,H+1.0/3.0);
|
|
c.g = HuetoRGB(m1,m2,H);
|
|
c.b = HuetoRGB(m1,m2,H-1.0/3.0);
|
|
}
|
|
}
|
|
|
|
float frand() {
|
|
return rand()/(float)RAND_MAX;
|
|
}
|
|
|
|
void drawSphere(GLfloat* pos, GLfloat rad) {
|
|
GLUquadricObj* x = gluNewQuadric();
|
|
glPushMatrix();
|
|
glTranslatef(pos[0], pos[1], pos[2]);
|
|
gluSphere(x, rad, 20, 20);
|
|
gluDeleteQuadric(x);
|
|
glPopMatrix();
|
|
}
|
|
|
|
void drawCylinder(bool vertical, GLfloat* pos, GLfloat len, GLfloat rad) {
|
|
GLUquadricObj* x = gluNewQuadric();
|
|
glPushMatrix();
|
|
glTranslatef(pos[0], pos[1], pos[2]);
|
|
if (vertical) {
|
|
glRotated(-90., 1., 0., 0.);
|
|
} else {
|
|
glRotated(90., 0., 1., 0.);
|
|
}
|
|
gluCylinder(x, rad, rad, len, 20, 1);
|
|
gluDeleteQuadric(x);
|
|
glPopMatrix();
|
|
}
|
|
|
|
#define STROKE_SCALE 120
|
|
// GLUT stroke characters are about 120 units high
|
|
|
|
GLfloat text_width(char* text) {
|
|
GLfloat sum = 0;
|
|
char* p;
|
|
|
|
for (p=text; *p; p++) {
|
|
sum += glutStrokeWidth(GLUT_STROKE_ROMAN, *p);
|
|
}
|
|
return sum/STROKE_SCALE;
|
|
}
|
|
|
|
static void draw_text_line_aux(char *text) {
|
|
char *p;
|
|
for (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]);
|
|
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_line(
|
|
GLfloat* _pos, GLfloat char_height, GLfloat line_width, 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 multiple lines of text
|
|
//
|
|
void draw_text(
|
|
GLfloat* _pos, GLfloat char_height, GLfloat line_width,
|
|
GLfloat line_spacing, char* text
|
|
) {
|
|
char* q, *p;
|
|
char buf[4096];
|
|
GLfloat pos[3];
|
|
memcpy(pos, _pos, sizeof(pos));
|
|
strcpy(buf, text);
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
// draw a rectangle of the given color in the XY plane
|
|
// and draw the given test in it
|
|
//
|
|
void draw_text_panel(
|
|
GLfloat* _pos, GLfloat* size, GLfloat margin, COLOR color,
|
|
GLfloat char_height, GLfloat line_width, GLfloat line_spacing,
|
|
char* text
|
|
) {
|
|
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
|
|
//
|
|
color.r /= 2;
|
|
color.g /= 2;
|
|
color.b /= 2;
|
|
glColor4fv(&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);
|
|
draw_text(pos3, char_height, line_width, line_spacing, text);
|
|
}
|
|
|
|
PROGRESS::PROGRESS(
|
|
GLfloat* p, GLfloat l, GLfloat r, GLfloat in, GLfloat* c, GLfloat* ic
|
|
) {
|
|
memcpy(pos, p, sizeof(pos));
|
|
len = l;
|
|
rad = r;
|
|
inner_rad = in;
|
|
memcpy(color, c, sizeof(color));
|
|
memcpy(inner_color, ic, sizeof(inner_color));
|
|
}
|
|
|
|
void PROGRESS::draw(float x) {
|
|
mode_shaded(inner_color);
|
|
drawCylinder(false, pos, x*len, inner_rad);
|
|
mode_shaded(color);
|
|
drawCylinder(false, pos, len, rad);
|
|
}
|
|
|
|
GRAPH_2D::GRAPH_2D(float* p, float* s, float* c, float* tc) {
|
|
memcpy(pos, p, sizeof(pos));
|
|
memcpy(size, s, sizeof(size));
|
|
memcpy(color, c, sizeof(color));
|
|
memcpy(tick_color, tc, sizeof(tick_color));
|
|
}
|
|
|
|
float yvec[] = {0., 1., 0.};
|
|
float xvec[] = {1., 0., 0.};
|
|
float xvecneg[] = {-1., 0., 0.};
|
|
float zvec[] = {0, 0, 1};
|
|
|
|
// draw horizontal plate from i to i+1, with height data[i]
|
|
//
|
|
void GRAPH_2D::draw_x(int i) {
|
|
GLfloat pt[3];
|
|
double r1 = i/(double)len;
|
|
double r2 = (i+1)/(double)len;
|
|
|
|
glNormal3fv(yvec);
|
|
pt[0] = pos[0] + r1*size[0];
|
|
pt[1] = pos[1] + data[i]*size[1]/dmax;
|
|
pt[2] = pos[2];
|
|
glVertex3fv(pt);
|
|
pt[0] = pos[0] + r2*size[0];
|
|
glVertex3fv(pt);
|
|
pt[2] = pos[2] + size[2];
|
|
glVertex3fv(pt);
|
|
pt[0] = pos[0] + r1*size[0];
|
|
glVertex3fv(pt);
|
|
glNormal3fv(zvec);
|
|
pt[0] = pos[0] + r1*size[0];
|
|
pt[1] = pos[1] + data[i]*size[1]/dmax;
|
|
pt[2] = pos[2]+size[2];
|
|
glVertex3fv(pt);
|
|
pt[1] = pos[1];
|
|
glVertex3fv(pt);
|
|
pt[0] = pos[0] + r2*size[0];
|
|
glVertex3fv(pt);
|
|
pt[1] = pos[1] + data[i]*size[1]/dmax;
|
|
glVertex3fv(pt);
|
|
}
|
|
|
|
// draw vertical plate at position i, with height from data[i-1] to data[i]
|
|
//
|
|
void GRAPH_2D::draw_y(int i) {
|
|
GLfloat pt[3];
|
|
double r1 = i/(double)len;
|
|
|
|
(data[i]>data[i-1])?glNormal3fv(xvecneg):glNormal3fv(xvec);
|
|
pt[0] = pos[0] + r1*size[0];
|
|
pt[1] = pos[1] + data[i-1]*size[1]/dmax;
|
|
pt[2] = pos[2];
|
|
glVertex3fv(pt);
|
|
pt[1] = pos[1] + data[i]*size[1]/dmax;
|
|
glVertex3fv(pt);
|
|
pt[2] = pos[2] + size[2];
|
|
glVertex3fv(pt);
|
|
pt[1] = pos[1] + data[i-1]*size[1]/dmax;
|
|
glVertex3fv(pt);
|
|
}
|
|
|
|
void GRAPH_2D::draw(float* d, int ln) {
|
|
int i;
|
|
|
|
data = d;
|
|
len = ln;
|
|
dmax = 0;
|
|
for (i=0; i<len; i++) {
|
|
if (data[i] > dmax) dmax = data[i];
|
|
}
|
|
|
|
mode_shaded(color);
|
|
glBegin(GL_QUADS);
|
|
draw_x(0);
|
|
for (i=1; i<len-1; i++) {
|
|
draw_y(i);
|
|
draw_x(i);
|
|
}
|
|
draw_x(len-1);
|
|
glEnd();
|
|
}
|
|
|
|
void GRAPH_2D::add_tick(float x, float yfrac) {
|
|
}
|
|
|
|
// read a PPM file
|
|
// to generate PPM from JPEG:
|
|
// mogrify -format ppm foo.jpg
|
|
// or xv foo.jpg; right click on image, choose PPM
|
|
//
|
|
int read_ppm_file(char* name, int& w, int& h, unsigned char** arrayp) {
|
|
FILE* f;
|
|
char buf[256];
|
|
char img_type;
|
|
unsigned char* array;
|
|
int i;
|
|
|
|
f = fopen(name, "rb");
|
|
if (!f) return -1;
|
|
do {fgets(buf, 256, f);} while (buf[0] == '#');
|
|
if (buf[0] != 'P') {
|
|
return -1;
|
|
}
|
|
img_type = buf[1];
|
|
do {fgets(buf, 256, f);} while (buf[0] == '#');
|
|
sscanf(buf, "%d %d", &w, &h);
|
|
do {fgets(buf, 256, f);} while (buf[0] == '#');
|
|
array = (unsigned char*)malloc(w*h*3);
|
|
switch(img_type) { // TODO: pad image dimension to power of 2
|
|
case '3':
|
|
for (i=0; i<w*h*3; i++) {
|
|
fscanf(f, "%d", array+i);
|
|
}
|
|
case '6':
|
|
fread(array, 3, w*h, f);
|
|
break;
|
|
}
|
|
*arrayp = array;
|
|
return 0;
|
|
}
|
|
|
|
unsigned int texture_id;
|
|
|
|
int init_texture(char* filename) {
|
|
unsigned char* pixels;
|
|
int width, height, retVal;
|
|
int err;
|
|
retVal = read_ppm_file(filename, width, height, &pixels);
|
|
if (retVal) return retVal;
|
|
glGenTextures(1, &texture_id);
|
|
err = glGetError();
|
|
if (err) return err;
|
|
glBindTexture(GL_TEXTURE_2D, texture_id);
|
|
err = glGetError();
|
|
if (err) return err;
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
err = glGetError();
|
|
if (err) return err;
|
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
err = glGetError();
|
|
if (err) return err;
|
|
//ASSERT(0);
|
|
glTexImage2D(
|
|
GL_TEXTURE_2D,
|
|
0,
|
|
3,
|
|
//0,
|
|
//0,
|
|
width,
|
|
height,
|
|
0,
|
|
GL_RGB,
|
|
GL_UNSIGNED_BYTE,
|
|
pixels // dimension of PPM file MUST be power of 2
|
|
);
|
|
err = glGetError();
|
|
if (err) {
|
|
fprintf(stderr, "glTexImage2D returned error # %d: %s\n", err, gluErrorString(err));
|
|
return err;
|
|
}
|
|
return 0;
|
|
}
|
|
struct Vertex
|
|
{
|
|
float tu, tv;
|
|
float x, y, z;
|
|
};
|
|
|
|
Vertex g_quadVertices[] =
|
|
{
|
|
{ 0.0f,0.0f, -1.0f,-1.0f, 0.0f },
|
|
{ 1.0f,0.0f, 1.0f,-1.0f, 0.0f },
|
|
{ 1.0f,1.0f, 1.0f, 1.0f, 0.0f },
|
|
{ 0.0f,1.0f, -1.0f, 1.0f, 0.0f }
|
|
};
|
|
float white[4] = {1., 1., 1., 1.};
|
|
|
|
void draw_texture(float* p, float* size) {
|
|
float pos[3];
|
|
memcpy(pos, p, sizeof(pos));
|
|
glEnable(GL_TEXTURE_2D);
|
|
glBindTexture(GL_TEXTURE_2D, texture_id);
|
|
mode_shaded(white);
|
|
#if 1
|
|
glBegin(GL_QUADS);
|
|
glTexCoord2f(0., 1.);
|
|
glVertex3fv(pos);
|
|
pos[0] += size[0];
|
|
glTexCoord2f(1., 1.);
|
|
glVertex3fv(pos);
|
|
pos[1] += size[1];
|
|
glTexCoord2f(1., 0.);
|
|
glVertex3fv(pos);
|
|
pos[0] -= size[0];
|
|
glTexCoord2f(0., 0.);
|
|
glVertex3fv(pos);
|
|
glEnd();
|
|
#else
|
|
glInterleavedArrays( GL_T2F_V3F, 0, g_quadVertices );
|
|
glDrawArrays( GL_QUADS, 0, 4 );
|
|
#endif
|
|
|
|
glDisable(GL_TEXTURE_2D);
|
|
}
|