Start implementing Python support for game-aware shaders.

This commit is contained in:
Themaister 2011-06-06 17:44:05 +02:00
parent 712f463022
commit 9bfeb88e24
7 changed files with 245 additions and 5 deletions

View File

@ -125,6 +125,12 @@ ifeq ($(HAVE_STRL), 1)
DEFINES += -DHAVE_STRL
endif
ifeq ($(HAVE_PYTHON), 1)
DEFINES += $(PYTHON_CFLAGS) -Wno-unused-parameter
LIBS += $(PYTHON_LIBS)
OBJ += gfx/py_state/py_state.o
endif
ifneq ($(V),1)
Q := @
endif

151
gfx/py_state/py_state.c Normal file
View File

@ -0,0 +1,151 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <Python.h>
#include <stdbool.h>
#include "dynamic.h"
#include "libsnes.hpp"
#include <stdlib.h>
#include "py_state.h"
#define PY_READ_FUNC_DECL(RAMTYPE) py_read_##RAMTYPE
#define PY_READ_FUNC(RAMTYPE) \
static PyObject* PY_READ_FUNC_DECL(RAMTYPE) (PyObject *self, PyObject *args) \
{ \
(void)self; \
\
const uint8_t *data = psnes_get_memory_data(SNES_MEMORY_##RAMTYPE); \
if (!data) \
{ \
Py_INCREF(Py_None); \
return Py_None; \
} \
unsigned max = psnes_get_memory_size(SNES_MEMORY_##RAMTYPE); \
\
unsigned addr; \
if (!PyArg_ParseTuple(args, "I", &addr)) \
return NULL; \
\
if (addr >= max || addr < 0) \
{ \
Py_INCREF(Py_None); \
return Py_None; \
} \
\
return PyLong_FromLong((long)data[addr]); \
}
PY_READ_FUNC(WRAM)
PY_READ_FUNC(VRAM)
PY_READ_FUNC(APURAM)
PY_READ_FUNC(CGRAM)
PY_READ_FUNC(OAM)
static PyMethodDef SNESMethods[] = {
{ "read_wram", PY_READ_FUNC_DECL(WRAM), METH_VARARGS, "Read WRAM from SNES." },
{ "read_vram", PY_READ_FUNC_DECL(VRAM), METH_VARARGS, "Read VRAM from SNES." },
{ "read_apuram", PY_READ_FUNC_DECL(APURAM), METH_VARARGS, "Read APURAM from SNES." },
{ "read_cgram", PY_READ_FUNC_DECL(CGRAM), METH_VARARGS, "Read CGRAM from SNES." },
{ "read_oam", PY_READ_FUNC_DECL(OAM), METH_VARARGS, "Read OAM from SNES." },
{ NULL, NULL, 0, NULL }
};
static PyModuleDef SNESModule = {
PyModuleDef_HEAD_INIT, "snes", NULL, -1, SNESMethods,
NULL, NULL, NULL, NULL
};
static PyObject* PyInit_SNES(void)
{
return PyModule_Create(&SNESModule);
}
struct py_state
{
PyObject *main;
PyObject *dict;
PyObject *inst;
};
py_state_t *py_state_new(const char *script_path, const char *pyclass)
{
PyImport_AppendInittab("snes", &PyInit_SNES);
Py_Initialize();
py_state_t *handle = calloc(1, sizeof(*handle));
handle->main = PyImport_AddModule("__main__");
if (!handle->main)
goto error;
FILE *file = fopen(script_path, "r");
if (!file)
goto error;
PyRun_SimpleFile(file, script_path);
fclose(file);
handle->dict = PyModule_GetDict(handle->main);
if (!handle->dict)
goto error;
PyObject *hook = PyDict_GetItemString(handle->dict, pyclass);
if (!hook)
goto error;
handle->inst = PyObject_CallFunction(hook, NULL);
if (!handle->inst)
goto error;
return handle;
error:
py_state_free(handle);
return NULL;
}
void py_state_free(py_state_t *handle)
{
if (handle)
{
if (handle->main)
Py_DECREF(handle->main);
if (handle->dict)
Py_DECREF(handle->dict);
if (handle->inst)
Py_DECREF(handle->inst);
free(handle);
}
Py_Finalize();
}
int py_state_get(py_state_t *handle, const char *id,
unsigned frame_count)
{
PyObject *ret = PyObject_CallMethod(handle->inst, (char*)id, (char*)"I", frame_count);
if (!ret)
return 0;
int retval = 0;
if (PyLong_Check(ret))
retval = (int)PyLong_AsLong(ret);
Py_DECREF(ret);
return retval;
}

31
gfx/py_state/py_state.h Normal file
View File

@ -0,0 +1,31 @@
/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes.
* Copyright (C) 2010-2011 - Hans-Kristian Arntzen
*
* Some code herein may be based on code found in BSNES.
*
* SSNES is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with SSNES.
* If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __SSNES_PY_STATE_H
#define __SSNES_PY_STATE_H
#include <stdint.h>
typedef struct py_state py_state_t;
py_state_t *py_state_new(const char *program, const char *pyclass);
void py_state_free(py_state_t *handle);
int py_state_get(py_state_t *handle,
const char *id, unsigned frame_count);
#endif

View File

@ -19,12 +19,21 @@
#include <stdlib.h>
#include <assert.h>
#include "strl.h"
#include "general.h"
#ifdef HAVE_PYTHON
#include "py_state/py_state.h"
#endif
struct snes_tracker_internal
{
char id[64];
const uint8_t *ptr;
#ifdef HAVE_PYTHON
py_state_t *py;
#endif
uint32_t addr;
uint8_t mask;
@ -33,12 +42,17 @@ struct snes_tracker_internal
uint8_t prev[2];
int frame_count;
uint8_t old_value;
};
struct snes_tracker
{
struct snes_tracker_internal *info;
unsigned info_elem;
#ifdef HAVE_PYTHON
py_state_t *py;
#endif
};
snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
@ -47,6 +61,19 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
if (!tracker)
return NULL;
#ifdef HAVE_PYTHON
if (info->script)
{
tracker->py = py_state_new(info->script, "GameAware");
if (!tracker->py)
{
free(tracker);
SSNES_ERR("Failed to init Python script.\n");
return NULL;
}
}
#endif
tracker->info = calloc(info->info_elem, sizeof(struct snes_tracker_internal));
tracker->info_elem = info->info_elem;
@ -57,6 +84,11 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
tracker->info[i].type = info->info[i].type;
tracker->info[i].mask = (info->info[i].mask == 0) ? 0xff : info->info[i].mask;
#ifdef HAVE_PYTHON
if (info->info[i].type == SSNES_STATE_PYTHON)
tracker->info[i].py = tracker->py;
#endif
assert(info->wram && info->vram && info->cgram &&
info->oam && info->apuram);
@ -83,13 +115,15 @@ snes_tracker_t* snes_tracker_init(const struct snes_tracker_info *info)
}
}
return tracker;
}
void snes_tracker_free(snes_tracker_t *tracker)
{
free(tracker->info);
#ifdef HAVE_PYTHON
py_state_free(tracker->py);
#endif
free(tracker);
}
@ -124,7 +158,6 @@ static void update_element(
info->frame_count = frame_count;
}
uniform->value = info->frame_count;
break;
case SSNES_STATE_TRANSITION_PREV:
@ -136,9 +169,14 @@ static void update_element(
info->frame_count = frame_count;
}
uniform->value = info->prev[1];
break;
#ifdef HAVE_PYTHON
case SSNES_STATE_PYTHON:
uniform->value = py_state_get(info->py, info->id, frame_count);
break;
#endif
default:
break;
}

