사용자 삽입 이미지


Frame buffer의 구조 및 그래픽의 기본적인 각도 계산 및 재귀호출, 베지어곡선의 수학개념을 이해하기 위해서 만들어 본겁니다.
lilo.conf 에 "vga=0x0317" 이라는 옵션을 주고 해보세요.

코드:

/*
  Copyright (C) Information Equipment co.,LTD
  All rights reserved.
  Code by JaeHyuk Cho <mailto:minzkn@infoeq.com>
  CVSTAG="$Header$"
*/

#include <sys/types.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <math.h>
#include <signal.h>

#include <linux/fb.h>

#define DEF_2PI (2.0 * 3.14159265358)

static int                        g_FB_Handle, g_FB_Cx, g_FB_Cy, g_FB_ScreenSize;
static struct fb_fix_screeninfo   g_FB_FIX;
static struct fb_var_screeninfo   g_FB_VAR;
static void                      *g_FB_Map;
static void (*DrawPixel)(int, int, int);

volatile int g_break_clock = 0;

static void clock_signal(int s_signal)
{
 g_break_clock = 1;
 (void)signal(s_signal, clock_signal);
}

static void (clock_load_balance)(void)
{
#if 1
 struct timeval s_timeval = {0l, 1000000l / 100l /* hz */};
 (void)select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, (struct timeval *)(&s_timeval));
#endif
}

static void DrawPixel8(int s_Color, int s_x, int s_y)
{
 *(((unsigned char *)g_FB_Map) + (s_y * g_FB_FIX.line_length) + s_x) = (unsigned char)s_Color;
}

static void DrawPixel16(int s_Color, int s_x, int s_y)
{
 *((unsigned short *)(((unsigned char *)g_FB_Map) + (s_y * g_FB_FIX.line_length) + (s_x << 1))) = (unsigned short)s_Color;
}

static void DrawPixel24(int s_Color, int s_x, int s_y)
{
 unsigned char *s_FB_Ptr = ((unsigned char *)g_FB_Map) + (s_y * g_FB_FIX.line_length) + ((s_x << 1) + s_x);
 *((unsigned short *)s_FB_Ptr) = (unsigned short)s_Color;
 *(s_FB_Ptr + sizeof(unsigned short)) = (unsigned char)(s_Color >> 16);
}

static void DrawPixel32(int s_Color, int s_x, int s_y)
{
 *((unsigned long *)(((unsigned char *)g_FB_Map) + (s_y * g_FB_FIX.line_length) + (s_x << 2))) = (unsigned long)s_Color;
}

static void PinXY(int s_Angle, int *s_x, int *s_y, int s_r)
{ /* s_To(Grid) : X = s_From(Grid) : s_Current */
 double s_Value = ((DEF_2PI * (double)(s_Angle % 360)) / 360.0);
 *(s_x) = (int)(sin(s_Value) * s_r); *(s_y) = (int)(-cos(s_Value) * s_r);
}

static void __DrawLine__(int s_Color, float s_x1, float s_y1, float s_x2, float s_y2, int s_Level)
{ /* Call by call level 16 optimize draw line : JaeHyuk algorithm ^^ */
 float s_cx = (s_x1 + s_x2) / 2.0, s_cy = (s_y1 + s_y2) / 2.0;
 if(((int)s_x1 == (int)s_x2 && (int)s_y1 == (int)s_y2) || s_Level > 16)DrawPixel(s_Color, (int)s_cx, (int)s_cy);
 else
 {
  s_Level++;
  __DrawLine__(s_Color, s_x1, s_y1, s_cx, s_cy, s_Level); __DrawLine__(s_Color, s_cx, s_cy, s_x2, s_y2, s_Level);
 }
}

static void DrawLine(int s_Color, int s_x1, int s_y1, int s_x2, int s_y2)
{
 __DrawLine__(s_Color, (float)s_x1, (float)s_y1, (float)s_x2, (float)s_y2, 0);
}

