FLTK+OpenGLのコードをChatGPTに書かせてみた

# 目的

FLTK+OpenGLで，立体をマウスドラッグで動かすようなコードを書いてみたいと思ったけれど，マウスドラッグの実装などが面倒なので，ChatGPTに書かせられないかと思って試してみた．


# FLTKを使った短いコード

ChatGPT（3.5）に，"Can you give me a sample code using FLTK?" と聞いて返ってきた答がこちら．

Certainly! FLTK (pronounced fulltick) is a cross-platform C++ GUI toolkit. Below is a simple example of a FLTK program in C++ that creates a window with a button:

```cpp:fltk.cpp
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Button.H>

void buttonCallback(Fl_Widget* widget, void* data) {
    // This function is called when the button is clicked
    Fl_Button* button = (Fl_Button*)widget;
    button->label("Hello, FLTK!");
}

int main(int argc, char* argv[]) {
    // Create a window
    Fl_Window* window = new Fl_Window(300, 200, "FLTK Example");

    // Create a button and set its position and size
    Fl_Button* button = new Fl_Button(110, 80, 80, 40, "Click me");

    // Set the callback function for the button
    button->callback(buttonCallback);

    // Display the window
    window->show(argc, argv);

    // Run the FLTK event loop
    return Fl::run();
}
```

なおコンパイルは

```
g++ fltk.cpp -lfltk
```

とした．

This program creates a window with a button. When the button is clicked, its label changes to "Hello, FLTK!".

だそうで，確かに"Click me"というボタンが現れ，押すと"Hello, FLTK"と表示される．

# teapotを描かせてみる

"Please modify the code so that a teapot is drawn." と命令してみた．答はこちら．

FLTK itself doesn't have built-in support for 3D graphics or drawing complex shapes like a teapot. However, you can integrate other libraries, like OpenGL, for such tasks. Here's an example using OpenGL to draw a teapot within an FLTK window:


```cpp:fltk_teapot.cpp
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/gl.h>
#include <FL/glu.h>

void drawTeapot() {
    // Set up the perspective projection matrix
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, 1.0, 1.0, 10.0);

    // Set up the modelview matrix
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

    // Draw a teapot
    glutSolidTeapot(1.0);
}

void drawCallback(void*) {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    drawTeapot();

    glFlush();
}

int main(int argc, char* argv[]) {
    // Create a window
    Fl_Window* window = new Fl_Window(400, 400, "Teapot Example");

    // Enable OpenGL for the window
    window->end();
    window->resizable(window);

    // Set up OpenGL settings
    glEnable(GL_DEPTH_TEST);
    glClearColor(1.0, 1.0, 1.0, 1.0);

    // Set the draw callback function
    Fl::add_idle(drawCallback);

    // Display the window
    window->show(argc, argv);

    // Run the FLTK event loop
    return Fl::run();
}
```

これを以下のようにコンパイル．

```
g++ fltk_teapot.cpp -lfltk -lfltk_gl -lGLU -lGL
```

これはコンパイルエラーとなり

```
fltk_teapot.cpp:In function ‘void drawTeapot()’:
fltk_teapot.cpp:18:5: error: ‘glutSolidTeapot’ was not declared in this scope
   18 |     glutSolidTeapot(1.0);
```

と言われる．どうやらglutのヘッダファイルが読み込まれていないためらしいので，コードの冒頭部を以下のように変える．

```
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/gl.h>
#include <FL/glu.h>
#include <FL/glut.H>
```

そうするとコンパイルは通るが，これを走らせても灰色の四角いウィンドウが表示されるだけで，teapotは描かれない．どうやらうまく行かないようだ．

# FLTKでteapot:自分のサンプルコードをmodifyさせてみる

ChatGPTに一からコードを書かせるのを断念して，単純なサンプルコードから発展させる方針に切り替えることにする．

FLTKでteapotを表示するだけの簡単なコードは既に持っているので，これを利用することにした．

