Commit d57499ef authored by Donald Haase's avatar Donald Haase
Browse files

Initial commit of libdreamscript from NesterDCSE-src_2005-12-24.zip

parents
DreamScript API Specification
by Scherzo
The following class and function definitions are only logical and are not any actually implementation of
any language.
class DSGlobal
{
enum { DM_320x240, DM_640x480, DM_800x608, DM_256x256, DM_768x480, DM_768x576 };
enum { FILE_READ, FILE_WRITE, FILE_BINARY };
}
// Completed!
class Image
{
Image();
String toString();
Boolean load(String fn, Number list, Number filtering, Number alpha);
Undefined unload();
Undefined draw(Number x, Number y, Number scale, Number a, Number z);
Undefined drawWH(Number x, Number y, Number width, Number height, Number a, Number z);
Undefined drawRotated(Number x, Number y, Number scale, Number a, Number z, Number pivotu, Number pivotv, Number angle);
String getFilename();
Number getWidth();
Number getHeight();
};
class Sprite
{
Sprite();
String toString();
Boolean load(String filename);
Undefined unload();
Sprite clone();
Undefined animAddImg(String name, Image img, Number framesDuration);
Undefined animClear(String name);
Undefined animAll();
String animation;
Image img;
Number frame;
Number x;
Number y;
Number z;
Number angle;
Number scale;
Number flippedx; // 1 is normal, -1 is flipped, can be anything in between
Number flippedy; // 1 is normal, -1 is flipped, can be anything in between
Number speed; // 1 is normal, 0 is stopped
Boolean visible;
};
// Completed!
class Controller
{
Undefined poll();
bool setMode(String strMapName);
CString getMode();
}
class Keyboard
{
Undefined poll();
}
// Completed!
class Mouse
{
Undefined poll();
Number dx;
Number dy;
Number dz;
Boolean lbutton;
Boolean rbutton;
Boolean sbutton;
}
singleton class Input
{
Boolean rescanDevices();
Array<Controller> pad;
Array<Keyboard> keyboard;
Array<Mouse> mouse;
}
singleton class Video
{
Number availableMemory();
String toString();
Undefined frameBegin();
Undefined frameFinish();
Undefined listBegin(Number list);
Undefined listFinish();
}
singleton class System
{
Number availableMemory();
}
/*
Current tested to support MOD, XM, S3M
*/
singleton class Music
{
Boolean play(String fn);
Boolean stop();
}
class SoundFX
{
SoundFX();
Boolean load(String fn);
Boolean unload();
Boolean play(Number chan = -1); // between 2 and 63. -1 means next available channel
Boolean stop(Number chan = -1); // If -1 specified. Will stop play on lasst channel used
static Boolean stopAll();
}
singleton class FileSystem
{
Boolean resetCD();
String getCWD();
Boolean setCWD(String dir);
Array getFileList(String dir);
File getFile(String filename);
}
class File
{
File();
Boolean open(String fn, String mode);
Undefined close();
Boolean seek(Number offset, Number origin);
Number tell();
Number readInt8();
Number readInt16();
Number readInt32();
Boolean writeInt8(Number n);
Boolean writeInt16(Number n);
Boolean writeInt32(Number n);
String readString();
Boolean writeString(String str);
String readChar();
}
\ No newline at end of file
# libkjs Makefile
TARGET = libdreamscript.a
# KJS
OBJS = kjs/array_object.o kjs/bool_object.o kjs/collector.o kjs/date_object.o kjs/debugger.o kjs/dtoa.o kjs/error_object.o
OBJS += kjs/function.o kjs/function_object.o kjs/grammar.o kjs/identifier.o kjs/internal.o kjs/interpreter.o kjs/lexer.o
OBJS += kjs/list.o kjs/lookup.o kjs/math_object.o kjs/nodes.o kjs/nodes2string.o kjs/number_object.o kjs/object.o
OBJS += kjs/object_object.o kjs/operations.o kjs/property_map.o kjs/reference.o kjs/reference_list.o kjs/regexp.o
OBJS += kjs/regexp_object.o kjs/scope_chain.o kjs/string_object.o kjs/ustring.o kjs/value.o kjs/snprintf.o
OBJS += kjs/pcre/pcre.o
OBJS += dreamscript.o
# DreamScript Core
OBJS += core/dc_controller.o core/dc_utils.o core/image.o
OBJS += core/dc_vmu.o core/image_object.o core/unzip.o core/unshrink.o core/explode.o core/unreduce.o
OBJS += core/video_object.o core/global_object.o core/dc_mouse.o core/input_object.o
OBJS += core/system_object.o core/filesystem_object.o core/file_object.o core/controller_object.o core/mouse_object.o
OBJS += core/XML.o core/music_object.o core/sprite_object.o core/makesplitpath.o
OBJS += core/allocator.o core/hashmap.o core/font_object.o core/soundeffect_object.o core/zipfile_object.o core/xml_object.o
OBJS += core/vmufile_object.o
KOS_CFLAGS += -g -Os
include $(KOS_BASE)/addons/Makefile.prefab
#include "XML.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
uint32 XML_resize_count = 0x10;
void XML_Init(XML* p, const char* szName)
{
if (szName)
{
uint32 len = strlen(szName);
p->name = (char*) malloc(len + 1);
memcpy(p->name, szName, len);
p->name[len] = '\0';
}
else
p->name = NULL;
p->text = NULL;
p->parent = NULL;
p->parent_delete = 1;
punk_array_init(p->children);
punk_array_init(p->attribute_names);
punk_array_init(p->attribute_values);
}
void XML_Destroy(XML* p)
{
if (p->name)
free(p->name);
if (p->text)
free(p->text);
uint32 k = 0;
for (; k < p->attribute_names.count; ++k)
free(p->attribute_names.data[k]);
for (k = 0; k < p->attribute_values.count; ++k)
free(p->attribute_values.data[k]);
for (k = 0; k < p->children.count; ++k)
{
if (p->children.data[k]->parent_delete)
free(p->children.data[k]);
}
}
void XML_SetText(XML* p, const char* szText)
{
if (p->text)
free(p->text);
p->text = (char*) malloc(strlen(szText)+1);
strcpy(p->text, szText);
}
void XML_AppendText(XML* p, const char* szText)
{
if (!p->text)
XML_SetText(p, szText);
else
{
char* sztemp = (char*) malloc(strlen(p->text)+strlen(szText)+1);
sprintf(sztemp, "%s%s", p->text, szText);
free(p->text);
p->text = sztemp;
}
}
void XML_AddChildNode(XML* p, XML* node)
{
node->parent_delete = 0;
punk_array_push(p->children, node);
node->parent = p;
}
XML* XML_AddChild(XML* p, const char* szName)
{
XML* temp = (XML*) malloc(sizeof(XML));
XML_Init(temp, szName);
XML_AddChildNode(p, temp);
return temp;
}
void XML_SetAttribute(XML* p, const char* name, const char* value)
{
uint32 k;
for (k = 0; k < p->attribute_names.count; ++k)
{
if (strcmp(p->attribute_names.data[k], name) == 0)
{
free(p->attribute_values.data[k]);
int32 len = strlen(value);
char* temp = (char*) malloc(len + 1);
memcpy(temp, value, len);
temp[len] = '\0';
p->attribute_values.data[k] = temp;
return;
}
}
int32 len = strlen(name);
char* temp = (char*) malloc(len + 1);
memcpy(temp, name, len);
temp[len] = '\0';
punk_array_push(p->attribute_names, temp);
len = strlen(value);
temp = (char*) malloc(len + 1);
memcpy(temp, value, len);
temp[len] = '\0';
punk_array_push(p->attribute_values, temp);
}
const char* XML_GetAttribute(XML* p, const char* name)
{
uint32 k;
for (k = 0; k < p->attribute_names.count; ++k)
{
if (stricmp(p->attribute_names.data[k], name) == 0)
return p->attribute_values.data[k];
}
return NULL;
}
const char* XML_GetAttributeString(XML* p, const char* name, const char* szDefault)
{
uint32 k;
for (k = 0; k < p->attribute_names.count; ++k)
{
if (stricmp(p->attribute_names.data[k], name) == 0)
return p->attribute_values.data[k];
}
return szDefault;
}
int32 XML_GetAttributeInt(XML* p, const char* name, int32 iDefault)
{
const char* sztemp = XML_GetAttribute(p, name);
if (!sztemp)
return iDefault;
return atoi(sztemp);
}
uint32 XML_GetAttributeHex(XML* p, const char* name, uint32 uiDefault)
{
const char* sztemp = XML_GetAttribute(p, name);
if (!sztemp)
return uiDefault;
hexstr_to_uint32(sztemp, &uiDefault);
return uiDefault;
}
XML* XML_Find(XML* p, const char* tagname, const char* attr_name, const char* attr_val)
{
XML* temp = NULL;
uint32 k;
for (k = 0; k < p->children.count; ++k)
{
temp = p->children.data[k];
if (stricmp(temp->name, tagname) == 0)
{
if (attr_name)
{
uint32 n;
for (n = 0; n < temp->attribute_names.count; ++n)
{
if (stricmp(temp->attribute_names.data[n], attr_name) == 0)
{
if (!attr_val || stricmp(temp->attribute_values.data[n], attr_val) == 0)
return temp;
}
}
}
else
return temp;
}
if ((temp = XML_Find(temp, tagname, attr_name, attr_val)))
return temp;
}
return NULL;
}
#define MODE_SCANNING 0
#define MODE_TAG 1
#define MODE_TEXT 2
char *ne_shave(char *str, const char *whitespace)
{
char *pnt, *ret = str;
while (*ret != '\0' && strchr(whitespace, *ret) != NULL) {
ret++;
}
/* pnt points at the NUL terminator. */
pnt = &ret[strlen(ret)];
while (pnt > ret && strchr(whitespace, *(pnt-1)) != NULL) {
pnt--;
}
*pnt = '\0';
return ret;
}
XML* XML_Parse(const char* szDoc)
{
XML* root = NULL;
XML* curnode = NULL;
int32 mode = MODE_SCANNING;
uint32 doclen = strlen(szDoc);
char* doc = (char*) malloc(doclen + 1);
memcpy(doc, szDoc, doclen);
doc[doclen] = '\0';
char* curTextBegin = NULL;
char* pos = doc;
char* end = doc + doclen;
while (pos < end)
{
//printf("pos = %d char = %c mode = %d\n", pos-doc, *pos, mode);
if (mode == MODE_SCANNING || mode == MODE_TEXT)
{
if (*pos == '<')
{
if (pos[1] == '/')
{
if (!curnode)
goto parse_failed;
// Make Text
if (mode == MODE_TEXT && curTextBegin && curnode)
{
*pos = '\0';
XML_AppendText(curnode, ne_shave(curTextBegin, " \t\r\n"));
}
pos += 2;
char* base = pos;
while (*pos != '>')
{
++pos;
if (pos == end)
goto parse_failed;
}
*pos = '\0';
//printf("end tag name = %s curnode = %s\n", base, curnode->name);
if (strcmp(base, curnode->name) != 0)
goto parse_failed;
curnode = curnode->parent;
curTextBegin = pos+1;
mode = MODE_TEXT;
}
else
{
++pos;
char* base = pos;
while (!isspace(*pos) && *pos != '>')
{
++pos;
if (pos == end)
goto parse_failed;
}
char ctemp = *pos;
*pos = '\0';
//printf("new tag name = %s\n", base);
//++pos;
XML* temp = (XML*) malloc(sizeof(XML));
XML_Init(temp, base);
if (!root)
root = temp;
else
XML_AddChildNode(curnode, temp);
curnode = temp;
*pos = ctemp;
pos--;
mode = MODE_TAG;
}
}
}
else if (mode == MODE_TAG)
{
if (!isspace(*pos))
{
switch (*pos)
{
case '>':
{
if (pos[-1] == '/')
{
//printf("self close start = %s\n", curnode->name);
curnode = curnode->parent;
//printf("self close end = %s\n", curnode->name);
}
curTextBegin = pos+1;
mode = MODE_TEXT;
break;
}
case '/':
{
break;
}
default: // attribute name
{
char* name_base = pos;
while (*pos != '=')
{
++pos;
if (pos == end)
goto parse_failed;
}
*pos = '\0';
++pos;
if (*pos != '"')
goto parse_failed;
++pos;
char* value_base = pos;
while (*pos != '"')
{
++pos;
if (pos == end)
goto parse_failed;
}
*pos = '\0';
//printf("attribute tag:%s %s=%s\n", curnode->name, name_base, value_base);
XML_SetAttribute(curnode, name_base, value_base);
break;
}
};
}
}
++pos;
}
free(doc);
return root;
parse_failed:
//printf("what?!\n");
if (root)
XML_Destroy(root);
free(doc);
return NULL;
}
XML* XML_OpenFile(const char* filename)
{
FILE* fp = fopen(filename, "rb");
if (fp)
{
fseek(fp, 0, SEEK_END);
int32 filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char* szTemp = (char*) malloc(filesize+1);
fread(szTemp, 1, filesize, fp);
szTemp[filesize] = '\0';
fclose(fp);
XML* tempXML = XML_Parse(szTemp);
free(szTemp);
return tempXML;
}
return NULL;
}
#if !defined(AFX_XML_H__D9F1340C_4C0C_4F5C_A646_46D6D74C3489__INCLUDED_)
#define AFX_XML_H__D9F1340C_4C0C_4F5C_A646_46D6D74C3489__INCLUDED_
#include "dc_utils.h"
#include "punk_array.h"
START_EXTERN_C
typedef struct SXML
{
char* name;
char* text;
DECLARE_PUNK_ARRAY(children, struct SXML*);
DECLARE_PUNK_ARRAY(attribute_names, char*);
DECLARE_PUNK_ARRAY(attribute_values, char*);
struct SXML* parent;
char parent_delete;
} XML;
extern uint32 XML_resize_count;
void XML_Init(XML* p, const char* szName /*= NULL*/);
void XML_Destroy(XML* p);
void XML_SetText(XML* p, const char* szText);
void XML_AppendText(XML* p, const char* szText);
void XML_AddChildNode(XML* p, XML* node);
XML* XML_AddChild(XML* p, const char* szName);
void XML_SetAttribute(XML* p, const char* name, const char* value);
const char* XML_GetAttribute(XML* p, const char* name);
const char* XML_GetAttributeString(XML* p, const char* name, const char* szDefault);
int32 XML_GetAttributeInt(XML* p, const char* name, int32 iDefault);
uint32 XML_GetAttributeHex(XML* p, const char* name, uint32 uiDefault);
XML* XML_Find(XML* p, const char* tagname, const char* attr_name /*= NULL*/, const char* attr_val /*= NULL*/);
XML* XML_Parse(const char* szDoc);
XML* XML_OpenFile(const char* filename);
END_EXTERN_C
#endif
/* allocator - allocate and free memory
* Copyright (c) 2003 Michael B. Allen <mba2000 ioplex.com>
*
* The MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <errno.h>
#include "allocator.h"
//#include "mba/msgno.h"
#include "defines.h"
void *
allocator_alloc(struct allocator *al0, size_t size, int zero)
{
struct allocator *al = al0 ? al0 : stdlib_allocator;
void *p;
if ((p = al->alloc(al, size, zero)) == NULL) {
//AMSG("");
}
return p;
}
void *
allocator_realloc(struct allocator *al0, void *obj, size_t size)
{
struct allocator *al = al0 ? al0 : stdlib_allocator;
void *p;
if ((p = al->realloc(al, obj, size)) == NULL && size) {
//AMSG("");
}
return p;
}
int
allocator_free(void *al0, void *obj)
{
struct allocator *al = al0 ? al0 : stdlib_allocator;
if (al->free(al, obj) == -1) {
//AMSG("");
return -1;
}
return 0;
}
void
allocator_set_reclaim(struct allocator *al, reclaim_fn recl, void *arg)
{
al->reclaim = recl;
al->reclaim_arg = arg;
}
void *
stdlib_alloc(struct allocator *al, size_t size, int zero)
{
void *p;
if (zero) {
p = calloc(1, size);
} else {
p = malloc(size);
}
if (p == NULL) {
//PMNO(errno);
return NULL;
}
al = NULL;
return p;
}
void *
stdlib_realloc(struct allocator *al, void *obj, size_t size)
{
void *p;
if ((p = realloc(obj, size)) == NULL && size) {
//PMNO(errno);
}
al = NULL;
return p;
}
int
stdlib_free(void *al, void *obj)
{
al = NULL;
if (obj)
free(obj);
return 0;
}
struct allocator _stdlib_allocator = {
"", 0, 0, 0, 0, 0, 0,
&stdlib_alloc,
&stdlib_realloc,
&stdlib_free,
NULL, NULL, 0, 0
};
struct allocator *stdlib_allocator = &_stdlib_allocator;
#ifndef ALLOCATOR_H
#define ALLOCATOR_H
/* allocator - allocate and free memory
*/
#ifdef __cplusplus
extern "C" {
#endif
#ifndef LIBMBA_API
#ifdef WIN32
# ifdef LIBMBA_EXPORTS
# define LIBMBA_API __declspec(dllexport)
# else /* LIBMBA_EXPORTS */
# define LIBMBA_API __declspec(dllimport)
# endif /* LIBMBA_EXPORTS */
#else /* WIN32 */
# define LIBMBA_API extern
#endif /* WIN32 */
#endif /* LIBMBA_API */
#include <stddef.h>
typedef size_t ref_t; /* suba offset from start of memory to object */
struct allocator;
typedef void *(*alloc_fn)(struct allocator *al, size_t size, int flags);
typedef void *(*realloc_fn)(struct allocator *al, void *obj, size_t size);
typedef int (*free_fn)(void *al, void *obj);
typedef int (*reclaim_fn)(struct allocator *al, void *arg, int attempt);
typedef void *(*new_fn)(void *context, size_t size, int flags);
typedef int (*del_fn)(void *context, void *object);
struct allocator {
unsigned char magic[8]; /* suba header identifier */
ref_t tail; /* offset to first cell in free list */
size_t mincell; /* min cell size must be at least sizeof cell */
size_t size; /* total size of memory area */
size_t alloc_total; /* total bytes utilized from this allocator */
size_t free_total; /* total bytes released from this allocator */
size_t size_total; /* total bytes requested from this allocator */
/* utilization = size_total / alloc_total * 100
* e.g. 50000.0 / 50911.0 * 100.0 = 98.2%
*/
alloc_fn alloc;
realloc_fn realloc;
free_fn free;
/* for reaping memory from pool, varray, etc */
reclaim_fn reclaim;
void *reclaim_arg;
int reclaim_depth;
ref_t userref;
};
LIBMBA_API struct allocator *stdlib_allocator;
LIBMBA_API void *allocator_alloc(struct allocator *al, size_t size, int flags);
LIBMBA_API void *allocator_realloc(struct allocator *al, void *obj, size_t size);
LIBMBA_API int allocator_free(void *al, void *obj);
LIBMBA_API void allocator_set_reclaim(struct allocator *al, reclaim_fn recl, void *arg);
#ifdef __cplusplus
}
#endif
#endif /* ALLOCATOR_H */
#include "controller_object.h"
#include "dc_utils.h"
#include "allocator.h"
#include "../kjs/lookup.h"
#include "input_object.h"
#define POLL_FUNC (CONT_DPAD2_RIGHT+1)
#define CONT_LTRIG (CONT_DPAD2_RIGHT+2)
#define CONT_RTRIG (CONT_DPAD2_RIGHT+3)
#define CONT_XAXIS (CONT_DPAD2_RIGHT+4)
#define CONT_YAXIS (CONT_DPAD2_RIGHT+5)
#define SETMODE_FUNC (CONT_DPAD2_RIGHT+6)
#define GETMODE_FUNC (CONT_DPAD2_RIGHT+7)
#define JUSTPRESSED_FUNC (CONT_DPAD2_RIGHT+8)
const ClassInfo ControllerImp::info = { "Controller", 0, 0, 0 };
struct hashmap* ControllerImp::storedMaps = NULL;
ControllerImp::ControllerImp(struct DCController* pad) : ObjectImp()
{
m_pad = pad;
cmdMap = (struct hashmap*) hashmap_get(storedMaps, "default");
}
struct hashmap* CreateBarebonesMap()
{
struct hashmap* tempmap = hashmap_new(hash_str, cmp_str, NULL, stdlib_allocator);
hashmap_put(tempmap, (void*) "poll", (void*) POLL_FUNC);
hashmap_put(tempmap, (void*) "setMode", (void*) SETMODE_FUNC);
hashmap_put(tempmap, (void*) "getMode", (void*) GETMODE_FUNC);
hashmap_put(tempmap, (void*) "justPressed", (void*) JUSTPRESSED_FUNC);
return tempmap;
}
bool ControllerImp::InitDefaultMappings()
{
struct hashmap* tempmap = CreateBarebonesMap();
storedMaps = hashmap_new(hash_str, cmp_str, NULL, stdlib_allocator);
// default mappings
#ifdef _arch_dreamcast
hashmap_put(tempmap, (void*) "A", (void*) CONT_A);
hashmap_put(tempmap, (void*) "B", (void*) CONT_B);
hashmap_put(tempmap, (void*) "X", (void*) CONT_X);
hashmap_put(tempmap, (void*) "Y", (void*) CONT_Y);
hashmap_put(tempmap, (void*) "START", (void*) CONT_START);
hashmap_put(tempmap, (void*) "UP", (void*) CONT_DPAD_UP);
hashmap_put(tempmap, (void*) "DOWN", (void*) CONT_DPAD_DOWN);
hashmap_put(tempmap, (void*) "LEFT", (void*) CONT_DPAD_LEFT);
hashmap_put(tempmap, (void*) "RIGHT", (void*) CONT_DPAD_RIGHT);
hashmap_put(tempmap, (void*) "LTRIG", (void*) CONT_LTRIG);
hashmap_put(tempmap, (void*) "RTRIG", (void*) CONT_RTRIG);
hashmap_put(tempmap, (void*) "XAXIS", (void*) CONT_XAXIS);
hashmap_put(tempmap, (void*) "YAXIS", (void*) CONT_YAXIS);
#else
#error You must define an architecture. Choices are: _arch_dreamcast
#endif
hashmap_put(storedMaps, (void*) "default", tempmap);
return true;
}
bool ControllerImp::LoadMappingsXML(XML* xmlnode)
{
XML* systemnode = XML_Find(xmlnode, "system", "name", "dreamcast");
if (!systemnode)
return false;
XML* inputnode = XML_Find(xmlnode, "input", NULL, NULL);
if (!inputnode)
return false;
uint32 k;
XML* modenode;
XML* controllernode;
const char* strTempName;
for (k = 0; k < inputnode->children.count; ++k)
{
modenode = inputnode->children.data[k];
if (stricmp(modenode->name, "mode") != 0)
continue;
strTempName = XML_GetAttribute(modenode, "name");
if (!strTempName)
continue;
controllernode = XML_Find(modenode, "controller", NULL, NULL);
if (!controllernode)
continue;
uint32 n = 0;
struct hashmap* tempMap = CreateBarebonesMap();
const char* strButtonName;
const char* strButtonMapping;
XML* actionnode;
uint32 iButton;
for (; n < controllernode->children.count; ++n)
{
actionnode = controllernode->children.data[n];
strButtonName = XML_GetAttribute(actionnode, "name");
strButtonMapping = XML_GetAttribute(actionnode, "mapping");
if (stricmp(actionnode->name, "action") != 0 || !strButtonName || !strButtonMapping)
continue;
if (stricmp(strButtonMapping, "A") == 0)
iButton = CONT_A;
else if (stricmp(strButtonMapping, "B") == 0)
iButton = CONT_B;
else if (stricmp(strButtonMapping, "X") == 0)
iButton = CONT_X;
else if (stricmp(strButtonMapping, "Y") == 0)
iButton = CONT_Y;
else if (stricmp(strButtonMapping, "START") == 0)
iButton = CONT_START;
else if (stricmp(strButtonMapping, "UP") == 0)
iButton = CONT_DPAD_UP;
else if (stricmp(strButtonMapping, "DOWN") == 0)
iButton = CONT_DPAD_DOWN;
else if (stricmp(strButtonMapping, "LEFT") == 0)
iButton = CONT_DPAD_LEFT;
else if (stricmp(strButtonMapping, "RIGHT") == 0)
iButton = CONT_DPAD_RIGHT;
else if (stricmp(strButtonMapping, "XAXIS") == 0)
iButton = CONT_XAXIS;
else if (stricmp(strButtonMapping, "YAXIS") == 0)
iButton = CONT_YAXIS;
else if (stricmp(strButtonMapping, "LTRIG") == 0)
iButton = CONT_LTRIG;
else if (stricmp(strButtonMapping, "RTRIG") == 0)
iButton = CONT_RTRIG;
else
continue;
hashmap_put(tempMap, (void*) strButtonName, (void*) iButton);
}
hashmap_put(storedMaps, (void*) strTempName, tempMap);
}
return true;
}
Value ControllerImp::get(ExecState *exec, const Identifier &propertyName) const
{
uint32 val = (uint32) hashmap_get(cmdMap, propertyName.ascii());
switch (val)
{
case POLL_FUNC:
return lookupOrCreateFunction<ControllerFunctionImp>(exec, propertyName, this, ControllerImp::e_poll, 0, DontDelete|ReadOnly|Function);
case SETMODE_FUNC:
return lookupOrCreateFunction<ControllerFunctionImp>(exec, propertyName, this, ControllerImp::e_setMode, 1, DontDelete|ReadOnly|Function);
case GETMODE_FUNC:
return lookupOrCreateFunction<ControllerFunctionImp>(exec, propertyName, this, ControllerImp::e_getMode, 0, DontDelete|ReadOnly|Function);
case JUSTPRESSED_FUNC:
return lookupOrCreateFunction<ControllerFunctionImp>(exec, propertyName, this, ControllerImp::e_justPressed, 1, DontDelete|ReadOnly|Function);
case CONT_LTRIG:
return Number(m_pad->state.ltrig);
case CONT_RTRIG:
return Number(m_pad->state.rtrig);
case CONT_XAXIS:
return Number(m_pad->state.joyx);
case CONT_YAXIS:
return Number(m_pad->state.joyy);
case CONT_A:
case CONT_B:
case CONT_X:
case CONT_Y:
case CONT_START:
case CONT_DPAD_UP:
case CONT_DPAD_DOWN:
case CONT_DPAD_LEFT:
case CONT_DPAD_RIGHT:
return Boolean(DCController_IsPressed(m_pad, val));
break;
}
return ObjectImp::get(exec, propertyName);
}
void ControllerImp::poll()
{
DCController_Poll(m_pad);
}
bool ControllerImp::setMode(const char* strMapName)
{
struct hashmap* tempmap = (struct hashmap*) hashmap_get(storedMaps, strMapName);
if (!tempmap)
return false;
cmdMap = tempmap;
modeName = strMapName;
return true;
}
CString ControllerImp::getMode()
{
return modeName;
}
bool ControllerImp::justPressed(const char* strval)
{
uint32 val = (uint32) hashmap_get(cmdMap, strval);
switch (val)
{
case CONT_LTRIG:
return (!m_pad->old_state.ltrig && m_pad->state.ltrig);
case CONT_RTRIG:
return (!m_pad->old_state.rtrig && m_pad->state.rtrig);
case CONT_A:
case CONT_B:
case CONT_X:
case CONT_Y:
case CONT_START:
case CONT_DPAD_UP:
case CONT_DPAD_DOWN:
case CONT_DPAD_LEFT:
case CONT_DPAD_RIGHT:
return DCController_JustPressed(m_pad, val);
break;
}
return false;
}
ControllerFunctionImp::ControllerFunctionImp(ExecState* exec, int i, int len) : ObjectImp()
{
id = i;
put(exec, lengthPropertyName, Number(len), DontDelete|ReadOnly|DontEnum);
}
Value ControllerFunctionImp::call(ExecState *exec, Object &thisObj, const List &args)
{
if (thisObj.className() != "Controller")
{
Object err = Error::create(exec, TypeError);
exec->setException(err);
return err;
}
switch (id)
{
case ControllerImp::e_poll:
{
((ControllerImp*) thisObj.imp())->poll();
break;
}
case ControllerImp::e_setMode:
{
if (args.size() == 1)
{
CString str = args[0].toString(exec).cstring();
return Boolean(((ControllerImp*) thisObj.imp())->setMode(str.c_str()));
}
break;
}
case ControllerImp::e_getMode:
{
return String(((ControllerImp*) thisObj.imp())->getMode().c_str());
break;
}
case ControllerImp::e_justPressed:
{
if (args.size() == 1)
{
CString str = args[0].toString(exec).cstring();
return Boolean(((ControllerImp*) thisObj.imp())->justPressed(str.c_str()));
}
break;
}
}
return Undefined();
}
void InitControllers(ExecState* exec, Object obj)
{
ControllerImp::InitDefaultMappings();
if (g_inputXML)
ControllerImp::LoadMappingsXML(g_inputXML);
else
dbgio_printf("g_inputXML == NULL\n");
List locargs;
int k;
ControllerImp* tempControllerImp;
for (k = 0; k < 4; ++k)
{
DCController_Init(g_controllers + k);
g_controllers[k].dev = dc_maple_controller_info[k].dev;
if (g_controllers[k].dev)
{
Object tempobj(tempControllerImp = new ControllerImp(g_controllers + k));
locargs.append(tempobj);
}
}
Object pad = exec->interpreter()->builtinArray().construct(exec, locargs);
obj.put(exec, Identifier("controller"), pad);
}
#ifndef _CONTROLLER_OBJECT_H_
#define _CONTROLLER_OBJECT_H_
#include "../kjs/value.h"
#include "../kjs/object.h"
#include "../kjs/types.h"
#include "../kjs/interpreter.h"
#include "dc_controller.h"
#include "hashmap.h"
#include "XML.h"
using namespace KJS;
class ControllerFunctionImp;
class ControllerImp : public ObjectImp
{
public:
ControllerImp(struct DCController* pad);
enum { e_poll, e_setMode, e_getMode, e_justPressed };
virtual UString className() const { return "Controller"; }
virtual Value get(ExecState *exec, const Identifier &propertyName) const;
//Value getValueProperty(ExecState *exec, int token) const;
// JS Funcs
void poll();
bool setMode(const char* strMapName);
CString getMode();
bool justPressed(const char* strval);
// end JS Funcs
struct DCController* m_pad;
struct hashmap* cmdMap;
CString modeName;
static const ClassInfo info;
static struct hashmap* storedMaps;
static bool InitDefaultMappings();
static bool LoadMappingsXML(struct SXML* xmlnode);
};
class ControllerFunctionImp : public ObjectImp
{
public:
ControllerFunctionImp(ExecState *exec, int i, int len);
virtual bool implementsCall() const { return true; }
virtual Value call(ExecState* exec, Object &thisObj, const List &args);
protected:
uint32 id;
};
void InitControllers(ExecState* exec, Object obj);
#endif
/* Automatically generated from controller_object.cpp using ./create_hash_table. DO NOT EDIT ! */
const struct HashEntry controllerTableEntries[] = {
{ "x", ControllerImp::X, DontDelete|ReadOnly, 0, 0 },
{ "y", ControllerImp::Y, DontDelete|ReadOnly, 0, 0 },
{ "right", ControllerImp::Right, DontDelete|ReadOnly, 0, 0 },
{ "start", ControllerImp::Start, DontDelete|ReadOnly, 0, 0 },
{ "poll", ControllerImp::Poll, DontDelete|ReadOnly|Function, 1, &controllerTableEntries[16] },
{ "down", ControllerImp::Down, DontDelete|ReadOnly, 0, 0 },
{ "ltrig", ControllerImp::Ltrig, DontDelete|ReadOnly, 0, 0 },
{ "a", ControllerImp::A, DontDelete|ReadOnly, 0, &controllerTableEntries[17] },
{ "joyx", ControllerImp::Joyx, DontDelete|ReadOnly, 0, &controllerTableEntries[15] },
{ "joyy", ControllerImp::Joyy, DontDelete|ReadOnly, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ "rtrig", ControllerImp::Rtrig, DontDelete|ReadOnly, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0 },
{ "b", ControllerImp::B, DontDelete|ReadOnly, 0, 0 },
{ "up", ControllerImp::Up, DontDelete|ReadOnly, 0, 0 },
{ "left", ControllerImp::Left, DontDelete|ReadOnly, 0, 0 }
};
const struct HashTable controllerTable = { 2, 18, controllerTableEntries, 15 };
#! /bin/perl -w
#
# Static Hashtable Generator
#
# (c) 2000-2002 by Harri Porten <porten@kde.org> and
# David Faure <faure@kde.org>
$file = $ARGV[0];
shift;
my $findSize = 0;
my $includelookup = 0;
# Use -s as second argument to make it try many hash sizes
$findSize = 1 if (defined($ARGV[0]) && $ARGV[0] eq "-s");
# Use -i as second argument to make it include "lookup.h"
$includelookup = 1 if (defined($ARGV[0]) && $ARGV[0] eq "-i");
print STDERR "Creating hashtable for $file\n";
open(IN, $file) or die "No such file $file";
@keys = ();
@values = ();
@attrs = ();
@params = ();
my $inside = 0;
my $name;
my $size;
my $hashsize;
my $banner = 0;
sub calcTable();
sub output();
sub hashValue($);
while (<IN>) {
chop;
s/^\s*//g;
if (/^\#|^$/) {
# comment. do nothing
} elsif (/^\@begin\s*(\w+)\s*(\d+)\s*$/ && !$inside) {
$inside = 1;
$name = $1;
$hashsize = $2;
} elsif (/^\@end\s*$/ && $inside) {
if($findSize) {
my $entriesnum=@keys;
print STDERR "Table: $name $entriesnum entries\n";
for( $i=3 ; $i<79 ; ++$i) { $hashsize=$i ; calcTable(); }
} else {
calcTable();
}
output();
@keys = ();
@values = ();
@attrs = ();
@params = ();
$inside = 0;
} elsif (/^([\w\[\=\]]+)\s*([\w\:-]+)\s*([\w\|]*)\s*(\w*)\s*$/ && $inside) {
my $key = $1;
my $val = $2;
my $att = $3;
my $param = $4;
push(@keys, $key);
push(@values, $val);
printf STDERR "WARNING: Number of arguments missing for $key/$val\n"
if ( $att =~ m/Function/ && length($param) == 0);
push(@attrs, length($att) > 0 ? $att : "0");
push(@params, length($param) > 0 ? $param : "0");
} elsif ($inside) {
die "invalid data";
}
}
die "missing closing \@end" if ($inside);
sub calcTable() {
@table = ();
@links = ();
$size = $hashsize;
my $collisions = 0;
my $maxdepth = 0;
my $i = 0;
foreach $key (@keys) {
my $depth = 0;
my $h = hashValue($key) % $hashsize;
while (defined($table[$h])) {
if (defined($links[$h])) {
$h = $links[$h];
$depth++;
} else {
$collisions++;
$links[$h] = $size;
$h = $size;
$size++;
}
}
$table[$h] = $i;
$i++;
$maxdepth = $depth if ( $depth > $maxdepth);
}
if ($findSize) {
my $emptycount = 0;
foreach $entry (@table) {
$emptycount++ if (!defined($entry));
}
print STDERR "Hashsize: $hashsize Total Size: $size Empty: $emptycount MaxDepth: $maxdepth Collisions: $collisions\n";
}
# my $i = 0;
# foreach $entry (@table) {
# print "$i " . $entry;
# print " -> " . $links[$i] if (defined($links[$i]));
# print "\n";
# $i++;
# }
}
sub hashValue($) {
@chars = split(/ */, $_[0]);
my $val = 0;
foreach $c (@chars) {
$val += ord($c);
}
return $val;
}
sub output() {
if (!$banner) {
$banner = 1;
print "/* Automatically generated from $file using $0. DO NOT EDIT ! */\n";
}
print "\n#include \"lookup.h\"\n" if ($includelookup);
print "\nnamespace KJS {\n";
print "\nconst struct HashEntry ${name}Entries[] = {\n";
my $i = 0;
foreach $entry (@table) {
if (defined($entry)) {
my $key = $keys[$entry];
print " \{ \"" . $key . "\"";
print ", " . $values[$entry];
print ", " . $attrs[$entry];
print ", " . $params[$entry];
print ", ";
if (defined($links[$i])) {
print "&${name}Entries[$links[$i]]" . " \}";
} else {
print "0 \}"
}
} else {
print " \{ 0, 0, 0, 0, 0 \}";
}
print "," unless ($i == $size - 1);
print "\n";
$i++;
}
print "};\n";
print "\nconst struct HashTable $name = ";
print "\{ 2, $size, ${name}Entries, $hashsize \};\n\n";
print "} // namespace\n";
}
#include "dc_controller.h"
struct DCController g_controllers[4];
#ifndef _DC_CONTROLLER_H_
#define _DC_CONTROLLER_H_
#include <kos.h>
struct DCController
{
maple_device_t* dev;
cont_state_t state;
cont_state_t old_state;
};
#define DCController_Init(p)\
(p)->dev = NULL;\
memset(&((p)->old_state), 0, sizeof(cont_state_t));\
memset(&((p)->state), 0, sizeof(cont_state_t));
#define DCController_Poll(p)\
(p)->old_state = (p)->state;\
(p)->state = *((cont_state_t*) maple_dev_status ((p)->dev));
#define DCController_IsPressed(p, which) (((p)->state.buttons & (which)) == (which))
#define DCController_JustPressed(p, which) (((p)->state.buttons & (which)) == (which) && ((p)->old_state.buttons & (which)) != (which))
extern struct DCController g_controllers[4];
#endif
#include "dc_mouse.h"
struct DCMouse g_mice[4];
#ifndef _DC_MOUSE_H_
#define _DC_MOUSE_H_
#include <kos.h>
struct DCMouse
{
maple_device_t* dev;
mouse_state_t state;
mouse_state_t old_state;
};
#define DCMouse_Init(p)\
{\
(p)->dev = NULL;\
memset(&(p)->old_state, 0, sizeof(mouse_state_t));\
memset(&(p)->state, 0, sizeof(mouse_state_t));\
}
#define DCMouse_Poll(p)\
{\
(p)->old_state = (p)->state;\
(p)->state = *((mouse_state_t*) maple_dev_status ((p)->dev));\
}
#define DCMouse_IsPressed(p, which) (((p)->state.buttons & which) == (which))
#define DCMouse_JustPressed(p, which) ((((p)->state.buttons & which) == (which)) && !(((p)->old_state.buttons & which) != (which)))
extern struct DCMouse g_mice[4];
#endif
#include <kos.h>
#include <stdio.h>
#include "dc_utils.h"
#include "dc_vmu.h"
#include <math.h>
#include <stdlib.h>
#include "unzip.h"
struct S_SCREEN_ADJUSTMENTS screen_adjustments = {0, 0, DC_SCREEN_WIDTH, DC_SCREEN_HEIGHT, 1.0f, 1.0f};
#include <imageload/jitterdefs.h>
//#include "jitter_table.h"
/* ============================================================ */
/* sq */
#include <dc/sq.h>
/* ============================================================ */
/* controller handling */
struct dc_maple_info_t dc_maple_controller_info[DC_MAPLE_INFO_SIZE];
struct dc_maple_info_t dc_maple_mouse_info[DC_MAPLE_INFO_SIZE];
struct dc_maple_info_t dc_maple_keyboard_info[DC_MAPLE_INFO_SIZE];
uint32 badstuffcount = 0;
void dc_maple_init ()
{
int n;
maple_device_t *dev;
struct dc_maple_info_t *p;
struct _typemap
{
char *name;
dc_maple_controller_type_t type;
} typemap[] = {
{"Arcade Stick", DC_MAPLE_CONTROLLER_ARCADESTICK},
{NULL, DC_MAPLE_CONTROLLER_NORMAL},
};
struct _typemap *tp;
memset(&dc_maple_controller_info, 0, sizeof(dc_maple_controller_info));
memset(&dc_maple_mouse_info, 0, sizeof(dc_maple_controller_info));
memset(&dc_maple_keyboard_info, 0, sizeof(dc_maple_controller_info));
// controller
n = 0;
p = dc_maple_controller_info;
for (;;)
{
dev = maple_enum_type (n, MAPLE_FUNC_CONTROLLER);
p->dev = dev;
p->type.c_type = DC_MAPLE_CONTROLLER_NORMAL;
tp = typemap;
while (tp->name)
{
if (!strncmp(tp->name, dev->info.product_name, strlen(tp->name)))
{
p->type.c_type = tp->type;
break;
}
++tp;
}
++n;
++p;
if (!dev)
break;
}
// mouse
n = 0;
p = dc_maple_mouse_info;
for (;;)
{
dev = maple_enum_type (n, MAPLE_FUNC_MOUSE);
p->dev = dev;
p->type.m_type = DC_MAPLE_MOUSE_3BUTTON;
++n;
++p;
if (!dev)
break;
}
// keyboard
n = 0;
p = dc_maple_keyboard_info;
for (;;)
{
dev = maple_enum_type (n, MAPLE_FUNC_KEYBOARD);
p->dev = dev;
p->type.k_type = DC_MAPLE_KEYBOARD_JP106;
++n;
++p;
if (!dev)
break;
}
}
/* ------------------------------------------------------------ */
/* screen rect */
struct dc_screen_offset_t dc_screen_offset = {0, 16};
void dc_screen_offset_init ()
{
dc_screen_offset.x = 0;
dc_screen_offset.y = 16;
}
maple_device_t* dc_vmu_search_file (const char* filename)
{
int n;
maple_device_t* dev;
n = 0;
for (;;)
{
dev = maple_enum_type (n, MAPLE_FUNC_MEMCARD);
if (!dev)
return NULL;
if (ndc_vmu_get_dirent (NULL, dev, filename) >= 0)
return dev;
++n;
}
}
int load_bmp (uint16** pRaw, const char *filename, uint32* width, uint32* height, uint32 fmt)
{
FILE *fp = NULL;
uint8* bmp = NULL;
uint8 *p;
uint16* raw = NULL;
uint32 i;
uint32 area;
uint32 bmp_size;
fp = fopen(filename, "rb");
if (!fp)
goto error;
fseek(fp, 18, SEEK_SET);
fread(width, sizeof(uint32), 1, fp);
fread(height, sizeof(uint32), 1, fp);
area = (*width) * (*height);
bmp_size = area * 3;
bmp = (uint8*) malloc(bmp_size);
//raw = *pRaw = new uint16[area];
raw = *pRaw = (uint16*) memalign(32, bmp_size);
fseek(fp, 54, SEEK_SET);
if (fread(bmp, bmp_size, 1, fp) != 1)
goto error;
fclose(fp);
p = bmp;
uint16 r, g, b;
for (i = 0; i < area; ++i)
{
b = *p++ * 32 / 256;
g = *p++ * 64 / 256;
r = *p++ * 32 / 256;
*raw++ = (r << 11) | (g << 5) | (b << 0);
}
if (bmp)
free(bmp);
return 0;
error:
if (fp)
fclose(fp);
if (bmp)
free(bmp);
if (raw)
free(raw);
*pRaw = NULL;
return -1;
}
void
dc_pvr_init ()
{
dc_screen_offset_init ();
}
void DrawString(const char* str, plx_fcxt_t* pCxt, point_t point, uint32 color)
{
float old_font_size = pCxt->size;
pCxt->size = pCxt->size * screen_adjustments.yscale;
char tempstr[0x200];
strcpy(tempstr, str);
char* curstr = tempstr;
char* tabstart = NULL;
char* tabend = NULL;
uint32 tablen = 0;
while (TRUE)
{
point_t working_point = point;
working_point.x += tablen;
tabstart = strstr(curstr, "[TAB]");
if (tabstart)
{
tabend = strstr(curstr, "[/TAB]");
if (!tabend)
break;
*tabstart = '\0';
tabstart += 5;
*tabend = '\0';
tabend += 6;
tablen = atoi(tabstart);
}
working_point.x = screen_adjustments.x1 + (working_point.x * screen_adjustments.xscale);
working_point.y = screen_adjustments.y1 + (working_point.y * screen_adjustments.yscale);
pCxt->color = color;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
if (tabstart)
curstr = tabend;
else
break;
}
pCxt->size = old_font_size;
}
void DrawStringWithBorder(const char* str, plx_fcxt_t* pCxt, point_t point, uint32 color, uint32 border_color)
{
float old_font_size = pCxt->size;
pCxt->size = pCxt->size * screen_adjustments.yscale;
char tempstr[0x200];
strcpy(tempstr, str);
char* curstr = tempstr;
char* tabstart = NULL;
char* tabend = NULL;
uint32 tablen = 0;
while (TRUE)
{
point_t working_point = point;
working_point.x += tablen;
tabstart = strstr(curstr, "[TAB]");
if (tabstart)
{
tabend = strstr(curstr, "[/TAB]");
if (!tabend)
break;
*tabstart = '\0';
tabstart += 5;
*tabend = '\0';
tabend += 6;
tablen = atoi(tabstart);
}
working_point.x = screen_adjustments.x1 + (working_point.x * screen_adjustments.xscale);
working_point.y = screen_adjustments.y1 + (working_point.y * screen_adjustments.yscale);
pCxt->color = color;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
--working_point.z;
--working_point.x;
--working_point.y;
pCxt->color = border_color;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
working_point.x += 2;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
working_point.y += 2;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
working_point.x -= 2;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
if (tabstart)
curstr = tabend;
else
break;
}
pCxt->size = old_font_size;
}
char* read_text_file(const char* filename)
{
FILE* fp = fopen(filename, "rb");
if (!fp)
return NULL;
fseek(fp, 0, SEEK_END);
uint32 filelen = ftell(fp);
fseek(fp, 0, SEEK_SET);
char* sztemp = (char*) malloc(filelen + 1);
fread(sztemp, sizeof(char), filelen, fp);
sztemp[filelen] = '\0';
fclose(fp);
return sztemp;
}
uint8 hexstr_to_uint32(const char* str, uint32* retval)
{
uint32 num = 0;
int32 len = strlen(str);
if (len == 0)
return 0;
uint32 digit = 0;
uint32 temppow;
int32 k;
for (k = len - 1; k >= 0; --k)
{
temppow = pow(16, digit);
switch (str[k])
{
case '0':
break;
case '1':
num += temppow;
break;
case '2':
num += temppow * 2;
break;
case '3':
num += temppow * 3;
break;
case '4':
num += temppow * 4;
break;
case '5':
num += temppow * 5;
break;
case '6':
num += temppow * 6;
break;
case '7':
num += temppow * 7;
break;
case '8':
num += temppow * 8;
break;
case '9':
num += temppow * 9;
break;
case 'a':
case 'A':
num += temppow * 10;
break;
case 'b':
case 'B':
num += temppow * 11;
break;
case 'c':
case 'C':
num += temppow * 12;
break;
case 'd':
case 'D':
num += temppow * 13;
break;
case 'e':
case 'E':
num += temppow * 14;
break;
case 'f':
case 'F':
num += temppow * 15;
break;
default:
{
dbgio_printf("hexstr_to_uint32() bad char: %c\n", str[k]);
return 0;
}
};
++digit;
}
*retval = num;
return 1;
}
static pvr_poly_hdr_t dc_pvr_font_poly_hdr;
/*
load 12x24 font. (use as 14x26).
*/
#define DC_PVR_FONT_WIDTH 14
#define DC_PVR_FONT_HEIGHT 26
void dc_pvr_font_init ()
{
pvr_ptr_t txr_font;
pvr_poly_cxt_t poly;
int x, y;
int ch;
uint16 font_image[256 * 256] __attribute__ ((aligned (32)));;
/* setup font texture */
txr_font = pvr_mem_malloc (256 * 256 * 2);
pvr_poly_cxt_txr (&poly, PVR_LIST_TR_POLY,
PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED,
256, 256, txr_font, PVR_FILTER_NONE);
pvr_poly_compile (&dc_pvr_font_poly_hdr, &poly);
/* draw font to texture */
memset(font_image, 0, sizeof(font_image));
ch = 0;
for (y = 0; y < 6; ++y)
{
for (x = 0; x < 16; ++x)
{
uint16 *p;
p = font_image + 256 * y * DC_PVR_FONT_HEIGHT + x * DC_PVR_FONT_WIDTH;
bfont_draw_thin (p, 256, 0, 32 + ch, 0);
bfont_draw_thin (p + 1, 256, 0, 32 + ch, 0);
++ch;
}
}
sq_cpy (txr_font, font_image, sizeof(font_image));
}
void dc_pvr_font_commit_start ()
{
pvr_prim (&dc_pvr_font_poly_hdr, sizeof(pvr_poly_hdr_t));
}
static void dc_pvr_font_commit_char (float x, float y, float z, uint32 argb, char ch)
{
pvr_vertex_t vert;
int cx, cy;
float u1, v1, u2, v2;
cx = ((ch - 32) & 15) * DC_PVR_FONT_WIDTH;
cy = ((ch - 32) >> 4) * DC_PVR_FONT_HEIGHT;
u1 = cx * 1.0 / 256;
v1 = cy * 1.0 / 256;
u2 = (cx + DC_PVR_FONT_WIDTH) * 1.0 / 256;
v2 = (cy + DC_PVR_FONT_HEIGHT) * 1.0 / 256;
vert.flags = PVR_CMD_VERTEX;
vert.x = dc_screen_offset.x + x;
vert.y = dc_screen_offset.y + y + DC_PVR_FONT_HEIGHT;
vert.z = z;
vert.u = u1;
vert.v = v2;
vert.argb = argb;
vert.oargb = 0;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x;
vert.y = dc_screen_offset.y + y;
vert.u = u1;
vert.v = v1;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x + DC_PVR_FONT_WIDTH;
vert.y = dc_screen_offset.y + y + DC_PVR_FONT_HEIGHT;
vert.u = u2;
vert.v = v2;
pvr_prim (&vert, sizeof(vert));
vert.flags = PVR_CMD_VERTEX_EOL;
vert.x = dc_screen_offset.x + x + DC_PVR_FONT_WIDTH;
vert.y = dc_screen_offset.y + y;
vert.u = u2;
vert.v = v1;
pvr_prim (&vert, sizeof(vert));
}
void dc_pvr_font_commit_string (float x, float y, float z, uint32 argb, const char *str)
{
if (!str) return;
while (*str)
{
dc_pvr_font_commit_char (x, y, z, argb, *str);
x += 12;
++str;
}
}
void dc_pvr_font_output_message (const char *title, const char *message, const char *foot, dc_pvr_bgfunc_t bgfunc)
{
int i;
int y;
uint32 f_color = 0xffffffff;
uint32 b_color = 0xffffa500;
uint32 w_color = 0xd0010101;
/* fill PVR cache */
for (i = 0; i < 2; ++i)
{
pvr_wait_ready ();
pvr_scene_begin ();
pvr_list_begin (PVR_LIST_OP_POLY);
if (bgfunc) bgfunc();
pvr_list_finish ();
pvr_list_begin (PVR_LIST_TR_POLY);
dc_pvr_font_commit_start ();
if (title)
{
dc_pvr_font_commit_string (20, 50, 512, f_color, title);
dc_pvr_font_commit_string (21, 51, 510, b_color, title);
}
if (message)
dc_pvr_font_commit_string (50, 150, 512, f_color, message);
if (foot)
{
dc_pvr_font_commit_string (20, 400, 512, f_color, foot);
dc_pvr_font_commit_string (21, 401, 510, b_color, foot);
}
dc_pvr_diagram_commit_start ();
y = 80;
dc_pvr_diagram_commit_line (20, y, 600, y, 500, b_color);
y = 430;
dc_pvr_diagram_commit_line (20, y, 600, y, 500, b_color);
dc_pvr_diagram_commit_box (0, 0, 640, 480, 300, w_color);
pvr_list_finish ();
pvr_scene_finish ();
}
}
/* ------------------------------------------------------------ */
pvr_poly_hdr_t dc_pvr_diagram_poly_hdr;
void dc_pvr_diagram_init()
{
pvr_poly_cxt_t poly;
pvr_poly_cxt_col (&poly, PVR_LIST_TR_POLY);
pvr_poly_compile(&dc_pvr_diagram_poly_hdr, &poly);
}
void dc_pvr_diagram_commit_start ()
{
pvr_prim(&dc_pvr_diagram_poly_hdr, sizeof(pvr_poly_hdr_t));
}
void dc_pvr_diagram_commit_line(float x1, float y1, float x2, float y2, float z, uint32 argb)
{
pvr_vertex_t vert;
vert.flags = PVR_CMD_VERTEX;
vert.x = dc_screen_offset.x + x1;
vert.y = dc_screen_offset.y + y1 + 2;
vert.z = z;
vert.u = vert.v = 0.0f;
vert.argb = argb;
vert.oargb = 0;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x1;
vert.y = dc_screen_offset.y + y1;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x2;
vert.y = dc_screen_offset.y + y2 + 2;
pvr_prim (&vert, sizeof(vert));
vert.flags = PVR_CMD_VERTEX_EOL;
vert.x = dc_screen_offset.x + x2;
vert.y = dc_screen_offset.y + y2;
pvr_prim(&vert, sizeof(vert));
}
void dc_pvr_diagram_commit_box (float x1, float y1, float x2, float y2, float z, uint32 argb)
{
pvr_vertex_t vert;
vert.flags = PVR_CMD_VERTEX;
vert.x = dc_screen_offset.x + x1;
vert.y = dc_screen_offset.y + y2;
vert.z = z;
vert.u = vert.v = 0.0f;
vert.argb = argb;
vert.oargb = 0;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x1;
vert.y = dc_screen_offset.y + y1;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x2;
vert.y = dc_screen_offset.y + y2;
pvr_prim (&vert, sizeof(vert));
vert.flags = PVR_CMD_VERTEX_EOL;
vert.x = dc_screen_offset.x + x2;
vert.y = dc_screen_offset.y + y1;
pvr_prim(&vert, sizeof(vert));
}
void dc_wait_sq_cpy_done()
{
/* wait for both store queues to complete */
*((uint32 *)(0xe0000000)) = 0;
*((uint32 *)(0xe0000020)) = 0;
}
char get_largest_rom_name_in_zip_fp(unzFile file, char* rcvbuf)
{
char name[132];
int port;
unz_file_info info;
int filesize = 0;
int len;
port = unzGoToFirstFile(file);
while (port == UNZ_OK)
{
unzGetCurrentFileInfo(file, &info, name, 128, NULL, 0, NULL, 0);
len = strlen(name);
if (info.uncompressed_size > filesize && ((name[len - 4] == '.') && ((name[len - 3] == 'n') || (name[len - 3] == 'N')) && ((name[len - 2] == 'e') || (name[len - 2] == 'E')) && ((name[len - 1] == 's') || (name[len - 1] == 'S'))))
{
strcpy(rcvbuf, name);
filesize = info.uncompressed_size;
}
port = unzGoToNextFile(file);
}
if (filesize == 0)
return 0;
return 1;
}
#include <kos.h>
#include <stdio.h>
#include "dc_utils.h"
#include "dc_vmu.h"
#include <math.h>
#include <stdlib.h>
#include "unzip.h"
struct S_SCREEN_ADJUSTMENTS screen_adjustments = {0, 0, DC_SCREEN_WIDTH, DC_SCREEN_HEIGHT, 1.0f, 1.0f};
#include <imageload/jitterdefs.h>
//#include "jitter_table.h"
/* ============================================================ */
/* sq */
#include <dc/sq.h>
/* ============================================================ */
/* controller handling */
struct dc_maple_info_t dc_maple_controller_info[DC_MAPLE_INFO_SIZE];
struct dc_maple_info_t dc_maple_mouse_info[DC_MAPLE_INFO_SIZE];
struct dc_maple_info_t dc_maple_keyboard_info[DC_MAPLE_INFO_SIZE];
uint32 badstuffcount = 0;
void dc_maple_init ()
{
int n;
maple_device_t *dev;
struct dc_maple_info_t *p;
struct _typemap
{
char *name;
dc_maple_controller_type_t type;
} typemap[] = {
{"Arcade Stick", DC_MAPLE_CONTROLLER_ARCADESTICK},
{NULL, DC_MAPLE_CONTROLLER_NORMAL},
};
struct _typemap *tp;
memset(&dc_maple_controller_info, 0, sizeof(dc_maple_controller_info));
memset(&dc_maple_mouse_info, 0, sizeof(dc_maple_controller_info));
memset(&dc_maple_keyboard_info, 0, sizeof(dc_maple_controller_info));
// controller
n = 0;
p = dc_maple_controller_info;
for (;;)
{
dev = maple_enum_type (n, MAPLE_FUNC_CONTROLLER);
p->dev = dev;
p->type.c_type = DC_MAPLE_CONTROLLER_NORMAL;
tp = typemap;
while (tp->name)
{
if (!strncmp(tp->name, dev->info.product_name, strlen(tp->name)))
{
p->type.c_type = tp->type;
break;
}
++tp;
}
++n;
++p;
if (!dev)
break;
}
// mouse
n = 0;
p = dc_maple_mouse_info;
for (;;)
{
dev = maple_enum_type (n, MAPLE_FUNC_MOUSE);
p->dev = dev;
p->type.m_type = DC_MAPLE_MOUSE_3BUTTON;
++n;
++p;
if (!dev)
break;
}
// keyboard
n = 0;
p = dc_maple_keyboard_info;
for (;;)
{
dev = maple_enum_type (n, MAPLE_FUNC_KEYBOARD);
p->dev = dev;
p->type.k_type = DC_MAPLE_KEYBOARD_JP106;
++n;
++p;
if (!dev)
break;
}
}
/* ------------------------------------------------------------ */
/* screen rect */
struct dc_screen_offset_t dc_screen_offset = {0, 16};
void dc_screen_offset_init ()
{
dc_screen_offset.x = 0;
dc_screen_offset.y = 16;
}
maple_device_t* dc_vmu_search_file (const char* filename)
{
int n;
maple_device_t* dev;
n = 0;
for (;;)
{
dev = maple_enum_type (n, MAPLE_FUNC_MEMCARD);
if (!dev)
return NULL;
if (ndc_vmu_get_dirent (NULL, dev, filename) >= 0)
return dev;
++n;
}
}
int load_bmp (uint16** pRaw, const char *filename, uint32* width, uint32* height, uint32 fmt)
{
FILE *fp = NULL;
uint8* bmp = NULL;
uint8 *p;
uint16* raw = NULL;
uint32 i;
uint32 area;
uint32 bmp_size;
fp = fopen(filename, "rb");
if (!fp)
goto error;
fseek(fp, 18, SEEK_SET);
fread(width, sizeof(uint32), 1, fp);
fread(height, sizeof(uint32), 1, fp);
area = (*width) * (*height);
bmp_size = area * 3;
bmp = (uint8*) malloc(bmp_size);
//raw = *pRaw = new uint16[area];
raw = *pRaw = (uint16*) memalign(32, bmp_size);
fseek(fp, 54, SEEK_SET);
if (fread(bmp, bmp_size, 1, fp) != 1)
goto error;
fclose(fp);
p = bmp;
uint16 r, g, b;
for (i = 0; i < area; ++i)
{
b = *p++ * 32 / 256;
g = *p++ * 64 / 256;
r = *p++ * 32 / 256;
*raw++ = (r << 11) | (g << 5) | (b << 0);
}
if (bmp)
free(bmp);
return 0;
error:
if (fp)
fclose(fp);
if (bmp)
free(bmp);
if (raw)
free(raw);
*pRaw = NULL;
return -1;
}
void
dc_pvr_init ()
{
dc_screen_offset_init ();
}
void DrawString(const char* str, plx_fcxt_t* pCxt, point_t point, uint32 color)
{
float old_font_size = pCxt->size;
pCxt->size = pCxt->size * screen_adjustments.yscale;
char tempstr[0x200];
strcpy(tempstr, str);
char* curstr = tempstr;
char* tabstart = NULL;
char* tabend = NULL;
uint32 tablen = 0;
while (TRUE)
{
point_t working_point = point;
working_point.x += tablen;
tabstart = strstr(curstr, "[TAB]");
if (tabstart)
{
tabend = strstr(curstr, "[/TAB]");
if (!tabend)
break;
*tabstart = '\0';
tabstart += 5;
*tabend = '\0';
tabend += 6;
tablen = atoi(tabstart);
}
working_point.x = screen_adjustments.x1 + (working_point.x * screen_adjustments.xscale);
working_point.y = screen_adjustments.y1 + (working_point.y * screen_adjustments.yscale);
pCxt->color = color;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
if (tabstart)
curstr = tabend;
else
break;
}
pCxt->size = old_font_size;
}
void DrawStringWithBorder(const char* str, plx_fcxt_t* pCxt, point_t point, uint32 color, uint32 border_color)
{
float old_font_size = pCxt->size;
pCxt->size = pCxt->size * screen_adjustments.yscale;
char tempstr[0x200];
strcpy(tempstr, str);
char* curstr = tempstr;
char* tabstart = NULL;
char* tabend = NULL;
uint32 tablen = 0;
while (TRUE)
{
point_t working_point = point;
working_point.x += tablen;
tabstart = strstr(curstr, "[TAB]");
if (tabstart)
{
tabend = strstr(curstr, "[/TAB]");
if (!tabend)
break;
*tabstart = '\0';
tabstart += 5;
*tabend = '\0';
tabend += 6;
tablen = atoi(tabstart);
}
working_point.x = screen_adjustments.x1 + (working_point.x * screen_adjustments.xscale);
working_point.y = screen_adjustments.y1 + (working_point.y * screen_adjustments.yscale);
pCxt->color = color;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
--working_point.z;
--working_point.x;
--working_point.y;
pCxt->color = border_color;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
working_point.x += 2;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
working_point.y += 2;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
working_point.x -= 2;
plx_fcxt_begin(pCxt);
plx_fcxt_setpos_pnt(pCxt, &working_point);
plx_fcxt_draw(pCxt, curstr);
plx_fcxt_end(pCxt);
if (tabstart)
curstr = tabend;
else
break;
}
pCxt->size = old_font_size;
}
char* read_text_file(const char* filename)
{
FILE* fp = fopen(filename, "rb");
if (!fp)
return NULL;
fseek(fp, 0, SEEK_END);
uint32 filelen = ftell(fp);
fseek(fp, 0, SEEK_SET);
char* sztemp = (char*) malloc(filelen + 1);
fread(sztemp, sizeof(char), filelen, fp);
sztemp[filelen] = '\0';
fclose(fp);
return sztemp;
}
uint8 hexstr_to_uint32(const char* str, uint32* retval)
{
uint32 num = 0;
int32 len = strlen(str);
if (len == 0)
return 0;
uint32 digit = 0;
uint32 temppow;
int32 k;
for (k = len - 1; k >= 0; --k)
{
temppow = pow(16, digit);
switch (str[k])
{
case '0':
break;
case '1':
num += temppow;
break;
case '2':
num += temppow * 2;
break;
case '3':
num += temppow * 3;
break;
case '4':
num += temppow * 4;
break;
case '5':
num += temppow * 5;
break;
case '6':
num += temppow * 6;
break;
case '7':
num += temppow * 7;
break;
case '8':
num += temppow * 8;
break;
case '9':
num += temppow * 9;
break;
case 'a':
case 'A':
num += temppow * 10;
break;
case 'b':
case 'B':
num += temppow * 11;
break;
case 'c':
case 'C':
num += temppow * 12;
break;
case 'd':
case 'D':
num += temppow * 13;
break;
case 'e':
case 'E':
num += temppow * 14;
break;
case 'f':
case 'F':
num += temppow * 15;
break;
default:
{
printf("hexstr_to_uint32() bad char: %c\n", str[k]);
return 0;
}
};
++digit;
}
*retval = num;
return 1;
}
static pvr_poly_hdr_t dc_pvr_font_poly_hdr;
/*
load 12x24 font. (use as 14x26).
*/
#define DC_PVR_FONT_WIDTH 14
#define DC_PVR_FONT_HEIGHT 26
void dc_pvr_font_init ()
{
pvr_ptr_t txr_font;
pvr_poly_cxt_t poly;
int x, y;
int ch;
uint16 font_image[256 * 256] __attribute__ ((aligned (32)));;
/* setup font texture */
txr_font = pvr_mem_malloc (256 * 256 * 2);
pvr_poly_cxt_txr (&poly, PVR_LIST_TR_POLY,
PVR_TXRFMT_ARGB4444 | PVR_TXRFMT_NONTWIDDLED,
256, 256, txr_font, PVR_FILTER_NONE);
pvr_poly_compile (&dc_pvr_font_poly_hdr, &poly);
/* draw font to texture */
memset(font_image, 0, sizeof(font_image));
ch = 0;
for (y = 0; y < 6; ++y)
{
for (x = 0; x < 16; ++x)
{
uint16 *p;
p = font_image + 256 * y * DC_PVR_FONT_HEIGHT + x * DC_PVR_FONT_WIDTH;
bfont_draw_thin (p, 256, 0, 32 + ch, 0);
bfont_draw_thin (p + 1, 256, 0, 32 + ch, 0);
++ch;
}
}
sq_cpy (txr_font, font_image, sizeof(font_image));
}
void dc_pvr_font_commit_start ()
{
pvr_prim (&dc_pvr_font_poly_hdr, sizeof(pvr_poly_hdr_t));
}
static void dc_pvr_font_commit_char (float x, float y, float z, uint32 argb, char ch)
{
pvr_vertex_t vert;
int cx, cy;
float u1, v1, u2, v2;
cx = ((ch - 32) & 15) * DC_PVR_FONT_WIDTH;
cy = ((ch - 32) >> 4) * DC_PVR_FONT_HEIGHT;
u1 = cx * 1.0 / 256;
v1 = cy * 1.0 / 256;
u2 = (cx + DC_PVR_FONT_WIDTH) * 1.0 / 256;
v2 = (cy + DC_PVR_FONT_HEIGHT) * 1.0 / 256;
vert.flags = PVR_CMD_VERTEX;
vert.x = dc_screen_offset.x + x;
vert.y = dc_screen_offset.y + y + DC_PVR_FONT_HEIGHT;
vert.z = z;
vert.u = u1;
vert.v = v2;
vert.argb = argb;
vert.oargb = 0;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x;
vert.y = dc_screen_offset.y + y;
vert.u = u1;
vert.v = v1;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x + DC_PVR_FONT_WIDTH;
vert.y = dc_screen_offset.y + y + DC_PVR_FONT_HEIGHT;
vert.u = u2;
vert.v = v2;
pvr_prim (&vert, sizeof(vert));
vert.flags = PVR_CMD_VERTEX_EOL;
vert.x = dc_screen_offset.x + x + DC_PVR_FONT_WIDTH;
vert.y = dc_screen_offset.y + y;
vert.u = u2;
vert.v = v1;
pvr_prim (&vert, sizeof(vert));
}
void dc_pvr_font_commit_string (float x, float y, float z, uint32 argb, const char *str)
{
if (!str) return;
while (*str)
{
dc_pvr_font_commit_char (x, y, z, argb, *str);
x += 12;
++str;
}
}
void dc_pvr_font_output_message (const char *title, const char *message, const char *foot, dc_pvr_bgfunc_t bgfunc)
{
int i;
int y;
uint32 f_color = 0xffffffff;
uint32 b_color = 0xffffa500;
uint32 w_color = 0xd0010101;
/* fill PVR cache */
for (i = 0; i < 2; ++i)
{
pvr_wait_ready ();
pvr_scene_begin ();
pvr_list_begin (PVR_LIST_OP_POLY);
if (bgfunc) bgfunc();
pvr_list_finish ();
pvr_list_begin (PVR_LIST_TR_POLY);
dc_pvr_font_commit_start ();
if (title)
{
dc_pvr_font_commit_string (20, 50, 512, f_color, title);
dc_pvr_font_commit_string (21, 51, 510, b_color, title);
}
if (message)
dc_pvr_font_commit_string (50, 150, 512, f_color, message);
if (foot)
{
dc_pvr_font_commit_string (20, 400, 512, f_color, foot);
dc_pvr_font_commit_string (21, 401, 510, b_color, foot);
}
dc_pvr_diagram_commit_start ();
y = 80;
dc_pvr_diagram_commit_line (20, y, 600, y, 500, b_color);
y = 430;
dc_pvr_diagram_commit_line (20, y, 600, y, 500, b_color);
dc_pvr_diagram_commit_box (0, 0, 640, 480, 300, w_color);
pvr_list_finish ();
pvr_scene_finish ();
}
}
/* ------------------------------------------------------------ */
pvr_poly_hdr_t dc_pvr_diagram_poly_hdr;
void dc_pvr_diagram_init()
{
pvr_poly_cxt_t poly;
pvr_poly_cxt_col (&poly, PVR_LIST_TR_POLY);
pvr_poly_compile(&dc_pvr_diagram_poly_hdr, &poly);
}
void dc_pvr_diagram_commit_start ()
{
pvr_prim(&dc_pvr_diagram_poly_hdr, sizeof(pvr_poly_hdr_t));
}
void dc_pvr_diagram_commit_line(float x1, float y1, float x2, float y2, float z, uint32 argb)
{
pvr_vertex_t vert;
vert.flags = PVR_CMD_VERTEX;
vert.x = dc_screen_offset.x + x1;
vert.y = dc_screen_offset.y + y1 + 2;
vert.z = z;
vert.u = vert.v = 0.0f;
vert.argb = argb;
vert.oargb = 0;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x1;
vert.y = dc_screen_offset.y + y1;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x2;
vert.y = dc_screen_offset.y + y2 + 2;
pvr_prim (&vert, sizeof(vert));
vert.flags = PVR_CMD_VERTEX_EOL;
vert.x = dc_screen_offset.x + x2;
vert.y = dc_screen_offset.y + y2;
pvr_prim(&vert, sizeof(vert));
}
void dc_pvr_diagram_commit_box (float x1, float y1, float x2, float y2, float z, uint32 argb)
{
pvr_vertex_t vert;
vert.flags = PVR_CMD_VERTEX;
vert.x = dc_screen_offset.x + x1;
vert.y = dc_screen_offset.y + y2;
vert.z = z;
vert.u = vert.v = 0.0f;
vert.argb = argb;
vert.oargb = 0;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x1;
vert.y = dc_screen_offset.y + y1;
pvr_prim (&vert, sizeof(vert));
vert.x = dc_screen_offset.x + x2;
vert.y = dc_screen_offset.y + y2;
pvr_prim (&vert, sizeof(vert));
vert.flags = PVR_CMD_VERTEX_EOL;
vert.x = dc_screen_offset.x + x2;
vert.y = dc_screen_offset.y + y1;
pvr_prim(&vert, sizeof(vert));
}
void dc_wait_sq_cpy_done()
{
/* wait for both store queues to complete */
*((uint32 *)(0xe0000000)) = 0;
*((uint32 *)(0xe0000020)) = 0;
}
char get_largest_rom_name_in_zip_fp(unzFile file, char* rcvbuf)
{
char name[132];
int port;
unz_file_info info;
int filesize = 0;
int len;
port = unzGoToFirstFile(file);
while (port == UNZ_OK)
{
unzGetCurrentFileInfo(file, &info, name, 128, NULL, 0, NULL, 0);
len = strlen(name);
if (info.uncompressed_size > filesize && ((name[len - 4] == '.') && ((name[len - 3] == 'n') || (name[len - 3] == 'N')) && ((name[len - 2] == 'e') || (name[len - 2] == 'E')) && ((name[len - 1] == 's') || (name[len - 1] == 'S'))))
{
strcpy(rcvbuf, name);
filesize = info.uncompressed_size;
}
port = unzGoToNextFile(file);
}
if (filesize == 0)
return 0;
return 1;
}
#ifndef _DC_UTILS_H_
#define _DC_UTILS_H_
#define DC_SCREEN_WIDTH 640
#define DC_SCREEN_HEIGHT 480
#if defined(__cplusplus) || defined(c_plusplus)
#define EXTERN_C extern "C"
#define START_EXTERN_C extern "C" {
#define END_EXTERN_C }
#else
#define EXTERN_C extern
#define START_EXTERN_C
#define END_EXTERN_C
#endif
START_EXTERN_C
#define MIN_Y 16
#include <kos.h>
#include <plx/font.h>
#include "unzip.h"
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
extern const char *progname;
/* ------------------------------------------------------------ */
/* controller handling */
/* low level interface */
typedef enum {
DC_MAPLE_CONTROLLER_NORMAL,
DC_MAPLE_CONTROLLER_ARCADESTICK,
} dc_maple_controller_type_t;
typedef enum {
DC_MAPLE_MOUSE_3BUTTON,
} dc_maple_mouse_type_t;
typedef enum {
DC_MAPLE_KEYBOARD_JP106,
} dc_maple_keyboard_type_t;
struct dc_maple_info_t
{
maple_device_t *dev;
union {
dc_maple_controller_type_t c_type;
dc_maple_mouse_type_t m_type;
dc_maple_keyboard_type_t k_type;
} type;
};
#define DC_MAPLE_INFO_SIZE 16
extern struct dc_maple_info_t dc_maple_controller_info[DC_MAPLE_INFO_SIZE];
extern struct dc_maple_info_t dc_maple_mouse_info[DC_MAPLE_INFO_SIZE];
extern struct dc_maple_info_t dc_maple_keyboard_info[DC_MAPLE_INFO_SIZE];
void dc_maple_init ();
struct dc_screen_offset_t
{
float x, y;
};
extern struct dc_screen_offset_t dc_screen_offset;
extern pvr_vertex_t main_vert;
void dc_screen_offset_init();
void dc_pvr_init ();
maple_device_t* dc_vmu_search_file (const char* filename);
int load_bmp(uint16** raw, const char *filename, uint32* width, uint32* height, uint32 fmt/* = PVR_TXRFMT_RGB565*/);
void DrawString(const char* str, plx_fcxt_t* pCxt, point_t point, uint32 color);
void DrawStringWithBorder(const char* str, plx_fcxt_t* pCxt, point_t point, uint32 color, uint32 border_color);
uint8 BrowseForFile(const char* szStartingDir, char* szResult, plx_fcxt_t* font, int16 x, int16 y, int16 w, int16 h, int16 depth, cont_state_t* prevstate/* = NULL*/);
uint8 scherzo_bmp_load_texture(const char* filename, pvr_ptr_t* tex, uint32 *w, uint32 *h, uint32 *tex_width, uint32 *tex_height);
char* read_text_file(const char* filename);
uint8 hexstr_to_uint32(const char* str, uint32* retval);
typedef void (*dc_pvr_bgfunc_t)();
/* font */
void dc_pvr_font_commit_start();
void dc_pvr_font_commit_string(float x, float y, float z, uint32 argb, const char* str);
void dc_pvr_font_output_message(const char* title, const char* message, const char* foot, dc_pvr_bgfunc_t bgfunc);
/* diagram */
void dc_pvr_diagram_commit_start ();
void dc_pvr_diagram_commit_line(float x1, float y1, float x2, float y2, float z, uint32 argb);
void dc_pvr_diagram_commit_box (float x1, float y1, float x2, float y2, float z, uint32 argb);
void dc_wait_sq_cpy_done();
struct S_SCREEN_ADJUSTMENTS
{
int32 x1, y1, x2, y2;
float xscale, yscale;
};
extern struct S_SCREEN_ADJUSTMENTS screen_adjustments;
char get_largest_rom_name_in_zip_fp(unzFile file, char* rcvbuf);
extern uint32 badstuffcount;
#define REPORT_BAD_STUFF dbgio_printf("BAD STUFF in " __FILE__ " on line %d count = %d\n", __LINE__, badstuffcount++);
END_EXTERN_C
#endif
/*
2001 Takayama Fumihiko <tekezo@catv296.ne.jp>
*/
#include "stdlib.h"
#include "dc_utils.h"
#include "dc_vmu.h"
/* ============================================================ */
static void
create_filename(char *dst, const char *src)
{
int i;
int src_len = strlen (src);
for (i = 0; i < 12; ++i)
{
if (i < src_len)
dst[i] = src[i];
else
dst[i] = ' ';
}
}
static void
create_desc_short(char *dst, const char *src)
{
int i;
int src_len = strlen (src);
for (i = 0; i < 16; ++i)
{
if (i < src_len)
dst[i] = src[i];
else
dst[i] = ' ';
}
}
static void
create_desc_long(char *dst, const char *src)
{
int i;
int src_len = strlen (src);
for (i = 0; i < 32; ++i)
{
if (i < src_len)
dst[i] = src[i];
else
dst[i] = ' ';
}
}
/* ============================================================ */
static int
get_root_block_info (root_block_info *rbi, maple_device_t *dev)
{
uint16 buf16[512 / 2];
int rv;
rv = vmu_block_read (dev, 255, (uint8 *)buf16);
if (rv != MAPLE_EOK) return rv;
rbi->fatblock = buf16[0x46 / 2];
rbi->dirblock = buf16[0x4a / 2];
rbi->dirlength = buf16[0x4c / 2];
return MAPLE_EOK;
}
static int
get_free_dirent_info (file_dirent_info *fdi, maple_device_t *dev)
{
root_block_info rbi;
int16 dirblock;
int n;
int rv;
rv = get_root_block_info(&rbi, dev);
if (rv != MAPLE_EOK) return rv;
dirblock = rbi.dirblock;
for (n = rbi.dirlength; n > 0; --n)
{
dirent_vmu ent[16];
int i;
rv = vmu_block_read(dev, dirblock, (uint8 *)ent);
if (rv != MAPLE_EOK) return rv;
for (i = 0; i < 16; ++i)
{
if (ent[i].filetype == 0x00)
{
fdi->dirblock = dirblock;
fdi->direntry = i;
return MAPLE_EOK;
}
}
--dirblock;
}
return MAPLE_EFAIL;
}
static int
get_file_dirent_info (file_dirent_info *fdi, maple_device_t *dev, const char *filename)
{
char fname[12];
root_block_info rbi;
int16 dirblock;
int n;
int rv;
create_filename(fname, filename);
rv = get_root_block_info(&rbi, dev);
if (rv != MAPLE_EOK) return rv;
dirblock = rbi.dirblock;
for (n = rbi.dirlength; n > 0; --n)
{
dirent_vmu ent[16];
int i;
rv = vmu_block_read(dev, dirblock, (uint8 *)ent);
if (rv != MAPLE_EOK) return rv;
for (i = 0; i < 16; ++i)
{
if (ent[i].filetype == 0x33 &&
!strncmp(ent[i].filename, fname, 12))
{
file_hdr_vmu fhv;
rv = vmu_block_read (dev, ent[i].firstblk, (uint8 *)(&fhv));
if (rv != MAPLE_EOK) return rv;
if (!strcmp (fhv.app_id, progname))
{
fdi->dirblock = dirblock;
fdi->direntry = i;
return MAPLE_EOK;
}
}
}
--dirblock;
}
return MAPLE_EFAIL;
}
/* This rouine came from Marcus's website */
/* http://mc.pp.se/dc/vms/fileheader.html */
static uint16
calc_crc(const unsigned char *buf, int size)
{
int i, c, n = 0;
for (i = 0; i < size; i++)
{
n ^= (buf[i] << 8);
for (c = 0; c < 8; c++)
if (n & 0x8000)
n = (n << 1) ^ 4129;
else
n = (n << 1);
}
return (n & 0xffff);
}
static int
allocate_blocks_on_fat (maple_device_t *dev, uint8 blocks)
{
int i;
uint8 free_mem[200];
int free_blocks;
root_block_info rbi;
uint16 fat_buf16[512 / 2];
uint16 this_block = 0;
uint8 max_block = blocks;
int firstblk;
int rv;
if (!blocks) return -1;
free_blocks = ndc_vmu_check_free_blocks (free_mem, dev);
if (free_blocks < 0 || free_blocks < blocks)
return -1;
rv = get_root_block_info(&rbi, dev);
if (rv != MAPLE_EOK) return -1;
rv = vmu_block_read(dev, rbi.fatblock, (uint8 *)fat_buf16);
if (rv != MAPLE_EOK) return -1;
firstblk = -1;
for (i = 0; i < 200; ++i)
{
if (free_mem[199-i] == 1)
{
if (blocks == max_block)
{
/* first file block */
this_block = firstblk = 199 - i;
}
else
{
/* need the next one */
fat_buf16[this_block] = 199 - i;
this_block = 199 - i;
}
--blocks;
/* last file block */
if (blocks == 0)
{
fat_buf16[this_block] = 0xfffa;
break;
}
}
}
rv = vmu_block_write (dev, rbi.fatblock, (uint8 *)fat_buf16);
if (rv != MAPLE_EOK) return -1;
return firstblk;
}
/* ============================================================ */
int
ndc_vmu_read_blocks (maple_device_t *dev, uint16 firstblk, uint8 *buffer, uint8 blocks)
{
int i, nread;
root_block_info rbi;
uint16 fat_buf16[512 / 2];
int rv;
if (!dev) return -1;
if (!blocks) return -1;
rv = get_root_block_info(&rbi, dev);
if (rv != MAPLE_EOK) return -1;
rv = vmu_block_read (dev, rbi.fatblock, (uint8 *)fat_buf16);
if (rv != MAPLE_EOK) return -1;
nread = 0;
for (i = 0; i < blocks; ++i)
{
vmu_block_read (dev, firstblk, buffer);
buffer += 512;
++nread;
firstblk = fat_buf16[firstblk];
if (firstblk == 0xfffa)
break;
if (firstblk == 0xfffc)
return -1;
}
return nread;
}
int
ndc_vmu_write_blocks (maple_device_t *dev, uint16 firstblk, uint8 *buffer, uint8 blocks)
{
int i, nwrite;
root_block_info rbi;
uint16 fat_buf16[512 / 2];
int rv;
if (!dev) return -1;
if (!blocks) return -1;
rv = get_root_block_info(&rbi, dev);
if (rv != MAPLE_EOK) return -1;
rv = vmu_block_read (dev, rbi.fatblock, (uint8 *)fat_buf16);
if (rv != MAPLE_EOK) return -1;
nwrite = 0;
for (i = 0; i < blocks; ++i)
{
vmu_block_write (dev, firstblk, buffer);
buffer += 512;
++nwrite;
firstblk = fat_buf16[firstblk];
if (firstblk == 0xfffa)
break;
if (firstblk == 0xfffc)
return -1;
}
return nwrite;
}
int
ndc_vmu_get_dirent (dirent_vmu *vmu, maple_device_t *dev, const char* filename)
{
file_dirent_info fdi;
dirent_vmu ent[16];
int rv;
if (!dev) return -1;
rv = get_file_dirent_info (&fdi, dev, filename);
if (rv != MAPLE_EOK) return -1;
rv = vmu_block_read (dev, fdi.dirblock, (uint8 *)ent);
if (rv != MAPLE_EOK) return -1;
if (vmu)
memcpy(vmu, ent + fdi.direntry, sizeof(dirent_vmu));
return ent[fdi.direntry].firstblk;
}
int
ndc_vmu_getall_dirent (dirent_vmu *entries, int *num_entries, maple_device_t *dev)
{
root_block_info rbi;
int16 dirblock;
int n;
int nwrite;
int rv;
if (!dev) return -1;
rv = get_root_block_info(&rbi, dev);
if (rv != MAPLE_EOK) return -1;
dirblock = rbi.dirblock;
nwrite = 0;
for (n = rbi.dirlength; n > 0; --n)
{
dirent_vmu ent[16];
rv = vmu_block_read(dev, dirblock, (uint8 *)ent);
if (rv != MAPLE_EOK) return -1;
if (nwrite < *num_entries)
{
int blocks;
if (*num_entries - nwrite > 16)
blocks = 16;
else
blocks = *num_entries - nwrite;
memcpy (entries, ent, sizeof(dirent_vmu) * blocks);
entries += blocks;
nwrite += blocks;
}
--dirblock;
}
*num_entries = nwrite;
return 0;
}
int
ndc_vmu_check_free_blocks (uint8 *free_mem, maple_device_t *dev)
{
root_block_info rbi;
uint16 fat_buf16[512 / 2];
int free_blocks;
int i;
int rv;
if (!dev) return -1;
rv = get_root_block_info(&rbi, dev);
if (rv != MAPLE_EOK) return -1;
rv = vmu_block_read (dev, rbi.fatblock, (uint8 *)fat_buf16);
if (rv != MAPLE_EOK) return -1;
if (free_mem)
memset(free_mem, 0, 200);
free_blocks = 0;
for (i = 0; i < 200; ++i)
{
if (fat_buf16[i] == 0xfffc)
{
free_blocks++;
if (free_mem)
free_mem[i] = 1;
}
}
return free_blocks;
}
void
ndc_vmu_do_crc (uint8 *buffer, uint16 bytes)
{
uint16 crc = calc_crc (buffer, bytes);
file_hdr_vmu *hdr = (file_hdr_vmu *)buffer;
hdr->crc = crc;
}
void
ndc_vmu_create_vmu_header(uint8 *header, const char *desc_short,
const char *desc_long, uint16 filesize,
const uint8 *icon)
{
file_hdr_vmu *hdr = (file_hdr_vmu *)header;
memset(header, 0, 640);
create_desc_short (hdr->desc_short, desc_short);
create_desc_long (hdr->desc_long, desc_long);
strcpy (hdr->app_id, progname);
hdr->icon_cnt = 1;
hdr->file_bytes = filesize;
if (icon)
memcpy(hdr->palette, icon, 32 + 512);
else
{
memset(hdr->palette, 0, 32 + 512);
}
}
int
ndc_vmu_allocate_file (maple_device_t *dev, const char *filename, uint8 blocks)
{
int firstblk;
int free_blocks;
if (!dev) return -1;
if (!blocks) return -1;
free_blocks = ndc_vmu_check_free_blocks (NULL, dev);
if (free_blocks < 0 || free_blocks < blocks)
return -1;
firstblk = allocate_blocks_on_fat (dev, blocks);
if (firstblk < 0)
return -1;
{
/* update directory entry */
dirent_vmu dir_entry;
file_dirent_info fdi;
dirent_vmu ent[16];
memset(&dir_entry, 0, sizeof(dir_entry));
dir_entry.filetype = 0x33;
dir_entry.copyprotect = 0x00;
dir_entry.firstblk = firstblk;
create_filename (dir_entry.filename, filename);
dir_entry.filesize = blocks;
dir_entry.hdroff = 0;
if (get_free_dirent_info (&fdi, dev) != MAPLE_EOK) return -1;
if (vmu_block_read (dev, fdi.dirblock, (uint8 *)ent) != MAPLE_EOK) return -1;
memcpy (ent + fdi.direntry, &dir_entry, sizeof(dirent_vmu));
if (vmu_block_write (dev, fdi.dirblock, (uint8 *)ent) != MAPLE_EOK) return -1;
}
return firstblk;
}
int
ndc_vmu_remove_file(maple_device_t *dev, const char *filename)
{
int16 firstblk = -1;
if (!dev) return -1;
if (!filename) return -1;
{
/* remove directory entry */
file_dirent_info fdi;
dirent_vmu ent[16];
if (get_file_dirent_info (&fdi, dev, filename) != MAPLE_EOK) return -1;
if (vmu_block_read (dev, fdi.dirblock, (uint8 *)ent) != MAPLE_EOK) return -1;
firstblk = ent[fdi.direntry].firstblk;
memset(ent + fdi.direntry, 0, sizeof(dirent_vmu));
if (vmu_block_write (dev, fdi.dirblock, (uint8 *)ent) != MAPLE_EOK) return -1;
}
{
/* remove fat entry */
root_block_info rbi;
uint16 fat_buf16[512 / 2];
int16 block = firstblk;
if (get_root_block_info(&rbi, dev) != MAPLE_EOK) return -1;
if (vmu_block_read (dev, rbi.fatblock, (uint8 *)fat_buf16) != MAPLE_EOK) return -1;
while (fat_buf16[block] != 0xfffa)
{
uint16 bak = fat_buf16[block];
fat_buf16[block] = 0xfffc;
block = bak;
}
fat_buf16[block] = 0xfffc;
if (vmu_block_write (dev, rbi.fatblock, (uint8 *)fat_buf16) != MAPLE_EOK) return -1;
}
return 0;
}
int
ndc_vmu_save(uint8 *src, uint32 src_len, maple_device_t *dev,
const char *filename,
const char *desc_short,
const char *desc_long,
const uint8 *icon)
{
int save_len;
int save_blocks;
uint8 buf[512 * 200]; /* 200 blocks */
dirent_vmu ent;
int firstblk;
if (!dev) return -1;
save_len = 1024 + src_len;
if (save_len % 512)
save_blocks = save_len / 512 + 1;
else
save_blocks = save_len / 512;
memset(buf, 0, sizeof(buf));
ndc_vmu_create_vmu_header (buf, desc_short, desc_long,
save_blocks * 512 - 128, icon);
memcpy(buf + 640, &src_len, sizeof(uint32));
memcpy(buf + 1024, src, src_len);
ndc_vmu_do_crc(buf, 512 * save_blocks);
firstblk = ndc_vmu_get_dirent (&ent, dev, filename);
if ((firstblk >= 0) && (ent.filesize != save_blocks))
{
int free_blocks = ndc_vmu_check_free_blocks (NULL, dev);
if (free_blocks < 0)
return -1;
if (ent.filesize + free_blocks < save_blocks)
return -1;
if (ndc_vmu_remove_file(dev, filename) < 0)
return -1;
firstblk = -1;
}
if (firstblk < 0)
{
int free_blocks = ndc_vmu_check_free_blocks (NULL, dev);
if (free_blocks < 0 || free_blocks < save_blocks)
return -1;
firstblk = ndc_vmu_allocate_file (dev, filename, save_blocks);
if (firstblk < 0)
return -1;
}
if (ndc_vmu_write_blocks (dev, firstblk, buf, save_blocks) != save_blocks)
return -1;
return 0;
}
int
ndc_vmu_load(uint8 *dst, uint32 *dst_len, maple_device_t *dev, const char *filename)
{
dirent_vmu ent;
uint32 src_len;
uint8 buf[512 * 200]; /* 200 blocks */
uint32 body_len;
int firstblk;
if (!dev) return -1;
firstblk = ndc_vmu_get_dirent (&ent, dev, filename);
if (firstblk < 0)
return -1;
body_len = (ent.filesize - 2) * 512;
if (*dst_len < body_len)
return -1;
if (ndc_vmu_read_blocks (dev, firstblk, buf, ent.filesize) != ent.filesize)
return -1;
memcpy (&src_len, buf + 640, sizeof(uint32));
memcpy (dst, buf + 1024, body_len);
if (src_len)
*dst_len = src_len;
return 0;
}
/*
2001 Takayama Fumihiko <tekezo@catv296.ne.jp>
*/
#ifndef _DC_VMU_H
#define _DC_VMU_H
#include <kos.h>
/*
The dirent_vmu and file_hdr_vmu types came from
vmuload01.0 (file dciwrap.c) by Dan Potter
Original code can be found on this site:
http://dcdev.allusion.net/softprj/
*/
/* VMU Directory Entry */
typedef struct {
uint8 filetype; /* 0x00 = no file; 0x33 = data; 0xcc = a game */
uint8 copyprotect; /* 0x00 = copyable; 0xff = copy protected */
uint16 firstblk; /* location of the first block in the file */
char filename[12]; /* there is no null terminator */
uint8 cent; /* these are all file creation date stuff, in BCD format */
uint8 year;
uint8 month;
uint8 day;
uint8 hour;
uint8 min;
uint8 sec;
uint8 dow; /* day of week (0 = monday, etc) */
uint16 filesize; /* size of the file in blocks */
uint16 hdroff; /* offset of header, in blocks from start of file */
char dummys[4]; /* unused */
} dirent_vmu;
/* ROM menu header */
typedef struct {
char desc_short[16];
char desc_long[32];
char app_id[16];
uint16 icon_cnt;
uint16 animation_speed;
uint16 eyecatch_type;
uint16 crc;
uint32 file_bytes;
char reserved[20];
uint16 palette[16];
uint8 icon_bitmap[384];
} file_hdr_vmu;
typedef struct {
int16 fatblock;
int16 dirblock;
int16 dirlength;
} root_block_info;
typedef struct {
int16 dirblock;
int16 direntry;
} file_dirent_info;
#ifdef __cplusplus
extern "C" {
#endif
/* low level interface */
int ndc_vmu_read_blocks (maple_device_t *dev, uint16 firstblk, uint8 *buffer, uint8 blocks);
int ndc_vmu_write_blocks (maple_device_t *dev, uint16 firstblk, uint8 *buffer, uint8 blocks);
int ndc_vmu_get_dirent (dirent_vmu *vmu, maple_device_t *dev, const char *filename);
int ndc_vmu_getall_dirent (dirent_vmu *entries, int *num_entries, maple_device_t *dev);
int ndc_vmu_check_free_blocks (uint8 *free_mem, maple_device_t *dev);
void ndc_vmu_do_crc (uint8 *buffer, uint16 bytes);
void ndc_vmu_create_vmu_header(uint8 *header,
const char *desc_short,
const char *desc_long,
uint16 filesize,
const uint8 *icon);
int ndc_vmu_allocate_file (maple_device_t *dev, const char *filename, uint8 blocks);
int ndc_vmu_remove_file(maple_device_t *dev, const char *filename);
/* high level interface */
int ndc_vmu_save(uint8 *src, uint32 src_len, maple_device_t *dev,
const char *filename,
const char *desc_short,
const char *desc_long,
const uint8 *icon);
int ndc_vmu_load(uint8 *dst, uint32 *dst_len, maple_device_t *dev, const char *filename);
#ifdef __cplusplus
}
#endif
#endif
#ifndef DEFINES_H
#define DEFINES_H
#define HAVE_ENCDEC 0
#define HAVE_STRDUP 1
#define HAVE_STRNLEN 1
#define HAVE_EXPAT 0
#define HAVE_MBSTATE 1
#define HAVE_WCWIDTH 1
#define HAVE_SNPRINTF 1
#define HAVE_VSNPRINTF 0
#define HAVE_VARMACRO 1
#define HAVE_LANGINFO 1
#ifdef __GNUC__
#define UNUSED __attribute__ ((unused))
#else
#define UNUSED
#endif
#endif /* DEFINES_H */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment