diff --git a/src/glutmain.cpp b/src/glutmain.cpp index 69d7e8aaf..e12affbde 100644 --- a/src/glutmain.cpp +++ b/src/glutmain.cpp @@ -22,6 +22,7 @@ #include "vecmath.h" #include "quaternion.h" #include "util.h" +#include "timer.h" #include "stardb.h" #include "solarsys.h" #include "asterism.h" @@ -46,10 +47,9 @@ static string welcomeMessage1("Welcome to Celestia 1.07"); static string welcomeMessage2("Press D to run demo"); -//---------------------------------- // Timer info. -static double currentTime=0.0; -static double deltaTime=0.0; +static double currentTime = 0.0; +static Timer* timer = NULL; static int nFrames = 0; static double fps = 0.0; @@ -409,6 +409,20 @@ void RenderOverlay() overlay->end(); } +static void ToggleLabelState(int labelState) +{ + renderer->setLabelMode(renderer->getLabelMode() ^ labelState); +} + +static void ToggleRenderFlag(int renderFlag) +{ + renderer->setRenderFlags(renderer->getRenderFlags() ^ renderFlag); +} + + +/* + * Definition of GLUT callback functions + */ void Display(void) { @@ -424,13 +438,17 @@ void Idle(void) { if (glutGetWindow() != mainWindow) glutSetWindow(mainWindow); - sim->update(0.1f); + + double lastTime = currentTime; + currentTime = timer->getTime(); + double dt = currentTime - lastTime; + sim->update(dt); + Display(); } void MouseDrag(int x, int y) { - cout << leftButton << ',' << middleButton << ',' << rightButton << '\n'; if (leftButton ^ rightButton) { Quatf q(1); @@ -444,7 +462,6 @@ void MouseDrag(int x, int y) Vec3f axis; float angle = 0; sim->getObserver().getOrientation().getAxisAngle(axis, angle); - cout << "[" << axis.x << "," << axis.y << "," << axis.z << "] " << angle << "\n"; } else if (rightButton && !leftButton) { @@ -470,21 +487,29 @@ void MouseButton(int button, int state, int x, int y) middleButton = (state == GLUT_DOWN); lastX = x; lastY = y; + + if (state == GLUT_DOWN) + { + mouseMotion = 0; + } + else + { + if (mouseMotion < 3) + { + if (button == GLUT_LEFT_BUTTON) + { + Vec3f pickRay = renderer->getPickRay(x, y); + Selection oldSel = sim->getSelection(); + Selection newSel = sim->pickObject(pickRay); + sim->setSelection(newSel); + if (!oldSel.empty() && oldSel == newSel) + sim->centerSelection(); + } + } + } } - -static void ToggleLabelState(int labelState) -{ - renderer->setLabelMode(renderer->getLabelMode() ^ labelState); -} - -static void ToggleRenderFlag(int renderFlag) -{ - renderer->setRenderFlags(renderer->getRenderFlags() ^ renderFlag); -} - - -void HandleKeyPress(unsigned char c, int x, int y) +void KeyPress(unsigned char c, int x, int y) { if (textEnterMode) { @@ -497,12 +522,27 @@ void HandleKeyPress(unsigned char c, int x, int y) if (typedText.size() > 0) typedText = string(typedText, 0, typedText.size() - 1); } + else if (c == '\n' || c == '\r') + { + if (typedText != "") + { + Selection sel = sim->findObject(typedText); + if (!sel.empty()) + sim->setSelection(sel); + typedText = ""; + } + textEnterMode = false; + } return; } c = toupper(c); switch (c) { + case '\n': + case '\r': + textEnterMode = true; + break; case 'A': if (sim->getTargetSpeed() == 0) sim->setTargetSpeed(0.000001f); @@ -769,20 +809,21 @@ int main(int argc, char* argv[]) sim->setTime((double) time(NULL) / 86400.0 + (double) astro::Date(1970, 1, 1)); sim->update(0.0); - glutInitWindowSize(400, 300); + glutInitWindowSize(480, 360); glutInitWindowPosition(0, 0); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); mainWindow = glutCreateWindow("Celestia"); - ChangeSize(400, 300); + ChangeSize(480, 360); glutReshapeFunc(ChangeSize); glutDisplayFunc(Display); glutIdleFunc(Idle); glutMouseFunc(MouseButton); glutMotionFunc(MouseDrag); - glutKeyboardFunc(HandleKeyPress); + glutKeyboardFunc(KeyPress); + timer = CreateTimer(); renderer = new Renderer(); // Prepare the scene for rendering. diff --git a/src/render.cpp b/src/render.cpp index 7b9784125..fba10a390 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -220,7 +220,7 @@ bool Renderer::init(int winWidth, int winHeight) galaxyTex = CreateProceduralTexture(128, 128, GL_RGBA, GlareTextureEval); galaxyTex->bindName(); - glareTex = CreateJPEGTexture("textures\\flare.jpg"); + glareTex = CreateJPEGTexture("textures/flare.jpg"); if (glareTex == NULL) glareTex = CreateProceduralTexture(64, 64, GL_RGB, GlareTextureEval); glareTex->bindName(); @@ -229,7 +229,7 @@ bool Renderer::init(int winWidth, int winHeight) shadowTex->bindName(); // font = txfLoadFont("fonts\\helvetica_14b.txf"); - font = txfLoadFont("fonts\\default.txf"); + font = txfLoadFont("fonts/default.txf"); if (font != NULL) txfEstablishTexture(font, 0, GL_FALSE); diff --git a/src/texture.cpp b/src/texture.cpp index df25b6ad1..2a40ee19b 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -8,18 +8,27 @@ // of the License, or (at your option) any later version. #ifdef _WIN32 -#define JPEG_SUPPORT +#define IJL_JPEG_SUPPORT #define PNG_SUPPORT -#endif +#else +#define IJG_JPEG_SUPPORT +#endif // _WIN32 #include #include +#include #include #include "gl.h" #include "glext.h" -#ifdef JPEG_SUPPORT +#ifdef IJL_JPEG_SUPPORT #include "ijl.h" #endif +#ifdef IJG_JPEG_SUPPORT +#include "setjmp.h" +extern "C" { +#include +} +#endif #ifdef PNG_SUPPORT #include "setjmp.h" #include "png.h" @@ -327,12 +336,38 @@ CTexture* LoadTextureFromFile(const string& filename) } + +#ifdef IJG_JPEG_SUPPORT + +struct my_error_mgr +{ + struct jpeg_error_mgr pub; // "public" fields + jmp_buf setjmp_buffer; // for return to caller +}; + +typedef struct my_error_mgr *my_error_ptr; + +METHODDEF(void) my_error_exit(j_common_ptr cinfo) +{ + // cinfo->err really points to a my_error_mgr struct, so coerce pointer + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + // Always display the message. + // We could postpone this until after returning, if we chose. + (*cinfo->err->output_message) (cinfo); + + // Return control to the setjmp point + longjmp(myerr->setjmp_buffer, 1); +} + +#endif // IJG_JPEG_SUPPORT + + + CTexture* CreateJPEGTexture(const char* filename, int channels) { -#ifndef JPEG_SUPPORT - return NULL; -#else +#if defined(IJL_JPEG_SUPPORT) JPEG_CORE_PROPERTIES jpegProps; printf("Reading texture: %s\n", filename); @@ -434,6 +469,140 @@ CTexture* CreateJPEGTexture(const char* filename, } return tex; +#elif defined(IJG_JPEG_SUPPORT) + CTexture* tex = NULL; + + // This struct contains the JPEG decompression parameters and pointers to + // working space (which is allocated as needed by the JPEG library). + struct jpeg_decompress_struct cinfo; + + // We use our private extension JPEG error handler. + // Note that this struct must live as long as the main JPEG parameter + // struct, to avoid dangling-pointer problems. + struct my_error_mgr jerr; + // More stuff + JSAMPARRAY buffer; // Output row buffer + int row_stride; // physical row width in output buffer + long cont; + JSAMPLE *image_buffer; + + // In this example we want to open the input file before doing anything else, + // so that the setjmp() error recovery below can assume the file is open. + // VERY IMPORTANT: use "b" option to fopen() if you are on a machine that + // requires it in order to read binary files. + + FILE *in; + in = fopen(filename, "rb"); + if (in == NULL) + { + printf("Can't open texture file '%s'\n", filename); + return NULL; + } + + // Step 1: allocate and initialize JPEG decompression object + // We set up the normal JPEG error routines, then override error_exit. + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + // Establish the setjmp return context for my_error_exit to use. + if (setjmp(jerr.setjmp_buffer)) + { + // If we get here, the JPEG code has signaled an error. + // We need to clean up the JPEG object, close the input file, and return. + jpeg_destroy_decompress(&cinfo); + fclose(in); + if (tex != NULL) + delete tex; + + return NULL; + } + + // Now we can initialize the JPEG decompression object. + jpeg_create_decompress(&cinfo); + + // Step 2: specify data source (eg, a file) + jpeg_stdio_src(&cinfo, in); + + // Step 3: read file parameters with jpeg_read_header() + (void) jpeg_read_header(&cinfo, TRUE); + + // We can ignore the return value from jpeg_read_header since + // (a) suspension is not possible with the stdio data source, and + // (b) we passed TRUE to reject a tables-only JPEG file as an error. + + // Step 4: set parameters for decompression + + // In this example, we don't need to change any of the defaults set by + // jpeg_read_header(), so we do nothing here. + + // Step 5: Start decompressor + + (void) jpeg_start_decompress(&cinfo); + // We can ignore the return value since suspension is not possible + // with the stdio data source. + + // We may need to do some setup of our own at this point before reading + // the data. After jpeg_start_decompress() we have the correct scaled + // output image dimensions available, as well as the output colormap + // if we asked for color quantization. + // In this example, we need to make an output work buffer of the right size. + // JSAMPLEs per row in output buffer + row_stride = cinfo.output_width * cinfo.output_components; + // Make a one-row-high sample array that will go away when done with image + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) & cinfo, JPOOL_IMAGE, row_stride, 1); + + // Step 6: while (scan lines remain to be read) + // jpeg_read_scanlines(...); + + // Here we use the library's state variable cinfo.output_scanline as the + // loop counter, so that we don't have to keep track ourselves. + + int format = GL_RGB; + if (cinfo.output_components == 1) + format = GL_LUMINANCE; + + tex = new CTexture(cinfo.image_width, cinfo.image_height, format); + + cont = cinfo.output_height - 1; + while (cinfo.output_scanline < cinfo.output_height) + { + // jpeg_read_scanlines expects an array of pointers to scanlines. + // Here the array is only one element long, but you could ask for + // more than one scanline at a time if that's more convenient. + (void) jpeg_read_scanlines(&cinfo, buffer, 1); + + // Assume put_scanline_someplace wants a pointer and sample count. + // put_scanline_someplace(buffer[0], row_stride); + memcpy(tex->pixels + + cinfo.image_width * cinfo.output_components * cont, + buffer[0], row_stride); + cont--; + } + + // Step 7: Finish decompression + + (void) jpeg_finish_decompress(&cinfo); + // We can ignore the return value since suspension is not possible + // with the stdio data source. + + // Step 8: Release JPEG decompression object + + // This is an important step since it will release a good deal of memory. + jpeg_destroy_decompress(&cinfo); + + // After finish_decompress, we can close the input file. + // Here we postpone it until after no more JPEG errors are possible, + // so as to simplify the setjmp error logic above. (Actually, I don't + // think that jpeg_destroy can do an error exit, but why assume anything... + + fclose(in); + + // At this point you may want to check to see whether any corrupt-data + // warnings occurred (test whether jerr.pub.num_warnings is nonzero). + + return tex; +#else + return NULL; #endif // JPEG_SUPPORT }