```cpp:sample.cpp
#include <iostream>
#include <string>

#include <GL/gl.h>
#include <GL/glu.h>
#include <FL/glut.H>

#include <FL/Fl.H>
#include <FL/Fl_Gl_Window.H>
#include <FL/Fl_Menu_Bar.H>

using namespace std;

const GLfloat MY_LIGHT0_POS[4] = { 2.0f, 4.0f, 1.0f, 0.0f };
const GLfloat MY_LIGHT_AMBI[4] = { 0.1f, 0.1f, 0.1f, 1.0f };
const GLfloat MY_LIGHT_DIFF[4] = { 0.9f, 0.9f, 0.9f, 1.0f };
const GLfloat MY_LIGHT_SPEC[4] = { 0.2f, 0.2f, 0.2f, 1.0f };


class myFlGLWindow : public Fl_Gl_Window
{
public:
// Constructor
myFlGLWindow(int x_, int y_, int w_, int h_, const char* l=0)
: Fl_Gl_Window(x_, y_, w_, h_, l) {
}
// Destructor
virtual ~myFlGLWindow() {
}

void InitGL(void)
{
cout << "OpenGL Ver. " << glGetString(GL_VERSION) << endl;
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);

// Light setting
glLightfv(GL_LIGHT0, GL_AMBIENT, MY_LIGHT_AMBI);
glLightfv(GL_LIGHT0, GL_DIFFUSE, MY_LIGHT_DIFF);
glLightfv(GL_LIGHT0, GL_SPECULAR, MY_LIGHT_SPEC);
glLightfv(GL_LIGHT0, GL_POSITION, MY_LIGHT0_POS);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);

glShadeModel(GL_SMOOTH);

glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
}

void Resize(int w, int h)
{
cout << "Resize " << w << " x " << h << endl;
glViewport(0, 0, w, h);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (float)w/(float)h, 0.2f, 1000.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glTranslatef(0.0f, 0.0f, -5.0f);
}

// Drawing function here..
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnable(GL_LIGHTING);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

// glut function for drawing here
glColor3f(0.0, 0.0, 1.0);
glutSolidTeapot(1.0);
}

private:
// for redrawing event
void draw(void)
{
if(!context_valid()){
InitGL();
}
if(!valid()){
Resize(w(), h());
}

// OpenGL
Display();
}

};


int main(int argc, char *argv[])
{
Fl::scheme("gtk+");
Fl::visual(FL_DOUBLE | FL_RGB);
Fl::get_system_colors();

//glutInit(&argc, argv);
//glutCreateWindow("hoge");
Fl_Window *flwin = new Fl_Window(480,480,"hoge");

//myFlGLWindow *window = new myFlGLWindow(100, 100, 480, 480, "FLTK + GLUT TEST");
myFlGLWindow *window = new myFlGLWindow(10, 10, flwin->w()-20, flwin->h()-20);
flwin->resizable(window);
flwin->show();
return Fl::run();
}
```

このコードを用いて，ChatGPTに次のような命令を与えてみた．

What follows is my code using FLTK and GLUT, which shows a teapot. Please modify this code so that the teapot can be rotated by mouse drag.

...
...
＜コード（上記）の中身＞
...
...


この要求に対するChatGPTの答はこちら．

To enable mouse dragging for rotating the teapot in your FLTK and GLUT code, you'll need to make a few modifications. The main changes involve handling mouse events and updating the rotation angles. Here's the modified code:

