mirror of
https://github.com/buserror/mii_emu.git
synced 2024-12-03 13:49:56 +00:00
d399b12a9d
AppleGalaxian failed to load because of a sparse track map. Signed-off-by: Michel Pollet <buserror@gmail.com>
283 lines
5.9 KiB
C
283 lines
5.9 KiB
C
/*
|
|
* mui_drawable.c
|
|
*
|
|
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
|
|
#include <pixman.h>
|
|
#include "mui.h"
|
|
#include "cg.h"
|
|
|
|
|
|
IMPLEMENT_C_ARRAY(mui_clip_stack);
|
|
|
|
void
|
|
mui_drawable_clear(
|
|
mui_drawable_t * dr)
|
|
{
|
|
if (!dr)
|
|
return;
|
|
if (dr->cg)
|
|
cg_destroy(dr->cg);
|
|
dr->cg = NULL;
|
|
if (dr->cg_surface)
|
|
cg_surface_destroy(dr->cg_surface);
|
|
dr->cg_surface = NULL;
|
|
if (dr->pixman)
|
|
pixman_image_unref(dr->pixman);
|
|
dr->pixman = NULL;
|
|
for (int i = 0; i < (int)dr->clip.count; i++)
|
|
pixman_region32_fini(&dr->clip.e[i]);
|
|
mui_clip_stack_clear(&dr->clip);
|
|
if (dr->pix.pixels && dr->dispose_pixels)
|
|
free(dr->pix.pixels);
|
|
dr->_pix_hash = NULL;
|
|
}
|
|
|
|
void
|
|
mui_drawable_dispose(
|
|
mui_drawable_t * dr)
|
|
{
|
|
if (!dr)
|
|
return;
|
|
mui_drawable_clear(dr);
|
|
mui_clip_stack_free(&dr->clip);
|
|
// free(dr);
|
|
}
|
|
|
|
static struct cg_ctx_t *
|
|
_cg_updated_clip(
|
|
mui_drawable_t * dr)
|
|
{
|
|
if (!dr->cg_clip_dirty)
|
|
return dr->cg;
|
|
dr->cg_clip_dirty = 0;
|
|
cg_reset_clip(dr->cg);
|
|
if (!dr->clip.count)
|
|
return dr->cg;
|
|
int cnt = 0;
|
|
pixman_box32_t *r = pixman_region32_rectangles(
|
|
&dr->clip.e[dr->clip.count-1], &cnt);
|
|
for (int i = 0; i < cnt; i++) {
|
|
cg_rectangle(dr->cg, r[i].x1, r[i].y1,
|
|
r[i].x2 - r[i].x1, r[i].y2 - r[i].y1);
|
|
}
|
|
cg_clip(dr->cg);
|
|
return dr->cg;
|
|
}
|
|
|
|
struct cg_ctx_t *
|
|
mui_drawable_get_cg(
|
|
mui_drawable_t * dr)
|
|
{
|
|
if (!dr)
|
|
return NULL;
|
|
|
|
if (dr->cg) {
|
|
// in case the pix structure had changed...
|
|
dr->cg_surface->stride = dr->pix.row_bytes;
|
|
dr->cg_surface->pixels = dr->pix.pixels;
|
|
dr->cg_surface->width = dr->pix.size.x;
|
|
dr->cg_surface->height = dr->pix.size.y;
|
|
return _cg_updated_clip(dr);
|
|
}
|
|
dr->cg_surface = cg_surface_create_for_data(
|
|
dr->pix.size.x, dr->pix.size.y,
|
|
dr->pix.pixels);
|
|
dr->cg_surface->stride = dr->pix.row_bytes;
|
|
dr->cg = cg_create(dr->cg_surface);
|
|
return _cg_updated_clip(dr);
|
|
}
|
|
|
|
/*
|
|
* Update clip to the 'latest' one from the stack of clips.
|
|
*/
|
|
static union pixman_image *
|
|
_pixman_updated_clip(
|
|
mui_drawable_t * dr)
|
|
{
|
|
if (!dr->pixman_clip_dirty)
|
|
return dr->pixman;
|
|
dr->pixman_clip_dirty = 0;
|
|
if (dr->clip.count)
|
|
pixman_image_set_clip_region32(
|
|
dr->pixman, &dr->clip.e[dr->clip.count-1]);
|
|
else
|
|
pixman_image_set_clip_region32(
|
|
dr->pixman, NULL);
|
|
return dr->pixman;
|
|
}
|
|
|
|
union pixman_image *
|
|
mui_pixmap_make_pixman(
|
|
mui_pixmap_t * pix)
|
|
{
|
|
pixman_format_code_t k = PIXMAN_a8r8g8b8;
|
|
switch (pix->bpp) {
|
|
case 8: k = PIXMAN_a8; break;
|
|
case 16: k = PIXMAN_r5g6b5; break;
|
|
case 24: k = PIXMAN_r8g8b8; break;
|
|
case 32: k = PIXMAN_a8r8g8b8; break;
|
|
}
|
|
union pixman_image * res = pixman_image_create_bits_no_clear(
|
|
k, pix->size.x, pix->size.y,
|
|
(uint32_t*)pix->pixels, pix->row_bytes);
|
|
return res;
|
|
}
|
|
|
|
union pixman_image *
|
|
mui_drawable_get_pixman(
|
|
mui_drawable_t * dr)
|
|
{
|
|
if (!dr)
|
|
return NULL;
|
|
void * _hash = dr->pix.pixels + dr->pix.size.y * dr->pix.row_bytes;
|
|
if (dr->_pix_hash != _hash) {
|
|
dr->_pix_hash = _hash;
|
|
dr->_pix_hash = dr->pix.pixels + dr->pix.size.y * dr->pix.row_bytes;
|
|
if (dr->pixman)
|
|
pixman_image_unref(dr->pixman);
|
|
dr->pixman = NULL;
|
|
}
|
|
// return _pixman_updated_clip(dr);
|
|
if (dr->pixman)
|
|
return _pixman_updated_clip(dr);
|
|
dr->pixman = mui_pixmap_make_pixman(&dr->pix);
|
|
dr->pixman_clip_dirty = 1;
|
|
return _pixman_updated_clip(dr);
|
|
}
|
|
|
|
pixman_region32_t *
|
|
mui_drawable_clip_get(
|
|
mui_drawable_t * dr)
|
|
{
|
|
if (!dr || !dr->clip.count)
|
|
return NULL;
|
|
return &dr->clip.e[dr->clip.count-1];
|
|
}
|
|
|
|
void
|
|
mui_drawable_set_clip(
|
|
mui_drawable_t * dr,
|
|
c2_rect_array_p clip )
|
|
{
|
|
if (!dr)
|
|
return;
|
|
for (int i = 0; i < (int)dr->clip.count; i++)
|
|
pixman_region32_fini(&dr->clip.e[i]);
|
|
mui_clip_stack_clear(&dr->clip);
|
|
if (clip && clip->count) {
|
|
pixman_region32_t r = {};
|
|
|
|
pixman_region32_init_rects(&r,
|
|
(pixman_box32_t*)clip->e, clip->count);
|
|
// intersect the whole lot with the whole pixmap boundary
|
|
pixman_region32_t rg = {};
|
|
pixman_region32_intersect_rect(&rg, &r,
|
|
0, 0, dr->pix.size.x, dr->pix.size.y);
|
|
pixman_region32_fini(&r);
|
|
|
|
mui_clip_stack_add(&dr->clip, rg);
|
|
}
|
|
dr->pixman_clip_dirty = 1;
|
|
dr->cg_clip_dirty = 1;
|
|
}
|
|
|
|
int
|
|
mui_drawable_clip_intersects(
|
|
mui_drawable_t * dr,
|
|
c2_rect_p r )
|
|
{
|
|
if (!dr || !r)
|
|
return 0;
|
|
if (!dr->clip.count)
|
|
return 1;
|
|
// conveniently, c2_rect_t is the same as pixman_box_32_t
|
|
pixman_region_overlap_t o = pixman_region32_contains_rectangle(
|
|
&dr->clip.e[dr->clip.count-1], (pixman_box32_t*)r);
|
|
|
|
return o == PIXMAN_REGION_OUT ? 0 :
|
|
o == PIXMAN_REGION_IN ? 1 : -1;
|
|
}
|
|
|
|
int
|
|
mui_drawable_clip_push(
|
|
mui_drawable_t * dr,
|
|
c2_rect_p r )
|
|
{
|
|
if (!dr || !r)
|
|
return 0;
|
|
pixman_region32_t rg = {};
|
|
if (dr->clip.count == 0) {
|
|
pixman_region32_init_rect(&rg,
|
|
r->l, r->t, c2_rect_width(r), c2_rect_height(r));
|
|
} else {
|
|
pixman_region32_intersect_rect(&rg, &dr->clip.e[dr->clip.count-1],
|
|
r->l, r->t, c2_rect_width(r), c2_rect_height(r));
|
|
}
|
|
mui_clip_stack_add(&dr->clip, rg);
|
|
dr->pixman_clip_dirty = 1;
|
|
dr->cg_clip_dirty = 1;
|
|
|
|
return dr->clip.count;
|
|
}
|
|
|
|
int
|
|
mui_drawable_clip_push_region(
|
|
mui_drawable_t * dr,
|
|
pixman_region32_t * rgn )
|
|
{
|
|
if (!dr || !rgn)
|
|
return 0;
|
|
|
|
pixman_region32_t rg = {};
|
|
if (dr->clip.count == 0) {
|
|
pixman_region32_copy(&rg, rgn);
|
|
} else {
|
|
pixman_region32_intersect(&rg, &dr->clip.e[dr->clip.count-1], rgn);
|
|
}
|
|
mui_clip_stack_add(&dr->clip, rg);
|
|
dr->pixman_clip_dirty = 1;
|
|
dr->cg_clip_dirty = 1;
|
|
|
|
return dr->clip.count;
|
|
}
|
|
|
|
int
|
|
mui_drawable_clip_substract_region(
|
|
mui_drawable_t * dr,
|
|
pixman_region32_t * rgn )
|
|
{
|
|
if (!dr || !rgn)
|
|
return 0;
|
|
|
|
pixman_region32_t rg = {};
|
|
if (dr->clip.count != 0) {
|
|
pixman_region32_subtract(&rg, &dr->clip.e[dr->clip.count-1], rgn);
|
|
}
|
|
mui_clip_stack_add(&dr->clip, rg);
|
|
dr->pixman_clip_dirty = 1;
|
|
dr->cg_clip_dirty = 1;
|
|
|
|
return dr->clip.count;
|
|
}
|
|
|
|
void
|
|
mui_drawable_clip_pop(
|
|
mui_drawable_t * dr )
|
|
{
|
|
if (!dr || !dr->clip.count)
|
|
return;
|
|
pixman_region32_fini(&dr->clip.e[dr->clip.count-1]);
|
|
dr->clip.count--;
|
|
dr->pixman_clip_dirty = 1;
|
|
dr->cg_clip_dirty = 1;
|
|
}
|