qtcreator에서 ros 프로젝트를 생성하고 방식을 catkin_make로 지정해두어도

 

catkin_make로 되지 않을 경우가 있다.(projects->ros manager>build system을 보면 catkintools로 되어 있었음)

 

이럴 때,

 

projects(설정) -> ros manager > build system 에서 catkintools -> catkinmake로 변경

 

그리고 하단에 add catkin step에서 catkinmake를 생성하고 우선순위를 catkintools보다 위로 변경

 

그리고 기존의 catkin_ws의 build 디렉토리를 삭제해야함

 

또는 build system을 catkintools로 사용할 경우

 

sudo apt install python-catkin-tools해서 catkintools를 사용하면 됨

Framework에 대한 정의를 내려 보려고 하니..참 막막하기는 하다...

Framework, Architecture 등 너무도 익숙하게 사용하는 용어라 정의하기가 더욱 어려운 것 같다.


google에서 Framework에 대한 정의를 찾아보면 20 여개 정도가 검색이 되는데 그중 아래의 정의가 일반적으로 우리가 생각하는 Framework이 아닐까 생각한다.


In software development, a Framework is a defined support structure in which another software project can be organized and developed. Typically, a framework may include support programs, code libraries and a scripting language amongst other software to help develop and glue together the different components of your project.


소프트웨어 프로젝트에서 활용할 수 있는 기반 구조로 일반적으로 지원 프로그램, 코드 라이브러리 등 프로젝트의 다양한 컴포넌트들을 개발하고 유기적으로 결합하기 위해 사용하는 소프트웨어를 말한다.

과거에 공통 코드라는 명칭으로 사용하던 것들을 좀더 구조화 시켜 Framework이라 부른다고 생각하면 될 것 같다.


이 Framework도 Component Framework, Application Framework, Web Framework 등 분류 기준에 따라 다양하게 분류가 된다.

여기서는 두가지로만 분류하겠다.

1. Component Framework (또는 Vendor Framework) : .NET Framework, J2EE Framework 과 같은 기능 중심의 Framework

2. Application Framework : Component Framework 기반으로 Application 내의 요소(Component)들간의 유기적인 연관 관계를 고려한 Framework (대표적인 것이 Apache Struts Framework, 다양한 SI회사에서 사용하는 Framework [필자의 회사에도 SummaFramework이라는 이름으로 가지고 있다] 등)


이러한 Framework을 활용하는 이유는 당연히 프로젝트의 생산성 향상 및 프로젝트의 표준화 지원을 통해 Quality 향상 등이 이유가 될 것이다. (사실 Framework이라는 표현을 쓰지 않을때에도 공통 코드 형태로 프로젝트 마다 사용해 왔던 것이다..)


이러한 Framework과 Architecture, Component, Library을 비교해 보면

Architecture는 시스템을 구성하고 있는 구성요소들 및 관계의 구조를 표현한 것으로 Framework 보다 좀더 추상적인 개념으로 보면 되겠다.

Component는 특정 기능을 수행하기 위해 잘 정의된 인터페이스를 통해 독립적으로 개발된 소프트웨어 단위로 Framework 기반에서 동작하는 모듈로 생각하면 되겠다.

Library는 재사용 가능한 함수와 루틴들을 모아 놓은 것으로 이러한 Library를 구조화 시켜 Framework을 만든다고 보면 되겠다.

재사용의 범위는 일반적으로

Library < Component < Framework < Architecture

라고 볼 수 있겠다.

Well, here it is the decoder source.
It takes as an input a JPG file and decodes it into a truecolor BMP.

Opposite to the encoder, it's not so optimized or clear as I wanted.
But since I received a lot of emails asking for it, here it is.

It is written long ago and since then I was quite busy learning other stuff
and I haven't modified it as it should [Huffman decoder probably can be made
better and IDCT (the most consuming CPU part) -- should be done faster],
so don't expect a super fast decoder [though it's speed seems reasonable].
Few comments are in romanian.
Some ideas have been taken from Independent JPEG Group's JPEG software.
(IDCT routine is taken with minor modifications)

It compiles under WATCOM C (still my favourite compiler) 10.0 for DOS, and
VISUAL C 5.0 (if you turn on optimizations in VC 5.0, make sure that the option
"assume aliasing across function calls" it's turned on for the "jpegdec.c" module).
I haven't tested it under other compilers.

I don't know when I'll have the time to make it better, but in the meantime,
I'd like to hear from you if you make it more clear and/or faster.

You are free to modify it as you want, but it would be nice to say somewhere
that you used ideas from these routines.

Disclaimer
----------

NO WARRANTY PROVIDED WITH THIS PROGRAM.
So, use it at your own risk.
It's status: freeware.

Author email:
            cristic22@yahoo.com

////////////////////////////////////////////////


BEGINNING OF HEADERS


/////////////////////////////////////////////////




#ifndef __JPEGDEC_H__
#define __JPEGDEC_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


#define BYTE unsigned char
#define WORD unsigned short int

#define DWORD unsigned int
#define SDWORD signed int

#define SBYTE signed char
#define SWORD signed short int

int load_JPEG_header(FILE *fp, DWORD *X_image, DWORD *Y_image);
void decode_JPEG_image();
int get_JPEG_buffer(WORD X_image,WORD Y_image, BYTE **address_dest_buffer);

#endif



/////////////////////////////////////////////////
BEGINNING OF PROGRAM SOURCE
//////////////////////////////////////////////////




#include "jpegdec.h"
#include <conio.h>
#include <time.h>
char *FileName="image.jpg";
extern char error_string[90];

typedef struct s_BM_header {
     WORD BMP_id ; // 'B''M'
     DWORD size; // size in bytes of the BMP file
     DWORD zero_res; // 0
     DWORD offbits; // 54
     DWORD biSize; // 0x28
     DWORD Width;  // X
     DWORD Height;  // Y
     WORD  biPlanes; // 1
     WORD  biBitCount ; // 24
     DWORD biCompression; // 0 = BI_RGB
     DWORD biSizeImage; // 0
     DWORD biXPelsPerMeter; // 0xB40
     DWORD biYPelsPerMeter; // 0xB40
     DWORD biClrUsed; //0
     DWORD biClrImportant; //0
} BM_header;
typedef struct s_RGB {
    BYTE B;
       BYTE G;
       BYTE R;
} RGB;

void exitmessage(char *message)
{
 printf("%s\n",message);exit(0);
}

void write_buf_to_BMP(BYTE *im_buffer, WORD X_bitmap, WORD Y_bitmap, char *BMPname)
{
 SWORD x,y;
 RGB *pixel;
 BM_header BH;
 FILE *fp_bitmap;
 DWORD im_loc_bytes;
 BYTE nr_fillingbytes, i;
 BYTE zero_byte=0;

 fp_bitmap=fopen(BMPname,"wb");
 if (fp_bitmap==NULL) exitmessage("File cannot be created");

 if (X_bitmap%4!=0) nr_fillingbytes=4-((X_bitmap*3L)%4);
  else nr_fillingbytes=0;

 BH.BMP_id = 'M'*256+'B';     fwrite(&BH.BMP_id,2,1,fp_bitmap);
 BH.size=54+Y_bitmap*(X_bitmap*3+nr_fillingbytes);fwrite(&BH.size,4,1,fp_bitmap);
 BH.zero_res = 0;             fwrite(&BH.zero_res,4,1,fp_bitmap);
 BH.offbits = 54;             fwrite(&BH.offbits,4,1,fp_bitmap);
 BH.biSize = 0x28;            fwrite(&BH.biSize,4,1,fp_bitmap);
 BH.Width = X_bitmap;       fwrite(&BH.Width,4,1,fp_bitmap);
 BH.Height = Y_bitmap;       fwrite(&BH.Height,4,1,fp_bitmap);
 BH.biPlanes = 1;             fwrite(&BH.biPlanes,2,1,fp_bitmap);
 BH.biBitCount = 24;          fwrite(&BH.biBitCount,2,1,fp_bitmap);
 BH.biCompression = 0;        fwrite(&BH.biCompression,4,1,fp_bitmap);
 BH.biSizeImage = 0;          fwrite(&BH.biSizeImage,4,1,fp_bitmap);
 BH.biXPelsPerMeter = 0xB40;  fwrite(&BH.biXPelsPerMeter,4,1,fp_bitmap);
 BH.biYPelsPerMeter = 0xB40;  fwrite(&BH.biYPelsPerMeter,4,1,fp_bitmap);
 BH.biClrUsed = 0;           fwrite(&BH.biClrUsed,4,1,fp_bitmap);
 BH.biClrImportant = 0;       fwrite(&BH.biClrImportant,4,1,fp_bitmap);

 printf("Writing bitmap ...\n");
 im_loc_bytes=(DWORD)im_buffer+((DWORD)Y_bitmap-1)*X_bitmap*4;

 for (y=0;y<Y_bitmap;y++)
  {
   for (x=0;x<X_bitmap;x++)
 {
  pixel=(RGB *)im_loc_bytes;
  fwrite(pixel, 3, 1, fp_bitmap);
  im_loc_bytes+=4;
 }
   for (i=0;i<nr_fillingbytes;i++)
    fwrite(&zero_byte,1,1,fp_bitmap);
   im_loc_bytes-=2L*X_bitmap*4;
  }
 printf("Done.\n");
 fclose(fp_bitmap);
}

void main(int argc, char *argv[])
{
 FILE *fp;
 DWORD X_image, Y_image;
 BYTE *our_image_buffer;
 clock_t start_time, finish_time;
 float duration;

 if (argc<=1) fp=fopen(FileName,"rb");
  else fp=fopen(argv[1],"rb");
 if (fp==NULL) exitmessage("File not found ?");
 if (!load_JPEG_header(fp,&X_image,&Y_image)) {exitmessage(error_string);return;}
 fclose(fp);

 printf(" X_image = %d\n",X_image);
 printf(" Y_image = %d\n",Y_image);

/*
 printf("Sampling factors: \n");
 printf("Y  : H=%d,V=%d\n", YH,YV);
 printf("Cb : H=%d,V=%d\n", CbH,CbV);
 printf("Cr : H=%d,V=%d\n", CrH,CrV);
 printf("Restart markers  = %d\n", Restart_markers);
 printf("MCU restart = %d\n", MCU_restart);
 getch();
*/

 printf("Decoding JPEG image...\n");
 // main decoder
 start_time = clock();
 decode_JPEG_image();
 printf("Decoding finished.\n");
 
 finish_time = clock();
 duration = (double)(finish_time - start_time) / CLK_TCK;
 printf( "Time elapsed: %2.1f seconds\n", duration );

 if (!get_JPEG_buffer(X_image,Y_image,&our_image_buffer)) {exitmessage(error_string);return;}

 write_buf_to_BMP(our_image_buffer,X_image,Y_image, "image.bmp");
 getch();
}


////////////////////////////////////////////////
DECODER SOURCE CODE
////////////////////////////////////////////////








// JPEG decoder module
// Copyright 1999 Cristi Cuturicu

#include "jpegdec.h"
// Used markers:
#define SOI 0xD8
#define EOI 0xD9
#define APP0 0xE0
#define SOF 0xC0
#define DQT 0xDB
#define DHT 0xC4
#define SOS 0xDA
#define DRI 0xDD
#define COM 0xFE

char error_string[90];
#define exit_func(err) { strcpy(error_string, err); return 0;}

static BYTE *buf; // the buffer we use for storing the entire JPG file

static BYTE bp; //current byte
static WORD wp; //current word

static DWORD byte_pos; // current byte position
#define BYTE_p(i) bp=buf[(i)++]
#define WORD_p(i) wp=(((WORD)(buf[(i)]))<<8) + buf[(i)+1]; (i)+=2

// WORD X_image_size,Y_image_size; // X,Y sizes of the image
static WORD X_round,Y_round; // The dimensions rounded to multiple of Hmax*8 (X_round)
     // and Ymax*8 (Y_round)

static BYTE *im_buffer; // RGBA image buffer
static DWORD X_image_bytes; // size in bytes of 1 line of the image = X_round * 4
static DWORD y_inc_value ; // 32*X_round; // used by decode_MCU_1x2,2x1,2x2

BYTE YH,YV,CbH,CbV,CrH,CrV; // sampling factors (horizontal and vertical) for Y,Cb,Cr
static WORD Hmax,Vmax;


static BYTE zigzag[64]={ 0, 1, 5, 6,14,15,27,28,
      2, 4, 7,13,16,26,29,42,
      3, 8,12,17,25,30,41,43,
      9,11,18,24,31,40,44,53,
     10,19,23,32,39,45,52,54,
     20,22,33,38,46,51,55,60,
     21,34,37,47,50,56,59,61,
     35,36,48,49,57,58,62,63 };
typedef struct {
   BYTE Length[17];  // k =1-16 ; L[k] indicates the number of Huffman codes of length k
   WORD minor_code[17];  // indicates the value of the smallest Huffman code of length k
   WORD major_code[17];  // similar, but the highest code
   BYTE V[65536];  // V[k][j] = Value associated to the j-th Huffman code of length k
 // High nibble = nr of previous 0 coefficients
 // Low nibble = size (in bits) of the coefficient which will be taken from the data stream
} Huffman_table;

static float *QT[4]; // quantization tables, no more than 4 quantization tables (QT[0..3])
static Huffman_table HTDC[4]; //DC huffman tables , no more than 4 (0..3)
static Huffman_table HTAC[4]; //AC huffman tables                  (0..3)

static BYTE YQ_nr,CbQ_nr,CrQ_nr; // quantization table number for Y, Cb, Cr
static BYTE YDC_nr,CbDC_nr,CrDC_nr; // DC Huffman table number for Y,Cb, Cr
static BYTE YAC_nr,CbAC_nr,CrAC_nr; // AC Huffman table number for Y,Cb, Cr

static BYTE Restart_markers; // if 1 => Restart markers on , 0 => no restart markers
static WORD MCU_restart; //Restart markers appears every MCU_restart MCU blocks
typedef void (*decode_MCU_func)(DWORD);


static SWORD DCY, DCCb, DCCr; // Coeficientii DC pentru Y,Cb,Cr
static SWORD DCT_coeff[64]; // Current DCT_coefficients
static BYTE Y[64],Cb[64],Cr[64]; // Y, Cb, Cr of the current 8x8 block for the 1x1 case
static BYTE Y_1[64],Y_2[64],Y_3[64],Y_4[64];
static BYTE tab_1[64],tab_2[64],tab_3[64],tab_4[64]; // tabelele de supraesantionare pt cele 4 blocuri

static SWORD Cr_tab[256],Cb_tab[256]; // Precalculated Cr, Cb tables
static SWORD Cr_Cb_green_tab[65536];

// Initial conditions:
// byte_pos = start position in the Huffman coded segment
// WORD_get(w1); WORD_get(w2);wordval=w1;

static BYTE d_k=0;  // Bit displacement in memory, relative to the offset of w1
    // it's always <16
static WORD w1,w2; // w1 = First word in memory; w2 = Second word
static DWORD wordval ; // the actual used value in Huffman decoding.
static DWORD mask[17];
static SWORD neg_pow2[17]={0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
static DWORD start_neg_pow2=(DWORD)neg_pow2;

static int shift_temp;
#define RIGHT_SHIFT(x,shft)  \
 ((shift_temp = (x)) < 0 ? \
  (shift_temp >> (shft)) | ((~(0L)) << (32-(shft))) : \
  (shift_temp >> (shft)))
#define DESCALE(x,n)  RIGHT_SHIFT((x) + (1L << ((n)-1)), n)
#define RANGE_MASK 1023L
static BYTE *rlimit_table;
void prepare_range_limit_table()
/* Allocate and fill in the sample_range_limit table */
{
  int j;
  rlimit_table = (BYTE *)malloc(5 * 256L + 128) ;
  /* First segment of "simple" table: limit[x] = 0 for x < 0 */
  memset((void *)rlimit_table,0,256);
  rlimit_table += 256; /* allow negative subscripts of simple table */
  /* Main part of "simple" table: limit[x] = x */
  for (j = 0; j < 256; j++) rlimit_table[j] = j;
  /* End of simple table, rest of first half of post-IDCT table */
  for (j = 256; j < 640; j++) rlimit_table[j] = 255;
  /* Second half of post-IDCT table */
  memset((void *)(rlimit_table + 640),0,384);
  for (j = 0; j < 128 ; j++) rlimit_table[j+1024] = j;
}

#ifdef _MSC_VER
WORD lookKbits(BYTE k)
{
 _asm {
  mov dl, k
  mov cl, 16
  sub cl, dl
  mov eax, [wordval]
  shr eax, cl
 }
}

WORD WORD_hi_lo(BYTE byte_high,BYTE byte_low)
{
 _asm {
    mov ah,byte_high
    mov al,byte_low
   }
}
SWORD get_svalue(BYTE k)
// k>0 always
// Takes k bits out of the BIT stream (wordval), and makes them a signed value
{
 _asm {
     xor ecx, ecx
     mov cl,k
     mov eax,[wordval]
     shl eax,cl
     shr eax, 16
     dec cl
     bt eax,ecx
     jc end_macro
 signed_value:inc cl
     mov ebx,[start_neg_pow2]
     add ax,word ptr [ebx+ecx*2]
   end_macro:
 }
}
#endif

#ifdef __WATCOMC__

WORD lookKbits(BYTE k);
#pragma aux lookKbits=\
       "mov eax,[wordval]"\
       "mov cl, 16"\
       "sub cl, dl"\
       "shr eax, cl"\
        parm [dl] \
        value [ax] \
        modify [eax cl];
WORD WORD_hi_lo(BYTE byte_high,BYTE BYTE_low);
#pragma aux WORD_hi_lo=\
      parm [ah] [al]\
      value [ax] \
      modify [ax];

SWORD get_svalue(BYTE k);
// k>0 always
// Takes k bits out of the BIT stream (wordval), and makes them a signed value
#pragma aux get_svalue=\
   "xor ecx, ecx"\
   "mov cl, al"\
   "mov eax,[wordval]"\
   "shl eax, cl"\
   "shr eax, 16"\
   "dec cl"\
   "bt eax,ecx"\
   "jc end_macro"\
   "signed_value:inc cl"\
   "mov ebx,[start_neg_pow2]"\
   "add ax,word ptr [ebx+ecx*2]"\
   "end_macro:"\
   parm [al]\
   modify [eax ebx ecx]\
   value [ax];
#endif

void skipKbits(BYTE k)
{
 BYTE b_high,b_low;
 d_k+=k;
 if (d_k>=16) { d_k-=16;
  w1=w2;
  // Get the next word in w2
  BYTE_p(byte_pos);
  if (bp!=0xFF) b_high=bp;
  else {
     if (buf[byte_pos]==0) byte_pos++; //skip 00
     else byte_pos--; // stop byte_pos pe restart marker
     b_high=0xFF;
  }
  BYTE_p(byte_pos);
  if (bp!=0xFF) b_low=bp;
  else {
     if (buf[byte_pos]==0) byte_pos++; //skip 00
     else byte_pos--; // stop byte_pos pe restart marker
     b_low=0xFF;
  }
  w2=WORD_hi_lo(b_high,b_low);
 }

 wordval = ((DWORD)(w1)<<16) + w2;
 wordval <<= d_k;
 wordval >>= 16;
}

SWORD getKbits(BYTE k)
{
 SWORD signed_wordvalue;
 signed_wordvalue=get_svalue(k);
 skipKbits(k);
 return signed_wordvalue;
}

void calculate_mask()
{
  BYTE k;
  DWORD tmpdv;
  for (k=0;k<=16;k++) { tmpdv=0x10000;mask[k]=(tmpdv>>k)-1;} //precalculated bit mask
}

void init_QT()
{
 BYTE i;
 for (i=0;i<=3;i++) QT[i]=(float *)malloc(sizeof(float)*64);
}

void load_quant_table(float *quant_table)
{
 float scalefactor[8]={1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
        1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
 BYTE j,row,col;
// Load quantization coefficients from JPG file, scale them for DCT and reorder
// from zig-zag order
 for (j=0;j<=63;j++) quant_table[j]=buf[byte_pos+zigzag[j]];
 j=0;
 for (row=0;row<=7;row++)
   for (col=0;col<=7;col++) {
  quant_table[j]*=scalefactor[row]*scalefactor[col];
  j++;
   }
 byte_pos+=64;
}

void load_Huffman_table(Huffman_table *HT)
{
  BYTE k,j;
  DWORD code;

  for (j=1;j<=16;j++) {
 BYTE_p(byte_pos);
 HT->Length[j]=bp;
  }
  for (k=1;k<=16;k++)
 for (j=0;j<HT->Length[k];j++) {
  BYTE_p(byte_pos);
  HT->V[WORD_hi_lo(k,j)]=bp;
 }

  code=0;
  for (k=1;k<=16;k++) {
  HT->minor_code[k] = (WORD)code;
  for (j=1;j<=HT->Length[k];j++) code++;
  HT->major_code[k]=(WORD)(code-1);
  code*=2;
  if (HT->Length[k]==0) {
  HT->minor_code[k]=0xFFFF;
  HT->major_code[k]=0;
  }
  }
}

void process_Huffman_data_unit(BYTE DC_nr, BYTE AC_nr,SWORD *previous_DC)
{
// Process one data unit. A data unit = 64 DCT coefficients
// Data is decompressed by Huffman decoding, then the array is dezigzag-ed
// The result is a 64 DCT coefficients array: DCT_coeff
   BYTE nr,k,j,EOB_found;
   register WORD tmp_Hcode;
   BYTE size_val,count_0;
   WORD *min_code,*maj_code; // min_code[k]=minimum code of length k, maj_code[k]=similar but maximum
   WORD *max_val, *min_val;
   BYTE *huff_values;
   SWORD DCT_tcoeff[64];
   BYTE byte_temp;

// Start Huffman decoding
// First the DC coefficient decoding
   min_code=HTDC[DC_nr].minor_code;
   maj_code=HTDC[DC_nr].major_code;
   huff_values=HTDC[DC_nr].V;

   for (nr = 0; nr < 64 ; nr++) DCT_tcoeff[nr] = 0; //Initialize DCT_tcoeff

   nr=0;// DC coefficient

   min_val = &min_code[1]; max_val = &maj_code[1];
   for (k=1;k<=16;k++) {
  tmp_Hcode=lookKbits(k);
//    max_val = &maj_code[k]; min_val = &min_code[k];
  if ( (tmp_Hcode<=*max_val)&&(tmp_Hcode>=*min_val) ) { //Found a valid Huffman code
  skipKbits(k);
  size_val=huff_values[WORD_hi_lo(k,(BYTE)(tmp_Hcode-*min_val))];
  if (size_val==0) DCT_tcoeff[0]=*previous_DC;
  else {
   DCT_tcoeff[0]=*previous_DC+getKbits(size_val);
   *previous_DC=DCT_tcoeff[0];
  }
  break;
  }
  min_val++; max_val++;
   }

// Second, AC coefficient decoding
   min_code=HTAC[AC_nr].minor_code;
   maj_code=HTAC[AC_nr].major_code;
   huff_values=HTAC[AC_nr].V;

   nr=1; // AC coefficient
   EOB_found=0;
   while ( (nr<=63)&&(!EOB_found) )
 {
  max_val = &maj_code[1]; min_val =&min_code[1];
  for (k=1;k<=16;k++)
  {
    tmp_Hcode=lookKbits(k);
//    max_val = &maj_code[k]; &min_val = min_code[k];
    if ( (tmp_Hcode<=*max_val)&&(tmp_Hcode>=*min_val) )
    {
  skipKbits(k);
  byte_temp=huff_values[WORD_hi_lo(k,(BYTE)(tmp_Hcode-*min_val))];
  size_val=byte_temp&0xF;
  count_0=byte_temp>>4;
  if (size_val==0) {if (count_0==0) EOB_found=1;
        else if (count_0==0xF) nr+=16; //skip 16 zeroes
      }
  else
  {
   nr+=count_0; //skip count_0 zeroes
   DCT_tcoeff[nr++]=getKbits(size_val);
  }
  break;
    }
    min_val++; max_val++;
  }
  if (k>16) nr++;  // This should not occur
 }
  for (j=0;j<=63;j++) DCT_coeff[j]=DCT_tcoeff[zigzag[j]]; // Et, voila ... DCT_coeff
}

void IDCT_transform(SWORD *incoeff,BYTE *outcoeff,BYTE Q_nr)
// Fast float IDCT transform
{
 BYTE x;
 SBYTE y;
 SWORD *inptr;
 BYTE *outptr;
 float workspace[64];
 float *wsptr;//Workspace pointer
 float *quantptr; // Quantization table pointer
 float dcval;
 float tmp0,tmp1,tmp2,tmp3,tmp4,tmp5,tmp6,tmp7;
 float tmp10,tmp11,tmp12,tmp13;
 float z5,z10,z11,z12,z13;
 BYTE *range_limit=rlimit_table+128;
 // Pass 1: process COLUMNS from input and store into work array.
 wsptr=workspace;
 inptr=incoeff;
 quantptr=QT[Q_nr];
 for (y=0;y<=7;y++)
  {
   if( (inptr[8]|inptr[16]|inptr[24]|inptr[32]|inptr[40]|inptr[48]|inptr[56])==0)
 {
  // AC terms all zero (in a column)
  dcval=inptr[0]*quantptr[0];
  wsptr[0]  = dcval;
  wsptr[8]  = dcval;
  wsptr[16] = dcval;
  wsptr[24] = dcval;
  wsptr[32] = dcval;
  wsptr[40] = dcval;
  wsptr[48] = dcval;
  wsptr[56] = dcval;
  inptr++;quantptr++;wsptr++;//advance pointers to next column
  continue ;
 }
  //Even part
 tmp0 = inptr[0] *quantptr[0];
 tmp1 = inptr[16]*quantptr[16];
 tmp2 = inptr[32]*quantptr[32];
 tmp3 = inptr[48]*quantptr[48];

 tmp10 = tmp0 + tmp2;// phase 3
 tmp11 = tmp0 - tmp2;

 tmp13 = tmp1 + tmp3;// phases 5-3
 tmp12 = (tmp1 - tmp3) * 1.414213562f - tmp13; // 2*c4

 tmp0 = tmp10 + tmp13;// phase 2
 tmp3 = tmp10 - tmp13;
 tmp1 = tmp11 + tmp12;
 tmp2 = tmp11 - tmp12;

 // Odd part
 tmp4 = inptr[8] *quantptr[8];
 tmp5 = inptr[24]*quantptr[24];
 tmp6 = inptr[40]*quantptr[40];
 tmp7 = inptr[56]*quantptr[56];

 z13 = tmp6 + tmp5;// phase 6
 z10 = tmp6 - tmp5;
 z11 = tmp4 + tmp7;
 z12 = tmp4 - tmp7;

 tmp7 = z11 + z13;// phase 5
 tmp11= (z11 - z13) * 1.414213562f; // 2*c4

 z5 = (z10 + z12) * 1.847759065f; // 2*c2
 tmp10 = 1.082392200f * z12 - z5; // 2*(c2-c6)
 tmp12 = -2.613125930f * z10 + z5;// -2*(c2+c6)

 tmp6 = tmp12 - tmp7;// phase 2
 tmp5 = tmp11 - tmp6;
 tmp4 = tmp10 + tmp5;

 wsptr[0]  = tmp0 + tmp7;
 wsptr[56] = tmp0 - tmp7;
 wsptr[8]  = tmp1 + tmp6;
 wsptr[48] = tmp1 - tmp6;
 wsptr[16] = tmp2 + tmp5;
 wsptr[40] = tmp2 - tmp5;
 wsptr[32] = tmp3 + tmp4;
 wsptr[24] = tmp3 - tmp4;
 inptr++;
 quantptr++;
 wsptr++;//advance pointers to the next column
  }

//  Pass 2: process ROWS from work array, store into output array.
// Note that we must descale the results by a factor of 8 = 2^3
 outptr=outcoeff;
 wsptr=workspace;
 for (x=0;x<=7;x++)
  {
   // Even part
 tmp10 = wsptr[0] + wsptr[4];
 tmp11 = wsptr[0] - wsptr[4];

 tmp13 = wsptr[2] + wsptr[6];
 tmp12 =(wsptr[2] - wsptr[6]) * 1.414213562f - tmp13;

 tmp0 = tmp10 + tmp13;
 tmp3 = tmp10 - tmp13;
 tmp1 = tmp11 + tmp12;
 tmp2 = tmp11 - tmp12;

   // Odd part
 z13 = wsptr[5] + wsptr[3];
 z10 = wsptr[5] - wsptr[3];
 z11 = wsptr[1] + wsptr[7];
 z12 = wsptr[1] - wsptr[7];

 tmp7 = z11 + z13;
 tmp11= (z11 - z13) * 1.414213562f;

 z5 = (z10 + z12) * 1.847759065f; // 2*c2
 tmp10 = 1.082392200f * z12 - z5;  // 2*(c2-c6)
 tmp12 = -2.613125930f * z10 + z5; // -2*(c2+c6)

 tmp6 = tmp12 - tmp7;
 tmp5 = tmp11 - tmp6;
 tmp4 = tmp10 + tmp5;

 // Final output stage: scale down by a factor of 8
 outptr[0] = range_limit[(DESCALE((int) (tmp0 + tmp7), 3)) & 1023L];
 outptr[7] = range_limit[(DESCALE((int) (tmp0 - tmp7), 3)) & 1023L];
 outptr[1] = range_limit[(DESCALE((int) (tmp1 + tmp6), 3)) & 1023L];
 outptr[6] = range_limit[(DESCALE((int) (tmp1 - tmp6), 3)) & 1023L];
 outptr[2] = range_limit[(DESCALE((int) (tmp2 + tmp5), 3)) & 1023L];
 outptr[5] = range_limit[(DESCALE((int) (tmp2 - tmp5), 3)) & 1023L];
 outptr[4] = range_limit[(DESCALE((int) (tmp3 + tmp4), 3)) & 1023L];
 outptr[3] = range_limit[(DESCALE((int) (tmp3 - tmp4), 3)) & 1023L];

 wsptr+=8;//advance pointer to the next row
 outptr+=8;
  }
}

void precalculate_Cr_Cb_tables()
{
 WORD k;
 WORD Cr_v,Cb_v;
 for (k=0;k<=255;k++) Cr_tab[k]=(SWORD)((k-128.0)*1.402);
 for (k=0;k<=255;k++) Cb_tab[k]=(SWORD)((k-128.0)*1.772);

 for (Cr_v=0;Cr_v<=255;Cr_v++)
  for (Cb_v=0;Cb_v<=255;Cb_v++)
   Cr_Cb_green_tab[((WORD)(Cr_v)<<8)+Cb_v]=(int)(-0.34414*(Cb_v-128.0)-0.71414*(Cr_v-128.0));

}

void convert_8x8_YCbCr_to_RGB(BYTE *Y, BYTE *Cb, BYTE *Cr, DWORD im_loc, DWORD X_image_bytes, BYTE *im_buffer)
// Functia (ca optimizare) poate fi apelata si fara parametrii Y,Cb,Cr
// Stim ca va fi apelata doar in cazul 1x1
{
  DWORD x,y;
  BYTE im_nr;
  BYTE *Y_val = Y, *Cb_val = Cb, *Cr_val = Cr;
  BYTE *ibuffer = im_buffer + im_loc;

  for (y=0;y<8;y++)
   {
 im_nr=0;
 for (x=0;x<8;x++)
   {
    ibuffer[im_nr++] = rlimit_table[*Y_val + Cb_tab[*Cb_val]]; //B
    ibuffer[im_nr++] = rlimit_table[*Y_val + Cr_Cb_green_tab[WORD_hi_lo(*Cr_val,*Cb_val)]]; //G
    ibuffer[im_nr++] = rlimit_table[*Y_val + Cr_tab[*Cr_val]]; // R
/*
// Monochrome display
    im_buffer[im_nr++] = *Y_val;
    im_buffer[im_nr++] = *Y_val;
    im_buffer[im_nr++] = *Y_val;
*/
    Y_val++; Cb_val++; Cr_val++; im_nr++;
   }
 ibuffer+=X_image_bytes;
   }
}

void convert_8x8_YCbCr_to_RGB_tab(BYTE *Y, BYTE *Cb, BYTE *Cr, BYTE *tab, DWORD im_loc, DWORD X_image_bytes, BYTE *im_buffer)
// Functia (ca optimizare) poate fi apelata si fara parametrii Cb,Cr
{
  DWORD x,y;
  BYTE nr, im_nr;
  BYTE Y_val,Cb_val,Cr_val;
  BYTE *ibuffer = im_buffer + im_loc;

  nr=0;
  for (y=0;y<8;y++)
   {
 im_nr=0;
 for (x=0;x<8;x++)
   {
    Y_val=Y[nr];
    Cb_val=Cb[tab[nr]]; Cr_val=Cr[tab[nr]]; // reindexare folosind tabelul
    // de supraesantionare precalculat
    ibuffer[im_nr++] = rlimit_table[Y_val + Cb_tab[Cb_val]]; //B
    ibuffer[im_nr++] = rlimit_table[Y_val + Cr_Cb_green_tab[WORD_hi_lo(Cr_val,Cb_val)]]; //G
    ibuffer[im_nr++] = rlimit_table[Y_val + Cr_tab[Cr_val]]; // R
    nr++; im_nr++;
   }
 ibuffer+=X_image_bytes;
   }
}

void calculate_tabs()
{
 BYTE tab_temp[256];
 BYTE x,y;

 // Tabelul de supraesantionare 16x16
 for (y=0;y<16;y++)
  for (x=0;x<16;x++)
    tab_temp[y*16+x] = (y/YV)* 8 + x/YH;

 // Din el derivam tabelele corespunzatoare celor 4 blocuri de 8x8 pixeli
 for (y=0;y<8;y++)
 {
  for (x=0;x<8;x++)
   tab_1[y*8+x]=tab_temp[y*16+x];
  for (x=8;x<16;x++)
   tab_2[y*8+(x-8)]=tab_temp[y*16+x];
 }
 for (y=8;y<16;y++)
 {
  for (x=0;x<8;x++)
   tab_3[(y-8)*8+x]=tab_temp[y*16+x];
  for (x=8;x<16;x++)
   tab_4[(y-8)*8+(x-8)]=tab_temp[y*16+x];
 }
}


int init_JPG_decoding()
{
 byte_pos=0;
 init_QT();
 calculate_mask();
 prepare_range_limit_table();
 precalculate_Cr_Cb_tables();
 return 1; //for future error check
}

DWORD filesize(FILE *fp)
{
 DWORD pos;
 DWORD pos_cur;
 pos_cur=ftell(fp);
 fseek(fp,0,SEEK_END);
 pos=ftell(fp);
 fseek(fp,pos_cur,SEEK_SET);
 return pos;
}

int load_JPEG_header(FILE *fp, DWORD *X_image, DWORD *Y_image)
{
 DWORD length_of_file;
 BYTE vers,units;
 WORD Xdensity,Ydensity,Xthumbnail,Ythumbnail;
 WORD length;
 float *qtable;
 DWORD old_byte_pos;
 Huffman_table *htable;
 DWORD j;
 BYTE precision,comp_id,nr_components;
 BYTE QT_info,HT_info;
 BYTE SOS_found,SOF_found;

 length_of_file=filesize(fp);
 buf=(BYTE *)malloc(length_of_file+4);
 if (buf==NULL) exit_func("Not enough memory for loading file");
 fread(buf,length_of_file,1,fp);

 if ((buf[0]!=0xFF)||(buf[1]!=SOI)) exit_func("Not a JPG file ?\n");
 if ((buf[2]!=0xFF)||(buf[3]!=APP0)) exit_func("Invalid JPG file.");
 if ( (buf[6]!='J')||(buf[7]!='F')||(buf[8]!='I')||(buf[9]!='F')||
   (buf[10]!=0) ) exit_func("Invalid JPG file.");

 init_JPG_decoding();
 byte_pos=11;

 BYTE_p(byte_pos);vers=bp;
 if (vers!=1) exit_func("JFIF version not supported");
 BYTE_p(byte_pos); // vers_lo=bp;
 BYTE_p(byte_pos);  units=bp;
 if (units!=0) //exit_func("JPG format not supported");
 ;// printf("units = %d\n", units);
 WORD_p(byte_pos); Xdensity=wp; WORD_p(byte_pos); Ydensity=wp;
 if ((Xdensity!=1)||(Ydensity!=1)) //exit_func("JPG format not supported");
  ;  //{printf("X density = %d\n",Xdensity); printf("Y density = %d\n",Ydensity);}
 BYTE_p(byte_pos);Xthumbnail=bp;BYTE_p(byte_pos);Ythumbnail=bp;
 if ((Xthumbnail!=0)||(Ythumbnail!=0))
 exit_func(" Cannot process JFIF thumbnailed files\n");
 // Start decoding process
 SOS_found=0; SOF_found=0; Restart_markers=0;
 while ((byte_pos<length_of_file)&&!SOS_found)
 {
  BYTE_p(byte_pos);
  if (bp!=0xFF) continue;
  // A marker was found
  BYTE_p(byte_pos);
  switch(bp)
  {
   case DQT: WORD_p(byte_pos); length=wp; // length of the DQT marker
    for (j=0;j<wp-2;)
    {
     old_byte_pos=byte_pos;
     BYTE_p(byte_pos); QT_info=bp;
     if ((QT_info>>4)!=0)
     exit_func("16 bit quantization table not supported");
     qtable=QT[QT_info&0xF];
     load_quant_table(qtable);
     j+=byte_pos-old_byte_pos;
    }
    break;
   case DHT: WORD_p(byte_pos); length=wp;
    for (j=0;j<wp-2;)
    {
     old_byte_pos=byte_pos;
     BYTE_p(byte_pos); HT_info=bp;
     if ((HT_info&0x10)!=0) htable=&HTAC[HT_info&0xF];
     else htable=&HTDC[HT_info&0xF];
     load_Huffman_table(htable);
     j+=byte_pos-old_byte_pos;
    }
    break;
   case COM: WORD_p(byte_pos); length=wp;
    byte_pos+=wp-2;
    break;
   case DRI: Restart_markers=1;
    WORD_p(byte_pos); length=wp; //should be = 4
    WORD_p(byte_pos);  MCU_restart=wp;
    if (MCU_restart==0) Restart_markers=0;
    break;
   case SOF: WORD_p(byte_pos); length=wp; //should be = 8+3*3=17
    BYTE_p(byte_pos); precision=bp;
    if (precision!=8) exit_func("Only 8 bit precision supported");
    WORD_p(byte_pos); *Y_image=wp; WORD_p(byte_pos); *X_image=wp;
    BYTE_p(byte_pos); nr_components=bp;
    if (nr_components!=3) exit_func("Only truecolor JPGS supported");
    for (j=1;j<=3;j++)
    {
     BYTE_p(byte_pos); comp_id=bp;
     if ((comp_id==0)||(comp_id>3)) exit_func("Only YCbCr format supported");
     switch (comp_id)
     {
      case 1: // Y
       BYTE_p(byte_pos); YH=bp>>4;YV=bp&0xF;
       BYTE_p(byte_pos); YQ_nr=bp;
       break;
      case 2: // Cb
       BYTE_p(byte_pos); CbH=bp>>4;CbV=bp&0xF;
       BYTE_p(byte_pos); CbQ_nr=bp;
       break;
      case 3: // Cr
       BYTE_p(byte_pos); CrH=bp>>4;CrV=bp&0xF;
       BYTE_p(byte_pos); CrQ_nr=bp;
       break;
     }
    }
    SOF_found=1;
    break;
   case SOS: WORD_p(byte_pos); length=wp; //should be = 6+3*2=12
   BYTE_p(byte_pos); nr_components=bp;
   if (nr_components!=3) exit_func("Invalid SOS marker");
   for (j=1;j<=3;j++)
     {
   BYTE_p(byte_pos); comp_id=bp;
   if ((comp_id==0)||(comp_id>3)) exit_func("Only YCbCr format supported");
   switch (comp_id)
   {
    case 1: // Y
     BYTE_p(byte_pos); YDC_nr=bp>>4;YAC_nr=bp&0xF;
     break;
    case 2: // Cb
     BYTE_p(byte_pos); CbDC_nr=bp>>4;CbAC_nr=bp&0xF;
     break;
    case 3: // Cr
     BYTE_p(byte_pos); CrDC_nr=bp>>4;CrAC_nr=bp&0xF;
     break;
   }
     }
   BYTE_p(byte_pos); BYTE_p(byte_pos); BYTE_p(byte_pos); // Skip 3 bytes
   SOS_found=1;
   break;
   case 0xFF:
   break; // do nothing for 0xFFFF, sequence of consecutive 0xFF are for
   // filling purposes and should be ignored
   default:  WORD_p(byte_pos); length=wp;
   byte_pos+=wp-2; //skip unknown marker
   break;
  }
 }
 if (!SOS_found) exit_func("Invalid JPG file. No SOS marker found.");
 if (!SOF_found) exit_func("Progressive JPEGs not supported");

 if ((CbH>YH)||(CrH>YH)) exit_func("Vertical sampling factor for Y should be >= sampling factor for Cb,Cr");
 if ((CbV>YV)||(CrV>YV)) exit_func("Horizontal sampling factor for Y should be >= sampling factor for Cb,Cr");

 if ((CbH>=2)||(CbV>=2)) exit_func("Cb sampling factors should be = 1");
 if ((CrV>=2)||(CrV>=2)) exit_func("Cr sampling factors should be = 1");

// Restricting sampling factors for Y,Cb,Cr should give us 4 possible cases for sampling factors
// YHxYV,CbHxCbV,CrHxCrV: 2x2,1x1,1x1;  1x2,1x1,1x1; 2x1,1x1,1x1;
// and 1x1,1x1,1x1 = no upsampling needed

 Hmax=YH,Vmax=YV;
 if ( *X_image%(Hmax*8)==0) X_round=*X_image; // X_round = Multiple of Hmax*8
 else X_round=(*X_image/(Hmax*8)+1)*(Hmax*8);
 if ( *Y_image%(Vmax*8)==0) Y_round=*Y_image; // Y_round = Multiple of Vmax*8
 else Y_round=(*Y_image/(Vmax*8)+1)*(Vmax*8);

 im_buffer=(BYTE *)malloc(X_round*Y_round*4);
 if (im_buffer==NULL) exit_func("Not enough memory for storing the JPEG image");

 return 1;
}

void resync()
// byte_pos  = pozitionat pe restart marker
{
 byte_pos+=2;
 BYTE_p(byte_pos);
 if (bp==0xFF) byte_pos++; // skip 00
 w1=WORD_hi_lo(bp, 0);
 BYTE_p(byte_pos);
 if (bp==0xFF) byte_pos++; // skip 00
 w1+=bp;
 BYTE_p(byte_pos);
 if (bp==0xFF) byte_pos++; // skip 00
 w2=WORD_hi_lo(bp, 0);
 BYTE_p(byte_pos);
 if (bp==0xFF) byte_pos++; // skip 00
 w2+=bp;
 wordval=w1; d_k=0; // Reinit bitstream decoding
 DCY=0; DCCb=0; DCCr=0; // Init DC coefficients
}

void decode_MCU_1x1(DWORD im_loc)
{
 // Y
 process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
 IDCT_transform(DCT_coeff,Y,YQ_nr);
 // Cb
 process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
 IDCT_transform(DCT_coeff,Cb,CbQ_nr);
 // Cr
 process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
 IDCT_transform(DCT_coeff,Cr,CrQ_nr);

 convert_8x8_YCbCr_to_RGB(Y,Cb,Cr,im_loc,X_image_bytes,im_buffer);
}
void decode_MCU_2x1(DWORD im_loc)
{
 // Y
 process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
 IDCT_transform(DCT_coeff,Y_1,YQ_nr);
 process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
 IDCT_transform(DCT_coeff,Y_2,YQ_nr);
 // Cb
 process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
 IDCT_transform(DCT_coeff,Cb,CbQ_nr);
 // Cr
 process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
 IDCT_transform(DCT_coeff,Cr,CrQ_nr);

 convert_8x8_YCbCr_to_RGB_tab(Y_1,Cb,Cr,tab_1,im_loc,X_image_bytes,im_buffer);
 convert_8x8_YCbCr_to_RGB_tab(Y_2,Cb,Cr,tab_2,im_loc+32,X_image_bytes,im_buffer);
}

void decode_MCU_2x2(DWORD im_loc)
{
 // Y
 process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
 IDCT_transform(DCT_coeff,Y_1,YQ_nr);
 process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
 IDCT_transform(DCT_coeff,Y_2,YQ_nr);
 process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
 IDCT_transform(DCT_coeff,Y_3,YQ_nr);
 process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
 IDCT_transform(DCT_coeff,Y_4,YQ_nr);
 // Cb
 process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
 IDCT_transform(DCT_coeff,Cb,CbQ_nr);
 // Cr
 process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
 IDCT_transform(DCT_coeff,Cr,CrQ_nr);

 convert_8x8_YCbCr_to_RGB_tab(Y_1,Cb,Cr,tab_1,im_loc,X_image_bytes,im_buffer);
 convert_8x8_YCbCr_to_RGB_tab(Y_2,Cb,Cr,tab_2,im_loc+32,X_image_bytes,im_buffer);
 convert_8x8_YCbCr_to_RGB_tab(Y_3,Cb,Cr,tab_3,im_loc+y_inc_value,X_image_bytes,im_buffer);
 convert_8x8_YCbCr_to_RGB_tab(Y_4,Cb,Cr,tab_4,im_loc+y_inc_value+32,X_image_bytes,im_buffer);
}

void decode_MCU_1x2(DWORD im_loc)
{
 // Y
 process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
 IDCT_transform(DCT_coeff,Y_1,YQ_nr);
 process_Huffman_data_unit(YDC_nr,YAC_nr,&DCY);
 IDCT_transform(DCT_coeff,Y_2,YQ_nr);
 // Cb
 process_Huffman_data_unit(CbDC_nr,CbAC_nr,&DCCb);
 IDCT_transform(DCT_coeff,Cb,CbQ_nr);
 // Cr
 process_Huffman_data_unit(CrDC_nr,CrAC_nr,&DCCr);
 IDCT_transform(DCT_coeff,Cr,CrQ_nr);

 convert_8x8_YCbCr_to_RGB_tab(Y_1,Cb,Cr,tab_1,im_loc,X_image_bytes,im_buffer);
 convert_8x8_YCbCr_to_RGB_tab(Y_2,Cb,Cr,tab_3,im_loc+y_inc_value,X_image_bytes,im_buffer);
}

void decode_JPEG_image()
{
 decode_MCU_func decode_MCU;

 WORD x_mcu_cnt,y_mcu_cnt;
 DWORD nr_mcu;
 WORD X_MCU_nr,Y_MCU_nr; // Nr de MCU-uri
 DWORD MCU_dim_x; //dimensiunea in bufferul imagine a unui MCU pe axa x
 DWORD im_loc_inc; // = 7 * X_round * 4 sau 15*X_round*4;
 DWORD im_loc; //locatia in bufferul imagine

 byte_pos-=2;
 resync();

 y_inc_value = 32*X_round;
 calculate_tabs(); // Calcul tabele de supraesantionare, tinand cont de YH si YV

 if ((YH==1)&&(YV==1)) decode_MCU=decode_MCU_1x1;
 else {
    if (YH==2)
    {
  if (YV==2) decode_MCU=decode_MCU_2x2;
  else decode_MCU=decode_MCU_2x1;
    }
    else decode_MCU=decode_MCU_1x2;
 }
 MCU_dim_x=Hmax*8*4;

 Y_MCU_nr=Y_round/(Vmax*8); // nr of MCUs on Y axis
 X_MCU_nr=X_round/(Hmax*8); // nr of MCUs on X axis

 X_image_bytes=X_round*4; im_loc_inc = (Vmax*8-1) * X_image_bytes;
 nr_mcu=0; im_loc=0; // memory location of the current MCU
 for (y_mcu_cnt=0;y_mcu_cnt<Y_MCU_nr;y_mcu_cnt++)
 {
  for (x_mcu_cnt=0;x_mcu_cnt<X_MCU_nr;x_mcu_cnt++)
   {
 decode_MCU(im_loc);
 if ((Restart_markers)&&((nr_mcu+1)%MCU_restart==0)) resync();
 nr_mcu++;
 im_loc+=MCU_dim_x;
   }
  im_loc+=im_loc_inc;
 }
}

int get_JPEG_buffer(WORD X_image,WORD Y_image, BYTE **address_dest_buffer)
{
 WORD y;
 DWORD dest_loc=0;
 BYTE *src_buffer=im_buffer;
 BYTE *dest_buffer_start, *dest_buffer;

 DWORD src_bytes_per_line=X_round*4;
 DWORD dest_bytes_per_line=X_image*4;


 if ((X_round==X_image)&&(Y_round==Y_image))
 *address_dest_buffer=im_buffer;
 else
 {
  dest_buffer_start = (BYTE *)malloc(X_image*Y_image*4);
  if (dest_buffer_start==NULL) exit_func("Not enough memory for storing the JPEG image");
  dest_buffer = dest_buffer_start;
  for (y=0;y<Y_image;y++) {
    memcpy(dest_buffer,src_buffer,dest_bytes_per_line);
    src_buffer+=src_bytes_per_line;
    dest_buffer+=dest_bytes_per_line;
  }
 *address_dest_buffer=dest_buffer_start;
 free(im_buffer);
 }
// release the buffer which contains the JPG file
 free(buf);
 return 1;
}


////////////////////////////////////////////////
END OF SOURCE CODE
//////////////////////////////////////////////

오라클(DATABASE MANAGEMENT SYSTEM)
먼저번의 CObject 클래스 부분에서 잠깐 언급한 CRuntimeClass 구조체를 이용하여 클래스를 동적으로 생성시크는 코드에 대해 말합니다.
이 방법은 여러모로 사용하기 편하고 쓰레드 클래스 생성시에도 사용가능 하지요.

COject 클래스의 매크로 DECLARE_DYNAMIC이나 DECLARE_DYNCREATE 사용시 Ructime으로 객체를 생성할 수 있다하였습니다.

이유룰 간단히 말씀드리면 DECLARE_DYNAMIC이나 DECLARE_DYNCREATE 매크로는 CObject 클래스에서 CRuntimeClass의 static 멤버를 갖게 됩니다.

이 멤버는 template Class로 정의가 되고 이 클래스의 포인터는 RUNTIME_CLASS 매크로를 사용하면 얻을 수 있습니다.

RUNTIME_CLASS는 다음처럼 정의되죠.
#define RUNTIME_CLASS(class_name) (&class_name::class##class_name)으로 정의되 있습니다.

또 CRuntimeClass 구조체는 다음의 데이터를 가지고 있구요.
struct CRuntimeClass
{
LPCSTR m_lpszClassName;
int m_nObjectSize;
UINT m_wSchema
CObject* (PASCAL* m_pfnCreateObject)( );
CObject* CreateObject( );

CRuntimeClass* (PASCAL* m_pfnGetBaseClass)( );
CRuntimeClass* m_pBaseClass;
BOOL IsDerivedFrom(const CRuntimeClass* pBaseClass) const;
};

위 멤버중 중요하게 생각하실 멤버는 m_lpszClassName, m_nObjectSize, m_pfnCreateObject, CreateObject( )가 중요합니다.
각 멤버를 보면 m_lpszClassName은 생성된 클래스 이름, m_nObjectSize는 메모리가 현재 유효한지 검사하기 위해 사용하며 m_pfnCreateObject는 CreateObject()의 함수포인터를 선언하는 곳입니다.

CreateObject 함수가 실제로 그 클래스들을 동적으로 생성시키는 부분입니다.

MFC를 예로 들면 보통 App클래스의 InitInstance 함수에서 다음처럼 되어 있는 부분을 보시기 바랍니다.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
    IDR_MAINFRAME,
    RUNTIME_CLASS(CMyDoc),
    RUNTIME_CLASS(CMainFrame),       // main SDI frame window
    RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);

위에서 CSingleDoctemplate 클래스는 SDI를 정의한 부분입니다.(이에대해서는 MSDN에 자세히 나와 있습니다.)

그리고 그 생성자에서 바로 Application에 대해 Document, MainFrame, View를 동적으로 생성시킵니다.

그런데 위 3가지 클래스의 헤더파일에 선언된 생성자를 보면 모두 protected 로 선언이 되어 있어 CMyView myView; 형태로 객체를 생성시키지 못하지요.
그리고 각 클래스들은 CRuntimeClass 멤버를 사용할 수 있게 DECLARE_DYNAMIC이나 DECLARE_DYNCREATE 매크로를 사용한 것을 볼 수 있을 것입니다.

즉 MFC에서는 위의 형태로 클래스 객체를 동적으로 생성시킬 수 있는 것입니다.
그러면 각각의 CreteObject() 함수는 어떻게 정의되어 있을까요?

view를 예로 들면
CObject* CView::CreateObject()
{
    return new CView;
}
형태로 되어 있어 여기서 메모리 로딩이 되지요. 물론 생성자도 호출이 되고...


그러면 여러분의 이해를 돕기위해 간단히 MFC식으로 C++ 코드를 사용하여 한번 코딩해보면

//Runtime 매크로 정의
#define RUN_TIME_CLASS(class_name) (&class_name::class##class_name)

//베이스 클래스 정의및 선언
class CObject;  //베이스 클래스 선언

//////////////Runtime 구조체 정의////////////////////////////////////////////
struct CRuntime  //CRuntimeClass 대신 CRuntime으로... (그리고 중요부분만 정의)
{
LPCSTR m_lpszClassName;
int m_nObjectSize;
CObject* (*m_pfnCreateObject)( );
CObject* CreateObject( );
};


////////////////베이스 클래스 정의//////////////////////////////////////////
class CObject
{
public:
    virtual CRuntime* GetRuntime()const {return NULL; } //Object의 ClassName은 없슴.

    static CRuntime classObject;    //DYNAMIC 매크로 사용시

    virtual ~CObject() {}

protected:
    CObject() { cout << "생성자 CObject!!" << endl ; }
};

//static 멤버변수 초기화
CRuntime CObject::classObject = {"CObject", sizeof(CObject), NULL};

CObject* CRuntime::CreateObject()
{
    return (*m_pfnCreateObject)(); //함수 포인터를 사용
}

////////////////View 클래스////////////////////////////////////////////////
class CView : public CObject
{
public:
    virtual CRuntime* GetRuntime* GetRuntime()const { return &classCView; }
    static CRuntime classCView;    //DYNAMIC 매크로 사용시
    static CObject* CreteObject(); //DYNCREATE 매크로 사용시

protected:
    CView() { cout << "생성자 CView!!" << endl; }
};

CRuntime CView::classCView = {"CView", sizeof(CView), CView::CreateObject};

CObject* CView::CreateObject()
{
    return new CView; //생성
}


////////////////Document Class ////////////////////////////////////////
class CDoc : public CObject
{
public:
    virtual CRuntime* GetRuntime* GetRuntime()const { return &classCDoc; }
    static CRuntime classCDoc;    //DYNAMIC 매크로 사용시
    static CObject* CreteObject(); //DYNCREATE 매크로 사용시

protected:
    CDoc() { cout << "생성자 CDoc!!" << endl; }
};

CRuntime CDoc::classCDoc = {"CDoc", sizeof(CDoc), CDoc::CreateObject};

CObject* CDoc::CreateObject()
{
    return new CDoc; //생성
}

//////////////////프로그램 메인함수 /////////////
void main()
{
    CRuntime* pView = RUN_TIME_CLASS(CView);
    CObject* pObjectView = pView->CreateObject();

    cout << "View Class Name: " <<
              pObjectView->GetRuntime()->m_lpszClassName << endl;

    CRuntime* pDoc = RUN_TIME_CLASS(CDoc);
    CObject* pObjectDoc = pDoc->CreateObject();

    cout << "Doc Class Name: " <<
             pObjectDoc->GetRuntime()->m_lpszClassName << endl;

    delete pObjectView;
    delete pObjectDoc;
}

의 형태로 MFC는 클래스를 동적으로 생성합니다.
물론 소멸은 MFC에서 하는 방법은 아니지만 여러분들이 MFC FrameWork을 직접 분석해 보시면 아실 겁니다.

/*
 select.c
*/

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/timeb.h>

#define BUFSIZE 30

int main(int argc, char * argv)
{
 fd_set reads, temps;
 int result;

 char message[BUFSIZE];
 int str_len;
 struct timeval timeout;

 FD_ZERO(&reads);
 FD_SET(0, &reads);
/*
 timeout.tv_sec = 5;
 timeout.tv_usec = 100000;
*/
 while( true )
 {
  temps = reads;
  timeout.tv_sec = 5;
  timeout.tv_usec = 0;

  result = select(1, &temps, 0, 0, &timeout);
 
  if( result == -1 )
  {
   puts("select 오류 발생");
   exit(1);
  }
  else if( result == 0 )
  {
   puts("시간이 초과되었습니다 : sekect");
  }
  else
  {
   if( FD_ISSET(0, &temps) )
   {
    str_len = read(0, message, BUFSIZE);
    message[str_len] = 0;
    fputs(message, stdout);
   }
  }
 }
}

WAVE FILE의 구조

WAVE 파일은 사운드 파일중에 한 형식으로 윈도우에서 가장 흔하게 쓰이는 파일중에 하나이다. 이번에 이 유령넘이 강좌랍시고 주절 거리는
내용은 이넘의 WAVE 파일을 한번 재생해 보자..는 것이다. WAVE 파일을재생하는데는, 쉽게는 SoundPlay() 함수였던가? .. 한줄이면 족하다...
물론, 지금 이 강좌는 그렇게 한줄이면 끝나는 정도가 아닌, WAVE 파일의 밑바닥부터 꼭대기까지 샅샅히 훑어 내려가며, 그 내부를 마구 파헤쳐
WAVE 파일을 맘대로 주무를 수 있도록 하는 경지?에까지 도달하도록하는것이 목표다.
일단, WAVE 파일이고 머고 간에, 기본적인 공식?부터 알아보고 넘어가도록 하자.사운드라는 것에 대해 깊이 있는 지식을 가지고 있는 사람은
볼 필요가 없겠지만, 어디까지나 처음 시작하는 사람들이 볼 것 이라고가정하고 설명하도록 한다.
WAVE 파일을 재생하면서 가끔 등록정보를 보신 분들은 알겠지만, 대게WAVE 파일의 등록정보라고 하면, 16 Bit , Stereo , 44.1 kHz...  등등
의 정보가 보일것이다. 이게 뭐가 중요하냐고? 중요하다.. 정말 중요하다. 이것으로 WAVE 파일이 시작되는 것이기 때문이다.예를 들어서 다음
과 같은 WAVE 파일이 하나 있다고 보자.

------------------------------------------------------------------
 [어떤 WAVE 파일의 등록정보]

 - 곡명 : 유령이라 불러라!
 - 16 Bit
 - Stereo
 - 44.1 khz
------------------------------------------------------------------

 이 세가지 정보면 WAVE 파일의 모든 것?을 알 수 있다. 일단 이 3가지기본적인 정보만으로 이 WAVE 파일의 초당전송량(Bit/Second)이나,전체

재생시간등을 계산해 보자. (이거 배워두면 정말 좋다..-_-;;..그냥..)

 일단 계산하는 방식은 모두 곱한다. 16 Bit 이므로 16 을 곱하고,스테레오 방식이기 때문에 (스테레오는 채널이 2개 이기때문에, 2를 곱한다

당연히 모노는 1채널이기 때문에 1을 곱하면 된다.... 1은 안곱해도 되는구나 --;) 그리고 44.1 kHz 라는 것은 1초에 44100 번 발광을 한다는

소리니까 44100을 곱하면 된다.
 

16 * 2 * 44100 = 1411200 Bit 다.. 다시 바이트로 고쳐주려면, 나누기 8을 하면 된다. (왜 나누기 8을 하냐고 묻는다면.. 아시다시피.. 8 Bit

는 1 Byte 이기 때문이다..) 나누기 8을 한 결과 176400 이라는 숫자가나왔다.


 즉, 이 WAVE 파일은 초당 176400 Byte 의 용량을 전송한다는 얘기다..숫자가 너무 크다고?.. 다시 KByte로 환산해 보자.. 172.265625가 나오

는데,귀찮으니까 소수점 아랫것들은 잘라버리고 정수부분만 읽어보자면172 KB 라고 나올 것이다. 그렇다. 이 WAVE 파일은 1초에 172 KB 나 차

지한다. (더럽게 크구만..) 전체 재생시간을 구하는 것 역시 간단하다.단순히 나누기만 하면 되기 때문이다.  전체 파일 크기를 알고 있다면,


 " 전체 파일 크기 / 초당 용량 = 전체 재생 시간 (초 단위) "

 라는 공식이 성립되는 것이다.자,이제 자신의 컴퓨터에 들어있는 WAVE들을 모조리 불러다가 그 넘들의 재생시간을 구해보고 실제로 플레이

해본다음 비슷하게 맞는지 비교해 보라.

------------------------------------------------------------------
 여기서, 숙제.. 다음의 WAVE 파일들의 전체 크기는 얼마나 될까??????

 [1]  8 Bit , Mono , 22 kHz
 [2] 16 Bit , Mono , 11 kHz
 [3] 16 Bit , Stereo , 22 KHz

 각각의 WAVE 파일들의 재생시간은 총 1분 30초씩 이다. 그렇다면 각각의 WAVE 파일들의 전체 파일크기는 얼마나 될까?? ( 대한민국 초등교육

과정을 이수한 사람이라면 누구나 풀 수 있는 문제라서 풀이는 생략..)
------------------------------------------------------------------

 WAVE 파일은 대게 8 Bit , 16 Bit 가 많이 쓰이는데, 24, 32 Bit 파일은 별도로 치고.. 대표적인 8 / 16 Bit 파일들은 아래의 그림처럼 파일

에 저장되어 있다. 8 Bit 라면 - 1 Byte 이므로 1 Byte 단위 마다 저장되어 있고, 16 Bit 라면 당연히 2 Byte 마다 저장되어 있다. 아래 그림

을 보면 8 Bit 파일은 전부 16개 (16진수 10까지..) 로 되어 있는 반면 16 Bit 는 같은 크기인데도 8 칸 밖에는 안된다. 이론적으로 16 Bit 는

8 Bit 에 비해 2 배의 용량을 차지하기 때문이다. [ D ] 라고 표기되어있는 것은 본인이 편의상 구분하기 쉽게 [ DATA ] 를 줄여 표현한 것이

고.. ( Mono 는 L / R 구분이 없다 ) Stereo에서 [ L ] , [ R ] 이라고

표기 한 것은 양 채널 ( Left Channel, Right Channel ) 을 뜻 한다...

------------------------------------------------------------------
 [ 8 Bit Mono ]

   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F  10
 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 : D : D : D : D : D : D : D : D : D : D : D : D : D : D : D : D :
 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

 [ 8 Bit Stereo ]

   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F  10
 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 : L : R : L : R : L : R : L : R : L : R : L : R : L : R : L : R :
 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+


 [ 16Bit Mono ]
     1       2       3       4       5       6       7       8
 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 :   D   :   D   :   D   :   D   :   D   :   D   :   D   :   D   :
 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

 [16Bit Stereo ]

     1       2       3       4       5       6       7       8
 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
 :   L   :   R   :   L   :   R   :   L   :   R   :   L   :   R   :
 +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

------------------------------------------------------------------

 이건 어디까지나 2 채널(Stereo)방식만을 봤을때 그렇다는 것이고, 채널이 많아지면 또 저장구조는 당연히 달라지게 된다. 요즘 흔히 말하는

5.1채널이니 7.1채널이니 하는 것들은, 저것과는 모양새가 또 다르다..

------------------------------------------------------------------

 WAVE 파일에 대해서 간략하게나마 알아봤는데,이제부터는 정말 자세히파헤쳐 볼 시간이다. WAVE 파일들은 크게 청크 부분과 데이타 부분으로

나뉜다. 실제 사운드가 들어있는 데이타 부분 앞에는 헤더 청크 부분이있는데, WAVE 파일의 구조를 살펴보면 아래와 같다.

------------------------------------------------------------------
1. Wave 파일 포맷(I)

   1) PCMWAVEFORMAT 구조체의 구조
      -. WAVEFORMAT wf;
      -. WORD       wBitsPerSample;

   2) WAVEFORMAT 구조체의 구조
      -. WORD   wFormatTag;
      -. WORD   nChannels;
      -. DWORD  nSamplesPerSec;
      -. DWORD  nAvgBytesPerSec;
      -. WORD   nBlockAlign;

   3) 예 : 22kHz 샘플링된 8bit 스테레오 Wave 파일의 구조

      PCMWAVEFORMAT PcmWaveFormat;
     
      PcmWaveFormat.wf.wFormatTag = 1;
      PcmWaveFormat.wf.nChannels = 2;      
      PcmWaveFormat.wf.nSamplesPerSec = 22050; 
      PcmWaveFormat.wf.nAvgBytesPerSec = 44100;
      PcmWaveFormat.wf.nBlockAlign = 2;
      PcmWaveFormat.wBitsPerSample = 8;       