```cpp:teapot_rotate.cpp
#include <iostream>
#include <FL/Fl.H>
#include <FL/Fl_Gl_Window.H>
#include <FL/gl.h>
#include <FL/glu.h>
#include <FL/glut.H>

using namespace std;

const GLfloat MY_LIGHT0_POS[4] = {2.0f, 4.0f, 1.0f, 0.0f};
const GLfloat MY_LIGHT_AMBI[4] = {0.1f, 0.1f, 0.1f, 1.0f};
const GLfloat MY_LIGHT_DIFF[4] = {0.9f, 0.9f, 0.9f, 1.0f};
const GLfloat MY_LIGHT_SPEC[4] = {0.2f, 0.2f, 0.2f, 1.0f};

class myFlGLWindow : public Fl_Gl_Window
{
public:
    // Constructor
    myFlGLWindow(int x_, int y_, int w_, int h_, const char *l = 0)
        : Fl_Gl_Window(x_, y_, w_, h_, l)
    {
    }
    // Destructor
    virtual ~myFlGLWindow()
    {
    }

    void InitGL(void)
    {
        cout << "OpenGL Ver. " << glGetString(GL_VERSION) << endl;
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        glEnable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);

        // Light setting
        glLightfv(GL_LIGHT0, GL_AMBIENT, MY_LIGHT_AMBI);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, MY_LIGHT_DIFF);
        glLightfv(GL_LIGHT0, GL_SPECULAR, MY_LIGHT_SPEC);
        glLightfv(GL_LIGHT0, GL_POSITION, MY_LIGHT0_POS);
        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);

        glShadeModel(GL_SMOOTH);

        glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
        glEnable(GL_COLOR_MATERIAL);
    }

    void Resize(int w, int h)
    {
        cout << "Resize " << w << " x " << h << endl;
        glViewport(0, 0, w, h);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0f, (float)w / (float)h, 0.2f, 1000.0f);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glTranslatef(0.0f, 0.0f, -5.0f);
    }

    // Drawing function here..
    void Display(void)
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glEnable(GL_LIGHTING);
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

        // glut function for drawing here
        glPushMatrix();
        glRotatef(rotate_x, 1.0, 0.0, 0.0);
        glRotatef(rotate_y, 0.0, 1.0, 0.0);
        glColor3f(0.0, 0.0, 1.0);
        glutSolidTeapot(1.0);
        glPopMatrix();
    }

    // Mouse event handling
    int handle(int event)
    {
        switch (event)
        {
        case FL_PUSH:
            last_x = Fl::event_x();
            last_y = Fl::event_y();
            mouse_down = true;
            return 1;

        case FL_RELEASE:
            mouse_down = false;
            return 1;

        case FL_DRAG:
            if (mouse_down)
            {
                int new_x = Fl::event_x();
                int new_y = Fl::event_y();

                // Calculate the rotation based on the mouse movement
                rotate_x += 0.5 * (new_y - last_y);
                rotate_y += 0.5 * (new_x - last_x);

                last_x = new_x;
                last_y = new_y;

                // Redraw the teapot
                redraw();
                return 1;
            }
            break;
        }

        return Fl_Gl_Window::handle(event);
    }

private:
    int last_x = 0;
    int last_y = 0;
    bool mouse_down = false;
    float rotate_x = 0.0;
    float rotate_y = 0.0;

    // for redrawing event
    void draw()
    {
        if (!context_valid())
        {
            InitGL();
        }
        if (!valid())
        {
            Resize(w(), h());
        }

        // OpenGL
        Display();
    }
};

int main(int argc, char *argv[])
{
    Fl::scheme("gtk+");
    Fl::visual(FL_DOUBLE | FL_RGB);
    Fl::get_system_colors();

    Fl_Window *flwin = new Fl_Window(480, 480, "FLTK + GLUT TEST");

    myFlGLWindow *window = new myFlGLWindow(10, 10, flwin->w() - 20, flwin->h() - 20);
    flwin->resizable(window);
    flwin->show();

    return Fl::run();
}
```

This modified code integrates mouse event handling for dragging, allowing you to rotate the teapot using FLTK and GLUT.

とのこと．確かに，マウスドラッグでteapotがぐりぐり回転できる機能が追加された．

# 拡大・縮小機能を追加#1: 失敗

調子に乗って，こんどはマウスドラッグで拡大・縮小できるような機能を追加してもらおうと，以下のように言ってみた．

Great! Now, please add a feature to magnify and shrink the teapot by mouse drag.

これに対し，ChatGPTは次のように返してきた．

Certainly! To implement zooming (magnifying and shrinking) of the teapot with mouse drag, you can add another set of variables for scaling. Here's the modified code with the added functionality:

