diff --git a/docs/sphere2-core-api.txt b/docs/sphere2-core-api.txt index 20df1552b..736a3802d 100644 --- a/docs/sphere2-core-api.txt +++ b/docs/sphere2-core-api.txt @@ -2159,6 +2159,34 @@ new Surface(width, height[, content]); [API 1] enough pixel data to cover the entire surface, a RangeError will be thrown. +new Surface(width, height[, options]); [NEW] + + Constructs a new Surface with the specified options. `width` and `height` + specify the size in pixels of the surface. + + The following are all optional: + + options.color + A `Color` with which the surface will be filled. The default is + `Color.Transparent`. + + options.content: + A buffer object holding the RGBA pixel data to use to initialize the + image. The pixel data should not be padded (i.e. stride equal to + width). + + options.multisample + The number of samples to use for multisample antialiasing. The default + value is 0, which means multisampling is not enabled. A value of 1 + would mean one sample per pixel, effectively the same as not being + enabled. Normal values would be multiples of 2. + + This effectively multiplies the resolution of the texture by the value + you choose internally, so can have a large effect on performance and + texture size. + + If `content` is specified, both `color` and `multisample` will be ignored. + new Surface(filename); [API 1] Loads the image file named by `filename` synchronously, without yielding to @@ -2276,6 +2304,34 @@ new Texture(width, height[, content]); [API 1] enough pixel data to cover the entire texture, a RangeError will be thrown. +new Texture(width, height[, options]); [NEW] + + Constructs a new Texture with the specified options. `width` and `height` + specify the size in pixels of the surface. + + The following are all optional: + + options.color + A `Color` with which the texture will be filled. The default is + `Color.Transparent`. + + options.content: + A buffer object holding the RGBA pixel data to use to initialize the + image. The pixel data should not be padded (i.e. stride equal to + width). + + options.multisample + The number of samples to use for multisample antialiasing. The default + value is 0, which means multisampling is not enabled. A value of 1 + would mean one sample per pixel, effectively the same as not being + enabled. Normal values would be multiples of 2. + + This effectively multiplies the resolution of the texture by the value + you choose internally, so can have a large effect on performance and + texture size. + + If `content` is specified, both `color` and `multisample` will be ignored. + new Texture(surface); [API 1] Constructs a new Texture from the contents of `surface`, a Surface object. diff --git a/src/minisphere/animation.c b/src/minisphere/animation.c index 62f4315f7..913127aea 100644 --- a/src/minisphere/animation.c +++ b/src/minisphere/animation.c @@ -221,7 +221,7 @@ mng_cb_processheader(mng_handle stream, mng_uint32 width, mng_uint32 height) anim->w = width; anim->h = height; image_unref(anim->frame); - if (!(anim->frame = image_new(anim->w, anim->h, NULL))) + if (!(anim->frame = image_new(anim->w, anim->h, NULL, 0))) goto on_error; mng_set_canvasstyle(stream, MNG_CANVAS_RGBA8); return MNG_TRUE; diff --git a/src/minisphere/atlas.c b/src/minisphere/atlas.c index 39ecb404b..4df6a3182 100644 --- a/src/minisphere/atlas.c +++ b/src/minisphere/atlas.c @@ -61,7 +61,7 @@ atlas_new(int num_images, int max_width, int max_height) atlas->max_width = max_width; atlas->max_height = max_height; atlas->size = mk_rect(0, 0, atlas->pitch * atlas->max_width, atlas->pitch * atlas->max_height); - if (!(atlas->image = image_new(atlas->size.x2, atlas->size.y2, NULL))) + if (!(atlas->image = image_new(atlas->size.x2, atlas->size.y2, NULL, 0))) goto on_error; atlas->id = s_next_atlas_id++; diff --git a/src/minisphere/font.c b/src/minisphere/font.c index 30ccc6138..3c34bd34c 100644 --- a/src/minisphere/font.c +++ b/src/minisphere/font.c @@ -159,7 +159,7 @@ font_load(const char* filename) n_glyphs_per_row = ceil(sqrt(rfn.num_chars)); atlas_size_x = max_x * n_glyphs_per_row; atlas_size_y = max_y * n_glyphs_per_row; - if ((atlas = image_new(atlas_size_x, atlas_size_y, NULL)) == NULL) + if ((atlas = image_new(atlas_size_x, atlas_size_y, NULL, 0)) == NULL) goto on_error; // pass 2: load glyph data diff --git a/src/minisphere/galileo.c b/src/minisphere/galileo.c index b4cc25ba7..a79498a4c 100644 --- a/src/minisphere/galileo.c +++ b/src/minisphere/galileo.c @@ -409,10 +409,27 @@ shader_ref(shader_t* it) void shader_unref(shader_t* it) { + struct uniform* uniform; + + iter_t iter; + if (it == NULL || --it->refcount > 0) return; console_log(3, "disposing shader program #%u no longer in use", it->id); + + iter = vector_enum(it->uniforms); + while ((uniform = iter_next(&iter))) { + switch (uniform->type) { + case UNIFORM_FLOAT_ARR: + free(uniform->float_list); + break; + case UNIFORM_INT_ARR: + free(uniform->int_list); + break; + } + } + al_destroy_shader(it->program); vector_free(it->uniforms); free(it); @@ -831,8 +848,18 @@ free_cached_uniform(shader_t* shader, const char* name) iter = vector_enum(shader->uniforms); while ((uniform = iter_next(&iter))) { - if (strcmp(uniform->name, name) == 0) + if (strcmp(uniform->name, name) == 0) { + switch (uniform->type) { + case UNIFORM_FLOAT_ARR: + free(uniform->float_list); + break; + case UNIFORM_INT_ARR: + free(uniform->int_list); + break; + } + iter_remove(&iter); + } } } diff --git a/src/minisphere/image.c b/src/minisphere/image.c index 3683a269c..d70b20f15 100644 --- a/src/minisphere/image.c +++ b/src/minisphere/image.c @@ -67,7 +67,7 @@ static image_t* s_last_image = NULL; static unsigned int s_next_image_id = 0; image_t* -image_new(int width, int height, const color_t* pixels) +image_new(int width, int height, const color_t* pixels, int multisample) { image_t* image; ALLEGRO_BITMAP* old_target; @@ -76,6 +76,7 @@ image_new(int width, int height, const color_t* pixels) if (!(image = calloc(1, sizeof(image_t)))) goto on_error; al_set_new_bitmap_depth(16); + al_set_new_bitmap_samples(multisample); if ((image->bitmap = al_create_bitmap(width, height)) == NULL) goto on_error; image->id = s_next_image_id++; diff --git a/src/minisphere/image.h b/src/minisphere/image.h index 19615ad64..e2189e768 100644 --- a/src/minisphere/image.h +++ b/src/minisphere/image.h @@ -61,7 +61,7 @@ struct image_lock ptrdiff_t pitch; } image_lock_t; -image_t* image_new (int width, int height, const color_t* pixels); +image_t* image_new (int width, int height, const color_t* pixels, int multisample); image_t* image_new_slice (image_t* parent, int x, int y, int width, int height); image_t* image_dup (const image_t* it); image_t* image_load (const char* filename); diff --git a/src/minisphere/pegasus.c b/src/minisphere/pegasus.c index 3299336b9..696f2649c 100644 --- a/src/minisphere/pegasus.c +++ b/src/minisphere/pegasus.c @@ -539,9 +539,11 @@ static mixer_t* s_def_mixer; static js_ref_t* s_screen_obj; static js_ref_t* s_key_color; +static js_ref_t* s_key_content; static js_ref_t* s_key_done; static js_ref_t* s_key_get; static js_ref_t* s_key_inBackground; +static js_ref_t* s_key_multisample; static js_ref_t* s_key_priority; static js_ref_t* s_key_set; static js_ref_t* s_key_stack; @@ -571,9 +573,11 @@ pegasus_init(int api_level) s_api_level_nominal = SPHERE_API_LEVEL_STABLE; s_key_color = jsal_new_key("color"); + s_key_content = jsal_new_key("content"); s_key_done = jsal_new_key("done"); s_key_get = jsal_new_key("get"); s_key_inBackground = jsal_new_key("inBackground"); + s_key_multisample = jsal_new_key("multisample"); s_key_priority = jsal_new_key("priority"); s_key_set = jsal_new_key("set"); s_key_stack = jsal_new_key("stack"); @@ -5177,6 +5181,7 @@ js_new_Texture(int num_args, bool is_ctor, intptr_t magic) color_t fill_color; int height; image_t* image; + int multisample; image_t* src_image; int width; @@ -5189,16 +5194,44 @@ js_new_Texture(int num_args, bool is_ctor, intptr_t magic) height = jsal_require_int(1); if (buffer_size < width * height * sizeof(color_t)) jsal_error(JS_RANGE_ERROR, "Not enough data in pixel buffer"); - if (!(image = image_new(width, height, buffer))) + if (!(image = image_new(width, height, buffer, 0))) jsal_error(JS_ERROR, "Couldn't create GPU texture"); } + else if (num_args >= 3 && s_api_level >= 4 && jsal_is_object_coercible(2)) { + // create an Image with additional options + width = jsal_require_int(0); + height = jsal_require_int(1); + + if (jsal_get_prop_key(2, s_key_multisample)) + multisample = jsal_require_int(-1); + else + multisample = 0; + + + if (jsal_get_prop_key(2, s_key_content)) { + buffer = jsal_require_buffer_ptr(-1, &buffer_size); + if (buffer_size < width * height * sizeof(color_t)) + jsal_error(JS_RANGE_ERROR, "Not enough data in pixel buffer"); + if (!(image = image_new(width, height, buffer, 0))) + jsal_error(JS_ERROR, "Couldn't create GPU texture"); + } + else { + if (jsal_get_prop_key(2, s_key_color)) + fill_color = jsal_pegasus_require_color(-1); + else + fill_color = mk_color(0, 0, 0, 0); + if (!(image = image_new(width, height, NULL, multisample))) + jsal_error(JS_ERROR, "Couldn't create GPU texture"); + image_fill(image, fill_color, 1.0f); + } + } else if (num_args >= 2) { // create a Texture filled with a single pixel value width = jsal_require_int(0); height = jsal_require_int(1); fill_color = num_args >= 3 ? jsal_pegasus_require_color(2) : mk_color(0, 0, 0, 0); - if (!(image = image_new(width, height, NULL))) + if (!(image = image_new(width, height, NULL, 0))) jsal_error(JS_ERROR, "Couldn't create GPU texture"); image_fill(image, fill_color, 1.0f); } diff --git a/src/minisphere/screen.c b/src/minisphere/screen.c index 5b87755e1..04678f3df 100644 --- a/src/minisphere/screen.c +++ b/src/minisphere/screen.c @@ -110,7 +110,7 @@ screen_new(const char* title, image_t* icon, size2_t resolution, int frameskip, // and the screen-grab functions. al_store_state(&old_state, ALLEGRO_STATE_NEW_BITMAP_PARAMETERS); al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ANY_24_NO_ALPHA); - backbuffer = image_new(resolution.width, resolution.height, NULL); + backbuffer = image_new(resolution.width, resolution.height, NULL, 0); al_restore_state(&old_state); } if (backbuffer == NULL) { @@ -444,7 +444,7 @@ screen_grab(screen_t* it, int x, int y, int width, int height) { image_t* image; - if (!(image = image_new(width, height, NULL))) + if (!(image = image_new(width, height, NULL, 0))) goto on_error; image_render_to(image, NULL); al_draw_bitmap_region(image_bitmap(it->backbuffer), x, y, width, height, 0, 0, 0x0); diff --git a/src/minisphere/utility.c b/src/minisphere/utility.c index be47129c0..698699535 100644 --- a/src/minisphere/utility.c +++ b/src/minisphere/utility.c @@ -135,7 +135,7 @@ fread_image(file_t* file, int width, int height) console_log(3, "reading %dx%d image from open file", width, height); file_pos = file_position(file); - if (!(image = image_new(width, height, NULL))) + if (!(image = image_new(width, height, NULL, 0))) goto on_error; if (!(lock = image_lock(image, true, false))) goto on_error; diff --git a/src/minisphere/vanilla.c b/src/minisphere/vanilla.c index c288c5fbf..1254cb036 100644 --- a/src/minisphere/vanilla.c +++ b/src/minisphere/vanilla.c @@ -2066,7 +2066,7 @@ js_CreateSpriteset(int num_args, bool is_ctor, intptr_t magic) spriteset = spriteset_new(); spriteset_set_base(spriteset, mk_rect(0, 0, width, height)); - image = image_new(width, height, NULL); + image = image_new(width, height, NULL, 0); for (i = 0; i < num_images; ++i) { // use the same image in all slots to save memory. this works because // images are read-only, so it doesn't matter that they all share the same @@ -2126,7 +2126,7 @@ js_CreateSurface(int num_args, bool is_ctor, intptr_t magic) height = jsal_to_int(1); fill_color = num_args >= 3 ? jsal_require_sphere_color(2) : mk_color(0, 0, 0, 0); - if (!(image = image_new(width, height, NULL))) + if (!(image = image_new(width, height, NULL, 0))) jsal_error(JS_ERROR, "Couldn't create GPU texture"); image_fill(image, fill_color, 1.0f); jsal_push_class_obj(SV1_SURFACE, image, false); @@ -8506,7 +8506,7 @@ js_Surface_cloneSection(int num_args, bool is_ctor, intptr_t magic) width = jsal_to_int(2); height = jsal_to_int(3); - if (!(new_image = image_new(width, height, NULL))) + if (!(new_image = image_new(width, height, NULL, 0))) jsal_error(JS_ERROR, "couldn't create surface"); image_render_to(new_image, NULL); al_clear_to_color(al_map_rgba(0, 0, 0, 0)); @@ -9045,7 +9045,7 @@ js_Surface_rotate(int num_args, bool is_ctor, intptr_t magic) // FIXME: implement in-place resizing for Surface#rotate() jsal_error(JS_ERROR, "Resizing not implemented for Surface#rotate()"); } - if (!(new_image = image_new(new_width, new_height, NULL))) + if (!(new_image = image_new(new_width, new_height, NULL, 0))) jsal_error(JS_ERROR, "Couldn't create new surface"); image_render_to(new_image, NULL); al_clear_to_color(al_map_rgba(0, 0, 0, 0));