#include #include extern "C" { #include } #include "OutputGL.hxx" float OutputGL::circle_x[]; float OutputGL::circle_y[]; const float OutputGL::BRIGHTNESS = 0.6f; OutputGL::OutputGL( char *filename, int size, bool smooth_shading, bool useTexturedFont, char *fontname, bool jpg, int q, int r ) : GfxOutput(filename, size), filename(filename), useTexturedFont(useTexturedFont), jpeg(jpg), jpeg_quality(q), rescale(r) { if ( filename == NULL ) openFragment( 0, 0, size ); glEnable(GL_BLEND); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); shade = true; glEnable(GL_LIGHTING); glShadeModel(smooth_shading ? GL_SMOOTH : GL_FLAT); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); if (useTexturedFont) { font = new fntTexFont( fontname ); textRenderer.setFont( font ); textRenderer.setPointSize( 12 ); } else { glutFont = new puFont; } for (int i = 0; i < SUBDIVISIONS; i++) { circle_x[i] = cos(2*SG_PI / SUBDIVISIONS * i); circle_y[i] = sin(2*SG_PI / SUBDIVISIONS * i); } image = new GLubyte[size*size*3]; } OutputGL::~OutputGL() { delete [] image; if (useTexturedFont) { delete font; } else { delete glutFont; } } void OutputGL::openFragment( int x, int y, int s ) { fragment_size = s; posx = x; posy = y; if ( s == 0 ) s = size; glViewport( 0, 0, s, s ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( x, x+s, y, y+s, -1.0f, 1.0f ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); } void OutputGL::closeFragment() { if (!open) return; GLubyte *subimage = new GLubyte[fragment_size*fragment_size*3]; if (!subimage) return; // grab screen glFinish(); glReadPixels(0, 0, fragment_size, fragment_size, GL_RGB, GL_UNSIGNED_BYTE, subimage); int sx = fragment_size, sy = fragment_size; if ( posx + sx > size ) sx = size - posx; if ( posy + sy > size ) sy = size - posy; for ( int i = 0; i < sx; ++i ) { for ( int j = 0; j < sy; ++j ) { image[(( j+posy ) * size + ( i+posx )) * 3] = subimage[(j * fragment_size + i) * 3]; image[(( j+posy ) * size + ( i+posx )) * 3 + 1] = subimage[(j * fragment_size + i) * 3 + 1]; image[(( j+posy ) * size + ( i+posx )) * 3 + 2] = subimage[(j * fragment_size + i) * 3 + 2]; } } delete [] subimage; } void OutputGL::closeOutput() { if (!open) return; open = false; int scale = rescale; int current_size = size; while ( scale && ( scale & 1 ) == 0 ) { int new_size = current_size / 2; GLubyte *buffer = new GLubyte[new_size*new_size*3]; for ( int x2 = 0; x2 < new_size; ++x2 ) { for ( int y2 = 0; y2 < new_size; ++y2 ) { for ( int c = 0; c < 3; ++c ) { int x1 = x2 + x2; int x1_1 = x1 + 1; int y1 = y2 + y2; int y1_1 = y1 + 1; int t1 = image[ (y1 * current_size + x1 ) * 3 + c ]; int t2 = image[ (y1_1 * current_size + x1 ) * 3 + c ]; int t3 = image[ (y1 * current_size + x1_1) * 3 + c ]; int t4 = image[ (y1_1 * current_size + x1_1) * 3 + c ]; buffer[ (y2 * new_size + x2) * 3 + c ] = ( t1 + t2 + t3 + t4 ) / 4 ; } } } scale >>= 1; current_size = new_size; delete[] image; image = buffer; } FILE *fp = fopen(filename, "wb"); if (!fp) { printf("OutputGL::closeOutput: can't create '%s'\n", filename); return; } if ( jpeg ) { jpeg_compress_struct cinfo; memset( &cinfo, 0, sizeof cinfo ); jpeg_error_mgr jerr; memset( &jerr, 0, sizeof jerr ); cinfo.err = jpeg_std_error( &jerr ); jpeg_create_compress( &cinfo ); jpeg_stdio_dest( &cinfo, fp ); cinfo.image_width = current_size; cinfo.image_height = current_size; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo,jpeg_quality,false); jpeg_start_compress( &cinfo, TRUE ); while ( cinfo.next_scanline < cinfo.image_height ) { unsigned char *buf; if ( 1 ) { buf = (unsigned char *)&image[ current_size * ( current_size - ( cinfo.next_scanline + 1 ) ) * 3 ]; } else { buf = (unsigned char *)&image[ current_size * cinfo.next_scanline * 3 ]; } jpeg_write_scanlines( &cinfo, (JSAMPARRAY)&buf, 1 ); } jpeg_finish_compress( &cinfo ); jpeg_destroy_compress( &cinfo ); } else { png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (!png_ptr) return; png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { png_destroy_write_struct(&png_ptr, (png_infopp)NULL); return; } if (setjmp(png_ptr->jmpbuf)) { png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } png_init_io(png_ptr, fp); png_set_IHDR(png_ptr, info_ptr, current_size, current_size, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); png_write_info(png_ptr, info_ptr); png_byte **row_pointers = new png_byte*[current_size]; for (int i = 1; i <= current_size; i++) { row_pointers[i-1] = (png_byte*)(image + current_size * (current_size-i) * 3); } // actually write the image png_write_image(png_ptr, row_pointers); delete[] row_pointers; png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); } fclose(fp); printf("Written '%s'\n", filename); } void OutputGL::setShade( bool shade ) { if (shade) { glEnable( GL_LIGHTING ); } else { glDisable( GL_LIGHTING ); } this->shade = shade; } bool OutputGL::getShade() { return shade; } void OutputGL::setLightVector( sgVec3 light ) { GLfloat ambient[] = {BRIGHTNESS/3.0f, BRIGHTNESS/3.0f, BRIGHTNESS/3.0f,1.0f}; GLfloat diffuse[] = {BRIGHTNESS, BRIGHTNESS, BRIGHTNESS, 1.0f}; sgCopyVec3( light_vector, light ); light_vector[3] = 0.0f; glLightfv( GL_LIGHT0, GL_AMBIENT, ambient ); glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse ); glLightfv( GL_LIGHT0, GL_POSITION, light_vector ); glEnable( GL_LIGHT0 ); } void OutputGL::setColor( const float *rgba ) { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, rgba); glColor4fv( rgba ); } void OutputGL::clear( const float *rgb ) { glClearColor(rgb[0], rgb[1], rgb[2], 1.0f); glClear(GL_COLOR_BUFFER_BIT); } void OutputGL::drawTriangle( const sgVec2 *p, const sgVec3 *normals ) { glBegin(GL_TRIANGLES); glNormal3fv( normals[0] ); glVertex2fv( p[0] ); glNormal3fv( normals[1] ); glVertex2fv( p[1] ); glNormal3fv( normals[2] ); glVertex2fv( p[2]); glEnd(); } void OutputGL::drawTriangle( const sgVec2 *p, const sgVec3 *normals, const sgVec4 *color ) { glBegin(GL_TRIANGLES); glColor4fv( color[0] );glNormal3fv( normals[0] ); glVertex2fv( p[0] ); glColor4fv( color[1] );glNormal3fv( normals[1] ); glVertex2fv( p[1] ); glColor4fv( color[2] );glNormal3fv( normals[2] ); glVertex2fv( p[2]); glEnd(); } void OutputGL::drawQuad( const sgVec2 *p, const sgVec3 *normals ) { glBegin(GL_QUADS); glNormal3fv( normals[0] ); glVertex2fv( p[0] ); glNormal3fv( normals[1] ); glVertex2fv( p[1] ); glNormal3fv( normals[2] ); glVertex2fv( p[2] ); glNormal3fv( normals[3] ); glVertex2fv( p[3] ); glEnd(); } void OutputGL::drawQuad( const sgVec2 *p, const sgVec3 *normals, const sgVec4 *color ) { glBegin(GL_QUADS); glColor4fv( color[0] );glNormal3fv( normals[0] ); glVertex2fv( p[0] ); glColor4fv( color[1] );glNormal3fv( normals[1] ); glVertex2fv( p[1] ); glColor4fv( color[2] );glNormal3fv( normals[2] ); glVertex2fv( p[2] ); glColor4fv( color[3] );glNormal3fv( normals[3] ); glVertex2fv( p[3] ); glEnd(); } void OutputGL::drawCircle( sgVec2 p, int radius ) { glBegin(GL_LINE_LOOP); for (int i = 0; i < SUBDIVISIONS; i++) { glVertex2f( p[0] + circle_x[i] * radius, p[1] + circle_y[i] * radius ); } glEnd(); } void OutputGL::drawLine( sgVec2 p1, sgVec2 p2 ) { glBegin(GL_LINES); glVertex2fv(p1); glVertex2fv(p2); glEnd(); } void OutputGL::drawText( sgVec2 p, char *text ) { if (useTexturedFont) { textRenderer.begin(); textRenderer.start2fv( p ); textRenderer.puts( text ); textRenderer.end(); glDisable(GL_TEXTURE_2D); } else { glutFont->drawString( text, (int)p[0], (int)p[1] ); } }