```cpp:teapot_rotate_zoom_failed.cpp
#include <iostream>
#include <FL/Fl.H>
#include <FL/Fl_Gl_Window.H>
#include <FL/gl.h>
#include <FL/glu.h>
#include <FL/glut.H>

using namespace std;

const GLfloat MY_LIGHT0_POS[4] = {2.0f, 4.0f, 1.0f, 0.0f};
const GLfloat MY_LIGHT_AMBI[4] = {0.1f, 0.1f, 0.1f, 1.0f};
const GLfloat MY_LIGHT_DIFF[4] = {0.9f, 0.9f, 0.9f, 1.0f};
const GLfloat MY_LIGHT_SPEC[4] = {0.2f, 0.2f, 0.2f, 1.0f};

class myFlGLWindow : public Fl_Gl_Window
{
public:
    // Constructor
    myFlGLWindow(int x_, int y_, int w_, int h_, const char *l = 0)
        : Fl_Gl_Window(x_, y_, w_, h_, l)
    {
    }
    // Destructor
    virtual ~myFlGLWindow()
    {
    }

    void InitGL(void)
    {
        cout << "OpenGL Ver. " << glGetString(GL_VERSION) << endl;
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        glEnable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);

        // Light setting
        glLightfv(GL_LIGHT0, GL_AMBIENT, MY_LIGHT_AMBI);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, MY_LIGHT_DIFF);
        glLightfv(GL_LIGHT0, GL_SPECULAR, MY_LIGHT_SPEC);
        glLightfv(GL_LIGHT0, GL_POSITION, MY_LIGHT0_POS);
        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);

        glShadeModel(GL_SMOOTH);

        glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
        glEnable(GL_COLOR_MATERIAL);
    }

    void Resize(int w, int h)
    {
        cout << "Resize " << w << " x " << h << endl;
        glViewport(0, 0, w, h);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0f, (float)w / (float)h, 0.2f, 1000.0f);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glTranslatef(0.0f, 0.0f, -5.0f);
    }

    // Drawing function here..
    void Display(void)
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glEnable(GL_LIGHTING);
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

        // glut function for drawing here
        glPushMatrix();
        glTranslatef(scale_factor, scale_factor, scale_factor); // Apply scaling
        glRotatef(rotate_x, 1.0, 0.0, 0.0);
        glRotatef(rotate_y, 0.0, 1.0, 0.0);
        glColor3f(0.0, 0.0, 1.0);
        glutSolidTeapot(1.0);
        glPopMatrix();
    }

    // Mouse event handling
    int handle(int event)
    {
        switch (event)
        {
        case FL_PUSH:
            last_x = Fl::event_x();
            last_y = Fl::event_y();
            mouse_down = true;
            return 1;

        case FL_RELEASE:
            mouse_down = false;
            return 1;

        case FL_DRAG:
            if (mouse_down)
            {
                int new_x = Fl::event_x();
                int new_y = Fl::event_y();

                // Calculate the rotation based on the mouse movement
                rotate_x += 0.5 * (new_y - last_y);
                rotate_y += 0.5 * (new_x - last_x);

                // Calculate the scaling based on the mouse movement
                scale_factor *= exp(0.01 * (new_x - last_x));

                last_x = new_x;
                last_y = new_y;

                // Redraw the teapot
                redraw();
                return 1;
            }
            break;
        }

        return Fl_Gl_Window::handle(event);
    }

private:
    int last_x = 0;
    int last_y = 0;
    bool mouse_down = false;
    float rotate_x = 0.0;
    float rotate_y = 0.0;
    float scale_factor = 1.0;

    // for redrawing event
    void draw()
    {
        if (!context_valid())
        {
            InitGL();
        }
        if (!valid())
        {
            Resize(w(), h());
        }

        // OpenGL
        Display();
    }
};

int main(int argc, char *argv[])
{
    Fl::scheme("gtk+");
    Fl::visual(FL_DOUBLE | FL_RGB);
    Fl::get_system_colors();

    Fl_Window *flwin = new Fl_Window(480, 480, "FLTK + GLUT TEST");

    myFlGLWindow *window = new myFlGLWindow(10, 10, flwin->w() - 20, flwin->h() - 20);
    flwin->resizable(window);
    flwin->show();

    return Fl::run();
}
```

This code allows you to zoom in and out by dragging the mouse horizontally. The scale_factor variable is used to control the scaling of the teapot. The scaling is applied when rendering the teapot, and it is adjusted based on the horizontal movement of the mouse.

このコードは

```
teapot_rotate_zoom_failed.cpp:109:33: error: ‘exp’ was not declared in this scope
  109 |                 scale_factor *= exp(0.01 * (new_x - last_x));
```

とコンパイル時に文句を言われるが，これは冒頭に

```
#include <math.h>
```

などとすればコンパイル可能になる．ところが，このままだとマウスボタンの種類（右，左）が区別されていないため，回転と拡大・縮小が（マウスのどのボタンを押しても）同時に行われてしまう，という問題が生じた．

# 拡大・縮小機能を追加#2: 成功

そこで，この問題に対処するよう，以下のように具体的に指示を出す．

The mathematical function "exp"  seems to need "math.h" , so please add a line to include it at the beginning. Also, please assign the rotation and zoom operations to the left and right mouse buttns, respectively.

そうするとChatGPTは以下のように返してきた．

Certainly! I've made the requested modifications, including including "math.h" and assigning the rotation operation to the left mouse button and the zoom operation to the right mouse button:

