35 Commits

Author SHA1 Message Date
PedroEdiaz
b83f0f07e3 Merge main, change compile.bat, add struct gui 2025-02-04 10:16:09 -06:00
PedroEdiaz
52aa9d4ac2 Fix size of klein files, debug of glfw 2024-12-15 19:58:58 -06:00
Crisel
bc537cf9f2 ui better 2024-12-10 00:06:17 -06:00
PedroEdiaz
533109fbcd Return color 2024-12-09 16:12:48 -06:00
PedroEdiaz
3997613d16 Fix nameing and reduce size 2024-12-09 00:40:40 -06:00
PedroEdiaz
f21121b88d Better contrast 2024-12-09 00:39:39 -06:00
PedroEdiaz
86480fe9b1 Add flow 2024-12-05 21:38:59 -06:00
PedroEdiaz
e9bd748dd8 Fix examples compilation 2024-12-05 19:19:19 -06:00
PedroEdiaz
ad4f5cb077 Merge branch 'main' into experimental 2024-12-04 13:22:05 -06:00
PedroEdiaz
a08b17e975 Update colors 2024-12-04 10:37:10 -06:00
PedroEdiaz
d97a35b898 Documentation 2024-12-04 10:32:38 -06:00
PedroEdiaz
b2f6707efc Update norm.h to be safe 2024-12-03 22:51:50 -06:00
PedroEdiaz
7344c6bfcb Fix 2024-12-03 22:44:39 -06:00
PedroEdiaz
b928dcd82d Update Readme 2024-12-03 22:42:53 -06:00
PedroEdiaz
f687117fed Merge branch 'klein' 2024-12-03 22:22:31 -06:00
PedroEdiaz
65017c859c Fix compilation 2024-12-03 22:21:22 -06:00
PedroEdiaz
f514fc7ffe setup examples and clean codebase 2024-12-03 22:18:48 -06:00
islas
f8eb20c0cf Actualizar src/surface.c 2024-12-03 01:31:47 +00:00
islas
33940b7bb6 Actualizar src/surface.c 2024-12-03 01:28:33 +00:00
islas
b1897b500b Actualizar src/surface.c 2024-12-03 01:18:23 +00:00
Crisel
81eb79662e 3rd ui 2024-12-02 14:59:47 -06:00
Crisel
d2e2c6eef7 2nd ui colors 2024-12-02 14:39:32 -06:00
Crisel
57091d3408 1rst ui 2024-12-02 14:12:01 -06:00
PedroEdiaz
fd598255f4 Allow droping klein files 2024-12-01 21:33:27 -06:00
PedroEdiaz
733ababde0 Read klein files, xd 2024-12-01 21:20:07 -06:00
PedroEdiaz
987ce54429 Read Klein file 2024-12-01 21:08:35 -06:00
alan
6d1223d79e Esfera y espacios lente agregados 2024-12-01 15:10:27 -06:00
alan
3e3c6e676e Merge branch 'experimental' of https://gitea.axiolutions.com/software/manigraph into experimental 2024-12-01 15:00:42 -06:00
alan
f33b8f67b5 esfera y espacios lente agregados 2024-12-01 14:49:02 -06:00
PedroEdiaz
eb59f5346a Merge branch 'experimental' 2024-12-01 12:28:39 -06:00
PedroEdiaz
ee144f2286 Assert Style 2024-11-30 22:33:28 -06:00
Crisel
56339e9e10 changes 2024-11-29 15:49:17 -06:00
PedroEdiaz
03796fdaff Fix: OpenGL changes of Nuklear 2024-11-07 14:14:20 -06:00
PedroEdiaz
46869cbcde WIP: Working window that breaks OpenGL settings 2024-11-06 19:27:02 -06:00
Crisel
25df66b5f8 wip2 2024-11-06 15:57:45 -06:00
30 changed files with 928 additions and 853 deletions

View File