View File

@ -20,12 +20,19 @@
#include <stdint.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
enum snes_tracker_type
{
SSNES_STATE_CAPTURE,
SSNES_STATE_TRANSITION,
SSNES_STATE_CAPTURE_PREV,
SSNES_STATE_TRANSITION_PREV
SSNES_STATE_TRANSITION_PREV,
#ifdef HAVE_PYTHON
SSNES_STATE_PYTHON
#endif
};
enum snes_ram_type
@ -56,6 +63,10 @@ struct snes_tracker_info
const struct snes_tracker_uniform_info *info;
unsigned info_elem;
#ifdef HAVE_PYTHON
const char *script;
#endif
};
struct snes_tracker_uniform

View File

@ -64,8 +64,10 @@ check_lib XVIDEO -lXv XvShmCreateImage
check_lib STRL -lc strlcpy
check_pkgconf PYTHON python3
# Creates config.mk and config.h.
VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL DYLIB CG XML IMLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO STRL"
VARS="ALSA OSS AL RSOUND ROAR JACK PULSE SDL DYLIB CG XML IMLIB DYNAMIC FFMPEG AVCODEC AVFORMAT AVCORE AVUTIL SWSCALE SRC CONFIGFILE FREETYPE XVIDEO NETPLAY FBO STRL PYTHON"
create_config_make config.mk $VARS
create_config_header config.h $VARS

View File

@ -27,3 +27,4 @@ add_command_line_enable PULSE "Enable PulseAudio support" auto
add_command_line_enable FREETYPE "Enable FreeType support" auto
add_command_line_enable XVIDEO "Enable XVideo support" auto
add_command_line_enable IMLIB "Enable imlib2 support" auto
add_command_line_enable PYTHON "Enable Python 3 support for shaders" auto