Back in May, I shared progress on a new C compiler and interpreter that I have been working on with the vision of building a C programming environment for iPad. There is enough of a vertical slice today to demonstrate the possibilities. Here is the current iPad editor, compiling and executing C code that reads a .obj file from disk using the standard C file API, parsing its contents, building a triangle mesh, and rendering the mesh using an OpenGL-like API (using Metal under the hood) in a separate window. Here is the code that is being executed: https://gist.github.com/machinamentum/0c0c12c973915e9bbf45e16fd22eaf08 Note that nearly all of this code is portable C; much care is taken to avoid requiring the user to write code that is specific to this environment, other than the necessity of APIs for interacting with the native environment for rendering, audio, gamepad input, etc...
-
-
Save machinamentum/0c0c12c973915e9bbf45e16fd22eaf08 to your computer and use it in GitHub Desktop.
CVM Demo - 15 Nov 2024
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[[vmfn("open_window")]] void open_window(); | |
[[vmfn("start_frame")]] void start_frame(); | |
[[vmfn("end_frame")]] void end_frame(); | |
[[vmfn("set_clear_color")]] void glClearColor(double r, double g, double b, double a); | |
[[vmfn("glBegin")]] void glBegin(int mode); | |
[[vmfn("glEnd")]] void glEnd(); | |
[[vmfn("glVertex3f")]] void glVertex3f(float x, float y, float z); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include "helpers.h" | |
char *read_file(const char *path) { | |
FILE *file = fopen(path, "rb"); | |
if (file != 0) { | |
printf("Could not open file: %s\n", path); | |
} | |
fseek(file, 0, SEEK_END); | |
long length = ftell(file); | |
fseek(file, 0, SEEK_SET); | |
printf("Length of file: %d\n", length); | |
char *contents = malloc(length + 1); | |
*(contents + length) = 0; | |
fread(contents, 1, length, file); | |
return contents; | |
} | |
typedef struct { | |
float x; | |
float y; | |
float z; | |
} Vector3; | |
typedef struct { | |
Vector3 *data; | |
size_t count; | |
} Vector3Array; | |
void Vec_push(Vector3Array *arr, void *src, int tsize) { | |
Vector3 *ndata = malloc((arr->count + 1) * tsize); | |
if (arr->data) | |
memcpy(ndata, arr->data, arr->count * tsize); | |
memcpy(ndata + arr->count, src, tsize); | |
free(arr->data); | |
arr->data = ndata; | |
arr->count += 1; | |
} | |
void Vector3_push(Vector3Array *arr, float x, float y, float z) { | |
Vector3 v; | |
v.x = x; | |
v.y = y; | |
v.z = z; | |
// printf("%p\n", arr); | |
Vec_push(arr, &v, sizeof(Vector3)); | |
} | |
#define GL_TRIANGLES 4 | |
void draw_mesh(Vector3Array *arr) { | |
glBegin(GL_TRIANGLES); | |
for (int i = 0; i < arr->count; i += 1) { | |
Vector3 *v = arr->data + i; | |
glVertex3f(v->x, v->y, v->z); | |
} | |
glEnd(); | |
} | |
void load_mesh(Vector3Array *mesh, const char *path) { | |
Vector3Array verts; | |
memset(&verts, 0, sizeof verts); | |
Vector3Array indices; | |
// printf("verts: %p\n", &verts); | |
char *source = read_file(path); | |
if (source) { | |
while (*source) { | |
//printf("Enter '%c'\n", *source); | |
if (*source == 'v') { | |
source += 1; | |
while (*source == ' ') | |
source += 1; | |
double x = atof(source); | |
while (*source != ' ') | |
source += 1; | |
while (*source == ' ') | |
source += 1; | |
double y = atof(source); | |
while (*source != ' ') | |
source += 1; | |
while (*source == ' ') | |
source += 1; | |
double z = atof(source); | |
Vector3_push(&verts, x, y, z); | |
} | |
if (*source == 'f') { | |
source += 1; | |
while (*source == ' ') | |
source += 1; | |
int x = atoi(source); | |
x -= 1; | |
while (*source != ' ') | |
source += 1; | |
while (*source == ' ') | |
source += 1; | |
int y = atoi(source); | |
y -= 1; | |
while (*source != ' ') | |
source += 1; | |
while (*source == ' ') | |
source += 1; | |
int z = atoi(source); | |
z -= 1; | |
Vector3 *v = (verts.data + x); | |
Vector3_push(mesh, v->x, v->y, v->z); | |
v = (verts.data + y); | |
Vector3_push(mesh, v->x, v->y, v->z); | |
v = (verts.data + z); | |
Vector3_push(mesh, v->x, v->y, v->z); | |
} | |
while (*source != 10) | |
source += 1; | |
source += 1; | |
//printf("Test %p '%c'\n", source, *source); | |
} | |
} | |
printf("Done processing mesh\n"); | |
} | |
int main() { | |
printf("Testing the output window\n"); | |
open_window(); | |
//char *contents = read_file("helper.h"); | |
//printf("Contents(0x%p): %s\n", contents, contents); | |
Vector3Array mesh; | |
memset(&mesh, 0, sizeof mesh); | |
{ | |
load_mesh(&mesh, "monkey.obj"); | |
printf("mesh verts: %d\n", mesh.count); | |
} | |
float r = 0; | |
int loops = 0; | |
while (1) { | |
r = r + 0.01; | |
if (r > 1.0) { | |
r = 0; | |
loops = loops + 1; | |
//printf("Reset r value %d\n", loops); | |
} | |
glClearColor(0, r, 0, 0); | |
start_frame(); | |
draw_mesh(&mesh); | |
end_frame(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment