├── .gitignore ├── src ├── log.h ├── script.h ├── log.c ├── branches.lua ├── script.c ├── local.h ├── km.h ├── d3d9.c └── km.c ├── kamui.cfg ├── pvr ├── include │ └── pvr.h ├── premake5.lua └── src │ ├── pvrc.c │ └── pvr.c ├── premake5.lua └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | scud 3 | koke 4 | fishman 5 | *.a 6 | *.lib 7 | *.exe 8 | *.dll 9 | *.zip 10 | *.DLL 11 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef struct _Log 4 | { 5 | FILE *fp; 6 | int level; 7 | }Log; 8 | 9 | int log_create (Log *ls, const char *name); 10 | int log_destroy (Log *ls); 11 | int log_write (Log *ls, int level, const char *fmt, ...); 12 | 13 | #define TRACE(...) log_write (&_log, 2, __VA_ARGS__) 14 | #define CRITICAL(...) log_write (&_log, 1, "CRITICAL: " __VA_ARGS__) 15 | 16 | -------------------------------------------------------------------------------- /kamui.cfg: -------------------------------------------------------------------------------- 1 | #Specifies the priority threshold to be logged to file. 2 | #Anything lower than the given level will be logged. 3 | #Set to -1 to log everything. 0 to disable logging. 4 | #Log level 1 is for the most critical messages. 5 | loglevel 0 6 | 7 | #Introduces an artificial framerate limit. Set to 0 for uncapped. 8 | framelimit 60 9 | 10 | #Buffer size for geometry, in megabytes 11 | vb_size 8 12 | -------------------------------------------------------------------------------- /src/script.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SCRIPT_EOF 0 4 | #define SCRIPT_STRING 1 5 | #define SCRIPT_SYMBOL 2 6 | 7 | #define SCRIPT_OK 0 8 | #define SCRIPT_NOSOURCE -1 9 | #define SCRIPT_TRUNCATED -2 10 | 11 | typedef struct _Script 12 | { 13 | char *source; 14 | char *pos; 15 | }Script; 16 | 17 | int script_next (Script *script, int *type, char *token, size_t len); 18 | int script_from_file (Script *script, const char *file); 19 | int script_destroy (Script *script); 20 | -------------------------------------------------------------------------------- /pvr/include/pvr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define PVR_OK 0 6 | #define PVR_INVALID -1 7 | #define PVR_BAD_SIZE -2 8 | #define PVR_NO_IMP -3 9 | #define PVR_NO_MEM -4 10 | 11 | typedef struct _PVR_surface 12 | { 13 | void *data; 14 | uint32_t width, height; 15 | uint32_t bpp; /*bytes per pixel*/ 16 | }PVR_surface; 17 | 18 | int 19 | pvr_surface_decode_ptr ( 20 | PVR_surface *dst, 21 | uint32_t type, 22 | uint32_t format, 23 | uint32_t width, 24 | uint32_t height, 25 | size_t size, 26 | uint8_t *src 27 | ); 28 | int pvr_surface_decode (PVR_surface *dst, uint8_t *src); 29 | int pvr_surface_free (PVR_surface *surf); 30 | -------------------------------------------------------------------------------- /pvr/premake5.lua: -------------------------------------------------------------------------------- 1 | workspace "pvr" 2 | configurations {"Debug", "Release"} 3 | location "build" 4 | targetdir "." 5 | debugdir "." 6 | filter "language:C" 7 | toolset "gcc" 8 | buildoptions {"-std=c11 -pedantic -Wall"} 9 | filter "configurations:Debug" 10 | defines {"DEBUG"} 11 | symbols "On" 12 | filter "configurations:Release" 13 | defines {"NDEBUG"} 14 | vectorextensions "Default" 15 | optimize "Speed" 16 | project "pvr" 17 | language "C" 18 | kind "StaticLib" 19 | includedirs {"include"} 20 | files { 21 | "include/pvr.h", 22 | "src/pvr.c", 23 | } 24 | project "pvrc" 25 | language "C" 26 | kind "ConsoleApp" 27 | includedirs {"include"} 28 | files { 29 | "src/pvrc.c", 30 | } 31 | links {"pvr", "png", "zlib"} 32 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "log.h" 6 | 7 | int 8 | log_create (Log *ls, const char *name) 9 | { 10 | memset (ls, 0, sizeof (*ls)); 11 | ls->level = 10; 12 | ls->fp = fopen (name, "w"); 13 | if (NULL == ls->fp) 14 | { 15 | return -1; 16 | } 17 | setbuf (ls->fp, NULL); 18 | return 0; 19 | } 20 | int 21 | log_destroy (Log *ls) 22 | { 23 | if (ls->fp) 24 | { 25 | fclose (ls->fp); 26 | ls->fp = NULL; 27 | } 28 | return 0; 29 | } 30 | int 31 | log_write (Log *ls, int level, const char *fmt, ...) 32 | { 33 | if (ls->level < level) 34 | { 35 | return -1; 36 | } 37 | FILE *fp = ls->fp ? ls->fp : stdout; 38 | va_list args; 39 | 40 | va_start (args, fmt); 41 | vfprintf (fp, fmt, args); 42 | fprintf (fp, "\r\n"); 43 | va_end (args); 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /premake5.lua: -------------------------------------------------------------------------------- 1 | workspace "kamui" 2 | configurations {"Debug", "Release"} 3 | location "build" 4 | targetname "KAMUI" 5 | targetprefix "" 6 | targetextension ".DLL" 7 | targetdir "." 8 | debugdir "." 9 | filter "language:C" 10 | toolset "gcc" 11 | buildoptions {"-std=gnu11 -pedantic -Wall -m32"} 12 | --KAMUI uses stdcall, but without the decoration, 13 | --so... it's not... standard... 14 | linkoptions {"-Wl,--kill-at"} 15 | filter "configurations:Debug" 16 | defines {"DEBUG"} 17 | symbols "On" 18 | filter "configurations:Release" 19 | defines {"NDEBUG"} 20 | vectorextensions "Default" 21 | optimize "Speed" 22 | project "kamui" 23 | language "C" 24 | kind "SharedLib" 25 | includedirs {"pvr/include"} 26 | syslibdirs {"pvr"} 27 | files { 28 | "src/**.h", 29 | "src/**.c", 30 | } 31 | links {"pvr", "d3d9", "d3dcompiler"} 32 | -------------------------------------------------------------------------------- /src/branches.lua: -------------------------------------------------------------------------------- 1 | local atoms = { 2 | "KM_PARAMTYPE", 3 | "KM_LISTTYPE", 4 | "KM_STRIPLENGTH", 5 | "KM_USERCLIPMODE", 6 | "KM_COLORTYPE", 7 | "KM_UVFORMAT", 8 | "KM_DEPTHMODE", 9 | "KM_CULLINGMODE", 10 | "KM_SCREENCOORDINATION", 11 | "KM_SHADINGMODE", 12 | "KM_MODIFIER", 13 | "KM_ZWRITEDISABLE", 14 | "KM_SRCBLENDINGMODE", 15 | "KM_DSTBLENDINGMODE", 16 | "KM_SRCSELECT", 17 | "KM_DSTSELECT", 18 | "KM_FOGMODE", 19 | "KM_USESPECULAR", 20 | "KM_USEALPHA", 21 | "KM_IGNORETEXTUREALPHA", 22 | "KM_CLAMPUV", 23 | "KM_FLIPUV", 24 | "KM_FILTERMODE", 25 | "KM_SUPERSAMPLE", 26 | "KM_MIPMAPDADJUST", 27 | "KM_TEXTURESHADINGMODE", 28 | "KM_COLORCLAMP", 29 | "KM_PALETTEBANK", 30 | "KM_DCALCEXACT" 31 | } 32 | 33 | for i, v in ipairs (atoms) do 34 | print (string.format ("if (state&%s)\n{\n}", v)) 35 | end 36 | 37 | for i, v in ipairs (atoms) do 38 | print (string.format ("if (state&%s) strcat (buf, \"%s \");", v, v)) 39 | end 40 | 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KAMUI Direct! 2 | 3 | --- 4 | 5 | Circa 1997 Sega was developing the KAMUI graphics API used for their newest console, the Dreamcast. There were no devkits yet, so the programmers were using Windows 95 workstations with a custom PCB plugged into the PCI bus to get the job done. 6 | 7 | 8 | The PCB had a PVR CLX2 graphics chip on it, and would output video to a NTSC compatible display hooked up to it, rather than the PC's monitor. This setup left PC display free for programming and debugging tools. 9 | 10 | 11 | Several demos were written to show off the hardware, which were thought lost to time until 2021, when they recovered. Since the demos were developed using Windows 95 on x86 hardware, they could be run today on modern computers - except that they required the custom PCBs to function. 12 | 13 | 14 | In theory, a custom driver could be written to reimplement the KAMUI API, wrapping around a modern API such as Direct3D or OpenGL, which would allow the demos to be run again. This project does just that. 15 | 16 | 17 | ## Compiling 18 | 19 | --- 20 | 21 | You will need a C11 compliant compiler with the Direct3D9 library to build the code. Premake5 is used to generate project files. 22 | 23 | 24 | The primary workstation for the project runs Void Linux and uses `i686-w64-mingw-gcc` to cross compile to Windows. Testing was done on Wine, Windows XP and Windows 10. 25 | 26 | 27 | The project might compile under Visual Studio, provided you configure it to use clang, or even better, gcc. This has been untested. 28 | 29 | 30 | ## Usage 31 | 32 | --- 33 | 34 | The easiest way to use this project is to copy the KAMUI.DLL into each demo directory and run executable. A better way would be to copy it into some directory in your PATH variable, so any KAMUI demo may access it regardless where it is stored. 35 | 36 | 37 | ## Acknowledgements 38 | 39 | --- 40 | 41 | This project was made possible under the auspices of Comby Laurent, for the benefit of the Sega Dreamcast scene. You may follow him on Twitter @combylaurent1. 42 | 43 | 44 | Shoutouts to Daxxtrias, for helping with the reverse engineering process, and to all my friends for morale support. 45 | -------------------------------------------------------------------------------- /src/script.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "script.h" 5 | 6 | int 7 | script_next (Script *script, int *type, char *token, size_t len) 8 | { 9 | char *p = script->pos; 10 | char *d = token; 11 | int code = SCRIPT_NOSOURCE; 12 | len--; 13 | while (p != NULL) 14 | { /*Skip leading white space*/ 15 | while (*p <= ' ') 16 | { 17 | if (*p == '\0') 18 | { 19 | *type = SCRIPT_EOF; 20 | code = SCRIPT_OK; 21 | goto Exit; 22 | } 23 | p++; 24 | } 25 | /*Single line comments*/ 26 | if ('#' == *p) 27 | { 28 | while (*p != '\n') 29 | { 30 | if (*p == '\0') break; 31 | p++; 32 | } 33 | continue; 34 | } 35 | /*Strings*/ 36 | if ('\"' == *p) 37 | { 38 | while (*++p != '\"') 39 | { 40 | if (len != 0) 41 | { 42 | *d++ = *p; 43 | *d = '\0'; 44 | len--; 45 | } 46 | } 47 | p++; 48 | *type = SCRIPT_STRING; 49 | code = (len != 0) ? SCRIPT_OK : SCRIPT_TRUNCATED; 50 | goto Exit; 51 | } 52 | /*Symbols*/ 53 | while (*p > ' ') 54 | { 55 | if (len != 0) 56 | { 57 | int c = *p; 58 | *d++ = c|((c != '_')<<5); 59 | *d = '\0'; 60 | len--; 61 | } 62 | p++; 63 | } 64 | *type = SCRIPT_SYMBOL; 65 | code = (len != 0) ? SCRIPT_OK : SCRIPT_TRUNCATED; 66 | goto Exit; 67 | } 68 | Exit: 69 | script->pos = p; 70 | return code; 71 | } 72 | int 73 | script_from_file (Script *script, const char *file) 74 | { 75 | char *text = NULL; 76 | size_t len = 0; 77 | 78 | FILE *fp = fopen (file, "rb"); 79 | if (NULL == fp) 80 | { 81 | return -1; 82 | } 83 | 84 | fseek (fp, 0, SEEK_END); 85 | len = ftell (fp); 86 | fseek (fp, 0, SEEK_SET); 87 | 88 | text = malloc (len + 1); 89 | if (NULL == text) 90 | { 91 | fclose (fp); 92 | return -2; 93 | } 94 | fread (text, len, 1, fp); 95 | text[len] = '\0'; 96 | 97 | fclose (fp); 98 | 99 | memset (script, 0, sizeof (*script)); 100 | script->source = text; 101 | script->pos = text; 102 | 103 | return 0; 104 | } 105 | int 106 | script_destroy (Script *script) 107 | { 108 | if (script->source) 109 | { 110 | free (script->source); 111 | script->source = NULL; 112 | script->pos = NULL; 113 | } 114 | return 0; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /src/local.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "script.h" 5 | #include "log.h" 6 | #include "km.h" 7 | 8 | #define VERIFY(x, y) assert ((x) && (y)) 9 | 10 | typedef struct _Backend 11 | { 12 | const char *tag; 13 | int (*init_device) (int, void *, void *); 14 | int (*destroy_device) (void); 15 | 16 | int (*pixel_clipping) (int, int, int, int); 17 | int (*render) (void); 18 | 19 | int (*framebuffer_flip) (void); 20 | 21 | int (*texture_create) (KM_surface_desc *, int, int, int); 22 | int (*texture_load) (KM_surface_desc *, uint32_t, uint32_t, uint32_t, void *); 23 | int (*texture_free) (KM_surface_desc *); 24 | 25 | }Backend; 26 | 27 | extern Backend backend_d3d9; 28 | 29 | #define KMC_NOP 0 30 | #define KMC_CTX 1 31 | #define KMC_POLY 2 32 | 33 | typedef struct _KM_command 34 | { 35 | int code; 36 | size_t size; 37 | }KM_command; 38 | typedef struct _KM_context 39 | { 40 | KM_command s; 41 | KM_vertex_ctx ctx; 42 | }KM_context; 43 | typedef struct _KM_polygon 44 | { 45 | KM_command s; 46 | struct _KM_polygon *next; 47 | KM_vertex_ctx ctx; 48 | size_t offset; 49 | float sort; 50 | int nverts; 51 | int index; 52 | }KM_polygon; 53 | 54 | typedef struct _KM_shim 55 | { 56 | uint32_t type; 57 | uint32_t format; 58 | uint32_t size; 59 | void *surface; 60 | }KM_shim; 61 | 62 | typedef struct _Config 63 | { 64 | uint32_t loglevel; 65 | uint32_t framelimit; 66 | size_t vb_size; 67 | char backend[16]; 68 | }Config; 69 | 70 | typedef struct _KM_command_list 71 | { 72 | struct _KM_polygon *poly; 73 | void *buffer; 74 | size_t size; 75 | size_t used; 76 | }KM_command_list; 77 | 78 | typedef struct _KM_global_state 79 | { 80 | int device; /*dreamcast or naomi mode*/ 81 | int display, bpp, dither, aa; 82 | int width, height; 83 | int viewport[4]; 84 | int rate; 85 | 86 | struct _Callbacks 87 | { 88 | KM_callback func; 89 | void *args; 90 | }vsync, eor, eov; 91 | 92 | float cull_value; 93 | 94 | size_t curr_list; 95 | void *base[KM_MAX_DISPLAY_LIST]; 96 | void *lists[KM_MAX_DISPLAY_LIST]; 97 | 98 | KM_command_list cl[KM_MAX_DISPLAY_LIST]; 99 | void *geobuf; 100 | size_t geobuf_used; 101 | size_t geobuf_indices; 102 | 103 | KM_vertex_ctx ctx; 104 | void *texture; 105 | 106 | void *opaque; 107 | void *sorted; 108 | int opaque_w; 109 | int opaque_c; 110 | int opaque_used; 111 | }KM_global_state; 112 | 113 | extern KM_global_state km; 114 | extern Log _log; 115 | extern Config _cfg; 116 | 117 | -------------------------------------------------------------------------------- /pvr/src/pvrc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "pvr.h" 7 | 8 | static jmp_buf jmpbuf; 9 | 10 | static void 11 | error_handler (png_structp png_ptr, png_const_charp msg) 12 | { 13 | longjmp (jmpbuf, 1); 14 | } 15 | 16 | int 17 | main (int argc, char **argv) 18 | { 19 | if (argc < 2) 20 | { 21 | printf ("prvc \n"); 22 | return -1; 23 | } 24 | 25 | FILE *fp = fopen (argv[1], "rb"); 26 | if (NULL == fp) 27 | { 28 | printf ("failed to open '%s'\n", argv[1]); 29 | return -1; 30 | } 31 | fseek (fp, 0, SEEK_END); 32 | int size = ftell (fp); 33 | uint8_t *buf = malloc (size); 34 | fseek (fp, 0, SEEK_SET); 35 | fread (buf, 1, size, fp); 36 | fclose (fp); 37 | 38 | PVR_surface srf; 39 | switch (pvr_surface_decode (&srf, buf)) 40 | { 41 | case PVR_OK: { 42 | printf ("saving...\n"); 43 | FILE *outfile2 = fopen ("out.raw", "wb"); 44 | fwrite (srf.data, 1, srf.width*srf.height*srf.bpp, outfile2); 45 | fclose (outfile2); 46 | 47 | /*Create output stream*/ 48 | FILE *outfile = fopen ("out.png", "wb"); 49 | if (NULL == outfile) 50 | { 51 | pvr_surface_free (&srf); 52 | return -1; 53 | } 54 | 55 | /*Initialise libpng*/ 56 | png_structp png_ptr = png_create_write_struct ( 57 | PNG_LIBPNG_VER_STRING, 58 | NULL, 59 | error_handler, 60 | NULL 61 | ); 62 | if (NULL == png_ptr) 63 | { 64 | pvr_surface_free (&srf); 65 | fclose (fp); 66 | return -1; 67 | } 68 | png_infop info_ptr = png_create_info_struct (png_ptr); 69 | if (!info_ptr) 70 | { 71 | png_destroy_write_struct (&png_ptr, NULL); 72 | pvr_surface_free (&srf); 73 | fclose (fp); 74 | return -1; 75 | } 76 | 77 | /*Abort! Abort! Abort!*/ 78 | if (setjmp (png_jmpbuf (png_ptr))) 79 | { 80 | png_destroy_write_struct (&png_ptr, &info_ptr); 81 | pvr_surface_free (&srf); 82 | fclose (fp); 83 | return -1; 84 | } 85 | 86 | png_init_io (png_ptr, fp); 87 | png_set_IHDR ( 88 | png_ptr, info_ptr, 89 | srf.width, srf.height, 8, 90 | (srf.bpp == 4) ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB, 91 | PNG_INTERLACE_NONE, 92 | PNG_COMPRESSION_TYPE_DEFAULT, 93 | PNG_FILTER_TYPE_DEFAULT 94 | ); 95 | 96 | png_write_info (png_ptr, info_ptr); 97 | png_set_packing (png_ptr); 98 | 99 | uint8_t *buf = srf.data; 100 | for (uint32_t i = 0; i < srf.height; i++) 101 | { 102 | png_write_row (png_ptr, buf); 103 | buf += srf.bpp*srf.width; 104 | } 105 | png_write_end (png_ptr, NULL); 106 | 107 | png_destroy_write_struct (&png_ptr, &info_ptr); 108 | pvr_surface_free (&srf); 109 | fclose (fp); 110 | } break; 111 | case PVR_BAD_SIZE: 112 | printf ("width/height must be <= 1024\n"); 113 | break; 114 | case PVR_NO_IMP: 115 | printf ("unsupported PVR format\n"); 116 | break; 117 | case PVR_NO_MEM: 118 | printf ("no memory left to allocate surface\n"); 119 | break; 120 | case PVR_INVALID: 121 | printf ("invalid image format\n"); 122 | default: 123 | break; 124 | } 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /pvr/src/pvr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "pvr.h" 6 | 7 | #define PVR_GBIX (('X'<<24)|('I'<<16)|('B'<<8)|'G') 8 | #define PVR_PVRT (('T'<<24)|('R'<<16)|('V'<<8)|'P') 9 | #define PVR_CODEBOOK 0x1000 10 | #define PVR_MAX_WIDTH 0x1000 11 | #define PVR_MAX_HEIGHT 0x1000 12 | 13 | #define PVR_ARGB1555 0x0 14 | #define PVR_RGB565 0x1 15 | #define PVR_ARGB4444 0x2 16 | #define PVR_YUV422 0x3 17 | #define PVR_BUMP 0x4 18 | #define PVR_RGB555 0x5 19 | #define PVR_YUV420 0x6 20 | 21 | #define PVR_TWIDDLED 0x1 22 | #define PVR_TWIDDLED_MIPMAP 0x2 23 | #define PVR_TWIDDLED_MIPMAP_DMA 0x12 /*Has padding at the end*/ 24 | #define PVR_VQ 0x3 25 | #define PVR_VQ_MIPMAP 0x4 26 | #define PVR_RECTANGLE 0x9 27 | #define PVR_RECTANGLE_MIPMAP 0xA 28 | #define PVR_RECTANGLE_TWIDDLED 0xD 29 | #define PVR_SMALL_VQ 0x10 30 | #define PVR_SMALL_VQ_MIPMAP 0x11 31 | #define PVR_STRIDE 0xB 32 | #define PVR_STRIDE_TWIDDLED 0xC 33 | #define PVR_BITMAP 0xE 34 | #define PVR_BITMAP_MIPMAP 0xF 35 | #define PVR_PAL4 0x5 36 | #define PVR_PAL4_MIPMAP 0x6 37 | #define PVR_PAL8 0x7 38 | #define PVR_PAL8_MIPMAP 0x8 39 | 40 | typedef struct _PVR_header 41 | { 42 | uint32_t magick; 43 | uint32_t size; 44 | uint8_t format; 45 | uint8_t type; 46 | uint16_t unk; 47 | uint16_t width; 48 | uint16_t height; 49 | }PVR_header; 50 | 51 | static uint32_t 52 | morton (uint32_t x, uint32_t y) 53 | { 54 | x = (x|(x<<8))&0x00ff00ff; 55 | y = (y|(y<<8))&0x00ff00ff; 56 | x = (x|(x<<4))&0x0f0f0f0f; 57 | y = (y|(y<<4))&0x0f0f0f0f; 58 | x = (x|(x<<2))&0x33333333; 59 | y = (y|(y<<2))&0x33333333; 60 | x = (x|(x<<1))&0x55555555; 61 | y = (y|(y<<1))&0x55555555; 62 | return x|(y<<1); 63 | } 64 | 65 | static uint32_t 66 | unpack1555 (uint32_t colour) 67 | { 68 | uint32_t a = (uint32_t)(255*((colour>>15)&31)); 69 | uint32_t r = (uint32_t)(255*((colour>>10)&31)/31.0); 70 | uint32_t g = (uint32_t)(255*((colour>> 5)&31)/31.0); 71 | uint32_t b = (uint32_t)(255*((colour )&31)/31.0); 72 | return (r<<24)|(g<<16)|(b<<8)|a; 73 | } 74 | 75 | static uint32_t 76 | unpack4444 (uint32_t colour) 77 | { 78 | uint32_t a = (uint32_t)(255*((colour>>12)&15)/15.0); 79 | uint32_t r = (uint32_t)(255*((colour>> 8)&15)/15.0); 80 | uint32_t g = (uint32_t)(255*((colour>> 4)&15)/15.0); 81 | uint32_t b = (uint32_t)(255*((colour )&15)/15.0); 82 | return (r<<24)|(g<<16)|(b<<8)|a; 83 | } 84 | static uint32_t 85 | unpack565 (uint32_t colour) 86 | { 87 | uint32_t r = (uint32_t)(255*((colour>>11)&31)/31.0); 88 | uint32_t g = (uint32_t)(255*((colour>> 5)&63)/63.0); 89 | uint32_t b = (uint32_t)(255*((colour )&31)/31.0); 90 | return (r<<24)|(g<<16)|(b<<8)|0xff; 91 | } 92 | 93 | static void 94 | write_24 (uint8_t **buf, uint32_t px) 95 | { 96 | uint8_t *pix = *buf; 97 | pix[0] = (px>>24)&0xff; 98 | pix[1] = (px>>16)&0xff; 99 | pix[2] = (px>> 8)&0xff; 100 | pix += 3; 101 | *buf = pix; 102 | } 103 | static void 104 | write_32 (uint8_t **buf, uint32_t px) 105 | { 106 | uint8_t *pix = *buf; 107 | pix[0] = (px>>24)&0xff; 108 | pix[1] = (px>>16)&0xff; 109 | pix[2] = (px>> 8)&0xff; 110 | pix[3] = (px )&0xff; 111 | pix += 4; 112 | *buf = pix; 113 | } 114 | 115 | int 116 | pvr_surface_decode_ptr ( 117 | PVR_surface *dst, 118 | uint32_t type, 119 | uint32_t format, 120 | uint32_t width, 121 | uint32_t height, 122 | size_t size, 123 | uint8_t *src 124 | ){ 125 | /*Set up I/O*/ 126 | uint32_t (*decoder) (uint32_t); 127 | void (*writer) (uint8_t **, uint32_t); 128 | uint32_t scalar = 0; 129 | switch (format) 130 | { 131 | case PVR_ARGB1555: 132 | decoder = unpack1555; 133 | writer = write_32; 134 | scalar = 4; 135 | break; 136 | case PVR_ARGB4444: 137 | decoder = unpack4444; 138 | writer = write_32; 139 | scalar = 4; 140 | break; 141 | case PVR_RGB565: 142 | decoder = unpack565; 143 | writer = write_24; 144 | scalar = 3; 145 | break; 146 | default: 147 | return PVR_NO_IMP; 148 | } 149 | 150 | /*Fill out the surface*/ 151 | dst->data = malloc (scalar*width*height); 152 | if (NULL == dst->data) 153 | { 154 | return PVR_NO_MEM; 155 | } 156 | dst->width = width; 157 | dst->height = height; 158 | dst->bpp = scalar; 159 | 160 | /*Decode the image data...*/ 161 | switch (type) 162 | { 163 | case PVR_VQ: 164 | case PVR_VQ_MIPMAP: 165 | case PVR_SMALL_VQ: 166 | case PVR_SMALL_VQ_MIPMAP: { 167 | uint32_t hw = width/2; 168 | uint32_t hh = height/2; 169 | uint32_t pitch = scalar*width; 170 | 171 | /*Extract VQ codebook*/ 172 | uint16_t codebook[PVR_CODEBOOK]; 173 | memcpy (codebook, src, sizeof (codebook)); 174 | 175 | /*Offset to highest resolution mipmap*/ 176 | uint8_t *pixels = src + size - hw*hh; 177 | 178 | /*Data is morton coded indices into the 2x2 16bit pixel codebook*/ 179 | uint8_t *row0 = (uint8_t *)dst->data; 180 | uint8_t *row1 = (uint8_t *)dst->data + pitch; 181 | for (uint32_t i = 0; i < hh; i++) 182 | { 183 | for (uint32_t j = 0; j < hw; j++) 184 | { 185 | uint32_t entry = 4*pixels[morton (i, j)]; 186 | writer (&row0, decoder (codebook[entry + 0])); 187 | writer (&row1, decoder (codebook[entry + 1])); 188 | writer (&row0, decoder (codebook[entry + 2])); 189 | writer (&row1, decoder (codebook[entry + 3])); 190 | } 191 | row0 += pitch; 192 | row1 += pitch; 193 | } 194 | } break; 195 | case PVR_TWIDDLED: 196 | case PVR_TWIDDLED_MIPMAP: 197 | case PVR_TWIDDLED_MIPMAP_DMA: 198 | case PVR_RECTANGLE_TWIDDLED: { 199 | /*Offset to highest resolution mipmap*/ 200 | uint16_t *pixels = (uint16_t *)(src + size - 2*width*height); 201 | uint8_t *row = (uint8_t *)dst->data; 202 | for (uint32_t i = 0; i < height; i++) 203 | { 204 | for (uint32_t j = 0; j < width; j++) 205 | { 206 | uint32_t colour = decoder (pixels[morton (i, j)]); 207 | writer (&row, colour); 208 | } 209 | } 210 | } break; 211 | case PVR_RECTANGLE: 212 | case PVR_RECTANGLE_MIPMAP: { 213 | /*Offset to highest resolution mipmap*/ 214 | uint16_t *pixels = (uint16_t *)(src + size - 2*width*height); 215 | uint8_t *row = (uint8_t *)dst->data; 216 | for (uint32_t i = 0; i < height; i++) 217 | { 218 | for (uint32_t j = 0; j < width; j++) 219 | { 220 | uint32_t index = i*width + j; 221 | uint32_t colour = decoder (pixels[index]); 222 | writer (&row, colour); 223 | } 224 | } 225 | } break; 226 | default: 227 | return PVR_NO_IMP; 228 | } 229 | return PVR_OK; 230 | } 231 | 232 | int 233 | pvr_surface_decode (PVR_surface *dst, uint8_t *src) 234 | { 235 | assert (sizeof (PVR_header) == 16 && "PVR_header is not 16 bytes!"); 236 | uint8_t *p = src; 237 | 238 | /*Ensure data is (likely) a PVR texture*/ 239 | uint32_t magick = *(uint32_t *)p; 240 | if (PVR_GBIX != magick && PVR_PVRT != magick) 241 | { 242 | return PVR_INVALID; 243 | } 244 | 245 | /*Skip gbix header*/ 246 | if (PVR_GBIX == magick) 247 | { 248 | p += 12; 249 | } 250 | 251 | /*Valid PVR header*/ 252 | PVR_header h = *(PVR_header *)p; 253 | if (PVR_PVRT != h.magick) 254 | { 255 | return PVR_INVALID; 256 | } 257 | if (PVR_MAX_WIDTH < h.width) 258 | { 259 | return PVR_BAD_SIZE; 260 | } 261 | if (PVR_MAX_HEIGHT < h.height) 262 | { 263 | return PVR_BAD_SIZE; 264 | } 265 | p += sizeof (h); 266 | 267 | /*Decode the data proper*/ 268 | return pvr_surface_decode_ptr ( 269 | dst, 270 | h.type, h.format, 271 | h.width, h.height, 272 | h.size - 8, p 273 | ); 274 | } 275 | int 276 | pvr_surface_free (PVR_surface *surf) 277 | { 278 | assert (surf != NULL && "surf is NULL!"); 279 | if (surf->data) 280 | { 281 | free (surf->data); 282 | surf->data = NULL; 283 | } 284 | return PVR_OK; 285 | } 286 | -------------------------------------------------------------------------------- /src/km.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /*Calling convention*/ 4 | #define KMAPI __stdcall 5 | 6 | #define PVR_TWIDDLED 0x1 7 | #define PVR_TWIDDLED_MIPMAP 0x2 8 | #define PVR_TWIDDLED_MIPMAP_DMA 0x12 /*Has padding at the end*/ 9 | #define PVR_VQ 0x3 10 | #define PVR_VQ_MIPMAP 0x4 11 | #define PVR_RECTANGLE 0x9 12 | #define PVR_RECTANGLE_MIPMAP 0xA 13 | #define PVR_RECTANGLE_TWIDDLED 0xD 14 | #define PVR_SMALL_VQ 0x10 15 | #define PVR_SMALL_VQ_MIPMAP 0x11 16 | #define PVR_STRIDE 0xB 17 | #define PVR_STRIDE_TWIDDLED 0xC 18 | #define PVR_BITMAP 0xE 19 | #define PVR_BITMAP_MIPMAP 0xF 20 | #define PVR_PAL4 0x5 21 | #define PVR_PAL4_MIPMAP 0x6 22 | #define PVR_PAL8 0x7 23 | #define PVR_PAL8_MIPMAP 0x8 24 | 25 | /*Kamui constants*/ 26 | #define KM_OK 0 27 | #define KM_BAD_VIDEO 2 28 | #define KM_NO_MEMORY 3 29 | #define KM_NO_HW 8 30 | #define KM_BAD_PARAM 0x0ddddL 31 | #define KM_ERROR 0x0eeeeL 32 | 33 | #define KM_DREAMCAST 0x000000 34 | #define KM_NAOMI 0x010000 35 | 36 | #define KM_NTSC 0x00 37 | #define KM_VGA 0x01 38 | #define KM_PAL 0x02 39 | #define KM_INTERLACE 0x04 40 | #define KM_PSEUDONONINTERLACE 0x08 41 | #define KM_WIDTH_640 0x10 42 | #define KM_HEIGHT_480 0x20 43 | 44 | #define KM_RGB565 0 45 | #define KM_RGB555 1 46 | #define KM_ARGB1555 3 47 | #define KM_RGB888 4 48 | #define KM_ARGB8888 5 49 | 50 | #define KM_TEXTURE_ARGB1555 0x00 51 | #define KM_TEXTURE_RGB565 0x01 52 | #define KM_TEXTURE_ARGB4444 0x02 53 | #define KM_TEXTURE_YUV422 0x03 54 | #define KM_TEXTURE_BUMP 0x04 55 | #define KM_TEXTURE_RGB555 0x05 /* for PCX compatible only. */ 56 | #define KM_TEXTURE_YUV420 0x06 /* for YUV converter */ 57 | 58 | #define KM_PIXELFORMAT_ARGB1555 0x00000000 59 | #define KM_PIXELFORMAT_RGB565 0x08000000 60 | #define KM_PIXELFORMAT_ARGB4444 0x10000000 61 | #define KM_PIXELFORMAT_YUV422 0x18000000 62 | #define KM_PIXELFORMAT_BUMP 0x20000000 63 | #define KM_PIXELFORMAT_PALETTIZED_4BPP 0x28000000 64 | #define KM_PIXELFORMAT_PALETTIZED_8BPP 0x30000000 65 | 66 | #define KM_SURFACEFLAGS_MIPMAPED 0x80000000 67 | #define KM_SURFACEFLAGS_VQ 0x40000000 68 | #define KM_SURFACEFLAGS_NOTWIDDLED 0x04000000 69 | #define KM_SURFACEFLAGS_TWIDDLED 0x00000000 70 | #define KM_SURFACEFLAGS_STRIDE 0x02000000 71 | #define KM_SURFACEFLAGS_PALETTIZED 0x00008000 72 | 73 | #define KM_SURFACEFLAGS_VSIZE8 0x00000000 74 | #define KM_SURFACEFLAGS_VSIZE16 0x00000001 75 | #define KM_SURFACEFLAGS_VSIZE32 0x00000002 76 | #define KM_SURFACEFLAGS_VSIZE64 0x00000003 77 | #define KM_SURFACEFLAGS_VSIZE128 0x00000004 78 | #define KM_SURFACEFLAGS_VSIZE256 0x00000005 79 | #define KM_SURFACEFLAGS_VSIZE512 0x00000006 80 | #define KM_SURFACEFLAGS_VSIZE1024 0x00000007 81 | 82 | #define KM_SURFACEFLAGS_USIZE8 0x00000000 83 | #define KM_SURFACEFLAGS_USIZE16 0x00000008 84 | #define KM_SURFACEFLAGS_USIZE32 0x00000010 85 | #define KM_SURFACEFLAGS_USIZE64 0x00000018 86 | #define KM_SURFACEFLAGS_USIZE128 0x00000020 87 | #define KM_SURFACEFLAGS_USIZE256 0x00000028 88 | #define KM_SURFACEFLAGS_USIZE512 0x00000030 89 | #define KM_SURFACEFLAGS_USIZE1024 0x00000038 90 | 91 | #define KM_NORMAL 0xE0000000 92 | #define KM_ENDOFSTRIP 0xF0000000 93 | 94 | #define KM_MIPMAP_D_ADJUST_0_25 0x00000001 95 | #define KM_MIPMAP_D_ADJUST_0_50 0x00000002 96 | #define KM_MIPMAP_D_ADJUST_0_75 0x00000003 97 | #define KM_MIPMAP_D_ADJUST_1_00 0x00000004 98 | #define KM_MIPMAP_D_ADJUST_1_25 0x00000005 99 | #define KM_MIPMAP_D_ADJUST_1_50 0x00000006 100 | #define KM_MIPMAP_D_ADJUST_1_75 0x00000007 101 | #define KM_MIPMAP_D_ADJUST_2_00 0x00000008 102 | #define KM_MIPMAP_D_ADJUST_2_25 0x00000009 103 | #define KM_MIPMAP_D_ADJUST_2_50 0x0000000A 104 | #define KM_MIPMAP_D_ADJUST_2_75 0x0000000B 105 | #define KM_MIPMAP_D_ADJUST_3_00 0x0000000C 106 | #define KM_MIPMAP_D_ADJUST_3_25 0x0000000D 107 | #define KM_MIPMAP_D_ADJUST_3_50 0x0000000E 108 | #define KM_MIPMAP_D_ADJUST_3_75 0x0000000F 109 | 110 | #define KM_PARAM_POLYGON 0x04 111 | #define KM_PARAM_MODIFIERVOLUME 0x04 112 | #define KM_PARAM_SPRITE 0x05 113 | 114 | #define PARAMTYPE 0x00100000 115 | #define KM_LISTTYPE 0x00200000 116 | #define KM_STRIPLENGTH 0x08000000 117 | #define KM_USERCLIPMODE 0x10000000 118 | #define KM_COLORTYPE 0x00400000 119 | #define KM_UVFORMAT 0x00800000 120 | #define KM_DEPTHMODE 0x00000001 121 | #define KM_CULLINGMODE 0x00000002 122 | #define KM_SCREENCOORDINATION 0x00000004 123 | #define KM_SHADINGMODE 0x00000008 124 | #define KM_MODIFIER 0x00000010 125 | #define KM_ZWRITEDISABLE 0x00000020 126 | #define KM_SRCBLENDINGMODE 0x00000040 127 | #define KM_DSTBLENDINGMODE 0x00000080 128 | #define KM_SRCSELECT 0x01000000 129 | #define KM_DSTSELECT 0x02000000 130 | #define KM_FOGMODE 0x00000100 131 | #define KM_USESPECULAR 0x00000200 132 | #define KM_USEALPHA 0x00000400 133 | #define KM_IGNORETEXTUREALPHA 0x00000800 134 | #define KM_CLAMPUV 0x00001000 135 | #define KM_FLIPUV 0x00002000 136 | #define KM_FILTERMODE 0x00004000 137 | #define KM_SUPERSAMPLE 0x00008000 138 | #define KM_MIPMAPDADJUST 0x00010000 139 | #define KM_TEXTURESHADINGMODE 0x00020000 140 | #define KM_COLORCLAMP 0x00040000 141 | #define KM_PALETTEBANK 0x00080000 142 | #define KM_DCALCEXACT 0x04000000 143 | 144 | 145 | #define KM_MODIFIER_NORMAL_POLY 0 146 | #define KM_MODIFIER_INCLUDE_FIRST_POLY KM_MODIFIER_NORMAL_POLY 147 | #define KM_MODIFIER_EXCLUDE_FIRST_POLY KM_MODIFIER_NORMAL_POLY 148 | #define KM_MODIFIER_INCLUDE_LAST_POLY (1 << 29) 149 | #define KM_MODIFIER_EXCLUDE_LAST_POLY (2 << 29) 150 | 151 | #define KM_MAXVTF 18 152 | 153 | #define KM_DISPLAY_LIST_OPAQUE 0 154 | #define KM_DISPLAY_LIST_OPAQUE_MOD 1 155 | #define KM_DISPLAY_LIST_TRANS 2 156 | #define KM_DISPLAY_LIST_TRANS_MOD 3 157 | #define KM_DISPLAY_LIST_RESV 4 158 | #define KM_MAX_DISPLAY_LIST 5 159 | 160 | #define KM_POLYGON 0 161 | #define KM_MODIFIERVOLUME 1 162 | #define KM_SPRITE 2 163 | 164 | #define KM_NORMAL_POLYGON 0 165 | #define KM_CHEAPSHADOW_POLYGON 1 166 | 167 | #define KM_PACKEDCOLOR 0 168 | #define KM_FLOATINGCOLOR 1 169 | #define KM_INTENSITY 2 170 | #define KM_INTENSITY_PREV_FACE_COL 3 171 | 172 | #define KM_32BITUV 0 173 | #define KM_16BITUV 1 174 | 175 | #define KM_NOMODIFIER 0 176 | #define KM_MODIFIER_A 1 177 | 178 | #define KM_IGNORE 0 179 | #define KM_LESS 1 180 | #define KM_EQUAL 2 181 | #define KM_LESSEQUAL 3 182 | #define KM_GREATER 4 183 | #define KM_NOTEQUAL 5 184 | #define KM_GREATEREQUAL 6 185 | #define KM_ALWAYS 7 186 | 187 | #define KM_NOCULLING 0 188 | #define KM_CULLSMALL 1 189 | #define KM_CULLCCW 2 190 | #define KM_CULLCW 3 191 | 192 | #define KM_NOTEXTUREFLAT 0 193 | #define KM_NOTEXTUREGOURAUD 1 194 | #define KM_TEXTUREFLAT 2 195 | #define KM_TEXTUREGOURAUD 3 196 | 197 | #define KM_FOGTABLE 0 198 | #define KM_FOGVERTEX 1 199 | #define KM_NOFOG 2 200 | #define KM_FOGTABLE_2 3 201 | 202 | #define KM_BOTHINVSRCALPHA 0 203 | #define KM_BOTHSRCALPHA 1 204 | #define KM_DESTALPHA 2 205 | #define KM_DESTCOLOR 3 206 | #define KM_INVDESTALPHA 4 207 | #define KM_INVDESTCOLOR 5 208 | #define KM_INVSRCALPHA 6 209 | #define KM_INVSRCCOLOR 7 210 | #define KM_SRCALPHA 8 211 | #define KM_SRCCOLOR 9 212 | #define KM_ONE 10 213 | #define KM_ZERO 11 214 | 215 | #define KM_NOCLAMP 0 216 | #define KM_CLAMP_V 1 217 | #define KM_CLAMP_U 2 218 | #define KM_CLAMP_UV 3 219 | 220 | #define KM_NOFLIP 0 221 | #define KM_FLIP_V 1 222 | #define KM_FLIP_U 2 223 | #define KM_FLIP_UV 3 224 | 225 | #define KM_POINT_SAMPLE 0 226 | #define KM_BILINEAR 1 227 | #define KM_TRILINEAR_A 2 228 | #define KM_TRILINEAR_B 3 229 | 230 | #define KM_DECAL 0 231 | #define KM_MODULATE 1 232 | #define KM_DECAL_ALPHA 2 233 | #define KM_MODULATE_ALPHA 3 234 | 235 | typedef void (*KM_callback) (void *args); 236 | typedef struct _KM_vertex_buffers 237 | { 238 | int lists[KM_MAX_DISPLAY_LIST]; 239 | }KM_vertex_buffers; 240 | 241 | typedef struct _KM_pass_info 242 | { 243 | int flags; 244 | int *vertex_buffer; 245 | int vertex_size; 246 | int txlist; 247 | float buffer_size[KM_MAX_DISPLAY_LIST]; 248 | int opb_size[KM_MAX_DISPLAY_LIST]; 249 | }KM_pass_info; 250 | 251 | typedef struct _KM_list_state 252 | { 253 | int type; 254 | int size; 255 | int vertex_type; 256 | int vertex_bank; 257 | int curr_pass; 258 | int max_pass; 259 | int flags; 260 | }KM_list_state; 261 | 262 | typedef struct _KM_vertex_desc 263 | { 264 | int **curr; 265 | int *param; 266 | KM_list_state *curr_list; 267 | KM_vertex_buffers **buffer; 268 | int size; 269 | KM_pass_info *passinfo; 270 | int resv; 271 | }KM_vertex_desc; 272 | 273 | typedef struct _KM_vertex_ctx 274 | { 275 | int state; 276 | int param_type; 277 | int list_type; 278 | int color_type; 279 | int uv_type; 280 | int depth_mode; 281 | int cull_mode; 282 | int resv0; 283 | int shade_mode; 284 | int modifier; 285 | int depth_write; 286 | int src_blend; 287 | int dst_blend; 288 | int src_select; 289 | int dst_select; 290 | int fog_mode; 291 | int use_specular; 292 | int use_alpha; 293 | int no_attribute; 294 | int clamp_uv; 295 | int flip_uv; 296 | int filter_mode; 297 | int super_sample; 298 | int mipmap_bias; 299 | int texture_mode; 300 | int clamp_color; 301 | int palette; 302 | void *surface; 303 | float a, r, g, b; 304 | float sa, sr, sg, sb; 305 | int param; 306 | int isp; 307 | int tsp; 308 | int tparam; 309 | int modifer_inst; 310 | float r0, r1, r2, r3; 311 | int exact; 312 | int resv1; 313 | int user_clip; 314 | }KM_vertex_ctx; 315 | 316 | typedef struct _KM_surface_desc 317 | { 318 | int type; 319 | int depth; 320 | int format; 321 | int width, height; 322 | int size; 323 | int flags; 324 | void *surface; 325 | }KM_surface_desc; 326 | 327 | /*Misc state*/ 328 | KMAPI int kmInitDevice (int device); 329 | KMAPI int kmSetDisplayMode (int mode, int bpp, int dither, int aa); 330 | KMAPI int kmSetWaitVsyncCount (int count); 331 | KMAPI int kmSetCullingRegister (float value); 332 | KMAPI int kmSetPixelClipping (int xmin, int ymin, int xmax, int ymax); 333 | KMAPI int kmRender (void); 334 | 335 | /*Framebuffers*/ 336 | KMAPI int kmCreateFrameBufferSurface ( 337 | KM_surface_desc *surf, 338 | int width, int height, 339 | int stripbuffer, 340 | int bufferclear 341 | ); 342 | KMAPI int kmActivateFrameBuffer ( 343 | KM_surface_desc *front, 344 | KM_surface_desc *back, 345 | int stripbuffer, 346 | int vsync 347 | ); 348 | KMAPI int kmFlipFrameBuffer (void); 349 | 350 | /*Callbacks*/ 351 | KMAPI int kmSetVSyncCallback (KM_callback func, void *args); 352 | KMAPI int kmSetEORCallback (KM_callback func, void *args); 353 | KMAPI int kmSetEndOfVertexCallback (KM_callback func, void *args); 354 | 355 | /*Vertices*/ 356 | KMAPI int kmCreateVertexBuffer ( 357 | KM_vertex_desc *desc, 358 | int opaque_buffer, 359 | int opaque_modifier, 360 | int trans_buffer, 361 | int trans_modifier 362 | ); 363 | KMAPI int kmSetVertexRenderState (KM_vertex_ctx *ctx); 364 | KMAPI int kmProcessVertexRenderState (KM_vertex_ctx *ctx); 365 | KMAPI int kmDiscardVertexBuffer (KM_vertex_desc *desc); 366 | KMAPI int kmStartVertexStrip (KM_vertex_desc *desc); 367 | KMAPI int kmSetVertex (KM_vertex_desc *desc, void *v, int type, int size); 368 | 369 | /*Textures*/ 370 | KMAPI int kmCreateTextureSurface ( 371 | KM_surface_desc *surf, 372 | int width, int height, 373 | int type 374 | ); 375 | KMAPI int kmLoadTexture (KM_surface_desc *surf, void *data, int unk0, int unk1); 376 | KMAPI int kmFreeTexture (KM_surface_desc *surf); 377 | KMAPI int kmReLoadMipmap (KM_surface_desc *surf, void *texture, int count); 378 | KMAPI int kmGetFreeTextureMem (int *size, int *block); 379 | KMAPI int kmSetFramebufferTexture (KM_surface_desc *surface); 380 | 381 | /*Modifier Volumes*/ 382 | KMAPI int kmSetModifierRenderState (KM_vertex_desc *desc, KM_vertex_ctx *ctx); 383 | KMAPI int kmUseAnotherModifier (int modifier); 384 | 385 | /*Background Planes*/ 386 | KMAPI int kmSetBackGroundPlane (void *v[3], int type, int size); 387 | KMAPI int kmSetBackGroundRenderState (KM_vertex_ctx *ctx); 388 | 389 | KMAPI int kmSetFogTable (void *); 390 | KMAPI int kmSetFogDensity (void *); 391 | KMAPI int kmSetFogTableColor (void *); 392 | -------------------------------------------------------------------------------- /src/d3d9.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "log.h" 12 | #include "local.h" 13 | 14 | /*Raw strings are not in the C spec, 15 | but the preprocessor can work around that...*/ 16 | #define RAWSTRING(...) #__VA_ARGS__ 17 | 18 | const char *kamui_vertex = RAWSTRING( 19 | struct VS_INPUT 20 | { 21 | float3 pos : POSITION; 22 | float2 tc : TEXCOORD0; 23 | float4 colour : COLOR0; 24 | float4 offset : COLOR1; 25 | }; 26 | struct VS_OUTPUT 27 | { 28 | float4 pos : POSITION; 29 | float4 tc : TEXCOORD0; 30 | float4 colour : COLOR0; 31 | float4 offset : COLOR1; 32 | }; 33 | 34 | float4x4 tform : register (c0); 35 | 36 | VS_OUTPUT main (in VS_INPUT v) 37 | { 38 | VS_OUTPUT o; 39 | o.pos = mul (tform, float4 (v.pos, 1.0)); 40 | o.tc = float4 (v.tc*o.pos.z, 0, o.pos.z); 41 | o.colour = v.colour; 42 | o.offset = v.offset*v.pos.z; 43 | o.pos.z = 0; 44 | return o; 45 | } 46 | ); 47 | 48 | const char *kamui_frag = RAWSTRING( 49 | struct PS_INPUT 50 | { 51 | float4 tc : TEXCOORD0; 52 | float4 colour : COLOR0; 53 | float4 offset : COLOR1; 54 | }; 55 | struct PS_OUTPUT 56 | { 57 | float4 colour : COLOR0; 58 | float depth : DEPTH; 59 | }; 60 | 61 | sampler2D tex : register (s0); 62 | float4 trialpha : register (c0); 63 | float4 mode : register (c1); 64 | 65 | PS_OUTPUT main (in PS_INPUT p) 66 | { 67 | PS_OUTPUT o; 68 | float4 ofs = p.offset/p.tc.w; 69 | float4 col = p.colour; 70 | float4 texel = tex2Dproj (tex, p.tc); 71 | 72 | 73 | int use_alpha = int (mode.y + 0.5); 74 | if (0 == use_alpha) col.a = 1.0; 75 | 76 | int val = int (mode.x + 0.5); 77 | if (val == 0) 78 | { 79 | o.colour = texel; 80 | } 81 | else if (val == 1) 82 | { 83 | o.colour.rgb = col.rgb*texel.rgb; 84 | o.colour.a = texel.a; 85 | } 86 | else if (val == 2) 87 | { 88 | o.colour.rgb = lerp (col.rgb, texel.rgb, texel.a); 89 | o.colour.a = col.a; 90 | } 91 | else 92 | { 93 | o.colour = col*texel; 94 | } 95 | o.colour.rgb += ofs.rgb; 96 | o.colour *= trialpha; 97 | o.depth = log2 (1.0 + p.tc.w*100000.0)/34.0; 98 | return o; 99 | } 100 | ); 101 | 102 | static HWND _win; 103 | static HINSTANCE _hinst; 104 | static IDirect3D9 *_d3d9 = NULL; 105 | static IDirect3DDevice9 *_d3dev = NULL; 106 | static IDirect3DVertexBuffer9 *_buf = NULL; 107 | static IDirect3DVertexShader9 *_vs = NULL; 108 | static IDirect3DPixelShader9 *_ps = NULL; 109 | static LPDIRECT3DVERTEXDECLARATION9 _vtxdecl; 110 | 111 | static int 112 | d3d_init (HWND hwnd, IDirect3D9 **iface, IDirect3DDevice9 **device) 113 | { 114 | HRESULT status; 115 | 116 | IDirect3D9 *d3d9 = Direct3DCreate9 (D3D_SDK_VERSION); 117 | if (NULL == d3d9) 118 | { 119 | return -1; 120 | } 121 | 122 | D3DPRESENT_PARAMETERS params; 123 | memset (¶ms, 0, sizeof (params)); 124 | params.Windowed = TRUE; 125 | params.SwapEffect = D3DSWAPEFFECT_DISCARD; 126 | params.EnableAutoDepthStencil = TRUE; 127 | params.AutoDepthStencilFormat = D3DFMT_D24S8; 128 | params.hDeviceWindow = hwnd; 129 | params.BackBufferWidth = 640; 130 | params.BackBufferHeight = 480; 131 | params.BackBufferFormat = D3DFMT_A8R8G8B8; 132 | params.BackBufferCount = 1; 133 | params.MultiSampleType = D3DMULTISAMPLE_NONE; 134 | params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; 135 | 136 | IDirect3DDevice9 *dev; 137 | status = IDirect3D9_CreateDevice ( 138 | d3d9, 139 | D3DADAPTER_DEFAULT, 140 | D3DDEVTYPE_HAL, 141 | hwnd, 142 | D3DCREATE_HARDWARE_VERTEXPROCESSING 143 | |D3DCREATE_MULTITHREADED, 144 | ¶ms, 145 | &dev 146 | ); 147 | if (D3D_OK != status) 148 | { 149 | IDirect3D9_Release (dev); 150 | return -2; 151 | } 152 | 153 | /*Create vertex buffer and definition*/ 154 | status = IDirect3DDevice9_CreateVertexBuffer ( 155 | dev, 156 | _cfg.vb_size, 157 | 0, 158 | 0, 159 | D3DPOOL_MANAGED, 160 | &_buf, 161 | NULL 162 | ); 163 | if (D3D_OK != status) 164 | { 165 | return -3; 166 | } 167 | 168 | D3DVERTEXELEMENT9 decl[] = { 169 | {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0}, 170 | {0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0}, 171 | {0, 16, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1}, 172 | {0, 20, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0}, 173 | D3DDECL_END() 174 | }; 175 | IDirect3DDevice9_CreateVertexDeclaration (dev, decl, &_vtxdecl); 176 | IDirect3DDevice9_SetVertexDeclaration (dev, _vtxdecl); 177 | 178 | /*Create vertex shader*/ 179 | ID3DBlob *vs = NULL; 180 | ID3DBlob *ps = NULL; 181 | ID3DBlob *error = NULL; 182 | status = D3DCompile ( 183 | kamui_vertex, 184 | strlen (kamui_vertex), 185 | "Vertex Shader", 186 | NULL, 187 | NULL, 188 | "main", 189 | "vs_3_0", 190 | D3DCOMPILE_DEBUG, 191 | 0, 192 | &vs, 193 | &error 194 | ); 195 | if (D3D_OK != status) 196 | { 197 | CRITICAL("%s", (char *)error->lpVtbl->GetBufferPointer (error)); 198 | return -4; 199 | } 200 | status = IDirect3DDevice9_CreateVertexShader ( 201 | dev, 202 | vs->lpVtbl->GetBufferPointer (vs), 203 | &_vs 204 | ); 205 | if (D3D_OK != status) 206 | { 207 | return -5; 208 | } 209 | vs->lpVtbl->Release (vs); 210 | 211 | /*Create fragment shader*/ 212 | status = D3DCompile ( 213 | kamui_frag, 214 | strlen (kamui_frag), 215 | "Fragment Shader", 216 | NULL, 217 | NULL, 218 | "main", 219 | "ps_3_0", 220 | D3DCOMPILE_DEBUG, 221 | 0, 222 | &ps, 223 | &error 224 | ); 225 | if (D3D_OK != status) 226 | { 227 | CRITICAL("%s", (char *)error->lpVtbl->GetBufferPointer (error)); 228 | return -6; 229 | } 230 | status = IDirect3DDevice9_CreatePixelShader ( 231 | dev, 232 | ps->lpVtbl->GetBufferPointer (ps), 233 | &_ps 234 | ); 235 | if (D3D_OK != status) 236 | { 237 | return -7; 238 | } 239 | ps->lpVtbl->Release (ps); 240 | 241 | *iface = d3d9; 242 | *device = dev; 243 | return 0; 244 | } 245 | /*Misc state*/ 246 | static int 247 | InitDevice (int device, void *instance, void *window) 248 | { 249 | static const float proj[] = { 250 | 2.0/640.0, 0, 0, 0, 251 | 0, -2.0/480.0, 0, 0, 252 | 0, 0, 1, 0, 253 | -1, 1, 0, 1 254 | }; 255 | 256 | _hinst = (HINSTANCE)instance; 257 | _win = (HWND)window; 258 | 259 | d3d_init ((HWND)window, &_d3d9, &_d3dev); 260 | 261 | IDirect3DDevice9_SetVertexShader (_d3dev, _vs); 262 | IDirect3DDevice9_SetVertexShaderConstantF (_d3dev, 0, proj, 4); 263 | IDirect3DDevice9_SetPixelShader (_d3dev, _ps); 264 | 265 | D3DVIEWPORT9 vp; 266 | memset (&vp, 0, sizeof (vp)); 267 | vp.X = 0; 268 | vp.Y = 0; 269 | vp.Width = 640; 270 | vp.Height = 480; 271 | vp.MinZ = 0; 272 | vp.MaxZ = 1; 273 | IDirect3DDevice9_SetViewport (_d3dev, &vp); 274 | 275 | return KM_OK; 276 | } 277 | static int 278 | DestroyDevice (void) 279 | { 280 | TRACE("Destroying D3D9..."); 281 | if (_d3dev) IDirect3DDevice9_Release (_d3dev); 282 | if (_d3d9) IDirect3D9_Release (_d3d9); 283 | return KM_OK; 284 | } 285 | static int 286 | SetPixelClipping (int xmin, int ymin, int xmax, int ymax) 287 | { 288 | D3DVIEWPORT9 vp; 289 | memset (&vp, 0, sizeof (vp)); 290 | vp.X = xmin; 291 | vp.Y = ymin; 292 | vp.Width = xmax; 293 | vp.Height = ymax; 294 | vp.MinZ = 0; 295 | vp.MaxZ = 1; 296 | IDirect3DDevice9_SetViewport (_d3dev, &vp); 297 | return KM_OK; 298 | } 299 | 300 | static void 301 | apply_context (KM_vertex_ctx *ctx) 302 | { 303 | static DWORD sblends[] = 304 | { 305 | D3DBLEND_INVSRCALPHA, 306 | D3DBLEND_SRCALPHA, 307 | D3DBLEND_SRCCOLOR, 308 | D3DBLEND_SRCALPHA, 309 | D3DBLEND_INVSRCALPHA, 310 | D3DBLEND_INVSRCCOLOR, 311 | D3DBLEND_INVDESTALPHA, 312 | D3DBLEND_INVDESTCOLOR, 313 | D3DBLEND_SRCALPHA, //this one 314 | D3DBLEND_DESTALPHA, 315 | D3DBLEND_ONE, 316 | D3DBLEND_ZERO 317 | }; 318 | static DWORD dblends[] = 319 | { 320 | D3DBLEND_SRCALPHA, 321 | D3DBLEND_INVSRCALPHA, 322 | D3DBLEND_DESTALPHA, 323 | D3DBLEND_DESTCOLOR, 324 | D3DBLEND_INVSRCCOLOR, 325 | D3DBLEND_INVSRCALPHA, 326 | D3DBLEND_INVSRCALPHA, //this one 327 | D3DBLEND_INVDESTALPHA, 328 | D3DBLEND_SRCALPHA, 329 | D3DBLEND_SRCCOLOR, 330 | D3DBLEND_ONE, 331 | D3DBLEND_ZERO 332 | }; 333 | 334 | IDirect3DDevice9_SetTexture (_d3dev, 0, ctx->surface); 335 | 336 | float x = 1.0; 337 | if (ctx->filter_mode > 1) 338 | { 339 | x = 0.25*(ctx->mipmap_bias&0x3); 340 | if (ctx->filter_mode == 2) 341 | x = 1 - x; 342 | } 343 | float alpha[] = {1, 1, 1, x}; 344 | IDirect3DDevice9_SetPixelShaderConstantF (_d3dev, 0, alpha, 1); 345 | 346 | float mode[] = {ctx->texture_mode, ctx->use_alpha, 0, 0}; 347 | IDirect3DDevice9_SetPixelShaderConstantF (_d3dev, 1, mode, 1); 348 | 349 | if (KM_IGNORE == ctx->depth_mode) 350 | { 351 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_ZENABLE, FALSE); 352 | } 353 | else 354 | { 355 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_ZENABLE, TRUE); 356 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_ZFUNC, ctx->depth_mode + 1); 357 | } 358 | 359 | switch (ctx->cull_mode) 360 | { 361 | case KM_NOCULLING: 362 | case KM_CULLSMALL: 363 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_CULLMODE, D3DCULL_NONE); 364 | break; 365 | case KM_CULLCCW: 366 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_CULLMODE, D3DCULL_CCW); 367 | break; 368 | case KM_CULLCW: 369 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_CULLMODE, D3DCULL_CW); 370 | break; 371 | default: 372 | TRACE("%s : Bad culling param!", __func__); 373 | break; 374 | } 375 | 376 | switch (ctx->shade_mode) 377 | { 378 | case KM_NOTEXTUREFLAT: 379 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_SHADEMODE, D3DSHADE_FLAT); 380 | break; 381 | case KM_NOTEXTUREGOURAUD: 382 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_SHADEMODE, D3DSHADE_GOURAUD); 383 | break; 384 | case KM_TEXTUREFLAT: 385 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_SHADEMODE, D3DSHADE_FLAT); 386 | break; 387 | case KM_TEXTUREGOURAUD: 388 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_SHADEMODE, D3DSHADE_GOURAUD); 389 | break; 390 | default: 391 | TRACE("%s : Bad shading param!", __func__); 392 | break; 393 | } 394 | 395 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_ZWRITEENABLE, !ctx->depth_write); 396 | if (KM_DISPLAY_LIST_TRANS == ctx->list_type) 397 | { 398 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_ALPHABLENDENABLE, TRUE); 399 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_SRCBLEND, sblends[ctx->src_blend]); 400 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_DESTBLEND, dblends[ctx->dst_blend]); 401 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_SRCBLENDALPHA, sblends[ctx->src_blend]); 402 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_DESTBLENDALPHA, dblends[ctx->dst_blend]); 403 | } 404 | else 405 | { 406 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_ALPHABLENDENABLE, FALSE); 407 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); 408 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); 409 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_SRCBLENDALPHA, D3DBLEND_SRCALPHA); 410 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_DESTBLENDALPHA, D3DBLEND_INVSRCALPHA); 411 | } 412 | 413 | switch (ctx->clamp_uv) 414 | { 415 | case KM_CLAMP_V: 416 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); 417 | break; 418 | case KM_CLAMP_U: 419 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); 420 | break; 421 | case KM_CLAMP_UV: 422 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP); 423 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP); 424 | break; 425 | default: 426 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); 427 | break; 428 | } 429 | 430 | switch (ctx->flip_uv) 431 | { 432 | case KM_FLIP_V: 433 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR); 434 | break; 435 | case KM_FLIP_U: 436 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR); 437 | break; 438 | case KM_FLIP_UV: 439 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR); 440 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR); 441 | break; 442 | default: 443 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP); 444 | break; 445 | } 446 | 447 | switch (ctx->filter_mode) 448 | { 449 | default: 450 | case KM_POINT_SAMPLE: 451 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MINFILTER, D3DTEXF_POINT); 452 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); 453 | break; 454 | case KM_BILINEAR: 455 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 456 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 457 | break; 458 | case KM_TRILINEAR_A: 459 | case KM_TRILINEAR_B: 460 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); 461 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); 462 | IDirect3DDevice9_SetSamplerState (_d3dev, D3DVERTEXTEXTURESAMPLER0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); 463 | break; 464 | } 465 | } 466 | static int 467 | Render (void) 468 | { 469 | IDirect3DDevice9_Clear ( 470 | _d3dev, 471 | 0, NULL, 472 | D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER, 473 | D3DCOLOR_XRGB(0, 0, 0), 474 | 0, 475 | 0 476 | ); 477 | IDirect3DDevice9_BeginScene (_d3dev); 478 | 479 | IDirect3DVertexBuffer9 *vb = _buf; 480 | IDirect3DDevice9_SetStreamSource (_d3dev, 0, vb, 0, 36); 481 | 482 | void *buffer = NULL; 483 | IDirect3DVertexBuffer9_Lock (vb, 0, 0, (void **)&buffer, 0); 484 | memcpy (buffer, km.geobuf, km.geobuf_used); 485 | IDirect3DVertexBuffer9_Unlock (vb); 486 | 487 | for (int i = 0; i < KM_MAX_DISPLAY_LIST; i++) 488 | { 489 | KM_command_list *cl = km.cl + i; 490 | KM_polygon *head = NULL; 491 | size_t read = 0; 492 | 493 | TRACE("CL %i has %i bytes", i, cl->used); 494 | while (read < cl->used) 495 | { 496 | KM_command *cmd = (KM_command *)((char *)cl->buffer + read); 497 | switch (cmd->code) 498 | { 499 | case KMC_NOP: 500 | break; 501 | case KMC_POLY: { 502 | KM_polygon *ply = (KM_polygon *)cmd; 503 | if (i == 0) 504 | { 505 | apply_context (&ply->ctx); 506 | IDirect3DDevice9_DrawPrimitive ( 507 | _d3dev, 508 | D3DPT_TRIANGLESTRIP, 509 | ply->offset, 510 | ply->nverts - 2 511 | ); 512 | } 513 | else 514 | { 515 | KM_polygon *n = head; 516 | KM_polygon *prev = head; 517 | while (n != NULL) 518 | { 519 | if (n->sort <= ply->sort) 520 | { 521 | prev = n; 522 | n = n->next; 523 | continue; 524 | } 525 | ply->next = n->next; 526 | n->next = ply; 527 | goto Linked; 528 | } 529 | if (prev) 530 | { 531 | prev->next = ply; 532 | ply->next = NULL; 533 | } 534 | Linked: 535 | if (!head) head = ply; 536 | } 537 | } break; 538 | default: 539 | TRACE("Unknown render code %i!!", cmd->code); 540 | } 541 | read += cmd->size; 542 | } 543 | while (head != NULL) 544 | { 545 | apply_context (&head->ctx); 546 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_ALPHABLENDENABLE, TRUE); 547 | IDirect3DDevice9_SetRenderState (_d3dev, D3DRS_ZWRITEENABLE, FALSE); 548 | IDirect3DDevice9_DrawPrimitive ( 549 | _d3dev, 550 | D3DPT_TRIANGLESTRIP, 551 | head->offset, 552 | head->nverts - 2 553 | ); 554 | head = head->next; 555 | } 556 | 557 | TRACE("Processed %u bytes of geometry", km.geobuf_used); 558 | cl->used = 0; 559 | } 560 | km.geobuf_used = 0; 561 | km.geobuf_indices = 0; 562 | IDirect3DDevice9_EndScene (_d3dev); 563 | return KM_OK; 564 | } 565 | 566 | /*Framebuffers*/ 567 | static int 568 | FlipFrameBuffer (void) 569 | { 570 | IDirect3DDevice9_Present (_d3dev, NULL, NULL, _win, NULL); 571 | return KM_OK; 572 | } 573 | 574 | /*Textures*/ 575 | static int 576 | CreateTextureSurface ( 577 | KM_surface_desc *surf, 578 | int width, int height, 579 | int type 580 | ) { 581 | D3DFORMAT d3df; 582 | d3df = D3DFMT_A8R8G8B8; 583 | DWORD mipmaps = 1; 584 | DWORD usage = 0; 585 | 586 | KM_shim *shim = (KM_shim *)surf->surface; 587 | IDirect3DDevice9_CreateTexture ( 588 | _d3dev, 589 | surf->width, surf->height, 590 | mipmaps, usage, 591 | d3df, 592 | D3DPOOL_MANAGED, 593 | (IDirect3DTexture9 **)(&(shim->surface)), 594 | NULL 595 | ); 596 | return KM_OK; 597 | } 598 | static int 599 | LoadTexture (KM_surface_desc *surf, uint32_t width, uint32_t height, uint32_t bpp, void *data) 600 | { 601 | D3DLOCKED_RECT rect; 602 | KM_shim *shim = (KM_shim *)surf->surface; 603 | IDirect3DTexture9_LockRect ((IDirect3DTexture9 *)shim->surface, 0, &rect, 0, 0); 604 | uint8_t *pix = (uint8_t *)rect.pBits; 605 | uint8_t *buf = (uint8_t *)data; 606 | uint32_t pitch = rect.Pitch>>2; 607 | if (4 == bpp) 608 | { 609 | for (uint32_t i = 0; i < height; i++) 610 | { 611 | for (uint32_t j = 0; j < width; j++) 612 | { 613 | uint32_t dst = 4*i*pitch + 4*j; 614 | uint32_t src = bpp*i*width + bpp*j; 615 | pix[dst + 0] = buf[src + 2]; 616 | pix[dst + 1] = buf[src + 1]; 617 | pix[dst + 2] = buf[src + 0]; 618 | pix[dst + 3] = buf[src + 3]; 619 | } 620 | } 621 | } 622 | else 623 | { 624 | for (uint32_t i = 0; i < height; i++) 625 | { 626 | for (uint32_t j = 0; j < width; j++) 627 | { 628 | uint32_t dst = 4*i*pitch + 4*j; 629 | uint32_t src = bpp*i*width + bpp*j; 630 | pix[dst + 0] = buf[src + 2]; 631 | pix[dst + 1] = buf[src + 1]; 632 | pix[dst + 2] = buf[src + 0]; 633 | pix[dst + 3] = 0xff; 634 | } 635 | } 636 | } 637 | IDirect3DTexture9_UnlockRect ((IDirect3DTexture9 *)shim->surface, 0); 638 | return KM_OK; 639 | } 640 | static int 641 | FreeTexture (KM_surface_desc *surf) 642 | { 643 | if (surf->surface) 644 | { 645 | KM_shim *shim = surf->surface; 646 | IDirect3DTexture9_Release ((IDirect3DTexture9 *)shim->surface); 647 | } 648 | return KM_OK; 649 | } 650 | 651 | Backend backend_d3d9 = 652 | { 653 | .tag = "d3d9", 654 | .init_device = InitDevice, 655 | .destroy_device = DestroyDevice, 656 | 657 | .framebuffer_flip = FlipFrameBuffer, 658 | 659 | .pixel_clipping = SetPixelClipping, 660 | .render = Render, 661 | 662 | .texture_create = CreateTextureSurface, 663 | .texture_load = LoadTexture, 664 | .texture_free = FreeTexture 665 | }; 666 | -------------------------------------------------------------------------------- /src/km.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "local.h" 13 | 14 | static HWND _win; 15 | static HINSTANCE _hinst; 16 | static HANDLE _timer; 17 | static Backend *_backends[] = 18 | { 19 | &backend_d3d9, 20 | NULL 21 | }; 22 | static Backend *_backend = NULL; 23 | 24 | KM_global_state km; 25 | Log _log; 26 | Config _cfg; 27 | 28 | static void 29 | parse_cfg (const char *file, Config *cfg) 30 | { 31 | #define MAX_TOKEN 128 32 | Script script; 33 | 34 | memset (cfg, 0, sizeof (*cfg)); 35 | cfg->vb_size = 8*1024*1024; 36 | 37 | if (script_from_file (&script, file)) 38 | { 39 | TRACE("No configuration file found"); 40 | return; 41 | } 42 | 43 | while (1) 44 | { 45 | char token[MAX_TOKEN]; 46 | int type = 0; 47 | int code = 0; 48 | 49 | code = script_next (&script, &type, token, MAX_TOKEN); 50 | if (SCRIPT_OK != code) 51 | { 52 | TRACE("SCRIPT ERROR"); 53 | } 54 | 55 | TRACE("%s", token); 56 | if (SCRIPT_EOF == type) 57 | { 58 | break; 59 | } 60 | 61 | if (!strcmp ("loglevel", token)) 62 | { 63 | script_next (&script, &type, token, MAX_TOKEN); 64 | cfg->loglevel = (uint32_t)atoi (token); 65 | continue; 66 | } 67 | if (!strcmp ("framelimit", token)) 68 | { 69 | script_next (&script, &type, token, MAX_TOKEN); 70 | cfg->framelimit = (uint32_t)atoi (token); 71 | continue; 72 | } 73 | if (!strcmp ("vb_size", token)) 74 | { 75 | script_next (&script, &type, token, MAX_TOKEN); 76 | cfg->vb_size = (size_t)atoi (token)*1024*1024; 77 | continue; 78 | } 79 | if (!strcmp ("backend", token)) 80 | { 81 | script_next (&script, &type, token, MAX_TOKEN); 82 | snprintf (cfg->backend, 16, "%16s", token); 83 | continue; 84 | } 85 | 86 | TRACE("Unrecognised token \'%s\'", token); 87 | } 88 | script_destroy (&script); 89 | } 90 | 91 | static int 92 | video_init (HINSTANCE hinst, HWND *window) 93 | { 94 | static const char *NAME = "Kamui Video-out"; 95 | HWND hwnd; 96 | WNDCLASS wc; 97 | 98 | memset (&wc, 0, sizeof (wc)); 99 | wc.lpfnWndProc = DefWindowProcA; 100 | wc.hInstance = hinst; 101 | wc.lpszClassName = NAME; 102 | if (0 == RegisterClass (&wc)) 103 | { 104 | return -1; 105 | } 106 | 107 | hwnd = CreateWindowEx ( 108 | 0, 109 | NAME, 110 | NAME, 111 | WS_OVERLAPPED|WS_CAPTION|WS_THICKFRAME, 112 | CW_USEDEFAULT, CW_USEDEFAULT, 113 | 640, 480, 114 | NULL, 115 | NULL, 116 | hinst, 117 | NULL 118 | ); 119 | if (NULL == hwnd) 120 | { 121 | return -2; 122 | } 123 | 124 | /*All good*/ 125 | ShowWindow (hwnd, SW_NORMAL); 126 | *window = hwnd; 127 | return 0; 128 | } 129 | 130 | BOOL WINAPI 131 | DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved) 132 | { 133 | switch( fdwReason ) 134 | { 135 | case DLL_PROCESS_ATTACH: 136 | log_create (&_log, "kamui_log.txt"); 137 | TRACE("===================="); 138 | TRACE("KAMUI DIRECT!"); 139 | TRACE("Compiled %s @ %s", __DATE__, __TIME__); 140 | TRACE("Dedicated to all the punks and cowboys out there in c-space"); 141 | TRACE("===================="); 142 | 143 | _timer = CreateWaitableTimer (NULL, TRUE, NULL); 144 | 145 | parse_cfg ("kamui.cfg", &_cfg); 146 | _log.level = _cfg.loglevel; 147 | _hinst = hinstDLL; 148 | break; 149 | case DLL_PROCESS_DETACH: 150 | _backend->destroy_device (); 151 | 152 | TRACE("Destroying video-out window..."); 153 | DestroyWindow (_win); 154 | 155 | TRACE("Keep the dream alive."); 156 | log_destroy (&_log); 157 | break; 158 | } 159 | return TRUE; 160 | } 161 | 162 | static inline void 163 | uv_from_f16 (DWORD uv, float *u, float *v) 164 | { 165 | union 166 | { 167 | DWORD dw; 168 | float fl; 169 | }val; 170 | 171 | val.dw = uv<<16; 172 | *u = val.fl; 173 | 174 | val.dw = uv&0xffff0000; 175 | *v = val.fl; 176 | } 177 | static DWORD 178 | vtx0_copy (void *dst, size_t length, void *src) 179 | { 180 | struct 181 | { 182 | float x, y, z; 183 | DWORD diff; 184 | DWORD spec; 185 | float u, v, s, t; 186 | }*output = dst; 187 | struct 188 | { 189 | int type; 190 | float x; 191 | float y; 192 | float z; 193 | int resv0; 194 | int resv1; 195 | int argb; 196 | int resv2; 197 | }*vtx = src; 198 | while (length--) 199 | { 200 | output->x = vtx->x; 201 | output->y = vtx->y; 202 | output->z = vtx->z; 203 | output->u = 0; 204 | output->v = 0; 205 | output->s = 1; 206 | output->t = 1; 207 | 208 | output->diff = vtx->argb; 209 | output->spec = D3DCOLOR_ARGB(0, 0, 0, 0); 210 | output++; 211 | vtx++; 212 | } 213 | return 0; 214 | } 215 | static DWORD 216 | vtx1_copy (void *dst, size_t length, void *src) 217 | { 218 | struct 219 | { 220 | float x, y, z; 221 | DWORD diff; 222 | DWORD spec; 223 | float u, v, s, t; 224 | }*output = dst; 225 | struct 226 | { 227 | int type; 228 | float x, y, z; 229 | float a, r, g, b; 230 | }*vtx = src; 231 | while (length--) 232 | { 233 | output->x = vtx->x; 234 | output->y = vtx->y; 235 | output->z = vtx->z; 236 | output->u = 0; 237 | output->v = 0; 238 | output->s = 1; 239 | output->t = 1; 240 | 241 | DWORD a = 255*vtx->a; 242 | DWORD r = 255*vtx->r; 243 | DWORD g = 255*vtx->g; 244 | DWORD b = 255*vtx->b; 245 | output->diff = D3DCOLOR_ARGB(a, r, g, b); 246 | output->spec = D3DCOLOR_ARGB(0, 0, 0, 0); 247 | output++; 248 | vtx++; 249 | } 250 | return 0; 251 | } 252 | static DWORD 253 | vtx2_copy (void *dst, size_t length, void *src) 254 | { 255 | struct 256 | { 257 | float x, y, z; 258 | DWORD diff; 259 | DWORD spec; 260 | float u, v, s, t; 261 | }*output = dst; 262 | struct 263 | { 264 | int type; 265 | float x; 266 | float y; 267 | float z; 268 | int resv0; 269 | int resv1; 270 | float intensity; 271 | int resv2; 272 | }*vtx = src; 273 | while (length--) 274 | { 275 | output->x = vtx->x; 276 | output->y = vtx->y; 277 | output->z = vtx->z; 278 | output->u = 0; 279 | output->v = 0; 280 | output->s = 0; 281 | output->t = 1; 282 | 283 | int white = 255*vtx->intensity; 284 | output->diff = D3DCOLOR_ARGB (255, white, white, white); 285 | output->spec = D3DCOLOR_ARGB(0, 0, 0, 0); 286 | output++; 287 | vtx++; 288 | } 289 | return 0; 290 | } 291 | static DWORD 292 | vtx3_copy (void *dst, size_t length, void *src) 293 | { 294 | struct 295 | { 296 | float x, y, z; 297 | DWORD diff; 298 | DWORD spec; 299 | float u, v, s, t; 300 | }*output = dst; 301 | struct 302 | { 303 | int type; 304 | float x; 305 | float y; 306 | float z; 307 | float u, v; 308 | DWORD diff; 309 | DWORD spec; 310 | }*vtx = src; 311 | while (length--) 312 | { 313 | output->x = vtx->x; 314 | output->y = vtx->y; 315 | output->z = vtx->z; 316 | 317 | output->u = vtx->u; 318 | output->v = vtx->v; 319 | output->s = vtx->z; 320 | output->t = vtx->z; 321 | 322 | output->diff = vtx->diff; 323 | output->spec = vtx->spec; 324 | output++; 325 | vtx++; 326 | 327 | 328 | } 329 | return 1; 330 | } 331 | static DWORD 332 | vtx4_copy (void *dst, size_t length, void *src) 333 | { 334 | struct 335 | { 336 | float x, y, z; 337 | DWORD diff; 338 | DWORD spec; 339 | float u, v, s, t; 340 | }*output = dst; 341 | struct 342 | { 343 | int type; 344 | float x; 345 | float y; 346 | float z; 347 | DWORD uv; 348 | DWORD resv; 349 | DWORD diff; 350 | DWORD spec; 351 | }*vtx = src; 352 | while (length--) 353 | { 354 | output->x = vtx->x; 355 | output->y = vtx->y; 356 | output->z = vtx->z; 357 | 358 | uv_from_f16 (vtx->uv, &output->u, &output->v); 359 | 360 | output->diff = vtx->diff; 361 | output->spec = vtx->spec; 362 | output++; 363 | vtx++; 364 | } 365 | return 1; 366 | } 367 | static DWORD 368 | vtx5_copy (void *dst, size_t length, void *src) 369 | { 370 | struct 371 | { 372 | float x, y, z; 373 | DWORD diff; 374 | DWORD spec; 375 | float u, v, s, t; 376 | }*output = dst; 377 | struct 378 | { 379 | int type; 380 | float x; 381 | float y; 382 | float z; 383 | DWORD uv; 384 | DWORD resv0; 385 | DWORD resv1; 386 | DWORD resv2; 387 | float diff[4]; 388 | float spec[4]; 389 | }*vtx = src; 390 | while (length--) 391 | { 392 | output->x = vtx->x; 393 | output->y = vtx->y; 394 | output->z = vtx->z; 395 | 396 | uv_from_f16 (vtx->uv, &output->u, &output->v); 397 | 398 | DWORD a0 = 255*vtx->diff[0]; 399 | DWORD r0 = 255*vtx->diff[1]; 400 | DWORD g0 = 255*vtx->diff[2]; 401 | DWORD b0 = 255*vtx->diff[3]; 402 | output->diff = D3DCOLOR_ARGB(a0, r0, g0, b0); 403 | 404 | DWORD a1 = 255*vtx->spec[0]; 405 | DWORD r1 = 255*vtx->spec[1]; 406 | DWORD g1 = 255*vtx->spec[2]; 407 | DWORD b1 = 255*vtx->spec[3]; 408 | output->spec = D3DCOLOR_ARGB(a1, r1, g1, b1); 409 | output++; 410 | vtx++; 411 | } 412 | return 1; 413 | } 414 | static DWORD 415 | vtx6_copy (void *dst, size_t length, void *src) 416 | { 417 | struct 418 | { 419 | float x, y, z; 420 | DWORD diff; 421 | DWORD spec; 422 | float u, v, s, t; 423 | }*output = dst; 424 | struct 425 | { 426 | int type; 427 | float x; 428 | float y; 429 | float z; 430 | DWORD uv; 431 | DWORD resv0; 432 | DWORD resv1; 433 | DWORD resv2; 434 | float diff[4]; 435 | float spec[4]; 436 | }*vtx = src; 437 | while (length--) 438 | { 439 | output->x = vtx->x; 440 | output->y = vtx->y; 441 | output->z = vtx->z; 442 | 443 | uv_from_f16 (vtx->uv, &output->u, &output->v); 444 | 445 | DWORD a0 = 255*vtx->diff[0]; 446 | DWORD r0 = 255*vtx->diff[1]; 447 | DWORD g0 = 255*vtx->diff[2]; 448 | DWORD b0 = 255*vtx->diff[3]; 449 | output->diff = D3DCOLOR_ARGB(a0, r0, g0, b0); 450 | 451 | DWORD a1 = 255*vtx->spec[0]; 452 | DWORD r1 = 255*vtx->spec[1]; 453 | DWORD g1 = 255*vtx->spec[2]; 454 | DWORD b1 = 255*vtx->spec[3]; 455 | output->spec = D3DCOLOR_ARGB(a1, r1, g1, b1); 456 | 457 | output++; 458 | vtx++; 459 | } 460 | return 1; 461 | } 462 | static DWORD 463 | vtx7_copy (void *dst, size_t length, void *src) 464 | { 465 | struct 466 | { 467 | float x, y, z; 468 | DWORD diff; 469 | DWORD spec; 470 | float u, v, s, t; 471 | }*output = dst; 472 | struct 473 | { 474 | int type; 475 | float x; 476 | float y; 477 | float z; 478 | float u; 479 | float v; 480 | float diff; 481 | float spec; 482 | }*vtx = src; 483 | while (length--) 484 | { 485 | output->x = vtx->x; 486 | output->y = vtx->y; 487 | output->z = vtx->z; 488 | 489 | output->u = vtx->u; 490 | output->v = vtx->v; 491 | output->s = vtx->z; 492 | output->t = vtx->z; 493 | 494 | DWORD a0 = 255*km.ctx.a; 495 | DWORD r0 = 255*km.ctx.r; 496 | DWORD g0 = 255*km.ctx.g; 497 | DWORD b0 = 255*km.ctx.b; 498 | output->diff = D3DCOLOR_ARGB(a0, r0, g0, b0); 499 | 500 | DWORD a1 = vtx->spec*255*km.ctx.sa; 501 | DWORD r1 = vtx->spec*255*km.ctx.sr; 502 | DWORD g1 = vtx->spec*255*km.ctx.sg; 503 | DWORD b1 = vtx->spec*255*km.ctx.sb; 504 | output->spec = D3DCOLOR_ARGB(a1, r1, g1, b1); 505 | output++; 506 | vtx++; 507 | } 508 | return 1; 509 | } 510 | static DWORD 511 | vtx8_copy (void *dst, size_t length, void *src) 512 | { 513 | struct 514 | { 515 | float x, y, z; 516 | DWORD diff; 517 | DWORD spec; 518 | float u, v, s, t; 519 | }*output = dst; 520 | struct 521 | { 522 | int type; 523 | float x; 524 | float y; 525 | float z; 526 | DWORD uv; 527 | float diff; 528 | float spec; 529 | }*vtx = src; 530 | while (length--) 531 | { 532 | output->x = vtx->x; 533 | output->y = vtx->y; 534 | output->z = vtx->z; 535 | 536 | uv_from_f16 (vtx->uv, &output->u, &output->v); 537 | 538 | int diff = 255*vtx->diff; 539 | int spec = 255*vtx->spec; 540 | output->diff = D3DCOLOR_ARGB (255, diff, diff, diff); 541 | output->spec = D3DCOLOR_ARGB (255, spec, spec, spec); 542 | output++; 543 | vtx++; 544 | } 545 | return 1; 546 | } 547 | 548 | typedef DWORD (*KM_vtx_copy) (void *, size_t, void *); 549 | static KM_vtx_copy _vfuncs[] = 550 | { 551 | vtx0_copy, 552 | vtx1_copy, 553 | vtx2_copy, 554 | vtx3_copy, 555 | vtx4_copy, 556 | vtx5_copy, 557 | vtx6_copy, 558 | vtx7_copy, 559 | vtx8_copy 560 | }; 561 | 562 | static KM_command * 563 | km_command_alloc (int code, size_t size) 564 | { 565 | KM_command_list *cl = km.cl + km.curr_list; 566 | KM_command *cmd = (KM_command *)((char *)cl->buffer + cl->used); 567 | cmd->code = code; 568 | cmd->size = size; 569 | cl->used += size; 570 | return cmd; 571 | } 572 | 573 | /*Misc state*/ 574 | KMAPI int 575 | kmInitDevice (int device) 576 | { 577 | TRACE("%s : device (%i)", __func__, device); 578 | 579 | memset (&km, 0, sizeof (km)); 580 | km.opaque = malloc (16*1024*1024); 581 | if (NULL == km.opaque) 582 | { 583 | return KM_NO_MEMORY; 584 | } 585 | km.sorted = malloc (16*1024*1024); 586 | if (NULL == km.sorted) 587 | { 588 | return KM_NO_MEMORY; 589 | } 590 | km.geobuf = malloc (16*1024*1024); 591 | km.device = device; 592 | 593 | for (int i = 0; i < KM_MAX_DISPLAY_LIST; i++) 594 | { 595 | KM_command_list *cl = km.cl + i; 596 | cl->buffer = malloc (16*1024*1024); 597 | cl->size = 16*1024*1024; 598 | cl->used = 0; 599 | } 600 | 601 | _backend = _backends[0]; 602 | for (int i = 0; _backends[i] != NULL; i++) 603 | { 604 | if (strcmp (_backends[i]->tag, _cfg.backend) != 0) 605 | { 606 | continue; 607 | } 608 | _backend = _backends[i]; 609 | } 610 | VERIFY(_backend != NULL, "No valid backends?"); 611 | TRACE("Selected %s as the backend", _backend->tag); 612 | 613 | TRACE("Creating video-out window..."); 614 | switch (video_init (_hinst, &_win)) 615 | { 616 | case -1: 617 | TRACE(" Failed to register classname"); 618 | return FALSE; 619 | case -2: 620 | TRACE(" Failed to create window"); 621 | return FALSE; 622 | default: 623 | TRACE(" Okay!"); 624 | } 625 | 626 | TRACE("Initialising backend..."); 627 | switch (_backend->init_device (device, _hinst, _win)) 628 | { 629 | case -1: 630 | TRACE(" Failed to create d3d9 interface!"); 631 | return FALSE; 632 | case -2: 633 | TRACE(" Failed to create d3d9 device!"); 634 | return FALSE; 635 | case -3: 636 | TRACE(" Failed to create d3d9 buffers!"); 637 | return FALSE; 638 | default: 639 | TRACE(" Okay!"); 640 | } 641 | return KM_OK; 642 | } 643 | 644 | KMAPI int 645 | kmSetDisplayMode (int mode, int bpp, int dither, int aa) 646 | { 647 | TRACE("%s : mode (%i) bpp (%i) dither (%i) aa (%i)", __func__, mode, bpp, dither, aa); 648 | return KM_OK; 649 | } 650 | 651 | KMAPI int 652 | kmSetWaitVsyncCount (int count) 653 | { 654 | TRACE("%s : count (%i)", __func__, count); 655 | return KM_OK; 656 | } 657 | KMAPI int 658 | kmSetCullingRegister (float value) 659 | { 660 | TRACE("%s : value (%f)", __func__, value); 661 | return KM_OK; 662 | } 663 | KMAPI int 664 | kmSetPixelClipping (int xmin, int ymin, int xmax, int ymax) 665 | { 666 | TRACE("%s : xmin (%i) ymin (%i) xmax (%i) ymax (%i)", __func__, xmin, ymin, xmax, ymax); 667 | int x0 = xmin; 668 | int y0 = ymin; 669 | int x1 = xmax; 670 | int y1 = ymax; 671 | if (KM_RGB888 == km.display) 672 | { 673 | x0 += (xmin&1); 674 | y0 += (ymin&1); 675 | x1 -= (xmax&1); 676 | y1 -= (ymax&1); 677 | } 678 | if (km.width <= x0 - x1) 679 | { 680 | return KM_BAD_PARAM; 681 | } 682 | if (km.height <= y0 - y1) 683 | { 684 | return KM_BAD_PARAM; 685 | } 686 | return _backend->pixel_clipping (x0, y0, x1, y1); 687 | } 688 | KMAPI int 689 | kmRender (void) 690 | { 691 | TRACE("%s", __func__); 692 | 693 | /*Activate the timer for the frame if using the limiter. 694 | If we're running slower than the requested rate then this 695 | will just expire partway through the frame and skip wait 696 | at the end*/ 697 | if (_cfg.framelimit != 0) 698 | { 699 | float tick = 1000.0/_cfg.framelimit; 700 | LARGE_INTEGER duration = {.QuadPart = -tick*1000LL}; 701 | SetWaitableTimer (_timer, &duration, 0, NULL, NULL, 0); 702 | } 703 | 704 | _backend->render (); 705 | 706 | if (km.eor.func != NULL) 707 | { 708 | km.eor.func (km.eor.args); 709 | } 710 | 711 | /*Wait out residual time if using frame limiter*/ 712 | if (_cfg.framelimit != 0) 713 | { 714 | WaitForSingleObject (_timer, INFINITE); 715 | } 716 | 717 | return KM_OK; 718 | } 719 | 720 | /*Framebuffers*/ 721 | KMAPI int 722 | kmCreateFrameBufferSurface ( 723 | KM_surface_desc *surf, 724 | int width, int height, 725 | int stripbuffer, 726 | int bufferclear 727 | ) { 728 | TRACE(\ 729 | "%s : surf (%p) width (%i) height (%i), stripbuffer (%i) bufferclear (%i)",\ 730 | __func__, surf, width, height, stripbuffer, bufferclear); 731 | memset (surf, 0, sizeof (*surf)); 732 | surf->type = 1; 733 | surf->depth = 1; 734 | surf->width = width; 735 | surf->height = height; 736 | surf->size = width*height*4; 737 | return KM_OK; 738 | } 739 | KMAPI int 740 | kmActivateFrameBuffer ( 741 | KM_surface_desc *front, 742 | KM_surface_desc *back, 743 | int stripbuffer, 744 | int vsync 745 | ) { 746 | TRACE("%s : front (%p) back (%p) stripbuffer (%i) vsync (%i)",\ 747 | __func__, front, back, stripbuffer, vsync); 748 | return KM_OK; 749 | } 750 | KMAPI int 751 | kmFlipFrameBuffer (void) 752 | { 753 | TRACE("%s", __func__); 754 | return _backend->framebuffer_flip (); 755 | } 756 | 757 | /*Callbacks*/ 758 | KMAPI int 759 | kmSetVSyncCallback (KM_callback func, void *args) 760 | { 761 | TRACE("%s", __func__); 762 | km.vsync.func = func; 763 | km.vsync.args = args; 764 | return KM_OK; 765 | } 766 | KMAPI int 767 | kmSetEORCallback (KM_callback func, void *args) 768 | { 769 | TRACE("%s", __func__); 770 | km.eor.func = func; 771 | km.eor.args = args; 772 | return KM_OK; 773 | } 774 | KMAPI int 775 | kmSetEndOfVertexCallback (KM_callback func, void *args) 776 | { 777 | TRACE("%s", __func__); 778 | km.eov.func = func; 779 | km.eov.args = args; 780 | return KM_OK; 781 | } 782 | 783 | /*Vertices*/ 784 | KMAPI int 785 | kmCreateVertexBuffer ( 786 | KM_vertex_desc *desc, 787 | int opaque_buffer, 788 | int opaque_modifier, 789 | int trans_buffer, 790 | int trans_modifier 791 | ) { 792 | TRACE("%s : desc (%p) opaque_buffer (%i) opaque_modifier (%i) trans_buffer (%i) trans_modifier (%i)",\ 793 | __func__,\ 794 | desc,\ 795 | opaque_buffer, opaque_modifier,\ 796 | trans_buffer, trans_modifier); 797 | 798 | /*Verify and setup state*/ 799 | VERIFY(0 <= opaque_buffer, "opaque_buffer is < 0"); 800 | VERIFY(0 <= opaque_modifier, "opaque_modifer is < 0"); 801 | VERIFY(0 <= trans_buffer, "trans_buffer is < 0"); 802 | VERIFY(0 <= trans_modifier, "trans_modifier is < 0"); 803 | void *ptrs[KM_MAX_DISPLAY_LIST] = { 804 | NULL, 805 | NULL, 806 | NULL, 807 | NULL, 808 | NULL, 809 | }; 810 | int sizes[KM_MAX_DISPLAY_LIST] = { 811 | opaque_buffer, 812 | opaque_modifier, 813 | trans_buffer, 814 | trans_modifier, 815 | 0 816 | }; 817 | 818 | /*Allocate buffers as needed*/ 819 | for (int i = 0; i < KM_MAX_DISPLAY_LIST; i++) 820 | { 821 | int size = sizes[i]; 822 | if (size <= 0) 823 | { 824 | continue; 825 | } 826 | void *ptr = malloc (size); 827 | if (NULL == ptr) 828 | { 829 | for (int j = 0; j < i; j++) 830 | { 831 | if (ptrs[j]) free (ptrs[j]); 832 | ptrs[j] = NULL; 833 | } 834 | return KM_BAD_PARAM; 835 | } 836 | ptrs[i] = ptr; 837 | } 838 | 839 | /*Store buffers into global state*/ 840 | memcpy (km.base, ptrs, sizeof (km.base)); 841 | for (int i = 0; i < KM_MAX_DISPLAY_LIST; i++) 842 | { 843 | km.lists[i] = km.base[i]; 844 | } 845 | return KM_OK; 846 | } 847 | KMAPI int 848 | kmSetVertexRenderState (KM_vertex_ctx *ctx) 849 | { 850 | TRACE("%s : ctx (%p)", __func__, ctx); 851 | 852 | int state = ctx->state; 853 | 854 | km.curr_list = ctx->list_type; 855 | km.ctx.list_type = ctx->list_type; 856 | if (ctx->surface) 857 | { 858 | KM_surface_desc *desc = (KM_surface_desc *)ctx->surface; 859 | if (desc) 860 | { 861 | KM_shim *shim = desc->surface; 862 | km.ctx.surface = shim->surface; 863 | } 864 | } 865 | 866 | if (state&KM_DEPTHMODE) 867 | { 868 | km.ctx.depth_mode = ctx->depth_mode; 869 | } 870 | if (state&KM_CULLINGMODE) 871 | { 872 | km.ctx.cull_mode = ctx->cull_mode; 873 | } 874 | if (state&KM_SHADINGMODE) 875 | { 876 | km.ctx.shade_mode = ctx->shade_mode; 877 | } 878 | if (state&KM_ZWRITEDISABLE) 879 | { 880 | km.ctx.depth_write = ctx->depth_write; 881 | } 882 | if (state&KM_SRCBLENDINGMODE) 883 | { 884 | km.ctx.src_blend = ctx->src_blend; 885 | } 886 | if (state&KM_DSTBLENDINGMODE) 887 | { 888 | km.ctx.dst_blend = ctx->dst_blend; 889 | } 890 | if (state&KM_CLAMPUV) 891 | { 892 | km.ctx.clamp_uv = ctx->clamp_uv; 893 | } 894 | if (state&KM_FLIPUV) 895 | { 896 | km.ctx.flip_uv = ctx->flip_uv; 897 | } 898 | if (state&KM_FILTERMODE) 899 | { 900 | km.ctx.filter_mode = ctx->filter_mode; 901 | } 902 | if (state&KM_TEXTURESHADINGMODE) 903 | { 904 | km.ctx.texture_mode = ctx->texture_mode; 905 | } 906 | 907 | if (state&KM_USEALPHA) 908 | { 909 | km.ctx.use_alpha = ctx->use_alpha; 910 | } 911 | 912 | km.ctx.a = ctx->a; 913 | km.ctx.r = ctx->r; 914 | km.ctx.g = ctx->g; 915 | km.ctx.b = ctx->b; 916 | 917 | km.ctx.sa = ctx->sa; 918 | km.ctx.sr = ctx->sr; 919 | km.ctx.sg = ctx->sg; 920 | km.ctx.sb = ctx->sb; 921 | return KM_OK; 922 | } 923 | KMAPI int 924 | kmProcessVertexRenderState (KM_vertex_ctx *ctx) 925 | { 926 | TRACE("%s : ctx (%p)", __func__, ctx); 927 | return KM_OK; 928 | } 929 | KMAPI int 930 | kmDiscardVertexBuffer (KM_vertex_desc *desc) 931 | { 932 | TRACE("%s : desc (%p)", __func__, desc); 933 | return KM_OK; 934 | } 935 | KMAPI int 936 | kmStartVertexStrip (KM_vertex_desc *desc) 937 | { 938 | TRACE("%s : desc (%p)", __func__, desc); 939 | return KM_OK; 940 | } 941 | KMAPI int 942 | kmSetVertex (KM_vertex_desc *desc, void *v, int type, int size) 943 | { 944 | TRACE("%s : desc (%p) v (%p) type (%i) size (%i)", __func__, desc, v, type, size); 945 | 946 | /*No modifier volumes for now*/ 947 | if (type >= 8) 948 | { 949 | return KM_OK; 950 | } 951 | 952 | unsigned char *base = (unsigned char *)km.base[km.curr_list]; 953 | unsigned char **list = (unsigned char **)&km.lists[km.curr_list]; 954 | memcpy (*list, v, size); 955 | *list += size; 956 | 957 | int code = *(int *)v; 958 | if (KM_ENDOFSTRIP == code) 959 | { 960 | size_t length = (size_t)((ptrdiff_t)(*list - base))/size; 961 | size_t verts = length*36; 962 | 963 | /*Store vertex data in the polygon object*/ 964 | KM_polygon *ply = (KM_polygon *)km_command_alloc (KMC_POLY, sizeof (*ply)); 965 | memcpy (&(ply->ctx), &km.ctx, sizeof (ply->ctx)); 966 | ply->next = NULL; 967 | ply->offset = km.geobuf_indices; 968 | ply->sort = ((float *)base)[2]; 969 | ply->nverts = length; 970 | ply->index = 0; 971 | 972 | _vfuncs[type] ((char *)km.geobuf + km.geobuf_used, length, base); 973 | km.geobuf_used += verts; 974 | km.geobuf_indices += length; 975 | 976 | #if 0 977 | /*Compute centroid*/ 978 | float centroid[3] = {0, 0, 0}; 979 | float centroid2[3] = {0,0,0}; 980 | float *point = (float *)((char *)km.geobuf + 36*ply->offset); 981 | float de = 0; 982 | for (int i = 0; i < ply->nverts; i++) 983 | { 984 | for (int j = 0; j < 3; j++) centroid[j] += point[j]; 985 | point += 36/4; 986 | de += 1.0; 987 | } 988 | float rp = 1.0/de; 989 | for (int i = 0; i < 3; i++) centroid2[i] = rp*centroid[i]; 990 | ply->sort = sqrtf (centroid[0]*centroid[0] + centroid[1]*centroid[1] + centroid[2]*centroid2[2]); 991 | ply->sort = log2 (1.0 + centroid[2]*100000.0)/34.0; 992 | #else 993 | float *point = (float *)((char *)km.geobuf + 36*ply->offset); 994 | ply->sort = log2 (1.0 + point[2]*100000.0)/34.0; 995 | #endif 996 | 997 | /*Reset the list head*/ 998 | *list = base; 999 | 1000 | if (km.eov.func) 1001 | { 1002 | km.eov.func (km.eov.args); 1003 | } 1004 | } 1005 | return KM_OK; 1006 | } 1007 | /*Textures*/ 1008 | KMAPI int 1009 | kmCreateTextureSurface ( 1010 | KM_surface_desc *surf, 1011 | int width, int height, 1012 | int type 1013 | ) { 1014 | TRACE("%s : surf (%p) width (%i) height (%i) type (%i)", __func__, surf, width, height, type); 1015 | int flags = 0; 1016 | int fmt = (type&0xff00)>>8; 1017 | int pix = type&0x00ff; 1018 | 1019 | memset (surf, 0, sizeof (*surf)); 1020 | surf->type = 2; 1021 | surf->depth = 1; 1022 | 1023 | switch (pix) 1024 | { 1025 | case KM_TEXTURE_ARGB1555: 1026 | surf->format = KM_PIXELFORMAT_ARGB1555; 1027 | break; 1028 | case KM_TEXTURE_RGB565: 1029 | surf->format = KM_PIXELFORMAT_RGB565; 1030 | break; 1031 | case KM_TEXTURE_ARGB4444: 1032 | surf->format = KM_PIXELFORMAT_ARGB4444; 1033 | break; 1034 | case KM_TEXTURE_YUV422: surf->format = KM_PIXELFORMAT_YUV422; break; 1035 | case KM_TEXTURE_BUMP: surf->format = KM_PIXELFORMAT_BUMP; break; 1036 | default: break; 1037 | } 1038 | 1039 | switch (fmt) 1040 | { 1041 | case PVR_TWIDDLED: 1042 | case PVR_RECTANGLE_TWIDDLED: 1043 | flags = 0; 1044 | break; 1045 | case PVR_TWIDDLED_MIPMAP: 1046 | case PVR_TWIDDLED_MIPMAP_DMA: 1047 | flags = KM_SURFACEFLAGS_MIPMAPED; 1048 | break; 1049 | case PVR_VQ: 1050 | case PVR_SMALL_VQ: 1051 | flags = KM_SURFACEFLAGS_VQ; 1052 | break; 1053 | case PVR_VQ_MIPMAP: 1054 | case PVR_SMALL_VQ_MIPMAP: 1055 | flags = KM_SURFACEFLAGS_VQ|KM_SURFACEFLAGS_MIPMAPED; 1056 | break; 1057 | case PVR_RECTANGLE: 1058 | flags = KM_SURFACEFLAGS_NOTWIDDLED; 1059 | break; 1060 | case PVR_RECTANGLE_MIPMAP: 1061 | flags = KM_SURFACEFLAGS_MIPMAPED|KM_SURFACEFLAGS_NOTWIDDLED; 1062 | break; 1063 | case PVR_STRIDE: 1064 | flags = KM_SURFACEFLAGS_STRIDE|KM_SURFACEFLAGS_NOTWIDDLED; 1065 | break; 1066 | case PVR_STRIDE_TWIDDLED: 1067 | flags = KM_SURFACEFLAGS_STRIDE; 1068 | break; 1069 | case PVR_BITMAP: break; 1070 | case PVR_BITMAP_MIPMAP: break; 1071 | case PVR_PAL8: 1072 | case PVR_PAL4: 1073 | flags = KM_SURFACEFLAGS_PALETTIZED; 1074 | break; 1075 | case PVR_PAL8_MIPMAP: 1076 | case PVR_PAL4_MIPMAP: 1077 | flags = KM_SURFACEFLAGS_PALETTIZED|KM_SURFACEFLAGS_MIPMAPED; 1078 | break; 1079 | } 1080 | switch (width) 1081 | { 1082 | case 8: flags |= KM_SURFACEFLAGS_USIZE8; break; 1083 | case 16: flags |= KM_SURFACEFLAGS_USIZE16; break; 1084 | case 32: flags |= KM_SURFACEFLAGS_USIZE32; break; 1085 | case 64: flags |= KM_SURFACEFLAGS_USIZE64; break; 1086 | case 128: flags |= KM_SURFACEFLAGS_USIZE128; break; 1087 | case 256: flags |= KM_SURFACEFLAGS_USIZE256; break; 1088 | case 512: flags |= KM_SURFACEFLAGS_USIZE512; break; 1089 | case 1024: flags |= KM_SURFACEFLAGS_USIZE1024; break; 1090 | default: break; 1091 | } 1092 | switch (height) 1093 | { 1094 | case 8: flags |= KM_SURFACEFLAGS_VSIZE8; break; 1095 | case 16: flags |= KM_SURFACEFLAGS_VSIZE16; break; 1096 | case 32: flags |= KM_SURFACEFLAGS_VSIZE32; break; 1097 | case 64: flags |= KM_SURFACEFLAGS_VSIZE64; break; 1098 | case 128: flags |= KM_SURFACEFLAGS_VSIZE128; break; 1099 | case 256: flags |= KM_SURFACEFLAGS_VSIZE256; break; 1100 | case 512: flags |= KM_SURFACEFLAGS_VSIZE512; break; 1101 | case 1024: flags |= KM_SURFACEFLAGS_VSIZE1024; break; 1102 | default: break; 1103 | } 1104 | //flags = 0; 1105 | 1106 | {/*Compute total size, including mipmaps and codebooks and such*/ 1107 | uint32_t size = 0; 1108 | if (flags&KM_SURFACEFLAGS_MIPMAPED) 1109 | { 1110 | uint32_t w = width; 1111 | uint32_t h = height; 1112 | uint32_t lo = w < h ? w : h; 1113 | if (flags&KM_SURFACEFLAGS_VQ) 1114 | { 1115 | size += 2048; 1116 | size += 1; 1117 | w >>= 1; 1118 | h >>= 1; 1119 | } 1120 | while (lo != 0) 1121 | { 1122 | size += w*h; 1123 | lo >>= 1; 1124 | w >>= 1; 1125 | h >>= 1; 1126 | } 1127 | } 1128 | else size = width*height; 1129 | if (!(flags&(KM_SURFACEFLAGS_PALETTIZED|KM_SURFACEFLAGS_VQ))) 1130 | { 1131 | size <<= 1; 1132 | } 1133 | surf->size = size + 2; 1134 | } 1135 | surf->width = width; 1136 | surf->height = height; 1137 | surf->flags = flags; 1138 | 1139 | /*This is needed to convert PVR textures properly 1140 | It's not possible to losslessly recover the format flags 1141 | with the standard fields, so we box them up inside the shim 1142 | and store it on the ->surface field, then store the actual 1143 | texture object inside the shim with everything else we need. 1144 | 1145 | Not great, but not the worst either*/ 1146 | KM_shim *shim = malloc (sizeof (*shim)); 1147 | memset (shim, 0, sizeof (*shim)); 1148 | shim->type = pix; 1149 | shim->format = fmt; 1150 | surf->surface = shim; 1151 | return _backend->texture_create (surf, width, height, flags); 1152 | } 1153 | 1154 | KMAPI int 1155 | kmLoadTexture (KM_surface_desc *surf, void *data, int unk0, int unk1) 1156 | { 1157 | TRACE("%s : surf (%p) data (%p) unk0 (%i) unk1 (%i)", __func__, surf, data, unk0, unk1); 1158 | 1159 | PVR_surface tex; 1160 | KM_shim *shim = surf->surface; 1161 | if (!(surf->flags&KM_SURFACEFLAGS_MIPMAPED)) data = (char *)data - 2; 1162 | if (pvr_surface_decode_ptr (&tex, shim->format, shim->type, surf->width, surf->height, surf->size, data)) 1163 | { 1164 | TRACE("Failed to decode"); 1165 | return KM_OK; 1166 | } 1167 | 1168 | return _backend->texture_load (surf, tex.width, tex.height, tex.bpp, tex.data); 1169 | } 1170 | KMAPI int 1171 | kmFreeTexture (KM_surface_desc *surf) 1172 | { 1173 | TRACE("%s : surf (%p)", __func__, surf); 1174 | return _backend->texture_free (surf); 1175 | } 1176 | KMAPI int 1177 | kmReLoadMipmap (KM_surface_desc *surf, void *texture, int count) 1178 | { 1179 | TRACE("%s : surf (%p), texture (%p) count (%i)", __func__, surf, texture, count); 1180 | return KM_OK; 1181 | } 1182 | KMAPI int 1183 | kmGetFreeTextureMem (int *size, int *block) 1184 | { 1185 | TRACE("%s", __func__); 1186 | *size = 32*1024*1024; 1187 | *block = 1*1024*1024; 1188 | return KM_OK; 1189 | } 1190 | KMAPI int 1191 | kmSetFramebufferTexture (KM_surface_desc *surface) 1192 | { 1193 | TRACE("%s : surf (%p)", __func__, surface); 1194 | return KM_OK; 1195 | } 1196 | 1197 | /*Modifier Volumes*/ 1198 | KMAPI int 1199 | kmSetModifierRenderState (KM_vertex_desc *desc, KM_vertex_ctx *ctx) 1200 | { 1201 | TRACE("%s", __func__); 1202 | return KM_OK; 1203 | } 1204 | KMAPI int 1205 | kmUseAnotherModifier (int modifier) 1206 | { 1207 | TRACE("%s", __func__); 1208 | return KM_OK; 1209 | } 1210 | 1211 | /*Background Planes*/ 1212 | KMAPI int 1213 | kmSetBackGroundPlane (void *v[3], int type, int size) 1214 | { 1215 | TRACE("%s", __func__); 1216 | return KM_OK; 1217 | } 1218 | KMAPI int 1219 | kmSetBackGroundRenderState (KM_vertex_ctx *ctx) 1220 | { 1221 | TRACE("%s", __func__); 1222 | return KM_OK; 1223 | } 1224 | 1225 | KMAPI int 1226 | kmSetFogTable (void *user) 1227 | { 1228 | return KM_OK; 1229 | } 1230 | KMAPI int 1231 | kmSetFogDensity (void *user) 1232 | { 1233 | return KM_OK; 1234 | } 1235 | KMAPI int 1236 | kmSetFogTableColor (void *user) 1237 | { 1238 | return KM_OK; 1239 | } 1240 | 1241 | 1242 | --------------------------------------------------------------------------------