@@ -2,32 +2,31 @@ BIN = manigraph
OBJ = \
ext/glad/glad.o \
src/surface.o \
src/context.o \
src/window.o \
src/load.o \
src/shader.o \
src/klein.o \
src/input.o \
src/load.o \
src/mesh.o \
src/gui.o \
src/main.o
EXAMPLES = \
example/basic \
example/riemman \
example/n-cube \
example/n-hilbert-cube \
example/lens
CFLAGS = \
-I./ext/cglm/include \
-I./ext/glfw/include \
-I./ext/glad \
-I./ext/nuklear \
-I./include \
-Wall -Wno-unused-function -std=c99 -D_GNU_SOURCE \
WAYLAND-LIB = \
xdg-shell \
relative-pointer-unstable-v1 \
xdg-decoration-unstable-v1 \
pointer-constraints-unstable-v1 \
viewporter \
idle-inhibit-unstable-v1 \
fractional-scale-v1 \
xdg-activation-v1 \
wayland
help:
@echo "Usage:"
@echo " $(MAKE) windows"
@@ -35,10 +34,12 @@ help:
@echo " $(MAKE) linux-wayland"
@echo " $(MAKE) cocoa"
@echo " $(MAKE) CC=emcc wasm"
@echo "Examples"
@echo " $(MAKE) examples"
@echo "Clean"
@echo " $(MAKE) clean"
src/main.o: src/data/axis.h src/data/shaders.h
src/main.o: src/data/shaders.h
windows: $(OBJ)
cd ext; $(MAKE) -f glfw.mk windows; cd -
@@ -50,11 +51,11 @@ glfw.dll:
# LINUX
linux-wayland: $(OBJ)
cd ext; $(MAKE) -f glfw.mk linux-wayland; cd -
$(CC) -o $(BIN) $(OBJ) ext/libglfw.a -lGL -lm
$(CC) -o $(BIN) $(OBJ) ext/libglfw.a -lm
linux-x11: $(OBJ)
cd ext; $(MAKE) -f glfw.mk linux-x11; cd -
$(CC) -o $(BIN) $(OBJ) ext/libglfw.a -lGL -lm
$(CC) -o $(BIN) $(OBJ) ext/libglfw.a -lm
cocoa: $(OBJ)
cd ext; $(MAKE) -f glfw.mk cocoa; cd -
@@ -64,15 +65,17 @@ wasm: $(OBJ)
$(CC) -sUSE_WEBGL2=1 -sUSE_GLFW=3 -o $(BIN).html $(OBJ)
chmod -x $(BIN).wasm
libglfw.so:
$(CC) -fPIC -shared $(DFLAGS) -D_GLFW_BUILD_DLL -Iext/glfw/deps/wayland ./ext/glfw/src/*.c -o $@
clean:
rm $(OBJ) $(BIN)
rm $(OBJ) $(BIN) $(EXAMPLES)
cd ext; $(MAKE) -f glfw.mk clean; cd -
examples: $(EXAMPLES)
.SUFFIXES: .c .o
.c.o:
$(CC) -Wno-implicit-function-declaration $(CFLAGS) -c -o $@ $<
.c:
$(CC) -I include -o $@ $< -lm

110
README.md
View File

@@ -1,92 +1,62 @@
# Manigraph: Graficadora de variedades
Diaz Camacho Pedro Emilio
# Manigraph
Manigraph is a cutting-edge tool for multidimentional surface visualization,
capable of handling over a hundred dimensions. It allows users to interactively
explore each dimension in an intuitive and dynamic way.
Import your .klein files, which represents multidimentional surface.
# Resumen
manigraph es un graficador interactiva de variedades que lee archivos binarios, con la información de
una variedad multidimensional y grafica esta variedad en una proyección tridimensional.
# Building
Manigraph is written in C99, and uses OpenGL 2.0 for the rendering. So you just
need a C compiler to build this project.
# Dependencias
Para poder compilar el proyecto hace falta lo siguiente.
## Programas
- `cc`: Cualquier compilador de C.
- `git`: Gestor de dependencias. (Opcional)
- `make`: Herramienta para compilar automáticamente. (Opcional)
## Librerías
- `openGL`: A cross-platform API for rendering 2D and 3D graphics. (no incluida)
- `glew`: The OpenGL Extension Wrangler Library (no incluida)
- `glfw`: A multi-platform library for OpenGL, OpenGL ES, Vulkan, window and input.
- `cglm`: Highly Optimized 2D / 3D Graphics Math (glm) for C.
### Linux
Para compilar `glfw` en linux hacen falta las siguientes librerías. (no incluidas)
- `x11`: libXcursor-devel libXi-devel libXinerama-devel libXrandr-devel
- `wayland`: libwayland-dev libxkbcommon-dev wayland-protocols
# Descargas
- [git](https://git-scm.com/downloads/win)
- [MinGW](https://github.com/niXman/mingw-builds-binaries/releases)
- [glew](https://glew.sourceforge.net/)
# Clonar el código fuente
## Source code
```
git clone https://gitea.adles.top/software/manigraph.git
git clone https://gitea.axiolutions.top/software/manigraph.git
cd manigraph
git submodule update --init --recursive
```
# Compilación
Para compilar manualmente el proyecto se puede usar `make` o ejecutar los comandos manualmente
en el código fuente de `manigraph`.
## Dependecies
You may need system specific dependecies to build *Manigraph*.
[Reference](https://www.glfw.org/docs/3.3/compile.html#compile_deps)
## Make
Los siguientes comandos sirven para compilar `manigraph` deacuerdo al sistema operativo.
### Linux
- `x11`: libXcursor-devel libXi-devel libXinerama-devel libXrandr-devel
- `wayland`: libwayland-dev libxkbcommon-dev wayland-protocols
## Commands
A C compiler is needed for building *Manigraph*. and any of those commands
```
make windows
./compile.bat
make linux-x11
make linux-wayland
make cocoa
make CC=emcc wasm
```
## Manualmente
se pueden compilar el proyecto manualmente sin necesidad del programa `make`.
# Flow of Manigraph
![Flow of Manigraph](doc/flow.svg)
### GLFW
Si tienes problemas compilando `GLFW` puedes checar su página web oficial
explicando el tema: [Compiling GLFW](https://www.glfw.org/docs/3.3/compile.html).
# Design
Manigraph is a program designed with sustainability in mind. It is built to be
portable, resource-efficient, and easy to maintain and scale. The program
follows a Data-Oriented Programming (DOP) paradigm, where each file is
responsible for a specific data type and manages its own dependencies. Each
function is named after the file it resides in, ensuring a clear organization
and structure.
#### Windows
```
cc -fPIC -shared -D_GLFW_WIN32 -D_GLFW_BUILD_DLL ./ext/glfw/src/*.c -o glfw.dll -lgdi32
```
The independence of data types allows for efficient scaling and maintenance.
The main file is a special case in this design: it is responsible for combining
all the data types in a comprehensive manner, actng as the workflow of the program.
#### Linux
```
cc -fPIC -shared -D_GLFW_X11 -D_GLFW_BUILD_DLL ./ext/glfw/src/*.c -o libglfw.so
cc -fPIC -shared -D_GLFW_WAYLAND -D_GLFW_BUILD_DLL ./ext/glfw/src/*.c -o libglfw.so
```
# Contributing
Before commiting use `clang-format`, for coding style consistency. Your
contribution must be whitin the design principles and the concept of Manigraph.
#### Mac
```
cc -fPIC -shared -D_GLFW_COCOA -D_GLFW_BUILD_DLL ./ext/glfw/src/*.c -o libglfw.so
```
The following diagram illustrates the relationships between files, showing how
they are connected through dependencies. It also highlights the scenarios where
files are not independent of one another,
### Manigraph
#### Windows
```
cc -I ext/cglm/include/ -I ext/glfw/include/ src/*.c -o manigraph -L. -lglfw -lopengl32 -lglew32
```
#### Linux
```
cc -I ext/cglm/include/ -I ext/glfw/include/ src/*.c -o manigraph -L. -lglfw -lGL -lGLEW
```
#### Mac
```
cc -framework GL -I ext/cglm/include/ -I ext/glfw/include/ src/*.c -o manigraph -L. -lglfw -lGLEW
```
![File layout](doc/file_layout.svg)
# Ejecutar
En linux se puede ejecutar el programa sin instalar la libreria de glfw usando:
```
LD_LIBRARY_PATH=. ./manigraph
```

View File

@@ -1,3 +1,3 @@
:: git submodule update --init --recursive
:: gcc -fPIC -shared -Iext/glfw/deps/MinGW -D_GLFW_WIN32 -D_GLFW_BUILD_DLL ./ext/glfw/src/*.c -o glfw.dll -lgdi32
gcc -I ext/cglm/include -I ext/glfw/include src/*.c -o manigraph -L . -lglfw -lopengl32 -lglew32
gcc -I ext/glad -I ext/cglm/include -I ext/nuklear -I ext/glfw/include src/*.c ext/glad/glad.c -o manigraph -L . -lglfw -lopengl32

View File

@@ -1,80 +0,0 @@
# Estructura de archivos
Díaz Camacho Pedro Emilio
# Headers
## main.h
Este archivo incluye los prototipos internos, que va a usar el programa
funge como api interna para los desarrolladores y debe estar bien documentada.
# codigo fuente
## main.c
Este archivo debe configurar el programa antes de iniciarse, avisar de los problemas
que eviten que el programa se ejecute correctamente, iniciar y terminar los objetos que use el
programa, así como ejecutar la función principal
### Depende de
- <GL/gl.h>
## context.c
En este archivo se escoge un color para limpiar la pantalla y tiene una función para limpiar
tanto lo dibujado en pantalla, como distintos buffers gráficos.
### Depende de
- <GL/gl.h>
## input.c
Incluye la función `poll_input`, que se ejecuta en cada ciclo del programa y devuelve un
cuaternion de tipo `float *` que representa la rotación total del cubo, después de interactuar
con el programa.
### Depende de
- <GLFW/glfw3.h>
- <cglm/quat.h>
## matrix.c
Incluye las funciónes para configurar y cargar en la GPU las 3 matrices principales.
- `fix_matrix` esta matriz no cambia y se usa para configurar la perspectiva y la vista que
va a usar el programa en todo momento.
- `mdl_matrix` esta matriz depende de cada mesh y describe la rotación única de cada objeto,
se usa para rotar los ejes ortogonamente con un indice.
- `rot_matrix` esta matriz describe la rotación total de todos los objetos y se configura con
un cuaternio
### Depende de
- <cglm/mat4.h>
- <cglm/cam.h>
- <cglm/quat.h>
## mesh.c
Este archivo se usa para crear, destruir y dibujar objetos de tipo `mesh`, un `mesh` es una
colección de triángulos que describen un objeto multidimensional.
### Depende de
- <GL/gl.h>
- <stdlib.h>
## shader.c
Debe crear, destruir y usar los shaders, estos shaders son programas para la gpu escritos en glsl para
además aquí se carga memoria en gpu con las funciónes `gload_`
### Depende de
- <GL/gl.h>
## texture.c
Debe cargar, usar y destruir las texturas, que va a usar la gpu, también crea una textura
para una paleta de colores definida, esto para manipular fácilmente los colores que usará el programa.
### Depende de
- <GL/gl.h>
## window.c
Crea, usa, limpie y cierra una ventana, una ventana tiene un contexto de OpenGL asociado para poder
dibujar objetos en ella, tiene una función especial para avisar si la ventana está abierta para
dibujar.
### Depende de
- <GLFW/glfw3.h>
# Datos
## data/cube.h
Aquí esta la información del mesh de un cubo, este se va a borrar cuando podamos
importar meshes para graficarlos.
## data/axis.h
Aquí está el mesh de un solo eje, este se va a rotar para hacer los otros 2 ejes.
## data/shaders.h
Aquí estan los shaders en glsl para dibujar en pantalla

View File

@@ -1,43 +0,0 @@
# Tipos de datos del proyecto
Díaz Camacho Pedro Emilio
# Introducción
En este archivo vamos a detallar los tipos de datos únicos del programa, estos
tipos de datos son estructuras que representan objetos computacionales y son
necesarios para integrar las distintas partes del programa.
## window_t
En `window.c` tenemos una estructura que es la ventana y esta se representa por `window_t`,
este tipo de dato es un pointer que es manejado por `glfw`.
## id_t
`id_t` es un tipo de dato que representa objetos de `OpenGL`, estos datos
normalmente vienen enumerados, y en `manigraph` se usan para representar `shaders`,
`programs` y `texture`.
## mesh_t
Este es un tipo de dato usado para interactuar con `mesh.c`, este representa la triangulación de un
objeto gráfico y funciona ocultando las variables que `OpenGL` necesita en un `void *`.
## mat4_t
`mat4_t` se usará para representar las matrices, se usará este tipo de dato exclusivamente
en `matrix.c` y funcionará con el tipo de dato `mat4` de `cglm`.
## quat_t
Este tipo de dato sirve para representar un quaternio, este quaternio representa la rotación
del objeto gráficado en la proyección tridimensional, y se usará para crear una matriz que
pueda entender `glsl`.
## narray
`narray` es un tipo de dato que funciona como un `array` enumerado, esto significa que el primer
elemento del `array` dice cuantos elementos tiene este, sin contar el primer elemento, y los demas elementos
funcionan como un `array` normal.
esta estructura nos ayuda a trabajar con arrays de tamaños arbitrario de forma óptima y sin tener que marcar el
último elemento de forma especial.
### narray_u8_t
es un `narray` para `char` y `unsigned char`.
### narray_float_t
es un `narray` para `float`.

View File

@@ -1,59 +0,0 @@
# Manual de Diseño
Diaz Camacho Pedro Emilio
# Objetivos
## Prioridad alta
- [ ] El programa debe actualizarse cuando interactuan con el.
- [ ] El usuario quiere:
- [X] Ver 3 ejes en todo momento.
- [ ] Ver que ejes esta viendo.
- [ ] Ver cuantos ejes hay.
- [X] El usuario quiere:
- [X] Rotar estos ejes,
- [X] Ver donde quedan los ejes despues de la rotados.
- [ ] El usuario experimentado quiere ejecutar el programa y pasar la variedad:
- [ ] Como argumento del programa.
- [ ] Desde la entrada estandar del programa.
## Prioridad media
- [ ] El usuario quiere:
- [ ] Cambiar los ejes que se ven por pares.
- [ ] Cambiar los ejes donde esta la informacion de los ejes.
- [ ] El usuario quiere interactuar con el programa:
- [ ] Usando solo el mouse.
- [ ] Usando solo el teclado.
## Prioridad baja
- [ ] El usuario quiere guardar las transformaciones como un archivo GIF.
# Camino
0. Graficadora de un cubo.
1. Se hace un programa que muestre un cubo.
1. Se muestran los 3 ejes del cubo
1. Se rota el cubo en sus 3 ejes usando el teclado.
1. Se rota el cubo en sus 3 ejes usando el mouse.
1. Se muestran la etiqueta de los ejes.
1. Se hace el formato de objetos multidimensionales.
0. Programa ejemplo
1. Se hace un programa que divida un cuadrado en triangulos.
1. Se mapea cada vertice del triangulo en un punto de la cinta de
mobius usando una parametrizacion
1. Se mapea cada vertice del triangulo en un punto de la botella de
klein usando una parametrizacion
1. Se divide cada lado de un cubo de n dimensiones, en triangulos.
0. Graficadora de variedades
1. Se generaliza el programa para usar este formato.
1. Se muestran la informacion de los ejes mostrados y cuantos hay.
1. Se pueden cambiar los ejes por pares
1. Usando el mouse.
1. Usando el teclado.
0. Detalles.
1. Se anima el cambio de eje.
1. Se hace el generador de GIF.
1. Se puede cambiar el shader
1. Documentacion

View File

@@ -1,22 +0,0 @@
# Problemas esperados al desarrollar
Diaz Camacho Pedro Emilio
## OpenGL esperan objetos tridimensionales, no de n dimensiones.
Usando glVertexAttribPointer podemos pasar las coordenadas que
queramos de los puntos de las variedades, y con ello usar objetos 3D en
el shader.
## Rotar ejes por pares en una animacion continua.
- Con glVertexAttribPointer podemos pasar las coordenadas del eje
seleccionado, al shader.
- Con la funcion mix del shader y bloqueando el input, podemos hacer
una animacion pasando una variable con la cpu.
- Cuando la animacion termine intercambiar los indices del layout,
usando glVertexAttribPointer otra vez.
## Volumen de la variedad.
Dado que la funcion parametrizadora es continua, mandamos la frontera
de un n-cubo a la frontera de una variedad, por lo que solo basta
graficar la frontera de la variedad.

View File

@@ -1,19 +0,0 @@
# Manual de usario para Manigraph
Manigraph es un graficador interactivo de variedades que lee archivos
binarios de una variedad multidimensional y los proyecta a 3 dimensiones.
# Glosario
Llamaremos a los 3 ejes de la proyección tridimensional `X`, `Y` y `Z`,
este sistema de coordenadas es derecho con el eje `Z` apuntando afuera de la pantalla
# Controles
## Teclado
- `Q` Rota el eje `X` de forma horaria.
- `W` Rota el eje `X` de forma antihoraria.
- `A` Rota el eje `Y` de forma horaria.
- `S` Rota el eje `Y` de forma antihoraria.
- `Z` Rota el eje `Z` de forma horaria.
- `X` Rota el eje `Z` de forma antihoraria.
## Mouse
- Hacer `click` en un eje lo selecciona.
- El `scroll` del mouse hace girar al eje seleccionado.

10
doc/file_layout.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 39 KiB

10
doc/flow.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 107 KiB

92
example/basic.c Normal file
View File

@@ -0,0 +1,92 @@
#include <math.h>
#include <stdio.h>
#define KLEIN_IMPLEMENT
#include <klein/klein.h>
#include <klein/norm.h>
#include <klein/parm.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
void cube(float *d_surface, int *coord, unsigned char *grid)
{
int i;
for (i = 0; i < 4; i++)
d_surface[i] = (2 * (float)coord[i] / grid[i]) - 1;
if (4 == 2)
d_surface[2] = 0;
}
void mobius(float *d_surface, int *coord, unsigned char *grid)
{
const float width = 0.5;
float u = (2 * M_PI) * ((float)coord[0] / grid[0]);
float v = (2 * width) * ((float)coord[1] / grid[1]) - width;
d_surface[0] = cos(u) + v * cos(u / 2) * cos(u);
d_surface[1] = sin(u) + v * cos(u / 2) * sin(u);
d_surface[2] = v * sin(u / 2);
}
void torus(float *d_surface, int *coord, unsigned char *grid)
{
float u = (2 * M_PI) * ((float)coord[0] / grid[0]);
float v = (2 * M_PI) * ((float)coord[1] / grid[1]);
d_surface[0] = (1 + 0.5 * cos(v)) * cos(u);
d_surface[1] = (1 + 0.5 * cos(v)) * sin(u);
d_surface[2] = 0.5 * sin(v);
}
void klein(float *d_surface, int *coord, unsigned char *grid)
{
float u = (2 * M_PI) * ((float)coord[0] / grid[0]);
float v = (2 * M_PI) * ((float)coord[1] / grid[1]);
d_surface[0] = (0.5 * cos(v) + 0.5) * cos(u);
d_surface[1] = (0.5 * cos(v) + 0.5) * sin(u);
d_surface[2] = sin(v) * cos(u / 2);
d_surface[3] = sin(v) * sin(u / 2);
}
int main(void)
{
unsigned char i = 0;
const char *file_name[] = {"mobius.klein", "torus.klein", "klein.klein"};
struct parm parametrization[] = {{
.grid = (unsigned char[]){16, 4},
.m = 2,
.n = 3,
.f = mobius,
},
{
.grid = (unsigned char[]){16, 8},
.m = 2,
.n = 3,
.f = torus,
},
{
.grid = (unsigned char[]){16, 16},
.m = 2,
.n = 4,
.f = klein,
}};
for (i = 0; i < 3; ++i)
{
struct klein klein;
printf("writing %s\n", file_name[i]);
klein_parametrize(&klein, parametrization[i]);
klein_normalize(&klein);
klein_export_file(klein, file_name[i]);
free(klein.vertex);
free(klein.normals);
}
return 0;
}

54
example/lens.c Normal file
View File

@@ -0,0 +1,54 @@
#include <math.h>
#include <stdio.h>
#define KLEIN_IMPLEMENT
#include <klein/klein.h>
#include <klein/norm.h>
#include <klein/parm.h>
int p = 37;
int q = 7;
void lens(float *d_surface, int *coord, unsigned char * grid)
{
float norm = 0;
float sphere[4];
for (int i = 0; i < 4; i++)
sphere[i] = ((float)coord[i] / grid[i]) - 0.5;
for(int i = 0; i < 4; i++)
norm += sphere[i] * sphere[i];
for (int i = 0; i < 4; i++)
sphere[i] = sphere[i] / sqrt(norm);
d_surface[0] = (sphere[0] * cos(2 * M_PI / p)) - (sphere[1] * sin(2 * M_PI / p));
d_surface[1] = (sphere[0] * sin(2 * M_PI / p)) + (sphere[1] * cos(2 * M_PI / p));
d_surface[2] = (sphere[2] * cos(2 * M_PI * q / p)) - (sphere[3] * sin(2 * M_PI * q / p));
d_surface[3] = (sphere[2] * sin(2 * M_PI * q / p)) + (sphere[3] * cos(2 * M_PI * q / p));
}
int main(void)
{
char file_name[0xff];
struct klein klein;
struct parm parametrization = {
.grid = (unsigned char[]){8, 8,8,8},
.m = 4,
.n = 4,
.f = lens,
};
snprintf(file_name, 0xff, "lens-%03d-%03d.klein", p, q);
printf("writing %s\n", file_name);
klein_parametrize(&klein, parametrization);
klein_normalize(&klein);
klein_export_file(klein, file_name);
free(klein.vertex);
free(klein.normals);
return 0;
}

50
example/n-cube.c Normal file
View File

@@ -0,0 +1,50 @@
#include <math.h>
#include <stdio.h>
#define KLEIN_IMPLEMENT
#include <klein/klein.h>
#include <klein/norm.h>
#include <klein/parm.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
unsigned char dim = 10;
void cube(float *d_surface, int *coord, unsigned char *grid)
{
int i;
for (i = 0; i < dim; i++)
d_surface[i] = (2 * (float)coord[i] / grid[i]) - 1;
if (dim == 2)
d_surface[2] = 0;
}
int main(void)
{
unsigned char i;
char file_name[0xff];
struct klein klein;
struct parm parametrization = {
.m = dim,
.n = dim,
.f = cube,
};
parametrization.grid = malloc(dim);
for (i = 0; i < dim; ++i)
parametrization.grid[i] = 1 + i;
snprintf(file_name, 0xff, "cube-%03d.klein", dim);
printf("writing %s\n", file_name);
klein_parametrize(&klein, parametrization);
klein_normalize(&klein);
klein_export_file(klein, file_name);
return 0;
}

50
example/riemman.c Normal file
View File

@@ -0,0 +1,50 @@
#include <complex.h>
#include <math.h>
#include <stdio.h>
#define KLEIN_IMPLEMENT
#include <klein/klein.h>
#include <klein/norm.h>
#include <klein/parm.h>
#ifndef CMPLX
#define CMPLX(a, b) (a + I * b)
#endif
complex float f(complex float z) { return csqrt(z); }
void riemman(float *d_surface, int *coords, unsigned char *grid)
{
complex float eq;
float u = 2 * ((float)coords[0] / grid[0]) - 1;
float v = 2 * ((float)coords[1] / grid[1]) - 1;
eq = f(CMPLX(u, v));
d_surface[0] = u;
d_surface[1] = v;
d_surface[2] = creal(eq);
d_surface[3] = cimag(eq);
}
int main(void)
{
const char *file_name = "riemman.klein";
struct klein klein;
struct parm parametrization = {
.grid = (unsigned char[]){16, 4},
.m = 2,
.n = 4,
.f = riemman,
};
printf("writing %s\n", file_name);
klein_parametrize(&klein, parametrization);
klein_normalize(&klein);
klein_export_file(klein, file_name);
free(klein.vertex);
free(klein.normals);
return 0;
}

48
include/klein/klein.h Normal file
View File

@@ -0,0 +1,48 @@
#ifdef KLEIN_H
#error file included twice
#endif
#define KLEIN_H
#ifdef KLEIN_IMPLEMENT
#include <stdio.h>
#include <stdlib.h>
#endif
struct klein
{
unsigned long vertex_size;
float *vertex, *normals;
unsigned char dim;
};
/*
The klein format must have:
5 bytes with klein.
1 byte empty for expantions
1 byte with the dimention of the surface
*/
static inline
int klein_export_file(struct klein klein, const char * filename);
#ifdef KLEIN_IMPLEMENT
static inline
int klein_export_file(struct klein klein, const char * filename)
{
FILE *file = fopen(filename, "wb");
if (!file)
return 1;
fwrite("KLEIN", 1, 5, file);
fwrite("\0", 1, 1, file);
fwrite(&klein.dim, 1, 1, file);
fwrite(&klein.vertex_size, 8, 1, file);
fwrite(klein.vertex, 4, klein.vertex_size * klein.dim, file);
fwrite(klein.normals, 4, klein.vertex_size * klein.dim, file);
fclose(file);
return 0;
}
#endif

132
include/klein/norm.h Normal file
View File

@@ -0,0 +1,132 @@
#ifdef KLEIN_NORM_H
#error file included twice
#endif
#define KLEIN_NORM_H
#ifndef KLEIN_H
#warning Please include klein/klein.h
#endif
void klein_normalize(struct klein * klein);
#ifdef KLEIN_IMPLEMENT
static inline
void __calculate_normal( float *p1, float *p2, float *p3, float *normal, unsigned char n)
{ unsigned char i;
float alpha;
float *v1, *v2, *v3;
float *u1, *u2, *u3;
v1 = malloc(n * sizeof(float));
v2 = malloc(n * sizeof(float));
v3 = malloc(n * sizeof(float));
u1 = malloc(n * sizeof(float));
u2 = malloc(n * sizeof(float));
u3 = malloc(n * sizeof(float));
/*
Calculate a normal vector of a plain using Gram-Schmidt process
*/
{
for (i = 0; i < n; ++i)
{
v1[i] = p2[i] - p1[i];
v2[i] = p3[i] - p1[i];
v3[i] = p1[i];
}
for (i = 0; i < n; ++i)
{
u1[i] = v1[i];
}
{
float proj[n];
float dot_v2_u1 = 0.0f, dot_u1_u1 = 0.0f;
for (i = 0; i < n; ++i)
{
dot_v2_u1 += v2[i] * u1[i];
dot_u1_u1 += u1[i] * u1[i];
}
alpha = dot_v2_u1 / dot_u1_u1;
for (i = 0; i < n; ++i)
{
proj[i] = u1[i] * alpha;
u2[i] = v2[i] - proj[i];
}
}
{
float proj1[n], proj2[n];
float dot_v3_u1 = 0.0f, dot_u1_u1 = 0.0f;
float dot_v3_u2 = 0.0f, dot_u2_u2 = 0.0f;
for (i = 0; i < n; ++i)
{
dot_v3_u1 += v3[i] * u1[i];
dot_u1_u1 += u1[i] * u1[i];
}
for (i = 0; i < n; ++i)
{
proj1[i] = u1[i] * (dot_v3_u1 / dot_u1_u1);
}
for (i = 0; i < n; ++i)
{
dot_v3_u2 += v3[i] * u2[i];
dot_u2_u2 += u2[i] * u2[i];
}
for (i = 0; i < n; ++i)
{
proj2[i] = u2[i] * (dot_v3_u2 / dot_u2_u2);
u3[i] = v3[i] - proj1[i] - proj2[i];
}
}
float magnitude = 0.0f;
for (i = 0; i < n; ++i)
{
magnitude += u3[i] * u3[i];
}
magnitude = sqrtf(magnitude);
for (i = 0; i < n; ++i)
{
normal[i] = u3[i] / magnitude;
}
free(v1);
free(v2);
free(v3);
free(u1);
free(u2);
free(u3);
return;
}
}
void klein_normalize(struct klein * klein)
{
unsigned long i;
unsigned char j;
float *norm_vec;
klein->normals = malloc((klein->dim * klein->vertex_size) * sizeof(float));
norm_vec = malloc(klein->dim * sizeof(float));
for (i = 0; i < klein->vertex_size; i += 3 * klein->dim)
{
__calculate_normal(klein->vertex + i, klein->vertex + i + klein->dim, klein->vertex + i + 2 * klein->dim, norm_vec, klein->dim);
for (j = 0; j < klein->dim; ++j )
{
(klein->normals + i)[j]=norm_vec[j];
(klein->normals + i + klein->dim)[j]=norm_vec[j];
(klein->normals + i + 2*klein->dim)[j]=norm_vec[j];
}
}
free(norm_vec);
}
#endif