```cpp:teapot_rotate_zoom.cpp
#include <iostream>
#include <FL/Fl.H>
#include <FL/Fl_Gl_Window.H>
#include <FL/gl.h>
#include <FL/glu.h>
#include <FL/glut.H>
#include <cmath> // Added to include math.h

using namespace std;

const GLfloat MY_LIGHT0_POS[4] = {2.0f, 4.0f, 1.0f, 0.0f};
const GLfloat MY_LIGHT_AMBI[4] = {0.1f, 0.1f, 0.1f, 1.0f};
const GLfloat MY_LIGHT_DIFF[4] = {0.9f, 0.9f, 0.9f, 1.0f};
const GLfloat MY_LIGHT_SPEC[4] = {0.2f, 0.2f, 0.2f, 1.0f};

class myFlGLWindow : public Fl_Gl_Window
{
public:
    // Constructor
    myFlGLWindow(int x_, int y_, int w_, int h_, const char *l = 0)
        : Fl_Gl_Window(x_, y_, w_, h_, l)
    {
    }
    // Destructor
    virtual ~myFlGLWindow()
    {
    }

    void InitGL(void)
    {
        cout << "OpenGL Ver. " << glGetString(GL_VERSION) << endl;
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        glEnable(GL_DEPTH_TEST);
        glDisable(GL_CULL_FACE);

        // Light setting
        glLightfv(GL_LIGHT0, GL_AMBIENT, MY_LIGHT_AMBI);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, MY_LIGHT_DIFF);
        glLightfv(GL_LIGHT0, GL_SPECULAR, MY_LIGHT_SPEC);
        glLightfv(GL_LIGHT0, GL_POSITION, MY_LIGHT0_POS);
        glEnable(GL_LIGHT0);
        glEnable(GL_LIGHTING);

        glShadeModel(GL_SMOOTH);

        glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
        glEnable(GL_COLOR_MATERIAL);
    }

    void Resize(int w, int h)
    {
        cout << "Resize " << w << " x " << h << endl;
        glViewport(0, 0, w, h);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45.0f, (float)w / (float)h, 0.2f, 1000.0f);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();

        glTranslatef(0.0f, 0.0f, -5.0f);
    }

    // Drawing function here..
    void Display(void)
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glEnable(GL_LIGHTING);
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

        // glut function for drawing here
        glPushMatrix();
        glTranslatef(scale_factor, scale_factor, scale_factor); // Apply scaling
        glRotatef(rotate_x, 1.0, 0.0, 0.0);
        glRotatef(rotate_y, 0.0, 1.0, 0.0);
        glColor3f(0.0, 0.0, 1.0);
        glutSolidTeapot(1.0);
        glPopMatrix();
    }

    // Mouse event handling
    int handle(int event)
    {
        switch (event)
        {
        case FL_PUSH:
            last_x = Fl::event_x();
            last_y = Fl::event_y();
            mouse_down = true;
            return 1;

        case FL_RELEASE:
            mouse_down = false;
            return 1;

        case FL_DRAG:
            if (mouse_down)
            {
                int new_x = Fl::event_x();
                int new_y = Fl::event_y();

                if (Fl::event_button() == FL_LEFT_MOUSE)
                {
                    // Calculate the rotation based on the mouse movement
                    rotate_x += 0.5 * (new_y - last_y);
                    rotate_y += 0.5 * (new_x - last_x);
                }
                else if (Fl::event_button() == FL_RIGHT_MOUSE)
                {
                    // Calculate the scaling based on the mouse movement
                    scale_factor *= exp(0.01 * (new_x - last_x));
                }

                last_x = new_x;
                last_y = new_y;

                // Redraw the teapot
                redraw();
                return 1;
            }
            break;
        }

        return Fl_Gl_Window::handle(event);
    }

private:
    int last_x = 0;
    int last_y = 0;
    bool mouse_down = false;
    float rotate_x = 0.0;
    float rotate_y = 0.0;
    float scale_factor = 1.0;

    // for redrawing event
    void draw()
    {
        if (!context_valid())
        {
            InitGL();
        }
        if (!valid())
        {
            Resize(w(), h());
        }

        // OpenGL
        Display();
    }
};

int main(int argc, char *argv[])
{
    Fl::scheme("gtk+");
    Fl::visual(FL_DOUBLE | FL_RGB);
    Fl::get_system_colors();

    Fl_Window *flwin = new Fl_Window(480, 480, "FLTK + GLUT TEST");

    myFlGLWindow *window = new myFlGLWindow(10, 10, flwin->w() - 20, flwin->h() - 20);
    flwin->resizable(window);
    flwin->show();

    return Fl::run();
}
```

Now, the left mouse button is used for rotation, and the right mouse button is used for zooming. I've included <cmath> to ensure the exp function is recognized.

とのこと．このコードは確かに，左ボタンのマウスドラッグで回転，右ボタンのドラッグで拡大・縮小が可能になっている．一応成功した，と言えるだろう．