Physics/main.c
2020-08-31 23:51:35 +08:00

409 lines
11 KiB
C

//
// main.c
// physics
//
// Created by Eric on 16/5/6.
// Copyright © 2016年 Bakantu Eric. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>
#include <GLUT/GLUT.h>
#define E_G -9.8
#define A_G 6.67259e-11
#define o_MAX 16
#define f_MAX 32
#define X_WIN 400
#define Y_WIN 400
#define w_MAX 32
#define Pi 3.1415926536
#define CLEAN system("clear")
#define GL_SILENCE_DEPRECATION
typedef struct{
double x;
double y;
double mass;
int gravity;
int e_gravity;
double vx;
double vy;
double a_x;
double a_y;
int elasticity;
} obj;
typedef struct {
double size;
double angle;
double time;
obj *p_obj;
} force;
typedef struct {
double x0;
double y0;
double x1;
double y1;
int on;
} wall;
int opengl_init(int argc, const char * argv[]);
int add_obj(obj *objs[o_MAX]);
int add_force(obj *objs[o_MAX], force *forces[f_MAX]);
int physics_engine(obj *objs[o_MAX],force *forces[f_MAX],wall *walls[w_MAX]);
int print(obj *objs[o_MAX], force *forces[f_MAX]);
int move_obj(obj *objs[o_MAX]);
int delete_obj(obj *objs[o_MAX]);
void o_display(void);
void key_down(unsigned char key, int x, int y);
void mouse_click(int button, int state, int x, int y);
void keep_physics_engine(void);
int set_wall(void);
void w_display(void);
int set_size(void);
obj *i_objs[o_MAX];
force *i_forces[f_MAX];
wall *i_walls[w_MAX];
int wall_point = 0;
int p_wall = 0;
int engine_on = 1;
int settings = 0;
double x_MAX = 1000, y_MAX = 1000;
double ENGINE_TIME = 0.01;
int main(int argc, const char * argv[]) {
for (int i = 0; i < o_MAX; i++) i_objs[i] = NULL;
for (int i = 0; i < f_MAX; i++) i_forces[i] = NULL;
for (int i = 0; i < f_MAX; i++) i_walls[i] = NULL;
CLEAN;
opengl_init(argc, argv);
//physics_engine(i_objs, i_forces);
for (int i = 0; i < o_MAX; i++) {
if(i_objs[i] != NULL) free(i_objs[i]);
if(i_forces[i] != NULL) free(i_forces[i]);
if(i_walls[i] != NULL) free(i_walls[i]);
}
return 0;
}
int add_obj(obj *objs[o_MAX]){
CLEAN;
int p_c = 0;
while (objs[p_c] != NULL) p_c++;
objs[p_c] = (obj *)malloc(sizeof(obj));
printf("X: ");
scanf("%lf",&objs[p_c]->x);
printf("Y: ");
scanf("%lf",&objs[p_c]->y);
printf("MASS: ");
scanf("%lf",&objs[p_c]->mass);
printf("IF EARTH_GRAVITY: ");
scanf("%d",&objs[p_c]->e_gravity);
printf("IF GRAVITY: ");
scanf("%d",&objs[p_c]->gravity);
printf("VX: ");
scanf("%lf",&objs[p_c]->vx);
printf("VY: ");
scanf("%lf",&objs[p_c]->vy);
//printf("IF ELASTICITY: ");
//scanf("%d",&objs[p_c]->elasticity);
fflush(stdin);
return 0;
}
int add_force(obj *objs[o_MAX], force *forces[f_MAX]){
CLEAN;
int p_c = 0, i_obj;
while (forces[p_c] != NULL) p_c++;
forces[p_c] = (force *)malloc(sizeof(force));
printf("SIZE: ");
scanf("%lf",&forces[p_c]->size);
printf("ANGLE: ");
scanf("%lf",&forces[p_c]->angle);
printf("TIME: ");
scanf("%lf",&forces[p_c]->time);
printf("OBJ: ");
scanf("%d",&i_obj);
if(objs[i_obj] != NULL) forces[p_c]->p_obj = objs[i_obj];
else forces[p_c]->p_obj = NULL;
fflush(stdin);
return 0;
}
int physics_engine(obj *objs[o_MAX],force *forces[f_MAX],wall *walls[w_MAX]){
for(int i = 0; i < o_MAX; i++){
double a_x = 0.0, a_y = 0.0;
if (objs[i] == NULL) continue;
if(fabs(objs[i]->x) > x_MAX || fabs(objs[i]->y) > y_MAX){
free(objs[i]);
objs[i] = NULL;
continue;
}
else{
if(objs[i]->e_gravity){
a_y += E_G * ENGINE_TIME;
}
if(objs[i]->gravity){
for (int k = 0; k < o_MAX; k ++){
if ((objs[k] == NULL)||(k == i)) continue;
else{
double d_x = objs[k]->x - objs[i]->x;
double d_y = objs[k]->y - objs[i]->y;
double d_angle = atan(d_y / d_x);
if (d_y < 0 && d_x < 0) {
d_angle = -d_angle;
d_angle -= Pi/2;
}
else if (d_y > 0 && d_x < 0) {
d_angle = -d_angle;
if (d_x < 0) d_angle += Pi/2;
}
double dis = sqrt((d_x * d_x) + (d_y * d_y));
double g_force =(A_G * objs[i]->mass * objs[k]->mass)/(dis * dis);
a_x += (g_force * cos(d_angle)) / objs[i]->mass;
a_y += (g_force * sin(d_angle)) / objs[i]->mass;
}
}
}
}
for (int k = 0; k < f_MAX; k++){
if (forces[k] == NULL)continue;
else if (forces[k]->p_obj == objs[i]){
a_x += (forces[k]->size * cos(forces[k]->angle)) / objs[i]->mass *ENGINE_TIME;
a_y += (forces[k]->size * sin(forces[k]->angle)) / objs[i]->mass *ENGINE_TIME;
}
if(forces[k]->time > 0) forces[k]->time -= ENGINE_TIME;
if(forces[k]->time <= 0) {
free(forces[k]);
forces[k] = NULL;
}
}
objs[i]->a_x = a_x;
objs[i]->a_y = a_y;
}
usleep(1000000*ENGINE_TIME);
move_obj(objs);
return 0;
}
int print(obj *objs[o_MAX], force *forces[f_MAX]){
CLEAN;
printf("#OBJ:\n");
for (int i = 0; i < o_MAX; i++){
if (objs[i] != NULL){
printf("OBJ[%d](%p): (%lf, %lf) \nMASS: %lf\n\n",i,objs[i],objs[i]->x,objs[i]->y,objs[i]->mass);
glVertex2f(objs[i]->x/x_MAX, objs[i]->y/y_MAX);
}
}
printf("\n#FORCE:\n");
for (int i = 0; i < o_MAX; i++){
if(forces[i] != NULL){
printf("FORCE[%d]: SIZE:%.5lf ANGLE: %.5lf P_OBJ: %p\n, TIME: %.2lf",\
i,forces[i]->size,forces[i]->angle,forces[i]->p_obj,forces[i]->time);
}
}
printf("\n");
return 0;
}
int move_obj(obj *objs[o_MAX]){
for (int i = 0; i < o_MAX; i++){
if (objs[i] == NULL) continue;
if (objs[i]->a_x != 0){
double a_x = objs[i]->a_x;
objs[i]->x += objs[i]->vx + 0.5 * a_x * ENGINE_TIME * ENGINE_TIME;
objs[i]->vx += a_x;
}
if (objs[i]->a_y != 0){
double a_y = objs[i]->a_y;
objs[i]->y += objs[i]->vy + 0.5 * a_y * ENGINE_TIME * ENGINE_TIME;
objs[i]->vy += a_y;
}
}
return 0;
}
int delete_obj(obj *objs[o_MAX]){
CLEAN;
int d_obj;
printf("DELETE OBJ: ");
scanf("%d",&d_obj);
if (objs[d_obj] != NULL){
free(objs[d_obj]);
objs[d_obj] = NULL;
}
fflush(stdin);
return 0;
}
int opengl_init(int argc, const char * argv[]){
glutInit(&argc, (char **)argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(X_WIN/2, Y_WIN/2);
glutInitWindowSize(X_WIN, Y_WIN);
glutCreateWindow("Physics");
glutDisplayFunc(&o_display);
glutIdleFunc(&keep_physics_engine);
glutKeyboardFunc(&key_down);
glutMouseFunc(&mouse_click);
glutMainLoop();
return 0;
}
void o_display(void){
glClearColor(1.0f,1.0f,1.0f,1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(4.0f);
glBegin(GL_POINTS);
glColor3f(0,255,0);
for (int i = 0; i < o_MAX; i++){
if (i_objs[i] != NULL){
glVertex2f(i_objs[i]->x/x_MAX, i_objs[i]->y/y_MAX);
}
}
glEnd();
glLineWidth(2);
glDisable(GL_LINE_STIPPLE);
glBegin(GL_LINES);
for (int i = 0; i < w_MAX; i++){
if (i_walls[i] != NULL){
if (i_walls[i]->on == 1){
glVertex2f(i_walls[i]->x0/X_WIN*2,i_walls[i]->y0/Y_WIN*2);
glVertex2f(i_walls[i]->x1/X_WIN*2,i_walls[i]->y1/Y_WIN*2);
}
}
}
glEnd();
glFlush();
}
void key_down(unsigned char key, int x, int y){
if(key == 's'){
CLEAN;
int ifnot = 1;
char input = '\0';
while (ifnot){
printf("DEALWHITH:\n");
printf("1.ADD OBJ\n");
printf("2.ADD FORCE\n");
printf("3.EXIT PROGRAM\n");
printf("4.DELETE OBJ\n");
printf("5.SET WALL\n");
printf("6.SET SIZE\n");
printf("q.START ENGINE\n");
fflush(stdin);
input = getchar();
fflush(stdin);
switch (input) {
case '1':
add_obj(i_objs);
break;
case '2':
add_force(i_objs, i_forces);
break;
case '3':
exit(0);
break;
case '4':
delete_obj(i_objs);
break;
case '5':
engine_on = 0;
settings = 1;
wall_point = 0;
p_wall = 0;
while (i_walls[p_wall] != NULL) p_wall++;
i_walls[p_wall] = (wall *)malloc(sizeof(wall));
i_walls[p_wall]->on = 0;
ifnot = 0;
break;
case '6':
set_size();
break;
case 'q':
ifnot = 0;
break;
default:
break;
}
CLEAN;
}
}
}
void keep_physics_engine(void){
if (engine_on) {
physics_engine(i_objs, i_forces,i_walls);
print(i_objs,i_forces);
}
else{
set_wall();
}
o_display();
}
int set_wall(void){
if (wall_point == 2){
engine_on = 1;
settings = 0;
wall_point = 0;
i_walls[p_wall]->on = 1;
}
return 0;
}
void mouse_click(int button, int state, int x, int y){
if (state == GLUT_DOWN){
if (!engine_on && settings == 1 && button == GLUT_RIGHT_BUTTON){
printf("%d,%d\n",x-X_WIN/2,-(y-Y_WIN/2));
printf("x = %d y = %d\n",x,y);
if(wall_point < 2){
if(wall_point == 0){
i_walls[p_wall]->x0 = (x-X_WIN/2);
i_walls[p_wall]->y0 = -(y-Y_WIN/2);
}
else if(wall_point == 1){
i_walls[p_wall]->x1 = (x-X_WIN/2);
i_walls[p_wall]->y1 = -(y-Y_WIN/2);
}
wall_point++;
}
}
}
}
void w_display(void){
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(4.0f);
glBegin(GL_POINTS);
for (int i = 0; i < o_MAX; i++){
if (i_objs[i] != NULL){
glVertex2f(i_objs[i]->x/x_MAX, i_objs[i]->y/y_MAX);
}
}
glEnd();
glFlush();
}
int set_size(void){
CLEAN;
printf("XMAX: ");
scanf("%lf",&x_MAX);
printf("YMAX: ");
scanf("%lf",&y_MAX);
printf("ENGINE_TIME: ");
scanf("%lf",&ENGINE_TIME);
return 0;
}