134
include/klein/parm.h Normal file
View File

@@ -0,0 +1,134 @@
#ifndef KLEIN_H
#warning Please include klein/klein.h before klein/parm.h
#endif
#ifdef KLEIN_PARM_H
#error file included twice
#endif
#define KLEIN_PARM_H
typedef void (*function_t)(float *, int *, unsigned char *);
struct parm
{
unsigned char *grid;
unsigned char m, n;
function_t f;
};
void klein_parametrize( struct klein * klein, struct parm parm );
#ifdef KLEIN_IMPLEMENT
#ifdef TEST
#include <assert.h>
#endif
static inline int __factorial(int n)
{
if (n == 1)
return 1;
return n * __factorial(n - 1);
}
static inline int __face(int n)
{
if (n == 2)
return 1;
return (1 << (n - 3)) * __factorial(n) / __factorial(n - 2);
}
void klein_parametrize( struct klein * klein, struct parm parm)
{
unsigned int i, j, k, o, p, n;
unsigned long size, q = 0;
int *face;
#ifdef TEST
assert(__face(2) == 1);
assert(__face(3) == 6);
assert(__face(4) == 24);
#endif
klein->dim = parm.n;
klein->vertex_size = 0;
{
unsigned char test = 0;
for (o = 0; o < parm.m; o++)
{
for (p = 0; p < o; p++)
{
test += 1;
klein->vertex_size += parm.grid[p] * parm.grid[o] * 6 * __face(parm.m);
}
}
klein->vertex_size /= test;
}
size = (klein->dim) * (klein->vertex_size);
klein->vertex = malloc(size * sizeof(float));
face = malloc(parm.m * sizeof(int));
for (o = 0; o < parm.m; o++)
{
for (p = 0; p < o; p++)
{
for (k = 0; k < (1 << (parm.m - 2)); k++)
{
unsigned char skip = 0;
for (n = 0; n < parm.m; n++)
{
if (n == o || n == p)
skip++;
face[n] = (k & (1 << (n - skip))) ? parm.grid[n] : 0;
}
for (i = 0; i < parm.grid[p]; i++)
{
for (j = 0; j < parm.grid[o]; j++)
{
face[p] = i;
face[o] = j;
parm.f(&klein->vertex[q], face, parm.grid);
q += parm.n;
face[p] = i + 1;
face[o] = j;
parm.f(&klein->vertex[q], face, parm.grid);
q += parm.n;
face[p] = i + 1;
face[o] = j + 1;
parm.f(&klein->vertex[q], face, parm.grid);
q += parm.n;
face[p] = i;
face[o] = j;
parm.f(&klein->vertex[q], face, parm.grid);
q += parm.n;
face[p] = i;
face[o] = j + 1;
parm.f(&klein->vertex[q], face, parm.grid);
q += parm.n;
face[p] = i + 1;
face[o] = j + 1;
parm.f(&klein->vertex[q], face, parm.grid);
q += parm.n;
}
}
}
}
}
#ifdef TEST
assert(q == size);
#endif
}
#endif

