[C言語]GLUTのマウス読み取りの仕組み

glutMouseFunc()でマウスボタンの操作を知る

#include <stdio.h>
#include <GL/glut.h>

void display(void){
	glClear(GL_COLOR_BUFFER_BIT);
	glFlush(); 
}

void resize(int w, int h){
	glViewport(0, 0, w, h);
	glLoadIdentity();
}

void mouse(int button, int state, int x, int y){
	switch(button){
		case GLUT_LEFT_BUTTON:
			printf("left");
			break;
		case GLUT_MIDDLE_BUTTON:
			printf("middle");
			break;
		case GLUT_RIGHT_BUTTON:
			printf("right");
			break;
		default:
			break;
	}

	printf(" button is ");

	switch(state){
		case GLUT_UP:
			printf("up");
			break;
		case GLUT_DOWN:
			printf("down");
			break;
		default:
			break;
	}

	printf(" at (%d, %d)\n", x, y);
}

void init(void){
	glClearColor(1.0, 1.0, 1.0, 1.0); 
}

int main(int argc, char *argv[]){
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(320, 240);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA); 
	glutCreateWindow(argv[0]); 
	glutDisplayFunc(display); 
	glutReshapeFunc(resize);
	glutMouseFunc(mouse);
	init();
	glutMainLoop(); 
	return 0;
}

$ ./app
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
left button is down at (172, 123)
left button is up at (172, 123)
right button is down at (188, 65)
right button is up at (188, 65)
right button is down at (188, 65)
right button is up at (186, 123)
left button is down at (186, 123)
left button is up at (109, 116)
left button is down at (207, 222)
left button is up at (207, 222)
left button is down at (103, 74)
left button is up at (102, 170)

お、大分シューティングゲームのイメージが出来てきました。
### ボタンを押した位置から離した位置まで線を引く

#include <stdio.h>
#include <GL/glut.h>

void display(void){
	glClear(GL_COLOR_BUFFER_BIT);
	glFlush(); 
}

void resize(int w, int h){
	glViewport(0, 0, w, h);
	glLoadIdentity();
	glOrtho(-0.5, (GLdouble)w - 0.5, (GLdouble)h - 0.5, -0.5, -1.0, 1.0);
}

void mouse(int button, int state, int x, int y){

	static int x0, y0;

	switch(button){
		case GLUT_LEFT_BUTTON:
			if(state == GLUT_UP){
				glColor3d(0.0, 0.0, 0.0);
				glBegin(GL_LINES);
				glVertex2i(x0, y0);
				glVertex2i(x, y);
				glEnd();
				glFlush();
			} else {
				x0 = x;
				y0 = y;
			}
			break;
		case GLUT_MIDDLE_BUTTON:
			break;
		case GLUT_RIGHT_BUTTON:
			break;
		default:
			break;
	}

}

void init(void){
	glClearColor(1.0, 1.0, 1.0, 1.0); 
}

int main(int argc, char *argv[]){
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(320, 240);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA); 
	glutCreateWindow(argv[0]); 
	glutDisplayFunc(display); 
	glutReshapeFunc(resize);
	glutMouseFunc(mouse);
	init();
	glutMainLoop(); 
	return 0;
}

すげえええええええええええええええ
マウス処理そのものやんか

### 配列に位置を記憶する

#include 
#include 

#define MAXPOINTS 100 /* 記憶する点の数 */
GLint point[MAXPOINTS][2]; /* 座標を記憶する配列 */
int pointnum = 0; /* 記憶した座標の数 */

void display(void){
	int i;

	glClear(GL_COLOR_BUFFER_BIT);

	if(pointnum > 1){
		glColor3d(0.0, 0.0, 0.0);
		glBegin(GL_LINES);
		for (i = 0; i < pointnum; ++i){
			glVertex2iv(point[i]);
		}
		glEnd();
	}
	glFlush(); 
}

void resize(int w, int h){
	glViewport(0, 0, w, h);
	glLoadIdentity();
	glOrtho(-0.5, (GLdouble)w - 0.5, (GLdouble)h - 0.5, -0.5, -1.0, 1.0);
}