2. Wave 파일 포맷(II)
------------------------------------------------------------------
     데이터형 Byte  내용            의미
------------------------------------------------------------------

 1) RIFF chunk 
     - Char   4   "RIFF"          파일의 종류가 RIFF 파일을 의미
     - DWORD  4   FILE SIZE       현재부터 끝까지의 파일크기
                                  (파일크기-4Byte 또는, 데이터 크기
                                   +40Byte)
     - Char   4   "WAVE"          Wave 파일을 의미
  
 2) FMT sub-chunk
     - Char   4   "fmt "          FMT sub-chunk의 시작
     - DWORD  4   16              현재 포인터(16 Byte)
     - short  2   wFormatTag      PCMWAVEFORMAT의 값
                                  ( 1:Wave Format이 PCM 방식 )
     - short  2   nChannels       채널 수 ( 1:모노, 2:스테레오 )
     - DWORD  4   nSamplesPerSec  샘플링 수
                                  ( 11kHz:11025,
                                    22kHz:22050,
                                    44kHz:44100 )
     - DWORD  4   nAvgBytesperSec 초당 샘플바이트
                                  ( nSamplesPerSec*BlockAlign )
     - short  2   BlockAlign      샘플당 바이트( nChannels*비트/8 )
     - short  2   wBitsPerSample  샘플당 비트수

   3) Data sub-chunk
     - Char   4   "data"          데이터청크의 시작
     - DWORD  4   DATA SIZE       데이터의 크기
                  DATA            데이터
------------------------------------------------------------------

 WAVE 파일들을 EDITOR 로 읽어보면 파일의 내용이 아래와 같이 나온다원래는 HEX 값이 나와야 하는데 메모장으로 읽어들였더니..아래처럼 나

왔다.. -_-; 그래도 상관없다. 중요한건 제일 처음 " RIFF " 라는 단어로 시작한다는 것이다. 그 다음에 WAVE 파일 포맷임을 알리는 " WAVE "

라는 단어가 온다. 보통 파일포맷에 따라 헤더에 해당 파일포맷임을 리는 식별자가 오는데 GIF나 PCX, 또는 EXE 파일들을 한번씩 열어 보면

같은 단어로 시작한다는 것을 알 수 있을 것이다.

[1] RIFF$?WAVEfmt D&#52550;Xdata? ...

[2] RIFF?$WAVEfmt D??data? ...

[3] RIFF? WAVEfmt   D  ? PAD ?                                      

                                          
------------------------------------------------------------------              

                   
 3 개의 WAVE 파일들을 열어봤는데, 모두 RIFF .. WAVE .. fmt 로 시작하고 있다.이 파일들이 WAVE 파일임을 알 수 있는 것이다. 사실 WAVE파

일에도 ADPCM 이니 PCM 이니 하는 식으로 다양한?포맷이 존재하는데 이

것은 쉽게 생각하면 압축방식의 차이다.  여기서 RIFF 파일 형식이라는

말이 나오는데, RIFF에 대해서 설명하자면..
          
------------------------------------------------------------------
[ RIFF 파일(Resource Interchange File Format) ]
------------------------------------------------------------------ 
음성이나 비디오 같은 유의 데이터들은 용량이 매우 크기 때문에  이를저장할 시에는 비트 단위보다는 블록 단위로 저장을 하게 된다.

이러한블록은 가변적인 크기를 가질 수 있는데 이를 위해서는 데이터 블록 앞에 헤더를 사용해 이를 정의해 주어야 한다. 일례로

10 MByte 의  음성

데이터를 파일에 저장 하려할 때 블록 단위로 하지 않으면 데이터를 불러오는데 10M의 메모리가 필요하게 된다. 이렇게 된다면 불러오기도 힘

들 뿐만 아니라 불러오는데 걸리는 시간이 많이 걸리는 단점이 생긴다.그러나 10M의 음성데이터를 0.5M 씩 블록으로 나누어 저장한다면 20 개

의 블록을 가질 것이다. 즉, 0.5M씩 메모리에 불러온 후 출력하고,  메모리를 해제한 후 다시 다음 블록을 불러오면 그만큼 메모리도 절약 할

수 있어 매우 편리하게 된다. 또한 데이터 저장 블록 앞에 블록의 데이터 크기를 넣어주는데, 이는 예를 들자면 어느 시간동안 모노로 듣다가

후에 스테레오로 들을 수 있는 상황 등에 대처하기 쉽다. 이럴 때 데이터 블록 앞에 데이터에 대한 정보를 만들어 준다. 각각의 부분 하나 하

나는 청크(Chunk)라고 하고 처음에 나오는 상자를 부모 청크,그 하단에위치하는 부분을 자식 청크, 데이터들은 데이터 청크라고 한다.이와 같

은 구성 데이터를 저장하는 방식을 RIFF라 하고 위와 같은 구성으로 저장된 데이터를 RIFF 파일이라 한다.  WAVE  파일이나 AVI  파일이 바로

RIFF 파일이다.


기타


