mirror of
https://github.com/eddyem/apogee_control.git
synced 2026-03-20 00:31:09 +03:00
Added image view module
This commit is contained in:
150
image_view_module/CMakeLists.txt
Normal file
150
image_view_module/CMakeLists.txt
Normal file
@@ -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)
|
||||
|
||||
|
||||
167
image_view_module/events.c
Normal file
167
image_view_module/events.c
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* events.c
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
42
image_view_module/events.h
Normal file
42
image_view_module/events.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* events.h
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <GL/glut.h>
|
||||
#include <GL/glext.h>
|
||||
#include <GL/freeglut.h>
|
||||
|
||||
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__
|
||||
455
image_view_module/imageview.c
Normal file
455
image_view_module/imageview.c
Normal file
@@ -0,0 +1,455 @@
|
||||
// bmpview.c
|
||||
//
|
||||
// Copyright 2010 Edward V. Emelianoff <eddy@sao.ru>
|
||||
//
|
||||
// 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 <pthread.h>
|
||||
#include <X11/Xlib.h> // 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;
|
||||
}
|
||||
52
image_view_module/imageview.h
Normal file
52
image_view_module/imageview.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* imageview.h
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#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__
|
||||
185
image_view_module/list.c
Normal file
185
image_view_module/list.c
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* simple_list.c - simple one-direction list
|
||||
*
|
||||
*
|
||||
* Copyright 2013 Edward V. Emelianoff <eddy@sao.ru>
|
||||
*
|
||||
* 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);
|
||||
}
|
||||
|
||||
69
image_view_module/list.h
Normal file
69
image_view_module/list.h
Normal file
@@ -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 <eddy@sao.ru>
|
||||
*
|
||||
* 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__
|
||||
BIN
image_view_module/locale/ru/LC_MESSAGES/openglview.mo
Normal file
BIN
image_view_module/locale/ru/LC_MESSAGES/openglview.mo
Normal file
Binary file not shown.
57
image_view_module/locale/ru/messages.po
Normal file
57
image_view_module/locale/ru/messages.po
Normal file
@@ -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 <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\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 ""
|
||||
63
image_view_module/locale/ru/ru.po
Normal file
63
image_view_module/locale/ru/ru.po
Normal file
@@ -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 <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\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 "îÅ ÍÏÇÕ ÏÔÍÅÎÉÔØ ×ÙÐÏÌÎÅÎÉÅ ÐÏÔÏËÁ!"
|
||||
149
image_view_module/main.c
Normal file
149
image_view_module/main.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* main.c
|
||||
*
|
||||
* Copyright 2015 Edward V. Emelianov <eddy@sao.ru, edward.emelianoff@gmail.com>
|
||||
*
|
||||
* 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 <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
6
image_view_module/main.h
Normal file
6
image_view_module/main.h
Normal file
@@ -0,0 +1,6 @@
|
||||
// pthread_t thread, thread_m;
|
||||
#include "events.h" // GLubyte etc
|
||||
|
||||
// GLubyte *prepareImage();
|
||||
void help(char *s);
|
||||
|
||||
Reference in New Issue
Block a user