void mouse(int button, int state, int x, int y){

	switch(button){
		case GLUT_LEFT_BUTTON:
			point[pointnum][0] = x;
			point[pointnum][1] = y;
			if(state == GLUT_UP){
				glColor3d(0.0, 0.0, 0.0);
				glBegin(GL_LINES);
				glVertex2iv(point[pointnum - 1]);
				glVertex2iv(point[pointnum]);
				glEnd();
				glFlush();
			} else {
			}
			if(pointnum < MAXPOINTS - 1) ++pointnum;
			break;
		case GLUT_MIDDLE_BUTTON:
			break;
		case GLUT_RIGHT_BUTTON:
			break;
		default:
			break;
	}

}

void init(void){
	glClearColor(1.0, 1.0, 1.0, 1.0); 
}

int main(int argc, char *argv[]){
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(320, 240);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA); 
	glutCreateWindow(argv[0]); 
	glutDisplayFunc(display); 
	glutReshapeFunc(resize);
	glutMouseFunc(mouse);
	init();
	glutMainLoop(); 
	return 0;
}

画面のマウス操作そのもの。
なるほど、OSはこういうGLエンジンも使ってるってことか。

GLUTの座標軸

#include <GL/glut.h>

void display(void){
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3d(1.0, 0.0, 0.0); // 描画する色指定
	glBegin(GL_POLYGON);
	glVertex2d(-0.9, -0.9);
	glVertex2d(0.9, -0.9);
	glVertex2d(0.9, 0.9);
	glVertex2d(-0.9, 0.9);
	glEnd();
	glFlush(); 
}

void resize(int w, int h){
	glViewport(0, 0, w, h); // ビューポート
	glLoadIdentity(); // 単位行列
	glOrtho(-w / 200.0, w / 200.0, -h / 200.0, h / 200.0, -1.0, 1.0); // 変換行列
}

void init(void){
	glClearColor(1.0, 1.0, 1.0, 1.0); 
}

int main(int argc, char *argv[]){
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA); 
	glutCreateWindow(argv[0]); 
	glutDisplayFunc(display); 
	glutReshapeFunc(resize); // リサイズされた時に実行する関数のポインタ
	init();
	glutMainLoop(); 
	return 0;
}

int main(int argc, char *argv[]){
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(320, 240);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA); 
	glutCreateWindow(argv[0]); 
	glutDisplayFunc(display); 
	glutReshapeFunc(resize);
	init();
	glutMainLoop(); 
	return 0;
}

ウィンドウの開く位置、サイズを決める

GLUTでウィンドウを塗り潰す

### ウィンドウ塗りつぶし

#include <GL/glut.h>

void display(void){
	glClear(GL_COLOR_BUFFER_BIT); // ウィンドウを塗り潰す GL_COLOR_BUFFER_BITはメモリのカラーバッファ
	glFlush(); // OpenGLの命令を全部実行
}

void init(void){
	glClearColor(0.5, 0.5, 1.0, 1.0); // 値は0~1, glutMainLoopの前に実行する
}

int main(int argc, char *argv[]){
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGBA);  // RGBA
	glutCreateWindow(argv[0]); 
	glutDisplayFunc(display); 
	init();
	glutMainLoop(); 
	return 0;
}

### 二次元図形

void display(void){
	glClear(GL_COLOR_BUFFER_BIT);
	glColor3d(1.0, 0.0, 0.0); // 描画する色指定
	glBegin(GL_POLYGON);
	glVertex2d(-0.9, -0.9);
	glVertex2d(0.9, -0.9);
	glVertex2d(0.9, 0.9);
	glVertex2d(-0.9, 0.9);
	glEnd();
	glFlush(); 
}

void init(void){
	glClearColor(1.0, 1.0, 1.0, 1.0); 
}

glVertexはphotoshopみたいに裏っ側でピクセル計算してるのかな?

GLUTでウィンドウを開く

OpenGLはSilicon Graphics社が開発したOSに依存しない三次元のグラフィックスライブラリ
AUXライブラリを改良したものがGLUT
※LinuxやMacintoshではMesaの上にAUXライブラリやGLUTが移植されている

freeglut

### GLUTインストール
$ sudo apt-get install freeglut3 freeglut3-dev

