diff --git a/Bresenham_circle.c b/Bresenham_circle.c new file mode 100644 index 0000000..d6b5731 --- /dev/null +++ b/Bresenham_circle.c @@ -0,0 +1,60 @@ +#include +#include +#include + +char *drawCircle(int R, int geom){ + if(R > 200 || R < 1) return NULL; + int S, i, Y = 2 * R + 2; + if(geom) + S = Y * (R + 1); + else + S = Y * (Y - 1); + char *buf = malloc(S+1); + if(!buf) return NULL; + memset(buf, ' ', S); + buf[S] = 0; + for(i = Y-1; i < S; i+=Y) buf[i] = '\n'; + inline void DrawPixel(int x, int y){ + if(geom){ + if(y%2==0) buf[Y * y/2 + x] = '*'; + }else{ + buf[Y * y + x] = '*'; + } + } + // Bresenham's circle algorithm + int x = R; + int y = 0; + int radiusError = 1-x; + while(x >= y){ + DrawPixel(x + R, y + R); + DrawPixel(y + R, x + R); + DrawPixel(-x + R, y + R); + DrawPixel(-y + R, x + R); + DrawPixel(-x + R, -y + R); + DrawPixel(-y + R, -x + R); + DrawPixel(x + R, -y + R); + DrawPixel(y + R, -x + R); + y++; + if (radiusError < 0){ + radiusError += 2 * y + 1; + }else{ + x--; + radiusError += 2 * (y - x) + 1; + } + } + return buf; +} + +int main(int argc, char **argv){ + int i, R; + char *buf; + for(i = 1; i < argc; i++){ + if(!(buf = drawCircle(R = atoi(argv[i]), 1))){ + printf("Wrong parameter %s\n", argv[i]); + continue; + } + printf("\nCircle with R = %d:\n%s\n", R, buf); + free(buf); buf = NULL; + } + return 0; +} diff --git a/image_view_module/bmpview.c b/image_view_module/bmpview.c deleted file mode 100644 index a14ed44..0000000 --- a/image_view_module/bmpview.c +++ /dev/null @@ -1,189 +0,0 @@ -// 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 "bmpview.h" -#include "macros.h" -#include - -int totWindows = 0; // total number of opened windows - -/* -void *GLloop(){ - FNAME(); - glutMainLoop(); - return NULL; -}*/ - -/** - * create window & run main loop - */ -void createWindow(windowData *win){ - FNAME(); - if(!win) return; - int w = win->w, h = win->h; -/* - char *argv[] = {PROJNAME, NULL}; - int argc = 1; - glutInit(&argc, argv); -*/ - glGenTextures(1, &(win->Tex)); - glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); - glutInitWindowSize(w, h); - win->GL_ID = glutCreateWindow(win->title); - DBG("created GL_ID=%d", win->GL_ID); - glutIdleFunc(Redraw); - glutReshapeFunc(Resize); - glutDisplayFunc(RedrawWindow); - glutKeyboardFunc(keyPressed); - glutSpecialFunc(keySpPressed); - glutMouseFunc(mousePressed); - glutMotionFunc(mouseMove); - win->z = 0.; - createMenu(win->ID); - 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); - 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, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, win->rawdata); - glDisable(GL_TEXTURE_2D); - totWindows++; -} -/* -void showid(int id){ - printf("ID: %d\n", id); -} -*/ -/** - * 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){ - windowData *win; - int canceled = 1; - if(type == OPENGL) - win = searchWindow_byGLID(window); - else - win = searchWindow(window); - if(!win) return 0; - //forEachWindow(showid); - pthread_mutex_lock(&win->mutex); - if(!pthread_cancel(win->thread)){ // cancel thread changing data - canceled = 0; - } - pthread_join(win->thread, NULL); - glDeleteTextures(1, &win->Tex); - glFinish(); - glutDestroyWindow(win->GL_ID); - win->GL_ID = 0; // reset for forEachWindow() - pthread_mutex_unlock(&win->mutex); - if(!canceled && !pthread_cancel(win->thread)){ // cancel thread changing data - WARN(_("can't cancel a thread!")); - } - pthread_join(win->thread, NULL); - if(!removeWindow(win->ID)) WARNX(_("Error removing from list")); - totWindows--; - //forEachWindow(showid); - return 1; -} - -void renderBitmapString(float x, float y, void *font, char *string, GLubyte *color){ - 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){ - glutSetWindow(GL_ID); - glutPostRedisplay(); -} - -void Redraw(){ - forEachWindow(redisplay); - usleep(10000); -} - -void RedrawWindow(){ - int window; - window = glutGetWindow(); - windowData *win = searchWindow_byGLID(window); - if(!win) return; - if(pthread_mutex_trylock(&win->mutex) != 0) return; - /* Clear the windwindowDataow to black */ - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glLoadIdentity(); - glTranslatef(-win->w/2.,-win->h/2., win->z); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, win->Tex); - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, win->w, win->h, GL_RGB, GL_UNSIGNED_BYTE, win->rawdata); - glBegin(GL_QUADS); - glTexCoord2f(0., 1.); glVertex3f(0., 0., 0.); - glTexCoord2f(0., 0.); glVertex3f(0., win->h, 0.); - glTexCoord2f(1., 0.); glVertex3f(win->w, win->h, 0.); - glTexCoord2f(1., 1.); glVertex3f(win->w, 0., 0.); - glEnd(); - glDisable(GL_TEXTURE_2D); - - glFinish(); - glutSwapBuffers(); - pthread_mutex_unlock(&win->mutex); -} - -void Resize(int width, int height){ - FNAME(); - 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); - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - GLfloat W = (GLfloat)GRAB_WIDTH; GLfloat H = (GLfloat)GRAB_HEIGHT; - //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(); -} - diff --git a/image_view_module/events.c b/image_view_module/events.c index bee6ee0..584a118 100644 --- a/image_view_module/events.c +++ b/image_view_module/events.c @@ -19,7 +19,7 @@ * MA 02110-1301, USA. */ #include "events.h" -#include "bmpview.h" +#include "imageview.h" #include "macros.h" /* * Функции для работы с OpenGL'ными событиями @@ -35,21 +35,29 @@ void keyPressed(unsigned char key, // //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 switch(key){ + case '1': // return zoom to 1 & image to 0 + win->zoom = 1; + win->x = 0; win->y = 0; + break; // case 'i': more_info = !more_info; // break; case 27: destroyWindow(window, OPENGL); break; case 'p': - printf("z = %f\n", win->z); + printf("zoom = %f\n", win->zoom); break; // case 'm': createWindow(&mainWindow); // break; // case 'w': createWindow(&WaveWindow); // break; - case 'Z': win->z += 1.0; - break; - case 'z': win->z -= 1.0; - break; + case 'Z': + win->zoom *= 1.1; + calc_win_props(win, NULL, NULL); + break; + case 'z': + win->zoom /= 1.1; + calc_win_props(win, NULL, NULL); + break; // case 'h': createWindow(&SubWindow); // break; } @@ -60,10 +68,28 @@ void keySpPressed(_U_ int key, _U_ int x, _U_ int y){ DBG("Sp. key pressed. mod=%d, keycode=%d, point=(%d,%d)\n", glutGetModifiers(), key, x,y); } -void mousePressed(int _U_ key, int _U_ state, _U_ int x, _U_ int y){ -// GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON - DBG("Mouse button %s. point=(%d, %d); mod=%d, button=%d\n", - (state == GLUT_DOWN)? "pressed":"released", x, y, glutGetModifiers(), key); +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(); + 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", x,y,X,Y); + if(key == GLUT_MIDDLE_BUTTON) movingwin = 1; + if(key == 3){ // wheel UP + }else if(key == 4){ // wheel DOWN + } + }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){ // щелкнули в окне с вейвлетом @@ -76,9 +102,36 @@ void mousePressed(int _U_ key, int _U_ state, _U_ int x, _U_ int y){ } */ } - +/* 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){ - DBG("Mouse moved to (%d, %d)\n", x, 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); + } } /** diff --git a/image_view_module/events.h b/image_view_module/events.h index 4fa41d6..b7fb208 100644 --- a/image_view_module/events.h +++ b/image_view_module/events.h @@ -27,6 +27,7 @@ #include #include #include +#include extern float Z; // координата Z (zoom) @@ -36,6 +37,6 @@ 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..c6d9266 --- /dev/null +++ b/image_view_module/imageview.c @@ -0,0 +1,398 @@ +// 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 + +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)); + calc_win_props(win, NULL, NULL); + win->zoom = 1. / win->Daspect; +// createMenu(win->ID); + 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); + 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++; + DBG("OK, total opened windows: %d", totWindows); +} + + +int killwindow(int GL_ID){ + DBG("try to kill win GL_ID=%d", GL_ID); + windowData *win; + int canceled = 1; + win = searchWindow_byGLID(GL_ID); + if(!win) return 0; + if(!pthread_cancel(win->thread)){ // cancel thread changing data + canceled = 0; + } +// pthread_join(win->thread, NULL); + glDeleteTextures(1, &win->Tex); + glFinish(); + glutDestroyWindow(win->GL_ID); + win->GL_ID = 0; // reset for forEachWindow() + pthread_mutex_unlock(&win->mutex); + if(!canceled && !pthread_cancel(win->thread)){ // cancel thread changing data + WARN(_("can't cancel a thread!")); + } + pthread_join(win->thread, NULL); + 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; + pthread_mutex_lock(&winini_mutex); + if(type == INNER){ + windowData *win = searchWindow(window); + if(win) r = killwindow(win->GL_ID); + }else + r = killwindow(window); + pthread_mutex_unlock(&winini_mutex); + return r; +} + +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){ + 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){ + while(1){ + pthread_mutex_lock(&winini_mutex); + if(!initialized) return 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; + } + forEachWindow(redisplay); + pthread_mutex_unlock(&winini_mutex); + if(totWindows) glutMainLoopEvent(); // process actions if there are windows + 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; + 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; + pthread_mutex_lock(&winini_mutex); + forEachWindow(killwindow_v); + pthread_cancel(GLUTthread); // kill main GLUT thread + pthread_join(GLUTthread, NULL); + initialized = 0; + pthread_mutex_unlock(&winini_mutex); +} + + +/* + * 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; +} + diff --git a/image_view_module/bmpview.h b/image_view_module/imageview.h similarity index 73% rename from image_view_module/bmpview.h rename to image_view_module/imageview.h index ac6310d..2c197dd 100644 --- a/image_view_module/bmpview.h +++ b/image_view_module/imageview.h @@ -1,5 +1,5 @@ /* - * bmpview.h + * imageview.h * * Copyright 2015 Edward V. Emelianov * @@ -33,11 +33,16 @@ typedef enum{ OPENGL } winIdType; -void createWindow(windowData *win); +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 Redraw(); -void RedrawWindow(); -void Resize(int width, int height); +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); #endif // __BMPVIEW_H__ diff --git a/image_view_module/list.c b/image_view_module/list.c index 795dc17..8215102 100644 --- a/image_view_module/list.c +++ b/image_view_module/list.c @@ -119,7 +119,7 @@ windowData *searchWindow_byGLID(int GL_ID){ /** * free() all data for node of list - * !!! data for raw pixels (rawdata) doesn't removed as it should be used + * !!! 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){ @@ -128,7 +128,10 @@ void WinList_freeNode(WinList **node){ windowData *win = cur->data; if(root == cur) root = next; FREE(win->title); - FREE(win->rawdata); + if(win->image->protected == 0){ + FREE(win->image->rawdata); + FREE(win->image); + } pthread_mutex_destroy(&win->mutex); FREE(*node); if(prev) @@ -154,7 +157,6 @@ int removeWindow(int winID){ /** * remove all nodes in list - * @param root - pointer to root node */ void freeWinList(){ WinList *node = root, *next; diff --git a/image_view_module/list.h b/image_view_module/list.h index f9fc67b..cd6ef56 100644 --- a/image_view_module/list.h +++ b/image_view_module/list.h @@ -29,14 +29,25 @@ #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 - GLubyte *rawdata; // raw image data - int w; int h; // image size - float z; // z-coordinate (zoom) + 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 pthread_t thread; // identificator of thread that changes window data pthread_mutex_t mutex;// mutex for operations with image } windowData; diff --git a/image_view_module/locale/ru/LC_MESSAGES/openglview.mo b/image_view_module/locale/ru/LC_MESSAGES/openglview.mo index 1e4cc61..88e0b13 100644 Binary files a/image_view_module/locale/ru/LC_MESSAGES/openglview.mo 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 index 8aabd6b..21fb0ab 100644 --- a/image_view_module/locale/ru/messages.po +++ b/image_view_module/locale/ru/messages.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-02-18 18:46+0300\n" +"POT-Creation-Date: 2015-02-28 19:36+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,41 +17,46 @@ msgstr "" "Content-Type: text/plain; charset=koi8-r\n" "Content-Transfer-Encoding: 8bit\n" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:175 +#: /home/eddy/tmp/image_view_module/macros.c:175 msgid "No filename given!" -msgstr "Не указано имя файла!" +msgstr "" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:177 +#: /home/eddy/tmp/image_view_module/macros.c:177 #, c-format msgid "Can't open %s for reading" -msgstr "Не могу открыть %s для чтения" +msgstr "" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:179 +#: /home/eddy/tmp/image_view_module/macros.c:179 #, c-format msgid "Can't stat %s" -msgstr "Не могу выполнить stat для %s" +msgstr "" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:182 +#: /home/eddy/tmp/image_view_module/macros.c:182 msgid "Mmap error for input" -msgstr "Ошибка mmap для входных данных" +msgstr "" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:183 +#: /home/eddy/tmp/image_view_module/macros.c:183 msgid "Can't close mmap'ed file" -msgstr "Не могу закрыть mmap'нутый файл" +msgstr "" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:192 +#: /home/eddy/tmp/image_view_module/macros.c:192 msgid "Can't munmap" -msgstr "Не могу вызывать munmap" - -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/main.c:106 -msgid "Can't init mutex!" -msgstr "Не могу инициировать взаимное исключение!" +msgstr "" #. cancel thread changing data -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/bmpview.c:102 +#: /home/eddy/tmp/image_view_module/imageview.c:124 msgid "can't cancel a thread!" -msgstr "Не могу отменить выполнение потока!" +msgstr "" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/bmpview.c:105 +#: /home/eddy/tmp/image_view_module/imageview.c:127 msgid "Error removing from list" -msgstr "Ошибка удаления из списка" +msgstr "" + +#: /home/eddy/tmp/image_view_module/imageview.c:318 +msgid "Can't init mutex!" +msgstr "" + +#. "Уже инициализировано!" +#: /home/eddy/tmp/image_view_module/imageview.c:345 +msgid "Already initialized!" +msgstr "" diff --git a/image_view_module/locale/ru/ru.po b/image_view_module/locale/ru/ru.po index c794abf..00c5d6e 100644 --- a/image_view_module/locale/ru/ru.po +++ b/image_view_module/locale/ru/ru.po @@ -7,7 +7,7 @@ msgid "" msgstr "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2015-02-18 18:46+0300\n" + "POT-Creation-Date: 2015-02-28 19:32+0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -16,41 +16,50 @@ msgstr "Project-Id-Version: PACKAGE VERSION\n" "Content-Type: text/plain; charset=koi8-r\n" "Content-Transfer-Encoding: 8bit\n" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:183 +#. "Уже инициализировано!" +#: /home/eddy/tmp/image_view_module/imageview.c:345 +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/wavelets-hough-and-so-on/image_view_module/main.c:106 +#: /home/eddy/tmp/image_view_module/imageview.c:318 msgid "Can't init mutex!" msgstr "Не могу инициировать взаимное исключение!" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:192 +#: /home/eddy/tmp/image_view_module/macros.c:192 msgid "Can't munmap" msgstr "Не могу вызывать munmap" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:177 +#: /home/eddy/tmp/image_view_module/macros.c:177 #, c-format msgid "Can't open %s for reading" msgstr "Не могу открыть %s для чтения" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:179 +#: /home/eddy/tmp/image_view_module/macros.c:179 #, c-format msgid "Can't stat %s" msgstr "Не могу выполнить stat для %s" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/bmpview.c:105 +#: /home/eddy/tmp/image_view_module/imageview.c:127 msgid "Error removing from list" msgstr "Ошибка удаления из списка" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:182 +#: /home/eddy/tmp/image_view_module/macros.c:182 msgid "Mmap error for input" msgstr "Ошибка mmap для входных данных" -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/macros.c:175 +#: /home/eddy/tmp/image_view_module/macros.c:175 msgid "No filename given!" msgstr "Не указано имя файла!" #. cancel thread changing data -#: /home/eddy/tmp/wavelets-hough-and-so-on/image_view_module/bmpview.c:102 +#: /home/eddy/tmp/image_view_module/imageview.c:124 msgid "can't cancel a thread!" msgstr "Не могу отменить выполнение потока!" + +#, fuzzy +#~ msgid "Can't init main GLUT mutex!" +#~ msgstr "Не могу инициировать взаимное исключение!" diff --git a/image_view_module/main.c b/image_view_module/main.c index d811a99..5a8160b 100644 --- a/image_view_module/main.c +++ b/image_view_module/main.c @@ -18,48 +18,28 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ - - #include #include #include #include -#include // XInitThreads(); #include "main.h" #include "macros.h" -#include "bmpview.h" - - -//GLubyte *BitmapBits = NULL; - -/* -pthread_mutex_t m_ima = PTHREAD_MUTEX_INITIALIZER, m_wvlt = PTHREAD_MUTEX_INITIALIZER, - m_hist = PTHREAD_MUTEX_INITIALIZER; -*/ -unsigned int bufsize; - -void help(char *s){ - fprintf(stderr, "\n\n%s, simple interface for LOMO's webcam \"microscope\"\n", s); - fprintf(stderr, "Usage: %s [-h] [-d videodev] [-c channel]\n\n", s); - fprintf(stderr, - "-h, --help:\tthis help\n" - "-d, --device:\tcapture from \n" - "-c, --channel:\tset channel (0..3)\n" - ); - fprintf(stderr, "\n\n"); -} +#include "imageview.h" void* change_image(void *data){ FNAME(); windowData *win = (windowData*) data; - int w = win->w, h = win->h, x,y, id = win->ID; + 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)) pthread_exit(NULL); + // DBG("found, lock mutex"); pthread_mutex_lock(&win->mutex); - GLubyte *raw = win->rawdata; + // DBG("refresh"); + GLubyte *raw = win->image->rawdata; for(y = 0; y < h; y++){ if(y%20 == 19){ raw += w*3; @@ -74,79 +54,49 @@ void* change_image(void *data){ raw += 3; } } + win->image->changed = 1; pthread_mutex_unlock(&win->mutex); usleep(10000); + //sleep(1); } } -/* -void *GLloop(void *data){ - FNAME(); - windowData *win = (windowData *)data; - createWindow(win); +void *main_thread(_U_ void *none){ +// while(1){}; + rawimage im; + windowData *mainwin, *win, *third; + 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); + 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(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; } -*/ - -/** - * create new window, run thread & return pointer to its structure or NULL - * @param title - header (copyed inside this function) - * @param w,h - image size - */ -windowData *createGLwin(char *title, int w, int h){ - windowData *win = MALLOC(windowData, 1); - if(!addWindow(win)){ - FREE(win); - return NULL; - } - GLubyte *raw = MALLOC(GLubyte, w*h*3); - win->title = strdup(title); - win->rawdata = raw; - if(pthread_mutex_init(&win->mutex, NULL)){ - WARN(_("Can't init mutex!")); - removeWindow(win->ID); - return NULL; - } - win->w = w; - win->h = h; -// pthread_create(&win->glthread, NULL, GLloop, (void*)win); - createWindow(win); - return win; -} - -/* -GLubyte *prepareImage(){ - static GLubyte *imPtr = NULL; - //static int bufferSize; - //int readlines, linesize; - //GLubyte *ptr; - if(!imPtr) imPtr = calloc(100, sizeof(GLubyte)); - return imPtr; -} -*/ - -int main(_U_ int argc, _U_ char** argv){ - windowData *mainwin, _U_ *win, _U_ *third; - int w = 640, h = 480; - - char *v[] = {PROJNAME, NULL}; - int c = 1; - glutInit(&c, v); +int main(_U_ int argc, _U_ char **argv){ + pthread_t mainthread; initial_setup(); // locale & messages - XInitThreads(); // we need it for threaded windows - //BitmapBits = prepareImage(); - mainwin = createGLwin("Sample window", w, h); - if(!mainwin) return 1; - pthread_create(&mainwin->thread, NULL, &change_image, (void*)mainwin); - win = createGLwin("Second window", w/2, h/2); - if(!win) return 1; - pthread_create(&win->thread, NULL, &change_image, (void*)win); - third = createGLwin("Second window", w/4, h/4); - if(!win) return 1; - pthread_create(&third->thread, NULL, &change_image, (void*)third); - // wait for end - glutMainLoop(); + imageview_init(); + DBG("init main thread"); + pthread_create(&mainthread, NULL, &main_thread, NULL); + pthread_join(mainthread, NULL); return 0; } - diff --git a/opengl.c b/opengl.c new file mode 100644 index 0000000..628221d --- /dev/null +++ b/opengl.c @@ -0,0 +1,44 @@ +// the simplest opengl example + +#include +#include +// compile: +// gcc -Wall -Wextra -Werror -lglut -lGL -lm -std=gnu99 -D_GNU_SOURCE opengl.c -o openglcircle + +#define _U_ __attribute__((__unused__)) +// exit by ctrl+q or escape +void keyPressed(unsigned char key, _U_ int x, _U_ int y){ + int mod = glutGetModifiers(); // window = glutGetWindow() + if(mod == GLUT_ACTIVE_CTRL && key == 'q') exit(0); + else if(key == 27) exit(0); +} + +void DrawCircle(float cx, float cy, float r, int num_segments){ + float theta = 2. * M_PI / (float)num_segments; + float c, s, t, x = r, y = 0.; + sincosf(theta, &s, &c); + glBegin(GL_LINE_LOOP); + for(int ii = 0; ii < num_segments; ii++){ + glVertex2f(x + cx, y + cy); + t = x; + x = c * x - s * y; + y = s * t + c * y; + } + glEnd(); +} + +void display(){ + glClear(GL_COLOR_BUFFER_BIT); + DrawCircle(0.,0.,0.5,100); + glFlush(); +} + +int main(int argc, char** argv){ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); + glutInitWindowSize(400, 400); + glutCreateWindow("A Simple Circle"); + glutDisplayFunc(display); + glutKeyboardFunc(keyPressed); + glutMainLoop(); +} diff --git a/sendfile.c b/sendfile.c new file mode 100644 index 0000000..07b2233 --- /dev/null +++ b/sendfile.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/* +./sendfile Titanik.mp4 +Copied by sendfile, time: 30.1055s +Copied by mmap, time: 35.6469s + +du Titanik.mp4 +2.6GTitanik.mp4 +*/ + + +double dtime(){ + double t; + struct timeval tv; + gettimeofday(&tv, NULL); + t = tv.tv_sec + ((double)tv.tv_usec)/1e6; + return t; +} + +typedef struct{ + char *data; + size_t len; +} mmapbuf; + +void My_munmap(mmapbuf **b){ + if(munmap((*b)->data, (*b)->len)) + perror("Can't munmap"); + free(*b); + *b = NULL; +} + +mmapbuf *My_mmap(char *filename){ + int fd; + char *ptr = NULL; + size_t Mlen; + struct stat statbuf; + if((fd = open(filename, O_RDONLY)) < 0){ + perror("Can't open file for reading"); + goto ret; + } + if(fstat (fd, &statbuf) < 0){ + perror("Can't stat file"); + goto ret; + } + Mlen = statbuf.st_size; + if((ptr = mmap (0, Mlen, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED){ + perror("Mmap error for input"); + goto ret; + } + mmapbuf *ret = calloc(sizeof(mmapbuf), 1); + if(ret){ + ret->data = ptr; + ret->len = Mlen; + }else munmap(ptr, Mlen); +ret: + if(close(fd)) perror("Can't close mmap'ed file"); + return ret; +} + + +int main(int argc, char **argv){ + struct stat st; + double T0; + if(argc != 2){ + printf("Usage: %s file\n", argv[0]); + return 2; + } + if (stat(argv[1], &st) == 0 && S_ISREG(st.st_mode)){ + off_t off = 0; + int fd = open(argv[1], O_RDONLY); + int fdo = open("tmpoutput", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0 || fdo < 0){ + perror("can't open"); + return 1; + } + T0 = dtime(); + posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL); + while (off < st.st_size) { + ssize_t bytes = sendfile(fdo, fd, &off, st.st_size - off); + if (bytes <= 0){ + perror("can't sendfile"); + } + } + close(fd); + close(fdo); + printf("Copied by sendfile, time: %gs\n", dtime()-T0); + T0 = dtime(); + mmapbuf *map = My_mmap(argv[1]); + if(map){ + fdo = open("tmpoutput", O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0 || fdo < 0){ + perror("can't open"); + return 1; + } + size_t written = 0, towrite = map->len; + char *ptr = map->data; + do{ + ssize_t wr = write(fdo, ptr, towrite); + if(wr <= 0) break; + written += wr; + towrite -= wr; + ptr += wr; + }while(towrite); + if(written != map->len){ + printf("err: writed only %zd byted of %zd\n", written, map->len); + } + close(fdo); + My_munmap(&map); + printf("Copied by mmap, time: %gs\n", dtime()-T0); + } + }else + perror("Can't stat file"); + return 0; +}