'분류 전체보기'에 해당되는 글 107건

  1. 2010.05.02 티스토리 분류 만들기
  2. 2010.05.01 일리히트 초간단 멥툴소스
  3. 2010.05.01 일리히트 터래인툴관련 소스입니다.
  4. 2010.03.31 윈도우미디어서버 보안설정하기
  5. 2010.03.27 오드로이드 구매했습니다.
  6. 2010.03.27 android os 에 일리히트엔진 올려보기 강좌.(irrlicht 엔진 1.7.1 base)
  7. 2010.02.28 iPhone에 irrlicht engine 올리기 9
  8. 2010.01.23 수학자료정리
  9. 2010.01.03 동적 반사 데모입니다.(소스포함)
  10. 2010.01.03 굴절데모입니다.(소스포함)

티스토리 분류 만들기

|
admin->스킨->카테고리
And

일리히트 초간단 멥툴소스

|



#include "irrlicht.h" 
using namespace irr; 
using namespace core; 
using namespace scene; 
using namespace video; 
using namespace gui; 

/*============================================================================== 
  Receiver class 
==============================================================================*/ 
class MyEventReceiver : public IEventReceiver 

   bool KeyIsDown[KEY_KEY_CODES_COUNT]; 
   bool LEFTBUTTONCLICKED; 
   bool RIGHTBUTTONCLICKED; 

public: 
    virtual bool OnEvent(const SEvent& event) 
    { 
        if (event.EventType == irr::EET_KEY_INPUT_EVENT) 
            KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown; 

        if(event.EventType == EET_MOUSE_INPUT_EVENT) 
        { 
         if     (event.MouseInput.Event==EMIE_LMOUSE_PRESSED_DOWN) LEFTBUTTONCLICKED = true; 
         else if(event.MouseInput.Event==EMIE_LMOUSE_LEFT_UP     ) LEFTBUTTONCLICKED = false; 
         else if(event.MouseInput.Event==EMIE_RMOUSE_PRESSED_DOWN) RIGHTBUTTONCLICKED = true; 
         else if(event.MouseInput.Event==EMIE_RMOUSE_LEFT_UP     ) RIGHTBUTTONCLICKED = false; 
        } 

        return false; 
    } 

    virtual bool IsKeyDown(EKEY_CODE keyCode) const { return KeyIsDown[keyCode]; } 
    virtual bool IsLMBDown() const { return LEFTBUTTONCLICKED; } 
    virtual bool IsRMBDown() const { return RIGHTBUTTONCLICKED; } 

    MyEventReceiver() 
    { 
        for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i) 
          KeyIsDown[i] = false; 

        LEFTBUTTONCLICKED = RIGHTBUTTONCLICKED = false; 
    } 
}; 

/*============================================================================== 
  Raise or lower terrain (selected vertice) 
==============================================================================*/ 
void RaiseTerrainVertex(ITerrainSceneNode* terrain, s32 index, f32 step, bool up) 

   IMesh* pMesh = terrain->getMesh(); 

   s32 b; 
   for (b=0; b<pMesh->getMeshBufferCount(); ++b) 
   { 
      IMeshBuffer* pMeshBuffer = pMesh->getMeshBuffer(b); 
      // skip mesh buffers that are not the right type 
      if (pMeshBuffer->getVertexType() != video::EVT_2TCOORDS) continue; 

      video::S3DVertex2TCoords* pVertices = (video::S3DVertex2TCoords*)pMeshBuffer->getVertices(); 

      pVertices[index].Pos.Y += (up) ? step : -step; 
   } 

   // force terrain render buffer to reload 
   terrain->setPosition(terrain->getPosition()); 


/*============================================================================== 
  Save file 
==============================================================================*/ 
void save (IVideoDriver* driver, ITerrainSceneNode* terrain) 

   core::dimension2d<s32> dim (256,256); 
   video::IImage *img = driver->createImage(ECF_R8G8B8, dim); 

   u32 VertexCount = terrain->getMesh()->getMeshBuffer(0)->getVertexCount(); 
   S3DVertex2TCoords* verts = (S3DVertex2TCoords*)terrain->getMesh()->getMeshBuffer(0)->getVertices();

   for (u32 i=0; i<VertexCount; i++) 
   { 
     S3DVertex2TCoords* vertex = verts + i; 
     u8 y = (u8)vertex->Pos.Y; 
     img->setPixel((u32)vertex->Pos.X, (u32)vertex->Pos.Z, video::SColor(0, y,y,y)); 
   } 

   driver->writeImageToFile(img, "heightmap.bmp", 0); 
   img->drop(); 


/*============================================================================== 
  Entry point 
==============================================================================*/ 
int main() 

  IrrlichtDevice* device = createDevice(EDT_OPENGL, dimension2d<s32>(800,600), 32, false); 
  if (!device) return 0; 

    IVideoDriver* driver = device->getVideoDriver(); 
    ISceneManager* smgr  = device->getSceneManager(); 
    device->getCursorControl()->setVisible(false); 
    device->setWindowCaption(L"terrain"); 
    MyEventReceiver receiver; 
    device->setEventReceiver(&receiver); 

  // Terrain 
  ITerrainSceneNode* terrain = smgr->addTerrainSceneNode("heightmap.bmp"); 
    terrain->setScale(core::vector3df(32, 2.f, 32)); 
    terrain->setMaterialFlag(video::EMF_LIGHTING, false); 
    terrain->setMaterialTexture(0, driver->getTexture("aer.jpg")); 
   ITriangleSelector* terrainSelector = smgr->createTerrainTriangleSelector(terrain, 0); 

  // Camera 
   scene::ICameraSceneNode* cam = smgr->addCameraSceneNodeFPS(0, 100.0f, .1f); 
   cam->setPosition(core::vector3df(-100,500,100)); 
   cam->setTarget(core::vector3df(0,0,0)); 

  // Arrow 
   ISceneNode* arrow = smgr->addAnimatedMeshSceneNode(smgr->addArrowMesh("arrow", 
            SColor(255, 255, 0, 0), SColor(255, 0, 255, 0)), NULL); 
   arrow->setMaterialFlag(video::EMF_LIGHTING, false); 
   arrow->setScale(vector3df(20,20,20)); 
   arrow->setRotation(vector3df(0,0,180)); 

  // GUI 
    IGUIEnvironment* guienv = device->getGUIEnvironment(); 
    IGUIFont* font = guienv->getFont("battlefield.bmp"); 
    guienv->getSkin()->setFont(font); 

    IGUIStaticText* txt[2]; 
    txt[0] = guienv->addStaticText(L"Left/Right Mouse Button : raise/lower\nF4/F5 : increase/decrease step\nW : switch wireframe\nS : save heightmap", 
                core::rect<s32>(10,10,600,120), false, true, 0, -1, false); 
    txt[0]->setOverrideColor(video::SColor(255,150,100,60)); 


    txt[1] = guienv->addStaticText(L"", core::rect<s32>(10,80,600,200), false, true, 0, -1, false); 
    txt[1]->setOverrideColor(video::SColor(255,0,255,0)); 


  ITimer* irrTimer = device->getTimer(); 
  u32 then = 0, then30 = 0; 
  char c[24]; 
  f32 step = 2.f; 
  bool wireframe = false; 

  while(device->run()) if (device->isWindowActive()) 
   { 
      u32 now = irrTimer->getTime(); 
      if (then30 < now) 
      { 
        if(receiver.IsKeyDown(irr::KEY_ESCAPE)) break; 


        if (receiver.IsKeyDown(irr::KEY_KEY_W) && then < now) 
        { 
          wireframe = !wireframe; 
          terrain->setMaterialFlag(video::EMF_WIREFRAME, wireframe); 
          then = now + 300; 
        } 

        if (receiver.IsKeyDown(irr::KEY_F4) && then < now) 
        { 
          step += 1.f; 
          then = now + 100; 
        } 
        else if (receiver.IsKeyDown(irr::KEY_F5) && then < now && step > 0) 
        { 
          step -= 1.f; 
          then = now + 100; 
        } 

        if(receiver.IsKeyDown(irr::KEY_KEY_S)) 
          save (driver, terrain); 

        // move the arrow to the nearest vertex ... 
        const position2di clickPosition = device->getCursorControl()->getPosition(); 
        const line3df ray = smgr->getSceneCollisionManager()->getRayFromScreenCoordinates(clickPosition, cam); 
        vector3df pos; 
        triangle3df Tri; 
        if (smgr->getSceneCollisionManager()->getCollisionPoint(ray, terrainSelector, pos, Tri)) 
        { 
          //arrow->setPosition(pos); 
          static const s32 scale = 32; // terrain is scaled 32X 
          static const s32 size = 256; // heightmap is 256X256 pixels 
          s32 x = (s32)(pos.X / scale); 
          s32 z = (s32)(pos.Z / scale); 
          s32 index = x * size + z; 

          // ... Move it if clicked 
          if( (receiver.IsLMBDown() || receiver.IsRMBDown()) && then < now) 
          { 
            RaiseTerrainVertex(terrain, index, step, receiver.IsLMBDown()); 
            then = now + 100; 
          } 

          x *= scale; 
          z *= scale; 

          arrow->setPosition(vector3df(x, terrain->getHeight(x, z) + 20, z)); 
        } 

        driver->beginScene(true, true, video::SColor(255,0,0,0)); 
        smgr->drawAll(); 

        sprintf(c,"elevation step : %.0f units", step); 
        txt[1]->setText(stringw(c).c_str()); 

        guienv->drawAll(); 
        driver->endScene(); 

        then30 = now + 30; 

      } // 30Hz 
   } 
  
  device->closeDevice();  
  device->drop(); 

  return 0; 
}
And