다음으로 알아두면 앞으로 강좌를 이해하기에 좋을 압축방식들에 대한정보들을 소개한다.

[ PCM(Pulse Code Modulation) 방식 ]

이 방식은 가장 널리 사용되는 방식으로서 음성을 아날로그에서 디지털로 변환하여 양자화(작은 단위화)한 데이터를 그대로 저장한 후 재생할

때에는 그 데이터를 디지털에서 아날로그로 재변환하여 음성 파형을 만든다. 이 방식은 양자화를 할 때 생기는 오차가 존재하지만 재생 시 상

당히 우수한 품질을 가진다.이 방식의 특징은 제로 크로스의 방법에 비해 생성되는 데이터의 양이 많다는 점이다.예를 들어, 샘플링 주파수를

8Khz로 하고 양자화 시 정밀도를 8bit로 하면 8000 * 8 = 64000/sec = 64Kbit/sec로 초당 64KB가 생성된다. 그러나 최근에는 메모리의 가격이

많이 떨어지고 있어서 뛰어난 음성 품질을 보장할수 있는 PCM방식을 많이 사용하고 있다.


[ DM(Delta Modulation) 방식 ]

DM 방식은 제로 크로스 방식과 PCM 방식의 중간적인 형태로 볼 수 있다이 방식은 어느 시점n의 파고와 바로 전 시점 (n-1)의 파고를 비교하여

그 차이점을 1,0,-1로 표현한다. DM 방식의 단점은 원파형의 급격한 변화를 따라가지 못한다는 것이다. DM 방식의 하드웨어 구현은 바로 이전

값에 1 또는 -1을 더하기만 하면 되므로 아주 간단하다.


[ DPCM(Differencial PCM) 방식 ]

우리의 음성 파형을 실제로 보면, 서로 인접한 샘플링 시점의 비교에서파형이 크게 변하지 않는다. 이점에 착안하여 만든 방식이 DPCM 방식이

다. DPCM 방식은 개선된 PCM 방식이라 할 수 있다. 즉,  PCM 방식은 파고 값을 그대로 저장하지만 DPCM  방식은 이전의 값과의 차이만을 저장

하는 것이다.  음성의 파형이 크게 변하지 않으므로 차이값도 작아져서 bit-rate를 낮출 수 있다.

[ ADPCM(Adaptive Differencial PCM) 방식 ]

ADPCM 방식은 위의 여러 가지 방식의 단점을 보완한 것이다. DM 방식이나 DPCM 방식은 압축된 비트수로 표현 되는 최대의 변화량이 실제 파형

의 변화량보다 작기 때문에 실제로 구현하면 재생 파형이 원 파형의 급격한 변화를 나타내지 못한다. 이를 막기 위하여 양자화할때 시간 간격

을 작게 하면 bit-rate를 증가시키는 결과를 가져오게 된다.ADPCM 방식은 파형의 변화량이 급격히 변할 때는 양자화 할 때의 단위를 크게하여

차분값을 이용하는 것으로 파형의 진폭이 클경우 약간의 잡음이 있어도 사람이 잘 감지하지 못하는 점을 이용한 것이다.


DirectX 9.0 한글판 도움말 ver 4.70 - by dexk


DirectX 9.0 한글판 도움말 입니다.

우선 M$社에 양해 말씀 드리고… 꼭 정식 한글판이 나왔으면 하는 바램이 있습니다.

부족한 점이 많지만 조금이나마 도움이 되었으면 합니다.

그럼. 멋찐 게임 제작 하시길...


홈페이지: http://www.spirit3d.net/

이메일 : dx-kor@hanmail.net



참고로 저와 이 사이트 운영자는 아무런 관계가 없고
다만 제 개인 홈페이지가 없어서 얹혀서 살고 있습니다.
개인적으로 무척 좋은 사이트라고 생각 합니다.
좋은 글들 있으면 꼭 올려 주시기 바랍니다.

칠복님의 도움으로 CHI 화일을 만들수 있게 되었습니다.
MSDNIntegrator.exe 실행화일을 사용해서 비주얼 스튜디오 6.0에
DX9.0 한글판 도움말을 추가 할수 있습니다.
삭제 할때는 추가 할때 사용한 GUID 사용 하시면됩니다.
그러니 추가 할때 사용한 GUID 를 꼭 보관하세요.
다른 방법으로도 삭제 할수 있으나 번거롭습니다.
그냥 추가 하거나 삭제 할때 아래의 GUID를 사용하세요.
{65250D7F-8992-4c9e-9703-395AAE86F427}

버전 업데이트 제작에 도움 주신 분들


spirit3d 운영자님들
( 3d 관련 문서 공유 도우미
소망 : 이세상의 모든 문서를 모울때 까지 살고 싶다.
http://www.spirit3d.net/ )

어벙벙 님
( 알려진 정보 없음...
성격 : 어색한 부분은 고쳐야 직성이 풀림
신조 : 눈에 거슬리는 것들은 내게 맏겨라
마인드 : 한글 문서가 나올 그날까지 투쟁 하리라! )

류광 님
( 게임 원서 번역의 지존
요즘 : 하도 번역하니 이제 번역하는 것도 지겹다.
http://gpgstudy.com/ )

칠복이 님
( CHI 화일 만드는 법은 hhp 화일에 [OPTIONS]에 아래와 같이 추가 하면된다!
☞ Create CHI file=Yes ☜
yakswa@hanmail.net )

기타... 게시판의 제보자님들...
(짝퉁 한글 도움말? 너 딱 걸렸어! 캬캬캬
http://www.spirit3d.net/cgi/ez2000/ezboard.cgi?db=freeboard )

그리고 헤더 파일이 있는 곳입니다.


참고 하시길...


http://clootie.narod.ru/delphi/download_dx92.html


페이지 내용입니다.

첨부 파일에 일부 다운로드 가능한 예제 파일들 있습니다.

그리고 다음글에 같이 연속해서 올립니다.

걍 나둘라했는데, 다운로드 속도가 장난 아니게 느리더라구요 ㅡ,.ㅡ;;



Currently DirectX 9.0 Software Development Kit Update (April 2005) is supported

Move to desired DirectX SDK part:

NOTE!
All source code and additional files located on this page
can also be downloaded from SourceForge!

  Either directly from CVS repositary or from File Release Page  


Info field below contains Name / Date / Size with links to file and description field contains some notes about sample and screenshot from run-time.

DirectX headers and libraries

Info Description
Clootie_DirectX92.exe
(WinRAR SFX archive)

08-May-2005
642Kb
Delphi headers adaptation followed by Borland and JEDI standarts for all (up to 9.0 from April 2005 DirectX SDK update) versions of DirectDraw, Direct3D, DirectInput, DirectSound, DirectMusic; DirectPlay8 (updated to DirectX9); D3DX 9.0 headers with support library; dxerr9 (DirectX 9.x error reporting) headers with support library. In this file you'll find JEDI compliant version and preprocessed versions of headers for Delphi 4/5, Delphi 6/7 and Delphi 2005. Also this archive contains simple example of Direct3D8 program.
This package DOES NOT include helper libraries: D3DX or DXErr - error reporting (DXErr9ab.dll).

Download it.
Subset of previous translation. Includes only PAS files compatible with JEDI standarts from Clootie_DirectX92.exe.

Download it.
Clootie_DX92_dlls.zip

08-May-2005
1,230Kb
DLLs needed for both Delphi and C++ Builder, to use D3DX 9.0 functionality from April 2005 DirectX SDK Update and/or DXErr (DirectX error reporting) in your projects or compile Microsoft demos: D3DX9_25.dll, DXErr9ab.dll. Note: D3DX9_25.dll is included in this package only for testing on developer system, not for redistribution.

Download it.
d3dx9_24_dll.zip

08-May-2005
980Kb
For compatibility with previous releases of Delphi DirectX SDK's I'm providing here d3dx9_24.dll compatible with February 2005 DirectX 9.0 SDK Update. DLL included in this package is only for testing on developer system, not for redistribution.
Note: this DLL provided only for compatibility and not required by current Delphi DirectX SDK. You need to download it only if you have application specially requiring it at startup.

Download it.
Clootie_D3DX92ab.zip

20-Feb-2005
1,044Kb
For compatibility with previous releases of Delphi DirectX SDK's I'm providing here D3DX92ab.dll compatible with December 2004 SDK Update D3DX9 library.
Note: this DLL provided only for compatibility and not required by current Delphi DirectX SDK. You need to download it only if you have application specially requiring it at startup.

Download it.
Also here you can find DirectX libraries required for compiling DirectX 9.0 applications with C++ Builder.

Direct3D examples from DirectX SDK

Notes: All examples can be compiled either in Delphi or FreePascal. Please read "How to compile ObjectPascal DirectX examples" page containing instructions how to compile examples in either compiler.

Info Description
Common.zip

09-May-2005
241Kb



Free Pascal compatible
Translated Direct3D Sample Framework - used by all Direct3D examples.
Includes: DXUT, DXUTcore, DXUTEnum, DXUTgui, DXUTmesh, DXUTmisc, DXUTSettingsDlg files.
Also DDUtil unit (DirectDraw utilities) is included - initially converted by Dominique Louis.

Download it.
SDKMedia.zip

12-Sep-2004
11,4 Mb




Media files from DirectX 9.0 October 2004 SDK
- these are required in some amount by all Direct3D examples.

At least all samples require "skin" texture for GUI! If you don't want to download all media files you should at least download
CustomUI sample containing above mentioned texture.


Download media files from SourceForge.
WARNING!
All Direct3D samples require
Direct3D Sample Framework to compile!

In addition to D3DFramework it’s recommended to download Media files from SDK or most of samples will not work or miss artwork!

Links to both items you can find just above -
Common.zip, SDK_Media.zip.
AntiAlias.zip

09-May-2005
779Kb















Free Pascal compatible
AntiAlias image Multisampling attempts to reduce aliasing by mimicking a higher resolution display using multiple sample points to determine each pixel's color. The Antialias sample shows how the various multisampling techniques supported by your video card affect the scene's rendering. Although multisampling effectively combats aliasing, under particular situations it can introduce visual artifacts of its own. As illustrated by the sample, centroid sampling seeks to eliminate one common type of multisampling artifact. Support for centroid sampling is supported by the pixel shader 2.0 model and later. Note: actually centroid sampling is supported by ATi R3xx (Radeon 9500 or later), R4xx (X800 series) and NVIDIA N4x (GeForce 6x00 series).

Download it (archive contains source, EXE, media files).
BasicHLSL.zip

09-May-2005
166Kb








Free Pascal compatible
BasicHLSL image The BasicHLSL sample simply loads a mesh, creates an effect from a file, and then uses the effect to render the mesh. The effect that is used is a simple vertex shader that animates the vertices based on time.

Download it (archive contains source, EXE, some media files).
Blobs.zip

09-May-2005
168Kb











Free Pascal compatible
Blobs image The Blobs sample mimics a metaball effect in screen space using a pixel shader. True metaball techniques deform surfaces according to pushing or pulling modifiers, and are commonly used to model liquid effects like the merging of water droplets. Metaball effects can be computationally expensive, however, so this sample implements a 3-D metaball effect in 2-D image space with a pixel shader.

Download it (archive contains source, EXE, some media files).
CompiledEffect.zip

09-May-2005
164Kb








Free Pascal compatible
CompiledEffect image The CompiledEffect sample shows how an ID3DXEffect object can be compiled when the project is built and loaded directly as a binary file at run time. This sample can be treaded like BasicHLSL modified to use precompiled EffectFile.

Download it (archive contains source, EXE, media files).
CustomUI.zip

09-May-2005
185Kb















Free Pascal compatible
CustomUI image The CustomUI sample is a simple demonstration of the UI subsystem implemented by the Microsoft Direct3D sample framework. The sample framework provides code and infrastructure common to most Microsoft DirectX applications. One area of the framework is user interface support. The sample framework contains commonly used control objects, such as buttons and check boxes, that both windowed and full screen Direct3D applications can use to implement their user interfaces.
Most notably GUI subsystem of D3DFramework implements edit controls event with IME!!! So, your new applications will be easily localized even for Chineese users!

Download it (archive contains source, EXE, some media files).
DepthOfField.zip

09-May-2005
170Kb












Free Pascal compatible
DepthOfField image The DepthOfField sample shows several techniques for creating a depth-of-field effect in which objects are only in focus at a given distance from the camera and out of focus at other distances. Rendering objects out of focus adds realism to the scene. The methods it shows are reasonably cheap to perform on most hardware, and the depth of field post processing can easily be combined with other post process techniques such as image-based motion blur or high dynamic range (HDR) lighting.

Download it (archive contains source, EXE, media files).
EffectParam.zip

09-May-2005
1,815Kb














Free Pascal compatible
EffectParam image The EffectParam sample demonstrates two D3DX effect system features: parameter blocks and parameter sharing (see Sharing Effect Parameters and Use Parameter Blocks to Manage Effect Parameters). Parameter blocks group multiple Setxxx application programming interface (API) calls and associate them with an effect handle. An application can then use the parameter block to make all those state changes with a single API call. Parameter sharing synchronizes parameters in multiple effects; each time an application updates a parameter in one effect, that parameter is updated in all the other shared effects.

Download it (archive contains source, EXE, some media files).
EmptyProject.zip

09-May-2005
157Kb








Free Pascal compatible
EmptyProject image The EmptyProject is a bare-bones Direct3D application provided as a convenient starting point for your own project. It's already contains rich set UI elements.

Download it (archive contains source, EXE, some media files).
EnhancedMesh.zip

09-May-2005
163Kb











Free Pascal compatible
EnhancedMesh image The EnhancedMesh Sample demonstrates mesh tessellation in Microsoft Direct3D. Mesh tessellation subdivides mesh triangles. This produces a mesh with finer geometry details which can produce better lighting results even with per-vertex lighting. Mesh tessellation is often used to implement a level of detail (LOD) technique where meshes closer to the viewer are rendered with more details, and meshes further away are rendered with less detail.

Download it (archive contains source, EXE, some media files).
FragmentLinker.zip

09-May-2005
160Kb










Free Pascal compatible
FragmentLinker image The FragmentLinker sample shows how to use the ID3DXFragmentLinker interface. Shader source code can be split into a series of shader fragments, which are compiled separately and linked together to form a complete shader. This linking stage is very efficient, making it suitable for run-time use. In this way a Microsoft Direct3D application can custom-build an appropriate shader for the current graphics card.

Download it (archive contains source, EXE, some media files).
HLSLWithoutEffects.zip

09-May-2005
161Kb












Free Pascal compatible
HLSLWithoutEffects image The HLSLwithoutEffects sample demonstrates using high-level shader language (HLSL) to write vertex shaders without using the D3DX effect interfaces. HLSL is a language that closely resembles C syntax and constructs. By writing shaders in HLSL instead of assembly language, developers can take advantage of not only the features and elements of the language they are already familiar with, but also the great optimization capabilities offered by the D3DX shader compiler.

Download it (archive contains source, EXE, some media files).
Instancing.zip

09-May-2005
171Kb











Free Pascal compatible
Instancing image The Instancing sample demonstrates the instancing feature available with Microsoft DirectX 9.0c. A vs_3_0 device is required for this feature. The sample also shows alternate ways of achieving results similar to hardware instancing, but for adapters that do not support vs_3_0. The shader instancing technique shows the benefits of efficient batching of primitives.
Note: On graphics hardware that does not support vs_2_0, the sample will run as a reference device.

Download it (archive contains source, EXE, some media files).
MeshFromOBJ.zip

09-May-2005
224Kb









Free Pascal compatible
MeshFromOBJ image The MeshFromOBJ sample shows how an ID3DXMesh object can be created from mesh data stored in a Wavefront Object file ( .obj). It's convenient to use .x files when working with ID3DXMesh objects since D3DX can create and fill an ID3DXMesh object directly from a .x file. It's also easy to initialize an ID3DXMesh object with data gathered from any file format or memory resource.

Download it (archive contains source, EXE, some media files).
OptimizedMesh.zip

09-May-2005
165Kb








Free Pascal compatible
OptimizedMesh image This OptimizedMesh sample sample demonstrates the different types of meshes D3DX can load and optimize, as well as the different types of underlying primitives it can render. An optimized mesh has its vertices and faces reordered so that rendering performance can be improved.

Download it (archive contains source, EXE, some media files).
ProgressiveMesh.zip

09-May-2005
163Kb











Free Pascal compatible
ProgressiveMesh image This ProgressiveMesh sample shows how an application can use the D3DX progressive mesh functionality to simplify meshes for faster rendering. A progressive mesh is a specialized mesh object that can increase or decrease its geometry complexity, thereby providing flexibility when drawing the mesh so that performance can be maintained at a steady level. This feature is useful when providing level of detail (LOD) support in an application.

Download it (archive contains source, EXE, some media files).
ShadowMap.zip

09-May-2005
349Kb
















Free Pascal compatible
ShadowMap image The ShadowMap sample demonstrates one popular shadowing technique called shadow mapping. A shadow map (in the form of a floating-point texture) is written with the scene's depth information with the camera placed at the light's position. Once generated, the shadow map is projected onto the scene during rendering. The depth values in the scene are compared with those in the shadow map. If they do not match for a particular pixel, then that pixel is in shadow. Shadow mapping is a very efficient real-time shadow casting technique.
Note: This sample requires ps_2_0 which supports floating-point textures. On cards that do not support ps_2_0, the sample will revert to a reference device which will degrade performance, but is useful for verifying functionality.

Download it (archive contains source, EXE, some media files).
ShadowVolume.zip

09-May-2005
180Kb











Free Pascal compatible
ShadowVolume image The ShadowVolume sample demonstrates one common technique for rendering real-time shadows called shadow volumes. The shadows in the sample work by extruding faces of the occluding geometry (that are facing away from light) to form a volume that represents the shadowed area in 3D space. The stencil buffer is used as a mask for rendering additional geometry, and is updated as geometry is rendered.

Download it (archive contains source, EXE, some media files).
SkinnedMesh.zip

09-May-2005
174Kb









Free Pascal compatible
SkinnedMesh image The SkinnedMesh sample illustrates mesh animation with skinning using D3DX. Skinning is an animation technique that takes data organized in a skeletal-mesh hierarchy and applies geometry blending to transform mesh vertices. The geometry blending generates smooth surfaces with fewer artifacts.

Download it (archive contains source, EXE, some media files).
Text3D.zip

09-May-2005
162Kb













Free Pascal compatible
Text3D image The Text3D sample uses ID3DXFont to display 2D text in a 3D scene. This is most useful for display stats, in game menus, etc... Note: ID3DXFont support UNICODE character rendering, so sample demostrates rendering of Japanese text (you should have installed Asian languages support to see them).
The sample also shows how to use D3DXCreateText() to create a D3DX mesh containing a 3D model of a text string. Note that D3DXCreateText may not work with certain types of fonts, such as bitmap fonts and some symbol fonts.

Download it (archive contains source, EXE, some media files).

Miscellaneous examples [Misc folder] from DirectX SDK

Info Description
GetDXVer.zip

09-May-2005
81Kb

Free Pascal compatible
Demonstrates how applications can detect what version of DirectX is installed. Support every version up to and including DirectX 9.0c.

Download it (archive contains source and excutable).

DirectDraw examples from DirectX SDK

Info Description
All_DirectDraw.zip

12-Dec-2002
225Kb
These are DirectX 8.1 SDK DirectDraw examples. Note: MS is already not including any DirectDraw examples with DirectX 9 SDK!

Translated Sample DirectDraw samples - this archive contains most of DirectDraw samples from DirectX 8.x SDK, originally produced as part of DirectXExamples effort: AnimatePalette, DDEnum, DirectSurfaceWrite, FullScreenDialog, FullScreenMode, GammaControl, OverlayAnimate, RefreshRate, SpriteAnimate, SwitchScreenMode, WindowedMode. Also DDUtil.pas helper unit can be found in archive too.
NOTE: these samples are not supported and/or maintained by me.

Download them locally.
Download them from Yahoo Groups.


1. 컨트롤
  가. 컨트롤(control)이란 사용자와의 인터페이스를 이루는 도구 (사용자로부터 명령과 입력을 받아들이고
    출력 결과를 보여준다, 즉 입출력 도구)
  나. 프로그램은 실행중에 끊임없이 사용자와 통신을 하는데 컨트롤을 통해 명령과 정보를 받아들이고
    또한 컨트롤을 통해 실행 결과를 사용자에게 보고한다.
  다. 컨트롤도 하나의 윈도우이다. 화면상의 일정한 영역을 차지하며 자신의 고유 메시지를 처리할 수
    있는 능력을 가지고 있으며 차일드 윈도우로 존재한다. 윈도우를 만들 때는 WNDCLASS형의 구조체를
    정의하고 RegisterClass함수로 등록한 후 CreateWindow 함수를 호출한다. 그러나 컨트롤은 윈도우즈가
    운영체제 차원에서 제공하기 때문에 윈도우 클래스를 등록할 필요없이 미리 등록되어 있는 윈도우 클래스를
    사용하기만 하면 된다. 미리 정의된 윈도우 클래스에는 다음과 같은 종류가 있다
  라. 윈도우 클래스의 종류
    윈도우 클래스         |           컨트롤
    ----------------------------------
    button                   |    버튼, 체크, 라디오
    static                   |    텍스트
    scrollbar               |    스크롤바
    edit                      |    에디트
    listbox                   |    리스트 박스
    combobox             |    콤보 박스
  마. 윈도우 클래스들은 시스템 부팅시에 운영체제에 의해 등록되므로 윈도우 클래스를 따로 등록할 필요없이
    CreateWindow함수의 첫 번째 인수로 클래스 이름만 주면 해당 컨트롤을 만들수 있다.

2. button
  가. CreateWindow(TEXT("button"), TEXT("Click Me"), WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
    20, 20, 100, 25, hWnd, (HMENU)0, g_hInst, NULL);
  == CreateWindow(만들고자 하는 윈도우의 클래스, 캡션, 스타일,
    위치, x위치, y위치, 폭, 높이, 부모 윈도우, 핸들, 부모윈도우 인스턴스 핸들, 사용자정의데이터);
  나. 스타일
    스타일                                           설명
    ------------------------------------------------------------------------------
    BS_PUSHBUTTON                           푸시 버튼
    BS_DEFPUSHBUTTON                     디폴트 푸시 버튼
    BS_CHECKBOX                               체크 박스
    BS_3STATE                                   3가지 상태를 가지는 체크 박스
    BS_AUTOCHECKBOX                       자동 체크 박스
    BS_AUTO3STATE                           3가지 상태를 가지는 자동 체크 박스
    BS_RADIOBUTTON                           라디오 버튼
    BS_AUTORADIOBUTTON                   자동 라디오 버튼
    BS_GROUPBOX                             그룹 박스
  다. 부모와의 통신
    1) 버튼을 클릭할 경우 WM_COMMAND 메시지를 부모 윈도우에게 보내며 이때 전달되는 정보는
      인수                 설명
      --------------------------
      HIWORD(wParam)        통지코드(왜 메시지를 보냈는가를 나타내는 값)
      LOWORD(wParam)       컨트롤의 ID (아홉번째 인수)
      lParam                        메시지를 보낸 차일드 윈도우의 윈도우 핸들
    2) 부모 윈도우는 WM_COMMAND에서 LOWORD(wParam)값을 조사하여 어떤 컨트롤이 눌러졌는지에
      따라 적절한 처리를 한다. WM_COMMAND 메시지는 컨트롤의 통지 메시지뿐만 아니라 메뉴항목,
      엑셀러레이터 등의 명령을 처리하는 중요한 일을 한다. 이름 그대로 버튼을 누르거나, 메뉴를 선택하거나
      엑셀러레이터를 누르는 등 사용자로부터의 명령이 될 만한 것들을 모두 처리한다. 이때 컨트롤의 ID, 메뉴 ID
      엑셀러레이터 ID등은 모두 LOWORD(WPARAM)으로 전달되므로 이 세가지 명령들끼리는 0~65535까지의
      범위에서 상호 중복되지 않는 ID를 가져야한다.
      가) 일반적인 메세지 처리 루틴
        case WM_COMMAND:
          switch( LOWORD(wParam) )     // ID에 따른 분기
             case 메뉴 1: 처리 1; break;
             case 메뉴 2: 처리 2; break;
             case 엑셀러레이터 1: 처리 3; break;
             case 컨트롤 1:
               switch( HIWORD(wParam) )       // 통지 코드에 따른 분기
                 case 통지코드 1: 처리 1; break;
                 case 통지코드 2: 처리 2; break;