View File

@@ -9,7 +9,6 @@
void set_clean_color_context(unsigned char r, unsigned char g, unsigned char b)
{
glEnable(GL_DEPTH_TEST);
glClearColor((float)r / 0xff, (float)g / 0xff, (float)b / 0xff, 1.0);
}
@@ -22,4 +21,11 @@ int init_context(void)
#endif
}
void clean_context(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); }
void clean_context(void)
{
/* This is important cos, Nuklear Disable DEPTH TEST */
glEnable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT );
}

View File

@@ -1,40 +0,0 @@
#undef A
#undef B
#undef C
#undef D
#undef E
#undef F
#undef G
#undef H
#define A -2.0,-0.05,-0.05,
#define B -2.0,-0.05, 0.05,
#define C -2.0, 0.05,-0.05,
#define D -2.0, 0.05, 0.05,
#define E 2.0,-0.05,-0.05,
#define F 2.0,-0.05, 0.05,
#define G 2.0, 0.05,-0.05,
#define H 2.0, 0.05, 0.05,
float d_axis[] =
{
3*3*2*6,
A C E
G E C
E G F
H F G
F H B
D B H
B D A
C A D
C D G
H G D
E B A
B E F
};

32
src/data/cube.h Normal file
View File

@@ -0,0 +1,32 @@
#define A -1,-1,-1,
#define B -1,-1, 1,
#define C -1, 1,-1,
#define D -1, 1, 1,
#define E 1,-1,-1,
#define F 1,-1, 1,
#define G 1, 1,-1,
#define H 1, 1, 1,
narray_float_t d_cube =
{
3*3*2*6,
A C E
C E G
E G F
G F H
F H B
H B D
B D A
D A C
C D G
D G H
A B E
B E F
};

View File

@@ -61,7 +61,7 @@ const char *fs_plain =
"void main()"
"{"
" FragColor = vec4(pow(vec3(Color),vec3(1.0/2.2)),Color.a);"
" FragColor = vec4(pow(vec3(Color),vec3(1.0/1.0)),Color.a);"
"}";
const char *fs =
@@ -92,7 +92,7 @@ const char *fs =
" float specular = pow(abs(dot(normalize(Normal), halfwayDir)), 32.0);\n"
" float diffuse = abs(dot(normalize(Normal), lightDir));\n"
" vec3 result = pow((0.5 + 0.5*diffuse + 1.5*specular) * Color.rgb, "
" vec3 result = pow((0.5 + 0.5*diffuse + 1*specular) * Color.rgb, "
"vec3(1.0/2.2));\n"
" FragColor = vec4(result, Color.a);\n"
"}";

83
src/gui.c Normal file
View File

@@ -0,0 +1,83 @@
#include <glad.h>
#include "main.h"
#define MAX_VERTEX_BUFFER 512 * 1024
#define MAX_ELEMENT_BUFFER 128 * 1024
#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#define NK_GLFW_GL3_IMPLEMENTATION
#include <nuklear.h>
#include <demo/glfw_opengl3/nuklear_glfw_gl3.h>
struct gui gui =
{
.file_name = {0},
.projection = (struct projection){ .mesh=NULL, .x =0, .y=1, .z=2 },
};
float surface_color[4] = {(float)0x2F/0xFF, (float)0x3C/0xFF, (float)0x7E/0xFF, (float)0xff/0xFF};
static inline
void restore_surface_color( void )
{
gui.picked_color[0] = surface_color[0];
gui.picked_color[1] = surface_color[1];
gui.picked_color[2] = surface_color[2];
gui.picked_color[3] = surface_color[3];
}
struct nk_glfw glfw ={0};
struct nk_context * context;
void draw_gui( void )
{
nk_glfw3_new_frame(&glfw);
if (nk_begin(context, "MANIGRAPH", nk_rect(10, 10, 256, 256),
NK_WINDOW_BORDER |NK_WINDOW_SCALABLE | NK_WINDOW_MOVABLE | NK_WINDOW_MINIMIZABLE) )
{
/* Color picker para personalización */
{
struct nk_colorf * p = (void*)&gui.picked_color;
nk_layout_row_dynamic(context, 120, 1);
*p = nk_color_picker(context, *p, NK_RGBA);
}
nk_layout_row_dynamic(context, 20, 1);
if (nk_button_label(context, "Restablecer"))
restore_surface_color();
nk_layout_row_dynamic(context, 12, 1);
nk_label(context, (char*)gui.file_name, NK_TEXT_ALIGN_LEFT);
nk_label_colored(context, "Atajos de teclado:", NK_TEXT_ALIGN_LEFT, nk_rgb(255, 255, 255)); // Encabezado
nk_label(context, " - W/S: Rotar eje X", NK_TEXT_ALIGN_LEFT);
nk_label(context, " - A/D: Rotar eje Y", NK_TEXT_ALIGN_LEFT);
nk_label(context, " - Z/X: Rotar eje Z", NK_TEXT_ALIGN_LEFT);
}
nk_end(context);
nk_glfw3_render(&glfw, NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);
}
void init_gui( window_t window )
{
struct nk_font_atlas * atlas;
restore_surface_color();
{
context = nk_glfw3_init(&glfw,(GLFWwindow*) window, NK_GLFW3_DEFAULT );
nk_glfw3_font_stash_begin(&glfw, &atlas);
nk_glfw3_font_stash_end(&glfw);
}
}