일리히트 터래인툴관련 소스입니다.

|





-실시간 폭파 효과 예제- 
void explode(ITerrainSceneNode* terrain, s32 indexMid, u8 nbBarrels, s32 size) 

  //printf("desired impact (%.2f,%.2f)\n", X, Z); 
  
  //elevation around impact. This array can be stored as raw image: 
  static const char eai[25]={ 
    0, 0, 0, 0, 0, 
    0, 1, 1, 1, 0, 
    0, 1, 2, 1, 0, // <- impact point vertex will be lowered by -2 units 
    0, 1, 1, 1, 0, 
    0, 0, 0, 0, 0 
  }; 
  
  //ok lets get terrain vertices 
  
  for (u8 n=0; n<nbBarrels; n++) 
  { 
  
    //apply the crater transformation 
    int cpt = 0; 
    for (u8 v=0; v<5; v++) 
      for (u8 u=0; u<5; u++) 
      { 
        s32 index = indexMid - 2 * size + v*size - 2 + u; 
                RaiseTerrainVertex(terrain, index, eai[cpt++], false); 
      } 
  
    // force terrain render buffer to reload 
    //terrain->setPosition(terrain->getPosition()); 
  
    //emit particles... 
  
  } 
  //shaking... 
  
  //play sound... 
}




And

윈도우미디어서버 보안설정하기

|

구룹 추가할때 이름이 없다고나는 대화창 상단에서 구룹 옵션도 체크 해줘야함...
And

오드로이드 구매했습니다.

|

디자인은 좀 투박하지만 개발용으론 괜찬네요^^; 가격도 적당하고요.

사진 1

사진 2

사진 3


참고로

xp용 usb 드라이버 입니다. 
윈도7에서도 동작잘하는듯 합니다.
And

android os 에 일리히트엔진 올려보기 강좌.(irrlicht 엔진 1.7.1 base)

|


전체화면은 더블클릭입니다.
동영상은 윈도우 7 에서만 보실수있습니다.

- 교재 - 
0. 개요

일리히트엔진버전 1.7.1 기반의 소스로 android ndk에서 컴파일하여 안드로이드에 올려봤습니다.

장좌는 일식편집기와 ndk 개발 환경이 세팅된 상태라는 가정하에서 진행하겠습니다.

1. 설치법

1-1. 엔진코어바이너리


1)  첨부파일의 압축을 풀면 include와 lib폴더가 나온다.
2) [안드로이드ndk디랙토리]/andrlicht 에 include,lib폴더를 복사해 넣는다.

위 과정은 최초 한번만 해주면된다. 추가적인 작업은 1-2부터 반복해 주면된다.


1-2. makefile 넣기

다음을 압축을 풀어서 [프로잭트 디랙토리] 루트 에 그냥 풀어준다.(그냥 현재폴더에 압축풀기)


     +-Android.mk
     +-/src