#include <GL/glut.h>

void display(void){

}

int main(int argc, char *argv[]){
	glutInit(&argc, argv);  // GLUTおよびOpenGL環境を初期化。引数がある時はこの後処理
	glutCreateWindow(argv[0]); // windowを開く、以降描画は開いたウィンドウに対して行われる
	glutDisplayFunc(display); // ウィンドウ内に描画するポインタ
	glutMainLoop(); // 無限ループ、イベントの待ち受け
	return 0;
}

mac vagrantでGLUTのGUIの立ち上げ方法

VagrantでGULTのGUIが立ち上がらない

#include <GL/glut.h>

void display(void){

}

int main(int argc, char *argv[]){
	glutInit(&argc, argv);
	glutCreateWindow(argv[0]);
	glutDisplayFunc(display);
	glutMainLoop();
	return 0;
}

$ ./app
freeglut (./app): failed to open display ”

1.一旦ログアウトしてvagrantを止めます。

$ exit
$ vagrant halt

2. Vagrantfileにssh.forward_x11を追記します。

Vagrantfile

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/bionic64"
  config.vm.network "private_network", ip: "192.168.33.10"
  config.ssh.forward_x11 = true // 追加
end

https://www.vagrantup.com/docs/vagrantfile/ssh_settings.html
config.ssh.forward_x11 (boolean) – If true, X11 forwarding over SSH connections is enabled. Defaults to false.

X Window Systemとは、UNIX系OSで標準的に用いられるウィンドウシステム。

XQuartzをダウンロード
-> MacユーティリティでXQuartzを起動し、terminalから再度実行

$ ./app
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
X Error of failed request: GLXBadContext
Major opcode of failed request: 149 (GLX)
Minor opcode of failed request: 6 (X_GLXIsDirect)
Serial number of failed request: 43
Current serial number in output stream: 42
X Error of failed request: BadValue (integer parameter out of range for operation)
Major opcode of failed request: 149 (GLX)
Minor opcode of failed request: 24 (X_GLXCreateNewContext)
Value in failed request: 0x0
Serial number of failed request: 42
Current serial number in output stream: 43

$ sudo ldconfig -p | grep -i gl.so
libwayland-egl.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libwayland-egl.so.1
libwayland-egl.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libwayland-egl.so
libOpenGL.so.0 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libOpenGL.so.0
libOpenGL.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libOpenGL.so
libGL.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libGL.so.1
libGL.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libGL.so
libEGL.so.1 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libEGL.so.1
libEGL.so (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libEGL.so

あれ、何故だーーーーーーーーーー
色々検索していたところ、同じ解決方法を発見
https://unix.stackexchange.com/questions/429760/opengl-rendering-with-x11-forwarding

Try the following: 1) ensure you are running up-to-date Xquartz. 2) in a terminal, defaults write org.macosforge.xquartz.X11 enable_iglx -bool true 3) restart xquartz. This worked for me to get a simple java app running. I tried "glxgears" and it starts, but the gears don't turn. I presume they're supposed to

mac側のterminalでX11をenableにする。
$ defaults write org.macosforge.xquartz.X11 enable_iglx -bool true

再度XQuartzでsshログイン
$ ./app

立ち上がったーーーーーーーーーーーー

C言語でジャンケンゲームを作る

1.ジャンケンゲームはランダム関数でrand() % 3 + 1; としてグーチョキパーを出す。
2.srand((unsigned int)time(NULL));でランダム関数を初期化する

#include <stdio.h>
#include <stdlib.h> // rand()に必要