3. 체크 박스
  가. 푸시 버튼은 사용자로부터 명령을 받아들이기 위해 사용하는데 비해 체크 박스는 참, 거짓의 진위적인
    선택을 입력받을 때 주로 사용된다. 체크 박스도 푸시버튼과 마찬가지로 차일드 윈도우이며 스타일에
    따라 4가지 종류의 체크박스가 있다.  우선 선택 가능한 옵션의 개수에 따라 두가지 상태를 가지는
    체크박스와 세가지상태를 가지는 체크 박스로 구분된다. 또한 동작 방법에 따라 자동 체크 박스와
    수동 체크 박스로 나누어지는데 수동 체크 박스는 선택/비선택 상태를 부모 윈도우가 직접 바꾸어야
    하며 자동 체크 박스는 스스로 체크 상태를 바꾼다.자동 체크 박스는 별도의 코드를 작성하지 않아도
    체크 상태를 자동으로 토글할 수 있는 장점이 있기는 하지만 체크 상태를 결정하기 위해 좀 더 복잡한
    조건을 점검하기에는 어울리지 않는다.
  나. 컨트롤의 메시지
    1) 체크 박스는 사용자가 마우스로 클릭할 때마다 부모 윈도우로 BN_CLICKED 메시지를 보낸다. 컨트롤이
      부모 윈도우로 보내는 통지 메시지와는 달리 부모 윈도우가 체크 박스의 상태를 알아보거나 상태를
      바꾸고자 할 때도 차일드 윈도우로 메시지를 보낸다. 통지 메시지는 차일드가 부모로 보내는 보고 메시지이고
      그냥 메시지는 부모가 차일드에게 어떤 지시를 내리기 위해 보내는 명령이다. 메시지의 종류는 컨트롤마다
      다르다.
      메시지              설명
      -----------------------------------
      BM_GETCHECK   체크 박스가 현재 체크되어 있는 상태를 조사하며 wParam, lParam은 사용하지 않는다.
                               체크 상태는 리턴값으로 돌려진다.
      BM_SETCHECK  체크 박스의 체크 상태를 변경하며 wParam에 변경할 체크 상태를 지정한다.

      BM_GETCHECK에 의해 리턴되는 값, BM_SETCHECK에 의해 설정되는 체크박스의 상태
      상수                             값          의미
      BM_UNCHECKED           0           현재 체크되어 있지 않다.
      BM_CHECKED               0           현재 체크되어 않다.
      BM_INDETERMINATE      0          체크도 아니고 안 체크도 아닌 상태
                            <------ BN_CLICKED : 클릭되었음 -------------
      부모 윈도우       ------ BM_GETCHECK : 체크 상태 질문 ------->     체크 박스
                             ------ BM_SETCHECK : 체크 상태 변경 ------->

4. 라디오 버튼
  가. BS_RADIOBUTTON, BS_AUTORADIOBUTTON 둘 중 하나의 스타일을 지정하면 라디오 버튼이 되며
    체크 박스와 마찬가지로 수동, 자동의 두가지 종류가 있으며 라디오 버튼이 체크 상태를 스스로 변경
    하는 그렇지 않은가의 차이가 있다. 수동 라디오 버튼이 필요한 상황은 사실상 거의 없으며 대개의
    경우는 자동 라디오 버튼으로 충분하다. 하나의 선택 사항에 대해 여러 개의 라디오 버튼들이
    그룹을 이루어 사용된다는 특징이 있다. 같은 그룹에 속한 라디오 버튼은 오직 하나만 선택 가능
  나. 라디오 버튼의 그룹을 구성하는 방법은 간단하다. 그룹을 이루는 첫 번째 라디오 버튼에만 WS_GROUP
    스타일을 주고 나머지 라디오 버튼은 WS_GROUP 스타일을 주지 않으면 된다. 최초로 WS_GROUP을 가지는
    라디오 버튼부터 다음 WS_GROUP 스타일을 가지는 라디오 버튼 직전까지가 한 그룹이 된다.

5. 에디트
  가. EDIT 윈도우 클래스로부터 생성하며 CREATEWINDOW 함수로 스타일 인수로 지정하면 된다.
    부모 윈도우는 이 메시지를 받았을 때 적절한 처리를 하면 된다.EN_CHANGE 문자열이 변경되었다.
     EN_KILLFOCUS, EN_SETFOCUS 포커스를 잃고 얻었을 때의 메시지가 있다.
  나. 컨트롤도 윈도우와 동격이다. 일단 화면상의 사각영역을 차지한다는 점에 있어서 윈도우와 같은데
    메인 윈도우의 차일드로 존재하며 타이틀 바가 없기 때문에 사용자가 직접 이동시킬 수 없을 뿐이다.
    또한 윈도우처럼 스타일을 가지며 만들 때 지정한 스타일에 따라 모양이나 기능이 달라진다.
    컨트롤이 윈도우라느 결정적인 증거는 스스로 메시지를 처리할 수 있는 능력을 가진다는 점이다.
    버틍을 마우스로 누르면 쑥 들어가는 모양으로 바뀌고 에디트는 키보드 입력을 받으면 문자열을 조립하여
    보여준다. eH한 WM_PAINT 메시지를 처리하기 때문에 스스로 자신을 복구(REPAIR)할 수 있고 부모윈도우가
    메시지를 보내면 그 메시지를 처리한다. 체크 박스는 BM_SETCHECK 메시지를 받으면 WPARAM값에 따라
    자신의 체크 상태를 스스로 변경한다.

6. 리스트 박스
  가. 리스트 박스는 선택 가능한 여러 개의 항목들을 나열해 놓고 그 중 하나(또는 여러개)를 선택하는 컨트롤
    이며 여기서 항목이란 주로 문자열이다. 리스트 박스도 일종의 윈도우이며 "listbox"라는 윈도우 클래스로
    생성한다. 차일드 컨트롤로 생성하는 것이 보통이므로 WS_CHILD|WS_VISIBLE 스타일은 기본적으로 지정
    해야 하며 이 외에 다음과 같은 여러 가지 고유의 스타일을 지정할 수 있다. 어떤 스타일을 지정하는가에
    따라 리스트박스와 모양과 동작이 달라진다.
    스타일                      설명
    LBS_MULIPLESEL    여러개의 항목을 선택 가능, 적용하지 않으면 디폴트로 하나의 선택만 가능
    LBS_NOTIFY             사용자가 목록중 하나를 선택했을 때 부모 윈도우로 통지 메시지를 보낸다.
    LBS_SORT                추가된 항목들을 자동 정렬한다.
    LBS_OWNERDRAW     문자열이 아닌 비트맵이나 그림을 넣을 수 있다..
    LBS_STANDARD        LBS_NOTIFY|LBS_SORT|WS_BORDER
  나. 부모 윈도우로 통지 메시지를 보내는 것이 일반적이르모 LBS_NOTIFY 스타일은 거의 필수적으로 선택
    하는 것이 좋으며 그 외는 필요할 때 선택하면 된다. 부모 윈도우가 리스트 박스를 조작하고자 할때는
    리스트 박스 메시지를 사용한다.
    메시지                      설명
    LB_ADDSTRING         리스트 박스에 항목을 추가 LPARAM으로 추가하고자 하는 문자열의 번지를 넘겨줌
    LB_DELETESTRING    항목을 삭제, WPARAM으로 항목의 번호를 넘겨주면 남은 항목수를 리턴
    LB_GETCURSEL        현재 선택된 항목의 번호를 조사
    LB_GETTEXT            지정한 항목의 문자열을 읽는다. WPARAM에 항목번호, LPARAM에 문자열
    LB_GETCOUNT         항목의 개수를 조사한다.
    LB_SETCURSEL        WPARAM이 지정한 항목을 선택한다
   다. 리스트 박스에서 어떤 사건이 발생했을 때 부모 윈도우로 다음과 같은 통지 메시지를 보낸다.
    메시지                      설명
    LBN_DBLCLK            리스트 박스를 더블 클릭하였다.
    LBN_ERRSPACE       메모리가 부족하다
    LBN_KILLFOCUS       키보드 포커스를 잃었다.
    LBN_SELCANCEL     사용자가 선택을 취소하였다
    LBN_SELCHANGE     사용자에 의해 선택이 변경되었다.
    LBN_SETFOCUS        키보드 포커스를 얻었다.
    자주 사용되는 통지 메시지는 선택이 변경될 때 보내지는 LBN_SELCHANGE이다

7. 콤보 박스
  가. 에디트컨트롤과 리스트 박스를 결합이다. 그래서 목록에 있는 항목중의 하나를 선택할 수도 있고 원하는
    항목이 없을 경우 에디트에 직접 입력해 넣을 수도 있다. combobox 윈도우 클래스를 사용하며 세 가지
    종류가 있는데 스타일로 원하는 종류를 선택
    스타일                        설명
    CBS_SIMPLE              에디트와 리스트 박스를 가지되 리스트 박스가 항상 펼쳐져 있다.
    CBS_DROPDOWN         에디트와 리스트 박스를 가진다.
    CBS_DROPDOWNLIST    리스트 박스만 가지며 에디트에 항목을 입력할 수는 없다.

8. 스크롤 바
  가. 비교적 복잡한 컨트롤로 윈도우의 스크롤 상태를 고나리하기 위해 사용하기도 하며 일정 범위에 있는 값을
    대충 선택할 때도 사용한다. scrollbar 위노우 클래스로 생성하며 수평 스크롤 바일경우 SBS_HORZ 스타일을
    수직 스크롤 일때는 SBS_VERT 스타일을 지정한다.
    BOOL SetScrollRange(HWND hWnd, int nBar, int nMinPos, int nMaxPos, BOOL bRedraw);
    (스크롤 바 윈도우 핸들, 표준 또는 별도 스크롤바를 지정하는 값, 최대값, 최소값, ?)
    int SetScrollPos(HWND hWnd, int nBar, int nPos, BOOL bRedraw);
    (?, ?, 현재 위치, ?);
  나. 다른 컨트롤은 WM_COMMAND로 통지메시지를 보내는데 스크롤 바는 WM_HSCROLL, WM_VSCROLL
    이라는 별도의 메시지를 부모 윈도우로 보낸다.
    인수                              설명
    LOWORD(WPARAM)        스크롤 바 내의 어디를 눌렀는가?
    HIWORD(WPARAM)          현재 위치
    LPARAM                          스크롤 바의 윈도우 핸들
  다. LOWORD(WPARAM)으로 전달되는 값은 사용자의 스크로로 요구사항을 나타냄
    값                                                 설명
    SB_LINELEFT, SB_LINEUP               사용자가 왼쪽 화살표를 눌렀음
    SB_LINERIGHT, SB_LINEDOWN         사용자가 오른쪽 화살표를 눌렀음
    SB_PAGELEFT, SB_PAGEUP            사용자가 왼쪽 몸통을 눌렀음
    SB_PAGERIGHT, SB_PAGEDOWN      사용자가 오른쪽 몸통을 눌렀음
    SB_THUMBPOSITION                       스크롤 박스를 드래그한 후 마우스 버튼을 놓았다.
    SB_THUMBTRACK                           스크롤 박스를 드래그하고 있는 중 마우스버튼 놓을때까지 계속 전달