Application.mk

위에것들이 추가된것을 확인한다.


2. 자바 부분 코딩하기

Activity 클래스안에 다음을 추가해준다.

 static {
// 실제 만들어진 so파일이름을 앞부분 lib 을 빼주고써주면된다.
        System.loadLibrary("andrlicht_sample1");  
    }
    
    public native void nativeInit();
    public native void nativeSetResDirectory(String path);
    public native void nativeResize(int width, int height);
    public native void nativeOnEvent(irrEvent event);
    public native void nativeUpdate();

이벤트 클래스 만들어준다.

public class irrEvent {
public int m_Action;
public float m_PosX;
public float m_PosY;

}

오픈지엘 뷰클래스를 추가해준다.

class irrlichtGLview extends GLSurfaceView {
private main m_ac;

public irrlichtGLview(main ac){
super(ac);
m_ac = ac;
setRenderer(new irrlichtRenderer(m_ac));
}
public boolean onTouchEvent(final MotionEvent event){
return true;
}
}

class irrlichtRenderer implements GLSurfaceView.Renderer {
private main m_ac; 
public irrlichtRenderer(main ac){
m_ac = ac;
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
m_ac.nativeInit();
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
m_ac.nativeResize(width, height);
}
public void onDrawFrame(GL10 gl) {
m_ac.nativeUpdate();
}
}



3. C/C++ 부분 코딩하기

3-1. 헤더파일 자동성생하기

bin폴더에서 액티비티 클래스를 인자로 javah를 실행시킨다.

예>
[project디랙토리]/bin/javah com.andrlicht.sample.main

생성된 헤더파일을 jni/src 에 카피한다.

3-2. 연결코드 예

#include "com_andrlicht_sample1_main.h"
#include <irrlicht.h>

irr::IrrlichtDevice *pDevice;
irr::video::IVideoDriver *pVideo;
irr::scene::ISceneManager *pSmgr;
irr::gui::IGUIEnvironment *pGuiEnv;

void init()
{
pDevice = irr::createDevice(
irr::video::EDT_OGLES1,
irr::core::dimension2du(480,778)
);

pDevice->setWindowCaption(L"Type-A2");

pVideo = pDevice->getVideoDriver();
pSmgr = pDevice->getSceneManager();
pGuiEnv = pDevice->getGUIEnvironment();

pSmgr->addCameraSceneNode(0, irr::core::vector3df(0,0,-5), irr::core::vector3df(0,0,0));

}

void update()
{
static irr::u32 uLastTick=0;
//밀리세컨드값얻기
irr::u32 uTick = pDevice->getTimer()->getTime();
irr::f32 fDelta = ((float)(uTick - uLastTick)) / 1000.f; //델타값 구하기
uLastTick = uTick;
irr::video::S3DVertex Vertices[4];
irr::u16 Indice[6];

Vertices[0] = irr::video::S3DVertex(-.5,-.5,0, 0,0,-1,irr::video::SColor(0,0,255,255),0,1);
Vertices[1] = irr::video::S3DVertex(-.5,.5,0, 0,0,-1,irr::video::SColor(0,255,0,255),0,0);
Vertices[2] = irr::video::S3DVertex(.5,.5,0, 0,0,-1,irr::video::SColor(0,255,255,0),1,0);
Vertices[3] = irr::video::S3DVertex(.5,-.5,0, 0,0,-1,irr::video::SColor(0,0,255,0),1,1);

Indice[0] = 0;
Indice[1] = 1;
Indice[2] = 2;
Indice[3] = 3;
Indice[4] = 0;
Indice[5] = 2;
pVideo->beginScene(true, true, irr::video::SColor(255,100,101,140));

pSmgr->drawAll();
pGuiEnv->drawAll();

//직접 그리기
{
irr::core::matrix4 mat;//단위행렬로초기화
mat.makeIdentity();
pVideo->setTransform(irr::video::ETS_WORLD, mat); //변환초기화

irr::video::SMaterial m;
m.Lighting = false;  //라이트를꺼야 색이 제데로나온다.
//m.ZBuffer = false;

pVideo->setMaterial(m);
}

pVideo->drawIndexedTriangleList(
Vertices,
4,
Indice,
2
);

pVideo->endScene();
}