static void DrawCircle(int s_Color, int s_x, int s_y, int s_r)
{
 double s_Pi, s_Grid = 1.0 / ((double)s_r), s_sinX, s_cosY;
 for(s_Pi = 0.0;s_Pi < (DEF_2PI / 4.0);s_Pi += s_Grid)
 {
  s_sinX = sin(s_Pi) * (double)s_r; s_cosY = -cos(s_Pi) * (double)s_r;
  DrawPixel(s_Color, (int)(s_x + s_sinX), (int)(s_y + s_cosY));
  DrawPixel(s_Color, (int)(s_x - s_sinX), (int)(s_y + s_cosY));
  DrawPixel(s_Color, (int)(s_x + s_sinX), (int)(s_y - s_cosY));
  DrawPixel(s_Color, (int)(s_x - s_sinX), (int)(s_y - s_cosY));
 }
}

static void Pin(int s_Color, int s_Angle, int s_Type)
{
 int s_x1, s_y1, s_x2, s_y2, s_x3, s_y3;
 int s_Size;
 s_Size = g_FB_ScreenSize >> 1;
 if(s_Type == 0)       s_Size -= ((g_FB_ScreenSize >> 1) >> 3);
 else if(s_Type == 10) s_Size -= ((g_FB_ScreenSize >> 1) >> 3);
 else if(s_Type == 20) s_Size -= ((g_FB_ScreenSize >> 1) >> 2);
 PinXY(s_Angle, &s_x1, &s_y1, s_Size >> 2); PinXY(s_Angle, &s_x2, &s_y2, s_Size);
 DrawLine(s_Color, g_FB_Cx - s_x1, g_FB_Cy - s_y1, g_FB_Cx + s_x2, g_FB_Cy + s_y2);
 if(s_Type > 0)
 {
  PinXY(s_Angle +  90, &s_x3, &s_y3, s_Type);
  DrawLine(s_Color, g_FB_Cx - s_x1, g_FB_Cy - s_y1, g_FB_Cx + s_x3, g_FB_Cy + s_y3);
  DrawLine(s_Color, g_FB_Cx + s_x2, g_FB_Cy + s_y2, g_FB_Cx + s_x3, g_FB_Cy + s_y3);
  DrawLine(s_Color, g_FB_Cx - s_x1, g_FB_Cy - s_y1, g_FB_Cx - s_x3, g_FB_Cy - s_y3);
  DrawLine(s_Color, g_FB_Cx + s_x2, g_FB_Cy + s_y2, g_FB_Cx - s_x3, g_FB_Cy - s_y3);
 }
}

int main(int s_argc, char **s_argv)
{
 (void)signal(SIGINT, clock_signal);
 printf("fbclock v1.0.1 - Code by JaeHyuk Cho <minzkn@infoeq.co.kr>\n\n");
 g_FB_Handle = open(s_argc >= 2 ? s_argv[1] : "/dev/fb0", O_RDWR);
 if(g_FB_Handle >= 0)
 {
  if(ioctl(g_FB_Handle, FBIOGET_FSCREENINFO, &g_FB_FIX) == 0)
  {
   if(ioctl(g_FB_Handle, FBIOGET_VSCREENINFO, &g_FB_VAR) == 0)
   {
    g_FB_Map = mmap((void *)0, g_FB_FIX.line_length * g_FB_VAR.yres, PROT_READ | PROT_WRITE, MAP_SHARED, g_FB_Handle, 0);
    if(g_FB_Map != (void *)(-1))
    {
     switch(g_FB_VAR.bits_per_pixel)
     {
      case  8: DrawPixel = DrawPixel8;  break;
      case 16: DrawPixel = DrawPixel16; break;
      case 24: DrawPixel = DrawPixel24; break;
      case 32: DrawPixel = DrawPixel32; break;
      default: DrawPixel = (void *)0;   break;
     }
     g_FB_Cx = g_FB_VAR.xres >> 1; g_FB_Cy = g_FB_VAR.yres >> 1;
     g_FB_ScreenSize = g_FB_VAR.xres < g_FB_VAR.yres ? g_FB_VAR.xres : g_FB_VAR.yres;
     if(DrawPixel)
     {
      int s_PreSecond = 0, s_PreMinute = 0, s_PreHour = 0, s_Count, s_Index, s_x, s_y;
      time_t s_UTC;
      struct tm *s_LocalTime;
      s_Count = 0;
      do
      {
       s_UTC = time((time_t *)0);
       s_LocalTime = localtime(&s_UTC);
       if(s_LocalTime->tm_sec != s_PreSecond)
       {
        if(s_LocalTime->tm_min != s_PreMinute)
        {
         if(s_LocalTime->tm_hour != s_PreHour)
         {
          Pin(0, s_PreHour * 30, 20);
          s_PreHour = s_LocalTime->tm_hour;
         }
         Pin(0, s_PreMinute * 6, 10);
         s_PreMinute = s_LocalTime->tm_min;
        }
        Pin(0, s_PreSecond * 6, 0);
        Pin(0xf00f, s_LocalTime->tm_hour * 30, 20);
        Pin(0x0ff0, s_LocalTime->tm_min  *  6, 10);
        Pin(0xffff, s_LocalTime->tm_sec  *  6, 0);
        DrawCircle(0x0fff, g_FB_Cx, g_FB_Cy, 5);
        s_PreSecond = s_LocalTime->tm_sec;
       }
       do
       {
        int s_tick;
        for(s_tick = 0;s_tick < 10;s_tick++)clock_load_balance();
       }while(0);
       PinXY(s_Count, &s_x, &s_y, (g_FB_ScreenSize >> 1) - (g_FB_ScreenSize >> 5));
       s_Index = (s_Count % 30) ? 5 : 10;
       DrawCircle(0xffff, g_FB_Cx + s_x, g_FB_Cy + s_y, s_Index);
       DrawCircle(0xffff, g_FB_Cx - s_x, g_FB_Cy + s_y, s_Index);
       DrawCircle(0xffff, g_FB_Cx + s_x, g_FB_Cy - s_y, s_Index);
       DrawCircle(0xffff, g_FB_Cx - s_x, g_FB_Cy - s_y, s_Index);
       s_Count+=6;
       if(s_Count > 90)s_Count = 0;
      }while(g_break_clock == 0);
     }
     else fprintf(stderr, "Err: %d\n", __LINE__);
     munmap(g_FB_Map, g_FB_FIX.line_length * g_FB_VAR.yres);
    }
    else fprintf(stderr, "Err: %d\n", __LINE__);
   }
   else fprintf(stderr, "Err: %d\n", __LINE__);
  }
  else fprintf(stderr, "Err: %d\n", __LINE__);
  close(g_FB_Handle);
 }
 else fprintf(stderr, "Err: %d\n", __LINE__);
 (void)fprintf(stdout, "End of clock\n");
 return(0);
}

/* vim: set expandtab: */
/* End of source */




Marius Konitzer 씨가 예전에 만들었던 fbclock을 개선하였다고 패치된 내용을 보내왔습니다. 외국인이 직접 제 소스를 패치해준것은 공식적으로 처음이군요.

잘 알지도 못하는 외국인으로부터 몇번 다른 여러 소스들에 대해서 개선점을 Mail 로 받아본적은 있지만 이렇게 패치로 보내준것은 처음인것 같네요.

Marius Konitzer 씨 에게 감사(Thanks)의 마음을 이자리를 빌어서 전합니다.

다음은 Marius Konitzer 씨가 저에게 보내준 Mail의 원문내용입니다.
인용:
Hello!

I recently needed a analog clock for fb output. It seemed that there was none - except from your fbclock. I liked it's charming simplicity and decided to improve it somewhat. So here is what I did:

* hour and minute hands are drawn on "in-between" positions, too
* added some commandline options for colour switching
* using default colours depending on the fb's bitdepth

I thought this could be of interest for you, if you like to implement it in the upstream version of your fbclock!? (perhaps even mentioning me in the source... ;-))


Nice greetings from Germany,
Marius Konitzer



아래의 패치가 patch명령으로 일부 적용되지 않을수 있습니다. 그래서 직접 손으로 해주어야 할지도 모릅니다. 원인은 제가 개념없이 버젼관리를 해서입니다. 버젼이 한가지라라면 문제가 없겠지만 비슷한 버젼이 꽤 많거든요...