int main(void){
	int n, r;
	printf("ジャンケン....\n");
	printf("1.グー、2.チョキ、3.パー [数字を入力してください]\n");
	scanf("%d", &n);
	switch(n){
		case 1:
			printf("グー\n");
			break;
		case 2:
			printf("チョキ\n");
			break;
		case 3:
			printf("パー\n");
			break;
		default:
			printf("1〜3の何れかを入力してください。\n");
			return 1;
	}	

	srand((unsigned int)time(NULL));
	r = rand() % 3 + 1;

	switch(r){
		case 1:
			printf("相手はグー\n\n");
			break;
		case 2:
			printf("相手はチョキ\n\n");
			break;
		case 3:
			printf("相手はパー\n\n");
			break;
	}
	switch(n){
		case 1:
			switch(r){
				case 1:
					printf("あいこです。\n");
					break;
				case 2:
					printf("あなたの勝ちです。\n");
					break;
				case 3:
					printf("あなたの負けです。\n");
					break;
			}
			break;
		case 2:
			switch(r) {
				case 1:
					printf("あなたの負けです。\n");
					break;
				case 2:
					printf("あいこです。\n");
					break;
				case 3:
					printf("あなたの勝ちです。\n");
					break;
			}
			break;				
		case 3:
			switch(r) {
				case 1:
					printf("あなたの勝ちです。\n");
					break;
				case 2:
					printf("あなたの負けです。\n");
					break;
				case 3:
					printf("あいこです。\n");
					break;
			}
			break;
	}

	return 0;
}

$ ./app
ジャンケン….
1.グー、2.チョキ、3.パー [数字を入力してください]
1
グー
相手はチョキ

あなたの勝ちです。
$ ./app
ジャンケン….
1.グー、2.チョキ、3.パー [数字を入力してください]
3
パー
相手はパー

あいこです。

一応できたけど、勝ち負けの判定をswitch文の入れ子にすると冗長になるな。。
他の方がどうやって書いているか見てみると、、、
あ、swtichではなく、以下の条件式で収まるじゃん。。。
if (r == n) : あいこ
elseif (r – n == 1 || r – n == -2) : あなたの勝ち
else : 負け

C言語 + Ubuntu18.04でGUIを作りたい

C言語でもGUIを自由に作れれば、C言語のロジックをコーディングすれば、ほぼC言語でもアプリケーションを作れるようになるのでは? という事で、C言語のGUIについて考えたい。

GUIライブラリはOSによって異なる
– WindowsはWindows API や、GUIライブラリ
– LinuxはLinux GUI アプリ
– Android, iOSはCを使うアプリから

### UbuntuのGUI
– GUIツールキットにGTK+2.0を使用する
– GIMP, Gnome, Mozilla FirfoxなどはGTK+を使用して作られた

GTK+とは?
クロスプラットフォームのウィジェット・ツールキット(GUIツールキット)
gtk.org

### GTK+, Gladeのインストール
$ sudo apt-get install libgtk2.0-dev glade
$ pkg-config –cflags gtk+-2.0  // gtkを使うのに必要なものを表示
-pthread -I/usr/include/gtk-2.0 -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/gio-unix-2.0/ -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libpng16 -I/usr/include/pango-1.0 -I/usr/include/harfbuzz -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/freetype2 -I/usr/include/libpng16

$ gcc -o gtk window.c
window.c:1:10: fatal error: gtk/gtk.h: No such file or directory
#include
^~~~~~~~~~~
compilation terminated.

うーむ、なんか上手くいかんな。

$ gcc -o gtk window.c `pkg-config –cflags –libs gtk+-2.0`
$ ./gtk
(gtk:17204): Gtk-WARNING **: 02:38:25.145: cannot open display:

何故だ。
というか、GTKで開発ってしないのか?

C言語でMySQLにinsertする書き方

sql_strの箇所をselectからinsert文に変えるだけです。update, deleteも一緒です。

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

int main(){
	MYSQL *conn = NULL;
	MYSQL_RES *resp = NULL;
     // MYSQL_ROW row;
	char sql_str[255];
	char *sql_serv = "localhost";
	char *user = "root";
	char *passwd = "hogehoge";
	char *db_name = "test";

	memset( &sql_str[0], 0x00, sizeof(sql_str));

	conn = mysql_init(NULL);
	if(!mysql_real_connect(conn, sql_serv, user, passwd, db_name, 0, NULL, 0)){ 
		 exit(-1);
	}

	snprintf(&sql_str[0], sizeof(sql_str)-1, "insert into test (id,name) values (4, 'ddd')"); 
	if(mysql_query(conn, &sql_str[0])){ 
		mysql_close(conn);
		exit(-1);
	}

	mysql_free_result(resp);
	mysql_close(conn);

	return 0;
}

