Hello,
write for the first time in this forum and wanted a small project to practice with ports and communication between C and Elixir. I chose SDL2, because there are enough tutorials to test it. In Elixir I only saw projects via Nif so far.
As a template I used the code from the page
https://cultivatehq.com/posts/communicating-with-c-from-elixir-using-ports/
which I have adapted accordingly for my project.
So far I only put in a few commands to show the first few tutorials of
[Lazy Foo' Productions - Beginning Game Programming v2.0]
to be able to port to Elixir
This is the C - main Code
#include "sdlCom.h"
#include "myfuncs.h"
#include "myfuncs2.h"
#define MAX_READ 1024
void process_command(char *buf, int bytes_read);
//////////////////////////////////////////////////////////////////////////////
int main(int argc, char *argv[]) {
char buffer[MAX_READ];
for(;;) {
int res = poll_input();
if(res > 0) {
int len = to_read_length();
if (len > MAX_READ) err(EXIT_FAILURE, "Too large message to read.");
// len being less than zero indicates STDIN has been closed - exit
if (len < 0) return 1;
read_in(buffer, len);
process_command(buffer, len);
}
}
}
//////////////////////////////////////////////////////////////////////////////
void process_command(char *buf, int bytes_read) {
int size=0, fn;
char **param=NULL;
if (bytes_read > 0){
param=getToken(buf,':', &size);
if (!param) exit(1);
fn=atoi(param[0]);
funcPtr[fn](buf, param);
free(param);
}
else if(bytes_read < 0) {
exit(1);
}
}
Then my own Parameter - Split - Funktion
#ifndef _MYFUNCS_H
#define _MYFUNCS_H
const int SIZE = sizeof(char*);
const int MAX_PARAM = 8;
char** getToken(const char* text, const char sep, int *anz){ // meine Parameter Split Version (ähnlich strtok)
int x=0;
char** token=NULL;
char* temp = text;
token = (char**) malloc(SIZE * MAX_PARAM);
if (token) {
token[0] = temp;
while(*temp){ // ersetze alle Trennzeichen durch '\0'
if (*temp == sep){
*temp = '\0';
token[++x] = ++temp; // Zeiger in die Token-Liste einfügen eine Stelle hinter dem NULL-Zeichen
}
++temp;
}
*anz=x;
}
return token;
}
#endif
#ifndef _MYFUNCS2_H
#define _MYFUNCS2_H
#include <SDL2/SDL.h>
typedef inline void(*fPtr)(char*, char**);
inline void WMEM(char* mem, void* p){
int64_t speicher = (int64_t)p;
sprintf(mem, "%ld", speicher);
write_back(mem);
}
#define GMEM(obj, var, mem)\
SDL_##obj* var = (SDL_##obj*)atol(mem)
#define MEM(obj, var, anz)\
SDL_##obj* var = (SDL_##obj*) malloc(sizeof(SDL_##obj) * anz)
#define FUNC(name, expr) \
void name(char* memory, char** pm){ \
expr \
}
FUNC(init, int erg=SDL_Init(SDL_INIT_EVERYTHING);
WMEM(memory, erg);
)
FUNC(quit, SDL_Quit(); )
FUNC(createWindow,
SDL_Window* win = SDL_CreateWindow(pm[1], SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, atoi(pm[2]), atoi(pm[3]), SDL_WINDOW_SHOWN);
WMEM(memory, win);
)
FUNC(destroyWindow,
GMEM(Window, win, pm[1]);
SDL_DestroyWindow(win);
)
FUNC(delay, SDL_Delay(atoi(pm[1])); )
FUNC(getWindowSurface,
GMEM(Window, win, pm[1]);
SDL_Surface* surface=SDL_GetWindowSurface(win);
WMEM(memory, surface);
)
FUNC(loadBMP,
SDL_Surface* surface=SDL_LoadBMP(pm[1]);
WMEM(memory, surface);
)
FUNC(updateWindowSurface,
GMEM(Window, win, pm[1]);
SDL_UpdateWindowSurface(win);
)
FUNC(blitSurface,
GMEM(Surface, image, pm[1]);
GMEM(Rect, srcRect, pm[2]);
GMEM(Surface, screen, pm[3]);
GMEM(Rect, dstRect, pm[4]);
SDL_BlitSurface(image, srcRect, screen, dstRect);
)
FUNC(freeSurface,
GMEM(Surface, surface, pm[1]);
SDL_FreeSurface(surface);
)
FUNC(createRect,
MEM(Rect, rect, 1);//SDL_Rect* rect = (SDL_Rect*) malloc(sizeof(SDL_Rect));
rect->x=atoi(pm[1]);
rect->y=atoi(pm[2]);
rect->w=atoi(pm[3]);
rect->h=atoi(pm[4]);
WMEM(memory, rect);
)
FUNC(freeRect,
GMEM(Rect, rect, pm[1]);
free(rect);
)
FUNC(pollEvent,
SDL_Event e;
int i = SDL_PollEvent(&e);
WMEM(memory, i);
WMEM(memory, e.type);
WMEM(memory, e.key.keysym.sym);
)
FUNC(getKeyName,
const char* name = SDL_GetKeyName(atoi(pm[1]));
strcpy(memory, name); memory[strlen(name)+1]='\0';
write_back(memory);
)
fPtr funcPtr[]={init,quit,createWindow,destroyWindow,delay,getWindowSurface,
loadBMP, updateWindowSurface, blitSurface, freeSurface,
createRect, freeRect, pollEvent, getKeyName};
#endif
Elixir - Code for SDL
defmodule ESDL.Event do
def type() do
%{QUIT: 0x100, KEYDOWN: 0x300, KEYUP: 0x301,
MOUSEMOTION: 0x400, MOUSEBUTTONDOWN: 0x401,
MOUSEBUTTONUP: 0x402, MOUSEWHEEL: 0x403}
end
end
defmodule ESDL do
def initModule() do Port.open({:spawn, "./sdlCom"}, [{:packet, 2}]) end
def get(p) do
receive do
{^p, {:data, result}} -> result
end
end
def init(p) do
Port.command(p, ["0"])
List.to_integer(get(p))
end
def quit(p) do Port.command(p, ["1"]) end
def createWindow(p, title, width, height) do
Port.command(p, ["2:#{title}:#{width}:#{height}"])
get(p)
end
def destroyWindow(p, win) do Port.command(p, ["3:#{win}"]) end
def delay(p, t) do Port.command(p, ["4:#{t}"]) end
def getWindowSurface(p, win) do
Port.command(p, ["5:#{win}"])
get(p)
end
def loadBMP(p, pic) do
Port.command(p, ["6:#{pic}"])
get(p)
end
def updateWindowSurface(p, win) do Port.command(p, ["7:#{win}"]) end
def blitSurface(p, src, srcRec, dst, dstRec) do Port.command(p, ["8:#{src}:#{srcRec}:#{dst}:#{dstRec}"]) end
def freeSurface(p, surface) do Port.command(p, ["9:#{surface}"]) end
def createRect(p, x, y, width, height) do
Port.command(p, ["10:#{x}:#{y}:#{width}:#{height}"])
get(p)
end
def deletRect(p, ptrRect) do Port.command(p, ["11:#{ptrRect}"]) end
def pollEvent(p) do
Port.command(p, ["12"])
i = List.to_integer(get(p))
type = List.to_integer(get(p))
key = List.to_integer(get(p))
{i, type, key}
end
def getKeyName(p, keyCode) do
Port.command(p, ["13:#{keyCode}"])
get(p)
end
end
defmodule ESDL.Loop do
def start(p, win, image, screen, loop) do
if (loop > 0) do
ESDL.delay(p,10)
ESDL.blitSurface(p, image, NULL, screen, NULL)
ESDL.updateWindowSurface(p, win)
{_i, event, key} = ESDL.pollEvent(p)
#keyName = ESDL.getKeyName(p, key);
if (event != ESDL.Event.type()[:QUIT] && key != 32) do
if (event == ESDL.Event.type()[:KEYDOWN]) do
IO.puts "#{key} pressed!"
end
start(p, win, image, screen, loop)
end
end
end
end
p= ESDL.initModule()
result = ESDL.init(p)
if result == 0 do
win = ESDL.createWindow(p,"SDL-Test", 640, 480)
screen = ESDL.getWindowSurface(p, win)
image = ESDL.loadBMP(p,"./hello_world.bmp")
ESDL.Loop.start(p, win, image, screen, 1)
ESDL.freeSurface(p, image)
ESDL.destroyWindow(p,win)
ESDL.quit(p)
end
best regards
Michael