코드:
--- fbclock.orig.c   2005-11-25 00:44:09.000000000 +0100
+++ fbclock.c   2005-11-26 14:21:43.000000000 +0100
@@ -8,6 +8,8 @@
 */
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -25,6 +27,10 @@
 static struct fb_var_screeninfo   g_FB_VAR;
 static void                      *g_FB_Map;
 static void (*DrawPixel)(int, int, int);
+static char                      *g_Progname;
+static int                        g_Col8[4]  = {0x04, 0x01, 0x0e, 0x07}; /* red, blue, green, grey */
+static int                        g_Col16[4] = {0xf000, 0x00f0, 0xff00, 0x8410}; /* rgb565 */
+static int                        g_Col24[4] = {0xdd0000, 0x0000ff, 0xffff00, 0x808080}; /* rgb888 */
 
 static void DrawPixel8(int s_Color, int s_x, int s_y)
 {
@@ -103,11 +109,50 @@
  }
 }
 
+void Usage() {
+   printf("Usage: %s [-h] [-d fbdev] [-hc col] [-mc col] [-sc col] [-bc col]\n", g_Progname);
+   printf("  -h           show this help page\n");
+   printf("  -d fbdev     use fbdev as framebuffer device\n");
+   printf("  -hc col      specifies colour for hour hand\n");
+   printf("  -mc col      specifies colour for minute hand\n");
+   printf("  -sc col      specifies colour for second hand\n");
+   printf("  -bc col      specifies border colour\n");
+   printf("col is a hexadecimal colour code, that depends on your framebuffer's\n");
+   printf("colour depth, e.g. \"-hc 0xf0f0\" for 16 bit\n");
+   exit(1);
+}
+
 int main(int s_Argc, char *s_Argv[])
 {
+ int i, s_Colour[4], s_isColSet[4]={0,0,0,0};
  char *s_Device = "/dev/fb0";   
- if(s_Argc > 1)s_Device = s_Argv[1];
+ g_Progname = s_Argv[0];
  printf("fbclock v1.0.1 - Code by JaeHyuk Cho <minzkn@infoeq.co.kr>\n\n");
+ while(--s_Argc) {
+  s_Argv++;
+  if (s_Argc<=1) Usage();
+  if (!strcmp(s_Argv[0], "-d"))
+     s_Device = s_Argv[1];
+  else if (!strcmp(s_Argv[0], "-hc")) {
+     if (sscanf(s_Argv[1], "0x%x", &s_Colour[0])!=1)
+        Usage();
+     s_isColSet[0]=1;
+  } else if (!strcmp(s_Argv[0], "-mc")) {
+     if (sscanf(s_Argv[1], "0x%x", &s_Colour[1])!=1)
+        Usage();
+     s_isColSet[1]=1;
+  } else if (!strcmp(s_Argv[0], "-sc")) {
+     if (sscanf(s_Argv[1], "0x%x", &s_Colour[2])!=1)
+        Usage();
+     s_isColSet[2]=1;
+  } else if (!strcmp(s_Argv[0], "-bc")) {
+     if (sscanf(s_Argv[1], "0x%x", &s_Colour[3])!=1)
+        Usage();
+     s_isColSet[3]=1;
+  } else
+     Usage();
+  s_Argc--; s_Argv++;
+ }
  g_FB_Handle = open(s_Device, O_RDWR);
  if(g_FB_Handle >= 0)
  {
@@ -130,40 +175,49 @@
      g_FB_ScreenSize = g_FB_VAR.xres < g_FB_VAR.yres ? g_FB_VAR.xres : g_FB_VAR.yres;
      if(DrawPixel)
      {
-      int s_PreSecond = 0, s_PreMinute = 0, s_PreHour = 0, s_Count, s_Index, s_x, s_y;
+      int s_Count, s_Index, s_x, s_y;
+      int s_PreAngleSecond = 0, s_PreAngleMinute = 0, s_PreAngleHour = 0;
+      int s_AngleSecond = 0, s_AngleMinute = 0, s_AngleHour = 0;
       time_t s_UTC;
       struct tm *s_LocalTime;
       s_Count = 0;
+      for (i=0; i<4; i++) {
+        if (!s_isColSet[i])
+           s_Colour[i]=(DrawPixel==DrawPixel8?g_Col8[i]:(DrawPixel==DrawPixel16?g_Col16[i]:g_Col24[i]));
+      }
       do
       {
        s_UTC = time((time_t *)0);
        s_LocalTime = localtime(&s_UTC);
-       if(s_LocalTime->tm_sec != s_PreSecond)
+       s_AngleSecond = s_LocalTime->tm_sec * 6;
+       s_AngleMinute = s_LocalTime->tm_min * 6 + ((float)s_LocalTime->tm_sec / 10);
+       s_AngleHour = s_LocalTime->tm_hour * 30 + ((float)s_LocalTime->tm_min / 2);
+       if(s_AngleSecond != s_PreAngleSecond)
        {
-   if(s_LocalTime->tm_min != s_PreMinute)
+   if(s_AngleMinute != s_PreAngleMinute)
    {
-         if(s_LocalTime->tm_hour != s_PreHour)
+         if(s_AngleHour != s_PreAngleHour)
     {
-     Pin(0, s_PreHour * 30, 20);          
-     s_PreHour = s_LocalTime->tm_hour;
+     Pin(0, s_PreAngleHour, 20);
+     s_PreAngleHour = s_AngleHour;
     }
-    Pin(0, s_PreMinute * 6, 10);          
-    s_PreMinute = s_LocalTime->tm_min;
+    Pin(0, s_PreAngleMinute, 10);
+    s_PreAngleMinute = s_AngleMinute;
    }
-        Pin(0, s_PreSecond * 6, 0);          
-        Pin(0xf00f, s_LocalTime->tm_hour * 30, 20);          
-        Pin(0x0ff0, s_LocalTime->tm_min  *  6, 10);          
-        Pin(0xffff, s_LocalTime->tm_sec  *  6, 0);        
-        DrawCircle(0x0fff, g_FB_Cx, g_FB_Cy, 5);   
-        s_PreSecond = s_LocalTime->tm_sec;
+        Pin(0, s_PreAngleSecond, 0);
+        s_PreAngleSecond = s_AngleSecond;
+        Pin(s_Colour[0], s_AngleHour, 20);
+        Pin(s_Colour[1], s_AngleMinute, 10);
+        Pin(s_Colour[2], s_AngleSecond, 0);
+        DrawCircle(s_Colour[3], g_FB_Cx, g_FB_Cy, 5);   
        }
        usleep(DEF_HEAT_CPU);
        PinXY(s_Count, &s_x, &s_y, (g_FB_ScreenSize >> 1) - (g_FB_ScreenSize >> 5));
        s_Index = (s_Count % 30) ? 5 : 10;
-       DrawCircle(0xffff, g_FB_Cx + s_x, g_FB_Cy + s_y, s_Index);   
-       DrawCircle(0xffff, g_FB_Cx - s_x, g_FB_Cy + s_y, s_Index);   
-       DrawCircle(0xffff, g_FB_Cx + s_x, g_FB_Cy - s_y, s_Index);   
-       DrawCircle(0xffff, g_FB_Cx - s_x, g_FB_Cy - s_y, s_Index);
+       DrawCircle(s_Colour[3], g_FB_Cx + s_x, g_FB_Cy + s_y, s_Index);   
+       DrawCircle(s_Colour[3], g_FB_Cx - s_x, g_FB_Cy + s_y, s_Index);   
+       DrawCircle(s_Colour[3], g_FB_Cx + s_x, g_FB_Cy - s_y, s_Index);   
+       DrawCircle(s_Colour[3], g_FB_Cx - s_x, g_FB_Cy - s_y, s_Index);
        s_Count+=6;
        if(s_Count > 90)s_Count = 0;
       }while(1);

크리에이티브 커먼즈 라이센스
Creative Commons License
Posted by minzkn

트랙백 주소 :: http://blog.minzkn.com/trackback/128

댓글을 달아 주세요