### コンパイル&実行
$ gcc -Wall -o dev hello.c -lmysqlclient -L/usr/lib/x86_64-linux-gnu/
$ ./dev

### 動作確認
mysql> select * from test;
+——+——+
| id | name |
+——+——+
| 1 | aaa |
| 2 | bbb |
| 3 | ccc |
| 4 | ddd |
+——+——+
4 rows in set (0.00 sec)

なるほど、DBとの接続はわかった。次はGUIか。

C言語でMySQLのレコードからSelectする方法

### ソースコード

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

int main(){
	MYSQL *conn = NULL;
	MYSQL_RES *resp = NULL;
	MYSQL_ROW row;
	char sql_str[255];
	char *sql_serv = "localhost";
	char *user = "root";
	char *passwd = "hogehoge";
	char *db_name = "test";

	memset( &sql_str[0], 0x00, sizeof(sql_str)); // memsetはメモリに指定バイト数分の値をセット, 0x00はヌル文字

	conn = mysql_init(NULL);
	if(!mysql_real_connect(conn, sql_serv, user, passwd, db_name, 0, NULL, 0)){ // サーバ接続開始 mysql_real_connect(mysql, host, user,passwd,db, port,  unix_socket, client_flag)
		 exit(-1);
	}

	// クエリ実行
	snprintf(&sql_str[0], sizeof(sql_str)-1, "select * from test");  // snprintfは指定文字数分だけ文字配列に書き込む
	if(mysql_query(conn, &sql_str[0])){  // sql_str によって指示される SQL ステートメントを実行
		mysql_close(conn);
		exit(-1);
	}

	// レスポンス
	resp = mysql_use_result(conn);  // 結果セットの取得を開始
	while((row = mysql_fetch_row(resp)) != NULL){   // 結果を添字配列として取得する
		printf("%d: %s\n", atoi(row[0]), row[1]);
	}

	mysql_free_result(resp);  // 結果保持用メモリを開放
	mysql_close(conn); // MySQL 接続を閉じる

	return 0;
}

### ライブラリのlibmysqlclient.soの配置場所を確認
$ find / -name “libmysqlclient.so”
/usr/lib/x86_64-linux-gnu/libmysqlclient.so

### コンパイル、実行
// -Wは警告メッセージ抑制, -Lはオブジェクトライブラリ
$ gcc -Wall -o dev hello.c -lmysqlclient -L/usr/lib/x86_64-linux-gnu/
$ ./dev
1: aaa
2: bbb
3: ccc

おいおい、マジかよ。。。
感動した。

C言語でmysqlを使う前準備

### MySQLにデータ挿入
$ mysql -u root -p
> use test;
> create table test(id int,name varchar(256));
> insert into test(id,name) values(1,”aaa”);
> insert into test(id,name) values(2,”bbb”);
> insert into test(id,name) values(3,”ccc”);
> select * from test;

### ubuntu18.04にmysql/mysql.hが入っているか確認
hello.c

#include <stdio.h>
#include <mysql/mysql.h>


int main(){

	return 0;
}

$ gcc -o dev hello.c
hello.c:2:10: fatal error: mysql/mysql.h: No such file or directory
#include
^~~~~~~~~~~~~~~
compilation terminated.
-> 入っていない

### libmysqlclient-devをインストール
$ sudo apt-get -y install libmysqlclient-dev
$ gcc -o dev hello.c
-> 無事コンパイル

trustyのlibmysqlclient-dev.installのgithub見たが、includeしてるって事か?

usr/include/mysql/*.h
usr/include/mysql/mysql/*.h
usr/include/mysql/mysql/*.h.pp
usr/include/mysql/mysql/psi/*.h
usr/lib/*/libmysqlclient.a
usr/lib/*/libmysqlclient.so
usr/lib/*/libmysqlservices.a
usr/bin/mysql_config
usr/bin/mysql_config_editor
usr/share/man/man1/mysql_config.1
usr/share/man/man1/mysql_config_editor.1
# legal
usr/share/doc/libmysqlclient-dev/COPYING
usr/share/doc/libmysqlclient-dev/README

.aファイルはStaticライブラリの事らしい。
あまり見ないな。