-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.c
316 lines (269 loc) · 10.2 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "raylib.h"
// #define RAYMATH_IMPLEMENTATION
#include "raymath.h"
#include "global.h"
#ifndef RELEASE
#include "debug.h"
#endif
#include "camera.h"
#include "pointcharge.h"
#include "chargemesh.h"
#include "ui.h"
#include "select.h"
#include "physics.h"
#include "vectorfield.h"
#define ACTION_ADD_POINTPA 1
#define ACTION_ADD_POINTNA 2
#define ACTION_ADD_POINTPB 3
#define ACTION_ADD_POINTNB 4
#define ACTION_ADD_POINTPC 5
#define ACTION_ADD_POINTNC 6
#define ACTION_ADD_POINTPD 7
#define ACTION_ADD_POINTND 8
// #define ACTION_ADD_LINEMESHP 5
// #define ACTION_ADD_LINEMESHN 6
#define ACTION_ADD_CIRCLEMESHP 9
#define ACTION_ADD_CIRCLEMESHN 10
// #define ACTION_ADD_SQUAREMESHP 9
// #define ACTION_ADD_SQUAREMESHN 10
#define ACTION_ADD_TRIANGLEMESHP 11
#define ACTION_ADD_TRIANGLEMESHN 12
#define ACTION_TOGGLE_VEC_FIELD 13
#define ACTION_TOGGLE_FIELD_LINES 14
#define ACTION_DELETE 15
// #define ACTION_TOGGLE_FIELD_IMAGE 16
bool isConsoleEnabled = false;
bool isMouseVectorEnabled = false;
bool isVectorFieldEnabled = true;
bool isFieldLinesEnabled = true;
// bool isFieldImageEnabled = false;
// MeshAsset lineMeshP;
// MeshAsset lineMeshN;
MeshAsset circleMeshP;
MeshAsset circleMeshN;
// MeshAsset squareMeshP;
// MeshAsset squareMeshN;
MeshAsset triangleMeshP;
MeshAsset triangleMeshN;
unsigned int getActionFromInput()
{
if (IsKeyPressed(KEY_DELETE) || IsKeyPressed(KEY_BACKSPACE)) return ACTION_DELETE;
return ACTION_NONE;
}
void handleAction(unsigned int actionId)
{
switch (actionId)
{
case ACTION_ADD_POINTPA:
addPointCharge(NANO_COULOMB * 10, screenToWorld(rightClickPosition));
break;
case ACTION_ADD_POINTNA:
addPointCharge(-NANO_COULOMB * 10, screenToWorld(rightClickPosition));
break;
case ACTION_ADD_POINTPB:
addPointCharge(NANO_COULOMB * 50, screenToWorld(rightClickPosition));
break;
case ACTION_ADD_POINTNB:
addPointCharge(-NANO_COULOMB * 50, screenToWorld(rightClickPosition));
break;
case ACTION_ADD_POINTPC:
addPointCharge(NANO_COULOMB * 100, screenToWorld(rightClickPosition));
break;
case ACTION_ADD_POINTNC:
addPointCharge(-NANO_COULOMB * 100, screenToWorld(rightClickPosition));
break;
case ACTION_ADD_POINTPD:
addPointCharge(NANO_COULOMB * 200, screenToWorld(rightClickPosition));
break;
case ACTION_ADD_POINTND:
addPointCharge(-NANO_COULOMB * 200, screenToWorld(rightClickPosition));
break;
// case ACTION_ADD_LINEMESHP:
// addChargeMesh(&lineMeshP, screenToWorld(rightClickPosition), -60.0f);
// break;
// case ACTION_ADD_LINEMESHN:
// addChargeMesh(&lineMeshN, screenToWorld(rightClickPosition), -60.0f);
// break;
case ACTION_ADD_CIRCLEMESHP:
addChargeMesh(&circleMeshP, screenToWorld(rightClickPosition), 0.0f);
break;
case ACTION_ADD_CIRCLEMESHN:
addChargeMesh(&circleMeshN, screenToWorld(rightClickPosition), 0.0f);
break;
// case ACTION_ADD_SQUAREMESHP:
// addChargeMesh(&squareMeshP, screenToWorld(rightClickPosition), 45.0f);
// break;
// case ACTION_ADD_SQUAREMESHN:
// addChargeMesh(&squareMeshN, screenToWorld(rightClickPosition), 45.0f);
// break;
case ACTION_ADD_TRIANGLEMESHP:
addChargeMesh(&triangleMeshP, screenToWorld(rightClickPosition), 0.0f);
break;
case ACTION_ADD_TRIANGLEMESHN:
addChargeMesh(&triangleMeshN, screenToWorld(rightClickPosition), 0.0f);
break;
case ACTION_TOGGLE_VEC_FIELD:
isVectorFieldEnabled = !isVectorFieldEnabled;
break;
// case ACTION_TOGGLE_FIELD_IMAGE:
// isFieldImageEnabled = !isFieldImageEnabled;
// break;
case ACTION_TOGGLE_FIELD_LINES:
isFieldLinesEnabled = !isFieldLinesEnabled;
break;
case ACTION_DELETE:
if (selectionType == SELECTION_POINT) {
removePointCharge((unsigned int)((PointCharge*)selection - pointCharges)); // This suspicious code calculates the index
selection = NULL;
selectionType = SELECTION_NONE;
} else if (selectionType == SELECTION_MESH) {
removeChargeMesh((unsigned int)((ChargeMesh*)selection - chargeMeshes));
selection = NULL;
selectionType = SELECTION_NONE;
}
break;
}
}
void onUpdate()
{
unsigned int oldChargeCount = pointChargeCount + chargeMeshCount;
#ifndef RELEASE
if (IsKeyPressed(KEY_Q))
dumpToConsole("Hello!");
if (IsKeyPressed(KEY_TAB))
isConsoleEnabled = !isConsoleEnabled;
#endif
if (IsMouseButtonPressed(1)) {
rightClickPosition = GetMousePosition();
rightClickMenuPosition = rightClickPosition;
if (rightClickMenuPosition.x + rightClickMenu.width > WINDOW_WIDTH)
rightClickMenuPosition.x -= rightClickMenuPosition.x + rightClickMenu.width - WINDOW_WIDTH + 1;
if (rightClickMenuPosition.y + rightClickMenu.height > WINDOW_HEIGHT)
rightClickMenuPosition.y -= rightClickMenuPosition.y + rightClickMenu.height - WINDOW_HEIGHT + 1;
isRightClickMenuEnabled = true;
}
unsigned int actionId = ACTION_NONE;
if (IsMouseButtonPressed(0)) {
actionId = getActionFromButtons(GetMousePosition());
handleAction(actionId);
if (!isMouseOnUI()) {
isRightClickMenuEnabled = false;
getSelection(GetMousePosition());
}
}
isMouseVectorEnabled = ( IsMouseButtonDown(0) && !isMouseOnUI() );
actionId = getActionFromInput();
handleAction(actionId);
updateVectorFieldChunks(pointChargeCount + chargeMeshCount != oldChargeCount);
updateCamera();
}
void onDraw()
{
ClearBackground( (Color){ 20, 20, 20, 255 } );
// if (isFieldImageEnabled)
// drawFieldImage();
drawGrid();
if (isVectorFieldEnabled && (pointChargeCount > 0 || chargeMeshCount > 0))
drawVectorFieldChunks();
if (isFieldLinesEnabled)
drawFieldLines();
if (isMouseVectorEnabled) {
Vector2 samplePoint = screenToWorld(GetMousePosition());
Vector2 strengthVector = getFieldStrength(samplePoint);
float strength = Vector2Length(strengthVector);
drawVector(Vector2Scale(strengthVector, 1.0f / strength), samplePoint, RAYWHITE);
DrawRectangle(0, 0, 150, 30, ALPHA_BLACK);
printFloat(strength, "V/m", 5, 5);
}
drawChargeMeshes();
drawPointCharges();
drawSelection();
drawStrengthGradient();
if (isRightClickMenuEnabled)
drawMenu(&rightClickMenu, rightClickMenuPosition, GetMousePosition());
#ifndef RELEASE
if (isConsoleEnabled) {
drawConsole();
printInt(GetFPS(), "FPS", 5, 5);
}
#endif
}
void onStart()
{
#ifndef RELEASE
initConsole();
#endif
createPointChargeBuffer(10);
createChargeMeshBuffer(3);
createChunkBuffer(20);
createMenu(&rightClickMenu, 17);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_STATIC, "Add", 0);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "+10 uC point", ACTION_ADD_POINTPA);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "-10 uC point", ACTION_ADD_POINTNA);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "+50 uC point", ACTION_ADD_POINTPB);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "-50 uC point", ACTION_ADD_POINTNB);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "+100 uC point", ACTION_ADD_POINTPC);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "-100 uC point", ACTION_ADD_POINTNC);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "+200 uC point", ACTION_ADD_POINTPD);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "-200 uC point", ACTION_ADD_POINTND);
// addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "+Line", ACTION_ADD_LINEMESHP);
// addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "-Line", ACTION_ADD_LINEMESHN);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "+1 nC * 72 Circle", ACTION_ADD_CIRCLEMESHP);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "-1 nC * 72 Circle", ACTION_ADD_CIRCLEMESHN);
// addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "+Square", ACTION_ADD_SQUAREMESHP);
// addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "-Square", ACTION_ADD_SQUAREMESHN);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "+1 nC * 60 Triangle", ACTION_ADD_TRIANGLEMESHP);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "-1 nC * 60 Triangle", ACTION_ADD_TRIANGLEMESHN);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BREAK, "", 0);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_STATIC, "View", 0);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "Vector field", ACTION_TOGGLE_VEC_FIELD);
addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "Field lines", ACTION_TOGGLE_FIELD_LINES);
// addMenuElement(&rightClickMenu, MENU_ELEM_TYPE_BUTTON, "Field image", ACTION_TOGGLE_FIELD_IMAGE);
// lineMeshP = generateMeshAsset(MESHASSET_LINE, NANO_COULOMB);
// lineMeshN = generateMeshAsset(MESHASSET_LINE, -NANO_COULOMB);
circleMeshP = generateMeshAsset(MESHASSET_CIRCLE, NANO_COULOMB);
circleMeshN = generateMeshAsset(MESHASSET_CIRCLE, -NANO_COULOMB);
// squareMeshP = generateMeshAsset(MESHASSET_SQUARE, NANO_COULOMB);
// squareMeshN = generateMeshAsset(MESHASSET_SQUARE, -NANO_COULOMB);
triangleMeshP = generateMeshAsset(MESHASSET_TRIANGLE, NANO_COULOMB);
triangleMeshN = generateMeshAsset(MESHASSET_TRIANGLE, -NANO_COULOMB);
camera.position = VEC2_ZERO;
camera.view = DEFAULT_ZOOM;
}
void onEnd()
{
CloseWindow();
destroyPointChargeBuffer();
destroyChargeMeshBuffer();
destroyChunkBuffer();
// free(lineMeshP.charges);
// free(lineMeshN.charges);
free(circleMeshP.charges);
free(circleMeshN.charges);
// free(squareMeshP.charges);
// free(squareMeshN.charges);
free(triangleMeshP.charges);
free(triangleMeshN.charges);
destroyMenu(&rightClickMenu);
#ifndef RELEASE
destroyConsole();
#endif
}
int main(void)
{
InitWindow(WINDOW_WIDTH, WINDOW_HEIGHT, "Electric field simulator");
SetTargetFPS(60);
onStart();
while (!WindowShouldClose())
{
onUpdate();
BeginDrawing();
onDraw();
EndDrawing();
}
onEnd();
return 0;
}