diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f45b05..4c06428 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(${PROJ}) set(VERSION "0.2.0") set(CMAKE_COLOR_MAKEFILE ON) #set(CMAKE_VERBOSE_MAKEFILE ON) -if(DEFINED DEBUG) +if(DEFINED EBUG) add_definitions(-DEBUG) endif() if(DEFINED CMAKE_INSTALL_PREFIX AND CMAKE_INSTALL_PREFIX MATCHES "/usr/local") @@ -14,7 +14,7 @@ message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}") if(NOT DEFINED LOCALEDIR) set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale) endif() -set(SOURCES takepic.c usage.c camtools.c am.c) +set(SOURCES takepic.c usage.c camtools.c am.c macros.c) if(NOT DEFINED NOBTA) set(SOURCES ${SOURCES} bta_print.c) add_definitions(-DUSE_BTA) @@ -29,7 +29,7 @@ if(DEFINED TELLAT) add_definitions(-DTELLAT=${TELLAT}) endif() set(LCPATH ${CMAKE_CURRENT_SOURCE_DIR}/locale/ru) -set(CFLAGS -O3 -Wall -Werror -W -std=gnu99) +set(CFLAGS -O2 -Wextra -Wall -Werror -W -std=gnu99) set(PO_FILE ${LCPATH}/messages.po) set(MO_FILE ${LCPATH}/LC_MESSAGES/${PROJ}.mo) set(RU_FILE ${LCPATH}/ru.po) @@ -43,30 +43,56 @@ pkg_check_modules(${PROJ} REQUIRED ${MODULES}) if(DEFINED USERAW) add_definitions(-DUSERAW) endif() + add_executable(${PROJ} ${SOURCES} ${PO_FILE} ${MO_FILE}) -target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm) -include_directories(${${PROJ}_INCLUDE_DIRS}) +include_directories(${${PROJ}_INCLUDE_DIRS} image_view_module) link_directories(${${PROJ}_LIBRARY_DIRS}) -add_definitions(${CFLAGS} - -DLOCALEDIR=\"${LOCALEDIR}\" - -DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\") +add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\" -DPACKAGE_VERSION=\"${VERSION}\" + -DGETTEXT_PACKAGE=\"${PROJ}\" -DPROJNAME=\"${PROJ}\") + +if(NOT DEFINED NOIMAGEVIEW) + add_subdirectory(image_view_module) +endif() +if(IMAGEVIEW_FOUND) + message("Found OpenGL. Will use ${IMLIB} to show data") + target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm ${IMLIB}) + add_definitions(-DIMAGEVIEW) +else() + message("Will compile without image view module") + target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm) +endif() # Installation of the program INSTALL(FILES ${MO_FILE} DESTINATION "share/locale/ru/LC_MESSAGES") INSTALL(TARGETS ${PROJ} DESTINATION "bin") -find_package(Gettext REQUIRED) -find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext) -if(NOT GETTEXT_XGETTEXT_EXECUTABLE OR NOT GETTEXT_MSGFMT_EXECUTABLE) - message(FATAL_ERROR "xgettext not found") +if(DEFINED EBUG) + message("Don't forget to do 'msgcat' ru.po from image view with this ru.po") + find_package(Gettext REQUIRED) + find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext) + if(NOT GETTEXT_XGETTEXT_EXECUTABLE OR NOT GETTEXT_MSGFMT_EXECUTABLE) + message(FATAL_ERROR "xgettext not found") + endif() + file(MAKE_DIRECTORY ${LCPATH}) + file(MAKE_DIRECTORY ${LCPATH}/LC_MESSAGES) + add_custom_command( + OUTPUT ${PO_FILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} --from-code=utf-8 ${SOURCES} -c -k_ -kN_ -o ${PO_FILE} + COMMAND sed -i 's/charset=.*\\\\n/charset=koi8-r\\\\n/' ${PO_FILE} + COMMAND enconv ${PO_FILE} + DEPENDS ${SOURCES} + ) + # we need this to prewent ru.po from deleting by make clean + add_custom_target( + RU_FILE + COMMAND [ -f ${RU_FILE} ] && ${GETTEXT_MSGMERGE_EXECUTABLE} -Uis ${RU_FILE} ${PO_FILE} || cp ${PO_FILE} ${RU_FILE} + DEPENDS ${PO_FILE} + ) + add_custom_command( + OUTPUT ${MO_FILE} + COMMAND make RU_FILE && ${GETTEXT_MSGFMT_EXECUTABLE} ${RU_FILE} -o ${MO_FILE} + DEPENDS ${PO_FILE} + ) endif() -add_custom_command( - OUTPUT ${PO_FILE} - COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} -D ${CMAKE_CURRENT_SOURCE_DIR} --from-code=koi8-r ${SOURCES} -c -k_ -kN_ -o ${PO_FILE} - COMMAND sed 's/charset=UTF-8/charset=koi8-r/' ${PO_FILE} | enconv > tmp && mv -f tmp ${PO_FILE} - COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} -Uis ${RU_FILE} ${PO_FILE} - DEPENDS ${SOURCES}) -add_custom_command( - OUTPUT ${MO_FILE} - COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ${RU_FILE} -o ${MO_FILE} - DEPENDS ${RU_FILE}) + diff --git a/bta_print.c b/bta_print.c index a932162..0cef010 100644 --- a/bta_print.c +++ b/bta_print.c @@ -1,3 +1,24 @@ +/* + * bta_print.c + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + /* Print some BTA NewACS data (or write to file) * Usage: * bta_print [time_step] [file_name] @@ -11,6 +32,7 @@ #include "takepic.h" #include "camtools.h" #include "bta_print.h" +#include "macros.h" #define CMNTSZ 79 char comment[CMNTSZ + 1]; diff --git a/bta_print.h b/bta_print.h index 69fdf00..657786a 100644 --- a/bta_print.h +++ b/bta_print.h @@ -1,3 +1,25 @@ +/* + * bta_print.h + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once #ifndef __BTA_PRINT_H__ #define __BTA_PRINT_H__ diff --git a/camtools.c b/camtools.c index 0b8e1e4..f4522b8 100644 --- a/camtools.c +++ b/camtools.c @@ -1,6 +1,28 @@ +/* + * camtools.c + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + #include "takepic.h" #include "camtools.h" #include "usage.h" +#include "macros.h" #ifdef USE_BTA #include "bta_print.h" @@ -361,3 +383,94 @@ int writeraw(char *filename, int width, int height, void *data){ return err; } #endif // USERAW + +#ifdef IMAGEVIEW +// here are the functions for converting gray (GLubyte) image into colour buffer + +/** + * Convert gray (unsigned short) into RGB components (GLubyte) + * @argument L - gray level + * @argument rgb - rgb array (GLubyte [3]) + */ +void gray2rgb(double gray, GLubyte *rgb){ + int i = gray * 4.; + double x = (gray - (double)i * .25) * 4.; + GLubyte r = 0, g = 0, b = 0; + //r = g = b = (gray < 1) ? gray * 256 : 255; + switch(i){ + case 0: + g = (GLubyte)(255. * x); + b = 255; + break; + case 1: + g = 255; + b = (GLubyte)(255. * (1. - x)); + break; + case 2: + r = (GLubyte)(255. * x); + g = 255; + break; + case 3: + r = 255; + g = (GLubyte)(255. * (1. - x)); + break; + default: + r = 255; + } + *rgb++ = r; + *rgb++ = g; + *rgb = b; +} + + +double linfun(double arg){ return arg; } // bung for PREVIEW_LINEAR +double logfun(double arg){ return log(1.+arg); } // for PREVIEW_LOG +double (*colorfun)(double) = linfun; // default function to convert color + +void change_colorfun(colorfn_type f){ + switch (f){ + case COLORFN_LINEAR: + colorfun = linfun; + break; + case COLORFN_LOG: + colorfun = logfun; + break; + default: // sqrt + colorfun = sqrt; + } +} + +/** + * Convert given FITS image src into RGB array dst + * for OpenGL texture + * @param w, h - image size (in pixels) + * array dst should have size w*h*3 + */ +void convert_grayimage(unsigned short *src, GLubyte *dst, int w, int h){ + FNAME(); + int x, y, S = w*h; + unsigned short *ptr = src; + double avr, wd, max, min; + avr = max = min = (double)*src; + for(x = 1; x < S; x++, ptr++){ + double pix = (double) *ptr; + if(pix > max) max = pix; + if(pix < min) min = pix; + avr += pix; + } + avr /= (double)S; + wd = max - min; + avr = (avr - min) / wd; // normal average by preview + DBG("stat: avr=%f wd=%f max=%f min=%f", avr, wd, max, min); +// avr = -log(avr); // scale factor +// if(avr > 1.) wd /= avr; + if(avr < 0.6) wd *= avr + 0.2; + DBG("now wd is %f", wd); + for(y = 0; y < h; y++){ + for(x = 0; x < w; x++, dst += 3, src++){ + gray2rgb(colorfun((*src - min) / wd), dst); + } + } +} + +#endif // IMAGEVIEW diff --git a/camtools.h b/camtools.h index 9b789ca..412e685 100644 --- a/camtools.h +++ b/camtools.h @@ -1,3 +1,24 @@ +/* + * camtools.h + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + #pragma once #ifndef __CAMTOOLS_H__ #define __CAMTOOLS_H__ @@ -41,5 +62,22 @@ int writepng(char *filename, int width, int height, void *data); int writeraw(char *filename, int width, int height, void *data); #endif // USERAW +#ifdef IMAGEVIEW +#include +#include +#include +#include + +// functions for converting grayscale value into colour +typedef enum{ + COLORFN_LINEAR, // linear + COLORFN_LOG, // ln + COLORFN_SQRT // sqrt +} colorfn_type; + +void change_colorfun(colorfn_type f); +void convert_grayimage(unsigned short *src, GLubyte *dst, int w, int h); +#endif // IMAGEVIEW + #endif // __CAMTOOLS_H__ diff --git a/image_view_module/CMakeLists.txt b/image_view_module/CMakeLists.txt new file mode 100644 index 0000000..ec04d3f --- /dev/null +++ b/image_view_module/CMakeLists.txt @@ -0,0 +1,150 @@ +# RUN cmake -DSTANDALONE=1 for standalone example +# -DEBUG=1 for debugging +# -DNOGETTEXT=1 for compilation without gettext support +# +# Into cmake file in parent directory add this: +#~ add_subdirectory(image_view_module) +#~ if(IMAGEVIEW_FOUND) + #~ message("Found OpenGL. Will use ${IMLIB} to show data") + #~ target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm ${IMLIB}) + #~ add_definitions(-DIMAGEVIEW) +#~ else() + #~ message("not found image view module") + #~ target_link_libraries(${PROJ} ${${PROJ}_LIBRARIES} -lm) +#~ endif() + +cmake_minimum_required(VERSION 2.8) +set(IMLIB image_view_module) + +if(DEFINED STANDALONE) + set(PROJ ${IMLIB}) + project(${PROJ}) +endif() + +set(CFLAGS -O2 -Wextra -Wall -Werror -W -std=gnu99) +set(CMAKE_COLOR_MAKEFILE ON) + +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} IMSOURCES) + +find_package(PkgConfig REQUIRED) +find_package(OpenGL REQUIRED) +find_package(GLUT REQUIRED) + +if(NOT GLUT_FOUND OR NOT OPENGL_FOUND) + message("GLUT library not found, image view won't be available") +else() +# exe file + +if(NOT DEFINED STANDALONE) + list(REMOVE_ITEM IMSOURCES main.c) + add_library(image_view_module ${IMSOURCES}) + + set(IMAGEVIEW_FOUND TRUE PARENT_SCOPE) + set(IMLIB ${IMLIB} PARENT_SCOPE) + if(DEFINED DEBUG) + set(LCPATH ${CMAKE_CURRENT_SOURCE_DIR}/locale/ru) + set(PO_FILE ${LCPATH}/messages.po) + set(RU_FILE ${LCPATH}/ru.po) + set(IMPO_FILE ${RU_FILE} PARENT_SCOPE) + add_custom_command( + OUTPUT ${PO_FILE} + COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} -D ${CMAKE_CURRENT_SOURCE_DIR} --from-code=koi8-r ${IMSOURCES} -c -k_ -kN_ -o ${PO_FILE} + COMMAND sed 's/charset=UTF-8/charset=koi8-r/' ${PO_FILE} | enconv > tmp && mv -f tmp ${PO_FILE} + COMMAND ${GETTEXT_MSGMERGE_EXECUTABLE} -Uis ${RU_FILE} ${PO_FILE} + DEPENDS ${IMSOURCES} + ) + endif() +else() + # cmake -DEBUG=1 -> debugging + if(DEFINED EBUG) + add_definitions(-DEBUG) + set(CMAKE_VERBOSE_MAKEFILE ON) + endif() + + set(MINOR_VERSION "1") + set(MID_VERSION "0") + set(MAJOR_VERSION "0") + set(VERSION "${MAJOR_VERSION}.${MID_VERSION}.${MINOR_VERSION}") + + message("VER: ${VERSION}") + add_executable(${PROJ} ${IMSOURCES} ${PO_FILE} ${MO_FILE}) + # change wrong behaviour with install prefix + if(CMAKE_INSTALL_PREFIX MATCHES "/usr/local") + message("Change default install path to /usr") + set(CMAKE_INSTALL_PREFIX "/usr") + endif() + message("Install dir prefix: ${CMAKE_INSTALL_PREFIX}") + add_definitions(${CFLAGS} -DLOCALEDIR=\"${LOCALEDIR}\" + -DPACKAGE_VERSION=\"${VERSION}\" -DGETTEXT_PACKAGE=\"${PROJ}\" + -DMINOR_VERSION=\"${MINOR_VERSION}\" -DMID_VERSION=\"${MID_VERSION}\" + -DMAJOR_VERSION=\"${MAJOR_VESION}\" -DPROJNAME=\"${PROJ}\") + + if(NOT DEFINED NOGETTEXT) + # directory should contain dir locale/ru for gettext translations + set(LCPATH ${CMAKE_SOURCE_DIR}/locale/ru) + if(NOT DEFINED LOCALEDIR) + if(DEFINED DEBUG) + set(LOCALEDIR ${CMAKE_CURRENT_SOURCE_DIR}/locale) + else() + set(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale) + endif() + endif() + # gettext files + set(PO_FILE ${LCPATH}/messages.po) + set(MO_FILE ${LCPATH}/LC_MESSAGES/${PROJ}.mo) + set(RU_FILE ${LCPATH}/ru.po) + else() + add_definitions(-DNOGETTEXT) + set(PO_FILE) + set(MO_FILE) + endif() + + # Installation of the program + if(NOT DEFINED DEBUG) + INSTALL(FILES ${MO_FILE} DESTINATION "share/locale/ru/LC_MESSAGES") + #PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) + INSTALL(TARGETS ${PROJ} DESTINATION "bin") + #PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + # Script to be executed at installation time (kind of post-intallation script) to + # change the right accesses on the installed files + #INSTALL(SCRIPT inst.cmake) + else() + install(CODE "MESSAGE(\"Don't install in DEBUG mode! First run cmake without -DEBUG defined.\")") + endif(NOT DEFINED DEBUG) + + if(NOT DEFINED NOGETTEXT) + find_package(Gettext REQUIRED) + find_program(GETTEXT_XGETTEXT_EXECUTABLE xgettext) + if(NOT GETTEXT_XGETTEXT_EXECUTABLE OR NOT GETTEXT_MSGFMT_EXECUTABLE) + message(FATAL_ERROR "xgettext not found") + endif() + file(MAKE_DIRECTORY ${LCPATH}) + file(MAKE_DIRECTORY ${LCPATH}/LC_MESSAGES) + + add_custom_command( + OUTPUT ${PO_FILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${GETTEXT_XGETTEXT_EXECUTABLE} --from-code=utf-8 ${IMSOURCES} -c -k_ -kN_ -o ${PO_FILE} + COMMAND sed -i 's/charset=.*\\\\n/charset=koi8-r\\\\n/' ${PO_FILE} + COMMAND enconv ${PO_FILE} + DEPENDS ${IMSOURCES} + ) + # we need this to prewent ru.po from deleting by make clean + add_custom_target( + RU_FILE + COMMAND [ -f ${RU_FILE} ] && ${GETTEXT_MSGMERGE_EXECUTABLE} -Uis ${RU_FILE} ${PO_FILE} || cp ${PO_FILE} ${RU_FILE} + DEPENDS ${PO_FILE} + ) + add_custom_command( + OUTPUT ${MO_FILE} + COMMAND make RU_FILE && ${GETTEXT_MSGFMT_EXECUTABLE} ${RU_FILE} -o ${MO_FILE} + DEPENDS ${PO_FILE} + ) + endif(NOT DEFINED NOGETTEXT) +endif(NOT DEFINED STANDALONE) +target_link_libraries(${IMLIB} ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} -lm -lpthread) +include_directories(${${IMLIB}_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR} ..) +link_directories(${${IMLIB}_LIBRARY_DIRS}) +endif(NOT GLUT_FOUND OR NOT OPENGL_FOUND) + + diff --git a/image_view_module/events.c b/image_view_module/events.c new file mode 100644 index 0000000..deece5f --- /dev/null +++ b/image_view_module/events.c @@ -0,0 +1,167 @@ +/* + * events.c + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include "events.h" +#include "imageview.h" +#include "macros.h" + +/** + * manage pressed keys & menu items + */ +void processKeybrd(unsigned char key, int mod, int win_GL_ID, _U_ int x, _U_ int y){ + windowData *win = searchWindow_byGLID(win_GL_ID); + if(!win) return; + if((mod == GLUT_ACTIVE_CTRL) && (key == 'q' || key == 17)) exit(0); // ctrl + q + switch(key){ + case '1': // return zoom to 1 & image to 0 + win->zoom = 1; + win->x = 0; win->y = 0; + break; + case 27: + destroyWindow_async(win_GL_ID); + break; + case 'Z': + win->zoom *= 1.1; + calc_win_props(win, NULL, NULL); + DBG("zoom: %f", win->zoom); + break; + case 'z': + win->zoom /= 1.1; + calc_win_props(win, NULL, NULL); + break; + } +} + +/* + * Process keyboard + */ +void keyPressed(unsigned char key, + _U_ int x, _U_ int y){ + int mod = glutGetModifiers(); + int window = glutGetWindow(); + //mod: GLUT_ACTIVE_SHIFT, GLUT_ACTIVE_CTRL, GLUT_ACTIVE_ALT; result is their sum + //DBG("Key pressed. mod=%d, keycode=%d, point=(%d,%d)\n", mod, key, x,y); + if((mod == GLUT_ACTIVE_CTRL) && (key == 'q' || key == 17)) exit(0); // ctrl + q + processKeybrd(key, mod, window, x, y); +} + +void keySpPressed(_U_ int key, _U_ int x, _U_ int y){ +// int mod = glutGetModifiers(); + DBG("Sp. key pressed. mod=%d, keycode=%d, point=(%d,%d)\n", glutGetModifiers(), key, x,y); +} + +int oldx, oldy; // coordinates when mouse was pressed +int movingwin = 0; // ==1 when user moves image by middle button +void mousePressed(_U_ int key, _U_ int state, _U_ int x, _U_ int y){ +// key: GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON +// state: GLUT_UP, GLUT_DOWN + int window = glutGetWindow(), mod = glutGetModifiers(); + windowData *win = searchWindow_byGLID(window); + if(!win) return; + if(state == GLUT_DOWN){ + oldx = x; oldy = y; + float X,Y; + conv_mouse_to_image_coords(x,y,&X,&Y,win); + DBG("press in (%d, %d) == (%f, %f) on image; mod == %d", x,y,X,Y, mod); + if(key == GLUT_MIDDLE_BUTTON) movingwin = 1; + if(key == 3){ // wheel UP + if(mod == 0) win->y += 10.*win->zoom; // nothing pressed - scroll up + else if(mod == GLUT_ACTIVE_SHIFT) win->x -= 10.*win->zoom; // shift pressed - scroll left + else if(mod == GLUT_ACTIVE_CTRL) win->zoom *= 1.1; // ctrl+wheel up == zoom+ + }else if(key == 4){ // wheel DOWN + if(mod == 0) win->y -= 10.*win->zoom; // nothing pressed - scroll down + else if(mod == GLUT_ACTIVE_SHIFT) win->x += 10.*win->zoom; // shift pressed - scroll right + else if(mod == GLUT_ACTIVE_CTRL) win->zoom /= 1.1; // ctrl+wheel down == zoom- + } + calc_win_props(win, NULL, NULL); + }else{ + movingwin = 0; + } +/* DBG("Mouse button %s. point=(%d, %d); mod=%d, button=%d\n", + (state == GLUT_DOWN)? "pressed":"released", x, y, glutGetModifiers(), key);*/ + +/* int window = glutGetWindow(); + if(window == WaveWindow){ // щелкнули в окне с вейвлетом + _U_ int w = glutGet(GLUT_WINDOW_WIDTH) / 2; + _U_ int h = glutGet(GLUT_WINDOW_HEIGHT) / 2; + if(state == GLUT_DOWN && key == GLUT_LEFT_BUTTON){ + //HistCoord[0] = (x > w); + //HistCoord[1] = (y > h); + } + } +*/ +} +/* this doesn't work +void mouseWheel(int button, int dir, int x, int y){ + int window = glutGetWindow(); + windowData *win = searchWindow_byGLID(window); + if(!win) return; + DBG("Mouse wheel, dir: %d. point=(%d, %d); mod=%d, button=%d\n", + dir, x, y, glutGetModifiers(), button); +} +*/ +void mouseMove(_U_ int x, _U_ int y){ + int window = glutGetWindow(); + windowData *win = searchWindow_byGLID(window); + if(!win) return; + //DBG("Mouse moved to (%d, %d)\n", x, y); + if(movingwin){ + float X, Y, nx, ny;//, w2, h2; + float a = win->Daspect; + X = (x - oldx) * a; Y = (y - oldy) * a; + nx = win->x + X; + ny = win->y - Y; +// w2 = win->image->w / 2. * win->zoom; +// h2 = win->image->h / 2. * win->zoom; + + // if(nx < w2 && nx > -w2) + win->x = nx; + // if(ny < h2 && ny > -h2) + win->y = ny; + oldx = x; + oldy = y; + calc_win_props(win, NULL, NULL); + } +} + +void menuEvents(int opt){ + FNAME(); + int window = glutGetWindow(); + if(opt == 'q') exit(0); + processKeybrd((unsigned char)opt, 0, window, 0, 0); +} + +/** + * winID - inner !!! + */ +void createMenu(int GL_ID){ + FNAME(); + windowData *win; + win = searchWindow_byGLID(GL_ID); + glutSetWindow(GL_ID); + if(win->menu) glutDestroyMenu(win->menu); + win->menu = glutCreateMenu(menuEvents); + DBG("created menu %d\n", win->menu); + glutAddMenuEntry("Quit (ctrl+q)", 'q'); + glutAddMenuEntry("Close this window (ESC)", 27); + glutAddMenuEntry("Restore zoom (1)", '1'); + glutAttachMenu(GLUT_RIGHT_BUTTON); +} + diff --git a/image_view_module/events.h b/image_view_module/events.h new file mode 100644 index 0000000..b7fb208 --- /dev/null +++ b/image_view_module/events.h @@ -0,0 +1,42 @@ +/* + * events.h + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __EVENTS_H__ +#define __EVENTS_H__ + +#include +#include +#include +#include +#include + +extern float Z; // координата Z (zoom) + +void keyPressed(unsigned char key, int x, int y); +void keySpPressed(int key, int x, int y); +void mousePressed(int key, int state, int x, int y); +void mouseMove(int x, int y); +void createMenu(int window); +void menuEvents(int opt); +//void mouseWheel(int button, int dir, int x, int y); + +#endif // __EVENTS_H__ diff --git a/image_view_module/imageview.c b/image_view_module/imageview.c new file mode 100644 index 0000000..785d5c2 --- /dev/null +++ b/image_view_module/imageview.c @@ -0,0 +1,455 @@ +// bmpview.c +// +// Copyright 2010 Edward V. Emelianoff +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//-lglut +#include "imageview.h" +#include "macros.h" +#include +#include // XInitThreads(); + +int totWindows = 0; // total number of opened windows + +pthread_t GLUTthread; // main GLUT thread +pthread_mutex_t winini_mutex = PTHREAD_MUTEX_INITIALIZER; // mutex for windows initialization +volatile int wannacreate = 0; // flag: ==1 if someone wants to create window +windowData *wininiptr = NULL; + +int initialized = 0; // ==1 if GLUT is initialized; ==0 after clear_GL_context +int wannakill_GL_ID = 0; // GL_ID of window for asynchroneous killing + +void createWindow(windowData *win); +void RedrawWindow(); +void Resize(int width, int height); + +/** + * calculate window properties on creating & resizing + */ +void calc_win_props(windowData *win, GLfloat *Wortho, GLfloat *Hortho){ + if(!win || ! win->image) return; + double a, A, w, h, W, H; + double Zoom = win->zoom; + w = (double)win->image->w / 2.; + h = (double)win->image->h / 2.; + W = (double)win->w; + H = (double)win->h; + A = W / H; + a = w / h; + if(A > a){ // now W & H are parameters for glOrtho + win->Daspect = h / H * 2.; + W = h * A; H = h; + }else{ + win->Daspect = w / W * 2.; + H = w / A; W = w; + } + if(Wortho) *Wortho = W; + if(Hortho) *Hortho = H; + // calculate coordinates of center + win->x0 = W/Zoom - w + win->x / Zoom; + win->y0 = H / Zoom + h - win->y / Zoom; +} + +/** + * create window & run main loop + */ +void createWindow(windowData *win){ + FNAME(); + if(!initialized) return; + if(!win) return; + int w = win->w, h = win->h; + DBG("create window with title %s", win->title); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); + glutInitWindowSize(w, h); + win->GL_ID = glutCreateWindow(win->title); + DBG("created GL_ID=%d", win->GL_ID); + glutReshapeFunc(Resize); + glutDisplayFunc(RedrawWindow); + glutKeyboardFunc(keyPressed); + glutSpecialFunc(keySpPressed); + //glutMouseWheelFunc(mouseWheel); + glutMouseFunc(mousePressed); + glutMotionFunc(mouseMove); + //glutIdleFunc(glutPostRedisplay); + glutIdleFunc(NULL); + DBG("init textures"); + glGenTextures(1, &(win->Tex)); + win->zoom = 1.; +// calc_win_props(win, NULL, NULL); +// win->zoom = 1. / win->Daspect; +// DBG("Daspect: %g, zoom: %g", win->Daspect, win->zoom); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, win->Tex); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +// glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + //glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, win->image->w, win->image->h, 0, + GL_RGB, GL_UNSIGNED_BYTE, win->image->rawdata); + glDisable(GL_TEXTURE_2D); + totWindows++; + createMenu(win->GL_ID); + DBG("OK, total opened windows: %d", totWindows); +} + + +int killwindow(int GL_ID){ + DBG("try to kill win GL_ID=%d", GL_ID); + windowData *win; + win = searchWindow_byGLID(GL_ID); + if(!win) return 0; + glutSetWindow(GL_ID); // obviously set window (for closing from menu) + if(!win->killthread){ + pthread_mutex_lock(&win->mutex); + // say changed thread to die + win->killthread = 1; + pthread_mutex_unlock(&win->mutex); + DBG("wait for changed thread"); + pthread_join(win->thread, NULL); // wait while thread dies + } + if(win->menu) glutDestroyMenu(win->menu); + glutDestroyWindow(win->GL_ID); + win->GL_ID = 0; // reset for forEachWindow() + DBG("destroy texture %d", win->Tex); + glDeleteTextures(1, &(win->Tex)); + glFinish(); + if(!removeWindow(win->ID)) WARNX(_("Error removing from list")); + totWindows--; + return 1; +} + +/** + * destroy window with OpenGL or inner identificator "window" + * @param window inner or OpenGL id + * @param idtype = INNER or OPENGL + * @return 1 in case of OK, 0 if fault + */ +int destroyWindow(int window, winIdType type){ + if(!initialized) return 0; + int r = 0; + DBG("lock"); + pthread_mutex_lock(&winini_mutex); + DBG("locked"); + if(type == INNER){ + windowData *win = searchWindow(window); + if(win) r = killwindow(win->GL_ID); + }else + r = killwindow(window); + pthread_mutex_unlock(&winini_mutex); + DBG("window killed"); + return r; +} + +/** + * asynchroneous destroying - for using from menu + */ +void destroyWindow_async(int window_GL_ID){ + pthread_mutex_lock(&winini_mutex); + wannakill_GL_ID = window_GL_ID; + pthread_mutex_unlock(&winini_mutex); +} + +void renderBitmapString(float x, float y, void *font, char *string, GLubyte *color){ + if(!initialized) return; + char *c; + int x1=x, W=0; + for(c = string; *c; c++){ + W += glutBitmapWidth(font,*c);// + 1; + } + x1 -= W/2; + glColor3ubv(color); + glLoadIdentity(); + glTranslatef(0.,0., -150); + //glTranslatef(x,y, -4000.); + for (c = string; *c != '\0'; c++){ + glColor3ubv(color); + glRasterPos2f(x1,y); + glutBitmapCharacter(font, *c); + //glutStrokeCharacter(GLUT_STROKE_ROMAN, *c); + x1 = x1 + glutBitmapWidth(font,*c);// + 1; + } +} + +void redisplay(int GL_ID){ + if(!initialized) return; + glutSetWindow(GL_ID); + glutPostRedisplay(); +} + +/* + if(redraw) + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, + GL_LUMINANCE, GL_FLOAT, ptro); // s/image->data/tex/ + else + glTexImage2D(GL_TEXTURE_2D, 0, GL_INTENSITY, w, h, + 0, GL_LUMINANCE, GL_FLOAT, ptro); + //glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); + //glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); +*/ + +void RedrawWindow(){ + if(!initialized) return; + int window; + window = glutGetWindow(); + windowData *win = searchWindow_byGLID(window); + if(!win) return; + if(pthread_mutex_trylock(&win->mutex) != 0) return; + int w = win->image->w, h = win->image->h; + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + //glTranslatef(win->x-w/2., win->y-h/2., win->z); + glTranslatef(win->x, win->y, 0.); + glScalef(-win->zoom, -win->zoom, 1.); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, win->Tex); + if(win->image->changed){ + DBG("change texture as image have been changed"); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, win->image->rawdata); + win->image->changed = 0; + } +/* + glBegin(GL_QUADS); + glTexCoord2f(0., 1.); glVertex3f(0., 0., 0.); + glTexCoord2f(0., 0.); glVertex3f(0.,h, 0.); + glTexCoord2f(1., 0.); glVertex3f(w, h, 0.); + glTexCoord2f(1., 1.); glVertex3f(w, 0., 0.); + glEnd(); +*/ + w /= 2.; h /= 2.; + glBegin(GL_QUADS); + glTexCoord2f(0.0f, 0.0f); glVertex2f(-w, -h ); + glTexCoord2f(1.0f, 0.0f); glVertex2f( w, -h ); + glTexCoord2f(1.0f, 1.0f); glVertex2f( w, h ); + glTexCoord2f(0.0f, 1.0f); glVertex2f(-w, h ); + glEnd(); + glDisable(GL_TEXTURE_2D); + glFinish(); + glutSwapBuffers(); + pthread_mutex_unlock(&win->mutex); +} + +/** + * main freeGLUT loop + * waits for global signals to create windows & make other actions + */ +void *Redraw(_U_ void *arg){ +// pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER; +// struct timeval tv; +// struct timespec timeToWait; +// struct timeval now; + while(1){ + pthread_mutex_lock(&winini_mutex); + if(!initialized){ + DBG("!initialized"); + pthread_mutex_unlock(&winini_mutex); + pthread_exit(NULL); + } + if(wannacreate){ // someone asks to create window + DBG("call for window creating, id: %d", wininiptr->ID); + createWindow(wininiptr); + DBG("done!"); + wininiptr = NULL; + wannacreate = 0; + } + if(wannakill_GL_ID){ + usleep(10000); // wait a little to be sure that caller is closed + killwindow(wannakill_GL_ID); + wannakill_GL_ID = 0; + } + forEachWindow(redisplay); +/* gettimeofday(&now,NULL); + timeToWait.tv_sec = now.tv_sec; + timeToWait.tv_nsec = now.tv_usec * 1000UL + 10000000UL; + pthread_cond_timedwait(&fakeCond, &winini_mutex, &timeToWait);*/ + pthread_mutex_unlock(&winini_mutex); + //pthread_testcancel(); + if(totWindows) glutMainLoopEvent(); // process actions if there are windows +/* gettimeofday(&now,NULL); + timeToWait.tv_sec = now.tv_sec; + timeToWait.tv_nsec = now.tv_usec * 1000UL + 10000000UL; + pthread_mutex_lock(&fakeMutex); + pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait); + pthread_mutex_unlock(&fakeMutex);*/ +/* tv.tv_sec = 0; + tv.tv_usec = 10000; + select(0, NULL, NULL, NULL, &tv);*/ + usleep(10000); + } + return NULL; +} + +void Resize(int width, int height){ + if(!initialized) return; + int window = glutGetWindow(); + windowData *win = searchWindow_byGLID(window); + if(!win) return; +/* int GRAB_WIDTH = win->w, GRAB_HEIGHT = win->h; + float _U_ tmp, wd = (float) width/GRAB_WIDTH, ht = (float)height/GRAB_HEIGHT; + tmp = (wd + ht) / 2.; + width = (int)(tmp * GRAB_WIDTH); height = (int)(tmp * GRAB_HEIGHT);*/ + glutReshapeWindow(width, height); + win->w = width; + win->h = height; + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + //GLfloat W = (GLfloat)GRAB_WIDTH; GLfloat H = (GLfloat)GRAB_HEIGHT; + GLfloat W, H; + calc_win_props(win, &W, &H); + glOrtho(-W,W, -H,H, -1., 1.); +// gluPerspective(90., W/H, 0., 100.0); +// gluLookAt(0., 0., H/2., 0., 0., 0., 0., 1., 0.); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +/** + * create new window, run thread & return pointer to its structure or NULL + * asynchroneous call from outside + * wait for window creating & return its data + * @param title - header (copyed inside this function) + * @param w,h - image size + * @param rawdata - NULL (then the memory will be allocated here with size w x h) + * or allocated outside data + */ +windowData *createGLwin(char *title, int w, int h, rawimage *rawdata){ + FNAME(); + if(!initialized) return NULL; + windowData *win = MALLOC(windowData, 1); + if(!addWindow(win)){ + FREE(win); + return NULL; + } + rawimage *raw; + if(rawdata){ + raw = rawdata; + }else{ + raw = MALLOC(rawimage, 1); + if(raw){ + raw->rawdata = MALLOC(GLubyte, w*h*3); + raw->w = w; + raw->h = h; + raw->changed = 1; + // raw->protected is zero automatically + } + } + if(!raw || !raw->rawdata){ + free(raw); + return NULL; + } + win->title = strdup(title); + win->image = raw; + if(pthread_mutex_init(&win->mutex, NULL)){ + WARN(_("Can't init mutex!")); + removeWindow(win->ID); + return NULL; + } + win->w = w; + win->h = h; + win->zoom = 1.; + while(wannacreate); // wait if there was another creating + pthread_mutex_lock(&winini_mutex); + wininiptr = win; + wannacreate = 1; + pthread_mutex_unlock(&winini_mutex); + DBG("wait for creatin"); + while(wannacreate); // wait until window created from main thread + DBG("window created"); + return win; +} + +/** + * Init freeGLUT + */ +void imageview_init(){ + FNAME(); + char *v[] = {PROJNAME, NULL}; + int c = 1; + static int glutnotinited = 1; + if(initialized){ + // "пёп╤п╣ п╦п╫п╦я├п╦п╟п╩п╦п╥п╦я─п╬п╡п╟п╫п╬!" + WARNX(_("Already initialized!")); + return; + } + if(glutnotinited){ + XInitThreads(); // we need it for threaded windows + glutInit(&c, v); + glutnotinited = 0; + } + glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION); + pthread_create(&GLUTthread, NULL, &Redraw, NULL); + initialized = 1; +} + +void killwindow_v(int GL_ID){ + DBG("GL_ID: %d", GL_ID); + killwindow(GL_ID); +} + +/** + * Close all opened windows and terminate main GLUT thread + */ +void clear_GL_context(){ + FNAME(); + if(!initialized) return; + DBG("lock"); + pthread_mutex_lock(&winini_mutex); + initialized = 0; + DBG("locked"); + // kill main GLUT thread +// pthread_cancel(GLUTthread); + pthread_mutex_unlock(&winini_mutex); + forEachWindow(killwindow_v); + DBG("join"); + pthread_join(GLUTthread, NULL); // wait while main thread exits +// pthread_mutex_unlock(&winini_mutex); + DBG("main GL thread cancelled"); +} + + +/* + * Coordinates transformation from CS of drawingArea into CS of picture + * x,y - pointer coordinates + * X,Y - coordinates of appropriate point at picture + */ +void conv_mouse_to_image_coords(int x, int y, + float *X, float *Y, + windowData *window){ + float a = window->Daspect / window->zoom; + *X = x * a - window->x0; + *Y = window->y0 - y * a; +} + +void conv_image_to_mouse_coords(float X, float Y, + int *x, int *y, + windowData *window){ + float a = window->zoom / window->Daspect; + *x = (X + window->x0) * a; + *y = (window->y0 - Y) * a; +} + +int get_windows_amount(){ + return totWindows; +} diff --git a/image_view_module/imageview.h b/image_view_module/imageview.h new file mode 100644 index 0000000..e0a3b1f --- /dev/null +++ b/image_view_module/imageview.h @@ -0,0 +1,52 @@ +/* + * imageview.h + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once +#ifndef __BMPVIEW_H__ +#define __BMPVIEW_H__ + +#include +#include +#include +#include "events.h" +#include "list.h" + +typedef enum{ + INNER, + OPENGL +} winIdType; + +void imageview_init(); +windowData *createGLwin(char *title, int w, int h, rawimage *rawdata); +//void window_redraw(windowData *win); +int destroyWindow(int window, winIdType type); +void renderBitmapString(float x, float y, void *font, char *string, GLubyte *color); +void clear_GL_context(); + +void calc_win_props(windowData *win, GLfloat *Wortho, GLfloat *Hortho); + +void conv_mouse_to_image_coords(int x, int y, float *X, float *Y, windowData *window); +void conv_image_to_mouse_coords(float X, float Y, int *x, int *y, windowData *window); + +void destroyWindow_async(int window_GL_ID); + +int get_windows_amount(); + +#endif // __BMPVIEW_H__ diff --git a/image_view_module/list.c b/image_view_module/list.c new file mode 100644 index 0000000..4fe64f1 --- /dev/null +++ b/image_view_module/list.c @@ -0,0 +1,185 @@ +/* + * simple_list.c - simple one-direction list + * + * + * Copyright 2013 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "list.h" +#include "macros.h" + +typedef struct list_{ + windowData *data; + struct list_ *next; + struct list_ *prev; +} WinList; + +static WinList *root = NULL; + +/** + * add element v to list with root root (also this can be last element) + * @param root (io) - pointer to root (or last element) of list or NULL + * if *root == NULL, just created node will be placed there + * IDs in list are sorted, so if root's ID isn't 0, it will be moved + * @param w - data inserted (with empty ID - identificator will be assigned here) + * @return pointer to data inside created node or NULL + */ +windowData *addWindow(windowData *w){ + WinList *node, *last, *curr; + int freeID = 1, curID; + if((node = MALLOC(WinList, 1)) == 0) return NULL; // allocation error + node->data = w; // insert data + if(root){ // there was root node - search last + last = root; + if(last->data->ID != 0){ // root element have non-zero ID + node->next = last; + root->prev = node; + root = NULL; + }else{ // root element have ID==0, search first free ID + while((curr = last->next)){ + if((curID = curr->data->ID) > freeID) // we found a hole! + break; + else + freeID = curID + 1; + last = last->next; + } + last->next = node; // insert pointer to new node into last element in list + node->prev = last; // don't forget a pointer to previous element + node->next = curr; // next item after a hole or NULL if there isn't holes + w->ID = freeID; + } + } + if(!root){ // we need to change root to this element; (*root=NULL could be done upper) + root = node; + w->ID = 0; + } + DBG("added window with id = %d", w->ID); + return w; +} + +/** + * search window with given inner identificator winID + * @return pointer to window struct or NULL if not found + */ +WinList *searchWindowList(int winID){ + WinList *node = NULL, *next = root; + int curID; + if(!root){ + DBG("no root leaf"); + return NULL; + } + do{ + node = next; + next = node->next; + curID = node->data->ID; + }while(curID < winID && next); + if(curID != winID) return NULL; + return node; +} +/** + * the same as upper but for outern usage + */ +windowData *searchWindow(int winID){ + WinList *node = searchWindowList(winID); + if(!node) return NULL; + return node->data; +} + +/** + * search window with given OpenGL identificator GL_ID + * @return pointer to window struct or NULL if not found + */ +windowData *searchWindow_byGLID(int GL_ID){ + WinList *node = NULL, *next = root; + int curID; + if(!root) return NULL; + do{ + node = next; + next = node->next; + curID = node->data->GL_ID; + }while(curID != GL_ID && next); + if(curID != GL_ID) return NULL; + return node->data; +} + +/** + * free() all data for node of list + * !!! data for raw pixels (win->image) will be removed only if image->protected == 0 + * only for initialisation and free() by user !!! + */ +void WinList_freeNode(WinList **node){ + if(!node || !*node) return; + WinList *cur = *node, *prev = cur->prev, *next = cur->next; + windowData *win = cur->data; + if(root == cur) root = next; + FREE(win->title); + if(win->image->protected == 0){ + FREE(win->image->rawdata); + FREE(win->image); + } + pthread_mutex_destroy(&win->mutex); + FREE(cur->data); // free memory & set to NULL the pointer + FREE(*node); + if(prev) + prev->next = next; + if(next) + next->prev = prev; +} + +/** + * remove window with ID winID + * @return 0 in case of error !0 if OK + */ +int removeWindow(int winID){ + WinList *node = searchWindowList(winID); + if(!node){ + DBG("Not found"); + return 0; + } + DBG("removing win ID=%d", winID); + WinList_freeNode(&node); + return 1; +} + +/** + * remove all nodes in list + */ +void freeWinList(){ + WinList *node = root, *next; + if(!root) return; + do{ + next = node->next; + WinList_freeNode(&node); + node = next; + }while(node); + root = NULL; +} + +/** + * run function for each window in list + */ +void forEachWindow(void (*fn)(int GL_ID)){ + WinList *node = root; + if(!root) return; + do{ + int id = node->data->GL_ID; + if(id) fn(id); + node = node->next; + }while(node); +} + diff --git a/image_view_module/list.h b/image_view_module/list.h new file mode 100644 index 0000000..e0fedcf --- /dev/null +++ b/image_view_module/list.h @@ -0,0 +1,69 @@ +/* + * simple_list.h - header file for simple list support + * TO USE IT you must define the type of data as + * typedef your_type listdata + * or at compiling time + * -Dlistdata=your_type + * or by changing this file + * + * Copyright 2013 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once +#ifndef __SIMPLE_LIST_H__ +#define __SIMPLE_LIST_H__ + +#include "events.h" + +typedef struct{ + GLubyte *rawdata; // raw image data + int protected; // don't delete this memory with window + int w; // size of image + int h; + int changed; // == 1 if data was changed outside (to redraw) +} rawimage; + +typedef struct{ + int ID; // identificator + char *title; // title of window + GLuint Tex; // texture for image inside window + int GL_ID; // identificator of OpenGL window + rawimage *image; // raw image data + int w; int h; // window size + float x; float y; // image offset coordinates + float x0; float y0;// center of window for coords conversion + float zoom; // zoom aspect + float Daspect; // aspect ratio between image & window sizes + int menu; // window menu identifier + pthread_t thread; // identificator of thread that changes window data + pthread_mutex_t mutex;// mutex for operations with image + int killthread; // flag for killing data changing thread & also signal that there's no threads +} windowData; + + + +// add element v to list with root root (also this can be last element) +windowData *addWindow(windowData *w); +windowData *searchWindow(int winID); +windowData *searchWindow_byGLID(int winGLID); + +void forEachWindow(void (*fn)(int GL_ID)); + +int removeWindow(int winID); +void freeWinList(); + +#endif // __SIMPLE_LIST_H__ diff --git a/image_view_module/locale/ru/LC_MESSAGES/openglview.mo b/image_view_module/locale/ru/LC_MESSAGES/openglview.mo new file mode 100644 index 0000000..ef9e8cc Binary files /dev/null and b/image_view_module/locale/ru/LC_MESSAGES/openglview.mo differ diff --git a/image_view_module/locale/ru/messages.po b/image_view_module/locale/ru/messages.po new file mode 100644 index 0000000..b6bbb9b --- /dev/null +++ b/image_view_module/locale/ru/messages.po @@ -0,0 +1,57 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-03-02 12:06+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=koi8-r\n" +"Content-Transfer-Encoding: 8bit\n" + +#: /home/eddy/tmp/image_view_module/macros.c:175 +msgid "No filename given!" +msgstr "" + +#: /home/eddy/tmp/image_view_module/macros.c:177 +#, c-format +msgid "Can't open %s for reading" +msgstr "" + +#: /home/eddy/tmp/image_view_module/macros.c:179 +#, c-format +msgid "Can't stat %s" +msgstr "" + +#: /home/eddy/tmp/image_view_module/macros.c:182 +msgid "Mmap error for input" +msgstr "" + +#: /home/eddy/tmp/image_view_module/macros.c:183 +msgid "Can't close mmap'ed file" +msgstr "" + +#: /home/eddy/tmp/image_view_module/macros.c:192 +msgid "Can't munmap" +msgstr "" + +#: /home/eddy/tmp/image_view_module/imageview.c:132 +msgid "Error removing from list" +msgstr "" + +#: /home/eddy/tmp/image_view_module/imageview.c:362 +msgid "Can't init mutex!" +msgstr "" + +#. "Уже инициализировано!" +#: /home/eddy/tmp/image_view_module/imageview.c:389 +msgid "Already initialized!" +msgstr "" diff --git a/image_view_module/locale/ru/ru.po b/image_view_module/locale/ru/ru.po new file mode 100644 index 0000000..719149d --- /dev/null +++ b/image_view_module/locale/ru/ru.po @@ -0,0 +1,63 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "Project-Id-Version: PACKAGE VERSION\n" + "Report-Msgid-Bugs-To: \n" + "POT-Creation-Date: 2015-03-02 12:05+0300\n" + "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" + "Last-Translator: FULL NAME \n" + "Language-Team: LANGUAGE \n" + "Language: \n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=koi8-r\n" + "Content-Transfer-Encoding: 8bit\n" + +#. "Уже инициализировано!" +#: /home/eddy/tmp/image_view_module/imageview.c:389 +msgid "Already initialized!" +msgstr "" + +#: /home/eddy/tmp/image_view_module/macros.c:183 +msgid "Can't close mmap'ed file" +msgstr "Не могу закрыть mmap'нутый файл" + +#: /home/eddy/tmp/image_view_module/imageview.c:362 +msgid "Can't init mutex!" +msgstr "Не могу инициировать взаимное исключение!" + +#: /home/eddy/tmp/image_view_module/macros.c:192 +msgid "Can't munmap" +msgstr "Не могу вызывать munmap" + +#: /home/eddy/tmp/image_view_module/macros.c:177 +#, c-format +msgid "Can't open %s for reading" +msgstr "Не могу открыть %s для чтения" + +#: /home/eddy/tmp/image_view_module/macros.c:179 +#, c-format +msgid "Can't stat %s" +msgstr "Не могу выполнить stat для %s" + +#: /home/eddy/tmp/image_view_module/imageview.c:132 +msgid "Error removing from list" +msgstr "Ошибка удаления из списка" + +#: /home/eddy/tmp/image_view_module/macros.c:182 +msgid "Mmap error for input" +msgstr "Ошибка mmap для входных данных" + +#: /home/eddy/tmp/image_view_module/macros.c:175 +msgid "No filename given!" +msgstr "Не указано имя файла!" + +#, fuzzy +#~ msgid "Can't init main GLUT mutex!" +#~ msgstr "Не могу инициировать взаимное исключение!" + +#~ msgid "can't cancel a thread!" +#~ msgstr "Не могу отменить выполнение потока!" diff --git a/image_view_module/main.c b/image_view_module/main.c new file mode 100644 index 0000000..6a39fb4 --- /dev/null +++ b/image_view_module/main.c @@ -0,0 +1,149 @@ +/* + * main.c + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include +#include +#include +#include + +#include "main.h" +#include "macros.h" +#include "imageview.h" + +void* change_image(void *data){ + FNAME(); + //struct timeval tv; + windowData *win = (windowData*) data; + int w = win->image->w, h = win->image->h, x,y, id = win->ID; + GLubyte i; + DBG("w=%d, h=%d",w,h); + for(i = 1; ;i++){ + // DBG("search to refresh %d", id); + if(!searchWindow(id)){ + DBG("Window deleted"); + pthread_exit(NULL); + } + // DBG("found, lock mutex"); + pthread_mutex_lock(&win->mutex); + if(win->killthread){ + pthread_mutex_unlock(&win->mutex); + DBG("got killthread"); + pthread_exit(NULL); + } + // DBG("refresh"); + GLubyte *raw = win->image->rawdata; + for(y = 0; y < h; y++){ + if(y%20 == 19){ + raw += w*3; + continue; + } + for(x = 0; x < w; x++){ + if(x%20 != 19){ + if(i < 80) raw[0]++; + else if(i < 170) raw[1]++; + else raw[2]++; + } + raw += 3; + } + } + win->image->changed = 1; + pthread_mutex_unlock(&win->mutex); + usleep(10000); + /*tv.tv_sec = 0; + tv.tv_usec = 10000; + select(0, NULL, NULL, NULL, &tv);*/ + } +} + +void* another_change(void *data){ + FNAME(); + windowData *win = (windowData*) data; + int w = win->image->w, h = win->image->h, x,y, id = win->ID; + GLubyte i; + for(i = 1; ;i++){ + if(!searchWindow(id)){ + DBG("Window deleted"); + pthread_exit(NULL); + } + pthread_mutex_lock(&win->mutex); + GLubyte *raw = win->image->rawdata; + for(y = 0; y < h; y++){ + if(y%20 == 19){ + raw += w*3; + continue; + } + for(x = 0; x < w; x++){ + if(x%20 != 19){ + if(i < 80) raw[0]--; + else if(i < 170) raw[1]--; + else raw[2]--; + } + raw += 3; + } + } + win->image->changed = 1; + pthread_mutex_unlock(&win->mutex); + usleep(10000); + } +} + +void *main_thread(_U_ void *none){ +// while(1){}; + rawimage im; + windowData *mainwin, *win, *third; + pthread_t mainthread; + int w = 640, h = 480; + im.protected = 1; + im.rawdata = MALLOC(GLubyte, w*h*3); + im.w = w; im.h = h; + mainwin = createGLwin("Sample window", w, h, &im); + DBG("ok"); + if(!mainwin) ERRX("can't create main"); +// pthread_create(&mainwin->thread, NULL, &change_image, (void*)mainwin); + pthread_create(&mainthread, NULL, &another_change, (void*)mainwin); + mainwin->killthread = 1; // say that there's no thread for manipulating + win = createGLwin("Second window", w/2, h/2, NULL); + if(!win) ERRX("can't create second"); + pthread_create(&win->thread, NULL, &change_image, (void*)win); + //pthread_join(mainwin->thread, NULL); + pthread_join(mainthread, NULL); + pthread_join(win->thread, NULL); + clear_GL_context(); + WARNX("Two windows closed, create another one"); + imageview_init(); // init after killing + third = createGLwin("third window", w*2, h, &im); + if(!third) ERRX("can't create third"); + pthread_create(&third->thread, NULL, &change_image, (void*)third); + pthread_join(third->thread, NULL); + DBG("try to clear"); + clear_GL_context(); + DBG("cleared"); + return NULL; +} + +int main(_U_ int argc, _U_ char **argv){ + pthread_t mainthread; + initial_setup(); // locale & messages + imageview_init(); + DBG("init main thread"); + pthread_create(&mainthread, NULL, &main_thread, NULL); + pthread_join(mainthread, NULL); + return 0; +} diff --git a/image_view_module/main.h b/image_view_module/main.h new file mode 100644 index 0000000..f7c6bbf --- /dev/null +++ b/image_view_module/main.h @@ -0,0 +1,6 @@ +// pthread_t thread, thread_m; +#include "events.h" // GLubyte etc + +// GLubyte *prepareImage(); +void help(char *s); + diff --git a/locale/ru/LC_MESSAGES/apogee_control.mo b/locale/ru/LC_MESSAGES/apogee_control.mo index ca0dadd..9745398 100644 Binary files a/locale/ru/LC_MESSAGES/apogee_control.mo and b/locale/ru/LC_MESSAGES/apogee_control.mo differ diff --git a/locale/ru/messages.po b/locale/ru/messages.po index 866deb5..401b786 100644 --- a/locale/ru/messages.po +++ b/locale/ru/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-08-29 10:54+0400\n" +"POT-Creation-Date: 2015-03-11 18:55+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,19 +17,41 @@ msgstr "" "Content-Type: text/plain; charset=koi8-r\n" "Content-Transfer-Encoding: 8bit\n" +#. "Устройство не найдено" +#: takepic.c:108 +msgid "Device not found" +msgstr "" + +#. "Не могу открыть файл устройства %s: %s" +#: takepic.c:116 +#, c-format +msgid "Can't open device file %s: %s" +msgstr "" + +#. "Не могу вызывать ioctl" +#: takepic.c:123 +msgid "Error in ioctl" +msgstr "" + #. "Получен сигнал %d, отключаюсь.\n" -#: takepic.c:62 +#: takepic.c:133 #, c-format msgid "Get signal %d, quit.\n" msgstr "" #. "Не могу удалить PID-файл" -#: takepic.c:68 +#: takepic.c:136 msgid "Can't delete PIDfile" msgstr "" +#. "Нажмите Ctrl+C еще %d раз[а], чтобы прервать считывание\n" +#: takepic.c:154 +#, c-format +msgid "Press Ctrl+C %d time[s] more to interrupt reading\n" +msgstr "" + #. "Обнаружен работающий процесс (pid=%d), выход.\n" -#: takepic.c:108 takepic.c:120 +#: takepic.c:222 takepic.c:234 #, c-format msgid "" "\n" @@ -37,55 +59,65 @@ msgid "" msgstr "" #. "Не могу открыть турель" -#: takepic.c:152 +#: takepic.c:251 msgid "Can't open turret" msgstr "" #. "Максимальная (MAX) и текущая (CUR) позиции турели:\n" -#: takepic.c:159 +#: takepic.c:258 #, c-format msgid "Turret MAXimum position and CURrent position:\n" msgstr "" #. "Требуемая позиция больше максимальной" -#: takepic.c:164 +#: takepic.c:263 msgid "Required position greater then max" msgstr "" #. "Не могу переместить турель" -#: takepic.c:169 +#: takepic.c:268 msgid "Can't move turret" msgstr "" #. "Подождите завершения перемещения турели " -#: takepic.c:174 +#: takepic.c:273 #, c-format msgid "Wait, while turret is moving " msgstr "" +#. "Не заданы параметры экспозиции, отключаюсь" +#: takepic.c:339 +msgid "Expose parameters aren't specified, exit" +msgstr "" + +#. "Не могу открыть камеру, завершаю" +#: takepic.c:347 +msgid "Can't open camera device, exit" +msgstr "" + #. "Обнаружена камера '%s' с датчиком '%s'" -#: takepic.c:226 +#: takepic.c:354 #, c-format msgid "Find camera '%s' with sensor '%s'" msgstr "" #. "Ошибка перехода в спящий режим!" -#: takepic.c:236 +#: takepic.c:372 msgid "Error: sleepless night!" msgstr "" #. "Не могу открыть файл журнала температур" -#: takepic.c:250 +#: takepic.c:386 msgid "Can't open temperature log file" msgstr "" #. "Не могу открыть файл журнала статистики" -#: takepic.c:264 +#: takepic.c:400 msgid "Can't open statistics log file" msgstr "" #. "\nЗатвор " -#: takepic.c:273 +#: takepic.c:409 #, c-format msgid "" "\n" @@ -93,555 +125,601 @@ msgid "" msgstr "" #. "открыт\n" -#: takepic.c:276 +#: takepic.c:412 #, c-format msgid "open\n" msgstr "" #. "закрыт\n" -#: takepic.c:279 +#: takepic.c:415 #, c-format msgid "closed\n" msgstr "" #. "Отключение холодильника" -#: takepic.c:285 +#: takepic.c:422 msgid "Switch cooler off" msgstr "" #. "Изменение температуры холодильника" -#: takepic.c:291 +#: takepic.c:428 msgid "Changing of cooler setpoint" msgstr "" #. "Температура ниже допустимой" -#: takepic.c:294 +#: takepic.c:431 msgid "The temperature setpoint is too low" msgstr "" #. "Видимое поле: %s" -#: takepic.c:303 +#: takepic.c:440 #, c-format msgid "Field of view: %s" msgstr "" #. "Поле изображения: (0, %d)(0, %d)" -#: takepic.c:305 +#: takepic.c:442 #, c-format msgid "Array field: (0, %d)(0, %d)" msgstr "" #. pre-expose #. "Предварительная экспозиция" -#: takepic.c:341 +#: takepic.c:466 msgid "Pre-expose" msgstr "" +#. "Ошибка выделения памяти!" +#: takepic.c:480 takepic.c:509 +msgid "malloc() failed!" +msgstr "" + #. "Ошибка считывания: %s\n" -#: takepic.c:353 takepic.c:414 +#: takepic.c:490 takepic.c:581 #, c-format msgid "Readout error: %s\n" msgstr "" #. "Захват кадра %d, время экспозиции - %g секунд\n" -#: takepic.c:380 +#: takepic.c:546 #, c-format msgid "Capture frame %d, exp time - %g sec\n" msgstr "" #. "Считывание изображения:" -#: takepic.c:408 +#: takepic.c:575 #, c-format msgid "Read image: " msgstr "" #. "Не могу сохранить файл" -#: takepic.c:428 +#: takepic.c:595 msgid "Can't save file" msgstr "" #. "Файл записан в '%s'" -#: takepic.c:432 +#: takepic.c:599 #, c-format msgid "File saved as '%s'" msgstr "" +#. "Не могу открыть окно OpenGL, просмотр будет недоступен!" +#: takepic.c:608 +msgid "Can't open OpenGL window, image preview will be inaccessible" +msgstr "" + #. "%d секунд до окончания паузы\n" -#: takepic.c:450 +#: takepic.c:635 #, c-format msgid "%d seconds till pause ends\n" msgstr "" #. "Неверная нижняя граница: %s" -#: usage.c:77 +#: usage.c:102 #, c-format msgid "Wrong lower border: %s" msgstr "" #. "Неверная верхняя граница: %s" -#: usage.c:82 +#: usage.c:107 #, c-format msgid "Wrong upper border: %s" msgstr "" #. "Использование:\t%s [опции] [префикс выходных файлов]\n" -#: usage.c:98 +#: usage.c:123 #, c-format msgid "Usage:\t%s [options] [output files prefix]\n" msgstr "" #. "\tОпции:\n" -#: usage.c:101 +#: usage.c:126 #, c-format msgid "\tOptions:\n" msgstr "" #. "автор программы" -#: usage.c:104 +#: usage.c:129 msgid "program author" msgstr "" #. "отключить холодильник" -#: usage.c:107 usage.c:289 +#: usage.c:132 usage.c:319 msgid "Set cooler off" msgstr "" #. "не открывать затвор при экспозиции (\"темновые\")" -#: usage.c:110 +#: usage.c:135 msgid "not open shutter when exposing (\"dark frames\")" msgstr "" +#. "Отобразить на экране полученное изображение" +#: usage.c:138 +msgid "Display last image" +msgstr "" + #. "не засвечивать матрицу перед экспозицией" -#: usage.c:113 +#: usage.c:141 msgid "Don't flash CCD chip before expose" msgstr "" #. "Установить скорость вентиляторов в F (0..3)" -#: usage.c:116 +#: usage.c:144 msgid "Set fan speed to F (0..3)" msgstr "" #. получить сведения о турели -#: usage.c:119 +#: usage.c:147 msgid "get turret's parameters" msgstr "" #. переместить турель в N-ю позицию -#: usage.c:122 +#: usage.c:150 msgid "set turret to Nth position" msgstr "" #. "интервал времени между последовательными записями в лог и HISTORY (в секундах)" -#: usage.c:125 +#: usage.c:153 msgid "time interval between sequential writings to log & HISTORY (in seconds)" msgstr "" #. "биннинг N пикселей по горизонтали" -#: usage.c:128 +#: usage.c:156 msgid "horizontal binning to N pixels" msgstr "" #. "тип изображения" -#: usage.c:131 +#: usage.c:159 msgid "image type" msgstr "" #. "название прибора" -#: usage.c:134 +#: usage.c:162 msgid "instrument name" msgstr "" #. "не сохранять изображения, лишь вести запись статистки" -#: usage.c:137 +#: usage.c:165 msgid "don't save images, only make all-stat log" msgstr "" #. "вести запись рабочих температур в файл temp_log" -#: usage.c:140 +#: usage.c:168 msgid "make temperatures logging to file temp_log" msgstr "" #. "работать с N-й камерой" -#: usage.c:143 +#: usage.c:171 msgid "work with Nth camera" msgstr "" #. "N кадров в серии" -#: usage.c:146 +#: usage.c:174 msgid "make series of N frames" msgstr "" #. "название объекта" -#: usage.c:149 +#: usage.c:177 msgid "object name" msgstr "" #. "имена наблюдателей" -#: usage.c:152 +#: usage.c:180 msgid "observers' names" msgstr "" #. "название программы наблюдений" -#: usage.c:155 +#: usage.c:183 msgid "observing program name" msgstr "" #. "выдержать ptime секунд между экспозициями" -#: usage.c:158 +#: usage.c:186 msgid "make pause for ptime seconds between expositions" msgstr "" #. "установить скорость считывания в N" -#: usage.c:161 +#: usage.c:189 msgid "set readout speed to N" msgstr "" #. "Полный сброс" -#: usage.c:164 +#: usage.c:192 msgid "full reset" msgstr "" #. "перейти в спящий режим" -#: usage.c:167 +#: usage.c:195 msgid "go to sleeping mode" msgstr "" #. "не сохранять изображение, а только отобразить статистику" -#: usage.c:170 +#: usage.c:198 msgid "not save image, just show statistics" msgstr "" #. "только задать/получить температуру" #. "только отобразить/задать температуру" -#: usage.c:173 usage.c:426 +#: usage.c:201 usage.c:465 msgid "only set/get temperature" msgstr "" #. "задать рабочую температуру degr градусов" -#: usage.c:176 +#: usage.c:204 msgid "set work temperature to degr C" msgstr "" #. "биннинг N пикселей по вертикали" -#: usage.c:179 +#: usage.c:207 msgid "vertical binning to N pixels" msgstr "" #. установить номер турели в N -#: usage.c:182 +#: usage.c:210 msgid "set turret's number to N" msgstr "" #. "возобновить питание" -#: usage.c:185 +#: usage.c:213 msgid "resume system" msgstr "" #. "время экспозиции exptime мс" -#: usage.c:188 +#: usage.c:216 msgid "set exposure time to exptime ms" msgstr "" #. "выбрать диапазон для считывания" -#: usage.c:191 usage.c:194 +#: usage.c:219 usage.c:222 msgid "select clip region" msgstr "" #. "не очищать матрицу после считывания" -#: usage.c:198 +#: usage.c:226 msgid "don't flush ccd after expose" msgstr "" #. "выполнить предварительную нулевую экспозицию для очистки матрицы" -#: usage.c:201 +#: usage.c:229 msgid "make a preliminary zero exposition for cleaning CCD" msgstr "" #. "открыть затвор" -#: usage.c:204 +#: usage.c:232 msgid "open shutter" msgstr "" #. "заткрыть затвор" -#: usage.c:207 +#: usage.c:235 msgid "close shutter" msgstr "" #. "не открывать устройство, лишь отобразить шапку FITS" -#: usage.c:210 +#: usage.c:238 msgid "don't open camera device, just show FITS header" msgstr "" #. "работать в 12-битном режиме" -#: usage.c:213 +#: usage.c:241 msgid "work in a 12-bit ADC mode" msgstr "" #. "Не введено никаких параметров" -#: usage.c:271 +#: usage.c:301 msgid "Any parameters are absent" msgstr "" #. "Автор программы: %s" -#: usage.c:283 +#: usage.c:313 #, c-format msgid "Program author: %s" msgstr "" #. "Съемка темновых" -#: usage.c:295 +#: usage.c:325 msgid "Dark frames" msgstr "" +#. "Отображение снятых кадров" +#: usage.c:331 +msgid "Will show images" +msgstr "" + #. "Не засвечивать камеру до экспозиции" -#: usage.c:300 +#: usage.c:339 msgid "No pre-expose flash" msgstr "" #. "Скорость вентилятора должна быть в пределе 0..3" -#: usage.c:305 +#: usage.c:344 msgid "Fan speed should be in interval 0..3" msgstr "" #. "Установить скорость вращения вентиляторов в %d" -#: usage.c:307 +#: usage.c:346 #, c-format msgid "Fan speed would be set to %d" msgstr "" #. "Получить информацию о турели" -#: usage.c:313 +#: usage.c:352 msgid "Get turret's info" msgstr "" #. "Номер позиции должен быть больше 0" -#: usage.c:319 +#: usage.c:358 msgid "Position number should be positive value" msgstr "" #. "Переместить турель в позицию %d" -#: usage.c:321 +#: usage.c:360 #, c-format msgid "Move turret into %d" msgstr "" #. "Значение time-interval должно быть натуральным числом" -#: usage.c:326 +#: usage.c:365 msgid "Value of time-interval must be non-zero positive" msgstr "" #. "Установить интервал логгирования в %d секунд" -#: usage.c:328 +#: usage.c:367 #, c-format msgid "Set logging interval to %d seconds" msgstr "" #. "Неверный" -#: usage.c:333 usage.c:442 +#: usage.c:372 usage.c:481 msgid "Wrong" msgstr "" #. "Гор. биннинг: %d" -#: usage.c:336 +#: usage.c:375 #, c-format msgid "Horisontal binning: %d" msgstr "" #. "Тип изображения - %s" -#: usage.c:341 +#: usage.c:380 #, c-format msgid "Image type - %s" msgstr "" #. "Название прибора - %s" -#: usage.c:346 +#: usage.c:385 #, c-format msgid "Instrument name - %s" msgstr "" #. Полное журналирование статистики -#: usage.c:351 +#: usage.c:390 msgid "Full statistics logging" msgstr "" #. "Сохранение журнала температур" -#: usage.c:357 +#: usage.c:396 msgid "Save temperature log" msgstr "" #. "Неверный номер камеры: %s" -#: usage.c:363 +#: usage.c:402 #, c-format msgid "Wrong camera number: %s" msgstr "" #. "Работать с камерой номер %d" -#: usage.c:366 +#: usage.c:405 #, c-format msgid "Open camera number %d" msgstr "" #. "Неверное кол-во кадров: %s" -#: usage.c:371 +#: usage.c:410 #, c-format msgid "Wrong frames number in series: %s" msgstr "" #. "Серия из %d кадров" -#: usage.c:374 +#: usage.c:413 #, c-format msgid "Series of %d frames" msgstr "" #. "Имя объекта - %s" -#: usage.c:379 +#: usage.c:418 #, c-format msgid "Object name - %s" msgstr "" #. "Наблюдатели: %s" -#: usage.c:384 +#: usage.c:423 #, c-format msgid "Observers: %s" msgstr "" #. "Название программы: %s" -#: usage.c:389 +#: usage.c:428 #, c-format msgid "Program name: %s" msgstr "" #. "Неверная пауза: %s" -#: usage.c:394 +#: usage.c:433 #, c-format msgid "Wrong pause length: %s" msgstr "" #. "Пауза: %dс" -#: usage.c:397 +#: usage.c:436 #, c-format msgid "Pause: %ds" msgstr "" #. "Скорость считывания - беззнаковое целое!" -#: usage.c:402 +#: usage.c:441 msgid "Readout speed should be unsigned int!" msgstr "" #. "Полный сброс" -#: usage.c:410 +#: usage.c:449 msgid "Reset" msgstr "" #. "Спящий режим" -#: usage.c:416 +#: usage.c:455 msgid "Go to sleep" msgstr "" #. "Неверное значение температуры: %s (должно быть от -35 до 30)" -#: usage.c:433 +#: usage.c:472 #, c-format msgid "Wrong temperature: %s (must be from -35 to 30)" msgstr "" #. "Установить температуру: %.3f" -#: usage.c:437 +#: usage.c:476 #, c-format msgid "Set temperature: %.3f" msgstr "" #. "Верт. биннинг: %d" -#: usage.c:445 +#: usage.c:484 #, c-format msgid "Vertical binning: %d" msgstr "" #. "Номер турели должен быть больше 0" -#: usage.c:451 +#: usage.c:490 msgid "Turret number should be positive value" msgstr "" #. "Работать с турелью %d" -#: usage.c:453 +#: usage.c:492 #, c-format msgid "Work with turret %d" msgstr "" #. "Активировать камеру" -#: usage.c:459 +#: usage.c:498 msgid "Wakeup camera" msgstr "" #. "Неверное время экспозиции: %s" -#: usage.c:465 +#: usage.c:504 #, c-format msgid "Wrong exposure time: %s" msgstr "" #. "Время экспозиции: %dмс" -#: usage.c:468 +#: usage.c:507 #, c-format msgid "Exposure time: %dms" msgstr "" #. "Диапазон по X: [%d, %d]" -#: usage.c:473 +#: usage.c:512 #, c-format msgid "X range: [%d, %d]" msgstr "" #. "Диапазон по Y: [%d, %d]" -#: usage.c:478 +#: usage.c:517 #, c-format msgid "Y range: [%d, %d]" msgstr "" #. "Игнорирую аргумент[ы]:\n" -#: usage.c:496 +#: usage.c:535 #, c-format msgid "Ignore argument[s]:\n" msgstr "" #. -255. - there's no thermometer on hot side #. "В вашем светоприемнике нет \"горячего\" термометра" -#: camtools.c:83 +#: camtools.c:105 msgid "Your camera have no hot temperature sensor\n" msgstr "" #. "Устанавливаю скорость вращения вентиляторов в %d\n" -#: camtools.c:97 +#: camtools.c:119 #, c-format msgid "Set fan speed %d\n" msgstr "" #. "Целевая температура: %g\n" -#: camtools.c:110 +#: camtools.c:132 #, c-format msgid "Cooler setpoint: %g\n" msgstr "" #. "Холодильник отключен" -#: camtools.c:115 +#: camtools.c:137 msgid "Cooler is off" msgstr "" #. "Установка заданной температуры" -#: camtools.c:118 +#: camtools.c:140 msgid "Go to setpoint" msgstr "" #. "Поддержание заданной температуры" -#: camtools.c:121 +#: camtools.c:143 msgid "Keeping setpoint" msgstr "" #. "Статус неизвестен" -#: camtools.c:124 +#: camtools.c:146 msgid "Unknown status" msgstr "" #. "Статистика по изображению:\n" -#: camtools.c:148 +#: camtools.c:170 #, c-format msgid "Image stat:\n" msgstr "" + +#: macros.c:175 +msgid "No filename given!" +msgstr "" + +#: macros.c:177 +#, c-format +msgid "Can't open %s for reading" +msgstr "" + +#: macros.c:179 +#, c-format +msgid "Can't stat %s" +msgstr "" + +#: macros.c:182 +msgid "Mmap error for input" +msgstr "" + +#: macros.c:183 +msgid "Can't close mmap'ed file" +msgstr "" + +#: macros.c:192 +msgid "Can't munmap" +msgstr "" diff --git a/locale/ru/ru.po b/locale/ru/ru.po index 4851252..83cb851 100644 --- a/locale/ru/ru.po +++ b/locale/ru/ru.po @@ -3,26 +3,29 @@ # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # +#, fuzzy msgid "" msgstr "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2013-08-29 10:54+0400\n" - "PO-Revision-Date: 2011-06-28 09:22+0300\n" - "Last-Translator: Edward V. Emelianov \n" + "POT-Creation-Date: 2015-03-11 18:55+0300\n" + "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" + "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=koi8-r\n" "Content-Transfer-Encoding: 8bit\n" + "#-#-#-#-# ru.po (PACKAGE VERSION) #-#-#-#-#\n" + "#-#-#-#-# ruru.po (PACKAGE VERSION) #-#-#-#-#\n" #. "\tОпции:\n" -#: usage.c:101 +#: usage.c:126 #, c-format msgid "\tOptions:\n" msgstr "\tОпции:\n" #. "Обнаружен работающий процесс (pid=%d), выход.\n" -#: takepic.c:108 takepic.c:120 +#: takepic.c:222 takepic.c:234 #, c-format msgid "\n" "Found running process (pid=%d), exit.\n" @@ -30,7 +33,7 @@ msgstr "\n" "Обнаружен работающий процесс (pid=%d), выход.\n" #. "\nЗатвор " -#: takepic.c:273 +#: takepic.c:409 #, c-format msgid "\n" "The shutter is " @@ -38,610 +41,697 @@ msgstr "\n" "Затвор " #. "%d секунд до окончания паузы\n" -#: takepic.c:450 +#: takepic.c:635 #, c-format msgid "%d seconds till pause ends\n" msgstr "%d секунд до окончания паузы\n" #. "Не введено никаких параметров" -#: usage.c:271 +#: usage.c:301 msgid "Any parameters are absent" msgstr "Не введено никаких параметров" #. "Поле изображения: (0, %d)(0, %d)" -#: takepic.c:305 +#: takepic.c:442 #, c-format msgid "Array field: (0, %d)(0, %d)" msgstr "Поле изображения: (0, %d)(0, %d)" +#: macros.c:183 +msgid "Can't close mmap'ed file" +msgstr "Не могу закрыть mmap'нутый файл" + #. "Не могу удалить PID-файл" -#: takepic.c:68 +#: takepic.c:136 msgid "Can't delete PIDfile" msgstr "Не могу удалить PID-файл" #. "Не могу переместить турель" -#: takepic.c:169 +#: takepic.c:268 msgid "Can't move turret" msgstr "Не могу переместить турель" +#: macros.c:192 +msgid "Can't munmap" +msgstr "Не могу вызывать munmap" + +#: macros.c:177 +#, c-format +msgid "Can't open %s for reading" +msgstr "Не могу открыть %s для чтения" + +#. "Не могу открыть окно OpenGL, просмотр будет недоступен!" +#: takepic.c:608 +msgid "Can't open OpenGL window, image preview will be inaccessible" +msgstr "" + +#. "Не могу открыть камеру, завершаю" +#: takepic.c:347 +msgid "Can't open camera device, exit" +msgstr "Не могу открыть камеру, завершаю" + +#. "Не могу открыть файл устройства %s: %s" +#: takepic.c:116 +#, c-format +msgid "Can't open device file %s: %s" +msgstr "Не могу открыть файл устройства %s: %s" + #. "Не могу открыть файл журнала статистики" -#: takepic.c:264 +#: takepic.c:400 msgid "Can't open statistics log file" msgstr "Не могу открыть журнал статистики" #. "Не могу открыть файл журнала температур" -#: takepic.c:250 +#: takepic.c:386 msgid "Can't open temperature log file" msgstr "Не могу открыть журнал температур" #. "Не могу открыть турель" -#: takepic.c:152 +#: takepic.c:251 msgid "Can't open turret" msgstr "Не могу открыть турель" #. "Не могу сохранить файл" -#: takepic.c:428 +#: takepic.c:595 msgid "Can't save file" msgstr "Не могу сохранить файл" +#: macros.c:179 +#, c-format +msgid "Can't stat %s" +msgstr "Не могу выполнить stat для %s" + #. "Захват кадра %d, время экспозиции - %g секунд\n" -#: takepic.c:380 +#: takepic.c:546 #, c-format msgid "Capture frame %d, exp time - %g sec\n" msgstr "Захват кадра %d, время экспозиции - %g секунд\n" #. "Изменение температуры холодильника" -#: takepic.c:291 +#: takepic.c:428 msgid "Changing of cooler setpoint" msgstr "Изменение температуры холодильника" #. "Холодильник отключен" -#: camtools.c:115 +#: camtools.c:137 msgid "Cooler is off" msgstr "Холодильник отключен" #. "Целевая температура: %g\n" -#: camtools.c:110 +#: camtools.c:132 #, c-format msgid "Cooler setpoint: %g\n" msgstr "Целевая температура: %g\n" #. "Съемка темновых" -#: usage.c:295 +#: usage.c:325 msgid "Dark frames" msgstr "Съемка темновых" +#. "Устройство не найдено" +#: takepic.c:108 +msgid "Device not found" +msgstr "Устройство не найдено" + +#. "Отобразить на экране полученное изображение" +#: usage.c:138 +msgid "Display last image" +msgstr "Отобразить на экране полученное изображение" + #. "не засвечивать матрицу перед экспозицией" -#: usage.c:113 +#: usage.c:141 msgid "Don't flash CCD chip before expose" msgstr "не засвечивать матрицу перед экспозицией" +#. "Не могу вызывать ioctl" +#: takepic.c:123 +msgid "Error in ioctl" +msgstr "Не могу вызывать ioctl" + #. "Ошибка перехода в спящий режим!" -#: takepic.c:236 +#: takepic.c:372 msgid "Error: sleepless night!" msgstr "Ошибка перехода в спящий режим!" +#. "Не заданы параметры экспозиции, отключаюсь" +#: takepic.c:339 +msgid "Expose parameters aren't specified, exit" +msgstr "" + #. "Время экспозиции: %dмс" -#: usage.c:468 +#: usage.c:507 #, c-format msgid "Exposure time: %dms" msgstr "Время экспозиции: %dмс" #. "Скорость вентилятора должна быть в пределе 0..3" -#: usage.c:305 +#: usage.c:344 msgid "Fan speed should be in interval 0..3" msgstr "Скорость вентилятора должна быть в пределе 0..3" #. "Установить скорость вращения вентиляторов в %d" -#: usage.c:307 +#: usage.c:346 #, c-format msgid "Fan speed would be set to %d" msgstr "Установить скорость вращения вентиляторов в %d" #. "Видимое поле: %s" -#: takepic.c:303 +#: takepic.c:440 #, c-format msgid "Field of view: %s" msgstr "Видимое поле: %s" #. "Файл записан в '%s'" -#: takepic.c:432 +#: takepic.c:599 #, c-format msgid "File saved as '%s'" msgstr "Файл записан в '%s'" #. "Обнаружена камера '%s' с датчиком '%s'" -#: takepic.c:226 +#: takepic.c:354 #, c-format msgid "Find camera '%s' with sensor '%s'" msgstr "Обнаружена камера '%s' с датчиком '%s'" #. Полное журналирование статистики -#: usage.c:351 +#: usage.c:390 msgid "Full statistics logging" msgstr "Полное журналирование статистики" #. "Получен сигнал %d, отключаюсь.\n" -#: takepic.c:62 +#: takepic.c:133 #, c-format msgid "Get signal %d, quit.\n" msgstr "Получен сигнал %d, отключаюсь.\n" #. "Получить информацию о турели" -#: usage.c:313 +#: usage.c:352 msgid "Get turret's info" msgstr "Получить информацию о турели" #. "Установка заданной температуры" -#: camtools.c:118 +#: camtools.c:140 msgid "Go to setpoint" msgstr "Установка заданной температуры" #. "Спящий режим" -#: usage.c:416 +#: usage.c:455 msgid "Go to sleep" msgstr "Спящий режим" #. "Гор. биннинг: %d" -#: usage.c:336 +#: usage.c:375 #, c-format msgid "Horisontal binning: %d" msgstr "Гор. биннинг: %d" #. "Игнорирую аргумент[ы]:\n" -#: usage.c:496 +#: usage.c:535 #, c-format msgid "Ignore argument[s]:\n" msgstr "Игнорирую аргумент[ы]:\n" #. "Статистика по изображению:\n" -#: camtools.c:148 +#: camtools.c:170 #, c-format msgid "Image stat:\n" msgstr "Статистика по изображению\n" #. "Тип изображения - %s" -#: usage.c:341 +#: usage.c:380 #, c-format msgid "Image type - %s" msgstr "Тип изображения - %s" #. "Название прибора - %s" -#: usage.c:346 +#: usage.c:385 #, c-format msgid "Instrument name - %s" msgstr "Название прибора - %s" #. "Поддержание заданной температуры" -#: camtools.c:121 +#: camtools.c:143 msgid "Keeping setpoint" msgstr "Поддержание заданной температуры" +#: macros.c:182 +msgid "Mmap error for input" +msgstr "Ошибка mmap для входных данных" + #. "Переместить турель в позицию %d" -#: usage.c:321 +#: usage.c:360 #, c-format msgid "Move turret into %d" msgstr "Переместить турель в позицию %d" +#: macros.c:175 +msgid "No filename given!" +msgstr "Не указано имя файла!" + #. "Не засвечивать камеру до экспозиции" -#: usage.c:300 +#: usage.c:339 msgid "No pre-expose flash" msgstr "Не засвечивать камеру до экспозиции" #. "Имя объекта - %s" -#: usage.c:379 +#: usage.c:418 #, c-format msgid "Object name - %s" msgstr "Имя объекта - %s" #. "Наблюдатели: %s" -#: usage.c:384 +#: usage.c:423 #, c-format msgid "Observers: %s" msgstr "Наблюдатели: %s" #. "Работать с камерой номер %d" -#: usage.c:366 +#: usage.c:405 #, c-format msgid "Open camera number %d" msgstr "Работать с камерой номер %d" #. "Пауза: %dс" -#: usage.c:397 +#: usage.c:436 #, c-format msgid "Pause: %ds" msgstr "Пауза: %dс" #. "Номер позиции должен быть больше 0" -#: usage.c:319 +#: usage.c:358 msgid "Position number should be positive value" msgstr "Номер позиции должен быть больше 0" #. pre-expose #. "Предварительная экспозиция" -#: takepic.c:341 +#: takepic.c:466 msgid "Pre-expose" msgstr "Предварительная экспозиция" +#. "Нажмите Ctrl+C еще %d раз[а], чтобы прервать считывание\n" +#: takepic.c:154 +#, c-format +msgid "Press Ctrl+C %d time[s] more to interrupt reading\n" +msgstr "Нажмите Ctrl+C еще %d раз[а], чтобы прервать считывание\n" + #. "Автор программы: %s" -#: usage.c:283 +#: usage.c:313 #, c-format msgid "Program author: %s" msgstr "Автор программы: %s" #. "Название программы: %s" -#: usage.c:389 +#: usage.c:428 #, c-format msgid "Program name: %s" msgstr "Название программы: %s" #. "Считывание изображения:" -#: takepic.c:408 +#: takepic.c:575 #, c-format msgid "Read image: " msgstr "Считывание изображения: " #. "Ошибка считывания: %s\n" -#: takepic.c:353 takepic.c:414 +#: takepic.c:490 takepic.c:581 #, c-format msgid "Readout error: %s\n" msgstr "Ошибка считывания: %s\n" #. "Скорость считывания - беззнаковое целое!" -#: usage.c:402 +#: usage.c:441 msgid "Readout speed should be unsigned int!" msgstr "Скорость считывания - беззнаковое целое!" #. "Требуемая позиция больше максимальной" -#: takepic.c:164 +#: takepic.c:263 msgid "Required position greater then max" msgstr "ребуемая позиция больше максимальной" #. "Полный сброс" -#: usage.c:410 +#: usage.c:449 msgid "Reset" msgstr "Полный сброс" #. "Сохранение журнала температур" -#: usage.c:357 +#: usage.c:396 msgid "Save temperature log" msgstr "Сохранение журнала температур" #. "Серия из %d кадров" -#: usage.c:374 +#: usage.c:413 #, c-format msgid "Series of %d frames" msgstr "Серия из %d кадров" #. "отключить холодильник" -#: usage.c:107 usage.c:289 +#: usage.c:132 usage.c:319 msgid "Set cooler off" msgstr "отключить холодильник" #. "Устанавливаю скорость вращения вентиляторов в %d\n" -#: camtools.c:97 +#: camtools.c:119 #, c-format msgid "Set fan speed %d\n" msgstr "Устанавливаю скорость вращения вентиляторов в %d\n" #. "Установить скорость вентиляторов в F (0..3)" -#: usage.c:116 +#: usage.c:144 msgid "Set fan speed to F (0..3)" msgstr "Установить скорость вентиляторов в F (0..3)" #. "Установить интервал логгирования в %d секунд" -#: usage.c:328 +#: usage.c:367 #, c-format msgid "Set logging interval to %d seconds" msgstr "Установить интервал логгирования в %d секунд" #. "Установить температуру: %.3f" -#: usage.c:437 +#: usage.c:476 #, c-format msgid "Set temperature: %.3f" msgstr "Установить температуру: %.3f" #. "Отключение холодильника" -#: takepic.c:285 +#: takepic.c:422 msgid "Switch cooler off" msgstr "Отключение холодильника" #. "Температура ниже допустимой" -#: takepic.c:294 +#: takepic.c:431 msgid "The temperature setpoint is too low" msgstr "Температура ниже допустимой" #. "Максимальная (MAX) и текущая (CUR) позиции турели:\n" -#: takepic.c:159 +#: takepic.c:258 #, c-format msgid "Turret MAXimum position and CURrent position:\n" msgstr "Максимальная (MAX) и текущая (CUR) позиции турели:\n" #. "Номер турели должен быть больше 0" -#: usage.c:451 +#: usage.c:490 msgid "Turret number should be positive value" msgstr "Номер турели должен быть больше 0" #. "Статус неизвестен" -#: camtools.c:124 +#: camtools.c:146 msgid "Unknown status" msgstr "Хрен знает что" #. "Использование:\t%s [опции] [префикс выходных файлов]\n" -#: usage.c:98 +#: usage.c:123 #, c-format msgid "Usage:\t%s [options] [output files prefix]\n" msgstr "Использование:\t%s [опции] [префикс выходных файлов]\n" #. "Значение time-interval должно быть натуральным числом" -#: usage.c:326 +#: usage.c:365 msgid "Value of time-interval must be non-zero positive" msgstr "Значение time-interval должно быть натуральным числом" #. "Верт. биннинг: %d" -#: usage.c:445 +#: usage.c:484 #, c-format msgid "Vertical binning: %d" msgstr "Верт. биннинг: %d" #. "Подождите завершения перемещения турели " -#: takepic.c:174 +#: takepic.c:273 #, c-format msgid "Wait, while turret is moving " msgstr "Подождите завершения перемещения турели " #. "Активировать камеру" -#: usage.c:459 +#: usage.c:498 msgid "Wakeup camera" msgstr "Активировать камеру" +#. "Отображение снятых кадров" +#: usage.c:331 +msgid "Will show images" +msgstr "Отображение снятых кадров" + #. "Работать с турелью %d" -#: usage.c:453 +#: usage.c:492 #, c-format msgid "Work with turret %d" msgstr "Работать с турелью %d" #. "Неверный" -#: usage.c:333 usage.c:442 +#: usage.c:372 usage.c:481 msgid "Wrong" msgstr "Неверный" #. "Неверный номер камеры: %s" -#: usage.c:363 +#: usage.c:402 #, c-format msgid "Wrong camera number: %s" msgstr "Неверный номер камеры: %s" #. "Неверное время экспозиции: %s" -#: usage.c:465 +#: usage.c:504 #, c-format msgid "Wrong exposure time: %s" msgstr "Неверное время экспозиции: %s" #. "Неверное кол-во кадров: %s" -#: usage.c:371 +#: usage.c:410 #, c-format msgid "Wrong frames number in series: %s" msgstr "Неверное кол-во кадров: %s" #. "Неверная нижняя граница: %s" -#: usage.c:77 +#: usage.c:102 #, c-format msgid "Wrong lower border: %s" msgstr "Неверная нижняя граница: %s" #. "Неверная пауза: %s" -#: usage.c:394 +#: usage.c:433 #, c-format msgid "Wrong pause length: %s" msgstr "Неверная пауза: %s" #. "Неверное значение температуры: %s (должно быть от -35 до 30)" -#: usage.c:433 +#: usage.c:472 #, c-format msgid "Wrong temperature: %s (must be from -35 to 30)" msgstr "Неверное значение температуры: %s (должно быть от -35 до 30)" #. "Неверная верхняя граница: %s" -#: usage.c:82 +#: usage.c:107 #, c-format msgid "Wrong upper border: %s" msgstr "Неверная верхняя граница: %s" #. "Диапазон по X: [%d, %d]" -#: usage.c:473 +#: usage.c:512 #, c-format msgid "X range: [%d, %d]" msgstr "Диапазон по X: [%d, %d]" #. "Диапазон по Y: [%d, %d]" -#: usage.c:478 +#: usage.c:517 #, c-format msgid "Y range: [%d, %d]" msgstr "Диапазон по Y: [%d, %d]" #. -255. - there's no thermometer on hot side #. "В вашем светоприемнике нет \"горячего\" термометра" -#: camtools.c:83 +#: camtools.c:105 msgid "Your camera have no hot temperature sensor\n" msgstr "В вашем светоприемнике нет \"горячего\" термометра\n" #. "заткрыть затвор" -#: usage.c:207 +#: usage.c:235 msgid "close shutter" msgstr "заткрыть затвор" #. "закрыт\n" -#: takepic.c:279 +#: takepic.c:415 #, c-format msgid "closed\n" msgstr "закрыт\n" #. "не очищать матрицу после считывания" -#: usage.c:198 +#: usage.c:226 msgid "don't flush ccd after expose" msgstr "не очищать матрицу после считывания" #. "не открывать устройство, лишь отобразить шапку FITS" -#: usage.c:210 +#: usage.c:238 msgid "don't open camera device, just show FITS header" msgstr "не открывать устройство, лишь отобразить шапку FITS" #. "не сохранять изображения, лишь вести запись статистки" -#: usage.c:137 +#: usage.c:165 msgid "don't save images, only make all-stat log" msgstr "не сохранять изображения, лишь вести запись статистки" #. "Полный сброс" -#: usage.c:164 +#: usage.c:192 msgid "full reset" msgstr "Полный сброс" #. получить сведения о турели -#: usage.c:119 +#: usage.c:147 msgid "get turret's parameters" msgstr "получить сведения о турели" #. "перейти в спящий режим" -#: usage.c:167 +#: usage.c:195 msgid "go to sleeping mode" msgstr "перейти в спящий режим" #. "биннинг N пикселей по горизонтали" -#: usage.c:128 +#: usage.c:156 msgid "horizontal binning to N pixels" msgstr "биннинг N пикселей по горизонтали" #. "тип изображения" -#: usage.c:131 +#: usage.c:159 msgid "image type" msgstr "тип изображения" #. "название прибора" -#: usage.c:134 +#: usage.c:162 msgid "instrument name" msgstr "название прибора" #. "выполнить предварительную нулевую экспозицию для очистки матрицы" -#: usage.c:201 +#: usage.c:229 msgid "make a preliminary zero exposition for cleaning CCD" msgstr "выполнить предварительную нулевую экспозицию для очистки матрицы" #. "выдержать ptime секунд между экспозициями" -#: usage.c:158 +#: usage.c:186 msgid "make pause for ptime seconds between expositions" msgstr "выдержать ptime секунд между экспозициями" #. "N кадров в серии" -#: usage.c:146 +#: usage.c:174 msgid "make series of N frames" msgstr "N кадров в серии" #. "вести запись рабочих температур в файл temp_log" -#: usage.c:140 +#: usage.c:168 msgid "make temperatures logging to file temp_log" msgstr "вести запись рабочих температур в файл temp_log" +#. "Ошибка выделения памяти!" +#: takepic.c:480 takepic.c:509 +msgid "malloc() failed!" +msgstr "" + #. "не открывать затвор при экспозиции (\"темновые\")" -#: usage.c:110 +#: usage.c:135 msgid "not open shutter when exposing (\"dark frames\")" msgstr "не открывать затвор при экспозиции (\"темновые\")" #. "не сохранять изображение, а только отобразить статистику" -#: usage.c:170 +#: usage.c:198 msgid "not save image, just show statistics" msgstr "не сохранять изображение, а только отобразить статистику" #. "название объекта" -#: usage.c:149 +#: usage.c:177 msgid "object name" msgstr "название объекта" #. "имена наблюдателей" -#: usage.c:152 +#: usage.c:180 msgid "observers' names" msgstr "имена наблюдателей" #. "название программы наблюдений" -#: usage.c:155 +#: usage.c:183 msgid "observing program name" msgstr "название программы наблюдений" #. "только задать/получить температуру" #. "только отобразить/задать температуру" -#: usage.c:173 usage.c:426 +#: usage.c:201 usage.c:465 msgid "only set/get temperature" msgstr "только задать/получить температуру" #. "открыт\n" -#: takepic.c:276 +#: takepic.c:412 #, c-format msgid "open\n" msgstr "открыт\n" #. "открыть затвор" -#: usage.c:204 +#: usage.c:232 msgid "open shutter" msgstr "открыть затвор" #. "автор программы" -#: usage.c:104 +#: usage.c:129 msgid "program author" msgstr "автор программы" #. "возобновить питание" -#: usage.c:185 +#: usage.c:213 msgid "resume system" msgstr "возобновить питание" #. "выбрать диапазон для считывания" -#: usage.c:191 usage.c:194 +#: usage.c:219 usage.c:222 msgid "select clip region" msgstr "выбрать диапазон для считывания" #. "время экспозиции exptime мс" -#: usage.c:188 +#: usage.c:216 msgid "set exposure time to exptime ms" msgstr "время экспозиции exptime мс" #. "установить скорость считывания в N" -#: usage.c:161 +#: usage.c:189 msgid "set readout speed to N" msgstr "установить скорость считывания в N" #. переместить турель в N-ю позицию -#: usage.c:122 +#: usage.c:150 msgid "set turret to Nth position" msgstr "переместить турель в N-ю позицию" #. установить номер турели в N -#: usage.c:182 +#: usage.c:210 msgid "set turret's number to N" msgstr "установить номер турели в N" #. "задать рабочую температуру degr градусов" -#: usage.c:176 +#: usage.c:204 msgid "set work temperature to degr C" msgstr "задать рабочую температуру degr градусов" #. "интервал времени между последовательными записями в лог и HISTORY (в секундах)" -#: usage.c:125 +#: usage.c:153 msgid "time interval between sequential writings to log & HISTORY (in " "seconds)" msgstr "интервал времени между последовательными записями в лог и HISTORY (в " "секундах)" #. "биннинг N пикселей по вертикали" -#: usage.c:179 +#: usage.c:207 msgid "vertical binning to N pixels" msgstr "биннинг N пикселей по вертикали" #. "работать в 12-битном режиме" -#: usage.c:213 +#: usage.c:241 msgid "work in a 12-bit ADC mode" msgstr "работать в 12-битном режиме" #. "работать с N-й камерой" -#: usage.c:143 +#: usage.c:171 msgid "work with Nth camera" msgstr "работать с N-й камерой" + +#~ msgid "Can't init mutex!" +#~ msgstr "Не могу инициировать взаимное исключение!" + +#~ msgid "Error removing from list" +#~ msgstr "Ошибка удаления из списка" + +#~ msgid "can't cancel a thread!" +#~ msgstr "Не могу отменить выполнение потока!" diff --git a/macros.c b/macros.c new file mode 100644 index 0000000..cc6bfe1 --- /dev/null +++ b/macros.c @@ -0,0 +1,195 @@ +/* + * usefull_macros.h - a set of usefull functions: memory, color etc + * + * Copyright 2013 Edward V. Emelianoff + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "macros.h" + + +#include +/** + * function for different purposes that need to know time intervals + * @return double value: time in seconds + */ +double dtime(){ + double t; + struct timeval tv; + gettimeofday(&tv, NULL); + t = tv.tv_sec + ((double)tv.tv_usec)/1e6; + return t; +} + +/******************************************************************************\ + * Coloured terminal +\******************************************************************************/ +int globErr = 0; // errno for WARN/ERR + +// pointers to coloured output printf +int (*red)(const char *fmt, ...); +int (*green)(const char *fmt, ...); +int (*_WARN)(const char *fmt, ...); + +/* + * format red / green messages + * name: r_pr_, g_pr_ + * @param fmt ... - printf-like format + * @return number of printed symbols + */ +int r_pr_(const char *fmt, ...){ + va_list ar; int i; + printf(RED); + va_start(ar, fmt); + i = vprintf(fmt, ar); + va_end(ar); + printf(OLDCOLOR); + return i; +} +int g_pr_(const char *fmt, ...){ + va_list ar; int i; + printf(GREEN); + va_start(ar, fmt); + i = vprintf(fmt, ar); + va_end(ar); + printf(OLDCOLOR); + return i; +} +/* + * print red error/warning messages (if output is a tty) + * @param fmt ... - printf-like format + * @return number of printed symbols + */ +int r_WARN(const char *fmt, ...){ + va_list ar; int i = 1; + fprintf(stderr, RED); + va_start(ar, fmt); + if(globErr){ + errno = globErr; + vwarn(fmt, ar); + errno = 0; + globErr = 0; + }else + i = vfprintf(stderr, fmt, ar); + va_end(ar); + i++; + fprintf(stderr, OLDCOLOR "\n"); + return i; +} + +const char stars[] = "****************************************"; +/* + * notty variants of coloured printf + * name: s_WARN, r_pr_notty + * @param fmt ... - printf-like format + * @return number of printed symbols + */ +int s_WARN(const char *fmt, ...){ + va_list ar; int i; + i = fprintf(stderr, "\n%s\n", stars); + va_start(ar, fmt); + if(globErr){ + errno = globErr; + vwarn(fmt, ar); + errno = 0; + globErr = 0; + }else + i = +vfprintf(stderr, fmt, ar); + va_end(ar); + i += fprintf(stderr, "\n%s\n", stars); + i += fprintf(stderr, "\n"); + return i; +} +int r_pr_notty(const char *fmt, ...){ + va_list ar; int i; + i = printf("\n%s\n", stars); + va_start(ar, fmt); + i += vprintf(fmt, ar); + va_end(ar); + i += printf("\n%s\n", stars); + return i; +} + +/** + * Run this function in the beginning of main() to setup locale & coloured output + */ +void initial_setup(){ + // setup coloured output + if(isatty(STDOUT_FILENO)){ // make color output in tty + red = r_pr_; green = g_pr_; + }else{ // no colors in case of pipe + red = r_pr_notty; green = printf; + } + if(isatty(STDERR_FILENO)) _WARN = r_WARN; + else _WARN = s_WARN; + // Setup locale + setlocale(LC_ALL, ""); + setlocale(LC_NUMERIC, "C"); +#ifndef NOGETTEXT + bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); + textdomain(GETTEXT_PACKAGE); +#endif +} + +/******************************************************************************\ + * Memory +\******************************************************************************/ +/* + * safe memory allocation for macro ALLOC + * @param N - number of elements to allocate + * @param S - size of single element (typically sizeof) + * @return pointer to allocated memory area + */ +void *my_alloc(size_t N, size_t S){ + void *p = calloc(N, S); + if(!p) ERR("malloc"); + //assert(p); + return p; +} + +/** + * Mmap file to a memory area + * + * @param filename (i) - name of file to mmap + * @return stuct with mmap'ed file or die + */ +mmapbuf *My_mmap(char *filename){ + int fd; + char *ptr; + size_t Mlen; + struct stat statbuf; + if(!filename) ERRX(_("No filename given!")); + if((fd = open(filename, O_RDONLY)) < 0) + ERR(_("Can't open %s for reading"), filename); + if(fstat (fd, &statbuf) < 0) + ERR(_("Can't stat %s"), filename); + Mlen = statbuf.st_size; + if((ptr = mmap (0, Mlen, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) + ERR(_("Mmap error for input")); + if(close(fd)) ERR(_("Can't close mmap'ed file")); + mmapbuf *ret = MALLOC(mmapbuf, 1); + ret->data = ptr; + ret->len = Mlen; + return ret; +} + +void My_munmap(mmapbuf *b){ + if(munmap(b->data, b->len)) + ERR(_("Can't munmap")); + FREE(b); +} + diff --git a/macros.h b/macros.h new file mode 100644 index 0000000..1c53c1b --- /dev/null +++ b/macros.h @@ -0,0 +1,117 @@ +/* + * macros.h + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#pragma once +#ifndef __MACROS_H__ +#define __MACROS_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// not used args +#ifndef _U_ +#define _U_ __attribute__((__unused__)) +#endif + +#define check_ptr(ptr, fn) \ + if((ptr) == NULL) { \ + printf("%10s: NULL pointer\n",(char *)(fn)); \ + perror((char *)(fn)); \ + exit(1); \ + } + +#ifdef NOGETTEXT + #ifdef gettext + #undef gettext + #endif + #define gettext(arg) arg +#endif +#define _(String) gettext(String) +#define gettext_noop(String) String +#define N_(String) gettext_noop(String) + +/* + * Coloured messages output + */ +#define RED "\033[1;31;40m" +#define GREEN "\033[1;32;40m" +#define OLDCOLOR "\033[0;0;0m" + +extern int globErr; + +#define ERR(...) do{globErr=errno; _WARN(__VA_ARGS__); exit(-1);}while(0) +#define ERRX(...) do{globErr=0; _WARN(__VA_ARGS__); exit(-1);}while(0) +#define WARN(...) do{globErr=errno; _WARN(__VA_ARGS__);}while(0) +#define WARNX(...) do{globErr=0; _WARN(__VA_ARGS__);}while(0) + +/* + * print function name, debug messages + * debug mode, -DEBUG + */ +#ifdef EBUG + #define FNAME() fprintf(stderr, "\n%s (%s, line %d)\n", __func__, __FILE__, __LINE__) + #define DBG(...) do{fprintf(stderr, "%s (%s, line %d): ", __func__, __FILE__, __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n");} while(0) +#else + #define FNAME() do{}while(0) + #define DBG(...) do{}while(0) +#endif //EBUG + +/* + * Memory allocation + */ +#define ALLOC(type, var, size) type * var = ((type *)my_alloc(size, sizeof(type))) +#define MALLOC(type, size) ((type *)my_alloc(size, sizeof(type))) +#define FREE(ptr) do{free(ptr); ptr = NULL;}while(0) + +// functions for color output in tty & no-color in pipes +extern int (*red)(const char *fmt, ...); +extern int (*_WARN)(const char *fmt, ...); +extern int (*green)(const char *fmt, ...); +void * my_alloc(size_t N, size_t S); +void initial_setup(); + +// mmap file +typedef struct{ + char *data; + size_t len; +} mmapbuf; +mmapbuf *My_mmap(char *filename); +void My_munmap(mmapbuf *b); + +#endif // __MACROS_H__ diff --git a/takepic.c b/takepic.c index 61c2314..8aa4933 100644 --- a/takepic.c +++ b/takepic.c @@ -1,3 +1,24 @@ +/* + * takepic.c + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + #include "takepic.h" #include #include @@ -11,6 +32,10 @@ #include "usage.h" #include "camtools.h" #include "bta_print.h" +#include "macros.h" +#ifdef IMAGEVIEW +#include "imageview.h" +#endif #define BUFF_SIZ 4096 #define PROC_BASE "/proc" @@ -106,15 +131,18 @@ static void signals(int sig){ int u; // "Получен сигнал %d, отключаюсь.\n" printf(_("Get signal %d, quit.\n"), sig); + u = unlink(pidfilename); + // "Не могу удалить PID-файл" + if(u == -1) perror(_("Can't delete PIDfile")); ApnGlueWheelClose(); DBG("wheel closed"); // ApnGlueExpAbort(); // this function stubs all! // DBG("exp aborted"); ApnGlueClose(); DBG("device closed"); - u = unlink(pidfilename); - // "Не могу удалить PID-файл" - if(u == -1) perror(_("Can't delete PIDfile")); + #ifdef IMAGEVIEW + clear_GL_context(); + #endif exit(sig); } @@ -148,6 +176,13 @@ void catch_signals(){ //signal(SIGTSTP, SIG_IGN); // ignore ctrl+Z } +void restore_signals(){ + sigcounter = 3; + for(int _=0; _<256; _++) + signal(_, SIG_DFL); + unlink(pidfilename); +} + // check for running process void check4running(){ // get process name from /proc @@ -185,7 +220,7 @@ void check4running(){ if(readname(name, run) && strncmp(name, myname, 255) == 0){ // "Обнаружен работающий процесс (pid=%d), выход.\n" ERR(_("\nFound running process (pid=%d), exit.\n"), run); - exit(0); + exit(7); } } // there's no PID file or it's old @@ -197,7 +232,7 @@ void check4running(){ if(strncmp(name, myname, 255) == 0){ // "Обнаружен работающий процесс (pid=%d), выход.\n" ERR(_("\nFound running process (pid=%d), exit.\n"), pid); - exit(0); + exit(7); } } closedir(dir); @@ -246,6 +281,22 @@ wheelret: ApnGlueWheelClose(); } +#ifdef IMAGEVIEW +void change_displayed_image(_U_ unsigned short *buf, windowData *win){ + FNAME(); + if(!win) return; + pthread_mutex_lock(&win->mutex); + int w = win->image->w, h = win->image->h; + static GLubyte i = 0; + GLubyte *raw = win->image->rawdata; + DBG("image size: %dx%d",w,h); + convert_grayimage(buf, raw, w, h); + win->image->changed = 1; + pthread_mutex_unlock(&win->mutex); + i++; +} +#endif + int main(int argc, char **argv){ int i; //cycles int pid = -1, vid = -1; // device pid/vid @@ -256,13 +307,19 @@ int main(int argc, char **argv){ int imW=0, imH=0; // real (with binning) image size unsigned short *buf = NULL; // image buffer double mintemp=0.; +#ifdef IMAGEVIEW + _U_ windowData *mainwin = NULL; + _U_ rawimage im; +#endif + initial_setup(); // setup for macros.c //setlocale(LC_ALL, getenv("LC_ALL")); - setlocale(LC_ALL, ""); +/* setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); //bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); textdomain(GETTEXT_PACKAGE); +*/ parse_args(argc, argv); @@ -272,20 +329,25 @@ int main(int argc, char **argv){ if(test_headers){ writefits(NULL, imW, imH, NULL); - exit(0); + return(0); } // Turret block if(open_turret) parse_turret_args(); - if(only_turret) goto returning; + if(only_turret){ + // "Не заданы параметры экспозиции, отключаюсь" + info(_("Expose parameters aren't specified, exit")); + goto returning; + } // And camera block // First - open camera devise if(ApnGlueOpen(Ncam)){ // "Не могу открыть камеру, завершаю" ERR(_("Can't open camera device, exit")); - return 1; + exit(9); } +DBG("open %d", Ncam); ApnGlueGetName(&sensor, &camera); camera = strdup(camera); sensor = strdup(sensor); // "Обнаружена камера '%s' с датчиком '%s'" @@ -398,7 +460,7 @@ int main(int argc, char **argv){ ApnGlueSetDatabits(Apn_Resolution_SixteenBit); if(ROspeed) ApnGlueSetSpeed(ROspeed); - DBG("here"); + if(pre_exp){// pre-expose // "Предварительная экспозиция" info(_("Pre-expose")); @@ -415,18 +477,17 @@ int main(int argc, char **argv){ buf = (unsigned short*) calloc(L, sizeof(unsigned short)); if(!buf){ // "Ошибка выделения памяти!" - err(1, "malloc() failed"); + ERR(_("malloc() failed!")); } if(ApnGlueStartExp(&E, 0)){ + reset_usb_port(pid, vid); // "Ошибка экспозиции!" - ERR("Error exposing frame!"); - exit(-2); + if(ApnGlueStartExp(&E, 0)) ERR("Error exposing frame!"); } ignore_signals(); if(ApnGlueReadPixels(buf, L, whynot)){ // "Ошибка считывания: %s\n" ERR(_("Readout error: %s\n"), whynot); - exit(-2); } free(buf); // restore signals @@ -445,10 +506,23 @@ int main(int argc, char **argv){ buf = (unsigned short*) calloc(L, sizeof(unsigned short)); if(!buf){ // "Ошибка выделения памяти!" - err(1, "malloc() failed"); + ERR(_("malloc() failed!")); } +#ifdef IMAGEVIEW + // start image view module if not need to save image or manually defined displaying + if(!save_image || show_image){ + imageview_init(); + im.protected = 1; + im.rawdata = MALLOC(GLubyte, imW*imH*3); + if(!im.rawdata) ERR("Can't allocate memory"); + im.w = imW; im.h = imH; + } +#endif + DBG("start %d expositions", pics); for (i = 0; i < pics; i++){ + DBG("spd"); AutoadjustFanSpeed(FALSE); + DBG("cooler"); temperature = printCoolerStat(NULL); double E; int I; @@ -456,10 +530,11 @@ int main(int argc, char **argv){ E = (double) exptime / 1000.; I = (int) E; ignore_signals(); + DBG("start exp"); if(ApnGlueStartExp(&E, shutter)){ + reset_usb_port(pid, vid); // "Ошибка экспозиции!" - ERR("Error exposing frame!"); - continue; + if(ApnGlueStartExp(&E, shutter)) ERR("Error exposing frame!"); } DBG("Exposing"); #ifdef USE_BTA @@ -524,7 +599,25 @@ int main(int argc, char **argv){ if (r == 0) info(_("File saved as '%s'"), whynot); } } +#ifdef IMAGEVIEW + if(!save_image || show_image){ + if(!get_windows_amount() || !mainwin){ + mainwin = createGLwin("Sample window", 400, 400, &im); + if(!mainwin){ + // "Не могу открыть окно OpenGL, просмотр будет недоступен!" + info(_("Can't open OpenGL window, image preview will be inaccessible")); + }else{ + mainwin->killthread = 1; + } + } + } + if(get_windows_amount() && mainwin){ + DBG("change image"); + change_displayed_image(buf, mainwin); + } +#endif if(save_image){ + DBG("save image"); #ifdef USERAW WRITEIMG(writeraw, "raw"); #endif // USERAW @@ -552,15 +645,28 @@ int main(int argc, char **argv){ fflush(NULL); } returning: - // set fan speed to 0 or 3 according cooler status - if(!only_turret) AutoadjustFanSpeed(TRUE); - DBG("abort exp"); - ApnGlueExpAbort(); - DBG("close"); - ApnGlueClose(); - DBG("free buffers & close files"); - free(buf); - if(f_tlog) fclose(f_tlog); - if(f_statlog) fclose(f_statlog); + if(!only_turret){ + // set fan speed to 0 or 3 according cooler status + AutoadjustFanSpeed(TRUE); + DBG("abort exp"); + ApnGlueExpAbort(); + DBG("close"); + ApnGlueClose(); + restore_signals(); + DBG("free buffers & close files"); + free(buf); + if(f_tlog) fclose(f_tlog); + if(f_statlog) fclose(f_statlog); +#ifdef IMAGEVIEW + DBG("test for GL window"); + if(mainwin){ //window was created - wait for manual close + DBG("wait for window closing"); + while(get_windows_amount()){ + usleep(50000); + } + FREE(im.rawdata); + } +#endif + } return 0; } diff --git a/takepic.h b/takepic.h index 00783b5..eb02b11 100644 --- a/takepic.h +++ b/takepic.h @@ -1,3 +1,24 @@ +/* + * takepic.h + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once #ifndef __TAKEPIC_H__ #define __TAKEPIC_H__ #define _XOPEN_SOURCE 501 @@ -31,11 +52,6 @@ #define LOCALEDIR "./locale" #endif -#define _(String) gettext(String) -#define gettext_noop(String) String -#define N_(String) gettext_noop(String) - - /* * SAO longitude 41 26 29.175 * SAO latitude 43 39 12.7 @@ -51,6 +67,10 @@ #define TELALT 2070.0 #endif +/* +#define _(String) gettext(String) +#define gettext_noop(String) String +#define N_(String) gettext_noop(String) // режим отладки, -DEBUG #ifdef EBUG #define RED "\033[1;32;41m" @@ -68,6 +88,8 @@ fprintf(stderr, "\n");} while(0) #endif //EBUG +*/ + extern int test_headers; extern const char *__progname; diff --git a/usage.c b/usage.c index dd526ee..8047264 100644 --- a/usage.c +++ b/usage.c @@ -1,4 +1,26 @@ +/* + * usage.c + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + #include "usage.h" +#include "macros.h" Apn_Filter Tturret = Apn_Filter_FW50_7S; // turrer type int @@ -52,6 +74,9 @@ bool ,stat_logging = FALSE // full stat log ,only_turret = TRUE // only move turret ,open_turret = FALSE // work with turret +#ifdef IMAGEVIEW + ,show_image = FALSE // show image on webgl window +#endif ; int myatoi(int *num, const char *str){ // "careful" atoi @@ -108,6 +133,9 @@ void usage(char *fmt, ...){ printf("\t-d,\t--dark\t\t\t%s\n", // "не открывать затвор при экспозиции (\"темновые\")" _("not open shutter when exposing (\"dark frames\")")); + printf("\t-D,\t--display-image\t\t%s\n", + // "Отобразить на экране полученное изображение" + _("Display last image")); printf("\t-f,\t--no-flash\t\t%s\n", // "не засвечивать матрицу перед экспозицией" _("Don't flash CCD chip before expose")); @@ -215,8 +243,9 @@ void usage(char *fmt, ...){ } void parse_args(int argc, char **argv){ + FNAME(); int i; - char short_options[] = "A:cdfF:gG:H:h:I:i:LlN:n:O:o:P:p:Rr:SsTt:v:Ww:x:X:Y:"; + char short_options[] = "A:cdDfF:gG:H:h:I:i:LlN:n:O:o:P:p:Rr:SsTt:v:Ww:x:X:Y:"; struct option long_options[] = { /* { name, has_arg, flag, val }, где: * name - name of long parameter @@ -229,6 +258,7 @@ void parse_args(int argc, char **argv){ {"author", 1, 0, 'A'}, {"cooler-off", 0, 0, 'c'}, {"dark", 0, 0, 'd'}, + {"display-image",0, 0, 'D'}, {"no-flash", 0, 0, 'f'}, {"fan-speed", 1, 0, 'F'}, {"wheel-get", 0, 0, 'g'}, @@ -294,6 +324,15 @@ void parse_args(int argc, char **argv){ // "Съемка темновых" info(_("Dark frames")); break; + case 'D': +#ifdef IMAGEVIEW + show_image = TRUE; + // "Отображение снятых кадров" + info(_("Will show images")); +#else + ERR("%s was compiled without OpenGL support!", __progname); +#endif + break; case 'f': noflash = TRUE; // "Не засвечивать камеру до экспозиции" diff --git a/usage.h b/usage.h index 5e45ce0..fe93ade 100644 --- a/usage.h +++ b/usage.h @@ -1,3 +1,24 @@ +/* + * usage.h + * + * Copyright 2015 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#pragma once #ifndef __USAGE_H__ #define __USAGE_H__ @@ -49,6 +70,9 @@ extern bool ,stat_logging ,only_turret ,open_turret +#ifdef IMAGEVIEW + ,show_image +#endif ; extern char *objname