View File

@@ -1,15 +1,18 @@
#include "main.h"
#include <glad.h>
#include <GLFW/glfw3.h>
#include <cglm/quat.h>
#include <stdio.h>
#include <string.h>
#define ANGLE ((float)0x01 / 0xff * 2 * GLM_PI)
unsigned char selected_axis = 0;
int window_width;
int window_height;
int window_width = 512;
int window_height = 512;
unsigned char animate_index=0;
unsigned char animate_index = 0;
extern struct gui gui;
versor q = GLM_QUAT_IDENTITY_INIT;
@@ -19,7 +22,13 @@ vec3 axis[3] = {
{0, 0, 1},
};
extern struct projection projection;
void __error_callback_input(int x, const char * msg )
{
mlog("[GLFW] ");
mlog(msg);
mlog("\n");
}
void __key_callback_input(
GLFWwindow *window, int key, int scancode, int action, int mods)
@@ -33,46 +42,45 @@ void __key_callback_input(
selected_coord = key - GLFW_KEY_0 - 1;
if (selected_coord >= projection.m)
if (selected_coord >= gui.projection.m)
return;
if (selected_coord == projection.x)
if (selected_coord == gui.projection.x)
return;
if (selected_coord == projection.y)
if (selected_coord == gui.projection.y)
return;
if (selected_coord == projection.z)
if (selected_coord == gui.projection.z)
return;
selected_coord = projection.w;
selected_coord = gui.projection.w;
}
if (projection.w >= projection.m)
if (gui.projection.w >= gui.projection.m)
return;
switch (key)
{
unsigned char tmp;
case GLFW_KEY_I:
tmp = projection.w;
projection.w = projection.x;
projection.x = tmp;
tmp = gui.projection.w;
gui.projection.w = gui.projection.x;
gui.projection.x = tmp;
animate_index=1;
animate_index = 1;
break;
case GLFW_KEY_O:
tmp = projection.w;
projection.w = projection.y;
projection.y = tmp;
animate_index=2;
tmp = gui.projection.w;
gui.projection.w = gui.projection.y;
gui.projection.y = tmp;
animate_index = 2;
break;
case GLFW_KEY_P:
tmp = projection.w;
projection.w = projection.z;
projection.z = tmp;
animate_index=3;
tmp = gui.projection.w;
gui.projection.w = gui.projection.z;
gui.projection.z = tmp;
animate_index = 3;
break;
}
return;
}
@@ -114,9 +122,9 @@ void __scroll_callback_input(GLFWwindow *window, double xoffset, double yoffset)
versor p = GLM_QUAT_IDENTITY_INIT;
versor r = GLM_QUAT_IDENTITY_INIT;
//glm_quatv(p, yoffset * ANGLE, axis[selected_axis]);
glm_quatv(p, yoffset * ANGLE * 2, (vec3){-1,0,0});
glm_quatv(r, xoffset * ANGLE * 2, (vec3){0,1,0});
// glm_quatv(p, yoffset * ANGLE, axis[selected_axis]);
glm_quatv(p, yoffset * ANGLE * 2, (vec3){-1, 0, 0});
glm_quatv(r, xoffset * ANGLE * 2, (vec3){0, 1, 0});
glm_quat_mul(p, q, q);
glm_quat_mul(r, q, q);
@@ -129,6 +137,25 @@ void __scroll_callback_input(GLFWwindow *window, double xoffset, double yoffset)
glm_quat_rotatev(r, axis[2], axis[2]);
}
void __drop_callback_input(GLFWwindow *window, int count, unsigned char **path)
{
struct surface surface;
if (create_surface_klein(*path, &surface))
return;
if (!(gui.projection.mesh = create_mesh(surface)))
return;
strcpy(gui.file_name, *path);
gui.projection.m = surface.dim;
set_projection_mesh(gui.projection);
free(surface.norm);
free(surface.data);
}
quat_t poll_input(window_t window)
{
versor p = GLM_QUAT_IDENTITY_INIT;
@@ -171,12 +198,5 @@ end:
glm_quat_rotatev(p, axis[2], axis[2]);
glm_quat_normalize(q);
// LOG INFO
if(0)
{
printf("QUAT: %2.5f %2.5f %2.5f %2.5f\n", q[0], q[1], q[2], q[3]);
printf("PROY: %3d %3d %3d (%3d)\n", projection.x, projection.y, projection.z, projection.w );
printf("\n");
}
return q;
}

44
src/klein.c Normal file
View File

@@ -0,0 +1,44 @@
#include "main.h"
#include <stdio.h>
/*
KLEIN Format:
5 bytes with KLEIN
1 byte empty for scaling
1 byte with the dimention of the surface
8 bytes interprated as a long with the number of vertex
n bytes with the vertex data of the surface
n bytes with the normal data of the surface
where n is the size of the vertex and normal data that could be
calculated as the dimention of the surface time the number of vertes
time the size of a 16 bytes float.
*/
int create_surface_klein(unsigned char *path, struct surface *surface)
{
unsigned long size;
char buffer[5];
FILE *file = fopen(path, "rb");
if (!file)
return 1;
fread(buffer, 1, 5, file);
if (strncmp(buffer, "KLEIN", 5))
return 1;
fread(buffer, 1, 1, file);
fread(&surface->dim, 1, 1, file);
fread(&surface->vertex, 8, 1, file);
size = surface->dim * surface->vertex;
surface->data = malloc(4 * size);
fread(surface->data, 4, size, file);
surface->norm = malloc(4 * size);
fread(surface->norm, 4, size, file);
return 0;
}

View File

@@ -22,13 +22,7 @@ void rot_matrix_load(id_t shader, quat_t q)
load_mat4_to_shader(shader, "rot", (mat4_t)m);
}
void color_load(id_t shader, unsigned char color[4])
void color_load(id_t shader, float res[4])
{
float res[4];
res[0] = (float)color[0] / 0xff;
res[1] = (float)color[1] / 0xff;
res[2] = (float)color[2] / 0xff;
res[3] = (float)color[3] / 0xff;
load_float4_to_shader(shader, "color", res);
}

View File