void resize(int w,int h)
{
irr::core::dimension2du size(w,h);
pVideo->OnResize(size);
}

#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_andrlicht_sample1_main
 * Method:    nativeInit
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_andrlicht_sample1_main_nativeInit
  (JNIEnv *env, jobject obj)
  {
   init();
  }

/*
 * Class:     com_andrlicht_sample1_main
 * Method:    nativeSetResDirectory
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_andrlicht_sample1_main_nativeSetResDirectory
  (JNIEnv *env, jobject obj, jstring str)
  {
  }

/*
 * Class:     com_andrlicht_sample1_main
 * Method:    nativeResize
 * Signature: (II)V
 */
JNIEXPORT void JNICALL Java_com_andrlicht_sample1_main_nativeResize
  (JNIEnv *env, jobject obj, jint w, jint h)
  {
   resize(w,h);
  }

/*
 * Class:     com_andrlicht_sample1_main
 * Method:    nativeOnEvent
 * Signature: (Lcom/andrlicht/sample1/irrEvent;)V
 */
JNIEXPORT void JNICALL Java_com_andrlicht_sample1_main_nativeOnEvent
  (JNIEnv *env, jobject obj1, jobject obj2)
  {
  }

/*
 * Class:     com_andrlicht_sample1_main
 * Method:    nativeUpdate
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_andrlicht_sample1_main_nativeUpdate
  (JNIEnv *env, jobject obj)
  {
   update();
  }

#ifdef __cplusplus
}
#endif



이런식으로 만든 cpp파일을 jni/scr에 생성한다.

4. 컴파일 하기
Application.mk파일을 내용에 맞게 수정한다.

APP_MODULES      := [프로잭트이름]


jni/adroid.mk 를 내용을 맞게 수정한다.

MYAPP_SRC = [컴파일할 cpp 파일이름들]

LOCAL_MODULE := [프로잭트이름]

시크윈에서 ndk 디랙토리를 찾아가서 make APP=[프로잭트이름] 해서 컴파일을 한다.





5. 실행하기

일식편집기에서 꼭 리프레쉬를 한번 한후에 실행시켜야한다.
(일식편집기 패키지뷰어에서 .so 파일 확인 필수!)



6. 보너스
안된다고 하시는 분들이 계셔셔 확인된 샘플코드 까지 추가로 올려드립니다.
디랙토리구조 확인해두시고요.
app폴더에 andrilicht_sample1.zip을 압축푸셔셔 andrilicht_sample1이름으로 만든 디랙토리에 푸시고요.
(app/andrilicht_sample1)

씨그윈에서 아래 스샷에 나와있는 위치에서
make APP=andrilicht_sample1
으로 컴파일합니다.














And

iPhone에 irrlicht engine 올리기

|
문서 최종 수정일 : 2011년 5월 12일

0. 들어가기전에...

많은 분들이 아이폰어플을 개발하기 위해서 오브잭트씨만을 써야한다고 잘못알고 계신분들이 많습니다.

Xcode는 c++도 컴파일이 가능하기때문에 기존에 c++기반의 공개엔진들을 올리실수가있습니다.
오브잭트씨는 c++과 별도의 언어가 아니고 c++코드를 생성해주는 관리스크립트언어(일종에 탬플릿)라 생각을하시면됩니다.
(MS의 managed c++과 비슷?)

c++기반의 일리히트엔진(irrlicht.sourceforge.net)을 올리는 방법을 설명해보도록 하겠습니다.

1. 맥개발환경 세팅하기
아이폰에 일리히트 엔진을 올리기 위해서 먼저 xcode와 최신의 아이폰 sdk를 설치해야합니다.
Install Xcode with last iPhone SDK. ( http://developer.apple.com/iphone/ )

공개소스들은 대부분 svn을 통해서 다운받는것이 많습니다. 윈도우즈는 tortoris-svn을 사용하지만
맥에서 SVN을 사용 하려면 아래 싸이트에 가면 SVN클라이언트프로그램을 구하실수 있습니다. 
Install scplugin for your Mac to access svn. ( http://scplugin.tigris.org/ ) 

 
2. 일리히트엔진 다운받기

opengl-es버전의 일리히트엔진svn으로 다운받습니다.

 
3. 엔진 컴파일하기

일단
source/Irrlicht/MacOSX/MacOSX.xcodeproj
경로에 있는 엑스코드용 프로잭트파일은 아이폰타겟이 아닌 맥운영체제용 빌드파일입니다.
그러나 이것을 조금수정하면 아이폰용으로 쉽게만들수있습니다.(역자주. 전 이것때문에 2주삽질을 ㅜ.ㅜ;;)

 
먼저 다음 3개의 파일을 프로잭트에서 제외시킵니다. (아이폰과는 무관한 맥운영체제 부분이며 컴파일시 에러가 발생합니다.)
- AppDelegate.mm 
- CIrrDeviceMacOSX.mm 
- OSXClipboard.mm 

그 다음 아래의 파일들을 프로잭트에 추가시켜줍니다.
(당근 헤더 파일은 안추가 시켜도 되겟죠. ^^;)


- source/Irrlicht/wglext.h 
- source/Irrlicht/eglext.h 
- source/Irrlicht/gles-ext.h 
- source/Irrlicht/COGLESDriver.h 
- source/Irrlicht/COGLESDriver.cpp 
- source/Irrlicht/COGLESExtensionHandler.h 
- source/Irrlicht/COGLESExtensionHandler.cpp 
- source/Irrlicht/COGLESMaterialRenderer.h 
- source/Irrlicht/COGLESTexture.h 
- source/Irrlicht/COGLESTexture.cpp 
- source/Irrlicht/CIrrDeviceIPhone.h 
- source/Irrlicht/CIrrDeviceIPhone.cpp 
- source/Irrlicht/CIrrDeviceIPhone.m 

include/IrrCompileCongig.h 파일의 앞부분에 아래 코드를 추가해줍니다.( #include <stdio.h> 바로 밑에쯤... )

#define NO_IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_ 
#define NO_IRR_COMPILE_WITH_HALFLIFE_LOADER_ 
#define NO_IRR_COMPILE_WITH_BURNINGSVIDEO_ 
#define NO_IRR_COMPILE_WITH_CONSOLE_DEVICE_ 
#define NO_IRR_COMPILE_WITH_OGLES2_ 

#define _IRR_COMPILE_WITH_OGLES1_ 

 


그리고 나서 마지막으로 Get Info->Base SDK for All Configurations->[현제 설정되어있는 최신 ios]
으로 설정을 해준뒤 빌드를 합니다.


 

아래의 파일이 생성됐다면 성공한것입니다.
- source/Irrlicht/MacOSX/build/Debug-iphonesimulator/irrlicht.a 
 
일단 여기까지 하시면 엔진컴파일은 완료가 됐습니다. 

4. 어플만들어보기

포럼에서 FuzzYspo0N 님이 올려주신 탬플릿을 다운받습니다.

그다음 빈폴더를 만들어 그안에  압축을 풀어넣습니다.
irrlicht.a파일도 같은 폴더에 카피해 넣습니다.

 iPhoneTemplateApp/irrlichtApplication.xcodeproj 파일로 프로잭트를 오픈합니다.

get info->irrlicht.a 에서 경로명을 카피해넣은 폴더로 새로지정해줍니다. 그러면 빨간색이 검은색으로 바뀌게 될것입니다.

get info->include 에서 일리히트엔진을 컴파일했던 include디랙토리로 지정해줍니다.

마지막으로 
Get Info->Base SDK for All Configurations->iPhone Simulator 3.x
선택해준뒤

빌드한후 실행해보실수 있습니다.



4.1 아나 토미 싸이트에서 어플 만들어 보기



5.참고자료
혹시 다운로드 링크가 깨져있을것에 대비해서 자료를 관련 자료 업로드 해둡니다.


ps.
다음 강좌에는 터치패널 컨트롤 하는 부분도 정리해서 올리겠습니다. 



=================================================================

포럼에 올라온 원문입니다.


And

수학자료정리

|
And

동적 반사 데모입니다.(소스포함)

|
And

굴절데모입니다.(소스포함)

|
And
prev | 1 | ··· | 7 | 8 | 9 | 10 | 11 | next