9. 스태틱
  가. 입력은 없고 오로지 문자열만 보여줌 WM_CREATE에서 스태틱 컨트롤을 만들기만 할 뿐 그외의 코드는
    작성할 필요가 없다. 스태틱 컨트롤은 실행중에 부모 윈도우로 통지 메시지를 보낼 필요가 없기 때문에 ID를
    -1로 지정하며 여러개의 스태틱 컨트롤이 있을 모든 경우도 -1의 같은 ID를 사용해도 된다. -1은 ID를 주지
    않는다는 뜻이며 더 이상 컨트롤을 프로그래밍할 필요가 없을 때 사용된다. 물론 필요하면 줄수도 있다.
  나. TextOut으로 출력한 문자열과는 달리 스태틱 컨트롤은 스스로 메시지를 처리할 수 있는 윈도우이기 때문에
    배치해 놓기만 하면 WM_PAINT와 같은 통지 메시지로 복구할 필요가 없다. 또한 색상, 글꼴 크기 등
    운영체제의 세팅이 바뀔 경우 이런 변화에 대해서도 스스로 대처한다는 장점이 있다.
 

C++ 프리프로세서 명령

16.1 서론

16.2 C++ 프리프로세서

16.3 파일의 include

16.4 단순한 문자열 치환

16.5 인수 없는 매크로

16.6 인수 있는 매크로

16.7 매크로 정의 해체

16.8 조건 컴파일러

16.9 #pragma

16.10 정리


 ◈ 16.2 C++프리프로세서

-C++프리프로세서 명령의 규칙은 C와 동일

-프리프로세서는 컴파일러에 넘겨주시 전에 프로그램의 소스 코드를 처리하는 프로그램이다.

-프리프로세서 명령은 기호 #이 앞에 놓여지고 프리프로세서 제어행이라고 부름.

-제어행의 내용에 따라 하나 또는 그 이상의 기능을 실행함.


■파일의 include

-다음이 있으면 파일이 include됨

 

 

 

 

#include

 

 

 


■문자열의 치환, 매크로 전개나 정의해제

-문자열의 치환, 매크로 전개나 정의해제 기능은, 다음의 명령으로 구현됨

 

 

 

 

#define 

#undef

 

 

 



■조건 컴파일의 명령

-조건 컴파일은, 다음의 제어행을 조합해서 구현됨

 

 

 

 

#if 

#else 

#endif 

#if 

#elif 

#endif 

#ifdef 

#endif 

#ifndef 

#endif

 

 

 


■디버그 작업의 보조

-다음의 제어행은 디버그를 지원함.

 

 

 

 

#pragma

 

 

 



 ◈ 16.3 파일의 include(1)


 

 

 

 

// test16_1.cpp//오류발생

//#include <iostream.h>

//#include <stdio.h>

void main(void)

{ 

  cout <<"Hi there ! \n";

        printf  ( "Hi there again ! \n");

}

 

 

 

-오류 매시지

 

 

 

 

error C2065: 'cout' : undeclared identifier

error C2297: '<<' : illegal, right operand has type 'char [13]'

error C2065: 'printf' : undeclared identifier

 

 

 


 ◈ 16.3 파일의 include(2)

 

 

 

 

// test16_2.cpp

#include <iostream.h>

#include <stdio.h>

void main(void)

{ 

  cout <<"Hi there ! \n";

        printf  ( "Hi there again ! \n");

}

 

 

 

-실행 결과

 

 

 

 

Hi there !

Hi there again !

 

 

 


-#include 명령은 컴파일 시에 명령 뒤에 있는 파일명의 모든 내용을 include함.

-헤더 파일 iostream.h는 cout의 정의를, stdio.h는 printf()의 정의를 포함


-#include 명령의 3가지 형식

■#include <filename>

 ∙<>괄호 안의 파일명은 컴파일러에게 현재의 작업 디렉토리 이외의 미리 준비된 디렉토리(표준 디렉토리)의 리스트로부터 그 파일을 찾도록 지시


■#include “filename”

∙컴파일러에게 현재의 작업 디렉토리 내에서 그 파일을 찾도록 지시


■#include “c:\wkspace\kdhong\"filename”

∙컴파일러에게 지정된 경로 내에서 그 파일을 찾도록 지시, 그 디렉토리에서 발견되지 않으면 표준 디렉토리를 찾음.

 

 

 

 

// test_16.3 cpp

#include <iostream.h>            // cout 에 필요

#include <stdio.h>              // printf()에 필요

#include "D:\Lecture2K-2\C++\nykwak.h"

void main(void)

{ 

        cout <<"Hi there ! \n";

        printf  ( "Hi there again ! \n");

        cout <<"a from nykwak.h is " <<a <<"\n";

}

 

 

 

-가령, D:\Lecture2K-2\C++\nykwak.h에 int a = 5;라는 선언문이 삽입되어 있을 경우, 실행 결과는, 다음과 같다.

 

 

 

 

Hi there !

Hi there again !

a from nykwak.h is 5

 

 

 


 ◈ 16.3 파일의 include(3)

 

 

 

 

// test_16.4 cpp//오류발생

#include <iostream.h>            // cout 에 필요

#include <stdio.h>              // printf()에 필요

#include "D:\Lecture2K-2\C++\kdhong.h"

void main(void)

{ 

        cout <<"Hi there ! \n";

        printf  ( "Hi there again ! \n");

        cout <<"a from kdhong.h is " <<a <<"\n";

}

 

 

 

-가령, D:\Lecture2K-2\C++\kdhong.h에

int a = 5

라는 선언문이 삽입되어 있을 경우, 메러 메시지는, 다음과 같다.

 

 

 

 

error C2144: syntax error : missing ';' before type 'void'

fatal error C1004: unexpected end of file found

 

 

 


 ◈ 16.4 단순한 문자열 치환

-일반적으로, #define 제어행을 사용할 때, 대문자를 사용.(그 이유는 프로그램 중에서 #define되는 변수를 쉽게 확인할 수 있기 때문.)

 

 

 

 

// test16_5.cpp//문자열 치환

#include <iostream.h>

#define HELLO "Hi there ! \n"

void main(void)

{ 

        cout <<HELLO ;

} 

 

 

 

-실행 결과

 

 

 

 

Hi there !

 

 

 


 ◈ 16.5 인수 없는 매크로

 

 

 

 

// test16_6.cpp//인수 없는 매크로

#include <iostream.h>         // I/O에 필요

#define SQUARE_TWO 2*2

void main(void)

{ 

        int a;

        a = SQUARE_TWO;

        cout <<"a is " <<a <<"\n";

}

 

 

 

-실행 결과

 

 

 

 

a is 4

 

 

 


-다음 제어행 중,

 

 

 

 

#define SQUARE_TWO 2*2

 

 

 

#define는 제어행으로, SQUARE_TWO는 매크로 템플리트이고, 2*2는 매크로 전개임.

 ◈ 16.6 인수 있는 매크로(1)

 

 

 

 

//test16_7.cpp 

#include <iostream.h>

#define ADD(X) (X+X)

void main(void)

{ 

        int b;

        b = ADD(4);

        cout <<"b is " <<b <<"\n";

}

 

 

 

-실행 결과

 

 

 

 

b is 8

 

 

 



 ◈ 16.6 인수 있는 매크로(2)

 

 

 

 

//test16_8.cpp//오류발생 

#include <iostream.h>

#define ADD (X) (X+X)

void main(void)

{ 

        int b;

        b = ADD(4);

        cout <<"b is " <<b <<"\n";

}

 

 

 

-오류 메시지

 

 

 

 

error C2065: 'X' : undeclared identifier

 

 

 



 ◈ 16.6 인수 있는 매크로(3)

 

 

 

 

//test16_9.cpp//오류발생 

#include <iostream.h>

//매크로명과 파라미터 사이의 괄호가 없는 것에 주의

#define ADD(X) X+X

void main(void)

{ 

        int b;

        b = ADD(4)*5;

        cout <<"b is " <<b <<"\n";

}

 

 

 

-실행 결과

 

 

 

 

b is 24

 

 

 


-test16_9.cpp의 동작 설명

 

 

 

 

 b = ADD(4)*5;

 

 

 

 

 

 

 

 b = 4 + 4 * 5;

 

 

 

와 같이 전개됨.

즉, 곱셈은 덧셈보다 연산우선순위가 빠르기 때문에 다음과 같이 계산됨

 

 

 

 

 b = 4 + (4 * 5);

 

 

 

그러나, 기대했던 것은 다음과 같은 것임.

 

 

 

 

 b = (4 + 4) * 5;

 

 

 

(따라서, 괄호를 생략해서는 안됨)


 ◈ 16.7 매크로 정의 해제

-이미 정의된 (#define) 매크로는 다음과 같은 제어행으로 정의를 해제할 수 있음.


 

 

 

 

#undef

 

 

 


 

 

 

 

// test16_10.cpp//오류발생

#include <iostream.h>

#define FOUR 4

void main(void)

{ 

        int a = FOUR;

        cout <<"a is " <<a <<"\n";

        #undef FOUR

      int b = FOUR;

        cout <<"b is " <<b <<"\n";

} 

 

 

 

-오류 메시지

 

 

 

 

error C2065: 'FOUR' : undeclared identifier

 

 

 


-메크로를 해제하는 이유는, 매크로 명을 필요로 하는 코드 부분만으로 유효 범위를 한정하기 위함.

 ◈ 16.8 조건 컴파일러

-조건 컴파일러는 소스 코드 중의 다음 키워드가 발견되면 수행됨.

 

 

 

 

#if - #else - #endif

#if - #elif  - #endif

#ifdef - #endif

#ifndef - #endif

 

 

 



16.8.1 #if - #else - #endif(1)

-키워드 #if에는 상수식, 코드블록이 이어지고, 그 뒤에 키워드 #endif가 놓여짐.

 

 

 

 

// test16_11a .cpp

#include <iostream.h>         // I/O 에 필요

#define FIVE 5

#define ZERO 0

void main(void)

{ 

       

              #if (FIVE)

                cout <<"FIVE is TRUE, i.e. non-zero \n";

        #else

                cout <<"FIVE is FALSE, i.e. zero \n";

        #endif

        #if (ZERO)

                cout <<"ZERO is TRUE, i.e. non-zero \n";

        #else

                cout <<"ZERO is FALSE, i.e. zero \n";

        #endif

        cout <<"This code is outside the blocks \n";

}

 

 

 

-실행 결과

 

 

 

 

FIVE is TRUE, i.e. non-zero

ZERO is FALSE, i.e. zero

This code is outside the blocks

 

 

 

16.8.1 #if - #else - #endif(2)

 

 

 

 

// test16_11.cpp//MS Visual C++의 경우, 실행되지만 오동작

#include <iostream.h>

void main(void)

{ 

        const int a = 5;

        const int b = 0;

        #if (a)

                cout <<"a is TRUE, i.e. non-zero \n";

        #else

                cout <<"a is FALSE, i.e. zero \n";

        #endif

        #if (b)

                cout <<"b is TRUE, i.e. non-zero \n";

        #else

                cout <<"b is FALSE, i.e. zero \n";

        #endif

       

        cout <<"This code is outside the blocks \n";

}

 

 

 

-실행 결과

 

 

 

 

a is FALSE, i.e. zero

b is FALSE, i.e. zero

This code is outside the blocks

 

 

 



16.8.1 #if - #else - #endif(3)

 

 

 

 

// test16_12.cpp//MS Visual C++의 경우, 실행되지만 오동작

#include <iostream.h>

void main(void)

{ 

        int a = 5;//a와 b는 변수로서 선언되고 있다.

        int b = 0;

        #if (a)

                cout <<"a is TRUE, i.e. non-zero \n";

        #else

                cout <<"a is FALSE, i.e. zero \n";

        #endif

        #if (b)

                cout <<"b is TRUE, i.e. non-zero \n";

        #else

                cout <<"b is FALSE, i.e. zero \n";

        #endif

       

        cout <<"This code is outside the blocks \n";

}

 

 

 

-실행 결과

 

 

 

 

a is FALSE, i.e. zero

b is FALSE, i.e. zero

This code is outside the blocks

 

 

 



16.8.1 #if - #else - #endif(4)


#if-#else-#endif와 정규 if-else-endif 제어 구조의 차이는, 전자에서는 case 평가를 프로그램이 컴파일되기 이전에 한다는 점이다. 테스트 조건 안에 변수를 두어서는 안된다. 왜냐하면, 변수의 값은 실행중에 변할 수도 있기 때문.

16.8.2 #if - #elif - #endif

#if-#elif-#endif는 #if-#else-#endif와 유사

 

 

 

 

// test16_11b.cpp

#include <iostream.h>         // I/O 에 필요

#define FIVE 5

#define ZERO 0

void main(void)

{ 

       

          #if (FIVE)

                cout <<"FIVE is TRUE, i.e. non-zero \n";

        #elif

                cout <<"FIVE is FALSE, i.e. zero \n";

        #endif

        #if (ZERO)

                cout <<"ZERO is TRUE, i.e. non-zero \n";

        #elif(ZERO)

                cout <<"ZERO is FALSE, i.e. zero \n";

        #endif

       

        cout <<"This code is outside the blocks \n";

}

 

 

 


-실행 결과

 

 

 

 

FIVE is TRUE, i.e. non-zero

This code is outside the blocks

 

 

 


16.8.3 #ifdef-#endif

-2개의 제어행 사이의 코드 블록은, 명령의 뒤에 있는 매크로명이 그 앞에 정의되어 있을 때에만 컴파일됨.

 

 

 

 

// test16_14.cpp

#include <iostream.h>

//#define COMPILE

void main(void)

{ 

        #ifdef COMPILE

                cout <<"This code will be compiled \n";

        #endif

} 

 

 

 


-실행 결과

 

 

 

 

 

 

 

 


16.8.4 #ifndef-#endif

-#indef-#endif문의 반대로, 제어행 사이 코드블록은, 매크로 명이 정의되어 있지 않을 때만 컴파일됨.

 

 

 

 

// test16_14.cpp

#include <iostream.h>

#define COMPILE

void main(void)

{ 

        #ifndef COMPILE

                cout <<"This code will be compiled \n";

        #endif

} 

 

 

 


-실행 결과

 

 

 

 

 

 

 

 


 ◈ 16.#pragma

-이 제어행은 컴파일러에 여러 가지 지령을 줄 수 있다. 특수한 지령은 처리계의 독자적인 지령이다.


MSDNdpt의 progma에 대한 설명

Each implementation of C and C++ supports some features unique to its host machine or operating system. Some programs, for instance, need to exercise precise control over the memory areas where data is placed or to control the way certain functions receive parameters. The #pragma directives offer a way for each compiler to offer machine- and operating-system-specific features while retaining overall compatibility with the C and C++ languages. Pragmas are machine- or operating-system-specific by definition, and are usually different for every compiler.


Syntax


#pragma token-string


The token-string is a series of characters that gives a specific compiler instruction and arguments, if any. The number sign (#) must be the first non-white-space character on the line containing the pragma; white-space characters can separate the number sign and the word pragma. Following #pragma, write any text that the translator can parse as preprocessing tokens. The argument to #pragma is subject to macro expansion.


If the compiler finds a pragma it does not recognize, it issues a warning, but compilation continues.


Pragmas can be used in conditional statements, to provide new preprocessor functionality, or to provide implementation-defined information to the compiler. The C and C++ compilers recognize the following pragmas:


alloc_text comment init_seg1 optimize

auto_inline component inline_depth pack

bss_seg data_seg inline_recursion pointers_to_members1

check_stack function intrinsic setlocale

code_seg hdrstop message vtordisp1

const_seg include_alias once warning

1. GDI Object
  GDI 오브젝트는 GDI가 그래픽 출력을 위해 사용하는 도구임과 동시에 사용자가 GDI의 출력을 조장할 수
  이쓴 도구이기도 하다. 원하는 색상과 모양의 모브젝트를 만들고 DC에 선택해 놓으면 이후부터 선택된
  오브젝트의 속성대로 출력

2. GDI 오브젝트를 만들 때 핸들을 발급받으며 선택하거나 삭제할 때는 이 핸들만 가지고 GDI 오브젝트를
  사용 DC가 BeginPaint나 GetDC 함수에 의해 처음 만들어 졌을 때 디폴트로 선택된 GDI 오브젝트는
  아래와 같음
GDI 오브젝트     핸들타입     설명                                디폴트
펜                    HPEN         선을 그을 때 사용              검정색의 가는 실선
브러시              HBRUSH     면을 채울때 사용               흰색
폰트                 HFONT       문자 출력에 사용되는 글꼴   시스템 글꼴
비트맵              HBITMAP    비트맵 이미지                   선택되지 않음
팔레트              HPALLETTE팔레트                              선택되지 않음
리전                 HRGN          화면상의 영역                  선택되지 않음

3. Stock Object
  가. 윈도우가 기본적으로 제공하는 GDI 오브젝트
  나. 운영체제가 부팅할 때부터 미리 만들어 놓아 일부러 만들지 않아도 언제든지 사용가능 하며
    사용한 후 파괴할 필요도 없음
    1) HGDIOBJ GetStockObject(int fnObject);  주로 브러시와 펜이 스톡 오브젝트로 제공됨
      함수는 여러 종류의 스톡 오브젝트를 리턴하므로 대입하기 전에 원하는 타입으로 캐스팅
    2) HGDIOBJ SelectObject(HDC hdc, HGDIOBJ hgdiobj); 이전에 쓰던 오브젝트를 리턴

4. 색상
  RGB 매크로 함수를 사용하여 색상값을 만듬
  typedef DWORD COLORREF;
  #define RGB(r, g, b)
                    ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b)<<16)))

5. PEN
  가. 기본 스톡 펜은 흰색, 검정색, 투명색 세 가지 뿐이며 원색 펜은 직접 만들어서 사용
    HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor);
    (선의 모양, 선의 폭, 선의 색상) 펜의 핸들을 리턴 리턴후에는 반드시 파괴
    BOOL DeleteObject(HGDIOBJ hObject);   GDI 오브젝트를 삭제할 때 사용

6. BRUSH
  가. 기본 스톡 브러시는 단색 브러시가 있음, 만드는 건 PEN과 동일
    HBRUSH CreateSolidBrush(COLORREF crColor);  단색의 브러시 제작
    HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref); 무늬와 색상을 지정할수 있음

7. Old의 의미
  가. GDI 오브젝트를 생성하고 파괴하지 않으면 안됨
  나. GDI 오브젝트를 저장하는 리소스 영역은 메인 메모리와는 다른 특수한 영역으로 이 영역의 크기가
    그리 크지 못해 오브젝트를 많이 만들면 금방 가득차 버림
  다. DC에 선택되어 있는 오브젝트는 삭제할 수 없기 때문에 Old라는 GDI 오브젝트를 사용하여
    사용중인 오브젝트를 Old라는 오브젝트로 교체후 삭제함
  라. 코드의 범용성을 위해서는 항상 Old 오브젝트를 사용하여 DC를 원래대로 돌려놓는 습관을
    가지는 것이 좋음

8. 투명 오브젝트
 스톡 오브젝트에는 투명색의 오브젝트가 존재함

9. 그리기 모드
  가. 윈도우즈에서 사용하는 디폴트 그리기 모드는 R2_COPYPEN 모드라서 그려지는 그림이
    기존 그림을 덮어버림
    1) int SetROP2(HDC hdc, int fnDrawMode);
        int GetROP2(HDC hdc);
  나. 마우스를 따라 선을 이동시킬 때 이미 그려진 그림을 보존해야 하므로 그리는 중의 선을 반점 모드로
    그려 이 선이 지워질 때 원래대로 복구해 놓고 가야하는 것이다. 그러기 위해서느 절대 색상으로 삭제,
    그리기 해서는 안되면 이미 그려진 그림과 논리 연산을 취하는 다른 방법을 사용해야 한다. R2_NOT는
    이런 작업이 가능한 그리기 모드의 한 예인데 흑백 환경에서는 이 모드가 가장 편리하며 컬러 환경에는
    R2_NOTXORPEN이 가장 완벽함

10. BITMAP
    비트맵은 대용량이라 직접 출력하는 함수는 제공하지 않으며 약간의 준비를 거친 후 출력해야 한다.
    이렇게 준비 동작을 취한 후 출력하면 여러번 출력할 때 이미 준비된 데이터를 전송하기만 하면
    출력 속도도 빠르고 예비동작을 미리 취해 놓을 수 있다는 점에서도 유리하다. 비트맵은 화면으로
    직접 출력할 수 없으며 반드시 메모리 DC에 미리 준비해 놓고 사용해야 한다
  가. 메모리 DC란 화면 DC와 동일한 특성을 가지며 그 내부에 출력 표면을 가진 메모리 영역이다.
    메모리에 있기는 하지만 화면 DC에서 사용할 수 있는 모든 출력을 메모리 DC 에서도 할 수 있다.
  나. HDC CreateCompatibleDC(HDC hdc);
    화면 DC의 핸들을 주면 화면 DC와 동일한 특성을 가지는 DC를 메모리에 만들어 핸들을 리턴
  다. HBITMAP LoadBitmap(HINSTANCE hInstance, LPCTSTR lpBitmapName);
    (비트맵 리소스를 가진 인스턴스의 핸들, 비트맵 리소스의 이름)
  라. BOOL BitBlt(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, HDC hdcSrc,
    int nXSrc, int nYSrc, DWORD dwRop);
    (복사 대상 DC, X좌표, Y좌표, 폭, 높이, 복사원 DC, 복사원X좌표, 복사원 Y좌표, 래스터 연산방법)
  마. BOOL StretchBlt(HDC hdcDest, int nXOriginDest, int nYOriginDest, int nWidthDest, int nHeightDest,
    HDC hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc, DWORD dwRop);
    확대, 축소가 가능
 
11. FONT
  HFONT CreateFont(int nHeight, int nWidth, int nEscapement, int nOrientation, int fnWeight,
    DWORD fdwItalic, DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet,
    DWORD FdwOutputPrecision, DWORD fdwClipPrecision, DWORD fdwQuality,
    DWORD fdwPitchAndFamily, LPCTSTR lpszFace);
  (폰트의 높이, 폰트의 폭, 폰트의 각도, 개별문자 기울기, 폰트의 두께, 폰트 속성, 문자셋,
  출력 정확도, 클리핑 정확도, 논리적 폰트를 물리적 폰트와 얼마나 근접시킬 것인가 지정,
  폰트의 피치와 그룹을 설정, 글꼴의 이름)
  가. LOGFONT 구조체를 사용하여 폰트를 정의하고 CreateFontIndirect 함수로 폰트를 만드는 방법
    LOGFONT 구조체는 CreateFont 함수의 인수 전체를 멤버로 가지는 구조체로 LOGFONT에
    원하는 값을 먼저 대입한 후 CreateFontIndirect 함수로 이 구조체의 번지를 넘기면 됨
    HFONT CreateFontIndirect(CONST LOGFONT * lplf);
  나. 텍스트의 색상
    COLORREF SetTextColor(HDC hdc, COLORREF crColor); 글자 색상
    COLORREF SetBkColor(HDC hdc, COLORREF crColor); 글자 배경색상
    int SetBkMode(HDC hdc, int iBkMode); 글자배경색상 모드(투명, 불투명) 기본은 불투명
1. 윈도우즈 환경에서 리소스를 만드는 과정과 코딩과정이 분리되면 얻는 장점
  가. 분담 작업으로 전문성을 높임, 개발과 디자인을 동시에 수행함으로써 전체적인 개발 기간 단축효과
  나. 재사용에 유리
  다. 모듈 분할 컴파일 방식의 장점과 같이 매번 컴파일할 필요가 없음
  라. 실행중에 교체가 가능한 모듈임

2. 리소스 편집기들은 리소스 ID에 겹따옴표없이 IDR_MENU1 식으로 이름을 지정하면 이 이름을
  resource.h에 정수형의 매크로로 정의하고 사용되지 않은 정수를 배정한다. 정수 타입의 리소스 ID를
  문자열 포인터에 대입할 수 없으므로 적당히 캐스팅해야 하는데 이 캐스팅을 대신하는  매크로가
  MAKEINTRESOURCE 이다
  ( #define MAKEINTRESOURCE(i)    (LPSTR)((DWORD)((WORD)(i))) )

3. WM_COMMAND
  가. 메뉴 항목을 선택하면 WM_COMMAND 메시지가 발생
  나. 어떤 메뉴 항목이 선택되었는가는 WPARAM의 하위 워드로 전달되므로 LOWORD(WPARAM)을 읽어
    판단
  다. WndProc에서는 WM_COMMAND 메시지를 받을 경우 switch 문으로 다시 LOWORD(WPARAM)의
    값에 따라 분기를 하여 각 메뉴 항목에 따른 처리를 수행

4. Accelerator
  가. 설정 기능을 곧바로 실행하는 키보드 조합키
  나. HACCEL LoadAccelerators(HINSTANCE hInstance, LPCTSTR lpTableName);
    리소스로부터 엑셀러레이터 테이블을 읽어들이며 그 핸들을 리턴
  다. int TranslateAccelerator(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg);
    키보드 메시지를 WM_COMMAND 메시지로 변경하여 액셀러레이터가 동작할 수 있도록 함

5. 문자열 테이블
  가. 대량의 문자열을 사용하는 프로그램은 리소스에 문자열을 정의해 놓고 필요할 때마다
    리소스의 문자열을 읽어와 사용(최대 4K까지의 길이를 가질 수 있음)
  나. int LoadString(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax);
    hInstance가 정의하고 있는 uID 문자열을 길이 nBuffexMax의 lpBuffer 문자 배열로 읽어오라는 뜻)
  다. 장점
    1) 문자열 자체가 코드와 분리됨으로써 문자열만 따로 관리할 수 있으며 프로젝ㅌ를 유지하는데 도움
    2) 많은 문자열을 다루는 대형 프로젝트에는 메시지만을 전문적으로 관리하는 사람이 따로 있어
      문체의 일관성 확보와 메시지의 내용을 정확하게 할 수 있으며 수정하기도 편리
    3) 다국어 버전을 쉽게 만들 수 있으며 문자열을 고쳐도 소스를 다시 컴파일 할 필요가 없어
      개발 속도가 빨라진다.
ORACLE DATA TYPE
invalid-file

ORACLE DATA TYPE

Button 생성시
CreateWindows(Text("button"), .............. );
첫번째 인수는 Button 생성시 이름이 고정되어 있음
1. 키보드로 입력이 발생되면 윈도우는 WM_CHAR, WM_KEYDOWN 메시지 발생
  입력된 문자의 코드는 WPARAM으로 전달되며 LPARAM에는 비트별로 복잡한 정보가 전달
  필요한 정보가 있으면 LPARAM을 참조하고 필요없으면 WPARAM만 사용하면 된다

2. 무효영역
  InvalidateRect 함수를 호출하여 강제로 WM_PAINT 메시지를 발생할 수 있다.
  BOOL InvalidateRect(HWND hWnd, CONST RECT * lpRect, BOOL bErase);

3. 문자를 입력하고자 할 경우는 WM_CHAR 메시지를 사용하고
  문자 이외의 키는 입력 받을 수 없다. 이럴때는 WM_KEYDOWN 메시지를 사용 한다.

4. 키보드를 입력하게 되면 Getmessage는 메시지 큐에서 메시지를 꺼낸 후 메시지를 TranslateMessage
  함수로 넘긴다. TranslateMessage 함수는 전달된 메시지가 WM_KEYDOWN 인지와 눌러진 키가
  문자키인지 검사해 보고 조건이 맞을 경우 WM_CHAR 메시지를 추가로 발생시킨다.

5. 마우스 입력
  가. 마우스 메시지는 LPARAM의 상위 워드에 마우스 버튼이 눌러진 Y좌표, 하위 워드에 X좌표를 가지며
    좌표값을 검출해 내기 위해 HIWORD, LOWORD 등의 매크로 함수를 사용한다. 즉 마우스 메시지가
    발생한 위치의 좌표는 (LOWORD(LPARAM), HIWORD(LPARAM))이 된다.
    좌표값을 음수가 발생할 수도 있다. 모니터가 2개이상일 시
  나. WPARAM에는 마우스 버튼의 상태와 키보드 조합 키(SHIFT, CTRL)의 상태가 전달된다.
  * 상, 하위 워드 추출, WORD로 부터 상, 하위 바이트 추출, 조립 매크로 들이 존재한다.
    (LOWORD, HIWORD, LOBYTE, HIBYTE <- 추출, MAKEWORD(A,B), MAKELONG(A,B) <- 조립)
  다. 더블클릭
    1) 더블클릭을 사용할시는 더블클릭 메시지를 받고자하면 윈도우 클래스의 스타일에 원한다는
      의사표시를 해야한다.
        WndClass.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCKS;
    2) 디폴트로 지원하지 않고 플래그를 지정하도록 되어 있는 이유는 더블클릭을 검출하는데는
      그만큼 실행시간의 감소가 요구되며 어떤 프로그램은 더블클릭보다 WM_LBUTTONDOWN을 두 번
      받기를 원할 수도 있기 때문이다. 가령 트리플 클릭을 검출하고 싶은데 더블클릭이 디폴토로 지원
      하게 되면 트리플 클릭이전에 운영체제에 의해 더블클릭이 처리되어 버리기 때문이다.

6. 타이머
  가. 한 번 지정해 놓기만 하면 일정한 시간 간격을 두고 연속적으로 계속 발생한다.
    Uint SetTimer(HWND hWnd, UINT nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc);
    BOOL KillTimer(HWND hWnd, UINT uIDEvent);
  나. LRESULT SendMessage(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
    강제로 메시지가 발생한 것처럼 만들어야 할 때 사용
  다. WndProc에서 첫 번째로 처리하는 메시지는 WM_CREATE 메시지이다.
  라. 두 개의 타이머
    SetTimer 함수의 두번째 인수로 지정한 값(타이머 ID)를 다르게 줌으로 가능하며
    (타이머 ID가 다른 2개의 타이머 함수 호출) 어떤 타이머로 부터 메시지가 발생하면
    WPARAM으로 타이머 ID가 전달된다.
  마. 콜백함수
    1) SetTimer의 네 번째 인수는 타이머 프로시저 함수의 포인터를 가리킨다. NULL일시는 첫 번째 인수로
      지정된 hWnd로 WM_TIMER 메시지가 전달되지만 이 인수에 타이머 함수가 지정되었을 경우는
      매 시간마다 이 함수가 대신 호출된다.
      VOID CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT idEvent, DWORD dwTime);
    2) 콜백함수를 사용하는 것과 WM_TIMER 메시지를 받는 것은 사실상 거의 동일한 기법이라고
      할 수 있으며 상황에 따라 편리한 방법을 사용하면 된다. 차이점이라면 WM_TIMER 메시지는 다른
      메시지가 있을 경우 실행 순서에 밀려 늦게 호출되는 경우가 있지만 콜백함수를 사용하면
      정확한 시간에 호출된다는 점이다.; 그래서 정확도를 요하는 작업은 타이머 메시지보다는 콜백함수를
      사용하는 것이 더 좋다고 되어 있다.
  바. 일회용 타이머
    타이머를 원하는 곳에 SetTimer함수를 사용한뒤 WM_TIMER 부분에 KillTimer을 호출하면 됨

7. 윈도우 관리 메시지
  가. 작업영역의 좌표를 조사 BOOL GetClientRect(HWND hWnd, LPRECT lpRect);
  나. 윈도우의 크기가 변경될 때마다 윈도우로 부터 WM_SIZE 메시지가 전달됨
    LPARAM의 하위워드는 변경된 후의 윈도우 폭이 상위 워드에는 높이가 전달되며
    WPARAM에는 이 메시지가 발생한 이유를 나타내는 플래그가 전달됨
  다. 윈도우의 위치가 변경될 때마다 WM_MOVE 메시지가 발생됨
    LPARAM의 하위워드는 새로운 X좌표, 상위워드는 새로운 Y좌표

#include <Windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass = TEXT("Class");

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdparam, int nCmdShow)
{
 HWND hWnd;
 MSG Message;
 WNDCLASS WndClass;
 g_hInst = hInstance;
 
 WndClass.cbClsExtra = 0;
 WndClass.cbWndExtra = 0;
 WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
 WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
 WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
 WndClass.hInstance = hInstance;
 WndClass.lpfnWndProc = WndProc;
 WndClass.lpszClassName = lpszClass;
 WndClass.lpszMenuName = NULL;
 WndClass.style = CS_HREDRAW|CS_VREDRAW;
 RegisterClass(&WndClass);
 
 hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
  CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  NULL, (HMENU)NULL, hInstance, NULL);
 ShowWindow(hWnd, nCmdShow);
 
 while( GetMessage(&Message, NULL, 0, 0) )
 {
  TranslateMessage(&Message);
  DispatchMessage(&Message);
 }
 
 return (int)Message.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;

 switch( iMessage )
 {
 case WM_CREATE:
  {
   hWndMain = hWnd;

   return 0;
  }
 case WM_PAINT:
  {
   hdc = BeginPaint(hWnd, &ps);
   EndPaint(hWnd, &ps);

   return 0;
  }
 case WM_DESTROY:
  {
   PostQuitMessage(0);
   
   return 0;
  }
 }
 
 return (DefWindowProc(hWnd, iMessage, wParam, lParam));
}

유니코드는 16비트의 단일한 값으로 지구상의 모든 문자를 표현할 수 있는 문자 코드 체계

C 타입           |        유니코드 타입
---------------------------------
char              |        TCHAR
char *            |        LPSTR
const char *   |        LPCTSRT

TCHAR는 C의 기본 타입 중 하나인 char과 일단 같지만 유니코드로 컴파일할 때는 wchar_t타입이 됨
wchar_t는 실제로 unsigned short로 정의되어 있으며 부호없는 16비트 정수형

TCHAR 타입의 실제 정의문은 다음과 같이 조건부 컴파일문으로 작성되어 있다.
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif

문자가 필요할시는 TCHAR로 문자열이 필요할 때는 LPSTR 또는 TCHAR *를 쓰는 것이 현명함

문자열처리 함수들도 C의 표준 함수를 쓰지 말고 가급적 유니코드를 인식하는 함수를 사용할 것

C 표준함수          |            유니코드 지원 함수
------------------------------------------
strlen                  |            lstrlen
strcpy                 |            lstrcpy
strcat                  |            lstrcat
strcmp                 |           lstrcmp
sprintf                  |           wsprintf

문자열 상수도 타입이 있으므로 겹 따옴표안에 바로 문자열 상수를 쓰지 말고
TEXT 매크로로 둘러싸는 것이 좋다.
TEXT 매크로는 유니코드 설정에 따라 문자열 상수의 타입을 변경한다.

+ Recent posts