@@ -7,6 +7,11 @@
#define WIDTH 512
#define HEIGHT 512
#include <glad.h>
float *generate_data_surface(unsigned int, unsigned char *);
float *generate_normals_surface(float *, unsigned char);
#ifdef EMSCRIPTEN
#include <emscripten.h>
#endif
@@ -15,14 +20,13 @@
#define M_PI 3.14159
#endif
float *generate_data_surface(unsigned char *, unsigned long *);
float *generate_normals_surface(float *, unsigned char, unsigned long);
struct projection projection = {.x = 0, .y = 1, .z = 2, .w = 3};
window_t window;
id_t shader, shader_plain;
const char *wname = "manigraph: manifold grapher";
unsigned char color[4] = {0x2F, 0x3C, 0x7E, 0xff};
extern volatile unsigned char animate_index;
extern struct gui gui;
void mlog(char *msg)
{
@@ -31,12 +35,6 @@ void mlog(char *msg)
#endif
}
window_t window;
mesh_t m_surface;
id_t shader, shader_plain;
extern volatile unsigned char animate_index;
#ifndef EMSCRIPTEN
static inline
#endif
@@ -48,10 +46,16 @@ static inline
q = poll_input(window);
gui.quat[0] = q[0];
gui.quat[1] = q[1];
gui.quat[2] = q[2];
gui.quat[3] = q[3];
rot_matrix_load(shader, q);
rot_matrix_load(shader_plain, q);
color_load(shader, color);
color_load(shader_plain, color);
color_load(shader, gui.picked_color);
color_load(shader_plain, gui.picked_color);
{
static float angle = 0;
@@ -63,7 +67,7 @@ static inline
load_float_to_shader(shader, "angle", angle);
load_float_to_shader(shader_plain, "angle", angle);
set_projection_mesh(projection);
set_projection_mesh(gui.projection);
}
if (animate_index)
@@ -78,13 +82,19 @@ static inline
}
clean_context();
draw_mesh(shader, m_surface);
draw_mesh_lines(shader_plain, m_surface);
if (gui.projection.mesh)
{
draw_mesh(shader, gui.projection.mesh);
draw_mesh_lines(shader_plain, gui.projection.mesh);
}
draw_gui();
}
int main(void)
{
mlog("[VENTANA] Inicializando...\n");
{
if (!(window = init_window(WIDTH, HEIGHT, wname)))
@@ -130,27 +140,9 @@ int main(void)
fix_matrix_load(shader_plain, (float)WIDTH / HEIGHT);
}
mlog("[MESH] Inicializando...\n");
mlog("[GUI] Inicializando...\n");
{
struct surface surface;
surface.data = generate_data_surface(&surface.dim, &surface.vertex);
surface.norm =
generate_normals_surface(surface.data, surface.dim, surface.vertex);
if (!(m_surface = create_mesh(surface)))
{
mlog("[MESH] Error al inicializar...\n");
goto error_mesh_surface;
}
projection.m = surface.dim;
projection.mesh = m_surface;
set_projection_mesh(projection);
free(surface.norm);
free(surface.data);
init_gui(window);
}
mlog("[MAIN LOOP] Inicializando...\n");
@@ -164,7 +156,7 @@ int main(void)
mlog("[MAIN LOOP] Terminando...\n");
mlog("[MESH] Destruyendo...\n");
destroy_mesh(m_surface);
destroy_mesh(gui.projection.mesh);
mlog("[SHADER] Destruyendo...\n");
destroy_shader(shader_plain);
mlog("[SHADER] Destruyendo...\n");
@@ -174,15 +166,12 @@ int main(void)
return 0;
error_context:
mlog("[MESH] Destruyendo...\n");
destroy_mesh(m_surface);
error_mesh_surface:
mlog("[SHADER] Destruyendo...\n");
destroy_shader(shader_plain);
error_shader_plain:
mlog("[SHADER] Destruyendo...\n");
destroy_shader(shader);
error_shader:
mlog("[SHADER] Destruyendo...\n");
destroy_shader(shader_plain);
error_shader_plain:
mlog("[WINDOW] Destruyendo...\n");
close_window(window);
error_window:

View File

@@ -5,6 +5,7 @@
*/
#define DEBUG
#define GLFW_INCLUDE_NONE
typedef const void *window_t;
typedef unsigned int id_t;
@@ -22,12 +23,19 @@ typedef float *mat4_t;
w: the coordanate of the w axis.
*/
struct projection
struct gui
{
float quat[4];
float picked_color[4];
char file_name[0xff];
struct projection
{
mesh_t mesh;
unsigned char m, x, y, z, w;
} projection;
};
/*
this structure has all the information to generate
a mesh, where:
@@ -36,6 +44,7 @@ struct projection
vertex: the number of vertex
dim: the dimentions of the surface
*/
struct surface
{
float *data, *norm;
@@ -50,6 +59,8 @@ struct surface
name: Name of the window.
*/
int create_surface_klein( unsigned char *, struct surface * );
window_t init_window(unsigned int w, unsigned int h, const char *name);
void use_window(window_t window);
@@ -160,7 +171,7 @@ void rot_matrix_load(id_t shader, quat_t q);
/*
*/
void color_load(id_t shader, unsigned char color[4]);
void color_load(id_t shader, float* color);
id_t config_texture(unsigned short type);
@@ -177,8 +188,5 @@ id_t create_palette_texture(const unsigned char colors[][4], unsigned char n);
quat_t poll_input(window_t window);
#ifdef EMSCRIPTEN
#ifdef GLAD
#error undefine GLAD on src/main.h please
#endif
#endif
void draw_gui( void );
void init_gui( window_t window );

View File

@@ -111,6 +111,7 @@ void draw_mesh_lines(id_t shader, mesh_t p)
#ifndef EMSCRIPTEN
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glDrawArrays(GL_TRIANGLES, 0, obj->vertex);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
#else
glDrawArrays(GL_LINES, 0, obj->vertex);
#endif

View File

@@ -1,400 +0,0 @@
#include <complex.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define TEST
#define CGLM_ALL_UNALIGNED
#include <cglm/vec3.h>
#include <cglm/vec4.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef CMPLX
#define CMPLX(a, b) (a + I * b)
#endif
#ifdef TEST
#include <assert.h>
#endif
#include <stdio.h>
typedef void (*function_t)(float *, int *, unsigned char *);
struct parm
{
unsigned char *grid;
unsigned char m, n;
function_t f;
} parm;
// Función para escribir el archivo .klein
void write_klein_file(const char *filename, unsigned char dim, unsigned long vertex, float *vertices, float *normals)
{
FILE *file = fopen(filename, "wb");
if (!file)
{
perror("Error al abrir el archivo");
exit(EXIT_FAILURE);
}
// Escribir encabezado
fwrite("KLEIN", 1, 5, file); // Los primeros 5 bytes son "KLEIN"
fputc(0, file); // Byte vacío
fwrite(&dim, 1, 1, file); // Dimensión de la superficie
fwrite(&vertex, sizeof(unsigned long), 1, file); // Número de vértices (8 bytes)
// Escribir dimensiones de la cuadrícula
fwrite(parm.grid, sizeof(unsigned char), dim, file);
// Debug info
for (int i = 0; i < dim; i++) {
printf("Grid[%d]: %u\n", i, parm.grid[i]);
}
// Escribir vértices (en float)
fwrite(vertices, sizeof(float), vertex * dim, file);
// Debug info
for (unsigned long i = 0; i < vertex * dim; i++) {
printf("Vertices[%lu]: %f\n", i, vertices[i]);
}
// Escribir normales (en float)
fwrite(normals, sizeof(float), vertex * dim, file);
// Debug info
for (unsigned long i = 0; i < vertex * dim; i++) {
printf("Normals[%lu]: %f\n", i, normals[i]);
}
fclose(file);
printf("Archivo %s escrito correctamente.\n", filename);
}
int factorial(int n)
{
if (n == 1)
return 1;
return n * factorial(n - 1);
}
int faces(int n)
{
if (n == 2)
return 1;
return (1 << (n - 3)) * factorial(n) / factorial(n - 2);
}
void riemman(float *d_surface, int *coords, unsigned char *grid)
{
complex double eq;
float u = 2 * ((float)coords[0] / grid[0]) - 1;
float v = 2 * ((float)coords[1] / grid[1]) - 1;
eq = csqrt(CMPLX(u, v));
d_surface[0] = u;
d_surface[1] = v;
d_surface[2] = creal(eq);
d_surface[3] = cimag(eq);
}
void cube(float *d_surface, int *coord, unsigned char *grid)
{
int i;
for (i = 0; i < parm.m; i++)
d_surface[i] = (2 * (float)coord[i] / grid[i]) - 1;
if (parm.m == 2)
d_surface[2] = 0;
}
void mobius(float *d_surface, int *coord, unsigned char *grid)
{
const float width = 0.5;
float u = (2 * M_PI) * ((float)coord[0] / grid[0]);
float v = (2 * width) * ((float)coord[1] / grid[1]) - width;
d_surface[0] = cos(u) + v * cos(u / 2) * cos(u);
d_surface[1] = sin(u) + v * cos(u / 2) * sin(u);
d_surface[2] = v * sin(u / 2);
}
void torus(float *d_surface, int *coord, unsigned char *grid)
{
float u = (2 * M_PI) * ((float)coord[0] / grid[0]);
float v = (2 * M_PI) * ((float)coord[1] / grid[1]);
d_surface[0] = (1 + 0.5 * cos(v)) * cos(u);
d_surface[1] = (1 + 0.5 * cos(v)) * sin(u);
d_surface[2] = 0.5 * sin(v);
}
void klein(float *d_surface, int *coord, unsigned char *grid)
{
float u = (2 * M_PI) * ((float)coord[0] / grid[0]);
float v = (2 * M_PI) * ((float)coord[1] / grid[1]);
d_surface[0] = (0.5 * cos(v) + 0.5) * cos(u);
d_surface[1] = (0.5 * cos(v) + 0.5) * sin(u);
d_surface[2] = sin(v) * cos(u / 2);
d_surface[3] = sin(v) * sin(u / 2);
}
float *generate_data_surface(unsigned char *dim, unsigned long *vertex)
{
unsigned int i, j, k, o, p, n;
unsigned long size, q = 0;
float *d_surface;
int *cara;
parm.f = cube;
parm.m = 4;
parm.n = 4;
parm.grid = (char[]){16, 8, 4, 2, 1};
#ifdef TEST
assert(faces(2) == 1);
assert(faces(3) == 6);
assert(faces(4) == 24);
#endif
*dim = parm.n;
*vertex = 0;
{
unsigned char test = 0;
for (o = 0; o < parm.m; o++)
{
for (p = 0; p < o; p++)
{
test += 1;
*vertex += parm.grid[p] * parm.grid[o] * 6 * faces(parm.n);
}
}
*vertex /= test;
}
cara = malloc(parm.m * sizeof(int));
size = (*dim) * (*vertex);
d_surface = malloc(size * sizeof(float));
for (o = 0; o < parm.m; o++)
{
for (p = 0; p < o; p++)
{
for (k = 0; k < (1 << (parm.m - 2)); k++)
{
unsigned char skip = 0;
for (n = 0; n < parm.m; n++)
{
if (n == o || n == p)
skip++;
cara[n] = (k & (1 << (n - skip))) ? parm.grid[n] : 0;
}
for (i = 0; i < parm.grid[p]; i++)
{
for (j = 0; j < parm.grid[o]; j++)
{
cara[p] = i;
cara[o] = j;
parm.f(&d_surface[q], cara, parm.grid);
q += parm.n;
cara[p] = i + 1;
cara[o] = j;
parm.f(&d_surface[q], cara, parm.grid);
q += parm.n;
cara[p] = i + 1;
cara[o] = j + 1;
parm.f(&d_surface[q], cara, parm.grid);
q += parm.n;
cara[p] = i;
cara[o] = j;
parm.f(&d_surface[q], cara, parm.grid);
q += parm.n;
cara[p] = i;
cara[o] = j + 1;
parm.f(&d_surface[q], cara, parm.grid);
q += parm.n;
cara[p] = i + 1;
cara[o] = j + 1;
parm.f(&d_surface[q], cara, parm.grid);
q += parm.n;
}
}
}
}
}
#ifdef TEST
assert(q == size);
#endif
return d_surface;
}
static void __calculate_normal(
float *p1, float *p2, float *p3, float *normal, unsigned char n)
{
unsigned char i;
float alpha;
float *v1, *v2, *v3;
float *u1, *u2, *u3;
v1 = malloc(n * sizeof(float));
v2 = malloc(n * sizeof(float));
v3 = malloc(n * sizeof(float));
u1 = malloc(n * sizeof(float));
u2 = malloc(n * sizeof(float));
u3 = malloc(n * sizeof(float));
/*
Calculate a normal vector of a plain using Gram-Schmidt process
*/
{
for (i = 0; i < n; ++i)
{
v1[i] = p2[i] - p1[i];
v2[i] = p3[i] - p1[i];
v3[i] = p1[i];
}
for (i = 0; i < n; ++i)
{
u1[i] = v1[i];
}
{
float proj[n];
float dot_v2_u1 = 0.0f, dot_u1_u1 = 0.0f;
for (i = 0; i < n; ++i)
{
dot_v2_u1 += v2[i] * u1[i];
dot_u1_u1 += u1[i] * u1[i];
}
alpha = dot_v2_u1 / dot_u1_u1;
for (i = 0; i < n; ++i)
{
proj[i] = u1[i] * alpha;
u2[i] = v2[i] - proj[i];
}
}
{
float proj1[n], proj2[n];
float dot_v3_u1 = 0.0f, dot_u1_u1 = 0.0f;
float dot_v3_u2 = 0.0f, dot_u2_u2 = 0.0f;
for (i = 0; i < n; ++i)
{
dot_v3_u1 += v3[i] * u1[i];
dot_u1_u1 += u1[i] * u1[i];
}
for (i = 0; i < n; ++i)
{
proj1[i] = u1[i] * (dot_v3_u1 / dot_u1_u1);
}
for (i = 0; i < n; ++i)
{
dot_v3_u2 += v3[i] * u2[i];
dot_u2_u2 += u2[i] * u2[i];
}
for (i = 0; i < n; ++i)
{
proj2[i] = u2[i] * (dot_v3_u2 / dot_u2_u2);
u3[i] = v3[i] - proj1[i] - proj2[i];
}
}
float magnitude = 0.0f;
for (i = 0; i < n; ++i)
{
magnitude += u3[i] * u3[i];
}
magnitude = sqrtf(magnitude);
for (i = 0; i < n; ++i)
{
normal[i] = u3[i] / magnitude;
}
free(v1);
free(v2);
free(v3);
free(u1);
free(u2);
free(u3);
return;
}
}
float *generate_normals_surface(float *d, unsigned char m, unsigned long vertex)
{
float *n;
float *norm_vec;
n = malloc((m * vertex) * sizeof(float));
norm_vec = malloc(m * sizeof(float));
for (int i = 0; i < *d; i += 3 * m)
{
__calculate_normal(d + i, d + i + m, d + i + 2 * m, norm_vec, m);
glm_vec3_copy(norm_vec, n + i);
glm_vec3_copy(norm_vec, n + i + m);
glm_vec3_copy(norm_vec, n + i + 2 * m);
}
free(norm_vec);
return n;
}
int main()
{
unsigned char dim;
unsigned long vertex;
float *vertices, *normals;
// Generar datos de la superficie
vertices = generate_data_surface(&dim, &vertex);
// Verificar datos generados
if (vertices == NULL) {
printf("Error: vertices no generados.\n");
return 1;
}
printf("Dim: %u, Vertex: %lu\n", dim, vertex);
// Generar normales
normals = generate_normals_surface(vertices, dim, vertex);
// Verificar normales generadas
if (normals == NULL) {
printf("Error: normales no generadas.\n");
free(vertices);
return 1;
}
// Escribir el archivo
printf("Escribiendo archivo .klein\n");
write_klein_file("kingtin.klein", dim, vertex, vertices, normals);
free(vertices);
free(normals);
return 0;
}

View File

@@ -7,6 +7,8 @@ void __window_callback_input(GLFWwindow *, int, int);
void __mouse_callback_input(GLFWwindow *, int, int, int);
void __scroll_callback_input(GLFWwindow *, double, double);
void __key_callback_input(GLFWwindow *, int, int, int, int);
void __drop_callback_input(GLFWwindow *, int, const char **);
void __error_callback_input(int, const char *);
window_t init_window(unsigned int w, unsigned int h, const char *name);
@@ -43,6 +45,7 @@ static void __limit_fps_window(int max_fps)
window_t init_window(unsigned int width, unsigned int height, const char *title)
{
window_t window;
glfwSetErrorCallback(__error_callback_input);
if (!glfwInit())
return NULL;
@@ -50,6 +53,7 @@ window_t init_window(unsigned int width, unsigned int height, const char *title)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, 1);
window = (window_t)glfwCreateWindow(width, height, title, NULL, NULL);
if (!(window))
@@ -64,16 +68,20 @@ window_t init_window(unsigned int width, unsigned int height, const char *title)
glfwSetMouseButtonCallback((GLFWwindow *)window, __mouse_callback_input);
glfwSetScrollCallback((GLFWwindow *)window, __scroll_callback_input);
glfwSetKeyCallback((GLFWwindow *)window, __key_callback_input);
__window_callback_input((GLFWwindow *)window, width, height);
glfwSetDropCallback((GLFWwindow *)window, __drop_callback_input);
return window;
}
void use_window(window_t window) { glfwMakeContextCurrent((void *)window); }
extern int window_width, window_height;
int is_open_window(window_t window)
{
/* Restore window proportions if Nuklear breaks it */
__window_callback_input((GLFWwindow *)window, window_width, window_height);
glfwSwapBuffers((void *)window);
glfwPollEvents();