1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
// SPDX-License-Identifier: LGPL-2.1-or-later
/* SPDX-FileCopyrightText: 2007-2015 Simon Wunderlich <sw@simonwunderlich.de>
*/
#include "s3d.h"
#include "s3dlib.h"
#include "hash.h"
#ifdef SHM
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
#include <stdlib.h> /* malloc(), free() */
#include <errno.h> /* errno */
#include <string.h> /* memcpy() */
static int _s3d_compare_cb(const void *d1, const void *d2);
static int _s3d_choose_cb(const void *d1, int size);
static void _s3d_free_s3dtex(void *d1);
static struct hashtable_t *tex_hash = NULL;
static int _s3d_choose_cb(const void *d1, int size)
{
struct s3d_texshm *t1 = (struct s3d_texshm *)d1;
return (t1->oid*32 + t1->tex) % size;
}
static int _s3d_compare_cb(const void *d1, const void *d2)
{
struct s3d_texshm *t1, *t2;
t1 = (struct s3d_texshm *)d1;
t2 = (struct s3d_texshm *)d2;
if ((t1->oid == t2->oid) && (t1->tex == t2->tex))
return 0;
return 1;
}
static void _s3d_free_s3dtex(void *d1)
{
struct s3d_tex *tex = (struct s3d_tex *)d1;
#ifdef SHM
if (tex->buf != NULL) {
shmdt(tex->buf);
tex->buf = NULL;
}
shmctl(tex->tshm.shmid, IPC_RMID, NULL);
free(tex);
#endif
return;
}
void _s3d_handle_texshm(struct s3d_texshm *tshm)
{
struct s3d_tex *tex = NULL;
s3dprintf(HIGH, "handling new texture ...");
if (tex_hash == NULL)
return;
#ifdef SHM
tex = (struct s3d_tex *)_s3d_hash_remove(tex_hash, tshm);
if (tex != NULL)
_s3d_free_s3dtex(tex);
if (tshm->shmid == -1)
return;
tex = (struct s3d_tex *)malloc(sizeof(*tex));
tex->tshm = *tshm;
tex->buf = (char*)shmat(tex->tshm.shmid, (void *)0, 0);
if ((key_t *)tex->buf == (key_t *)(-1)) {
errn("shm_init():shmat()", errno);
free(tex);
return;
}
s3dprintf(HIGH, "adding new texture ...");
_s3d_hash_add(tex_hash, tex);
#endif
return;
}
int _s3d_load_texture_shm(int object, uint32_t tid, uint16_t xpos, uint16_t ypos, uint16_t w, uint16_t h, const uint8_t *data)
{
struct s3d_texshm check;
struct s3d_tex *tex;
int32_t i, p1, p2, m;
int16_t mw, mh;
if (tex_hash == NULL)
return -1;
check.oid = object;
check.tex = tid;
tex = (struct s3d_tex *)_s3d_hash_find(tex_hash, (void *) & check);
if (tex == NULL)
return -1; /* coudn't find */
s3dprintf(VLOW, "texture: oid %d, tex %d, shmid %d, tw %d, th %d, w %d, h %d ...",
tex->tshm.oid, tex->tshm.tex, tex->tshm.shmid, tex->tshm.tw, tex->tshm.th, tex->tshm.w, tex->tshm.th);
/* found it, assume that it's properly attached. */
m = tex->tshm.w * tex->tshm.th + tex->tshm.tw; /* maximum: position of the last pixel in the buffer */
if ((xpos + w) > tex->tshm.tw) mw = (tex->tshm.tw - xpos);
else mw = w;
if ((ypos + h) > tex->tshm.th) mh = (tex->tshm.th - ypos);
else mh = h;
if (mw <= 0) { /* nothing to do */
return 0;
}
for (i = 0; i < mh; i++) {
p1 = (ypos + i) * tex->tshm.w + xpos; /* scanline start position */
p2 = mw; /* and length */
if (p1 > m) {
break; /* need to break here. */
}
memcpy(tex->buf + 4*p1, /* draw at p1 position ... */
data + 4*i*w, /* scanline number i ... */
4*p2);
}
return 0;
}
int _s3d_texture_init(void)
{
tex_hash = _s3d_hash_new(256, _s3d_compare_cb, _s3d_choose_cb);
if (tex_hash == NULL)
return -1;
else
return 0;
}
int _s3d_texture_quit(void)
{
if (tex_hash == NULL)
return -1;
_s3d_hash_delete(tex_hash, _s3d_free_s3dtex);
tex_hash = NULL;
return 0;
}
|