add tilemap
This commit is contained in:
@@ -75,13 +75,6 @@ draw.point = function(pos, size, opt = {}, material) {
|
||||
material: material
|
||||
})
|
||||
}
|
||||
draw.point[cell.DOC] = `
|
||||
:param pos: A 2D position ([x, y]) where the point should be drawn.
|
||||
:param size: The size of the point.
|
||||
:param opt: Optional geometry properties.
|
||||
:param material: Material/styling information (color, shaders, etc.)
|
||||
:return: None
|
||||
`
|
||||
|
||||
draw.ellipse = function(pos, radii, def, material) {
|
||||
var opt = def ? {...ellipse_def, ...def} : ellipse_def
|
||||
|
||||
@@ -3,7 +3,7 @@ var io = use('io');
|
||||
var transform = use('transform');
|
||||
var rasterize = use('rasterize');
|
||||
var time = use('time')
|
||||
var num = use('num');
|
||||
var tilemap = use('tilemap')
|
||||
|
||||
// Frame timing variables
|
||||
var frame_times = []
|
||||
@@ -32,9 +32,6 @@ $_.start(e => {
|
||||
})
|
||||
}, 'prosperon/sdl_video', cnf)
|
||||
|
||||
|
||||
var input = use('input')
|
||||
|
||||
var geometry = use('geometry')
|
||||
|
||||
function updateCameraMatrix(camera, winW, winH) {
|
||||
@@ -101,7 +98,6 @@ function worldToScreenRect(rect, camera) {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
var camera = {
|
||||
size: [640,480],//{width:500,height:500}, // pixel size the camera "sees", like its resolution
|
||||
pos: [250,250],//{x:0,y:0}, // where it is
|
||||
@@ -256,6 +252,22 @@ function translate_draw_commands(commands) {
|
||||
}
|
||||
})
|
||||
break
|
||||
|
||||
case "tilemap":
|
||||
var texid
|
||||
tilemap.for(cmd.tilemap, (tile,{x,y}) => {
|
||||
if (!texid) texid = graphics.texture(tile)
|
||||
return graphics.texture(tile)
|
||||
})
|
||||
var geom = geometry.tilemap_to_data(cmd.tilemap)
|
||||
if (texid.gpu)
|
||||
geom.texture_id = texid.gpu.id
|
||||
|
||||
renderer_commands.push({
|
||||
op: "geometry_raw",
|
||||
data: geom
|
||||
})
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
@@ -289,12 +301,36 @@ var last_time = time.number()
|
||||
var frames = []
|
||||
var frame_avg = 0
|
||||
|
||||
var input = use('input')
|
||||
|
||||
var input_state = {
|
||||
poll: 1/60
|
||||
}
|
||||
|
||||
// 1) input runs completely independently
|
||||
function poll_input() {
|
||||
send(video, {kind:'input', op:'get'}, evs => {
|
||||
for (let ev of evs) if (ev.type === 'quit') $_.stop()
|
||||
for (var ev of evs) {
|
||||
if (ev.type === 'quit')
|
||||
$_.stop()
|
||||
|
||||
if (ev.type.includes('mouse')) {
|
||||
if (ev.pos)
|
||||
ev.pos = screenToWorldPoint(ev.pos, camera, 500,500)
|
||||
|
||||
if (ev.d_pos)
|
||||
ev.d_pos.y *= -1
|
||||
}
|
||||
|
||||
if (ev.type.includes('key')) {
|
||||
if (ev.key)
|
||||
ev.key = input.keyname(ev.key)
|
||||
}
|
||||
}
|
||||
|
||||
send(gameactor, evs)
|
||||
})
|
||||
$_.delay(poll_input, 1/60)
|
||||
$_.delay(poll_input, input_state.poll)
|
||||
}
|
||||
|
||||
// 2) helper to build & send a batch, then call done()
|
||||
@@ -361,20 +397,8 @@ function render_step() {
|
||||
}
|
||||
|
||||
|
||||
|
||||
$_.receiver(e => {
|
||||
if (e.type) {
|
||||
if (e.type === 'quit')
|
||||
$_.stop()
|
||||
|
||||
if (e.type.includes('mouse')) {
|
||||
if (e.pos)
|
||||
e.pos = screenToWorldPoint(e.pos, camera, 500, 500)
|
||||
|
||||
if (e.d_pos)
|
||||
e.d_pos.y *= -1
|
||||
}
|
||||
}
|
||||
|
||||
switch(e.op) {
|
||||
case 'resolution':
|
||||
log.console(json.encode(e))
|
||||
|
||||
@@ -360,6 +360,11 @@ var renderfuncs = {
|
||||
return {success: true};
|
||||
},
|
||||
|
||||
geometry_raw: function geometry_raw(msg) {
|
||||
var geom = msg.data
|
||||
ren.geometry_raw(resources.texture[geom.texture_id], geom.xy, geom.xy_stride, geom.color, geom.color_stride, geom.uv, geom.uv_stride, geom.num_vertices, geom.indices, geom.num_indices, geom.size_indices);
|
||||
},
|
||||
|
||||
debugText: function(msg) {
|
||||
if (!msg.data || !msg.data.text) return {error: "Missing text"};
|
||||
ren.debugText([msg.data.pos.x, msg.data.pos.y], msg.data.text);
|
||||
|
||||
78
prosperon/tilemap.cm
Normal file
78
prosperon/tilemap.cm
Normal file
@@ -0,0 +1,78 @@
|
||||
// tilemap
|
||||
|
||||
function tilemap()
|
||||
{
|
||||
this.tiles = [];
|
||||
this.offset_x = 0;
|
||||
this.offset_y = 0;
|
||||
this.size_x = 32;
|
||||
this.size_y = 32;
|
||||
return this;
|
||||
}
|
||||
|
||||
tilemap.for = function (map, fn) {
|
||||
for (var x = 0; x < map.tiles.length; x++) {
|
||||
if (!map.tiles[x]) continue;
|
||||
for (var y = 0; y < map.tiles[x].length; y++) {
|
||||
if (map.tiles[x][y] !== undefined) {
|
||||
var result = fn(map.tiles[x][y], {
|
||||
x: x + map.offset_x,
|
||||
y: y + map.offset_y
|
||||
});
|
||||
if (result !== undefined) {
|
||||
map.tiles[x][y] = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tilemap.prototype =
|
||||
{
|
||||
at(pos) {
|
||||
var x = pos.x - this.offset_x;
|
||||
var y = pos.y - this.offset_y;
|
||||
if (!this.tiles[x]) return undefined;
|
||||
return this.tiles[x][y];
|
||||
},
|
||||
|
||||
set(pos, image) {
|
||||
// Shift arrays if negative indices
|
||||
if (pos.x < this.offset_x) {
|
||||
var shift = this.offset_x - pos.x;
|
||||
var new_tiles = [];
|
||||
for (var i = 0; i < shift; i++) new_tiles[i] = [];
|
||||
this.tiles = new_tiles.concat(this.tiles);
|
||||
this.offset_x = pos.x;
|
||||
}
|
||||
|
||||
if (pos.y < this.offset_y) {
|
||||
var shift = this.offset_y - pos.y;
|
||||
for (var i = 0; i < this.tiles.length; i++) {
|
||||
if (!this.tiles[i]) this.tiles[i] = [];
|
||||
var new_col = [];
|
||||
for (var j = 0; j < shift; j++) new_col[j] = undefined;
|
||||
this.tiles[i] = new_col.concat(this.tiles[i]);
|
||||
}
|
||||
this.offset_y = pos.y;
|
||||
}
|
||||
|
||||
var x = pos.x - this.offset_x;
|
||||
var y = pos.y - this.offset_y;
|
||||
|
||||
// Ensure array exists up to x
|
||||
while (this.tiles.length <= x) this.tiles.push([]);
|
||||
|
||||
// Set the value
|
||||
this.tiles[x][y] = image;
|
||||
},
|
||||
|
||||
draw() {
|
||||
return {
|
||||
cmd:'tilemap',
|
||||
tilemap:this
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return tilemap
|
||||
@@ -43,7 +43,7 @@ var console_mod = cell.hidden.console
|
||||
var logs = {}
|
||||
logs.console = function(msg)
|
||||
{
|
||||
var caller = caller_data(4)
|
||||
var caller = caller_data(2)
|
||||
console_mod.print(console_rec(caller.line, caller.file, msg))
|
||||
}
|
||||
|
||||
|
||||
@@ -243,7 +243,6 @@ static inline void tile_region(text_vert **verts, rect src_uv, rect dst, float t
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JSC_CCALL(gpu_slice9,
|
||||
JSValue jstex = argv[0];
|
||||
rect dst = js2rect(js, argv[1]);
|
||||
@@ -808,6 +807,153 @@ JSC_CCALL(geometry_rect_transform,
|
||||
return rect2js(js, newrect);
|
||||
)
|
||||
|
||||
JSC_CCALL(geometry_tilemap_to_data,
|
||||
JSValue tilemap_obj = argv[0];
|
||||
|
||||
// Get tilemap properties
|
||||
double offset_x, offset_y, size_x, size_y;
|
||||
JS_GETPROP(js, offset_x, tilemap_obj, offset_x, number)
|
||||
JS_GETPROP(js, offset_y, tilemap_obj, offset_y, number)
|
||||
JS_GETPROP(js, size_x, tilemap_obj, size_x, number)
|
||||
JS_GETPROP(js, size_y, tilemap_obj, size_y, number)
|
||||
|
||||
JSValue tiles_array = JS_GetPropertyStr(js, tilemap_obj, "tiles");
|
||||
if (!JS_IsArray(js, tiles_array)) {
|
||||
JS_FreeValue(js, tiles_array);
|
||||
return JS_ThrowTypeError(js, "tilemap.tiles must be an array");
|
||||
}
|
||||
|
||||
// Count tiles
|
||||
int tile_count = 0;
|
||||
int tiles_len = JS_ArrayLength(js, tiles_array);
|
||||
for (int x = 0; x < tiles_len; x++) {
|
||||
JSValue col = JS_GetPropertyUint32(js, tiles_array, x);
|
||||
if (JS_IsArray(js, col)) {
|
||||
int col_len = JS_ArrayLength(js, col);
|
||||
for (int y = 0; y < col_len; y++) {
|
||||
JSValue tile = JS_GetPropertyUint32(js, col, y);
|
||||
if (!JS_IsUndefined(tile) && !JS_IsNull(tile)) {
|
||||
tile_count++;
|
||||
}
|
||||
JS_FreeValue(js, tile);
|
||||
}
|
||||
}
|
||||
JS_FreeValue(js, col);
|
||||
}
|
||||
|
||||
if (tile_count == 0) {
|
||||
JS_FreeValue(js, tiles_array);
|
||||
return JS_NewObject(js);
|
||||
}
|
||||
|
||||
// Allocate buffers - 4 vertices per tile
|
||||
int vertex_count = tile_count * 4;
|
||||
int index_count = tile_count * 6;
|
||||
|
||||
float *xy_data = malloc(vertex_count * 2 * sizeof(float));
|
||||
float *uv_data = malloc(vertex_count * 2 * sizeof(float));
|
||||
SDL_FColor *color_data = malloc(vertex_count * sizeof(SDL_FColor));
|
||||
uint16_t *index_data = malloc(index_count * sizeof(uint16_t));
|
||||
|
||||
// Generate vertices
|
||||
int vertex_idx = 0;
|
||||
int index_idx = 0;
|
||||
|
||||
for (int x = 0; x < tiles_len; x++) {
|
||||
JSValue col = JS_GetPropertyUint32(js, tiles_array, x);
|
||||
if (JS_IsArray(js, col)) {
|
||||
int col_len = JS_ArrayLength(js, col);
|
||||
for (int y = 0; y < col_len; y++) {
|
||||
JSValue tile = JS_GetPropertyUint32(js, col, y);
|
||||
if (!JS_IsUndefined(tile) && !JS_IsNull(tile)) {
|
||||
// Calculate world position
|
||||
float world_x = (x + offset_x) * size_x;
|
||||
float world_y = (y + offset_y) * size_y;
|
||||
|
||||
// Set vertex positions (4 corners of the tile)
|
||||
int base = vertex_idx * 2;
|
||||
xy_data[base + 0] = world_x;
|
||||
xy_data[base + 1] = world_y;
|
||||
xy_data[base + 2] = world_x + size_x;
|
||||
xy_data[base + 3] = world_y;
|
||||
xy_data[base + 4] = world_x;
|
||||
xy_data[base + 5] = world_y + size_y;
|
||||
xy_data[base + 6] = world_x + size_x;
|
||||
xy_data[base + 7] = world_y + size_y;
|
||||
|
||||
// Set UVs (normalized 0-1 for now)
|
||||
uv_data[base + 0] = 0.0f;
|
||||
uv_data[base + 1] = 0.0f;
|
||||
uv_data[base + 2] = 1.0f;
|
||||
uv_data[base + 3] = 0.0f;
|
||||
uv_data[base + 4] = 0.0f;
|
||||
uv_data[base + 5] = 1.0f;
|
||||
uv_data[base + 6] = 1.0f;
|
||||
uv_data[base + 7] = 1.0f;
|
||||
|
||||
// Set colors (check if tile has color property)
|
||||
SDL_FColor default_color = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
if (JS_IsObject(tile)) {
|
||||
JSValue color_val = JS_GetPropertyStr(js, tile, "color");
|
||||
if (!JS_IsUndefined(color_val)) {
|
||||
HMM_Vec4 color = js2color(js, color_val);
|
||||
default_color.r = color.r;
|
||||
default_color.g = color.g;
|
||||
default_color.b = color.b;
|
||||
default_color.a = color.a;
|
||||
JS_FreeValue(js, color_val);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
color_data[vertex_idx + i] = default_color;
|
||||
}
|
||||
|
||||
// Set indices (two triangles per tile)
|
||||
uint16_t base_idx = vertex_idx;
|
||||
index_data[index_idx++] = base_idx + 0;
|
||||
index_data[index_idx++] = base_idx + 1;
|
||||
index_data[index_idx++] = base_idx + 2;
|
||||
index_data[index_idx++] = base_idx + 1;
|
||||
index_data[index_idx++] = base_idx + 3;
|
||||
index_data[index_idx++] = base_idx + 2;
|
||||
|
||||
vertex_idx += 4;
|
||||
}
|
||||
JS_FreeValue(js, tile);
|
||||
}
|
||||
}
|
||||
JS_FreeValue(js, col);
|
||||
}
|
||||
|
||||
JS_FreeValue(js, tiles_array);
|
||||
|
||||
// Create result object with blob data
|
||||
ret = JS_NewObject(js);
|
||||
|
||||
// Create blobs for each data type
|
||||
JSValue xy_blob = js_new_blob_stoned_copy(js, xy_data, vertex_count * 2 * sizeof(float));
|
||||
JSValue uv_blob = js_new_blob_stoned_copy(js, uv_data, vertex_count * 2 * sizeof(float));
|
||||
JSValue color_blob = js_new_blob_stoned_copy(js, color_data, vertex_count * sizeof(SDL_FColor));
|
||||
JSValue index_blob = js_new_blob_stoned_copy(js, index_data, index_count * sizeof(uint16_t));
|
||||
|
||||
JS_SetPropertyStr(js, ret, "xy", xy_blob);
|
||||
JS_SetPropertyStr(js, ret, "xy_stride", JS_NewInt32(js, 2 * sizeof(float)));
|
||||
JS_SetPropertyStr(js, ret, "uv", uv_blob);
|
||||
JS_SetPropertyStr(js, ret, "uv_stride", JS_NewInt32(js, 2 * sizeof(float)));
|
||||
JS_SetPropertyStr(js, ret, "color", color_blob);
|
||||
JS_SetPropertyStr(js, ret, "color_stride", JS_NewInt32(js, sizeof(SDL_FColor)));
|
||||
JS_SetPropertyStr(js, ret, "indices", index_blob);
|
||||
JS_SetPropertyStr(js, ret, "num_vertices", JS_NewInt32(js, vertex_count));
|
||||
JS_SetPropertyStr(js, ret, "num_indices", JS_NewInt32(js, index_count));
|
||||
JS_SetPropertyStr(js, ret, "size_indices", JS_NewInt32(js, 2)); // using uint16_t
|
||||
|
||||
free(xy_data);
|
||||
free(uv_data);
|
||||
free(color_data);
|
||||
free(index_data);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_geometry_funcs[] = {
|
||||
MIST_FUNC_DEF(geometry, rect_intersection, 2),
|
||||
MIST_FUNC_DEF(geometry, rect_intersects, 2),
|
||||
@@ -819,6 +965,7 @@ static const JSCFunctionListEntry js_geometry_funcs[] = {
|
||||
MIST_FUNC_DEF(geometry, rect_pos, 1),
|
||||
MIST_FUNC_DEF(geometry, rect_move, 2),
|
||||
MIST_FUNC_DEF(geometry, rect_transform, 2),
|
||||
MIST_FUNC_DEF(geometry, tilemap_to_data, 1),
|
||||
MIST_FUNC_DEF(gpu, tile, 4),
|
||||
MIST_FUNC_DEF(gpu, slice9, 3),
|
||||
MIST_FUNC_DEF(gpu, make_sprite_mesh, 2),
|
||||
|
||||
@@ -888,6 +888,39 @@ JSC_CCALL(renderer_geometry,
|
||||
JS_FreeValue(js,indices);
|
||||
)
|
||||
|
||||
JSC_CCALL(renderer_geometry_raw,
|
||||
SDL_Renderer *r = js2SDL_Renderer(js,self);
|
||||
|
||||
// argv[0] is texture
|
||||
SDL_Texture *tex = NULL;
|
||||
if (argc > 0 && !JS_IsNull(argv[0]) && !JS_IsUndefined(argv[0]))
|
||||
tex = js2SDL_Texture(js,argv[0]);
|
||||
|
||||
// Get blob data
|
||||
size_t xy_size, color_size, uv_size, indices_size;
|
||||
void *xy_data = js_get_blob_data(js, &xy_size, argv[1]);
|
||||
int xy_stride = js2number(js, argv[2]);
|
||||
void *color_data = js_get_blob_data(js, &color_size, argv[3]);
|
||||
int color_stride = js2number(js, argv[4]);
|
||||
void *uv_data = js_get_blob_data(js, &uv_size, argv[5]);
|
||||
int uv_stride = js2number(js, argv[6]);
|
||||
int num_vertices = js2number(js, argv[7]);
|
||||
void *indices_data = js_get_blob_data(js, &indices_size, argv[8]);
|
||||
int num_indices = js2number(js, argv[9]);
|
||||
int size_indices = js2number(js, argv[10]);
|
||||
|
||||
if (!xy_data || !color_data || !uv_data)
|
||||
return JS_ThrowTypeError(js, "Invalid geometry data");
|
||||
|
||||
if (!SDL_RenderGeometryRaw(r, tex,
|
||||
(const float *)xy_data, xy_stride,
|
||||
(const SDL_FColor *)color_data, color_stride,
|
||||
(const float *)uv_data, uv_stride,
|
||||
num_vertices,
|
||||
indices_data, num_indices, size_indices))
|
||||
return JS_ThrowReferenceError(js, "Error rendering geometry: %s", SDL_GetError());
|
||||
)
|
||||
|
||||
JSC_CCALL(renderer_geometry2,
|
||||
SDL_Renderer *r = js2SDL_Renderer(js, self);
|
||||
|
||||
@@ -1378,6 +1411,7 @@ static const JSCFunctionListEntry js_SDL_Renderer_funcs[] = {
|
||||
MIST_FUNC_DEF(renderer, texture, 5),
|
||||
MIST_FUNC_DEF(renderer, rects, 1),
|
||||
MIST_FUNC_DEF(renderer, geometry, 2),
|
||||
MIST_FUNC_DEF(renderer, geometry_raw, 11),
|
||||
MIST_FUNC_DEF(renderer, geometry2, 2),
|
||||
MIST_FUNC_DEF(renderer, sprite, 1),
|
||||
MIST_FUNC_DEF(renderer, load_texture, 1),
|
||||
|
||||
Reference in New Issue
Block a user